@shtse8/fluxus
Version:
A functional, reactive state management library for TypeScript inspired by Riverpod.
1 lines • 12.4 kB
Source Map (JSON)
{"version":3,"sources":["/home/runner/work/fluxus/fluxus/dist/react-adapter.cjs","../react-adapter/ProviderScope.tsx","../react-adapter/context.ts","../react-adapter/hooks.ts"],"names":[],"mappings":"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","file":"/home/runner/work/fluxus/fluxus/dist/react-adapter.cjs","sourcesContent":[null,"import * as React from 'react';\nimport { Scope, createScope } from '../src/scope.js';\nimport { ScopeContext } from './context.js';\n\n/**\n * Props for the {@link ProviderScope} component.\n */\ninterface ProviderScopeProps {\n /** The child components that will have access to the scope created by this ProviderScope. */\n children: React.ReactNode;\n /** Optional: Provide specific provider overrides for this scope. (Not yet implemented) */\n // overrides?: ProviderOverride[];\n}\n\n/**\n * A React component that creates and manages a Fluxus {@link Scope} instance\n * and provides it to descendant components via React Context.\n *\n * This is the entry point for using Fluxus providers within a React application tree.\n * It ensures that a stable scope is available and handles the automatic disposal\n * of the scope and its associated provider states when the component unmounts.\n *\n * Scopes can be nested by nesting `ProviderScope` components.\n *\n * @param {ProviderScopeProps} props - The component props.\n * @returns {React.ReactElement} The provider component wrapping the children.\n *\n * @example\n * ```tsx\n * ReactDOM.createRoot(document.getElementById('root')!).render(\n * <React.StrictMode>\n * <ProviderScope>\n * <App />\n * </ProviderScope>\n * </React.StrictMode>,\n * )\n * ```\n */\nexport function ProviderScope({ children }: ProviderScopeProps): React.ReactElement {\n const parentScope = React.useContext(ScopeContext);\n const scopeRef = React.useRef<Scope | null>(null);\n\n // Initialize the scope ref *during render* if it's null.\n // useRef ensures this happens only once for the component instance's lifetime,\n // persisting across StrictMode unmount/remount cycles.\n if (scopeRef.current === null) {\n scopeRef.current = createScope(parentScope);\n }\n\n // The scope instance is now guaranteed to exist.\n const scope = scopeRef.current;\n\n // Use useEffect for the disposal cleanup on final unmount.\n React.useEffect(() => {\n // Capture the ref value at the time the effect runs.\n const scopeToDispose = scopeRef.current;\n return () => {\n // Only dispose if the scope exists and hasn't already been disposed.\n if (scopeToDispose && !scopeToDispose.isDisposed) {\n scopeToDispose.dispose();\n }\n };\n }, []); // Empty dependency array ensures cleanup runs only on final unmount.\n\n return (\n <ScopeContext.Provider value={scope}>\n {children}\n </ScopeContext.Provider>\n );\n}","import * as React from 'react';\nimport { Scope } from '../src/scope.js'; // Adjust path as needed\n\n/**\n * React Context to provide the Fluxus Scope to descendant components.\n */\nexport const ScopeContext = React.createContext<Scope | null>(null);\n\n/**\n * Hook to access the current Fluxus Scope from the context.\n * Throws an error if used outside of a ProviderScope.\n * @returns The current Fluxus Scope instance.\n */\nexport function useScope(): Scope {\n const scope = React.useContext(ScopeContext);\n if (!scope) {\n throw new Error('useScope must be used within a ProviderScope');\n }\n return scope;\n}","import * as React from 'react';\nimport { useScope } from './context.js';\nimport { Provider } from '../src/types.js';\nimport { StateProviderInstance, StateUpdater, isStateProviderInstance } from '../src/providers/stateProvider.js';\n\n/**\n * A React hook that reads a provider's value from the current {@link Scope}\n * and subscribes to updates.\n *\n * The component calling this hook will re-render whenever the provider's\n * state changes in the scope. It uses `useSyncExternalStore` internally\n * to ensure compatibility with concurrent rendering features in React.\n *\n * Must be used within a {@link ProviderScope}.\n *\n * @template T The type of the value provided by the provider.\n * @param {Provider<T>} provider The provider whose value is to be read and watched.\n * @returns {T} The current value of the provider.\n * @throws {Error} If used outside of a `ProviderScope`.\n * @throws {Error} If the provider state has been disposed.\n * @throws {Error} If a circular dependency is detected during initialization.\n */\nexport function useProvider<T>(provider: Provider<T>): T {\n const scope = useScope();\n\n // Store the last known value to handle potential reads after scope disposal\n const lastValueRef = React.useRef<T | undefined>(undefined);\n\n // Subscribe to provider updates\n const subscribe = React.useCallback((onStoreChange: () => void) => { // Renamed callback for clarity\n try {\n // scope.watch returns the unsubscribe function\n return scope.watch(provider, () => {\n onStoreChange(); // Call the callback provided by useSyncExternalStore\n });\n } catch (error: any) {\n // If scope is disposed during subscribe, return a no-op unsubscribe\n // Check for disposal errors more broadly\n if (error instanceof Error && error.message.includes('disposed')) {\n return () => {};\n }\n throw error; // Re-throw other errors\n }\n }, [scope, provider]); // Add scope and provider back as dependencies\n\n // Get the current value (snapshot) of the provider\n const getSnapshot = React.useCallback(() => {\n try {\n const currentValue = scope.read(provider);\n lastValueRef.current = currentValue; // Cache the latest value\n return currentValue;\n } catch (error: any) {\n // If scope is disposed, return the last known value if available\n if (error.message === 'Scope has been disposed') {\n if (lastValueRef.current !== undefined) {\n // console.warn('useProvider: Scope disposed, returning last known value.');\n return lastValueRef.current;\n } else {\n // This case should be rare (disposed before first successful read)\n // Re-throwing might be better, but could crash the app.\n // Depending on requirements, returning undefined or a specific error value might be options.\n // For now, re-throw to make the issue visible during testing.\n throw error;\n }\n }\n // Re-throw other errors\n throw error;\n }\n }, [scope, provider]); // Add scope and provider back as dependencies\n\n // Initialize ref with the first snapshot if it's undefined\n if (lastValueRef.current === undefined) {\n try {\n lastValueRef.current = scope.read(provider);\n } catch {\n // Ignore errors here, getSnapshot will handle them\n }\n }\n\n // Optional: Define getServerSnapshot for SSR/server components.\n // It should return the initial state on the server.\n // const getServerSnapshot = React.useCallback(() => {\n // return scope.read(provider);\n // }, [scope, provider]);\n\n // Use useSyncExternalStore to manage the subscription and state updates.\n return React.useSyncExternalStore(\n subscribe,\n getSnapshot\n // getServerSnapshot // Uncomment if supporting SSR\n );\n}\n\n/**\n * A React hook that returns the updater function for a {@link StateProviderInstance}.\n *\n * This hook allows components to update the state of a `StateProvider` without\n * needing to subscribe to its value (and thus avoiding re-renders when the\n * value changes if the component doesn't display it).\n *\n * The returned function has a stable identity across re-renders as long as the\n * provider and scope remain the same, making it safe to use in dependency arrays\n * of other hooks like `useEffect` or `useCallback`.\n *\n * Must be used within a {@link ProviderScope}.\n *\n * @template T The type of the state managed by the StateProvider.\n * @param {StateProviderInstance<T>} provider The StateProvider instance whose updater is needed.\n * @returns {(newValueOrFn: T | ((prev: T) => T)) => void} A stable function to update the provider's state.\n * @throws {Error} If used outside of a `ProviderScope`.\n * @throws {Error} If the provider is not a valid, initialized StateProvider in the scope.\n */\n// Return type is now the simplified version for the user: (newValueOrFn) => void\nexport function useProviderUpdater<T>(provider: StateProviderInstance<T>): (newValueOrFn: T | ((prev: T) => T)) => void {\n const scope = useScope();\n\n // Get the internal updater function from the scope.\n // Fetch it directly to avoid stale closures related to the scope instance.\n const internalUpdater = scope.updater(provider);\n\n // Return a stable function that calls the internal updater with scope and provider.\n // Use useCallback to ensure the returned function identity is stable if scope/provider don't change.\n const stableUpdater = React.useCallback((newValueOrFn: T | ((prev: T) => T)) => {\n // Call the internal updater, passing the current scope and provider instance.\n internalUpdater(scope, provider, newValueOrFn);\n }, [scope, provider, internalUpdater]); // internalUpdater dependency ensures if scope.updater changes behavior, we update\n\n return stableUpdater;\n}\n\n// Example of a combined hook (less common, usually separate value/updater)\n// export function useAtom<T>(provider: StateProviderInstance<T>): [T, StateUpdater<T>] {\n// const value = useProvider(provider);\n// const updater = useProviderUpdater(provider);\n// return [value, updater];\n// }"]}