{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"internals-dom","type":"registry:lib","title":"Shared internals (DOM)","description":"Ref, context and server-rendering helpers for DOM-bound components.","files":[{"path":"react/src/internals/dom/context.ts","content":"\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { Provider } from \"react\";\n\nexport interface InternalContext<T> {\n\tProvider: Provider<T | undefined>;\n\tuseRequired: () => T;\n\tuseOptional: () => T | undefined;\n}\n\n/**\n * A typed context plus its two readers. `useRequired` throws a named error outside its\n * provider (the compound-component contract); `useOptional` returns `undefined` (the\n * degrade-gracefully contract — a field reader with no field, a group item outside its\n * group).\n *\n * A context VALUE is a plain object rebuilt when its scalar inputs change, and the\n * rebuild is what makes consumers re-render. Never wrap one in `useMemo(..., [])`.\n */\nexport function createInternalContext<T>(displayName: string): InternalContext<T> {\n\tconst Context = createContext<T | undefined>(undefined);\n\tContext.displayName = displayName;\n\n\tfunction useRequired(): T {\n\t\tconst value = useContext(Context);\n\t\tif (value === undefined) {\n\t\t\tthrow new Error(`${displayName} is missing: this component must be rendered inside its provider.`);\n\t\t}\n\t\treturn value;\n\t}\n\n\tfunction useOptional(): T | undefined {\n\t\treturn useContext(Context);\n\t}\n\n\treturn { Provider: Context.Provider, useRequired, useOptional };\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/context.ts"},{"path":"react/src/internals/dom/ssr.ts","content":"\"use client\";\n\nimport { useEffect, useLayoutEffect, useRef, useSyncExternalStore } from \"react\";\n\n/**\n * `useLayoutEffect` in the browser, `useEffect` on the server. Everything whose\n * absence is visible in the first painted frame — position, focus, scroll lock, a\n * transition leg — runs through this.\n *\n * The branch is taken once at module scope, never in a render path, so it costs\n * nothing per render and cannot desynchronise a hydration.\n */\nexport const useIsomorphicLayoutEffect: typeof useLayoutEffect =\n\ttypeof document !== \"undefined\" ? useLayoutEffect : useEffect;\n\nconst emptySubscribe = () => () => {};\nconst getSnapshot = () => true;\nconst getServerSnapshot = () => false;\n\n/**\n * `false` on the server AND during the hydration render, `true` from the first\n * post-hydration render on. useSyncExternalStore, not useState+useEffect: no extra\n * commit, and tear-free under concurrent rendering.\n */\nexport function useIsHydrated(): boolean {\n\treturn useSyncExternalStore(emptySubscribe, getSnapshot, getServerSnapshot);\n}\n\n/** Nothing a caller can produce is this symbol, so it is a safe \"not created yet\". */\nconst UNSET = Symbol(\"useConstant.unset\");\n\n/**\n * Lazily create a per-instance value exactly once. StrictMode-safe only because every\n * `create*` factory in this contract is allocation-only — no listeners, no timers.\n */\nexport function useConstant<T>(create: () => T): T {\n\tconst ref = useRef<T | typeof UNSET>(UNSET);\n\tif (ref.current === UNSET) ref.current = create();\n\treturn ref.current as T;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/ssr.ts"},{"path":"react/src/internals/dom/types.ts","content":"\"use client\";\n\n/**\n * Structural ref type. NOT React.RefObject / React.MutableRefObject: those changed\n * shape between @types/react 18 and 19 (19 dropped the mutable/readonly split), and\n * this package's peer range is `^18 || ^19`. A structural type is assignable from\n * every variant either version emits.\n */\nexport type ElementRef<T extends Element = HTMLElement> = { readonly current: T | null };\n","type":"registry:lib","target":"@ui/fancy/internals/dom/types.ts"},{"path":"react/src/internals/dom/use-composed-refs.ts","content":"\"use client\";\n\nimport { useCallback, useRef } from \"react\";\nimport type { Ref, RefCallback } from \"react\";\n\n/**\n * Non-hook form, for use inside an existing callback ref.\n *\n * Returns the cleanup a React 19 callback ref may hand back, or `undefined`.\n * React 19 runs that cleanup on detach INSTEAD of calling the ref with\n * `null`, so a composer that swallowed the return value would silently drop\n * the consumer's teardown. React 18 has no such channel and ignores whatever\n * a callback ref returns — which is why the value is passed on rather than\n * acted upon here, and why every caller must still be able to cope with a\n * plain `assignRef(ref, null)` detach.\n */\nexport function assignRef<T>(\n\tref: Ref<T> | undefined | null,\n\tnode: T | null\n): (() => void) | undefined {\n\tif (typeof ref === \"function\") {\n\t\tconst cleanup = ref(node);\n\t\treturn typeof cleanup === \"function\" ? (cleanup as () => void) : undefined;\n\t}\n\tif (ref) (ref as { current: T | null }).current = node;\n\treturn undefined;\n}\n\n/** Merges any number of refs into one callback ref. Skips nullish entries. */\nexport function useComposedRefs<T>(...refs: Array<Ref<T> | undefined | null>): RefCallback<T> {\n\t// The teardown owed for the CURRENT attachment: one entry per incoming\n\t// ref, either the cleanup that ref returned or a null-write standing in\n\t// for the one it did not. Held in a ref rather than a closure variable so\n\t// it survives the composed callback changing identity mid-life, which is\n\t// exactly when a detach of the old callback is followed by an attach of\n\t// the new one.\n\tconst pending = useRef<Array<() => void> | null>(null);\n\n\tconst detach = useCallback(() => {\n\t\tconst cleanups = pending.current;\n\t\tpending.current = null;\n\t\tif (!cleanups) return;\n\t\tfor (const cleanup of cleanups) cleanup();\n\t}, []);\n\n\t// The rest array IS the dependency list: the composed callback's identity\n\t// changes exactly when one of the incoming refs does, never on every render.\n\t// A call site always passes the same number of refs, so the list length is\n\t// stable — which is the one thing a dynamic dependency list must guarantee.\n\t// `detach` is appended and permanently identity-stable, so the length stays\n\t// stable too.\n\treturn useCallback<RefCallback<T>>(\n\t\t(node) => {\n\t\t\t// Returns NOTHING, on purpose, on both React versions.\n\t\t\t//\n\t\t\t// React 18 treats a ref callback that returns a function as a\n\t\t\t// mistake and logs \"Unexpected return value from a callback ref\"\n\t\t\t// once per attach — for a package whose peer range is\n\t\t\t// `^18 || ^19`, that is dev-console noise on every element wired\n\t\t\t// through here, and a hard failure in any consumer whose CI fails\n\t\t\t// on console.error. React 19's cleanup channel would accept a\n\t\t\t// returned function and call it INSTEAD of passing `null`, but it\n\t\t\t// buys nothing: `detach()` at the head of this callback plus the\n\t\t\t// `node === null` branch below already release the previous\n\t\t\t// attachment on both versions, and `detach` is idempotent, so no\n\t\t\t// cleanup can run twice or be skipped. One code path, one\n\t\t\t// observable behaviour, no warning.\n\t\t\tdetach();\n\t\t\tif (node === null) return;\n\t\t\tpending.current = refs.map((ref) => {\n\t\t\t\tconst cleanup = assignRef(ref, node);\n\t\t\t\t// A ref that returned no cleanup keeps the pre-19 contract: it\n\t\t\t\t// is cleared by being called with `null`. A ref that DID return\n\t\t\t\t// one must never also be nulled — running its cleanup is the\n\t\t\t\t// whole of its teardown.\n\t\t\t\treturn cleanup ?? (() => assignRef(ref, null));\n\t\t\t});\n\t\t},\n\t\t[...refs, detach]\n\t);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/use-composed-refs.ts"},{"path":"react/src/internals/dom/use-element-ref.ts","content":"\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport type { RefCallback } from \"react\";\n\n/**\n * The node, and the callback ref that publishes it. THE way a component hands an\n * element to an internals hook (convention C-1).\n *\n * Returns state, not a ref, so a hook keyed on `[node]` re-runs the moment the node\n * appears — which is the only correct behaviour for a node whose existence is\n * conditional (a presence-mounted panel, an `{#if}`-equivalent branch). The setter\n * identity is stable for the life of the component.\n */\nexport function useElementRef<T extends Element = HTMLElement>(): [T | null, RefCallback<T>] {\n\tconst [node, setNode] = useState<T | null>(null);\n\n\t// Block body, never a concise arrow: React 19 reads a returned value as a\n\t// cleanup function (convention C-3). The `[]` deps keep the identity stable\n\t// for the life of the component, so React never detaches and reattaches.\n\tconst ref = useCallback<RefCallback<T>>((next) => {\n\t\tsetNode(next);\n\t}, []);\n\n\treturn [node, ref];\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/use-element-ref.ts"},{"path":"react/src/internals/dom/use-event-callback.ts","content":"\"use client\";\n\nimport { useCallback, useInsertionEffect, useRef } from \"react\";\n\n/**\n * A permanently identity-stable wrapper that always calls the most recent `fn`.\n * `undefined` yields a stable no-op returning `undefined`.\n *\n * The ref is written inside `useInsertionEffect`, NOT during render. Insertion effects\n * run before every layout effect, so a listener always sees the current callback, and\n * a concurrent render that React throws away can never publish a stale one. This is\n * the React counterpart of the getter-object call sites the Svelte sources use.\n *\n * Every `on*` option on every internals hook goes through this. It is also why\n * anchor-position's `newOpts.onPlacement !== options.onPlacement` reset branch is\n * unreachable from the hook path: the identity never changes.\n */\nexport function useEventCallback<A extends unknown[], R>(\n\tfn: ((...args: A) => R) | undefined\n): (...args: A) => R | undefined {\n\t// Seeded with the first render's `fn` so a call made before the first\n\t// insertion effect — a mount-time layout effect — already reaches it.\n\tconst ref = useRef<((...args: A) => R) | undefined>(fn);\n\n\tuseInsertionEffect(() => {\n\t\tref.current = fn;\n\t}, [fn]);\n\n\treturn useCallback((...args: A) => ref.current?.(...args), []);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/use-event-callback.ts"},{"path":"react/src/internals/dom/use-inert-attribute.ts","content":"\"use client\";\n\nimport { useCallback, useRef } from \"react\";\nimport type { RefCallback } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./ssr\";\nimport { useLiveRef } from \"./use-live-ref\";\n\n/**\n * Keeps the `inert` ATTRIBUTE on an element in sync with a boolean, imperatively.\n *\n * Not a JSX prop, because there is no spelling of one that works across this\n * package's peer range: `inert={true}` is dropped with a warning by React 18\n * (which knows no such attribute and refuses to guess), and `inert=\"\"` is\n * rejected by React 19 (which knows it as a boolean). The attribute itself is\n * what `:not([inert])` selectors and assistive technology key on, so it is\n * written straight to the node instead — one mechanism, identical output on 18\n * and 19.\n *\n * The returned callback ref is identity-stable, so React never detaches and\n * reattaches it; it applies the current value the instant a node arrives (which\n * is what covers a node that REMOUNTS while the flag is unchanged), and the\n * layout effect applies every later change to the node already held. Layout, not\n * passive: inertness that lands a frame late is a frame in which a collapsed\n * region is still clickable and still reachable by Tab.\n *\n * Compose it with `useComposedRefs` when the element already has a ref.\n *\n * SSR: an element is never inert in the server HTML — an attribute this hook\n * writes at commit cannot exist before hydration. Divergence from the Svelte\n * source, which SSRs `inert` inline; observable only in the pre-hydration frame.\n */\nexport function useInertAttribute<T extends Element = HTMLElement>(inert: boolean): RefCallback<T> {\n\tconst nodeRef = useRef<T | null>(null);\n\tconst inertRef = useLiveRef(inert);\n\n\t// Block body, never a concise arrow: React 19 reads a returned value as a\n\t// cleanup function (convention C-3), and `toggleAttribute` returns a boolean.\n\tconst ref = useCallback<RefCallback<T>>(\n\t\t(node) => {\n\t\t\tnodeRef.current = node;\n\t\t\tif (node) node.toggleAttribute(\"inert\", inertRef.current);\n\t\t},\n\t\t[inertRef]\n\t);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tnodeRef.current?.toggleAttribute(\"inert\", inert);\n\t}, [inert]);\n\n\treturn ref;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/use-inert-attribute.ts"},{"path":"react/src/internals/dom/use-live-ref.ts","content":"\"use client\";\n\nimport { useInsertionEffect, useRef } from \"react\";\n\n/**\n * A read-only ref mirroring `value`, written in `useInsertionEffect` for the same\n * reason as `useEventCallback`. The React counterpart of a Svelte getter for a\n * NON-callback value: a long-lived closure (a document listener, an observer\n * callback, a stack entry) reads `ref.current` and sees the latest render's value\n * without being rebuilt.\n */\nexport function useLiveRef<T>(value: T): { readonly current: T } {\n\tconst ref = useRef<T>(value);\n\n\tuseInsertionEffect(() => {\n\t\tref.current = value;\n\t}, [value]);\n\n\treturn ref;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dom/use-live-ref.ts"}]}