"use client"; import * as React from "react"; /** * Creates a type-safe context and provider with automatic error handling * @template T The type of the context value * @param name The name of the root component for error messages * @param defaultValue Optional default value for the context */ function createContext( rootComponentName: string, defaultValue?: T, ) { const Context = React.createContext(defaultValue); Context.displayName = rootComponentName; function Provider(props: T & { children: React.ReactNode }) { const { children, ...contextValue } = props; // Memoize the context value by its values const value = React.useMemo( () => contextValue, // eslint-disable-next-line react-hooks/exhaustive-deps Object.values(contextValue), ) as T; return {children}; } Provider.displayName = `${rootComponentName}Provider`; type ContextReturn = Optional extends true ? T | undefined : T; /** * @param consumerName The name of the component that is consuming the context * @param optional Whether the context is optional (defaults to false) */ function useContext( consumerName: string, optional?: Optional, ): ContextReturn { const context = React.useContext(Context); if (!context && !optional) { throw new Error( `\`${consumerName}\` must be used within \`${rootComponentName}\``, ); } if (context) return context; if (defaultValue !== undefined) return defaultValue; return undefined as ContextReturn; } return [Provider, useContext] as const; } export { createContext };