All files / packages/hooks/src createScopedContext.ts

100% Statements 14/14
100% Branches 2/2
100% Functions 7/7
100% Lines 12/12

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57                                        1x     4x   4x     8x 8x 2x     6x       4x     4x     4x     2x     4x              
import { type Context, createContext, useContextSelector } from "use-context-selector";
 
export type ScopedContextValue<TState, TActions> = {
  state: TState;
  actions: TActions;
};
 
export type ScopedContextSelector<TValue, TSelected> = (value: TValue) => TSelected;
 
export type ScopedContext<TState, TActions> = {
  Context: Context<ScopedContextValue<TState, TActions> | null>;
  useSelector: <TSelected>(
    selector: ScopedContextSelector<ScopedContextValue<TState, TActions>, TSelected>,
  ) => TSelected;
  useStateSelector: <TSelected>(selector: ScopedContextSelector<TState, TSelected>) => TSelected;
  useActionsSelector: <TSelected>(
    selector: ScopedContextSelector<TActions, TSelected>,
  ) => TSelected;
};
 
export const createScopedContext = <TState, TActions>(
  errorMessage: string,
): ScopedContext<TState, TActions> => {
  const Context = createContext<ScopedContextValue<TState, TActions> | null>(null);
 
  const useSelector = <TSelected>(
    selector: ScopedContextSelector<ScopedContextValue<TState, TActions>, TSelected>,
  ): TSelected => {
    return useContextSelector(Context, (value: ScopedContextValue<TState, TActions> | null) => {
      if (!value) {
        throw new Error(errorMessage);
      }
 
      return selector(value);
    });
  };
 
  const useStateSelector = <TSelected>(
    selector: ScopedContextSelector<TState, TSelected>,
  ): TSelected => {
    return useSelector((value) => selector(value.state));
  };
 
  const useActionsSelector = <TSelected>(
    selector: ScopedContextSelector<TActions, TSelected>,
  ): TSelected => {
    return useSelector((value) => selector(value.actions));
  };
 
  return {
    Context,
    useSelector,
    useStateSelector,
    useActionsSelector,
  };
};