@weasel-js/react 1.11.1 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -139,6 +139,9 @@ interface VisibleRaf {
|
|
|
139
139
|
isVisible(): boolean;
|
|
140
140
|
}
|
|
141
141
|
/**
|
|
142
|
+
* A `requestAnimationFrame` loop that runs only while someone can see it: never while the document is hidden,
|
|
143
|
+
* and, given a `target`, never while that element is outside the viewport. Nothing runs until `request()`.
|
|
144
|
+
*
|
|
142
145
|
* @param frame Runs on the frame, with the timestamp the clock supplied and the
|
|
143
146
|
* loop's own handle. A continuous loop calls `loop.request()` from inside it;
|
|
144
147
|
* a one-shot loop does not.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/assignRef.ts","../src/adoptCss.ts","../src/useCanvasFocus.ts","../src/useLatest.ts","../src/reducedMotion.ts","../src/useVisibleRaf.ts","../src/useFrameClock.ts","../src/useStableByContent.ts","../src/kitSettings.ts","../src/useKitSetting.ts"],"names":["useRef","useCallback","useMemo","useState","loop","held","useInsertionEffect","useLayoutEffect","useSyncExternalStore"],"mappings":"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","file":"index.js","sourcesContent":["import type { Ref } from 'react';\n\n/**\n * Write `value` into a ref a caller passed in, whichever shape it has: call a\n * callback ref, set an object ref's `current`, ignore `null` or `undefined`.\n *\n * For a component that keeps the element (or handle) for itself and also\n * forwards it to a ref prop — call this from the component's own callback ref.\n */\nexport function assignRef<T>(ref: Ref<T> | undefined, value: T | null): void {\n if (typeof ref === 'function') ref(value);\n else if (ref) (ref as { current: T | null }).current = value;\n}\n","/** Where an element's styles come from. */\nexport type StyleRoot = Document | ShadowRoot;\n\n/** The root `el`'s styles come from: its shadow root, else its document. */\nexport function styleRootOf(el: Element): StyleRoot {\n const root = el.getRootNode();\n return root instanceof (el.ownerDocument.defaultView?.ShadowRoot ?? ShadowRoot) ? (root as ShadowRoot) : el.ownerDocument;\n}\n\n/** A sheet {@link adoptCss} put in a root. */\nexport interface AdoptedCss {\n /** Replace the sheet's text. */\n write: (css: string) => void;\n /** Take the sheet out of its root. */\n release: () => void;\n}\n\n/**\n * A sheet of its own in `root`, holding `css`: an adopted constructed sheet\n * where the root takes one, else a `<style>`, with `styleId` as its id when\n * one is passed.\n */\nexport function adoptCss(root: StyleRoot, css: string, styleId?: string): AdoptedCss {\n const doc = 'host' in root ? root.ownerDocument : root;\n const Sheet = doc.defaultView?.CSSStyleSheet;\n if (Sheet && 'replaceSync' in Sheet.prototype && Array.isArray(root.adoptedStyleSheets)) {\n // From the root's own window: a constructed sheet cannot be adopted across documents.\n const sheet = new Sheet();\n sheet.replaceSync(css);\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];\n return {\n write: (next) => sheet.replaceSync(next),\n release: () => {\n root.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);\n },\n };\n }\n const style = doc.createElement('style');\n if (styleId !== undefined) style.id = styleId;\n style.textContent = css;\n ('host' in root ? root : doc.head).appendChild(style);\n return {\n write: (next) => {\n style.textContent = next;\n },\n release: () => style.remove(),\n };\n}\n\nlet held = new WeakMap<StyleRoot, Set<string>>();\n\n/**\n * Hold `css` in the root `el`'s styles come from, once per root however many\n * elements ask, and never take it back out: for a component's fixed rules.\n */\nexport function adoptCssOnce(el: Element, css: string): void {\n const root = styleRootOf(el);\n let rules = held.get(root);\n if (rules === undefined) held.set(root, (rules = new Set()));\n if (rules.has(css)) return;\n rules.add(css);\n adoptCss(root, css);\n}\n\n/** Test seam: forgets which roots hold which rules. */\nexport function __resetAdoptedCss(): void {\n held = new WeakMap();\n}\n","/**\n * Track DOM focus on a canvas (or any focusable host element). Returns the\n * live `focused` boolean, props to spread onto the focusable element, and a\n * stable `getFocused()` getter for use inside per-frame closures (notably\n * `RenderLayer.draw`, which is constructed once but called every frame).\n *\n * No Canvas/SceneCanvas integration. Consumers compose the hook with core's\n * `gateLayer` (or their own gate) to hide affordances when blurred.\n */\nimport { useCallback, useMemo, useRef, useState } from 'react';\n\n/** Options for `useCanvasFocus`. */\nexport interface UseCanvasFocusOptions {\n /** Initial focus state. Default `false` — handles hidden until first click. */\n initial?: boolean;\n /** `tabIndex` to set on the focusable element. Default `0` (focusable in\n * document tab order). Set to `-1` for programmatic-only focus. */\n tabIndex?: number;\n}\n\n/** What `useCanvasFocus` hands back: the focus state, the props that\n * maintain it, and a getter for reading it from per-frame code. */\nexport interface CanvasFocusReturn {\n /** Live boolean — true when the element has DOM focus. Triggers re-renders\n * when the focus state changes (set via React state). */\n focused: boolean;\n /** Spread onto the focusable element (e.g. the canvas). Includes\n * `tabIndex`, `onFocus`, `onBlur`. */\n focusProps: {\n tabIndex: number;\n onFocus: () => void;\n onBlur: () => void;\n };\n /** Stable getter for the live focused state. Use inside per-frame closures\n * like `RenderLayer.draw`, where the layer is constructed once and\n * reading `focused` directly would capture the value at construction\n * time. The getter always returns the current value. */\n getFocused: () => boolean;\n /** Imperative focus / blur. Useful for tests and programmatic control. */\n setFocused: (next: boolean) => void;\n}\n\n/** Track DOM focus on the canvas, so chrome that should only show while the\n * canvas is focused can be gated on it. */\nexport function useCanvasFocus(options: UseCanvasFocusOptions = {}): CanvasFocusReturn {\n const { initial = false, tabIndex = 0 } = options;\n const [focused, setFocusedState] = useState<boolean>(initial);\n // Every state change goes through a handler below that writes this first.\n const focusedRef = useRef<boolean>(initial);\n\n const onFocus = useCallback(() => {\n if (!focusedRef.current) {\n focusedRef.current = true;\n setFocusedState(true);\n }\n }, []);\n const onBlur = useCallback(() => {\n if (focusedRef.current) {\n focusedRef.current = false;\n setFocusedState(false);\n }\n }, []);\n const getFocused = useCallback(() => focusedRef.current, []);\n const setFocused = useCallback((next: boolean) => {\n if (focusedRef.current === next) return;\n focusedRef.current = next;\n setFocusedState(next);\n }, []);\n\n // Stable until tabIndex changes, so it can be spread onto memoized elements\n // without retriggering downstream effects.\n const focusProps = useMemo(() => ({ tabIndex, onFocus, onBlur }), [tabIndex, onFocus, onBlur]);\n\n return {\n focused,\n focusProps,\n getFocused,\n setFocused,\n };\n}\n","import { useInsertionEffect, useRef } from 'react';\n\n/**\n * A ref holding the `value` of the last **committed** render, for event\n * handlers, frame loops and other code that runs outside render and must not\n * re-subscribe every time `value` changes.\n *\n * Writing `ref.current = value` in a render body is not the same thing: React\n * may start a render and throw it away (a transition that suspends, a render\n * interrupted by a more urgent update), and the value that render computed\n * would stay behind for the next event to read. This writes from\n * `useInsertionEffect`, so only a render that commits ever lands, and it lands\n * before any layout effect in that commit runs.\n *\n * Don't read `.current` during render expecting this render's value: until the\n * commit it holds the previous committed one (on mount, this first `value`).\n * Render code should use `value` itself.\n */\nexport function useLatest<T>(value: T): { readonly current: T } {\n const ref = useRef(value);\n useInsertionEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n","import { useSyncExternalStore } from 'react';\n\nconst QUERY = '(prefers-reduced-motion: reduce)';\n\n/** Whether the reader has asked for less motion. False where there is no `matchMedia` to ask. */\nexport function prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function' && matchMedia(QUERY).matches;\n}\n\nfunction subscribe(onChange: () => void): () => void {\n if (typeof matchMedia !== 'function') return () => {};\n const list = matchMedia(QUERY);\n list.addEventListener?.('change', onChange);\n return () => list.removeEventListener?.('change', onChange);\n}\n\n/** {@link prefersReducedMotion}, re-rendering when the preference changes. */\nexport function usePrefersReducedMotion(): boolean {\n return useSyncExternalStore(subscribe, prefersReducedMotion, () => false);\n}\n","/**\n * The one place weasel decides whether a frame may run, so that \"a loop does no\n * work nobody can see\" holds by construction rather than by every loop author\n * remembering. Nothing runs while the document is hidden; a loop that names an\n * element also stops while that element is outside the viewport.\n *\n * A request made while suspended is held, not dropped, and re-armed when the\n * surface comes back — so a loop never needs to poll visibility itself.\n */\n\nimport { type RefObject, useCallback, useLayoutEffect, useMemo, useRef } from 'react';\nimport { useLatest } from './useLatest';\n\n/** What a loop names as its element, resolved every time the gate is consulted\n * so a ref filled in after mount still starts the observer. */\nexport type VisibleRafTarget = RefObject<Element | null> | (() => Element | null);\n\n/** Options for {@link useVisibleRaf}. */\nexport interface VisibleRafOptions {\n /** Also gate on this element's intersection with the viewport. Omit it and\n * the loop is gated on document visibility alone. */\n target?: VisibleRafTarget;\n /**\n * Run frames regardless of visibility. The escape hatch for a loop that is\n * not painting for a viewer — an offscreen recording, an export driving its\n * own frames. It is the wrong fix for a loop that stalls after a tab switch:\n * that is a missing `request()`, and setting this hides it.\n */\n dangerouslyRunWhenHidden?: boolean;\n /** Frame clock. Read live, so a test may inject one after mount. */\n requestFrame?: (cb: FrameRequestCallback) => number;\n cancelFrame?: (handle: number) => void;\n /**\n * Runs once when the loop leaves suspension, before the frame that follows\n * it. Where a loop that measures elapsed time drops the interval it spent\n * suspended — without it, an hour hidden arrives as one hour-long frame.\n */\n onResume?: () => void;\n}\n\n/** The handle {@link useVisibleRaf} returns. Nothing runs until `request()` is called. */\nexport interface VisibleRaf {\n /** Ask for a frame. Idempotent while one is outstanding, and held rather than\n * dropped while suspended. Identity is stable for the component's lifetime. */\n request(): void;\n /** Drop the outstanding request, held or scheduled. */\n cancel(): void;\n /** Whether a frame would run right now. */\n isVisible(): boolean;\n}\n\nconst documentHidden = (): boolean => typeof document !== 'undefined' && document.hidden;\n\nconst resolveTarget = (target: VisibleRafTarget | undefined): Element | null =>\n typeof target === 'function' ? target() : (target?.current ?? null);\n\n/**\n * @param frame Runs on the frame, with the timestamp the clock supplied and the\n * loop's own handle. A continuous loop calls `loop.request()` from inside it;\n * a one-shot loop does not.\n */\nexport function useVisibleRaf(\n frame: (time: number, loop: VisibleRaf) => void,\n options: VisibleRafOptions = {},\n): VisibleRaf {\n const frameRef = useLatest(frame);\n const optsRef = useLatest(options);\n\n const rafRef = useRef<number | null>(null);\n const pendingRef = useRef(false);\n const suspendedRef = useRef(false);\n const aliveRef = useRef(true);\n const intersectingRef = useRef(true);\n const observerRef = useRef<IntersectionObserver | null>(null);\n const observedRef = useRef<Element | null>(null);\n const handleRef = useRef<VisibleRaf | null>(null);\n\n const isVisible = useCallback(\n (): boolean =>\n optsRef.current.dangerouslyRunWhenHidden === true ||\n (!documentHidden() && intersectingRef.current),\n [optsRef],\n );\n\n const cancelRaf = useCallback(() => {\n if (rafRef.current === null) return;\n (optsRef.current.cancelFrame ?? cancelAnimationFrame)(rafRef.current);\n rafRef.current = null;\n }, [optsRef]);\n\n const scheduleRaf = useCallback(() => {\n if (rafRef.current !== null || !aliveRef.current) return;\n rafRef.current = (optsRef.current.requestFrame ?? requestAnimationFrame)((time) => {\n // Released before the frame runs, so a `request()` issued from inside it\n // schedules the next one instead of being swallowed.\n rafRef.current = null;\n if (!aliveRef.current || !pendingRef.current || !isVisible()) return;\n pendingRef.current = false;\n frameRef.current(time, handleRef.current!);\n });\n }, [frameRef, isVisible, optsRef]);\n\n /** Attaches the observer once the named element exists. Ref callbacks and\n * lazily-mounted hosts fill their refs after this hook's effect has run. */\n const syncObserver = useCallback(() => {\n const io = observerRef.current;\n if (!io) return;\n const el = resolveTarget(optsRef.current.target);\n if (el === observedRef.current) return;\n if (observedRef.current) io.unobserve(observedRef.current);\n observedRef.current = el;\n // An element that has gone away stops gating rather than stopping the loop.\n intersectingRef.current = true;\n if (el) io.observe(el);\n }, [optsRef]);\n\n /** Re-reads the gate after something that could have changed it. Suspending\n * drops the outstanding frame but keeps the request; resuming hands the\n * loop its rebase before re-arming. */\n const syncGate = useCallback(() => {\n if (!isVisible()) {\n if (suspendedRef.current) return;\n suspendedRef.current = true;\n cancelRaf();\n return;\n }\n if (!suspendedRef.current) return;\n suspendedRef.current = false;\n if (!aliveRef.current) return;\n optsRef.current.onResume?.();\n if (pendingRef.current) scheduleRaf();\n }, [cancelRaf, isVisible, optsRef, scheduleRaf]);\n\n const request = useCallback(() => {\n if (!aliveRef.current) return;\n syncObserver();\n pendingRef.current = true;\n if (!isVisible()) {\n suspendedRef.current = true;\n return;\n }\n scheduleRaf();\n }, [isVisible, scheduleRaf, syncObserver]);\n\n const cancel = useCallback(() => {\n pendingRef.current = false;\n cancelRaf();\n }, [cancelRaf]);\n\n // Re-armed in setup because the refs survive StrictMode's simulated remount, and\n // a layout effect so the arming precedes the host's own layout effects — a loop\n // driven from one of those would otherwise be declined on the second mount.\n useLayoutEffect(() => {\n aliveRef.current = true;\n document.addEventListener('visibilitychange', syncGate);\n if (typeof IntersectionObserver !== 'undefined') {\n observerRef.current = new IntersectionObserver((entries) => {\n intersectingRef.current = entries.some((e) => e.isIntersecting);\n syncGate();\n });\n syncObserver();\n }\n return () => {\n aliveRef.current = false;\n document.removeEventListener('visibilitychange', syncGate);\n observerRef.current?.disconnect();\n observerRef.current = null;\n observedRef.current = null;\n intersectingRef.current = true;\n cancelRaf();\n pendingRef.current = false;\n suspendedRef.current = false;\n };\n }, [cancelRaf, syncGate, syncObserver]);\n\n // Stable identity: `requestRedraw` and friends outlive the render that made\n // them, and consumers capture the handle.\n const handle = useMemo(() => ({ request, cancel, isVisible }), [request, cancel, isVisible]);\n useLayoutEffect(() => { handleRef.current = handle; }, [handle]);\n return handle;\n}\n","import { createEmitter } from '@weasel-js/registry';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { useLatest } from './useLatest';\nimport { useVisibleRaf } from './useVisibleRaf';\n\n/** Options for {@link useFrameClock}. */\nexport interface FrameClockOptions {\n /** Stop the clock where it is. Time spent paused is not counted. */\n paused?: boolean;\n /** What `seconds()` reads before any frame has run. Read once, at mount. */\n start?: number;\n /** Frame source, as on `useVisibleRaf`. */\n requestFrame?: (cb: FrameRequestCallback) => number;\n cancelFrame?: (handle: number) => void;\n}\n\n/** A clock a paint reads without rendering. It has `subscribe`, so a render\n * layer can name it as its redraw source. */\nexport interface FrameClock {\n /** Seconds of frames that ran: time hidden, paused, or with no subscriber is left out. */\n seconds(): number;\n /** Called once per frame. The clock runs while it has a subscriber. */\n subscribe(listener: () => void): () => void;\n}\n\n/**\n * Elapsed time for something that animates in its paint and nowhere else: a\n * shader uniform, a procedural layer. Each frame notifies the subscribers and\n * changes no React state, so the component that owns it does not re-render.\n */\nexport function useFrameClock(options: FrameClockOptions = {}): FrameClock {\n const { paused = false, requestFrame, cancelFrame } = options;\n const elapsed = useRef(options.start ?? 0);\n const last = useRef<number | null>(null);\n const [ticked] = useState(() => createEmitter());\n const pausedRef = useLatest(paused);\n\n const loop = useVisibleRaf(\n (now, loop) => {\n if (last.current !== null) elapsed.current += (now - last.current) / 1000;\n last.current = now;\n ticked.emit();\n if (ticked.size > 0 && !pausedRef.current) loop.request();\n },\n { requestFrame, cancelFrame, onResume: () => { last.current = null; } },\n );\n\n useEffect(() => {\n if (paused) return;\n last.current = null;\n if (ticked.size > 0) loop.request();\n return () => loop.cancel();\n }, [paused, loop, ticked]);\n\n return useMemo<FrameClock>(() => ({\n seconds: () => elapsed.current,\n subscribe(listener) {\n if (ticked.size === 0) last.current = null;\n const off = ticked.subscribe(listener);\n if (!pausedRef.current) loop.request();\n return () => {\n off();\n if (ticked.size === 0) loop.cancel();\n };\n },\n }), [loop, pausedRef, ticked]);\n}\n","import { useInsertionEffect, useRef } from 'react';\n\n/**\n * `value`, or the one the last committed render returned when `same` says the\n * two are equal — so a caller rebuilding an equivalent object every render\n * hands its readers one identity. Compared against the committed value only:\n * a render React throws away never becomes the one the next render keeps.\n */\nexport function useStableByContent<T>(value: T, same: (a: T, b: T) => boolean): T {\n const held = useRef(value);\n const out = held.current === value || same(held.current, value) ? held.current : value;\n useInsertionEffect(() => {\n held.current = out;\n });\n return out;\n}\n\n/** Same length, and the same element at every index. */\nexport function sameList<T>(a: readonly T[], b: readonly T[]): boolean {\n return a.length === b.length && a.every((t, i) => t === b[i]);\n}\n","import type { KitSettings } from './index';\n\n/** A value a settings leaf can hold. */\nexport type KitSettingLeaf = number | string | boolean;\n\n/** `T` with every area and leaf optional: what a provider sets. */\nexport type KitSettingsOverrides<T = KitSettings> = {\n [K in keyof T]?: T[K] extends KitSettingLeaf ? T[K] : KitSettingsOverrides<T[K]>;\n};\n\n/** The dotted path of every leaf in `T`: `'tree.typeaheadMs'`. */\nexport type KitSettingPath<T = KitSettings> = {\n [K in keyof T & string]: T[K] extends KitSettingLeaf ? K : `${K}.${KitSettingPath<T[K]>}`;\n}[keyof T & string];\n\n/** The type of the leaf at `P` in `T`. */\nexport type KitSettingAt<P extends string, T = KitSettings> = P extends `${infer H}.${infer R}`\n ? H extends keyof T ? KitSettingAt<R, T[H]> : never\n : P extends keyof T ? T[P] : never;\n\n/** Reads settings by path and says when any of them changed. */\nexport interface KitSettingsStore<T = KitSettings> {\n /** The value at `path`: this store's own, else the nearest ancestor's, else `undefined`. */\n get<P extends KitSettingPath<T>>(path: P): KitSettingAt<P, T> | undefined;\n subscribe(listener: () => void): () => void;\n}\n\n/** A store whose own overrides can be replaced. */\nexport interface WritableKitSettingsStore<T = KitSettings> extends KitSettingsStore<T> {\n /** Replace this store's own overrides, notifying only when some leaf's value changed. */\n set(overrides: KitSettingsOverrides<T>): void;\n}\n\nfunction leafAt(tree: unknown, path: string): unknown {\n let at = tree;\n for (const key of path.split('.')) {\n if (at === null || typeof at !== 'object' || !Object.hasOwn(at, key)) return undefined;\n at = (at as Record<string, unknown>)[key];\n }\n return at;\n}\n\nfunction flatten(tree: unknown, prefix: string, out: Map<string, unknown>): Map<string, unknown> {\n if (tree === null || typeof tree !== 'object') return out;\n for (const [key, value] of Object.entries(tree)) {\n if (value === undefined) continue;\n const path = prefix === '' ? key : `${prefix}.${key}`;\n if (value !== null && typeof value === 'object') flatten(value, path, out);\n else out.set(path, value);\n }\n return out;\n}\n\nconst sameLeaves = (a: Map<string, unknown>, b: Map<string, unknown>): boolean =>\n a.size === b.size && [...a].every(([path, value]) => b.has(path) && Object.is(b.get(path), value));\n\n/**\n * A settings store holding `overrides`, reading through to `parent` for any\n * leaf it does not set. A change in the parent notifies this store's\n * listeners too.\n */\nexport function createKitSettingsStore<T = KitSettings>(\n overrides: KitSettingsOverrides<T> = {},\n parent: KitSettingsStore<T> | null = null,\n): WritableKitSettingsStore<T> {\n let own: unknown = overrides;\n let leaves = flatten(own, '', new Map());\n const listeners = new Set<() => void>();\n const notify = (): void => {\n for (const listener of [...listeners]) listener();\n };\n let unhookParent: (() => void) | null = null;\n\n return {\n get(path) {\n const value = leafAt(own, path);\n return (value !== undefined ? value : parent?.get(path)) as never;\n },\n subscribe(listener) {\n listeners.add(listener);\n if (parent && unhookParent === null) unhookParent = parent.subscribe(notify);\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0 && unhookParent) {\n unhookParent();\n unhookParent = null;\n }\n };\n },\n set(next) {\n const nextLeaves = flatten(next, '', new Map());\n own = next;\n if (sameLeaves(leaves, nextLeaves)) return;\n leaves = nextLeaves;\n notify();\n },\n };\n}\n\n/** The store read where no provider is mounted: it sets nothing. */\nexport const NO_KIT_SETTINGS: KitSettingsStore = createKitSettingsStore();\n","import { createContext, createElement, useCallback, useContext, useLayoutEffect, useState, useSyncExternalStore, type ReactNode } from 'react';\nimport {\n createKitSettingsStore,\n NO_KIT_SETTINGS,\n type KitSettingAt,\n type KitSettingPath,\n type KitSettingsOverrides,\n type KitSettingsStore,\n} from './kitSettings';\n\nconst KitSettingsContext = createContext<KitSettingsStore>(NO_KIT_SETTINGS);\n\n/**\n * Set kit settings for everything inside. Nested providers merge: a leaf this\n * one leaves unset reads through to the one above.\n */\nexport function KitSettingsProvider({ value, children }: { value: KitSettingsOverrides; children?: ReactNode }): ReactNode {\n const parent = useContext(KitSettingsContext);\n const [store, setStore] = useState(() => ({ parent, store: createKitSettingsStore(value, parent) }));\n if (store.parent !== parent) setStore({ parent, store: createKitSettingsStore(value, parent) });\n useLayoutEffect(() => {\n store.store.set(value);\n }, [store, value]);\n return createElement(KitSettingsContext.Provider, { value: store.store }, children);\n}\n\n/**\n * The store the nearest provider holds, for code outside React — a gesture\n * recognizer, a canvas action — to read with `get(path)` at the moment it\n * needs a value.\n */\nexport function useKitSettings(): KitSettingsStore {\n return useContext(KitSettingsContext);\n}\n\n/**\n * The setting at `path`, or `undefined` where no provider sets it; the caller\n * falls back to its own constant. Re-renders only when this path's value changes.\n */\nexport function useKitSetting<P extends KitSettingPath>(path: P): KitSettingAt<P> | undefined {\n const store = useKitSettings();\n const read = useCallback(() => store.get(path), [store, path]);\n return useSyncExternalStore(store.subscribe, read, read);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/assignRef.ts","../src/adoptCss.ts","../src/useCanvasFocus.ts","../src/useLatest.ts","../src/reducedMotion.ts","../src/useVisibleRaf.ts","../src/useFrameClock.ts","../src/useStableByContent.ts","../src/kitSettings.ts","../src/useKitSetting.ts"],"names":["useRef","useCallback","useMemo","useState","loop","held","useInsertionEffect","useLayoutEffect","useSyncExternalStore"],"mappings":"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","file":"index.js","sourcesContent":["import type { Ref } from 'react';\n\n/**\n * Write `value` into a ref a caller passed in, whichever shape it has: call a\n * callback ref, set an object ref's `current`, ignore `null` or `undefined`.\n *\n * For a component that keeps the element (or handle) for itself and also\n * forwards it to a ref prop — call this from the component's own callback ref.\n */\nexport function assignRef<T>(ref: Ref<T> | undefined, value: T | null): void {\n if (typeof ref === 'function') ref(value);\n else if (ref) (ref as { current: T | null }).current = value;\n}\n","/** Where an element's styles come from. */\nexport type StyleRoot = Document | ShadowRoot;\n\n/** The root `el`'s styles come from: its shadow root, else its document. */\nexport function styleRootOf(el: Element): StyleRoot {\n const root = el.getRootNode();\n return root instanceof (el.ownerDocument.defaultView?.ShadowRoot ?? ShadowRoot) ? (root as ShadowRoot) : el.ownerDocument;\n}\n\n/** A sheet {@link adoptCss} put in a root. */\nexport interface AdoptedCss {\n /** Replace the sheet's text. */\n write: (css: string) => void;\n /** Take the sheet out of its root. */\n release: () => void;\n}\n\n/**\n * A sheet of its own in `root`, holding `css`: an adopted constructed sheet\n * where the root takes one, else a `<style>`, with `styleId` as its id when\n * one is passed.\n */\nexport function adoptCss(root: StyleRoot, css: string, styleId?: string): AdoptedCss {\n const doc = 'host' in root ? root.ownerDocument : root;\n const Sheet = doc.defaultView?.CSSStyleSheet;\n if (Sheet && 'replaceSync' in Sheet.prototype && Array.isArray(root.adoptedStyleSheets)) {\n // From the root's own window: a constructed sheet cannot be adopted across documents.\n const sheet = new Sheet();\n sheet.replaceSync(css);\n root.adoptedStyleSheets = [...root.adoptedStyleSheets, sheet];\n return {\n write: (next) => sheet.replaceSync(next),\n release: () => {\n root.adoptedStyleSheets = root.adoptedStyleSheets.filter((s) => s !== sheet);\n },\n };\n }\n const style = doc.createElement('style');\n if (styleId !== undefined) style.id = styleId;\n style.textContent = css;\n ('host' in root ? root : doc.head).appendChild(style);\n return {\n write: (next) => {\n style.textContent = next;\n },\n release: () => style.remove(),\n };\n}\n\nlet held = new WeakMap<StyleRoot, Set<string>>();\n\n/**\n * Hold `css` in the root `el`'s styles come from, once per root however many\n * elements ask, and never take it back out: for a component's fixed rules.\n */\nexport function adoptCssOnce(el: Element, css: string): void {\n const root = styleRootOf(el);\n let rules = held.get(root);\n if (rules === undefined) held.set(root, (rules = new Set()));\n if (rules.has(css)) return;\n rules.add(css);\n adoptCss(root, css);\n}\n\n/** Test seam: forgets which roots hold which rules. */\nexport function __resetAdoptedCss(): void {\n held = new WeakMap();\n}\n","/**\n * Track DOM focus on a canvas (or any focusable host element). Returns the\n * live `focused` boolean, props to spread onto the focusable element, and a\n * stable `getFocused()` getter for use inside per-frame closures (notably\n * `RenderLayer.draw`, which is constructed once but called every frame).\n *\n * No Canvas/SceneCanvas integration. Consumers compose the hook with core's\n * `gateLayer` (or their own gate) to hide affordances when blurred.\n */\nimport { useCallback, useMemo, useRef, useState } from 'react';\n\n/** Options for `useCanvasFocus`. */\nexport interface UseCanvasFocusOptions {\n /** Initial focus state. Default `false` — handles hidden until first click. */\n initial?: boolean;\n /** `tabIndex` to set on the focusable element. Default `0` (focusable in\n * document tab order). Set to `-1` for programmatic-only focus. */\n tabIndex?: number;\n}\n\n/** What `useCanvasFocus` hands back: the focus state, the props that\n * maintain it, and a getter for reading it from per-frame code. */\nexport interface CanvasFocusReturn {\n /** Live boolean — true when the element has DOM focus. Triggers re-renders\n * when the focus state changes (set via React state). */\n focused: boolean;\n /** Spread onto the focusable element (e.g. the canvas). Includes\n * `tabIndex`, `onFocus`, `onBlur`. */\n focusProps: {\n tabIndex: number;\n onFocus: () => void;\n onBlur: () => void;\n };\n /** Stable getter for the live focused state. Use inside per-frame closures\n * like `RenderLayer.draw`, where the layer is constructed once and\n * reading `focused` directly would capture the value at construction\n * time. The getter always returns the current value. */\n getFocused: () => boolean;\n /** Imperative focus / blur. Useful for tests and programmatic control. */\n setFocused: (next: boolean) => void;\n}\n\n/** Track DOM focus on the canvas, so chrome that should only show while the\n * canvas is focused can be gated on it. */\nexport function useCanvasFocus(options: UseCanvasFocusOptions = {}): CanvasFocusReturn {\n const { initial = false, tabIndex = 0 } = options;\n const [focused, setFocusedState] = useState<boolean>(initial);\n // Every state change goes through a handler below that writes this first.\n const focusedRef = useRef<boolean>(initial);\n\n const onFocus = useCallback(() => {\n if (!focusedRef.current) {\n focusedRef.current = true;\n setFocusedState(true);\n }\n }, []);\n const onBlur = useCallback(() => {\n if (focusedRef.current) {\n focusedRef.current = false;\n setFocusedState(false);\n }\n }, []);\n const getFocused = useCallback(() => focusedRef.current, []);\n const setFocused = useCallback((next: boolean) => {\n if (focusedRef.current === next) return;\n focusedRef.current = next;\n setFocusedState(next);\n }, []);\n\n // Stable until tabIndex changes, so it can be spread onto memoized elements\n // without retriggering downstream effects.\n const focusProps = useMemo(() => ({ tabIndex, onFocus, onBlur }), [tabIndex, onFocus, onBlur]);\n\n return {\n focused,\n focusProps,\n getFocused,\n setFocused,\n };\n}\n","import { useInsertionEffect, useRef } from 'react';\n\n/**\n * A ref holding the `value` of the last **committed** render, for event\n * handlers, frame loops and other code that runs outside render and must not\n * re-subscribe every time `value` changes.\n *\n * Writing `ref.current = value` in a render body is not the same thing: React\n * may start a render and throw it away (a transition that suspends, a render\n * interrupted by a more urgent update), and the value that render computed\n * would stay behind for the next event to read. This writes from\n * `useInsertionEffect`, so only a render that commits ever lands, and it lands\n * before any layout effect in that commit runs.\n *\n * Don't read `.current` during render expecting this render's value: until the\n * commit it holds the previous committed one (on mount, this first `value`).\n * Render code should use `value` itself.\n */\nexport function useLatest<T>(value: T): { readonly current: T } {\n const ref = useRef(value);\n useInsertionEffect(() => {\n ref.current = value;\n });\n return ref;\n}\n","import { useSyncExternalStore } from 'react';\n\nconst QUERY = '(prefers-reduced-motion: reduce)';\n\n/** Whether the reader has asked for less motion. False where there is no `matchMedia` to ask. */\nexport function prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function' && matchMedia(QUERY).matches;\n}\n\nfunction subscribe(onChange: () => void): () => void {\n if (typeof matchMedia !== 'function') return () => {};\n const list = matchMedia(QUERY);\n list.addEventListener?.('change', onChange);\n return () => list.removeEventListener?.('change', onChange);\n}\n\n/** {@link prefersReducedMotion}, re-rendering when the preference changes. */\nexport function usePrefersReducedMotion(): boolean {\n return useSyncExternalStore(subscribe, prefersReducedMotion, () => false);\n}\n","/**\n * The one place weasel decides whether a frame may run, so that \"a loop does no\n * work nobody can see\" holds by construction rather than by every loop author\n * remembering. Nothing runs while the document is hidden; a loop that names an\n * element also stops while that element is outside the viewport.\n *\n * A request made while suspended is held, not dropped, and re-armed when the\n * surface comes back — so a loop never needs to poll visibility itself.\n */\n\nimport { type RefObject, useCallback, useLayoutEffect, useMemo, useRef } from 'react';\nimport { useLatest } from './useLatest';\n\n/** What a loop names as its element, resolved every time the gate is consulted\n * so a ref filled in after mount still starts the observer. */\nexport type VisibleRafTarget = RefObject<Element | null> | (() => Element | null);\n\n/** Options for {@link useVisibleRaf}. */\nexport interface VisibleRafOptions {\n /** Also gate on this element's intersection with the viewport. Omit it and\n * the loop is gated on document visibility alone. */\n target?: VisibleRafTarget;\n /**\n * Run frames regardless of visibility. The escape hatch for a loop that is\n * not painting for a viewer — an offscreen recording, an export driving its\n * own frames. It is the wrong fix for a loop that stalls after a tab switch:\n * that is a missing `request()`, and setting this hides it.\n */\n dangerouslyRunWhenHidden?: boolean;\n /** Frame clock. Read live, so a test may inject one after mount. */\n requestFrame?: (cb: FrameRequestCallback) => number;\n cancelFrame?: (handle: number) => void;\n /**\n * Runs once when the loop leaves suspension, before the frame that follows\n * it. Where a loop that measures elapsed time drops the interval it spent\n * suspended — without it, an hour hidden arrives as one hour-long frame.\n */\n onResume?: () => void;\n}\n\n/** The handle {@link useVisibleRaf} returns. Nothing runs until `request()` is called. */\nexport interface VisibleRaf {\n /** Ask for a frame. Idempotent while one is outstanding, and held rather than\n * dropped while suspended. Identity is stable for the component's lifetime. */\n request(): void;\n /** Drop the outstanding request, held or scheduled. */\n cancel(): void;\n /** Whether a frame would run right now. */\n isVisible(): boolean;\n}\n\nconst documentHidden = (): boolean => typeof document !== 'undefined' && document.hidden;\n\nconst resolveTarget = (target: VisibleRafTarget | undefined): Element | null =>\n typeof target === 'function' ? target() : (target?.current ?? null);\n\n/**\n * A `requestAnimationFrame` loop that runs only while someone can see it: never while the document is hidden,\n * and, given a `target`, never while that element is outside the viewport. Nothing runs until `request()`.\n *\n * @param frame Runs on the frame, with the timestamp the clock supplied and the\n * loop's own handle. A continuous loop calls `loop.request()` from inside it;\n * a one-shot loop does not.\n */\nexport function useVisibleRaf(\n frame: (time: number, loop: VisibleRaf) => void,\n options: VisibleRafOptions = {},\n): VisibleRaf {\n const frameRef = useLatest(frame);\n const optsRef = useLatest(options);\n\n const rafRef = useRef<number | null>(null);\n const pendingRef = useRef(false);\n const suspendedRef = useRef(false);\n const aliveRef = useRef(true);\n const intersectingRef = useRef(true);\n const observerRef = useRef<IntersectionObserver | null>(null);\n const observedRef = useRef<Element | null>(null);\n const handleRef = useRef<VisibleRaf | null>(null);\n\n const isVisible = useCallback(\n (): boolean =>\n optsRef.current.dangerouslyRunWhenHidden === true ||\n (!documentHidden() && intersectingRef.current),\n [optsRef],\n );\n\n const cancelRaf = useCallback(() => {\n if (rafRef.current === null) return;\n (optsRef.current.cancelFrame ?? cancelAnimationFrame)(rafRef.current);\n rafRef.current = null;\n }, [optsRef]);\n\n const scheduleRaf = useCallback(() => {\n if (rafRef.current !== null || !aliveRef.current) return;\n rafRef.current = (optsRef.current.requestFrame ?? requestAnimationFrame)((time) => {\n // Released before the frame runs, so a `request()` issued from inside it\n // schedules the next one instead of being swallowed.\n rafRef.current = null;\n if (!aliveRef.current || !pendingRef.current || !isVisible()) return;\n pendingRef.current = false;\n frameRef.current(time, handleRef.current!);\n });\n }, [frameRef, isVisible, optsRef]);\n\n /** Attaches the observer once the named element exists. Ref callbacks and\n * lazily-mounted hosts fill their refs after this hook's effect has run. */\n const syncObserver = useCallback(() => {\n const io = observerRef.current;\n if (!io) return;\n const el = resolveTarget(optsRef.current.target);\n if (el === observedRef.current) return;\n if (observedRef.current) io.unobserve(observedRef.current);\n observedRef.current = el;\n // An element that has gone away stops gating rather than stopping the loop.\n intersectingRef.current = true;\n if (el) io.observe(el);\n }, [optsRef]);\n\n /** Re-reads the gate after something that could have changed it. Suspending\n * drops the outstanding frame but keeps the request; resuming hands the\n * loop its rebase before re-arming. */\n const syncGate = useCallback(() => {\n if (!isVisible()) {\n if (suspendedRef.current) return;\n suspendedRef.current = true;\n cancelRaf();\n return;\n }\n if (!suspendedRef.current) return;\n suspendedRef.current = false;\n if (!aliveRef.current) return;\n optsRef.current.onResume?.();\n if (pendingRef.current) scheduleRaf();\n }, [cancelRaf, isVisible, optsRef, scheduleRaf]);\n\n const request = useCallback(() => {\n if (!aliveRef.current) return;\n syncObserver();\n pendingRef.current = true;\n if (!isVisible()) {\n suspendedRef.current = true;\n return;\n }\n scheduleRaf();\n }, [isVisible, scheduleRaf, syncObserver]);\n\n const cancel = useCallback(() => {\n pendingRef.current = false;\n cancelRaf();\n }, [cancelRaf]);\n\n // Re-armed in setup because the refs survive StrictMode's simulated remount, and\n // a layout effect so the arming precedes the host's own layout effects — a loop\n // driven from one of those would otherwise be declined on the second mount.\n useLayoutEffect(() => {\n aliveRef.current = true;\n document.addEventListener('visibilitychange', syncGate);\n if (typeof IntersectionObserver !== 'undefined') {\n observerRef.current = new IntersectionObserver((entries) => {\n intersectingRef.current = entries.some((e) => e.isIntersecting);\n syncGate();\n });\n syncObserver();\n }\n return () => {\n aliveRef.current = false;\n document.removeEventListener('visibilitychange', syncGate);\n observerRef.current?.disconnect();\n observerRef.current = null;\n observedRef.current = null;\n intersectingRef.current = true;\n cancelRaf();\n pendingRef.current = false;\n suspendedRef.current = false;\n };\n }, [cancelRaf, syncGate, syncObserver]);\n\n // Stable identity: `requestRedraw` and friends outlive the render that made\n // them, and consumers capture the handle.\n const handle = useMemo(() => ({ request, cancel, isVisible }), [request, cancel, isVisible]);\n useLayoutEffect(() => { handleRef.current = handle; }, [handle]);\n return handle;\n}\n","import { createEmitter } from '@weasel-js/registry';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { useLatest } from './useLatest';\nimport { useVisibleRaf } from './useVisibleRaf';\n\n/** Options for {@link useFrameClock}. */\nexport interface FrameClockOptions {\n /** Stop the clock where it is. Time spent paused is not counted. */\n paused?: boolean;\n /** What `seconds()` reads before any frame has run. Read once, at mount. */\n start?: number;\n /** Frame source, as on `useVisibleRaf`. */\n requestFrame?: (cb: FrameRequestCallback) => number;\n cancelFrame?: (handle: number) => void;\n}\n\n/** A clock a paint reads without rendering. It has `subscribe`, so a render\n * layer can name it as its redraw source. */\nexport interface FrameClock {\n /** Seconds of frames that ran: time hidden, paused, or with no subscriber is left out. */\n seconds(): number;\n /** Called once per frame. The clock runs while it has a subscriber. */\n subscribe(listener: () => void): () => void;\n}\n\n/**\n * Elapsed time for something that animates in its paint and nowhere else: a\n * shader uniform, a procedural layer. Each frame notifies the subscribers and\n * changes no React state, so the component that owns it does not re-render.\n */\nexport function useFrameClock(options: FrameClockOptions = {}): FrameClock {\n const { paused = false, requestFrame, cancelFrame } = options;\n const elapsed = useRef(options.start ?? 0);\n const last = useRef<number | null>(null);\n const [ticked] = useState(() => createEmitter());\n const pausedRef = useLatest(paused);\n\n const loop = useVisibleRaf(\n (now, loop) => {\n if (last.current !== null) elapsed.current += (now - last.current) / 1000;\n last.current = now;\n ticked.emit();\n if (ticked.size > 0 && !pausedRef.current) loop.request();\n },\n { requestFrame, cancelFrame, onResume: () => { last.current = null; } },\n );\n\n useEffect(() => {\n if (paused) return;\n last.current = null;\n if (ticked.size > 0) loop.request();\n return () => loop.cancel();\n }, [paused, loop, ticked]);\n\n return useMemo<FrameClock>(() => ({\n seconds: () => elapsed.current,\n subscribe(listener) {\n if (ticked.size === 0) last.current = null;\n const off = ticked.subscribe(listener);\n if (!pausedRef.current) loop.request();\n return () => {\n off();\n if (ticked.size === 0) loop.cancel();\n };\n },\n }), [loop, pausedRef, ticked]);\n}\n","import { useInsertionEffect, useRef } from 'react';\n\n/**\n * `value`, or the one the last committed render returned when `same` says the\n * two are equal — so a caller rebuilding an equivalent object every render\n * hands its readers one identity. Compared against the committed value only:\n * a render React throws away never becomes the one the next render keeps.\n */\nexport function useStableByContent<T>(value: T, same: (a: T, b: T) => boolean): T {\n const held = useRef(value);\n const out = held.current === value || same(held.current, value) ? held.current : value;\n useInsertionEffect(() => {\n held.current = out;\n });\n return out;\n}\n\n/** Same length, and the same element at every index. */\nexport function sameList<T>(a: readonly T[], b: readonly T[]): boolean {\n return a.length === b.length && a.every((t, i) => t === b[i]);\n}\n","import type { KitSettings } from './index';\n\n/** A value a settings leaf can hold. */\nexport type KitSettingLeaf = number | string | boolean;\n\n/** `T` with every area and leaf optional: what a provider sets. */\nexport type KitSettingsOverrides<T = KitSettings> = {\n [K in keyof T]?: T[K] extends KitSettingLeaf ? T[K] : KitSettingsOverrides<T[K]>;\n};\n\n/** The dotted path of every leaf in `T`: `'tree.typeaheadMs'`. */\nexport type KitSettingPath<T = KitSettings> = {\n [K in keyof T & string]: T[K] extends KitSettingLeaf ? K : `${K}.${KitSettingPath<T[K]>}`;\n}[keyof T & string];\n\n/** The type of the leaf at `P` in `T`. */\nexport type KitSettingAt<P extends string, T = KitSettings> = P extends `${infer H}.${infer R}`\n ? H extends keyof T ? KitSettingAt<R, T[H]> : never\n : P extends keyof T ? T[P] : never;\n\n/** Reads settings by path and says when any of them changed. */\nexport interface KitSettingsStore<T = KitSettings> {\n /** The value at `path`: this store's own, else the nearest ancestor's, else `undefined`. */\n get<P extends KitSettingPath<T>>(path: P): KitSettingAt<P, T> | undefined;\n subscribe(listener: () => void): () => void;\n}\n\n/** A store whose own overrides can be replaced. */\nexport interface WritableKitSettingsStore<T = KitSettings> extends KitSettingsStore<T> {\n /** Replace this store's own overrides, notifying only when some leaf's value changed. */\n set(overrides: KitSettingsOverrides<T>): void;\n}\n\nfunction leafAt(tree: unknown, path: string): unknown {\n let at = tree;\n for (const key of path.split('.')) {\n if (at === null || typeof at !== 'object' || !Object.hasOwn(at, key)) return undefined;\n at = (at as Record<string, unknown>)[key];\n }\n return at;\n}\n\nfunction flatten(tree: unknown, prefix: string, out: Map<string, unknown>): Map<string, unknown> {\n if (tree === null || typeof tree !== 'object') return out;\n for (const [key, value] of Object.entries(tree)) {\n if (value === undefined) continue;\n const path = prefix === '' ? key : `${prefix}.${key}`;\n if (value !== null && typeof value === 'object') flatten(value, path, out);\n else out.set(path, value);\n }\n return out;\n}\n\nconst sameLeaves = (a: Map<string, unknown>, b: Map<string, unknown>): boolean =>\n a.size === b.size && [...a].every(([path, value]) => b.has(path) && Object.is(b.get(path), value));\n\n/**\n * A settings store holding `overrides`, reading through to `parent` for any\n * leaf it does not set. A change in the parent notifies this store's\n * listeners too.\n */\nexport function createKitSettingsStore<T = KitSettings>(\n overrides: KitSettingsOverrides<T> = {},\n parent: KitSettingsStore<T> | null = null,\n): WritableKitSettingsStore<T> {\n let own: unknown = overrides;\n let leaves = flatten(own, '', new Map());\n const listeners = new Set<() => void>();\n const notify = (): void => {\n for (const listener of [...listeners]) listener();\n };\n let unhookParent: (() => void) | null = null;\n\n return {\n get(path) {\n const value = leafAt(own, path);\n return (value !== undefined ? value : parent?.get(path)) as never;\n },\n subscribe(listener) {\n listeners.add(listener);\n if (parent && unhookParent === null) unhookParent = parent.subscribe(notify);\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0 && unhookParent) {\n unhookParent();\n unhookParent = null;\n }\n };\n },\n set(next) {\n const nextLeaves = flatten(next, '', new Map());\n own = next;\n if (sameLeaves(leaves, nextLeaves)) return;\n leaves = nextLeaves;\n notify();\n },\n };\n}\n\n/** The store read where no provider is mounted: it sets nothing. */\nexport const NO_KIT_SETTINGS: KitSettingsStore = createKitSettingsStore();\n","import { createContext, createElement, useCallback, useContext, useLayoutEffect, useState, useSyncExternalStore, type ReactNode } from 'react';\nimport {\n createKitSettingsStore,\n NO_KIT_SETTINGS,\n type KitSettingAt,\n type KitSettingPath,\n type KitSettingsOverrides,\n type KitSettingsStore,\n} from './kitSettings';\n\nconst KitSettingsContext = createContext<KitSettingsStore>(NO_KIT_SETTINGS);\n\n/**\n * Set kit settings for everything inside. Nested providers merge: a leaf this\n * one leaves unset reads through to the one above.\n */\nexport function KitSettingsProvider({ value, children }: { value: KitSettingsOverrides; children?: ReactNode }): ReactNode {\n const parent = useContext(KitSettingsContext);\n const [store, setStore] = useState(() => ({ parent, store: createKitSettingsStore(value, parent) }));\n if (store.parent !== parent) setStore({ parent, store: createKitSettingsStore(value, parent) });\n useLayoutEffect(() => {\n store.store.set(value);\n }, [store, value]);\n return createElement(KitSettingsContext.Provider, { value: store.store }, children);\n}\n\n/**\n * The store the nearest provider holds, for code outside React — a gesture\n * recognizer, a canvas action — to read with `get(path)` at the moment it\n * needs a value.\n */\nexport function useKitSettings(): KitSettingsStore {\n return useContext(KitSettingsContext);\n}\n\n/**\n * The setting at `path`, or `undefined` where no provider sets it; the caller\n * falls back to its own constant. Re-renders only when this path's value changes.\n */\nexport function useKitSetting<P extends KitSettingPath>(path: P): KitSettingAt<P> | undefined {\n const store = useKitSettings();\n const read = useCallback(() => store.get(path), [store, path]);\n return useSyncExternalStore(store.subscribe, read, read);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "Generic React hooks the weasel packages share: a committed-value ref, content-stable identity, and the stylesheet a component adopts into its root. No weasel domain in it.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"react": { "optional": true }
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@weasel-js/registry": "1.
|
|
25
|
+
"@weasel-js/registry": "1.12.0"
|
|
26
26
|
},
|
|
27
27
|
"author": "orochi235",
|
|
28
28
|
"homepage": "https://orochi235.github.io/weasel/",
|