import type { ReadableFamilyToken, ReadableToken, ViewOf } from "atom.io" import type { Canonical } from "atom.io/foundations/canonical" import { getFromStore, subscribeToState } from "atom.io/internal" import { useCallback, useContext, useEffect, useId, useRef, useState, useSyncExternalStore, } from "react" import { parseStateOverloads } from "./parse-state-overloads.ts" import { StoreContext } from "./store-context.tsx" export function useO( token: ReadableToken, ): ViewOf export function useO( token: ReadableFamilyToken, key: NoInfer, ): ViewOf export function useO( ...params: | [ReadableFamilyToken, NoInfer] | [ReadableToken] ): ViewOf { const store = useContext(StoreContext) const token = parseStateOverloads(store, ...params) const id = useId() if ( token.type === `mutable_atom` || token.type === `readonly_held_selector` || token.type === `writable_held_selector` ) { const [, dispatch] = useState(0) const sourceRef = useRef<{ store: typeof store tokenKey: string value: ViewOf } | null>(null) let source = sourceRef.current if ( source === null || source.store !== store || source.tokenKey !== token.key ) { source = { store, tokenKey: token.key, value: getFromStore(store, token), } sourceRef.current = source } useEffect(() => { const unsub = subscribeToState( store, token, `use-o:${id}`, ({ newValue }) => { source.value = newValue dispatch((c) => c + 1) }, ) return unsub }, [store, token.key]) return source.value } const sub = useCallback( (dispatch: () => void) => subscribeToState(store, token, `use-o:${id}`, dispatch), [store, token.key], ) const get = useCallback(() => getFromStore(store, token), [store, token.key]) return useSyncExternalStore>(sub, get, get) }