"use client"; import { type Context, createContext, createElement, type PropsWithChildren, use, useEffect, useMemo, useState, } from "react"; import { type Bunja, type BunjaStore, createBunjaStore, createReadScopeFn, createScope, delayUnmount, type HashFn, type ReadScope, type Scope, type ScopeValuePair, } from "./bunja.ts"; // @ts-ignore dev // deno-lint-ignore no-process-global const __DEV__ = process.env.NODE_ENV !== "production"; export const BunjaStoreContext: Context = createContext( createBunjaStore(), ); export function BunjaStoreProvider( { children }: PropsWithChildren, ): React.JSX.Element { const [value] = useState(createBunjaStore); useEffect(() => () => value.dispose(), [value]); return createElement(BunjaStoreContext, { value, children }); } export const scopeContextMap: Map, Context> = new Map(); export function bindScope(scope: Scope, context: Context): void { scopeContextMap.set(scope as Scope, context as Context); } export function createScopeFromContext( context: Context, hash?: HashFn, ): Scope { const scope = createScope(hash); bindScope(scope, context); return scope; } const defaultReadScope: ReadScope = (scope: Scope) => { const context = scopeContextMap.get(scope as Scope)!; return use(context) as T; }; export function useBunja( bunja: Bunja, scopeValuePairs?: ScopeValuePair[], ): T { const store = use(BunjaStoreContext); const readScope = scopeValuePairs ? createReadScopeFn(scopeValuePairs, defaultReadScope) : defaultReadScope; if (__DEV__) { const { value, mount, deps, bunjaInstance } = store.get(bunja, readScope); useEffect(delayUnmount(mount), deps); useMemo( () => ({ bunja, scopeValuePairs, bunjaInstance }), [bunja, scopeValuePairs, bunjaInstance], ); return value; } else { const { value, mount, deps } = store.get(bunja, readScope); useEffect(delayUnmount(mount), deps); return value; } }