2018-06-25 17:37:36 -06:00
|
|
|
import * as React from "react";
|
|
|
|
|
2018-08-07 21:21:26 +03:00
|
|
|
import { AppState } from "@client/state";
|
2018-06-25 17:37:36 -06:00
|
|
|
|
2018-07-02 15:22:59 -06:00
|
|
|
const StateContext = React.createContext<AppState | null>(null);
|
2018-06-25 17:37:36 -06:00
|
|
|
|
|
|
|
export interface ProvideStateProps {
|
2018-09-02 02:57:55 -06:00
|
|
|
state: AppState;
|
|
|
|
children: React.ReactNode;
|
2018-06-25 17:37:36 -06:00
|
|
|
}
|
|
|
|
|
2018-07-02 15:22:59 -06:00
|
|
|
export function ProvideState({ state, children }: ProvideStateProps) {
|
2018-09-02 02:57:55 -06:00
|
|
|
return (
|
|
|
|
<StateContext.Provider value={state}>{children}</StateContext.Provider>
|
|
|
|
);
|
2018-06-25 17:37:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface ConsumeStateProps {
|
2018-09-02 02:57:55 -06:00
|
|
|
children: (state: AppState) => React.ReactNode;
|
2018-06-25 17:37:36 -06:00
|
|
|
}
|
|
|
|
|
2018-07-02 15:22:59 -06:00
|
|
|
export function ConsumeState({ children }: ConsumeStateProps) {
|
2018-09-02 02:57:55 -06:00
|
|
|
const consumeState = (state: AppState | null) => {
|
|
|
|
if (state == null) {
|
|
|
|
throw new Error(
|
|
|
|
"Component with ConsumeState must be mounted inside ProvideState"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return children(state);
|
|
|
|
};
|
|
|
|
return <StateContext.Consumer>{consumeState}</StateContext.Consumer>;
|
2018-06-25 17:37:36 -06:00
|
|
|
}
|
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
export function injectState<P extends { appState: AppState }>(
|
|
|
|
Component: React.ComponentType<P>
|
2019-07-22 21:33:48 -06:00
|
|
|
): React.FunctionComponent<Omit<P, "appState">> {
|
|
|
|
return function InjectState(props) {
|
|
|
|
const state = React.useContext(StateContext);
|
|
|
|
if (state == null) {
|
|
|
|
throw new Error(
|
|
|
|
"Component with injectState must be mounted inside ProvideState"
|
|
|
|
);
|
2018-09-02 02:57:55 -06:00
|
|
|
}
|
2019-07-22 21:33:48 -06:00
|
|
|
// tslint:disable-next-line: no-object-literal-type-assertion
|
|
|
|
const allProps: Readonly<P> = {...props, appState: state} as Readonly<P>;
|
|
|
|
return <Component {...allProps} />;
|
|
|
|
}
|
2018-06-25 17:37:36 -06:00
|
|
|
}
|