import React, { ForwardRefRenderFunction } from 'react'; import * as ContextSelector from 'use-context-selector'; import { As, AsProps, ExtractRefElement, ForwardRefComponentWithAs, } from '../types'; /* ================================================================================ forwardRef ================================================================================ */ /** * React.forwardRef with typed `as` prop. */ export function forwardRef< Component extends As = As, BaseProps = {}, Props = AsProps, RefElement = Props extends { ref?: infer R } ? ExtractRefElement : never, >(render: ForwardRefRenderFunction) { return React.forwardRef( render, ) as unknown as ForwardRefComponentWithAs; } /* ================================================================================ createContext ================================================================================ */ type CreateContextOptions = { name?: string }; export function createContext( defaultValue: T, { name = 'Context' }: CreateContextOptions = {}, ) { const Context = React.createContext(defaultValue); Context.displayName = name; const useContext = () => { const context = React.useContext(Context); if (context === undefined) { throw new Error( `\`use${name}\` must be used within \`${name}.Provider\``, ); } return context; }; return [Context, useContext] as const; } /* ================================================================================ createContextSelector ================================================================================ */ type CreateContextSelectorOptions = { name?: string }; /** * Creates a context selector and a hook that uses this context. * Context selector allows to subscribe only for certain context changes. */ export function createContextSelector( defaultValue: Value, { name = 'Context' }: CreateContextSelectorOptions = {}, ) { const Context = ContextSelector.createContext(defaultValue); Context.displayName = name; const useContext = ( selector?: (value: Value) => Selected, ) => ContextSelector.useContextSelector( Context, selector || (x => x as unknown as Selected), ); return [Context, useContext] as const; }