1
0

bind.ts 1.2 KB

123456789101112131415161718192021222324
  1. /**
  2. * uSES bridge: turns any bare observable snapshot source into a typed
  3. * selector hook. Client-side-rendered only, so no server snapshot is wired.
  4. * This is the ONE hook constructor in the client stack — engines and hosts
  5. * traffic in bare sources; binding happens on the React side.
  6. */
  7. import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector.js'
  8. import type { HostObservable, SnapshotSelectorHook } from '@deepseek-ai/dsh-client-ui-slots'
  9. /**
  10. * Bind a bare observable source to a typed uSES selector hook.
  11. * subscribe/getSnapshot are captured once per source into stable closures
  12. * (also re-binds `this` for method-based sources), so components never
  13. * resubscribe across renders. Equality defaults to Object.is.
  14. * @param w - snapshot source (engine store, Session object, store instance).
  15. * @returns the selector hook.
  16. */
  17. export function bindSnapshotSelector<T>(w: HostObservable<T>): SnapshotSelectorHook<T> {
  18. const subscribe = (fn: () => void) => w.subscribe(fn)
  19. const getSnapshot = () => w.getSnapshot()
  20. return function useSelector<S>(sel: (s: T) => S, eq?: (a: S, b: S) => boolean): S {
  21. return useSyncExternalStoreWithSelector(subscribe, getSnapshot, undefined, sel, eq)
  22. }
  23. }