{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"internals","type":"registry:lib","title":"Shared internals","description":"Hooks and helpers the components share: positioning, focus, dismissal, ids, text streaming and portals.","registryDependencies":["https://fancy-ui.rama.app/r/internals-dom.json","https://fancy-ui.rama.app/r/utils.json"],"files":[{"path":"react/src/internals/Portal.tsx","content":"\"use client\";\n\n// Renders children into a different place in the document (defaults to\n// <body>) and takes them out again on unmount.\n//\n// The Svelte counterpart is an action that MOVES an already-rendered node;\n// `createPortal` RENDERS INTO the target instead. Same resulting DOM, a\n// different route — and two consequences worth stating out loud:\n//\n//   * There is no \"portal before focus-trap\" ordering hazard here. React\n//     commits portalled children into the container before any effect runs\n//     and populates refs before layout effects, so a node is always connected\n//     by the time anything focuses it. The Svelte action had to be applied\n//     first or `.focus()` was a silent no-op on a detached node.\n//   * SYNTHETIC events still bubble through the React tree even though the\n//     DOM node lives elsewhere, where a moved node's native events stop at\n//     <body>. Inert in practice: `useDismissable` listens natively on\n//     `document`, and no compound root that owns a portalled surface renders\n//     handlers of its own.\n//\n// Usage:\n//   <Portal><div>…</div></Portal>\n//   <Portal target=\"#modal-root\">…</Portal>\n//   <Portal target={someElement}>…</Portal>\n\nimport { useState } from \"react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useIsHydrated, useIsomorphicLayoutEffect } from \"./dom/ssr\";\n\nexport interface PortalProps {\n\t/**\n\t * Element, CSS selector, or undefined for `document.body`. A selector\n\t * matching nothing falls back to `document.body`.\n\t */\n\ttarget?: HTMLElement | string;\n\t/** Render children in place instead of portalling. */\n\tdisabled?: boolean;\n\tchildren?: ReactNode;\n}\n\n/**\n * Resolves a portal target argument to an actual element.\n * Falls back to `document.body` when a string selector matches nothing.\n */\nexport function resolvePortalTarget(target?: HTMLElement | string): HTMLElement {\n\tif (target instanceof HTMLElement) {\n\t\treturn target;\n\t}\n\n\tif (typeof target === \"string\") {\n\t\tconst match = document.querySelector<HTMLElement>(target);\n\t\tif (match) {\n\t\t\treturn match;\n\t\t}\n\t}\n\n\treturn document.body;\n}\n\n/**\n * The mounted target, or `null` on the server and during the hydration\n * render.\n *\n * The gate is what makes a hydration mismatch structurally impossible: the\n * server emits nothing, the hydration render emits nothing, and the target is\n * only resolved once from a layout effect. It costs one extra client render\n * for a surface that is open during SSR — a case that does not occur, since\n * every portalled surface is gated on an `open` that starts false.\n *\n * Never a lazy `useState` initializer reading `document` (convention C-7).\n */\nexport function usePortalTarget(target?: HTMLElement | string): HTMLElement | null {\n\tconst hydrated = useIsHydrated();\n\tconst [container, setContainer] = useState<HTMLElement | null>(null);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tif (!hydrated) return;\n\t\tsetContainer(resolvePortalTarget(target));\n\t}, [hydrated, target]);\n\n\treturn hydrated ? container : null;\n}\n\n/**\n * Renders `children` into `target` for as long as it is mounted.\n *\n * SSR-safe: renders `null` on the server and during hydration, then portals.\n */\nexport function Portal({ target, disabled, children }: PortalProps): ReactElement | null {\n\t// Above the early returns, always — a conditional hook throws the first\n\t// time `disabled` flips (convention C-2).\n\tconst container = usePortalTarget(target);\n\n\tif (disabled) return <>{children}</>;\n\tif (!container) return null;\n\n\treturn createPortal(children, container);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/Portal.tsx"},{"path":"react/src/internals/StreamText.tsx","content":"\"use client\";\n\nimport type { CSSProperties, JSX } from \"react\";\nimport { cn } from \"../utils\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\nimport { useIsomorphicLayoutEffect } from \"./dom/ssr\";\nimport { useTextStream } from \"./use-text-stream\";\nimport \"./stream-text.css\";\n\nexport interface StreamTextProps {\n\t/** The whole text so far. Hand over a longer string to stream more in. */\n\ttext: string;\n\t/** How long a newly arrived chunk stays tinted, in ms. */\n\tsettleMs?: number;\n\t/** Additional CSS classes */\n\tclassName?: string;\n}\n\n/**\n * Renders `text`, tinting only the delta between renders while it settles.\n *\n * Built once from the first `text`/`settleMs` it sees — the server renders\n * the whole string as a single plain span, and only later growth animates —\n * mirroring the Svelte source's `untrack(() => createTextStream(...))`. The\n * push that reconciles the stream with a new `text` runs in a layout effect,\n * before paint, so a re-render never flashes the previous content for a\n * frame.\n */\nexport function StreamText({ text, settleMs = 350, className }: StreamTextProps): JSX.Element {\n\t// A live getter, read once per pushed chunk (never during render), so a\n\t// later `settleMs` reaches later chunks instead of only the CSS custom\n\t// property.\n\tconst settleMsRef = useLiveRef(settleMs);\n\tconst { segments, push } = useTextStream(text, { settleMs: () => settleMsRef.current });\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\t// The first run pushes the text the stream was built from, which is a\n\t\t// no-op.\n\t\tpush(text);\n\t}, [text, push]);\n\n\treturn (\n\t\t<span\n\t\t\tclassName={cn(\"ft-stream\", className)}\n\t\t\tstyle={{ whiteSpace: \"pre-wrap\", [\"--ft-settle\" as string]: `${settleMs}ms` } as CSSProperties}\n\t\t>\n\t\t\t{segments.map((segment) => (\n\t\t\t\t<span key={segment.id} className={segment.fresh ? \"ft-fresh\" : undefined}>\n\t\t\t\t\t{segment.text}\n\t\t\t\t</span>\n\t\t\t))}\n\t\t</span>\n\t);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/StreamText.tsx"},{"path":"react/src/internals/ai-types.ts","content":"\"use client\";\n\n/**\n * Shared data model for the AI component family.\n *\n * Every conversational and agent-activity component reads from these shapes, so\n * one message object can flow from a thread list into a transcript, a tool\n * timeline, or a citation card without translation at each boundary. Types only:\n * nothing here runs, imports, or touches the DOM.\n */\n\n/** Who produced a turn in a conversation. */\nexport type ChatRole = \"user\" | \"assistant\" | \"system\";\n\n/** Lifecycle of a token stream, from the first chunk to its terminal state. */\nexport type StreamStatus = \"idle\" | \"streaming\" | \"done\" | \"error\";\n\n/** Lifecycle of anything the model kicks off and can finish, fail, or abandon. */\nexport type RunStatus = \"pending\" | \"running\" | \"done\" | \"error\" | \"cancelled\";\n\n/** One conversation turn — consumed by message bubbles, transcripts, and branch switchers. */\nexport interface ChatMessageData {\n\tid: string;\n\trole: ChatRole;\n\tcontent: string;\n\tstatus?: StreamStatus;\n\tcreatedAt?: Date | number;\n\tbranchIndex?: number;\n\tbranchCount?: number;\n}\n\n/** A single tool invocation — consumed by tool-call cards and their input/output panels. */\nexport interface ToolCallData {\n\tid: string;\n\tname: string;\n\tstatus: RunStatus;\n\tinput?: unknown;\n\toutput?: unknown;\n\terror?: string;\n\tdurationMs?: number;\n}\n\n/** A document backing an answer — consumed by source lists and inline citations. */\nexport interface SourceData {\n\tid: string;\n\ttitle: string;\n\turl: string;\n\tsnippet?: string;\n\tdomain?: string;\n}\n\n/** One hit from a web lookup — consumed by search-result surfaces. */\nexport interface SearchResultData {\n\tid: string;\n\ttitle: string;\n\turl: string;\n\tsnippet?: string;\n}\n\n/** A file riding along with a turn — consumed by composer attachment chips and previews. */\nexport interface AttachmentData {\n\tid: string;\n\tname: string;\n\tsize?: number;\n\ttype?: string;\n\tpreviewUrl?: string;\n\tprogress?: number;\n\tstatus?: \"uploading\" | \"done\" | \"error\";\n}\n\n/** A node in an agent's plan — consumed by plan trees and task checklists, nests via `substeps`. */\nexport interface PlanStepData {\n\tid: string;\n\tlabel: string;\n\tstatus: RunStatus;\n\tdetail?: string;\n\tsubsteps?: PlanStepData[];\n}\n\n/** A delegated worker — consumed by subagent cards and fan-out activity views. */\nexport interface SubagentData {\n\tid: string;\n\tname: string;\n\ttask: string;\n\tstatus: RunStatus;\n\tprogress?: number;\n\tmodel?: string;\n}\n\n/** A conversation in the sidebar — consumed by thread lists and history pickers. */\nexport interface ThreadData {\n\tid: string;\n\ttitle: string;\n\tpreview?: string;\n\tupdatedAt: Date | number;\n\tunread?: boolean;\n}\n\n/** A selectable action — consumed by slash-command menus and command palettes. */\nexport interface CommandItemData {\n\tid: string;\n\tlabel: string;\n\tdescription?: string;\n\thint?: string;\n}\n\n/** A model the user can switch to — consumed by model pickers in the composer. */\nexport interface ModelOptionData {\n\tid: string;\n\tlabel: string;\n\tbadge?: string;\n\tdescription?: string;\n}\n\n/** Context-window consumption — consumed by token meters and context rings. */\nexport interface TokenUsageData {\n\tused: number;\n\tmax: number;\n\tbreakdown?: Array<{ label: string; tokens: number }>;\n}\n\n/** One line of agent activity — consumed by tool timelines that read as an action log. */\nexport interface ToolTimelineItemData {\n\tid: string;\n\tverb: string;\n\ttarget: string;\n\tdetail?: string;\n\tadditions?: number;\n\tdeletions?: number;\n\ttimestamp?: Date | number;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/ai-types.ts"},{"path":"react/src/internals/anchor-position.ts","content":"\"use client\";\n\n// Framework-agnostic floating-element positioning: given an anchor rect and\n// the size of a floating element (popover / tooltip / menu), computes the\n// x/y coordinates that place it on the requested side, aligned against the\n// anchor, offset away from it, flipped to the opposite side when it would\n// overflow the viewport, and clamped so it never renders off-screen.\n//\n// `computePosition` is a pure function: it takes a DOMRect-shaped anchor and\n// plain dimensions, so it is fully testable without a DOM. `attachAnchorPosition`\n// is the framework-free core that wires it up to a live anchor element; the\n// React binding lives in `use-anchor-position.ts`.\n//\n// Usage:\n//   const { x, y, side } = computePosition(anchorEl.getBoundingClientRect(), { width: 200, height: 40 });\n//\n//   const handle = attachAnchorPosition(node, { anchor: () => anchorEl, side: \"bottom\" });\n\nexport type Side = \"top\" | \"bottom\" | \"left\" | \"right\";\nexport type Align = \"start\" | \"center\" | \"end\";\n\nexport interface ComputePositionOptions {\n\t/** Side of the anchor to place the floating element on. Defaults to \"bottom\". */\n\tside?: Side;\n\t/** Alignment along the cross axis of `side`. Defaults to \"center\". */\n\talign?: Align;\n\t/** Gap in pixels between the anchor and the floating element. Defaults to 8. */\n\toffset?: number;\n\t/** Viewport bounds used for flip/clamp. Defaults to `window` when available, otherwise unbounded (SSR). */\n\tviewport?: { width: number; height: number };\n\t/** Flip to the opposite side when the requested side would overflow the viewport. Defaults to true. */\n\tflip?: boolean;\n}\n\nexport interface ComputePositionResult {\n\tx: number;\n\ty: number;\n\t/** The side actually used, which may differ from the requested one when flipped. */\n\tside: Side;\n\t/**\n\t * The cross-axis alignment the element actually ended up with, which\n\t * differs from the requested one whenever clamping slid it along that\n\t * axis. Read it — not the requested `align` — for anything that has to\n\t * point back at the anchor, such as a transform origin or a caret.\n\t */\n\talign: Align;\n}\n\nconst OPPOSITE_SIDE: Record<Side, Side> = {\n\ttop: \"bottom\",\n\tbottom: \"top\",\n\tleft: \"right\",\n\tright: \"left\",\n};\n\nfunction isHorizontalSide(side: Side): boolean {\n\treturn side === \"top\" || side === \"bottom\";\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(value, max));\n}\n\nfunction getDefaultViewport(): { width: number; height: number } {\n\tif (typeof window !== \"undefined\") {\n\t\treturn { width: window.innerWidth, height: window.innerHeight };\n\t}\n\t// SSR fallback: no viewport to overflow against, so flip/clamp become no-ops.\n\treturn { width: Number.POSITIVE_INFINITY, height: Number.POSITIVE_INFINITY };\n}\n\n/** Whether placing the floating element on `side` would overflow the viewport. */\nfunction overflows(\n\tside: Side,\n\tanchor: DOMRect,\n\tfloating: { width: number; height: number },\n\toffset: number,\n\tviewport: { width: number; height: number }\n): boolean {\n\tswitch (side) {\n\t\tcase \"top\":\n\t\t\treturn anchor.top - floating.height - offset < 0;\n\t\tcase \"bottom\":\n\t\t\treturn anchor.bottom + offset + floating.height > viewport.height;\n\t\tcase \"left\":\n\t\t\treturn anchor.left - floating.width - offset < 0;\n\t\tcase \"right\":\n\t\t\treturn anchor.right + offset + floating.width > viewport.width;\n\t}\n}\n\n/** Computes the raw (unclamped) x/y for `side` + `align`, before flip/clamp are applied. */\nfunction placeAt(\n\tside: Side,\n\tanchor: DOMRect,\n\tfloating: { width: number; height: number },\n\talign: Align,\n\toffset: number\n): { x: number; y: number } {\n\tif (isHorizontalSide(side)) {\n\t\tconst y = side === \"top\" ? anchor.top - floating.height - offset : anchor.bottom + offset;\n\t\tlet x: number;\n\t\tswitch (align) {\n\t\t\tcase \"start\":\n\t\t\t\tx = anchor.left;\n\t\t\t\tbreak;\n\t\t\tcase \"end\":\n\t\t\t\tx = anchor.right - floating.width;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tx = anchor.left + anchor.width / 2 - floating.width / 2;\n\t\t}\n\t\treturn { x, y };\n\t}\n\n\tconst x = side === \"left\" ? anchor.left - floating.width - offset : anchor.right + offset;\n\tlet y: number;\n\tswitch (align) {\n\t\tcase \"start\":\n\t\t\ty = anchor.top;\n\t\t\tbreak;\n\t\tcase \"end\":\n\t\t\ty = anchor.bottom - floating.height;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ty = anchor.top + anchor.height / 2 - floating.height / 2;\n\t}\n\treturn { x, y };\n}\n\n/**\n * Where the anchor's cross-axis centre falls inside the element as finally\n * placed, expressed in the same vocabulary as the requested `align`.\n *\n * The requested alignment cannot answer this: clamping moves x/y without\n * touching either input, so a menu asked for `align: \"start\"` next to the\n * viewport's right edge is reported as `start` while the anchor now sits by\n * its right edge. Deriving from the clamped coordinates keeps that honest.\n * The thirds are the natural split of the three-value vocabulary.\n */\nfunction resolveAlign(\n\tside: Side,\n\tanchor: DOMRect,\n\tfloating: { width: number; height: number },\n\tx: number,\n\ty: number,\n\trequested: Align\n): Align {\n\tconst horizontal = isHorizontalSide(side);\n\tconst extent = horizontal ? floating.width : floating.height;\n\t// A zero-size element has no inside for the anchor to fall in — an\n\t// unlaid-out first frame, a `display: none` ancestor, or jsdom, where\n\t// every element measures zero. Nothing was clamped in that state either,\n\t// so the requested alignment is both the honest answer and the one that\n\t// keeps a never-measured panel behaving exactly as it did before.\n\tif (extent <= 0) return requested;\n\n\tconst anchorCentre = horizontal ? anchor.left + anchor.width / 2 : anchor.top + anchor.height / 2;\n\tconst ratio = (anchorCentre - (horizontal ? x : y)) / extent;\n\n\tif (ratio < 1 / 3) return \"start\";\n\tif (ratio > 2 / 3) return \"end\";\n\treturn \"center\";\n}\n\n/**\n * Computes where to place a floating element relative to an anchor rect.\n *\n * Pure function — no DOM access, so it is testable with plain objects that\n * satisfy the `DOMRect` shape.\n */\nexport function computePosition(\n\tanchor: DOMRect,\n\tfloating: { width: number; height: number },\n\topts: ComputePositionOptions = {}\n): ComputePositionResult {\n\tconst { side = \"bottom\", align = \"center\", offset = 8, flip = true } = opts;\n\tconst viewport = opts.viewport ?? getDefaultViewport();\n\n\tconst resolvedSide =\n\t\tflip && overflows(side, anchor, floating, offset, viewport) ? OPPOSITE_SIDE[side] : side;\n\n\tconst { x, y } = placeAt(resolvedSide, anchor, floating, align, offset);\n\n\tconst maxX = Math.max(0, viewport.width - floating.width);\n\tconst maxY = Math.max(0, viewport.height - floating.height);\n\n\tconst clampedX = clamp(x, 0, maxX);\n\tconst clampedY = clamp(y, 0, maxY);\n\n\treturn {\n\t\tx: clampedX,\n\t\ty: clampedY,\n\t\tside: resolvedSide,\n\t\talign: resolveAlign(resolvedSide, anchor, floating, clampedX, clampedY, align),\n\t};\n}\n\nexport interface AnchorPositionOptions {\n\t/** Resolves the current anchor element. Called on every recompute so it can track a moving target. */\n\tanchor: () => HTMLElement | null;\n\tside?: Side;\n\talign?: Align;\n\toffset?: number;\n\t/**\n\t * Called with the side the element was actually placed on, which differs\n\t * from the requested `side` whenever a flip occurred, and with the\n\t * cross-axis alignment it actually ended up with, which differs from the\n\t * requested `align` whenever clamping slid it along that axis. Fires once\n\t * on the initial placement and thereafter only when either resolved value\n\t * changes, so a consumer can react (move a caret, set a transform origin,\n\t * mirror a submenu's open direction) without re-rendering on every scroll\n\t * frame.\n\t *\n\t * Without this, `computePosition`'s resolved placement is computed and\n\t * discarded here, and a consumer has no way to learn a flip or a clamp\n\t * happened.\n\t */\n\tonPlacement?: (side: Side, align: Align) => void;\n}\n\nexport interface AnchorPositionHandle {\n\t/** Swaps the options and recomputes — the action's `update` under a new name. */\n\tupdate(options: AnchorPositionOptions): void;\n\t/** Recomputes against the current options, for a caller that knows the geometry moved. */\n\trecompute(): void;\n\t/** Detaches the scroll and resize listeners, and strips the position `update()` wrote. */\n\tdestroy(): void;\n}\n\n/**\n * Positions `node` with `position: fixed` against a live anchor element, using\n * `computePosition`. Recomputes on scroll and resize (passive, capturing\n * listeners so nested scroll containers are caught too) and cleans up its\n * listeners — and the position it wrote — on destroy.\n *\n * SSR-safe: does nothing when `window` is unavailable.\n */\nexport function attachAnchorPosition(\n\tnode: HTMLElement,\n\topts: AnchorPositionOptions\n): AnchorPositionHandle {\n\tif (typeof window === \"undefined\") {\n\t\treturn { update() {}, recompute() {}, destroy() {} };\n\t}\n\n\tlet options = opts;\n\t// The last placement reported through `onPlacement`, so a scroll or resize\n\t// that recomputes to the same one stays silent. `null` means \"nothing\n\t// reported yet\", which is distinct from any real value and makes the first\n\t// placement always fire.\n\tlet reportedSide: Side | null = null;\n\tlet reportedAlign: Align | null = null;\n\n\t/**\n\t * The floating element's size as LAID OUT, never as PAINTED.\n\t *\n\t * `getBoundingClientRect()` reports the box AFTER transforms, and every\n\t * anchored surface in this package is mid-entrance the first time this\n\t * runs. The presence clock pins `transform: scale(0.92)` on the panel in\n\t * the commit its node attaches; the node reaches this module one commit\n\t * later, because the transition takes it through a plain ref callback and\n\t * the position takes it through state. Measuring the painted box would\n\t * size the panel 8% small, place it that much off its anchor, and leave it\n\t * there — the entrance settles and nothing recomputes.\n\t *\n\t * `offsetWidth`/`offsetHeight` are layout metrics: a transform does not\n\t * touch them. They round to whole pixels, a quarter pixel of placement\n\t * against the several the transform costs. Zero means there is no layout\n\t * box to read — a detached node, a `display: none` ancestor, or jsdom,\n\t * where every element measures zero — so the rect answers for that case,\n\t * and the two agree everywhere else.\n\t */\n\tfunction measureFloating(): { width: number; height: number } {\n\t\tconst rect = node.getBoundingClientRect();\n\t\treturn {\n\t\t\twidth: node.offsetWidth || rect.width,\n\t\t\theight: node.offsetHeight || rect.height,\n\t\t};\n\t}\n\n\tfunction update(): void {\n\t\tconst anchorEl = options.anchor();\n\t\tif (!anchorEl) return;\n\n\t\tconst anchorRect = anchorEl.getBoundingClientRect();\n\t\t// Measured as the box it is about to become. Before the first update\n\t\t// a portalled node is a static block as wide as its container, so a\n\t\t// panel with no width of its own would centre on the full page width\n\t\t// and clamp to the left edge. Parked at the origin, a fixed box\n\t\t// shrinks to its content with the whole viewport to grow into,\n\t\t// wherever the last update left it.\n\t\tnode.style.position = \"fixed\";\n\t\tnode.style.left = \"0px\";\n\t\tnode.style.top = \"0px\";\n\t\tconst { x, y, side, align } = computePosition(anchorRect, measureFloating(), {\n\t\t\tside: options.side,\n\t\t\talign: options.align,\n\t\t\toffset: options.offset,\n\t\t\tviewport: { width: window.innerWidth, height: window.innerHeight },\n\t\t});\n\n\t\tnode.style.position = \"fixed\";\n\t\tnode.style.left = `${x}px`;\n\t\tnode.style.top = `${y}px`;\n\n\t\tif (side !== reportedSide || align !== reportedAlign) {\n\t\t\treportedSide = side;\n\t\t\treportedAlign = align;\n\t\t\toptions.onPlacement?.(side, align);\n\t\t}\n\t}\n\n\t// Everything `update()` wrote onto the node, cleared.\n\t//\n\t// DIVERGENCE from the Svelte action, deliberate. There, destroy runs only\n\t// when the element the action is attached to is itself being removed, so\n\t// leftover inline styles are unobservable. The React binding adds an\n\t// `enabled` option that tears this handle down while the node stays\n\t// mounted, and the same leftovers then read as a surface frozen at its\n\t// last computed coordinates — `position: fixed` at a stale left/top, over\n\t// content it no longer belongs to, until something re-enables it. Clearing\n\t// here also matches `FloatHandle.destroy()`, the sibling core, which\n\t// already promises to strip the node's own styles.\n\tfunction reset(): void {\n\t\tnode.style.position = \"\";\n\t\tnode.style.left = \"\";\n\t\tnode.style.top = \"\";\n\t}\n\n\tupdate();\n\n\twindow.addEventListener(\"scroll\", update, { passive: true, capture: true });\n\twindow.addEventListener(\"resize\", update, { passive: true });\n\n\treturn {\n\t\tupdate(newOpts: AnchorPositionOptions) {\n\t\t\t// A new `onPlacement` is a new listener that has never been told\n\t\t\t// anything, so it gets a report even if the side did not move.\n\t\t\t// Without this, the idiomatic call site — an inline arrow in the\n\t\t\t// options object, rebuilt on every re-render — silently never\n\t\t\t// fires after the first one: `reportedSide` is scoped to the node,\n\t\t\t// not to the callback, so the gate that exists to suppress\n\t\t\t// duplicate reports to the *same* listener ends up suppressing the\n\t\t\t// first report to a *different* one. Unreachable from the React\n\t\t\t// hook, whose `onPlacement` goes through `useEventCallback` and so\n\t\t\t// keeps one identity for the life of the component; kept because\n\t\t\t// the core is public to any caller that hands over a fresh arrow.\n\t\t\tif (newOpts.onPlacement !== options.onPlacement) {\n\t\t\t\treportedSide = null;\n\t\t\t\treportedAlign = null;\n\t\t\t}\n\t\t\toptions = newOpts;\n\t\t\tupdate();\n\t\t},\n\t\trecompute() {\n\t\t\tupdate();\n\t\t},\n\t\tdestroy() {\n\t\t\twindow.removeEventListener(\"scroll\", update, { capture: true });\n\t\t\twindow.removeEventListener(\"resize\", update);\n\t\t\treset();\n\t\t},\n\t};\n}\n","type":"registry:lib","target":"@ui/fancy/internals/anchor-position.ts"},{"path":"react/src/internals/calendar-core.ts","content":"\"use client\";\n\n// Pure calendar math shared by date-picker style components. Everything here\n// operates on native `Date` objects in local time and has no DOM dependency,\n// so it is trivially unit-testable and safe to call during SSR.\n//\n// Usage:\n//   const weeks = getMonthGrid(2024, 1); // February 2024, 6 weeks x 7 days\n\nexport type WeekStartsOn = 0 | 1;\n\nexport interface MonthGridDay {\n\tdate: Date;\n\t/** False for the leading/trailing days that pad the grid but belong to an adjacent month. */\n\tinMonth: boolean;\n}\n\nconst DAYS_IN_WEEK = 7;\nconst WEEKS_IN_GRID = 6;\n\n/**\n * Builds a 6-week x 7-day grid for `month` (0-11) of `year`, padded with the\n * trailing days of the previous month and the leading days of the next one\n * so every week is complete.\n *\n * @param weekStartsOn - 0 for Sunday, 1 for Monday. Defaults to 0.\n */\nexport function getMonthGrid(\n\tyear: number,\n\tmonth: number,\n\tweekStartsOn: WeekStartsOn = 0\n): MonthGridDay[][] {\n\t// Normalize through Date so out-of-range month values (e.g. 12) resolve\n\t// the same way the rest of this module treats them.\n\tconst reference = new Date(year, month, 1);\n\tconst firstWeekday = reference.getDay();\n\tconst leadingDays = (firstWeekday - weekStartsOn + 7) % 7;\n\n\tconst gridStart = new Date(reference.getFullYear(), reference.getMonth(), 1 - leadingDays);\n\n\tconst days: MonthGridDay[] = [];\n\tfor (let i = 0; i < WEEKS_IN_GRID * DAYS_IN_WEEK; i++) {\n\t\tconst date = new Date(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + i);\n\t\tdays.push({\n\t\t\tdate,\n\t\t\tinMonth:\n\t\t\t\tdate.getMonth() === reference.getMonth() && date.getFullYear() === reference.getFullYear(),\n\t\t});\n\t}\n\n\tconst weeks: MonthGridDay[][] = [];\n\tfor (let w = 0; w < WEEKS_IN_GRID; w++) {\n\t\tweeks.push(days.slice(w * DAYS_IN_WEEK, (w + 1) * DAYS_IN_WEEK));\n\t}\n\treturn weeks;\n}\n\n/**\n * Returns a new date `n` months away from `date`. Clamps the day-of-month to\n * the target month's length instead of letting it roll over (e.g. Jan 31 + 1\n * month lands on Feb 28/29, not Mar 2/3).\n */\nexport function addMonths(date: Date, n: number): Date {\n\tconst day = date.getDate();\n\n\t// Move to day 1 first so setMonth can't overflow into an unrelated month.\n\tconst result = new Date(date);\n\tresult.setDate(1);\n\tresult.setMonth(result.getMonth() + n);\n\n\tconst daysInTargetMonth = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();\n\tresult.setDate(Math.min(day, daysInTargetMonth));\n\tresult.setHours(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());\n\treturn result;\n}\n\n/** Whether `a` and `b` fall on the same calendar day (year/month/date), ignoring time. */\nexport function isSameDay(a: Date, b: Date): boolean {\n\treturn (\n\t\ta.getFullYear() === b.getFullYear() &&\n\t\ta.getMonth() === b.getMonth() &&\n\t\ta.getDate() === b.getDate()\n\t);\n}\n\n/** Clamps `date` into the `[min, max]` range (either bound optional). Always returns a new Date. */\nexport function clampDate(date: Date, min?: Date, max?: Date): Date {\n\tif (min && date.getTime() < min.getTime()) {\n\t\treturn new Date(min);\n\t}\n\tif (max && date.getTime() > max.getTime()) {\n\t\treturn new Date(max);\n\t}\n\treturn new Date(date);\n}\n\n/** Formats `date` as a \"YYYY-MM-DD\" string using its local date components. */\nexport function formatISODate(date: Date): string {\n\tconst year = date.getFullYear().toString().padStart(4, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\treturn `${year}-${month}-${day}`;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/calendar-core.ts"},{"path":"react/src/internals/diff.ts","content":"\"use client\";\n\n/**\n * Unified diff parser.\n *\n * Total and side-effect free: every input yields a value and nothing throws.\n * Malformed, truncated or headerless patches degrade to a best-effort reading,\n * so a patch that is still streaming in can be re-parsed on every chunk.\n */\n\nexport type DiffLineType = \"add\" | \"del\" | \"context\" | \"meta\";\n\n/**\n * One line of a hunk. `text` drops the leading `+`/`-`/space marker; `meta`\n * lines (`\\ No newline at end of file`) keep their raw text. A line number is\n * null on the side where the line does not exist.\n */\nexport interface DiffLine {\n\ttype: DiffLineType;\n\ttext: string;\n\toldLine: number | null;\n\tnewLine: number | null;\n}\n\nexport interface DiffHunk {\n\theader: string;\n\toldStart: number;\n\toldCount: number;\n\tnewStart: number;\n\tnewCount: number;\n\tlines: DiffLine[];\n}\n\nexport interface DiffFile {\n\toldPath: string | null;\n\tnewPath: string | null;\n\thunks: DiffHunk[];\n\tadditions: number;\n\tdeletions: number;\n\tisNew: boolean;\n\tisDeleted: boolean;\n\tisRename: boolean;\n}\n\nconst HUNK_HEADER = /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/;\nconst FILE_HEADER = /^(?:---|\\+\\+\\+) /;\n\nconst GIT_HEADER = \"diff --git \";\n\ninterface State {\n\tfiles: DiffFile[];\n\tfile: DiffFile | null;\n\thunk: DiffHunk | null;\n\toldLine: number;\n\tnewLine: number;\n\tremainingOld: number;\n\tremainingNew: number;\n}\n\nfunction isBodyLine(line: string): boolean {\n\tconst marker = line.charAt(0);\n\treturn marker === \"+\" || marker === \"-\" || marker === \" \";\n}\n\n/** Drops trailing timestamp metadata, surrounding quotes and the `a/` `b/` prefixes. */\nfunction cleanPath(raw: string, stripAffix: boolean): string | null {\n\tlet path = raw.replace(/\\s+$/, \"\");\n\tconst tab = path.indexOf(\"\\t\");\n\tif (tab !== -1) path = path.slice(0, tab).replace(/\\s+$/, \"\");\n\tif (path.length > 1 && path.startsWith('\"') && path.endsWith('\"')) path = path.slice(1, -1);\n\tif (path === \"/dev/null\" || path === \"\") return null;\n\tif (stripAffix && (path.startsWith(\"a/\") || path.startsWith(\"b/\"))) path = path.slice(2);\n\treturn path === \"\" ? null : path;\n}\n\nfunction gitHeaderPaths(line: string): [string | null, string | null] {\n\tconst rest = line.slice(GIT_HEADER.length);\n\t// Greedy on purpose: a path may itself contain \" b/\".\n\tconst paired = /^a\\/(.*) b\\/(.*)$/.exec(rest);\n\t// Both groups exist whenever the pattern matched at all.\n\tif (paired) return [cleanPath(paired[1]!, false), cleanPath(paired[2]!, false)];\n\tconst parts = rest.split(\" \");\n\tif (parts.length < 2) return [null, null];\n\t// `parts[0]` exists: the length check on the line above passed.\n\treturn [cleanPath(parts[0]!, true), cleanPath(parts.slice(1).join(\" \"), true)];\n}\n\nfunction openFile(state: State): DiffFile {\n\tconst file: DiffFile = {\n\t\toldPath: null,\n\t\tnewPath: null,\n\t\thunks: [],\n\t\tadditions: 0,\n\t\tdeletions: 0,\n\t\tisNew: false,\n\t\tisDeleted: false,\n\t\tisRename: false,\n\t};\n\tstate.files.push(file);\n\tstate.file = file;\n\tstate.hunk = null;\n\treturn file;\n}\n\nfunction currentFile(state: State): DiffFile {\n\treturn state.file ?? openFile(state);\n}\n\nfunction openHunk(state: State, hunk: DiffHunk): void {\n\tcurrentFile(state).hunks.push(hunk);\n\tstate.hunk = hunk;\n\tstate.oldLine = hunk.oldStart;\n\tstate.newLine = hunk.newStart;\n\tstate.remainingOld = hunk.oldCount;\n\tstate.remainingNew = hunk.newCount;\n}\n\nfunction appendBody(state: State, raw: string): void {\n\tconst hunk = state.hunk;\n\tconst file = state.file;\n\tif (!hunk || !file) return;\n\tconst marker = raw.charAt(0);\n\tconst known = marker === \"+\" || marker === \"-\" || marker === \" \";\n\tconst text = known ? raw.slice(1) : raw;\n\n\tif (marker === \"+\") {\n\t\thunk.lines.push({ type: \"add\", text, oldLine: null, newLine: state.newLine++ });\n\t\tfile.additions++;\n\t\tif (state.remainingNew > 0) state.remainingNew--;\n\t\treturn;\n\t}\n\tif (marker === \"-\") {\n\t\thunk.lines.push({ type: \"del\", text, oldLine: state.oldLine++, newLine: null });\n\t\tfile.deletions++;\n\t\tif (state.remainingOld > 0) state.remainingOld--;\n\t\treturn;\n\t}\n\t// Space, empty, or anything unrecognised inside a hunk: treated as context.\n\thunk.lines.push({ type: \"context\", text, oldLine: state.oldLine++, newLine: state.newLine++ });\n\tif (state.remainingOld > 0) state.remainingOld--;\n\tif (state.remainingNew > 0) state.remainingNew--;\n}\n\nexport function parseUnifiedDiff(src: string): DiffFile[] {\n\tif (typeof src !== \"string\" || src.trim() === \"\") return [];\n\n\tconst state: State = {\n\t\tfiles: [],\n\t\tfile: null,\n\t\thunk: null,\n\t\toldLine: 0,\n\t\tnewLine: 0,\n\t\tremainingOld: 0,\n\t\tremainingNew: 0,\n\t};\n\n\tconst lines = src.split(/\\r?\\n/);\n\tif (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n\n\tfor (const raw of lines) {\n\t\tif (state.hunk) {\n\t\t\tif (raw.startsWith(\"\\\\\")) {\n\t\t\t\tstate.hunk.lines.push({ type: \"meta\", text: raw, oldLine: null, newLine: null });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// `---`/`+++` are ambiguous with content, so only unmistakable\n\t\t\t// boundaries end a hunk early; otherwise the declared counts do. Once\n\t\t\t// the counts are spent they stop being ambiguous: concatenated `diff -u`\n\t\t\t// output has no `diff --git` separator, and its next file announces\n\t\t\t// itself with exactly those two headers.\n\t\t\tconst budget = state.remainingOld > 0 || state.remainingNew > 0;\n\t\t\tconst boundary =\n\t\t\t\traw.startsWith(GIT_HEADER) || HUNK_HEADER.test(raw) || (!budget && FILE_HEADER.test(raw));\n\t\t\tif (!boundary && (budget || isBodyLine(raw))) {\n\t\t\t\tappendBody(state, raw);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tstate.hunk = null;\n\t\t}\n\n\t\tconst header = HUNK_HEADER.exec(raw);\n\t\tif (header) {\n\t\t\topenHunk(state, {\n\t\t\t\theader: raw,\n\t\t\t\toldStart: Number(header[1]),\n\t\t\t\toldCount: header[2] === undefined ? 1 : Number(header[2]),\n\t\t\t\tnewStart: Number(header[3]),\n\t\t\t\tnewCount: header[4] === undefined ? 1 : Number(header[4]),\n\t\t\t\tlines: [],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith(\"@@\")) continue;\n\n\t\tif (raw.startsWith(GIT_HEADER)) {\n\t\t\tconst file = openFile(state);\n\t\t\t[file.oldPath, file.newPath] = gitHeaderPaths(raw);\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith(\"--- \")) {\n\t\t\t// A bare `---` with no `diff --git` above it starts the next file.\n\t\t\tconst file = !state.file || state.file.hunks.length > 0 ? openFile(state) : state.file;\n\t\t\tfile.oldPath = cleanPath(raw.slice(4), true);\n\t\t\tif (file.oldPath === null) file.isNew = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith(\"+++ \")) {\n\t\t\tconst file = currentFile(state);\n\t\t\tfile.newPath = cleanPath(raw.slice(4), true);\n\t\t\tif (file.newPath === null) file.isDeleted = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith(\"rename from \")) {\n\t\t\tconst file = currentFile(state);\n\t\t\tfile.isRename = true;\n\t\t\tfile.oldPath = cleanPath(raw.slice(\"rename from \".length), false);\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith(\"rename to \")) {\n\t\t\tconst file = currentFile(state);\n\t\t\tfile.isRename = true;\n\t\t\tfile.newPath = cleanPath(raw.slice(\"rename to \".length), false);\n\t\t\tcontinue;\n\t\t}\n\t\t// A binary add or delete carries no `--- /dev/null` / `+++ /dev/null` to\n\t\t// clear the path the git header already copied onto both sides, so the mode\n\t\t// marker has to do it: `{ isNew: true, oldPath: \"new.bin\" }` is nonsense.\n\t\tif (raw.startsWith(\"new file mode\")) {\n\t\t\tconst file = currentFile(state);\n\t\t\tfile.isNew = true;\n\t\t\tfile.oldPath = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith(\"deleted file mode\")) {\n\t\t\tconst file = currentFile(state);\n\t\t\tfile.isDeleted = true;\n\t\t\tfile.newPath = null;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isBodyLine(raw)) {\n\t\t\topenHunk(state, {\n\t\t\t\theader: \"\",\n\t\t\t\toldStart: 1,\n\t\t\t\toldCount: 0,\n\t\t\t\tnewStart: 1,\n\t\t\t\tnewCount: 0,\n\t\t\t\tlines: [],\n\t\t\t});\n\t\t\tappendBody(state, raw);\n\t\t\tcontinue;\n\t\t}\n\t\t// Index lines, binary notices and prose between files are ignored.\n\t}\n\n\treturn state.files.filter(\n\t\t(file) =>\n\t\t\tfile.hunks.length > 0 ||\n\t\t\tfile.oldPath !== null ||\n\t\t\tfile.newPath !== null ||\n\t\t\tfile.isNew ||\n\t\t\tfile.isDeleted ||\n\t\t\tfile.isRename\n\t);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/diff.ts"},{"path":"react/src/internals/dismissable.ts","content":"\"use client\";\n\n// Calls `onDismiss` when the user presses Escape and/or clicks outside of the\n// node. Both triggers are on by default and can be disabled individually.\n// `exclude` lets callers ignore extra elements that live outside the node but\n// should not count as \"outside\" (e.g. a trigger button that toggles the\n// dismissable element).\n//\n// `attachDismissable` is the framework-free core with the action's exact\n// body; `useDismissable` is the React binding on top of it. The nested-overlay\n// contract — the layer stack, the downward scan past inactive layers, and the\n// order of the `isActive()` guard against `stopImmediatePropagation()` — lives\n// entirely in the core and must not drift.\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport type { ElementRef } from \"./dom/types\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\n\nexport interface DismissableCoreOptions {\n\t/** Called when the node should be dismissed. */\n\tonDismiss: () => void;\n\t/** Whether pressing Escape dismisses. Defaults to true. */\n\tescape?: boolean;\n\t/** Whether a pointerdown outside the node dismisses. Defaults to true. */\n\toutsideClick?: boolean;\n\t/** Elements to ignore when detecting outside clicks (e.g. a trigger button). */\n\texclude?: () => (HTMLElement | null)[];\n\t/**\n\t * Whether this layer is still the live one. A GETTER, not a boolean, and\n\t * read fresh on every Escape and every outside pointerdown, so a layer\n\t * that goes inactive stops answering without anything having to hand the\n\t * core a new value first.\n\t *\n\t * Every overlay that animates its exit passes its `open`. The moment\n\t * `open` flips false the layer stops answering Escape AND stops counting\n\t * as the top layer, so a second Escape during the fade is a no-op and the\n\t * dialog underneath gets it instead of having it swallowed by a panel that\n\t * is already leaving. Defaults to always-active.\n\t */\n\tactive?: () => boolean;\n\t/**\n\t * Whether an outside press that dismisses should keep the focus the\n\t * overlay hands back. Defaults to false. Only an overlay that returns focus\n\t * to a trigger on dismiss passes true (dialog, sheet, drawer, popover, menu,\n\t * command menu). A panel anchored to an input that keeps focus while it is\n\t * open (combobox, autocomplete) leaves it off: there the press must blur\n\t * the input as usual, or the field stays focused, a focus-to-open field\n\t * never reopens on the next click, and a touch keyboard stays up.\n\t *\n\t * With `outsideClick: false` it also keeps focus that is inside the layer\n\t * through an outside press that does not dismiss, so a modal that ignores\n\t * such presses does not lose focus to `<body>`. That case cancels every\n\t * outside mousedown while the layer holds focus, so only a modal layer may\n\t * combine the two: a non-modal one that ignores outside presses (a\n\t * non-dismissible popover) leaves `keepFocus` off and the page untouched.\n\t */\n\tkeepFocus?: boolean;\n}\n\n// Stack of currently mounted dismissable layers. With nested overlays (e.g. a\n// popover inside a dialog) only the top-most layer reacts to Escape or an\n// outside pointerdown, so one interaction closes one layer at a time.\n//\n// A layer stays on this stack for as long as its node is mounted — which, for\n// an overlay that animates its exit, is the whole length of the fade, because\n// the surface is kept mounted through its exit leg. So \"on the stack\" and\n// \"live\" are two different things, and each entry carries its own liveness\n// getter to tell them apart.\ninterface Layer {\n\tnode: HTMLElement;\n\tisActive: () => boolean;\n}\n\nconst layers: Layer[] = [];\n\n// What a mousedown can move focus to by itself. A press on anything else —\n// plain text, a scrim, empty page — makes the browser blur to `<body>`.\nconst FOCUS_TAKING_SELECTOR =\n\t'a[href], area[href], button, input, select, textarea, label, summary, iframe, [tabindex], [contenteditable]:not([contenteditable=\"false\"])';\n\n// An outside press dismisses on `pointerdown`, and an overlay with `keepFocus`\n// hands focus back (to its trigger) right then — but the press's own\n// `mousedown` comes after, and on a target that cannot take focus its default\n// action blurs whatever is focused to `<body>`, undoing the return a moment\n// after it happened. Cancelling that ONE default keeps the returned focus. A\n// press on something focusable is left alone: focus moving there is what the\n// user asked for.\n//\n// The guard must never outlive its press. It disarms on the first of:\n// - mousedown (the default it exists to cancel), click, pointercancel;\n// - contextmenu (a touch long-press can open the menu with neither a click\n//   nor a pointercancel);\n// - a mouse pointerup, one microtask later (a mouse press dispatches its\n//   mousedown before pointerup, so none is coming);\n// - a timeout after a touch or pen pointerup, whose compatibility mousedown\n//   arrives AFTER pointerup and so has to be waited for, but not forever.\nconst TOUCH_MOUSEDOWN_WINDOW_MS = 750;\n\nfunction keepFocusThroughPress(target: Node) {\n\tconst el = target instanceof Element ? target : target.parentElement;\n\tif (el?.closest(FOCUS_TAKING_SELECTOR)) return;\n\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet armed = true;\n\n\tfunction preventBlur(event: Event) {\n\t\tevent.preventDefault();\n\t\tdisarm();\n\t}\n\tfunction handlePointerup(event: Event) {\n\t\tconst pointerType = (event as PointerEvent).pointerType;\n\t\tif (pointerType === \"touch\" || pointerType === \"pen\") {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = setTimeout(disarm, TOUCH_MOUSEDOWN_WINDOW_MS);\n\t\t} else {\n\t\t\tqueueMicrotask(disarm);\n\t\t}\n\t}\n\tfunction disarm() {\n\t\tif (!armed) return;\n\t\tarmed = false;\n\t\tclearTimeout(timer);\n\t\tdocument.removeEventListener(\"mousedown\", preventBlur, true);\n\t\tdocument.removeEventListener(\"click\", disarm, true);\n\t\tdocument.removeEventListener(\"pointercancel\", disarm, true);\n\t\tdocument.removeEventListener(\"contextmenu\", disarm, true);\n\t\tdocument.removeEventListener(\"pointerup\", handlePointerup, true);\n\t}\n\tdocument.addEventListener(\"mousedown\", preventBlur, true);\n\tdocument.addEventListener(\"click\", disarm, true);\n\tdocument.addEventListener(\"pointercancel\", disarm, true);\n\tdocument.addEventListener(\"contextmenu\", disarm, true);\n\tdocument.addEventListener(\"pointerup\", handlePointerup, true);\n}\n\nexport interface DismissableHandle {\n\t/** Swaps the options in place — the action's `update` under a new name. */\n\tupdate(options: DismissableCoreOptions): void;\n\t/** Pops this layer off the stack and detaches the document listeners. */\n\tdestroy(): void;\n}\n\n/**\n * Registers `node` as a dismissable layer and wires the document listeners.\n *\n * SSR-safe: does nothing when `document` is unavailable.\n */\nexport function attachDismissable(\n\tnode: HTMLElement,\n\topts: DismissableCoreOptions\n): DismissableHandle {\n\tif (typeof document === \"undefined\") {\n\t\treturn { update() {}, destroy() {} };\n\t}\n\n\tlet onDismiss = opts.onDismiss;\n\tlet escape = opts.escape ?? true;\n\tlet outsideClick = opts.outsideClick ?? true;\n\tlet exclude = opts.exclude;\n\tlet isActive = opts.active ?? (() => true);\n\tlet keepFocus = opts.keepFocus ?? false;\n\n\t// Scans DOWN past inactive layers rather than testing only the last entry:\n\t// a closing panel is still ON the stack (it stays mounted for its exit),\n\t// it just must not be TOP of it. The first live layer found from the top\n\t// is the one that owns the interaction.\n\tfunction isTopLayer(): boolean {\n\t\tfor (let i = layers.length - 1; i >= 0; i -= 1) {\n\t\t\tconst candidate = layers[i]!;\n\t\t\tif (candidate.isActive()) return candidate.node === node;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction handleKeydown(event: KeyboardEvent) {\n\t\t// Before `stopImmediatePropagation()`, deliberately: an inactive layer\n\t\t// must not swallow the key on its way to whatever is underneath.\n\t\tif (!isActive()) return;\n\t\tif (!escape) return;\n\t\tif (event.key !== \"Escape\") return;\n\t\tif (!isTopLayer()) return;\n\t\tevent.stopImmediatePropagation();\n\t\tonDismiss();\n\t}\n\n\tfunction handlePointerdown(event: PointerEvent) {\n\t\tif (!isActive()) return;\n\t\tif (!outsideClick && !keepFocus) return;\n\t\tif (!isTopLayer()) return;\n\n\t\tconst target = event.target as Node | null;\n\t\tif (!target || node.contains(target)) return;\n\n\t\tconst excluded = exclude?.() ?? [];\n\t\tif (excluded.some((el) => el?.contains(target))) return;\n\n\t\tif (!outsideClick) {\n\t\t\t// A layer that ignores outside presses (an alert dialog) still owns\n\t\t\t// the focus it holds: a press on its scrim or on plain page text\n\t\t\t// must not blur that focus out of the panel to <body>.\n\t\t\tif (node.contains(document.activeElement)) keepFocusThroughPress(target);\n\t\t\treturn;\n\t\t}\n\n\t\tif (keepFocus) keepFocusThroughPress(target);\n\t\tonDismiss();\n\t}\n\n\tconst layer: Layer = { node, isActive: () => isActive() };\n\tlayers.push(layer);\n\tdocument.addEventListener(\"keydown\", handleKeydown);\n\tdocument.addEventListener(\"pointerdown\", handlePointerdown);\n\n\treturn {\n\t\tupdate(newOpts: DismissableCoreOptions) {\n\t\t\tonDismiss = newOpts.onDismiss;\n\t\t\tescape = newOpts.escape ?? true;\n\t\t\toutsideClick = newOpts.outsideClick ?? true;\n\t\t\texclude = newOpts.exclude;\n\t\t\tisActive = newOpts.active ?? (() => true);\n\t\t\tkeepFocus = newOpts.keepFocus ?? false;\n\t\t},\n\t\tdestroy() {\n\t\t\t// Spliced BY IDENTITY, so a StrictMode double cycle\n\t\t\t// (push → splice → push) leaves a stack of one at the same depth.\n\t\t\tconst i = layers.indexOf(layer);\n\t\t\tif (i !== -1) layers.splice(i, 1);\n\t\t\tdocument.removeEventListener(\"keydown\", handleKeydown);\n\t\t\tdocument.removeEventListener(\"pointerdown\", handlePointerdown);\n\t\t},\n\t};\n}\n\n/** Test-only. Not exported from index.ts. */\nexport function __dismissableLayerCount(): number {\n\treturn layers.length;\n}\n\nexport interface DismissableOptions {\n\t/** Called when the node should be dismissed. */\n\tonDismiss: () => void;\n\t/** Escape dismisses. Default true. */\n\tescape?: boolean;\n\t/** A pointerdown outside dismisses. Default true. */\n\toutsideClick?: boolean;\n\t/**\n\t * Elements that do not count as \"outside\" — typically the trigger. An\n\t * array of nodes or refs, resolved at event time, or the getter form for\n\t * a genuinely dynamic set.\n\t */\n\texclude?:\n\t\t| Array<ElementRef<HTMLElement> | HTMLElement | null | undefined>\n\t\t| (() => (HTMLElement | null)[]);\n\t/**\n\t * Whether this layer is still LIVE. Pass the surface's `open`. Default true.\n\t *\n\t * A plain boolean where the core takes a getter: React re-renders the\n\t * still-mounted exiting surface normally, so the hook can hold the current\n\t * value in a live ref and hand the core a getter over it. Semantics are\n\t * unchanged — a layer stays ON the stack for its whole exit and stops\n\t * being TOP of it the instant `active` flips.\n\t */\n\tactive?: boolean;\n\t/**\n\t * Keep the focus the overlay hands back through a dismissing outside press.\n\t * Default false; only an overlay that returns focus to a trigger passes\n\t * true. See the core option of the same name.\n\t */\n\tkeepFocus?: boolean;\n\t/** Whether the layer is registered at all. Default true. */\n\tenabled?: boolean;\n}\n\n/**\n * Dismissable behaviour for `node`.\n *\n * Returns nothing: this hook owns behaviour, not state — nothing it does is\n * rendered, so neither `useState` nor `useSyncExternalStore` has any part in\n * it.\n *\n * A passive effect, not a layout one: the layer push and the two document\n * listeners are invisible in the first painted frame, and no key can be\n * pressed before they land.\n */\nexport function useDismissable(node: HTMLElement | null, options: DismissableOptions): void {\n\tconst {\n\t\tescape = true,\n\t\toutsideClick = true,\n\t\tactive = true,\n\t\tkeepFocus = false,\n\t\tenabled = true,\n\t} = options;\n\n\tconst onDismiss = useEventCallback(options.onDismiss);\n\tconst activeRef = useLiveRef(active);\n\tconst excludeRef = useLiveRef(options.exclude);\n\tconst escapeRef = useLiveRef(escape);\n\tconst outsideClickRef = useLiveRef(outsideClick);\n\tconst keepFocusRef = useLiveRef(keepFocus);\n\n\t// Getter closures over the live refs, with an identity that never changes:\n\t// the layer's `isActive()` and both handlers read the current render's\n\t// values with zero listener churn.\n\tconst getActive = useCallback(() => activeRef.current, [activeRef]);\n\tconst getExclude = useCallback((): (HTMLElement | null)[] => {\n\t\tconst exclude = excludeRef.current;\n\t\tif (!exclude) return [];\n\t\tif (typeof exclude === \"function\") return exclude();\n\t\treturn exclude.map((entry) => (entry && \"current\" in entry ? entry.current : (entry ?? null)));\n\t}, [excludeRef]);\n\n\tconst handleRef = useRef<DismissableHandle | null>(null);\n\n\tuseEffect(() => {\n\t\tif (!node || !enabled) return;\n\n\t\tconst handle = attachDismissable(node, {\n\t\t\tonDismiss,\n\t\t\tescape: escapeRef.current,\n\t\t\toutsideClick: outsideClickRef.current,\n\t\t\texclude: getExclude,\n\t\t\tactive: getActive,\n\t\t\tkeepFocus: keepFocusRef.current,\n\t\t});\n\t\thandleRef.current = handle;\n\n\t\treturn () => {\n\t\t\thandleRef.current = null;\n\t\t\thandle.destroy();\n\t\t};\n\t}, [node, enabled, onDismiss, getActive, getExclude, escapeRef, outsideClickRef, keepFocusRef]);\n\n\t// `escape`, `outsideClick` and `keepFocus` are the options the core holds as\n\t// plain values rather than getters, so a change to any is pushed through\n\t// `update()` — which reassigns locals and touches no listener.\n\tuseEffect(() => {\n\t\thandleRef.current?.update({\n\t\t\tonDismiss,\n\t\t\tescape,\n\t\t\toutsideClick,\n\t\t\texclude: getExclude,\n\t\t\tactive: getActive,\n\t\t\tkeepFocus,\n\t\t});\n\t}, [escape, outsideClick, keepFocus, onDismiss, getActive, getExclude]);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/dismissable.ts"},{"path":"react/src/internals/field.ts","content":"\"use client\";\n\n/**\n * The contract between a FormField and whatever control it wraps.\n *\n * `FormField` owns the id, the label/help/error wiring and the required/\n * disabled flags; every control in this wave (Input, Textarea, Checkbox, ...)\n * reads all of that through `useField()` instead of a caller threading ids\n * and aria attributes by hand. A control mounted outside a `FormField`\n * degrades to `undefined` — it must still work standalone, falling back to\n * its own props, exactly like `ToggleGroupItem` degrades outside a\n * `ToggleGroup`.\n *\n * `FieldContext` below is the frozen surface every other component in this\n * wave was built against — its shape must not change. `createFieldState` is\n * this file's own implementation detail: what `FormField` actually\n * constructs and publishes, and the only thing that changes if the wiring\n * inside `describedBy` ever needs to change.\n */\n\nimport { createContext, createElement, useContext } from \"react\";\nimport type { ReactNode } from \"react\";\n\n/** What a `FormField` publishes to the control (and `Label`) it wraps. */\nexport interface FieldContext {\n\t/**\n\t * The id the labelled control must carry. Pair it with a native\n\t * `for`/`id` association — only meaningful for a control whose *root* is\n\t * one of the elements `<label for>` can target (button, input, meter,\n\t * output, progress, select, textarea). A control whose root is anything\n\t * else (a `<div role=\"radiogroup\">`, say) must use `labelId` below\n\t * instead — `for` cannot reach it, ARIA role or not.\n\t */\n\treadonly controlId: string;\n\t/**\n\t * Id of the rendered `<label>` element, for a control whose root is not\n\t * one `for` can target — point that control's own `aria-labelledby` at\n\t * this instead. `undefined` when `FormField` renders no label of its\n\t * own (no `label` prop given). Optional for the same reason `valid` is —\n\t * see its doc comment.\n\t */\n\treadonly labelId?: string;\n\t/** Space-joined ids of whichever help and error text are actually rendered, or undefined. */\n\treadonly describedBy: string | undefined;\n\treadonly invalid: boolean;\n\t/**\n\t * Whether the field is explicitly marked as passing validation. Never\n\t * `true` while `invalid` is `true` — a control that reads both should\n\t * still treat them as mutually exclusive, but this is the authority on\n\t * that, not an assumption a control has to make itself.\n\t *\n\t * Optional, not required: this was added after four other builders had\n\t * already coded their own controls, harnesses and hand-built\n\t * `FieldContext` object literals against the original five-field shape.\n\t * Making it required would have been a breaking change to a contract\n\t * that was frozen out from under them — every one of those literals\n\t * would fail to type-check the moment this file changed, with none of\n\t * their own files touched to explain why. Optional keeps every existing\n\t * literal valid as-is; `createFieldState`'s own output always populates\n\t * it, so `FormField` itself never has to treat it as absent — only a\n\t * hand-built context that predates this field does, and `undefined`\n\t * there reads the same as `false` to a `field?.valid ?? false` consumer.\n\t */\n\treadonly valid?: boolean;\n\treadonly required: boolean;\n\treadonly disabled: boolean;\n}\n\n/**\n * Inputs `createFieldState` builds a `FieldContext` from. Every entry is a\n * plain value, where the Svelte source takes a getter: React re-renders\n * `FormField` when any of these nine change, and the rebuilt context object\n * is what makes the controls below it re-render. A getter would buy nothing\n * here and would defeat the `useMemo` dependency array documented on\n * `createFieldState`.\n */\nexport interface FieldStateOptions {\n\t/** The id to publish as `controlId`. */\n\tcontrolId: string;\n\t/** The id to publish as `labelId`, or undefined while no label is rendered. */\n\tlabelId: string | undefined;\n\t/** The id the help paragraph carries while it is rendered. */\n\tdescriptionId: string;\n\t/** The id the error paragraph carries while it is rendered. */\n\terrorId: string;\n\t/** Whether the help paragraph is currently rendered. */\n\thasDescription: boolean;\n\t/** Whether the error paragraph is currently rendered. */\n\thasError: boolean;\n\t/** Whether the field is explicitly marked valid. The caller decides how this interacts with `hasError` — see `valid`'s own doc comment on `FieldContext`. */\n\tvalid: boolean;\n\trequired: boolean;\n\tdisabled: boolean;\n}\n\n/**\n * Builds the object `FormField` publishes through `<FieldProvider value={...}>`.\n *\n * `describedBy` is derived, not registered: it is computed from\n * `hasDescription`/`hasError`, the same two flags `FormField`'s own\n * conditionals gate the help/error paragraphs on. That is what keeps the id\n * list honest — a described-by id only ever appears while the element it\n * points at is actually in the DOM, because both are driven by the exact\n * same read, in the exact same render pass. A separate mount/unmount\n * registration written into state would add a step between \"the paragraph is\n * in the DOM\" and \"the id is in the list\" — and that step runs inside\n * `useEffect`, which never fires during SSR, so the very first paint would\n * carry the paragraph without the attribute pointing at it. Deriving\n * directly avoids that entirely: `describedBy` is exactly as correct on the\n * server-rendered HTML as it is after hydration.\n *\n * Pure and framework-free, so `FormField` calls it from a `useMemo` keyed on\n * the nine scalars — a field-by-field dependency array, never the options\n * object, so the identity is stable across unrelated parent re-renders and\n * changes exactly when a consumer must re-render:\n *\n * ```ts\n * const field = useMemo(\n *   () => createFieldState({ controlId, labelId, descriptionId, errorId,\n *     hasDescription, hasError, valid, required, disabled }),\n *   [controlId, labelId, descriptionId, errorId, hasDescription, hasError, valid, required, disabled]\n * );\n * ```\n */\nexport function createFieldState(options: FieldStateOptions): FieldContext {\n\tconst ids: string[] = [];\n\tif (options.hasDescription) ids.push(options.descriptionId);\n\tif (options.hasError) ids.push(options.errorId);\n\n\treturn {\n\t\tcontrolId: options.controlId,\n\t\tlabelId: options.labelId,\n\t\tdescribedBy: ids.length > 0 ? ids.join(\" \") : undefined,\n\t\tinvalid: options.hasError,\n\t\t// Enforced here, not trusted from the caller: `hasError` always wins,\n\t\t// so a control reading `field.valid` never has to also check\n\t\t// `field.invalid` itself to get the \"error still wins\" rule right.\n\t\tvalid: options.valid && !options.hasError,\n\t\trequired: options.required,\n\t\tdisabled: options.disabled,\n\t};\n}\n\n/**\n * The context `FormField` publishes under. Consumers read it only via\n * `useField()`.\n *\n * Its default is `undefined`, which is the whole \"no FormField above me\"\n * case: a control outside a provider reads back exactly what a provider that\n * published `undefined` would have given it.\n */\nexport const FieldReactContext = createContext<FieldContext | undefined>(undefined);\nFieldReactContext.displayName = \"FieldContext\";\n\nexport interface FieldProviderProps {\n\t/** The context object, built by `createFieldState`. */\n\tvalue: FieldContext;\n\tchildren?: ReactNode;\n}\n\n/** Publishes a `FieldContext` to every control rendered beneath it. */\nexport function FieldProvider({ value, children }: FieldProviderProps): ReactNode {\n\treturn createElement(FieldReactContext.Provider, { value }, children);\n}\n\n/** Returns the surrounding FormField's context, or undefined when there is none. */\nexport function useField(): FieldContext | undefined {\n\treturn useContext(FieldReactContext);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/field.ts"},{"path":"react/src/internals/float.ts","content":"\"use client\";\n\n/**\n * Floating element positioning — geometry only.\n *\n * A pure geometry helper that pins a floating box (menu, popover, completion\n * list) to an anchor. The anchor can be a real element's rect or a virtual\n * rect, which is how a caret-following menu is placed.\n *\n * `attachFloat` / `useFloat` (the DOM-observing half) are a separate,\n * hook-carrying unit and are not ported here.\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type FloatPlacement =\n\t| \"top\"\n\t| \"bottom\"\n\t| \"top-start\"\n\t| \"bottom-start\"\n\t| \"top-end\"\n\t| \"bottom-end\";\n\nexport interface FloatRect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\nexport interface FloatSize {\n\twidth: number;\n\theight: number;\n}\n\nexport interface FloatOptions {\n\t/** Real element, a fixed rect, or a getter returning the current rect (caret anchoring). */\n\tanchor: HTMLElement | FloatRect | (() => FloatRect | null);\n\tplacement?: FloatPlacement;\n\toffset?: number;\n\tpadding?: number;\n\t/** Force the float to the anchor's width before measuring. */\n\tmatchWidth?: boolean;\n\tenabled?: boolean;\n}\n\ntype Side = \"top\" | \"bottom\";\ntype Align = \"start\" | \"end\" | \"center\";\n\n// =============================================================================\n// Pure compute\n// =============================================================================\n\nfunction clamp(value: number, min: number, max: number): number {\n\t// When max < min (float larger than the viewport) the min bound wins, so an\n\t// oversized float overflows off the far edge rather than the near one.\n\treturn Math.max(min, Math.min(value, max));\n}\n\nfunction splitPlacement(placement: FloatPlacement): { side: Side; align: Align } {\n\tconst [side, align] = placement.split(\"-\") as [Side, Exclude<Align, \"center\"> | undefined];\n\treturn { side, align: align ?? \"center\" };\n}\n\nfunction joinPlacement(side: Side, align: Align): FloatPlacement {\n\treturn (align === \"center\" ? side : `${side}-${align}`) as FloatPlacement;\n}\n\n/**\n * Resolve the viewport-space position of a floating box against its anchor.\n *\n * Flips to the opposite side only when the requested side cannot hold the float\n * *and* the opposite side has strictly more room. If neither side fits, the\n * larger one is kept — overflowing where the least content is hidden.\n */\nexport function computeFloatPosition(\n\tanchor: FloatRect,\n\tfloat: FloatSize,\n\tviewport: FloatSize,\n\topts: { placement: FloatPlacement; offset: number; padding: number }\n): { top: number; left: number; placement: FloatPlacement } {\n\tconst { offset, padding } = opts;\n\tconst { side, align } = splitPlacement(opts.placement);\n\n\tconst roomBelow = viewport.height - (anchor.y + anchor.height) - offset - padding;\n\tconst roomAbove = anchor.y - offset - padding;\n\tconst wanted = side === \"bottom\" ? roomBelow : roomAbove;\n\tconst opposite = side === \"bottom\" ? roomAbove : roomBelow;\n\tconst flipped = float.height > wanted && opposite > wanted;\n\tconst finalSide: Side = flipped ? (side === \"bottom\" ? \"top\" : \"bottom\") : side;\n\n\tconst top =\n\t\tfinalSide === \"bottom\" ? anchor.y + anchor.height + offset : anchor.y - float.height - offset;\n\tconst left =\n\t\talign === \"start\"\n\t\t\t? anchor.x\n\t\t\t: align === \"end\"\n\t\t\t\t? anchor.x + anchor.width - float.width\n\t\t\t\t: anchor.x + anchor.width / 2 - float.width / 2;\n\n\treturn {\n\t\ttop: clamp(top, padding, viewport.height - float.height - padding),\n\t\tleft: clamp(left, padding, viewport.width - float.width - padding),\n\t\tplacement: joinPlacement(finalSide, align),\n\t};\n}\n","type":"registry:lib","target":"@ui/fancy/internals/float.ts"},{"path":"react/src/internals/focus-trap.ts","content":"\"use client\";\n\n// Traps Tab/Shift+Tab focus cycling within a node.\n//\n// On activation it remembers the previously active element, moves focus to\n// `initialFocus` (or the first focusable descendant), and keeps Tab/Shift+Tab\n// cycling between the first and last focusable descendants. On destroy it\n// restores focus to the previously active element when `returnFocus` is true\n// (the default) — see `fallbackFocus` below for what happens when that\n// element is gone by the time destroy runs.\n//\n// `attachFocusTrap` is the framework-free core: the same body the Svelte\n// action has, with an `{ update, destroy }` handle. `useFocusTrap` is the\n// React binding on top of it, and it mounts in a LAYOUT effect so focus lands\n// before the user's first frame.\n//\n// An overlay that animates its exit does not wait for destroy: the handle\n// carries a function that runs the same return chain at the dismiss instant,\n// and destroy then stands down. It carries a second function that re-arms the\n// trap when the surface comes back, because a reopen during the exit reverses\n// the outro instead of remounting and the trap is therefore never re-created.\n// See `FocusTrapHandle` below for why an animated close cannot use the destroy\n// path, and why the eager return needs an undo.\n//\n// The Svelte action's ordering requirement for callers combining this with a\n// portal — both actions on the same element, portal written first, so the\n// initial `.focus()` never lands on a still-detached subtree — has no React\n// counterpart. `Portal` renders through `createPortal`, which commits children\n// into the container before any effect runs, and refs populate before layout\n// effects, so the node this hook focuses is always connected. The silent-no-op\n// `.focus()` hazard cannot recur here.\n\nimport { useRef } from \"react\";\nimport { useConstant, useIsomorphicLayoutEffect } from \"./dom/ssr\";\nimport type { ElementRef } from \"./dom/types\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\n\nexport interface FocusTrapOptions {\n\t/**\n\t * Element to focus when the trap activates. Defaults to the first focusable\n\t * descendant of node. A ref is resolved at every use rather than at attach\n\t * time, so a target that appears later still wins.\n\t */\n\tinitialFocus?: ElementRef<HTMLElement> | HTMLElement | null;\n\t/**\n\t * Whether to restore focus to the previously active element on destroy.\n\t * Defaults to true. It does NOT govern `returnFocusNow()`: a caller that\n\t * passes `returnFocus: false` and then calls the handle is contradicting\n\t * itself, and the handle wins — asking for the eager return IS asking for\n\t * the return. `returnFocus: false` governs the *unmount* path only.\n\t */\n\treturnFocus?: boolean;\n\t/**\n\t * Called on destroy, but only when the element that had focus before the\n\t * trap activated is no longer in the document — removed by a re-render,\n\t * a list row disappearing, a trigger inside a reordering list. Should\n\t * return a still-connected element to focus instead, typically the\n\t * overlay's own trigger, or `null`/`undefined` to fall through to the last\n\t * resort. Never called while the original element is still connected —\n\t * that element always wins first, unconditionally.\n\t */\n\tfallbackFocus?: () => HTMLElement | null | undefined;\n}\n\n/**\n * The two functions the Svelte side hands out through `onActivate`. Here they\n * are simply RETURNED: a hook can return a value, an action cannot.\n *\n * 1. `returnFocusNow` exists because an animated exit delays the unmount by the\n *    length of the fade. Without it a keyboard user pressing Escape waits\n *    200 ms for focus to come back — and worse, the panel is marked `inert` the\n *    instant the exit starts, which drops focus to `<body>` for that whole\n *    window. It is called at the dismiss instant, from `usePresence`'s\n *    `onExitStart`, which fires on every close path (Escape, outside click,\n *    close button, a caller's own `open` write) and fires before the node goes.\n *\n * 2. `rearm` exists because a surface reopened DURING its exit is not a new\n *    mount: `usePresence` keeps it mounted through the whole exit, so the\n *    effect never re-ran, the initial focus move never re-ran, and the\n *    `returned` latch is still set. Without it the reopened `aria-modal` panel\n *    would be interactive again with focus sitting on the trigger *behind* it\n *    — untrapped, because the Tab handler is bound to the panel — and its next\n *    dismiss would return focus nowhere at all, the handle and the unmount path\n *    both being permanently disarmed for the life of the instance.\n */\nexport interface FocusTrapHandle {\n\t/**\n\t * Runs the three-step return chain IMMEDIATELY and disarms the unmount\n\t * return. Idempotent: calling it twice, or letting the unmount follow it,\n\t * returns focus exactly once.\n\t */\n\treturnFocusNow(): void;\n\t/**\n\t * Undoes that latch and pulls focus back inside, recapturing the element it\n\t * displaced. Called at `onEnterStart` when a surface is reopened mid-exit.\n\t */\n\trearm(): void;\n}\n\nexport interface FocusTrapCoreHandle extends FocusTrapHandle {\n\tupdate(options?: FocusTrapOptions): void;\n\tdestroy(): void;\n}\n\nconst FOCUSABLE_SELECTOR = [\n\t\"button:not([disabled])\",\n\t\"[href]:not([disabled])\",\n\t\"input:not([disabled])\",\n\t\"select:not([disabled])\",\n\t\"textarea:not([disabled])\",\n\t'[tabindex]:not([tabindex=\"-1\"]):not([disabled])',\n].join(\", \");\n\nfunction isVisible(el: HTMLElement): boolean {\n\t// offsetParent/getClientRects are unusable under jsdom, so rely on the\n\t// hidden attribute and computed styles, which jsdom does implement.\n\tif (el.hidden || el.closest(\"[hidden]\") !== null) return false;\n\t// `visibility` INHERITS, so the element's own computed value already\n\t// accounts for a hidden ancestor — and, just as importantly, for a\n\t// descendant that opts back in with `visibility: visible`, which really is\n\t// focusable and must not be filtered out.\n\tif (getComputedStyle(el).visibility === \"hidden\") return false;\n\t// `display` does NOT inherit: a control inside a `display: none` ancestor\n\t// still computes its own `display` as `block`/`inline` and looks perfectly\n\t// visible in isolation, while the whole subtree is absent from the layout\n\t// tree and `.focus()` on it is a silent no-op. Treating it as focusable\n\t// let the trap \"focus\" a control that never took focus — leaving focus\n\t// outside the modal, which is the one thing this module exists to prevent.\n\t// DIVERGENCE from the Svelte source, which checks the control's own style\n\t// only and carries the same hole.\n\tfor (let node: HTMLElement | null = el; node; node = node.parentElement) {\n\t\tif (getComputedStyle(node).display === \"none\") return false;\n\t}\n\treturn true;\n}\n\nfunction radioGroupKey(el: Element): string | null {\n\tif (!(el instanceof HTMLInputElement) || el.type !== \"radio\" || !el.name) return null;\n\treturn el.name;\n}\n\n// Two elements are the same Tab stop when they are the same element or radios\n// of one named group: the browser treats a whole group as ONE stop, so Tab\n// from any of its radios leaves the group in a single step.\nfunction sameTabStop(a: Element | null, b: Element): boolean {\n\tif (a === b) return true;\n\tif (!a) return false;\n\tconst key = radioGroupKey(a);\n\treturn (\n\t\tkey !== null &&\n\t\tkey === radioGroupKey(b) &&\n\t\t(a as HTMLInputElement).form === (b as HTMLInputElement).form\n\t);\n}\n\nfunction getFocusableElements(node: HTMLElement): HTMLElement[] {\n\tconst visible = Array.from(node.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n\t\tisVisible\n\t);\n\t// Collapse every named radio group to the one radio Tab really lands on:\n\t// the checked one, or the first when none is checked. Counting every\n\t// radio made an unchecked radio the trap's \"last\" element while the\n\t// browser's own Tab, sitting on the checked radio, walked straight out of\n\t// the panel without the trap ever seeing its boundary.\n\treturn visible.filter((el) => {\n\t\tif (radioGroupKey(el) === null) return true;\n\t\tconst group = visible.filter((other) => sameTabStop(other, el));\n\t\tconst stop = group.find((radio) => (radio as HTMLInputElement).checked) ?? group[0];\n\t\treturn stop === el;\n\t});\n}\n\n// Where Shift+Tab really lands when it enters `stop`'s Tab stop backwards. A\n// radio group with nothing checked is entered at its LAST radio going\n// backwards (its first going forwards), so a backwards wrap onto such a group\n// has to land there too. Anything else is entered at `stop` itself.\nfunction backwardEntry(node: HTMLElement, stop: HTMLElement): HTMLElement {\n\tif (radioGroupKey(stop) === null || (stop as HTMLInputElement).checked) return stop;\n\tconst group = Array.from(node.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n\t\t(el) => isVisible(el) && sameTabStop(el, stop)\n\t);\n\treturn group[group.length - 1] ?? stop;\n}\n\n/**\n * Unwraps the one option this port widens. The Svelte action takes a raw\n * element because a Svelte template always has one by the time the action\n * runs; a React caller usually holds a ref, and resolving it lazily — here,\n * at every use — is what makes a target that mounts after the trap still win.\n */\nfunction resolveElement(\n\ttarget: ElementRef<HTMLElement> | HTMLElement | null | undefined\n): HTMLElement | null {\n\tif (!target) return null;\n\treturn \"current\" in target ? target.current : target;\n}\n\n/**\n * The framework-free core. Activates the trap on `node` synchronously and\n * returns the handle plus `update`/`destroy`.\n *\n * SSR-safe: does nothing when `document` is unavailable.\n */\nexport function attachFocusTrap(\n\tnode: HTMLElement,\n\topts: FocusTrapOptions = {}\n): FocusTrapCoreHandle {\n\tif (typeof document === \"undefined\") {\n\t\treturn { returnFocusNow() {}, rearm() {}, update() {}, destroy() {} };\n\t}\n\n\tlet returnFocus = opts.returnFocus ?? true;\n\tlet fallbackFocus = opts.fallbackFocus;\n\t// Tracked like the other two rather than read off the original `opts`:\n\t// a caller that retargets the initial focus between form steps updates\n\t// the trap, and `rearm()` below has to honour the CURRENT target, not\n\t// the one this instance happened to mount with.\n\tlet initialFocus = opts.initialFocus;\n\t// Not `const`: this is the element the trap displaced, and a surface\n\t// reopened mid-exit is displacing a different one. `rearm()` recaptures.\n\tlet previouslyFocused = document.activeElement as HTMLElement | null;\n\n\tfunction focusContainerFallback() {\n\t\t// No focusable descendants (empty/loading dialog): contain focus on the\n\t\t// node itself so it does not leak to the page behind the trap.\n\t\tif (!node.hasAttribute(\"tabindex\")) node.setAttribute(\"tabindex\", \"-1\");\n\t\tnode.focus();\n\t}\n\n\tfunction focusInitial(initialFocus: ElementRef<HTMLElement> | HTMLElement | null | undefined) {\n\t\tconst target = resolveElement(initialFocus) ?? getFocusableElements(node)[0] ?? null;\n\t\tif (target) target.focus();\n\t\telse focusContainerFallback();\n\t}\n\n\t// The three-step return chain, extracted so it can be run EAGERLY at the\n\t// dismiss instant (via the handle) as well as at destroy. The latch makes\n\t// it run exactly once whichever path gets there first.\n\tlet returned = false;\n\n\tfunction returnFocus_() {\n\t\t// The latch guards as well as records: the handle may be called more\n\t\t// than once (a reopen mid-exit, a caller being careful), and destroy()\n\t\t// may still follow it. Focus moves exactly once either way.\n\t\tif (returned) return;\n\t\treturned = true;\n\n\t\t// `previouslyFocused` is a raw reference, captured at activation and\n\t\t// recaptured by `rearm()` on a reopen —\n\t\t// `.focus()` on it is the same silent no-op a detached node always\n\t\t// is if whatever it pointed at has since left the document, so it\n\t\t// is checked rather than trusted. Three-step chain, each step only\n\t\t// reached if the one before it failed:\n\t\t//   1. The original element, if it is still connected — the\n\t\t//      common case, unchanged from before this fallback existed.\n\t\t//   2. `fallbackFocus()`, if the caller supplied one and it points\n\t\t//      at a still-connected element — typically the overlay's own\n\t\t//      trigger: a real, findable place for focus to land even\n\t\t//      though it is not literally \"back where it was.\"\n\t\t//   3. `document.body` — always connected, so unlike the previous\n\t\t//      two steps this one cannot fail by being disconnected. It\n\t\t//      still needs a `tabindex` to be programmatically focusable\n\t\t//      at all (the same reason `focusContainerFallback` above\n\t\t//      gives the trap node one) — real browsers implicitly treat\n\t\t//      `<body>` as tabindex=\"-1\" for this purpose, but that\n\t\t//      default is not universal across environments, so it is\n\t\t//      set explicitly rather than assumed. This is a last\n\t\t//      resort, not a good outcome: it clears focus rather than\n\t\t//      pretending some unrelated element is where the user was,\n\t\t//      but it is never nothing — a user's focus should not\n\t\t//      silently vanish.\n\t\tif (previouslyFocused?.isConnected) {\n\t\t\tpreviouslyFocused.focus();\n\t\t\treturn;\n\t\t}\n\t\tconst fallback = fallbackFocus?.();\n\t\tif (fallback?.isConnected) {\n\t\t\tfallback.focus();\n\t\t\treturn;\n\t\t}\n\t\tif (!document.body.hasAttribute(\"tabindex\")) {\n\t\t\tdocument.body.setAttribute(\"tabindex\", \"-1\");\n\t\t}\n\t\tdocument.body.focus();\n\t}\n\n\t// The counterpart to the eager return, run when the surface comes BACK — a\n\t// reopen mid-exit reverses the outro rather than remounting, so this trap,\n\t// and the latch above, survive the aborted close. Clearing the latch\n\t// re-arms both the handle and `destroy()` for the next dismiss; focus is\n\t// pulled back only when it has left the node, which makes the ordinary\n\t// first enter a no-op (focus is already where `focusInitial` just put it)\n\t// and never yanks focus away from a user who has moved it inside the panel\n\t// themselves.\n\tfunction rearm() {\n\t\treturned = false;\n\t\tconst active = document.activeElement as HTMLElement | null;\n\t\tif (node.contains(active)) return;\n\n\t\t// A reopen mid-exit is a NEW opening, and it can come from a different\n\t\t// control than the one that opened the surface the first time. Without\n\t\t// recapturing, the next dismissal would return focus to the original\n\t\t// opener — or fall through to the fallback, if that opener has since\n\t\t// been removed. `document.body` is excluded because it is exactly what\n\t\t// `activeElement` reports while the exiting panel is still `inert`:\n\t\t// adopting it would throw away a perfectly good return target in\n\t\t// favour of one that clears focus.\n\t\tif (active && active !== document.body && active.isConnected) {\n\t\t\tpreviouslyFocused = active;\n\t\t}\n\t\tfocusInitial(initialFocus);\n\t}\n\n\t// No `active` gate on the Tab handler, deliberately. Once the exit starts\n\t// the panel is `inert`, `.focus()` on its descendants is a browser no-op,\n\t// and focus has already been returned by `returnFocusNow()` — so the trap\n\t// has nothing left to trap and needs no flag nobody reads.\n\tfunction handleKeydown(event: KeyboardEvent) {\n\t\tif (event.key !== \"Tab\") return;\n\n\t\tconst focusable = getFocusableElements(node);\n\t\tif (focusable.length === 0) {\n\t\t\tevent.preventDefault();\n\t\t\tfocusContainerFallback();\n\t\t\treturn;\n\t\t}\n\n\t\tconst first = focusable[0]!;\n\t\tconst last = focusable[focusable.length - 1]!;\n\t\tconst active = document.activeElement;\n\n\t\tif (event.shiftKey) {\n\t\t\tif (sameTabStop(active, first) || !node.contains(active)) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tbackwardEntry(node, last).focus();\n\t\t\t}\n\t\t} else if (sameTabStop(active, last) || !node.contains(active)) {\n\t\t\tevent.preventDefault();\n\t\t\tfirst.focus();\n\t\t}\n\t}\n\n\tfocusInitial(initialFocus);\n\tnode.addEventListener(\"keydown\", handleKeydown);\n\n\t// Returned AFTER the initial focus move, so a caller that runs the eager\n\t// return synchronously on the handle still restores the element the trap\n\t// displaced rather than racing it.\n\treturn {\n\t\treturnFocusNow: returnFocus_,\n\t\trearm,\n\t\tupdate(newOpts: FocusTrapOptions = {}) {\n\t\t\treturnFocus = newOpts.returnFocus ?? true;\n\t\t\tfallbackFocus = newOpts.fallbackFocus;\n\t\t\tinitialFocus = newOpts.initialFocus;\n\t\t},\n\t\tdestroy() {\n\t\t\tnode.removeEventListener(\"keydown\", handleKeydown);\n\t\t\t// `returned` disarms this path once the eager handle has already run\n\t\t\t// it — an animated exit calls the handle at the dismiss instant and\n\t\t\t// only gets here when the fade finishes, and focus must move exactly\n\t\t\t// once.\n\t\t\tif (!returnFocus || returned) return;\n\t\t\treturnFocus_();\n\t\t},\n\t};\n}\n\n/**\n * React binding. Pass the node (convention C-1), get back an identity-stable\n * handle that is safe in a dependency array.\n *\n * The trap attaches in a layout effect keyed on `[node]` so focus lands before\n * paint; option changes flow through the core's `update()` instead of\n * re-attaching, so retargeting `initialFocus` between form steps never\n * re-runs the initial focus move.\n */\nexport function useFocusTrap(\n\tnode: HTMLElement | null,\n\toptions: FocusTrapOptions = {}\n): FocusTrapHandle {\n\tconst { initialFocus = null, returnFocus = true } = options;\n\t// Permanently identity-stable, so it can be handed to the core once and\n\t// still call the caller's latest closure.\n\tconst fallbackFocus = useEventCallback(options.fallbackFocus);\n\n\tconst coreRef = useRef<FocusTrapCoreHandle | null>(null);\n\t// Read by the attach effect, which is keyed on `[node]` alone: the options\n\t// in force at the moment the trap arms, without making a changed option\n\t// re-arm it.\n\tconst latest = useLiveRef<FocusTrapOptions>({ initialFocus, returnFocus, fallbackFocus });\n\n\t// One object for the life of the component. `previouslyFocused` is captured\n\t// inside the effect and never in a render-phase ref, which is what makes the\n\t// StrictMode double cycle — attach (focus panel) → cleanup (return focus to\n\t// the trigger) → attach (recapture the trigger, focus panel) — self-healing.\n\tconst handle = useConstant<FocusTrapHandle>(() => ({\n\t\treturnFocusNow() {\n\t\t\tcoreRef.current?.returnFocusNow();\n\t\t},\n\t\trearm() {\n\t\t\tcoreRef.current?.rearm();\n\t\t},\n\t}));\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tif (!node) return;\n\t\tconst core = attachFocusTrap(node, latest.current);\n\t\tcoreRef.current = core;\n\t\treturn () => {\n\t\t\tcoreRef.current = null;\n\t\t\tcore.destroy();\n\t\t};\n\t}, [node, latest]);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tcoreRef.current?.update({ initialFocus, returnFocus, fallbackFocus });\n\t}, [initialFocus, returnFocus, fallbackFocus]);\n\n\treturn handle;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/focus-trap.ts"},{"path":"react/src/internals/host.ts","content":"\"use client\";\n\n/**\n * The two scraps of text that identify a cited document on screen: the host it\n * came from, and the single character that stands in for a favicon.\n *\n * Loading a real favicon would mean a request to the cited site from every\n * reader's browser, which is a tracking beacon nobody asked for and a broken\n * image the moment the site is gone. A letter drawn from the host says the same\n * thing, costs nothing, and cannot fail.\n *\n * Every citation surface — source cards, the collapsed sources pill, search\n * result rows — reads hosts through here, so a `www.` is stripped and a\n * scheme-less fixture is parsed the same way everywhere. Internal: not exported\n * from the package.\n */\n\n/**\n * The host of a URL with any `www.` prefix removed, or an empty string when\n * there is no host to show.\n *\n * `new URL` is the parser of record; the regex behind it only exists for the\n * protocol-relative and scheme-less strings it rejects (`//docs.example.dev/x`,\n * `docs.example.dev/x`), which turn up constantly in hand-written fixtures and\n * in model output.\n *\n * `undefined` is accepted rather than merely typed away: the data reaching these\n * components comes off the wire, where an optional field is a real possibility\n * whatever the interface says.\n */\nexport function hostOf(url: string | undefined): string {\n\tif (typeof url !== \"string\" || url === \"\") return \"\";\n\n\ttry {\n\t\treturn stripWww(new URL(url).hostname);\n\t} catch {\n\t\tconst match = /^(?:[a-z][a-z0-9+.-]*:)?(?:\\/\\/)?([^/?#\\s]+)/i.exec(url);\n\t\tif (!match) return \"\";\n\t\t// Whatever is left has to look like a host, or we are just echoing the\n\t\t// path of a relative link back at the reader. Group 1 exists: `match`\n\t\t// was checked truthy on the line above and the pattern has one group.\n\t\tconst host = match[1]!.split(\"@\").pop() as string;\n\t\treturn host.includes(\".\") ? stripWww(host) : \"\";\n\t}\n}\n\n/**\n * The character in a monogram circle: the first letter or digit of the text,\n * upper-cased, falling back to a question mark so the circle is never empty.\n *\n * First letter or digit rather than first character, because a title that opens\n * with a quote or a bullet would otherwise put punctuation in the circle. The\n * `u` flag is what keeps a character outside the BMP whole instead of matching\n * half a surrogate pair.\n */\nexport function monogram(text: string | undefined): string {\n\tconst match = /[\\p{L}\\p{N}]/u.exec(text ?? \"\");\n\tconst upper = (match?.[0] ?? \"?\").toUpperCase();\n\t// A few letters upper-case into more than one character — \"ß\" becomes \"SS\" —\n\t// and this has one glyph's worth of room. The original stands in those cases:\n\t// a lone \"ß\" reads better than half of \"SS\".\n\treturn [...upper].length > 1 ? (match?.[0] ?? \"?\") : upper;\n}\n\nfunction stripWww(host: string): string {\n\treturn host.replace(/^www\\./i, \"\");\n}\n","type":"registry:lib","target":"@ui/fancy/internals/host.ts"},{"path":"react/src/internals/listbox.ts","content":"\"use client\";\n\n/**\n * Listbox keyboard-navigation core: which option is \"active\" (highlighted,\n * `aria-activedescendant`-pointed-at) as arrow keys, Home/End and typeahead\n * move through a flat list of options, some of which may be disabled.\n *\n * This is the frozen surface `Select`, `Combobox`, `Autocomplete` and\n * `TimePicker` all consume, so every one of them gets the same two behaviours\n * right once instead of four times:\n *\n * - A run of consecutive disabled options is skipped as a block, not one\n *   step into a dead end — `move`/`moveToEdge` keep stepping past them. If\n *   *every* option is disabled, stepping terminates after at most `count()`\n *   attempts rather than looping forever hunting for an enabled option that\n *   does not exist.\n * - Typeahead accumulates characters typed within a short window and resets\n *   after it, so \"ne\" lands on \"Netherlands\" rather than re-matching \"e\"\n *   against everything. Repeating the same character cycles through the\n *   matches for that character, one per press, the way a native `<select>`\n *   does.\n *\n * Pure state + behaviour, no DOM: a caller wires `count`/`enabled` off\n * whatever it renders (a data array for `Select`, live DOM children for a\n * `Combobox` built on real elements) and reacts to `onActiveChange` to keep\n * the active row in view.\n *\n * `createListbox` is framework-free and stays the tested surface. `useListbox`\n * is the thin React binding on top: one store per mount, `destroy()` on\n * unmount, and `activeIndex` read through `useSyncExternalStore` because this\n * is the one index in the internals that genuinely has to drive rendering\n * (`aria-activedescendant` on the listbox, `isActive(index)` on every row).\n */\n\nimport { useCallback, useEffect, useMemo, useSyncExternalStore } from \"react\";\nimport { useConstant } from \"./dom/ssr\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\n\nexport interface ListboxOptions {\n\t/** Number of options currently rendered. */\n\tcount: () => number;\n\t/** Whether the option at this index can be activated. */\n\tenabled?: (index: number) => boolean;\n\t/** Called when the active option changes, so the caller can scroll it into view. */\n\tonActiveChange?: (index: number) => void;\n\t/** Whether arrow navigation wraps at the ends. Defaults to true. */\n\tloop?: boolean;\n}\n\nexport interface ListboxState {\n\t/** Index of the active option, or -1 when nothing is active. */\n\treadonly activeIndex: number;\n\t/** Moves by delta, skipping disabled options, wrapping when `loop`. `delta === 0` is a no-op. */\n\tmove(delta: number): void;\n\t/** Jumps to the first or last enabled option. */\n\tmoveToEdge(edge: \"first\" | \"last\"): void;\n\t/** Sets the active option directly; -1 clears it. A disabled index is left alone (no-op), never activated. */\n\tsetActive(index: number): void;\n\t/** Advances typeahead with a printable character and activates the match. */\n\ttypeahead(char: string, labelAt: (index: number) => string): void;\n\t/** Clears the typeahead buffer and any pending timer. Call from teardown. */\n\tdestroy(): void;\n\t/**\n\t * Added for React, standing in for the Svelte `$state` rune: notifies on\n\t * every `activeIndex` change. Returns the unsubscribe.\n\t */\n\tsubscribe(listener: () => void): () => void;\n}\n\n/** No candidate could be found — every reachable option was disabled, or the edge was reached without `loop`. */\nconst NONE = null;\n\n// How long a typeahead buffer stays open for the next character before a\n// fresh keystroke starts a new search. Matches the ~500ms window most\n// platforms use for native <select> typeahead.\nconst TYPEAHEAD_TIMEOUT_MS = 500;\n\n/**\n * Walks from `from` in `direction`, skipping disabled options (and, without\n * `loop`, stopping dead at the edge instead of wrapping), and returns the\n * first enabled index it finds. Bounded to `count` attempts — the loop\n * cannot run more steps than there are options, so a list where every option\n * is disabled terminates instead of spinning forever.\n */\nfunction findNext(\n\tfrom: number,\n\tdirection: 1 | -1,\n\tcount: number,\n\tloop: boolean,\n\tisEnabled: (index: number) => boolean\n): number | typeof NONE {\n\tlet idx = from;\n\tfor (let attempts = 0; attempts < count; attempts++) {\n\t\tidx += direction;\n\t\tif (loop) {\n\t\t\tidx = ((idx % count) + count) % count;\n\t\t} else if (idx < 0 || idx >= count) {\n\t\t\treturn NONE;\n\t\t}\n\t\tif (isEnabled(idx)) return idx;\n\t}\n\treturn NONE;\n}\n\nexport function createListbox(options: ListboxOptions): ListboxState {\n\tlet activeIndex = -1;\n\tlet buffer = \"\";\n\tlet timer: ReturnType<typeof setTimeout> | null = null;\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify(): void {\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\tfunction subscribe(listener: () => void): () => void {\n\t\tlisteners.add(listener);\n\t\treturn () => {\n\t\t\tlisteners.delete(listener);\n\t\t};\n\t}\n\n\tfunction isEnabled(index: number): boolean {\n\t\treturn options.enabled?.(index) ?? true;\n\t}\n\n\tfunction commitActive(index: number): void {\n\t\tif (index === activeIndex) return;\n\t\tactiveIndex = index;\n\t\tnotify();\n\t\toptions.onActiveChange?.(index);\n\t}\n\n\tfunction setActive(index: number): void {\n\t\t// -1 always clears — there is nothing to check \"enabled\" for on\n\t\t// \"nothing active\". Any other index that resolves to a disabled\n\t\t// option is left alone rather than activated: `move`, `moveToEdge`\n\t\t// and `typeahead` already never land on a disabled option themselves\n\t\t// (each walks past one to find a real candidate before ever calling\n\t\t// `commitActive`) — `setActive` was the one way in that skipped this\n\t\t// check, so a caller handing it a bad index directly (a stale\n\t\t// fallback, an unchecked default) could still activate one. No\n\t\t// skip-to-nearest here: unlike a relative `move`, a direct\n\t\t// `setActive(index)` call carries no implied direction to hunt a\n\t\t// substitute in, so the safe answer is to do nothing rather than\n\t\t// guess one.\n\t\t//\n\t\t// Bounds come first, before `enabled` is consulted at all: an index\n\t\t// outside `0..count()-1` names no option, so there is nothing for a\n\t\t// caller-supplied `enabled(index)` to answer about — it would be asked\n\t\t// about a row that does not exist, and a permissive predicate (the\n\t\t// default `?? true`) would wave it straight through to\n\t\t// `commitActive`. Publishing it puts an option id with no matching\n\t\t// row in `aria-activedescendant`, which a screen reader reads as a\n\t\t// dangling reference. `move`, `moveToEdge` and `typeahead` are all\n\t\t// bounded by `count()` already; `setActive` is the one way in that\n\t\t// takes an index from outside the module.\n\t\tif (index !== -1) {\n\t\t\tconst count = options.count();\n\t\t\tif (index < 0 || index >= count) return;\n\t\t\tif (!isEnabled(index)) return;\n\t\t}\n\t\tcommitActive(index);\n\t}\n\n\tfunction move(delta: number): void {\n\t\tif (delta === 0) return;\n\t\tconst count = options.count();\n\t\tif (count <= 0) return;\n\t\tconst loop = options.loop ?? true;\n\t\tconst direction: 1 | -1 = delta >= 0 ? 1 : -1;\n\t\tconst steps = Math.abs(delta);\n\n\t\t// -1 (nothing active) is not a real position to step away from: it\n\t\t// reads as \"one before the first option\" for a forward move and \"one\n\t\t// after the last\" for a backward one, so the very first arrow press\n\t\t// from an unset state lands on index 0 (ArrowDown) or the last index\n\t\t// (ArrowUp) — the platform convention this module exists to reproduce,\n\t\t// not on whatever `findNext` would make of stepping away from -1\n\t\t// itself.\n\t\tlet from = activeIndex === -1 ? (direction === 1 ? -1 : count) : activeIndex;\n\n\t\tlet found: number | typeof NONE = NONE;\n\t\tfor (let i = 0; i < steps; i++) {\n\t\t\tconst next = findNext(found ?? from, direction, count, loop, isEnabled);\n\t\t\tif (next === NONE) break;\n\t\t\tfound = next;\n\t\t}\n\n\t\tif (found !== NONE) commitActive(found);\n\t}\n\n\tfunction moveToEdge(edge: \"first\" | \"last\"): void {\n\t\tconst count = options.count();\n\t\tif (count <= 0) return;\n\n\t\tif (edge === \"first\") {\n\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\tif (isEnabled(i)) {\n\t\t\t\t\tcommitActive(i);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = count - 1; i >= 0; i--) {\n\t\t\tif (isEnabled(i)) {\n\t\t\t\tcommitActive(i);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction clearBuffer(): void {\n\t\tbuffer = \"\";\n\t\tif (timer !== null) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = null;\n\t\t}\n\t}\n\n\tfunction typeahead(char: string, labelAt: (index: number) => string): void {\n\t\tconst count = options.count();\n\t\tif (count <= 0) return;\n\t\tconst lower = char.toLowerCase();\n\n\t\t// A run of presses of the SAME character, with nothing else typed in\n\t\t// between, is the platform's cycle-through-matches gesture rather than\n\t\t// a fresh multi-character query — \"nn\" searches for options starting\n\t\t// with \"n\" a second time, past the one already active, instead of\n\t\t// literally matching the two-letter string \"nn\". Any other character\n\t\t// breaks the run and starts accumulating a real query instead.\n\t\tconst isRepeatChar = buffer.length > 0 && [...buffer].every((c) => c === lower);\n\n\t\tif (timer !== null) clearTimeout(timer);\n\t\ttimer = setTimeout(clearBuffer, TYPEAHEAD_TIMEOUT_MS);\n\n\t\tif (isRepeatChar) {\n\t\t\t// Collapsed to the single repeated character, not appended — this\n\t\t\t// is the deliberate choice for what happens next if a DIFFERENT\n\t\t\t// character breaks the cycle (see below), not an incidental detail.\n\t\t\tbuffer = lower;\n\t\t\t// Search strictly after the active option, wrapping once all the\n\t\t\t// way around back to it, so repeated presses cycle through every\n\t\t\t// match instead of re-selecting the first one forever.\n\t\t\tfor (let i = 1; i <= count; i++) {\n\t\t\t\tconst candidate = (activeIndex + i + count) % count;\n\t\t\t\tif (!isEnabled(candidate)) continue;\n\t\t\t\tif (labelAt(candidate).toLowerCase().startsWith(lower)) {\n\t\t\t\t\tcommitActive(candidate);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Deliberate decision, not an accident of the collapse above: breaking\n\t\t// a same-character cycle with a different character continues from\n\t\t// that cycle's single collapsed character, not the literal keystroke\n\t\t// history. Pressing \"s\" three times (cycling through \"s\" matches)\n\t\t// then \"e\" searches for \"se\" — the same as if \"s\" had only been\n\t\t// pressed once — not the literal four-keystroke \"sse\". The\n\t\t// alternative (tracking every keystroke verbatim) would almost always\n\t\t// produce a query nothing matches, since cycling exists specifically\n\t\t// to revisit single-character matches rather than build a longer one;\n\t\t// \"se\" is at least a plausible two-character query the way \"sse\"\n\t\t// rarely is.\n\t\tbuffer += lower;\n\t\tconst query = buffer;\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tif (!isEnabled(i)) continue;\n\t\t\tif (labelAt(i).toLowerCase().startsWith(query)) {\n\t\t\t\tcommitActive(i);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction destroy(): void {\n\t\tclearBuffer();\n\t}\n\n\treturn {\n\t\tget activeIndex() {\n\t\t\treturn activeIndex;\n\t\t},\n\t\tmove,\n\t\tmoveToEdge,\n\t\tsetActive,\n\t\ttypeahead,\n\t\tdestroy,\n\t\tsubscribe,\n\t};\n}\n\nexport interface UseListboxOptions {\n\t/**\n\t * A plain number. The hook wraps it in a live ref and hands the factory the\n\t * getter it expects, so a virtualised list that changes `count` between\n\t * renders is honoured at call time exactly as in Svelte.\n\t */\n\tcount: number;\n\t/** Whether the option at this index can be activated. Read on every call, so an inline literal is fine. */\n\tenabled?: (index: number) => boolean;\n\t/** Called when the active option changes, so the caller can scroll it into view. */\n\tonActiveChange?: (index: number) => void;\n\t/** Whether arrow navigation wraps at the ends. Defaults to true. */\n\tloop?: boolean;\n}\n\nexport interface ListboxHandle {\n\t/** The active option for THIS render, or -1. */\n\treadonly activeIndex: number;\n\t/** Moves by delta, skipping disabled options, wrapping when `loop`. `delta === 0` is a no-op. */\n\tmove(delta: number): void;\n\t/** Jumps to the first or last enabled option. */\n\tmoveToEdge(edge: \"first\" | \"last\"): void;\n\t/** Sets the active option directly; -1 clears it. A disabled index is left alone (no-op), never activated. */\n\tsetActive(index: number): void;\n\t/** Advances typeahead with a printable character and activates the match. */\n\ttypeahead(char: string, labelAt: (index: number) => string): void;\n}\n\n// -1 is the value the module starts at on both sides, so the server and the\n// hydration render agree that nothing is active.\nconst getServerSnapshot = () => -1;\n\n/**\n * One store per mount, `destroy()` on unmount — the consumer cannot forget the\n * teardown the way a component wiring the factory by hand could.\n *\n * `count`, `enabled`, `onActiveChange` and `loop` are all read at call time\n * from live refs, so passing them as plain values (or as inline literals that\n * change identity every render) behaves exactly like the Svelte call sites'\n * getter objects. The store is never rebuilt, so the buffered typeahead and\n * the active index survive every re-render.\n *\n * Only the returned object's identity changes, and only when `activeIndex`\n * does; the four methods are stable for the life of the component.\n */\nexport function useListbox(options: UseListboxOptions): ListboxHandle {\n\tconst countRef = useLiveRef(options.count);\n\tconst enabledRef = useLiveRef(options.enabled);\n\tconst loopRef = useLiveRef(options.loop);\n\tconst onActiveChange = useEventCallback(options.onActiveChange);\n\n\tconst store = useConstant(() =>\n\t\tcreateListbox({\n\t\t\tcount: () => countRef.current,\n\t\t\tenabled: (index) => enabledRef.current?.(index) ?? true,\n\t\t\tonActiveChange,\n\t\t\tget loop() {\n\t\t\t\treturn loopRef.current;\n\t\t\t},\n\t\t})\n\t);\n\n\tuseEffect(() => () => store.destroy(), [store]);\n\n\tconst getSnapshot = useCallback(() => store.activeIndex, [store]);\n\tconst activeIndex = useSyncExternalStore(store.subscribe, getSnapshot, getServerSnapshot);\n\n\treturn useMemo(\n\t\t() => ({\n\t\t\tactiveIndex,\n\t\t\tmove: store.move,\n\t\t\tmoveToEdge: store.moveToEdge,\n\t\t\tsetActive: store.setActive,\n\t\t\ttypeahead: store.typeahead,\n\t\t}),\n\t\t[activeIndex, store]\n\t);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/listbox.ts"},{"path":"react/src/internals/markdown.ts","content":"\"use client\";\n\n/**\n * A deliberately small markdown reader for chat / assistant message surfaces.\n *\n * It produces a token tree, never a string of HTML: the renderer walks the\n * tokens with plain Svelte markup, so anything that is not an explicitly\n * supported construct ends up as escaped text instead of live markup.\n *\n * Supported: paragraphs, ATX headings, fenced code, flat lists, blockquotes,\n * thematic breaks, pipe tables, and inline strong / em / del / code / link.\n * Everything else (nested lists, setext headings, images, raw HTML, autolinks,\n * footnotes) degrades to text rather than being parsed.\n *\n * Every entry point is total: it returns a value for any input, including\n * half-written markdown from a stream.\n *\n * The non-null assertions below are all of one kind: an index read inside a\n * loop already bounded by `i < lines.length` / `i < src.length`, or a capture\n * group of a regex whose match was checked truthy on the line above. Every\n * invariant is visible next to the assertion that relies on it.\n */\n\nexport type InlineToken =\n\t| { type: \"text\"; text: string }\n\t| { type: \"code\"; text: string }\n\t| { type: \"strong\" | \"em\" | \"del\"; children: InlineToken[] }\n\t| { type: \"link\"; href: string | null; children: InlineToken[] };\n\nexport type TableAlign = \"left\" | \"center\" | \"right\" | null;\n\nexport type BlockToken =\n\t| { type: \"paragraph\"; children: InlineToken[] }\n\t| { type: \"heading\"; depth: 1 | 2 | 3 | 4 | 5 | 6; children: InlineToken[] }\n\t| { type: \"code\"; lang: string; text: string }\n\t| { type: \"list\"; ordered: boolean; start: number; items: InlineToken[][] }\n\t| { type: \"blockquote\"; children: BlockToken[] }\n\t| { type: \"table\"; align: TableAlign[]; header: InlineToken[][]; rows: InlineToken[][][] }\n\t| { type: \"hr\" };\n\nconst ALLOWED_SCHEMES = new Set([\"http\", \"https\", \"mailto\"]);\nconst ESCAPABLE = \"\\\\`*_{}[]()#+-.!>~|\";\nconst MAX_INLINE_DEPTH = 12;\nconst MAX_BLOCK_DEPTH = 8;\n// Scan bounds. Without them a crafted run of openers (\"[[[[…]\", \"[a](\" repeated)\n// makes every bracket re-scan to end-of-input — quadratic on a parser that chat\n// surfaces re-run on every streamed token. 999 is CommonMark's own label limit.\nconst MAX_LINK_LABEL = 999;\nconst MAX_LINK_DEST = 2048;\nconst MAX_INPUT = 100_000;\n\nconst RE_HR = /^ {0,3}-{3,}[ \\t]*$/;\nconst RE_HEADING = /^ {0,3}(#{1,6})(?:[ \\t]+(.*))?$/;\nconst RE_QUOTE = /^ {0,3}>/;\nconst RE_QUOTE_STRIP = /^ {0,3}> ?/;\nconst RE_BULLET = /^ {0,3}([-*])(?:[ \\t]+(.*))?$/;\nconst RE_ORDERED = /^ {0,3}(\\d{1,9})[.)](?:[ \\t]+(.*))?$/;\nconst RE_ALIGN_CELL = /^:?-+:?$/;\n\n/**\n * Strips an ATX closing hash sequence (\"## title ##\" → \"title\") in linear time.\n * A regex here backtracks quadratically on crafted space/hash runs, which\n * matters because chat surfaces re-parse on every streamed token.\n */\nfunction stripClosingHashes(raw: string): string {\n\tconst content = raw.trimEnd();\n\tlet end = content.length;\n\twhile (end > 0 && content[end - 1] === \"#\") end--;\n\tif (end === content.length) return content;\n\tif (end === 0) return \"\";\n\tconst before = content[end - 1];\n\tif (before === \" \" || before === \"\\t\") return content.slice(0, end).trimEnd();\n\treturn content;\n}\n\n/**\n * Returns a URL safe to put in an `href`, or `null` when the scheme is not one\n * we are willing to link to. Entities are never decoded first — a browser\n * decodes them after the attribute is set, so decoding here would let\n * `&#106;avascript:` through a check that the raw string fails.\n */\nexport function sanitizeHref(raw: string): string | null {\n\tif (typeof raw !== \"string\") return null;\n\t// A scheme can hide behind characters the URL parser ignores\n\t// (\"java\\nscript:\"), so they go before the scheme is read.\n\tconst cleaned = raw.replace(/^[\\u0000-\\u0020]+/, \"\").replace(/[\\u0000-\\u001F\\u007F]/g, \"\");\n\tif (cleaned === \"\") return null;\n\tconst scheme = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(cleaned);\n\tif (scheme && !ALLOWED_SCHEMES.has(scheme[1]!.toLowerCase())) return null;\n\treturn cleaned;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Inline                                                                     */\n/* -------------------------------------------------------------------------- */\n\nexport function parseInline(src: string): InlineToken[] {\n\treturn parseInlineAt(typeof src === \"string\" ? src : \"\", 0, false);\n}\n\n/**\n * `inLink` is true while parsing a link's own label. CommonMark forbids a link\n * inside a link, and so does the DOM: nested `<a>` elements are repaired by the\n * HTML parser, so SSR markup and the client's hydration tree would disagree.\n */\nfunction parseInlineAt(src: string, depth: number, inLink: boolean): InlineToken[] {\n\tif (src === \"\") return [];\n\tif (depth > MAX_INLINE_DEPTH) return [{ type: \"text\", text: src }];\n\n\tconst out: InlineToken[] = [];\n\tlet buf = \"\";\n\tlet i = 0;\n\n\t// Monotonic caches of the next \"]\" / \")\" at/after the cursor (-1 = none\n\t// ahead, -2 = not looked yet). A link can only succeed past a \"]\" AND a \")\",\n\t// so floods of bare \"[\" or \"[a](\" cost one forward scan total instead of one\n\t// full label/destination scan per opener.\n\tlet nextClose = -2;\n\tlet nextParen = -2;\n\tfunction hasCloseAhead(from: number): boolean {\n\t\tif (nextClose === -1) return false;\n\t\tif (nextClose < from) nextClose = src.indexOf(\"]\", from);\n\t\treturn nextClose !== -1;\n\t}\n\tfunction hasParenAhead(from: number): boolean {\n\t\tif (nextParen === -1) return false;\n\t\tif (nextParen < from) nextParen = src.indexOf(\")\", from);\n\t\treturn nextParen !== -1;\n\t}\n\t// Backtick run lengths that already failed to find a closer (see \"`\" branch).\n\tlet failedSpanRuns: Set<number> | null = null;\n\t// End of the \"*\" run the cursor is currently inside. A run that opens no\n\t// emphasis is walked one character at a time, and counting the rest of the run\n\t// again at each step is quadratic — an 80k run of asterisks would stall the\n\t// thread. The cursor only moves forward, so one forward scan per run is enough.\n\tlet starRunEnd = -1;\n\tfunction starRun(from: number): number {\n\t\tif (from >= starRunEnd) {\n\t\t\tlet end = from;\n\t\t\twhile (src[end] === \"*\") end++;\n\t\t\tstarRunEnd = end;\n\t\t}\n\t\treturn starRunEnd - from;\n\t}\n\n\tfunction flush() {\n\t\tif (buf !== \"\") {\n\t\t\tout.push({ type: \"text\", text: buf });\n\t\t\tbuf = \"\";\n\t\t}\n\t}\n\n\twhile (i < src.length) {\n\t\tconst c = src[i];\n\n\t\tif (c === \"\\\\\" && i + 1 < src.length && ESCAPABLE.includes(src[i + 1]!)) {\n\t\t\tbuf += src[i + 1];\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (c === \"`\") {\n\t\t\tlet runEnd = i + 1;\n\t\t\twhile (runEnd < src.length && src[runEnd] === \"`\") runEnd++;\n\t\t\tconst runLen = runEnd - i;\n\t\t\t// A span can only open on a full backtick run, and a run length that\n\t\t\t// found no closer once will never find one later — so a failed run is\n\t\t\t// consumed whole and its length remembered, keeping bare-run floods\n\t\t\t// linear instead of one full rescan per backtick.\n\t\t\tif (!failedSpanRuns?.has(runLen)) {\n\t\t\t\tconst span = matchCodeSpan(src, i);\n\t\t\t\tif (span) {\n\t\t\t\t\tflush();\n\t\t\t\t\tout.push({ type: \"code\", text: span.text });\n\t\t\t\t\ti = span.end;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t(failedSpanRuns ??= new Set()).add(runLen);\n\t\t\t}\n\t\t\tbuf += src.slice(i, runEnd);\n\t\t\ti = runEnd;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Images are out of scope: keep the alt text, drop the reference.\n\t\tif (c === \"!\" && src[i + 1] === \"[\" && hasCloseAhead(i + 1) && hasParenAhead(i + 1)) {\n\t\t\tconst image = matchLink(src, i + 1);\n\t\t\tif (image) {\n\t\t\t\tflush();\n\t\t\t\tout.push(...parseInlineAt(image.label, depth + 1, inLink));\n\t\t\t\ti = image.end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Inside a label the \"[\" falls through to text, which degrades the inner\n\t\t// link to its literal source rather than nesting an anchor.\n\t\tif (c === \"[\" && !inLink && hasCloseAhead(i) && hasParenAhead(i)) {\n\t\t\tconst link = matchLink(src, i);\n\t\t\tif (link) {\n\t\t\t\tflush();\n\t\t\t\tout.push({\n\t\t\t\t\ttype: \"link\",\n\t\t\t\t\thref: sanitizeHref(link.dest),\n\t\t\t\t\tchildren: parseInlineAt(link.label, depth + 1, true),\n\t\t\t\t});\n\t\t\t\ti = link.end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (c === \"*\") {\n\t\t\tconst emphasis = matchEmphasis(src, i, starRun(i));\n\t\t\tif (emphasis) {\n\t\t\t\tflush();\n\t\t\t\tout.push({\n\t\t\t\t\ttype: emphasis.strong ? \"strong\" : \"em\",\n\t\t\t\t\tchildren: parseInlineAt(emphasis.inner, depth + 1, inLink),\n\t\t\t\t});\n\t\t\t\ti = emphasis.end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (c === \"~\" && src[i + 1] === \"~\") {\n\t\t\tconst close = findCloser(src, i + 2, \"~~\");\n\t\t\tif (close > i + 2) {\n\t\t\t\tflush();\n\t\t\t\tout.push({\n\t\t\t\t\ttype: \"del\",\n\t\t\t\t\tchildren: parseInlineAt(src.slice(i + 2, close), depth + 1, inLink),\n\t\t\t\t});\n\t\t\t\ti = close + 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tbuf += c;\n\t\ti++;\n\t}\n\n\tflush();\n\treturn out;\n}\n\n/** Length of the run of `ch` starting at `i`. */\nfunction countRun(src: string, i: number, ch: string): number {\n\tlet run = 0;\n\twhile (src[i + run] === ch) run++;\n\treturn run;\n}\n\n/** Index of the next `delim` at this nesting level, or -1. */\nfunction findCloser(src: string, from: number, delim: string): number {\n\tlet i = from;\n\twhile (i < src.length) {\n\t\tconst c = src[i];\n\t\tif (c === \"\\\\\") {\n\t\t\ti += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"`\") {\n\t\t\tconst span = matchCodeSpan(src, i);\n\t\t\tif (span) {\n\t\t\t\ti = span.end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif (src.startsWith(delim, i)) return i;\n\t\ti++;\n\t}\n\treturn -1;\n}\n\nfunction matchCodeSpan(src: string, i: number): { text: string; end: number } | null {\n\tlet run = 0;\n\twhile (src[i + run] === \"`\") run++;\n\tconst open = i + run;\n\tlet j = open;\n\twhile (j < src.length) {\n\t\tif (src[j] !== \"`\") {\n\t\t\tj++;\n\t\t\tcontinue;\n\t\t}\n\t\tlet close = 0;\n\t\twhile (src[j + close] === \"`\") close++;\n\t\tif (close === run) return { text: normalizeCodeSpan(src.slice(open, j)), end: j + close };\n\t\tj += close;\n\t}\n\treturn null;\n}\n\nfunction normalizeCodeSpan(raw: string): string {\n\tconst text = raw.replace(/\\r?\\n/g, \" \");\n\tif (text.length > 2 && text.startsWith(\" \") && text.endsWith(\" \") && text.trim() !== \"\") {\n\t\treturn text.slice(1, -1);\n\t}\n\treturn text;\n}\n\nfunction matchEmphasis(\n\tsrc: string,\n\ti: number,\n\t// Length of the \"*\" run starting at `i`. The caller already knows it while\n\t// walking a run, and recounting it here is what makes a long run quadratic.\n\trun = countRun(src, i, \"*\")\n): { strong: boolean; inner: string; end: number } | null {\n\tif (run >= 3) {\n\t\tconst close = findCloser(src, i + 3, \"***\");\n\t\t// Re-wrapping in single markers lets the recursive pass build em-in-strong.\n\t\tif (close > i + 3) {\n\t\t\treturn { strong: true, inner: `*${src.slice(i + 3, close)}*`, end: close + 3 };\n\t\t}\n\t}\n\tif (run >= 2) {\n\t\tconst close = findCloser(src, i + 2, \"**\");\n\t\tif (close > i + 2) return { strong: true, inner: src.slice(i + 2, close), end: close + 2 };\n\t}\n\tconst close = findCloser(src, i + 1, \"*\");\n\tif (close > i + 1) return { strong: false, inner: src.slice(i + 1, close), end: close + 1 };\n\treturn null;\n}\n\nfunction matchLink(src: string, i: number): { label: string; dest: string; end: number } | null {\n\tif (src[i] !== \"[\") return null;\n\n\tlet bracket = 0;\n\tlet j = i;\n\tlet labelEnd = -1;\n\twhile (j < src.length) {\n\t\tif (j - i > MAX_LINK_LABEL) return null;\n\t\tconst c = src[j];\n\t\tif (c === \"\\\\\") {\n\t\t\tj += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"`\") {\n\t\t\tconst span = matchCodeSpan(src, j);\n\t\t\tif (span) {\n\t\t\t\tj = span.end;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif (c === \"[\") bracket++;\n\t\telse if (c === \"]\") {\n\t\t\tbracket--;\n\t\t\tif (bracket === 0) {\n\t\t\t\tlabelEnd = j;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tj++;\n\t}\n\tif (labelEnd < 0 || src[labelEnd + 1] !== \"(\") return null;\n\n\tlet k = labelEnd + 2;\n\tlet paren = 1;\n\tlet dest = \"\";\n\twhile (k < src.length) {\n\t\tif (dest.length > MAX_LINK_DEST) return null;\n\t\tconst c = src[k];\n\t\tif (c === \"\\n\") return null;\n\t\tif (c === \"\\\\\" && k + 1 < src.length) {\n\t\t\tdest += src[k + 1];\n\t\t\tk += 2;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"(\") paren++;\n\t\telse if (c === \")\") {\n\t\t\tparen--;\n\t\t\tif (paren === 0) break;\n\t\t}\n\t\tdest += c;\n\t\tk++;\n\t}\n\tif (paren !== 0) return null;\n\n\treturn { label: src.slice(i + 1, labelEnd), dest: stripDestination(dest), end: k + 1 };\n}\n\n/** `url \"title\"` and `<url>` both reduce to the bare destination. */\nfunction stripDestination(dest: string): string {\n\tconst trimmed = dest.trim();\n\tconst space = trimmed.search(/\\s/);\n\tconst url = space === -1 ? trimmed : trimmed.slice(0, space);\n\tif (url.length > 1 && url.startsWith(\"<\") && url.endsWith(\">\")) return url.slice(1, -1);\n\treturn url;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Blocks                                                                     */\n/* -------------------------------------------------------------------------- */\n\nexport function parseMarkdown(src: string): BlockToken[] {\n\tif (typeof src !== \"string\" || src === \"\") return [];\n\t// Belt-and-braces bound for adversarial vectors nobody has found yet: a chat\n\t// message beyond this size is truncated rather than allowed to own the main\n\t// thread. Consumers with genuinely huge documents should chunk upstream.\n\tconst bounded = src.length > MAX_INPUT ? src.slice(0, MAX_INPUT) : src;\n\treturn parseBlocks(bounded.split(/\\r\\n|\\r|\\n/), 0);\n}\n\nfunction parseBlocks(lines: string[], depth: number): BlockToken[] {\n\tconst out: BlockToken[] = [];\n\tif (depth > MAX_BLOCK_DEPTH) {\n\t\tconst text = lines.join(\"\\n\").trim();\n\t\tif (text !== \"\") out.push({ type: \"paragraph\", children: parseInline(text) });\n\t\treturn out;\n\t}\n\n\tlet i = 0;\n\twhile (i < lines.length) {\n\t\tconst line = lines[i]!;\n\n\t\tif (line.trim() === \"\") {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fence = matchFence(line);\n\t\tif (fence) {\n\t\t\tconst body: string[] = [];\n\t\t\ti++;\n\t\t\t// An unterminated fence stays open — the common case mid-stream.\n\t\t\twhile (i < lines.length && !isFenceClose(lines[i]!, fence.width)) {\n\t\t\t\tbody.push(lines[i]!);\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tif (i < lines.length) i++;\n\t\t\tout.push({ type: \"code\", lang: fence.lang, text: body.join(\"\\n\") });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (RE_HR.test(line)) {\n\t\t\tout.push({ type: \"hr\" });\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst heading = RE_HEADING.exec(line);\n\t\tif (heading) {\n\t\t\tconst content = stripClosingHashes(heading[2] ?? \"\");\n\t\t\tout.push({\n\t\t\t\ttype: \"heading\",\n\t\t\t\tdepth: heading[1]!.length as 1 | 2 | 3 | 4 | 5 | 6,\n\t\t\t\tchildren: parseInline(content),\n\t\t\t});\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (RE_QUOTE.test(line)) {\n\t\t\tconst inner: string[] = [];\n\t\t\twhile (i < lines.length && RE_QUOTE.test(lines[i]!)) {\n\t\t\t\tinner.push(lines[i]!.replace(RE_QUOTE_STRIP, \"\"));\n\t\t\t\ti++;\n\t\t\t}\n\t\t\tout.push({ type: \"blockquote\", children: parseBlocks(inner, depth + 1) });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst table = matchTable(lines, i);\n\t\tif (table) {\n\t\t\tout.push(table.token);\n\t\t\ti = table.end;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst list = matchList(lines, i);\n\t\tif (list) {\n\t\t\tout.push(list.token);\n\t\t\ti = list.end;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst parts = [line.trim()];\n\t\ti++;\n\t\twhile (i < lines.length && lines[i]!.trim() !== \"\" && !startsBlock(lines, i)) {\n\t\t\tparts.push(lines[i]!.trim());\n\t\t\ti++;\n\t\t}\n\t\tout.push({ type: \"paragraph\", children: parseInline(parts.join(\"\\n\")) });\n\t}\n\n\treturn out;\n}\n\nfunction startsBlock(lines: string[], i: number): boolean {\n\tconst line = lines[i]!;\n\treturn (\n\t\tmatchFence(line) !== null ||\n\t\tRE_HR.test(line) ||\n\t\tRE_HEADING.test(line) ||\n\t\tRE_QUOTE.test(line) ||\n\t\tmatchListItem(line) !== null ||\n\t\tisTableStart(lines, i)\n\t);\n}\n\nfunction matchFence(line: string): { width: number; lang: string } | null {\n\tconst m = /^ {0,3}(`{3,})(.*)$/.exec(line);\n\t// A backtick in the info string means this is not a fence at all.\n\tif (!m || m[2]!.includes(\"`\")) return null;\n\tconst lang = (m[2]!.trim().split(/\\s+/)[0] ?? \"\").replace(/[^a-zA-Z0-9_+#.-]/g, \"\").slice(0, 32);\n\treturn { width: m[1]!.length, lang };\n}\n\nfunction isFenceClose(line: string, width: number): boolean {\n\tconst m = /^ {0,3}(`{3,})[ \\t]*$/.exec(line);\n\treturn m !== null && m[1]!.length >= width;\n}\n\nfunction matchListItem(line: string): { ordered: boolean; start: number; content: string } | null {\n\tif (RE_HR.test(line)) return null;\n\tconst bullet = RE_BULLET.exec(line);\n\tif (bullet) return { ordered: false, start: 1, content: bullet[2] ?? \"\" };\n\tconst ordered = RE_ORDERED.exec(line);\n\tif (ordered) {\n\t\treturn { ordered: true, start: Number.parseInt(ordered[1]!, 10), content: ordered[2] ?? \"\" };\n\t}\n\treturn null;\n}\n\nfunction matchList(lines: string[], from: number): { token: BlockToken; end: number } | null {\n\tconst first = matchListItem(lines[from]!);\n\tif (!first) return null;\n\n\tconst ordered = first.ordered;\n\tconst items: InlineToken[][] = [];\n\tlet raw = [first.content];\n\tlet i = from + 1;\n\n\twhile (i < lines.length) {\n\t\tconst line = lines[i]!;\n\n\t\tif (line.trim() === \"\") {\n\t\t\tconst next = i + 1 < lines.length ? matchListItem(lines[i + 1]!) : null;\n\t\t\tif (next && next.ordered === ordered) {\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// Deeper indentation is not a level of its own here: an item is an item.\n\t\tconst item = matchListItem(line);\n\t\tif (item) {\n\t\t\tif (item.ordered !== ordered) break;\n\t\t\titems.push(parseInline(raw.join(\"\\n\")));\n\t\t\traw = [item.content];\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (startsBlock(lines, i)) break;\n\t\traw.push(line.trim());\n\t\ti++;\n\t}\n\n\titems.push(parseInline(raw.join(\"\\n\")));\n\treturn { token: { type: \"list\", ordered, start: first.start, items }, end: i };\n}\n\nfunction parseAlignRow(line: string | undefined): TableAlign[] | null {\n\tif (line === undefined || !line.includes(\"|\") || !line.includes(\"-\")) return null;\n\tconst cells = splitTableRow(line);\n\tconst align: TableAlign[] = [];\n\tfor (const cell of cells) {\n\t\tif (!RE_ALIGN_CELL.test(cell)) return null;\n\t\tconst left = cell.startsWith(\":\");\n\t\tconst right = cell.endsWith(\":\");\n\t\talign.push(left && right ? \"center\" : right ? \"right\" : left ? \"left\" : null);\n\t}\n\treturn align.length > 0 ? align : null;\n}\n\nfunction isTableStart(lines: string[], i: number): boolean {\n\tconst line = lines[i]!;\n\tif (!line.includes(\"|\")) return false;\n\tconst align = parseAlignRow(lines[i + 1]);\n\treturn align !== null && splitTableRow(line).length === align.length;\n}\n\nfunction matchTable(lines: string[], from: number): { token: BlockToken; end: number } | null {\n\tif (!isTableStart(lines, from)) return null;\n\n\tconst align = parseAlignRow(lines[from + 1]) as TableAlign[];\n\tconst header = splitTableRow(lines[from]!).map((cell) => parseInline(cell));\n\tconst rows: InlineToken[][][] = [];\n\tlet i = from + 2;\n\n\twhile (i < lines.length) {\n\t\tconst line = lines[i]!;\n\t\tif (line.trim() === \"\" || !line.includes(\"|\")) break;\n\t\tif (matchFence(line) || RE_HEADING.test(line) || RE_QUOTE.test(line)) break;\n\t\tconst cells = splitTableRow(line);\n\t\trows.push(align.map((_, c) => parseInline(cells[c] ?? \"\")));\n\t\ti++;\n\t}\n\n\treturn { token: { type: \"table\", align, header, rows }, end: i };\n}\n\nfunction splitTableRow(line: string): string[] {\n\tlet s = line.trim();\n\tif (s.startsWith(\"|\")) s = s.slice(1);\n\tif (s.endsWith(\"|\") && !s.endsWith(\"\\\\|\")) s = s.slice(0, -1);\n\n\tconst cells: string[] = [];\n\tlet cell = \"\";\n\tfor (let i = 0; i < s.length; i++) {\n\t\tconst c = s[i];\n\t\tif (c === \"\\\\\" && s[i + 1] === \"|\") {\n\t\t\tcell += \"|\";\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (c === \"|\") {\n\t\t\tcells.push(cell.trim());\n\t\t\tcell = \"\";\n\t\t\tcontinue;\n\t\t}\n\t\tcell += c;\n\t}\n\tcells.push(cell.trim());\n\treturn cells;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/markdown.ts"},{"path":"react/src/internals/menu.ts","content":"\"use client\";\n\n/**\n * Menu keyboard-navigation core: which item holds **real DOM focus** as arrow\n * keys, Home/End and typeahead move through a `role=\"menu\"` surface.\n *\n * This is the counterpart to `listbox.ts`, and the difference between the two\n * is the whole reason both exist. A listbox keeps focus on its input or\n * trigger and points at the active row with `aria-activedescendant`; a menu\n * moves focus onto the item itself. That is the WAI-ARIA menu pattern, and it\n * is what assistive technology expects when it meets `role=\"menu\"` — so a menu\n * built on `aria-activedescendant` reads as broken even though nothing about\n * it looks wrong. Consumers must not add `aria-activedescendant` to a surface\n * driven by this module.\n *\n * Three guarantees, so `DropdownMenu`, `ContextMenu` and every submenu get\n * them once rather than three times:\n *\n * - **Items navigate in DOM order, not registration order.** Mount order and\n *   document order diverge routinely — a conditional block, a list that\n *   reorders, a submenu that mounts before the item above it. Ordering is\n *   therefore resolved by `compareDocumentPosition` at navigation time, not\n *   by the order `register` happened to be called in. This is also what makes\n *   the promise survive React's child-before-parent effect ordering for free.\n * - **Disabled items are skipped**, a consecutive run of them as a block, and\n *   movement terminates rather than spinning when every item is disabled.\n * - **Typeahead** accumulates characters within a short window and resets\n *   after it, with a repeated character cycling through its matches — the\n *   same semantics as the listbox core, so the two feel identical to use.\n *\n * The focused item is tracked as an *element*, not an index: menus mutate\n * their item list while open (a filtered list, a submenu opening), and an\n * index captured before that mutation silently points at a different item\n * afterwards. `focusedIndex` is derived from the element on read.\n */\n\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from \"react\";\nimport type { RefCallback } from \"react\";\nimport { useConstant } from \"./dom/ssr\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\n\nexport interface MenuFocusOptions {\n\t/** Whether arrow navigation wraps at the ends. Defaults to true. */\n\tloop?: boolean;\n\t/** Called when focus moves to an item, with the item's index and element. */\n\tonFocusChange?: (index: number, element: HTMLElement) => void;\n}\n\nexport interface MenuFocusState {\n\t/**\n\t * Index of the focused item in DOM order, or -1 when focus is not on an item.\n\t *\n\t * Computed on read from the live ordered list, exactly like the Svelte\n\t * getter — so the value is correct on a fresh read and `document.activeElement`\n\t * is never wrong. It is deliberately NOT React state: nothing re-renders when\n\t * focus moves, because real DOM focus does the rendering through `:focus` /\n\t * `:focus-visible`. Use `onFocusChange`, or opt into `useMenuFocusedIndex`\n\t * when a component genuinely must render off the number.\n\t */\n\treadonly focusedIndex: number;\n\t/** Registers an item element. Returns an unregister function; call it on destroy. */\n\tregister(element: HTMLElement): () => void;\n\t/** Moves focus by delta, skipping disabled items. `delta === 0` is a no-op. */\n\tmove(delta: number): void;\n\t/** Moves focus to the first or last enabled item. */\n\tmoveToEdge(edge: \"first\" | \"last\"): void;\n\t/** Focuses a specific element, if it is registered and enabled. */\n\tfocusItem(element: HTMLElement): void;\n\t/** Clears the focused item without moving DOM focus. */\n\tclear(): void;\n\t/**\n\t * Advances typeahead with a printable character and focuses the match.\n\t *\n\t * Matches against the item's `data-typeahead-label` when it has one, and\n\t * otherwise against its visible text — decorative `aria-hidden` content\n\t * (icon glyphs, `<kbd>` shortcuts) is excluded either way. Set the\n\t * attribute whenever the item knows its own label as a string; it is\n\t * cheaper and more reliable than making this reconstruct it from the DOM.\n\t */\n\ttypeahead(char: string): void;\n\t/** Clears the typeahead buffer and any pending timer. Call from teardown. */\n\tdestroy(): void;\n\t/**\n\t * Added for React. Notifies on every `focusedElement` change, so\n\t * `useMenuFocusedIndex` can read the index through `useSyncExternalStore`.\n\t * The mutation source is outside React's knowledge — a `focusItem` from a\n\t * `pointerenter`, a `typeahead` from a document keydown — which is exactly\n\t * the case that API exists for.\n\t */\n\tsubscribe(listener: () => void): () => void;\n}\n\n// Matches the window used by `listbox.ts`, and by native menus on most\n// platforms. Divergence between the two would be felt immediately: the same\n// keystrokes behave differently in a menu and in a select.\nconst TYPEAHEAD_TIMEOUT_MS = 500;\n\n/**\n * Orders two elements by their position in the document.\n *\n * The identity case is not decoration: `compareDocumentPosition` returns 0 for\n * an element compared with itself, so returning a non-zero value there would\n * claim an element sorts after itself — not a valid total order, and\n * `Array.prototype.sort` is entitled to produce an arbitrary arrangement when\n * given one. Duplicates should never reach here (`register` refuses them), so\n * this is the second of two locks on the same door rather than the only one.\n */\nfunction compareDocumentOrder(a: HTMLElement, b: HTMLElement): number {\n\tif (a === b) return 0;\n\treturn a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;\n}\n\n/**\n * The text of an element as a sighted user reads it: every text node except\n * those inside a subtree marked `aria-hidden=\"true\"`.\n *\n * `textContent` is the obvious choice and the wrong one. It walks every text\n * node regardless of `aria-hidden`, so an item rendered as a decorative glyph\n * plus a label — `<span aria-hidden=\"true\">✎</span> Rename`, which is exactly\n * the shape the menu components use — yields `\"✎ Rename\"`, and typing \"r\"\n * matches nothing. The user sees a list starting with \"Rename\" and the\n * keyboard disagrees, with no way to tell why.\n *\n * `aria-hidden` is the right signal to key on because this library already\n * requires it on decorative icons and on the `<kbd>` shortcut text, so items\n * that follow the existing convention get correct typeahead for free. What\n * this deliberately does *not* skip is `sr-only` content, which is visually\n * hidden but genuinely part of the item's name — an item can override the\n * whole computation with `data-typeahead-label` when it wants something else.\n */\nfunction visibleTextOf(node: Node): string {\n\tif (node.nodeType === Node.TEXT_NODE) return node.textContent ?? \"\";\n\tif (node.nodeType !== Node.ELEMENT_NODE) return \"\";\n\tconst element = node as HTMLElement;\n\tif (element.getAttribute(\"aria-hidden\") === \"true\") return \"\";\n\tlet text = \"\";\n\tfor (const child of Array.from(element.childNodes)) text += visibleTextOf(child);\n\treturn text;\n}\n\n/**\n * Note on a case this module cannot handle and jsdom cannot demonstrate: an\n * item that becomes natively `disabled` *while it holds DOM focus*. A real\n * browser force-blurs it to `<body>`; jsdom leaves focus on it. Either way\n * nothing here listens for that blur, so `focusedIndex` keeps reporting the\n * now-unfocusable item until the next `move`, `focusItem` or `clear`. A\n * consumer that disables items dynamically should call `clear()` or move\n * focus itself, rather than assume this module noticed.\n */\nfunction isDisabled(element: HTMLElement): boolean {\n\tif (element.getAttribute(\"aria-disabled\") === \"true\") return true;\n\t// A native `disabled` button is not focusable at all, so treating it as\n\t// enabled would make `move` \"succeed\" onto an element that then refuses\n\t// focus, stranding focus on whatever held it before.\n\treturn \"disabled\" in element && (element as HTMLButtonElement).disabled === true;\n}\n\nexport function createMenuFocus(options: MenuFocusOptions = {}): MenuFocusState {\n\t// Registration order — deliberately not the navigation order. See\n\t// `orderedItems` for why.\n\tconst registered: HTMLElement[] = [];\n\t// The one edit against the Svelte source: `$state<HTMLElement | null>(null)`\n\t// becomes a plain `let` plus a `notify()` at each of the three assignment\n\t// sites, backed by the listener set below.\n\tlet focusedElement: HTMLElement | null = null;\n\tlet buffer = \"\";\n\tlet timer: ReturnType<typeof setTimeout> | null = null;\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify(): void {\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\t/**\n\t * The registered items that are still in the document, in document order.\n\t *\n\t * Disconnected elements are dropped rather than trusted: an item whose\n\t * component was destroyed without its unregister running (an error during\n\t * teardown, a parent removed wholesale) would otherwise stay in the list\n\t * forever as a focus target that cannot be focused.\n\t */\n\tfunction orderedItems(): HTMLElement[] {\n\t\treturn registered.filter((element) => element.isConnected).sort(compareDocumentOrder);\n\t}\n\n\tfunction focusAt(items: HTMLElement[], index: number): void {\n\t\tconst element = items[index];\n\t\tif (!element) return;\n\t\tfocusedElement = element;\n\t\tnotify();\n\t\telement.focus();\n\t\toptions.onFocusChange?.(index, element);\n\t}\n\n\t/**\n\t * Walks from `from` in `direction`, skipping disabled items and either\n\t * wrapping or stopping dead at the edge, and returns the first enabled\n\t * index. Bounded to `items.length` attempts so an all-disabled menu\n\t * terminates instead of spinning.\n\t */\n\tfunction findNext(\n\t\titems: HTMLElement[],\n\t\tfrom: number,\n\t\tdirection: 1 | -1,\n\t\tloop: boolean\n\t): number | null {\n\t\tconst count = items.length;\n\t\tlet idx = from;\n\t\tfor (let attempts = 0; attempts < count; attempts++) {\n\t\t\tidx += direction;\n\t\t\tif (loop) {\n\t\t\t\tidx = ((idx % count) + count) % count;\n\t\t\t} else if (idx < 0 || idx >= count) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst element = items[idx];\n\t\t\tif (element && !isDisabled(element)) return idx;\n\t\t}\n\t\treturn null;\n\t}\n\n\tfunction indexOfFocused(items: HTMLElement[]): number {\n\t\treturn focusedElement ? items.indexOf(focusedElement) : -1;\n\t}\n\n\tfunction register(element: HTMLElement): () => void {\n\t\t// A second registration of the same element is ignored rather than\n\t\t// stored twice. A duplicate would make the element occupy two slots in\n\t\t// the ordered list, so one arrow press would appear to do nothing, and\n\t\t// it would hand `sort` a pair it cannot order consistently. Re-running\n\t\t// a registration effect without its teardown is an ordinary enough\n\t\t// mistake in a consumer that this should not be its problem.\n\t\tif (!registered.includes(element)) registered.push(element);\n\t\treturn () => {\n\t\t\tconst at = registered.indexOf(element);\n\t\t\tif (at !== -1) registered.splice(at, 1);\n\t\t\t// Releasing the reference, not enforcing a behaviour: focus\n\t\t\t// tracking already stops surviving unregistration, because\n\t\t\t// `focusedIndex` looks the element up in the *current* ordered\n\t\t\t// list and an unregistered element is not in it. Dropping the\n\t\t\t// reference here only avoids retaining a detached element for as\n\t\t\t// long as the menu lives.\n\t\t\tif (focusedElement === element) {\n\t\t\t\tfocusedElement = null;\n\t\t\t\tnotify();\n\t\t\t}\n\t\t};\n\t}\n\n\tfunction move(delta: number): void {\n\t\tif (delta === 0) return;\n\t\tconst items = orderedItems();\n\t\tif (items.length === 0) return;\n\t\tconst loop = options.loop ?? true;\n\t\tconst direction: 1 | -1 = delta >= 0 ? 1 : -1;\n\t\tconst steps = Math.abs(delta);\n\n\t\t// Nothing focused is not a position to step away from: it reads as one\n\t\t// before the first item going forward, one past the last going back,\n\t\t// so the first ArrowDown lands on the first item and the first ArrowUp\n\t\t// on the last — the convention this module exists to reproduce.\n\t\tconst current = indexOfFocused(items);\n\t\tconst from = current === -1 ? (direction === 1 ? -1 : items.length) : current;\n\n\t\tlet found: number | null = null;\n\t\tfor (let i = 0; i < steps; i++) {\n\t\t\tconst next = findNext(items, found ?? from, direction, loop);\n\t\t\tif (next === null) break;\n\t\t\tfound = next;\n\t\t}\n\n\t\tif (found !== null) focusAt(items, found);\n\t}\n\n\tfunction moveToEdge(edge: \"first\" | \"last\"): void {\n\t\tconst items = orderedItems();\n\t\tif (items.length === 0) return;\n\n\t\tif (edge === \"first\") {\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tif (!isDisabled(items[i]!)) {\n\t\t\t\t\tfocusAt(items, i);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = items.length - 1; i >= 0; i--) {\n\t\t\tif (!isDisabled(items[i]!)) {\n\t\t\t\tfocusAt(items, i);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction focusItem(element: HTMLElement): void {\n\t\tconst items = orderedItems();\n\t\tconst index = items.indexOf(element);\n\t\t// An unregistered or disabled element is left alone rather than\n\t\t// focused. Unlike a relative `move`, a direct `focusItem` carries no\n\t\t// direction to hunt a substitute in, so doing nothing beats guessing.\n\t\tif (index === -1 || isDisabled(element)) return;\n\t\tfocusAt(items, index);\n\t}\n\n\tfunction clear(): void {\n\t\tfocusedElement = null;\n\t\tnotify();\n\t}\n\n\tfunction clearBuffer(): void {\n\t\tbuffer = \"\";\n\t\tif (timer !== null) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = null;\n\t\t}\n\t}\n\n\tfunction labelOf(element: HTMLElement): string {\n\t\t// An explicit label always wins. A menu item knows its own label as a\n\t\t// string; asking the DOM to reconstruct it is guesswork we only fall\n\t\t// back to when the item did not say.\n\t\tconst explicit = element.dataset.typeaheadLabel;\n\t\treturn (explicit ?? visibleTextOf(element)).trim().toLowerCase();\n\t}\n\n\tfunction typeahead(char: string): void {\n\t\tconst items = orderedItems();\n\t\tif (items.length === 0) return;\n\t\tconst lower = char.toLowerCase();\n\n\t\t// A run of the SAME character with nothing else typed in between is the\n\t\t// platform's cycle-through-matches gesture, not a fresh multi-character\n\t\t// query: \"nn\" searches for \"n\" a second time past the focused item\n\t\t// rather than matching the literal string \"nn\".\n\t\tconst isRepeatChar = buffer.length > 0 && [...buffer].every((c) => c === lower);\n\n\t\tif (timer !== null) clearTimeout(timer);\n\t\ttimer = setTimeout(clearBuffer, TYPEAHEAD_TIMEOUT_MS);\n\n\t\tif (isRepeatChar) {\n\t\t\t// Collapsed to the single character, not appended — so breaking the\n\t\t\t// cycle with a different character continues from \"s\" + \"e\", not\n\t\t\t// from the literal keystroke history \"sss\" + \"e\", which would match\n\t\t\t// nothing. Cycling exists to revisit single-character matches, not\n\t\t\t// to build a longer query.\n\t\t\tbuffer = lower;\n\t\t\tconst from = indexOfFocused(items);\n\t\t\tfor (let i = 1; i <= items.length; i++) {\n\t\t\t\tconst candidate = (from + i + items.length) % items.length;\n\t\t\t\tconst element = items[candidate]!;\n\t\t\t\tif (isDisabled(element)) continue;\n\t\t\t\tif (labelOf(element).startsWith(lower)) {\n\t\t\t\t\tfocusAt(items, candidate);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tbuffer += lower;\n\t\tconst query = buffer;\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst element = items[i]!;\n\t\t\tif (isDisabled(element)) continue;\n\t\t\tif (labelOf(element).startsWith(query)) {\n\t\t\t\tfocusAt(items, i);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction destroy(): void {\n\t\tclearBuffer();\n\t}\n\n\tfunction subscribe(listener: () => void): () => void {\n\t\tlisteners.add(listener);\n\t\treturn () => {\n\t\t\tlisteners.delete(listener);\n\t\t};\n\t}\n\n\treturn {\n\t\tget focusedIndex() {\n\t\t\treturn indexOfFocused(orderedItems());\n\t\t},\n\t\tregister,\n\t\tmove,\n\t\tmoveToEdge,\n\t\tfocusItem,\n\t\tclear,\n\t\ttypeahead,\n\t\tdestroy,\n\t\tsubscribe,\n\t};\n}\n\n/**\n * One store per mount, torn down on unmount.\n *\n * The options are handed to the factory as a getter object over live refs, so\n * passing `loop` as a PLAIN VALUE behaves identically to the Svelte call sites'\n * `get loop() { … }` — the factory reads it lazily at navigation time, and a\n * re-render that changes it is honoured without rebuilding anything.\n *\n * The returned handle's identity NEVER changes, so it goes straight into a\n * context value with no memo dance, and no item re-renders when focus moves.\n * `destroy()` is still on the handle, but a consumer never has to call it: the\n * unmount cleanup below closes the typeahead timer that the Svelte side's\n * `DropdownMenuContent` forgets (divergence D-5).\n */\nexport function useMenuFocus(options: MenuFocusOptions = {}): MenuFocusState {\n\tconst loop = useLiveRef(options.loop);\n\tconst onFocusChange = useEventCallback(options.onFocusChange);\n\n\tconst menu = useConstant(() =>\n\t\tcreateMenuFocus({\n\t\t\tget loop() {\n\t\t\t\treturn loop.current;\n\t\t\t},\n\t\t\tonFocusChange,\n\t\t})\n\t);\n\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tmenu.destroy();\n\t\t};\n\t}, [menu]);\n\n\treturn menu;\n}\n\n/**\n * A per-item callback ref — one line in each item component, replacing the\n * Svelte side's per-item registration effect.\n *\n * Registration happens in the ref callback (commit phase) rather than an\n * effect, so it survives React's detach-then-attach protocol: the previous\n * registration is released before the new node registers. React 18 ref\n * callbacks cannot return a cleanup — that is 19-only — so the unregister is\n * held locally instead.\n *\n * Registration order is irrelevant: `orderedItems()` sorts by\n * `compareDocumentPosition` at navigation time.\n */\nexport function useMenuItemRef(menu: MenuFocusState): RefCallback<HTMLElement> {\n\tconst unregister = useRef<(() => void) | null>(null);\n\n\treturn useCallback(\n\t\t(node: HTMLElement | null) => {\n\t\t\tunregister.current?.();\n\t\t\tunregister.current = node ? menu.register(node) : null;\n\t\t},\n\t\t[menu]\n\t);\n}\n\n/** The server never has a focused item, and neither does the hydration render. */\nconst getServerFocusedIndex = () => -1;\n\n/**\n * Subscribes to the focused index so a component can render off it.\n *\n * Opt-in, and discouraged for the reason `focusedIndex`'s own doc comment\n * gives: real DOM focus is what should drive rendering, through `:focus` /\n * `:focus-visible`. Reach for this only when a component genuinely cannot.\n */\nexport function useMenuFocusedIndex(menu: MenuFocusState): number {\n\tconst getSnapshot = useCallback(() => menu.focusedIndex, [menu]);\n\treturn useSyncExternalStore(menu.subscribe, getSnapshot, getServerFocusedIndex);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/menu.ts"},{"path":"react/src/internals/merge-ids.ts","content":"\"use client\";\n\n/**\n * Joins id lists (each possibly space-separated) into one `aria-describedby`\n * value: tokens are split on whitespace, de-duplicated in first-seen order, and\n * the result is `undefined` when nothing is left.\n */\nexport function mergeIds(...parts: Array<string | null | undefined | false>): string | undefined {\n\tconst seen = new Set<string>();\n\tfor (const part of parts) {\n\t\tif (!part) continue;\n\t\tfor (const token of part.split(/\\s+/)) if (token) seen.add(token);\n\t}\n\treturn seen.size > 0 ? [...seen].join(\" \") : undefined;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/merge-ids.ts"},{"path":"react/src/internals/relative-time.ts","content":"\"use client\";\n\n/**\n * Locale-aware relative timestamps (\"5 minutes ago\", \"in 2 hours\") built on\n * `Intl.RelativeTimeFormat`. Pure and dependency-free: pass `now` to make the\n * output deterministic in tests.\n */\n\nconst SECOND = 1000;\nconst MINUTE = 60 * SECOND;\nconst HOUR = 60 * MINUTE;\nconst DAY = 24 * HOUR;\nconst WEEK = 7 * DAY;\nconst MONTH = 30.436875 * DAY; // Average Gregorian month.\nconst YEAR = 365.2425 * DAY;\n\n/** Largest absolute delta each unit covers, in ascending order. */\nconst BUCKETS: ReadonlyArray<[limit: number, step: number, unit: Intl.RelativeTimeFormatUnit]> = [\n\t[45 * SECOND, SECOND, \"second\"],\n\t[45 * MINUTE, MINUTE, \"minute\"],\n\t[22 * HOUR, HOUR, \"hour\"],\n\t[7 * DAY, DAY, \"day\"],\n\t[4 * WEEK, WEEK, \"week\"],\n\t[11 * MONTH, MONTH, \"month\"],\n\t[Infinity, YEAR, \"year\"],\n];\n\nconst formatters = new Map<string, Intl.RelativeTimeFormat>();\n\nfunction formatter(locale: string | undefined, numeric: \"auto\" | \"always\") {\n\tconst key = `${locale ?? \"\"}|${numeric}`;\n\tlet rtf = formatters.get(key);\n\tif (!rtf) {\n\t\trtf = new Intl.RelativeTimeFormat(locale, { numeric });\n\t\tformatters.set(key, rtf);\n\t}\n\treturn rtf;\n}\n\nexport interface RelativeTimeOptions {\n\t/** BCP 47 tag. Defaults to the runtime locale. */\n\tlocale?: string;\n\t/**\n\t * Epoch ms to measure against. Defaults to `Date.now()`. A non-finite\n\t * value (a shared clock's \"not started yet\" sentinel) yields `\"\"`.\n\t */\n\tnow?: number;\n\t/** Defaults to `\"auto\"`, which yields idiomatic words (\"now\", \"yesterday\"). */\n\tnumeric?: \"auto\" | \"always\";\n}\n\n/**\n * Format `date` relative to `now`. Past dates read \"5 minutes ago\", future\n * dates \"in 2 hours\".\n *\n * Under `numeric: \"auto\"` anything inside the last (or next) 45 seconds is\n * reported as the locale's zero-word — \"now\" in English — rather than an exact\n * second count. Pass `numeric: \"always\"` to get \"10 seconds ago\" instead.\n */\nexport function formatRelativeTime(date: number | Date, opts: RelativeTimeOptions = {}): string {\n\tconst target = date instanceof Date ? date.getTime() : date;\n\tif (!Number.isFinite(target)) return \"\";\n\n\t/*\n\t * A non-finite `now` is a shared clock's \"not started yet\" sentinel: a\n\t * clock that must read the same on the server and through the hydration\n\t * render has no reading to give until it starts, and reports `NaN`.\n\t * Reporting nothing is the only honest answer — measuring against it\n\t * would print a label off by decades, and `Intl.RelativeTimeFormat`\n\t * throws on a non-finite value.\n\t */\n\tconst now = opts.now ?? Date.now();\n\tif (!Number.isFinite(now)) return \"\";\n\n\tconst numeric = opts.numeric ?? \"auto\";\n\tconst rtf = formatter(opts.locale, numeric);\n\tconst diff = target - now;\n\tconst abs = Math.abs(diff);\n\n\tfor (const [limit, step, unit] of BUCKETS) {\n\t\tif (abs >= limit) continue;\n\t\tconst value = unit === \"second\" && numeric === \"auto\" ? 0 : Math.round(diff / step);\n\t\treturn rtf.format(value, unit);\n\t}\n\treturn \"\";\n}\n","type":"registry:lib","target":"@ui/fancy/internals/relative-time.ts"},{"path":"react/src/internals/scroll-lock.ts","content":"\"use client\";\n\n// Locks the page's own scroll while one or more overlays are open.\n//\n// Reference-counted: `lockScroll()` can be called any number of times while\n// overlays nest (a Popover opened from inside a Dialog acquires its own\n// lock on top of the Dialog's), and the page only unlocks once every caller\n// has released. The body's scroll-affecting styles are only ever touched by\n// the FIRST acquire and the LAST release — every acquire in between is a\n// free ride on the lock already in place, and every release before the last\n// is a no-op on the DOM.\n//\n// Technique: `position: fixed` on `<body>`, offset by the current scroll\n// position, rather than plain `overflow: hidden`. Plain `overflow: hidden`\n// does not reliably stop touch-driven scrolling on iOS Safari — the body\n// can still rubber-band under a finger even though its scrollbar is gone.\n// Pinning the body in place with `position: fixed` blocks that too, but it\n// also means the page's scroll position is lost the instant `position`\n// leaves `static` (the viewport jumps to its top-left), so the position has\n// to be captured before locking and restored by hand after unlocking — the\n// cost of choosing this technique over the simpler one.\n//\n// Scrollbar compensation: removing the scrollbar reflows the page — content\n// widens by however many pixels the scrollbar used to occupy, and\n// everything shifts sideways. Padding the body by that same width keeps the\n// layout still. Measured as `window.innerWidth - document.documentElement\n// .clientWidth`; on a platform with overlay scrollbars (macOS by default,\n// most mobile browsers) that measures zero, so the padding write is skipped\n// entirely rather than adding a stray `padding-right: 0px`.\n\nimport { useIsomorphicLayoutEffect } from \"./dom/ssr\";\n\ninterface LockedState {\n\tscrollY: number;\n\tbodyPosition: string;\n\tbodyTop: string;\n\tbodyLeft: string;\n\tbodyRight: string;\n\tbodyWidth: string;\n\tbodyOverflow: string;\n\tbodyPaddingRight: string;\n}\n\nlet lockCount = 0;\nlet saved: LockedState | null = null;\n\n/**\n * Acquires the scroll lock and returns a function that releases this\n * specific acquisition. Safe to call from SSR (returns a no-op release).\n * The returned function is idempotent — calling it more than once only\n * decrements the shared count on its first call.\n */\nexport function lockScroll(): () => void {\n\tif (typeof document === \"undefined\") {\n\t\treturn () => {};\n\t}\n\n\tif (lockCount === 0) {\n\t\tconst body = document.body;\n\t\tconst root = document.documentElement;\n\t\tconst scrollbarGutter = window.innerWidth - root.clientWidth;\n\t\tconst currentPaddingRight = parseFloat(getComputedStyle(body).paddingRight) || 0;\n\n\t\tsaved = {\n\t\t\tscrollY: window.scrollY,\n\t\t\tbodyPosition: body.style.position,\n\t\t\tbodyTop: body.style.top,\n\t\t\tbodyLeft: body.style.left,\n\t\t\tbodyRight: body.style.right,\n\t\t\tbodyWidth: body.style.width,\n\t\t\tbodyOverflow: body.style.overflow,\n\t\t\tbodyPaddingRight: body.style.paddingRight,\n\t\t};\n\n\t\tbody.style.position = \"fixed\";\n\t\tbody.style.top = `-${saved.scrollY}px`;\n\t\tbody.style.left = \"0\";\n\t\tbody.style.right = \"0\";\n\t\tbody.style.width = \"100%\";\n\t\tbody.style.overflow = \"hidden\";\n\t\t// Overlay-scrollbar platforms measure a zero gutter — leaving\n\t\t// padding-right untouched there instead of writing \"0px\" over\n\t\t// whatever the page's own styles already set.\n\t\tif (scrollbarGutter > 0) {\n\t\t\tbody.style.paddingRight = `${currentPaddingRight + scrollbarGutter}px`;\n\t\t}\n\t}\n\n\tlockCount += 1;\n\tlet released = false;\n\n\treturn function release() {\n\t\tif (released) return;\n\t\treleased = true;\n\t\tlockCount -= 1;\n\t\tif (lockCount > 0) return;\n\n\t\tconst body = document.body;\n\t\tconst state = saved;\n\t\tsaved = null;\n\t\tif (!state) return;\n\n\t\tbody.style.position = state.bodyPosition;\n\t\tbody.style.top = state.bodyTop;\n\t\tbody.style.left = state.bodyLeft;\n\t\tbody.style.right = state.bodyRight;\n\t\tbody.style.width = state.bodyWidth;\n\t\tbody.style.overflow = state.bodyOverflow;\n\t\tbody.style.paddingRight = state.bodyPaddingRight;\n\t\twindow.scrollTo(0, state.scrollY);\n\t};\n}\n\n/**\n * Acquires the scroll lock while mounted and `enabled` (default true).\n *\n * TIMING RULE FOR PORTS: call it INSIDE the presence-mounted subtree — the\n * panel component that `usePresence` keeps alive through the exit — and do\n * NOT pass `open`. Release timing is the whole point: an effect keyed on\n * `open` releases the instant `open` flips, leaving the page scrollable under\n * a scrim that is still on screen. Mounting scope is what holds the lock for\n * the length of the fade instead. `enabled` exists only for non-animated\n * surfaces (a `duration: 0` drawer, a reduced-motion path).\n *\n * Goes on the PANEL, never the scrim — the panel is the component that\n * already carries the portal, the focus trap and the dismissable layer.\n *\n * Reference-counted through `lockScroll()`, so nesting is unchanged, and a\n * layout effect rather than a passive one: a lock applied after paint is a\n * visible one-frame scroll jump on a long page.\n */\nexport function useScrollLock(enabled = true): void {\n\tuseIsomorphicLayoutEffect(() => {\n\t\tif (!enabled) return;\n\t\treturn lockScroll();\n\t}, [enabled]);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/scroll-lock.ts"},{"path":"react/src/internals/stream-text.css","content":"/*\n * Reduced motion gets plain text at its final colour: with the whole rule\n * behind the query there is no animation to shorten or fall back from.\n */\n@media (prefers-reduced-motion: no-preference) {\n\t/*\n\t * Anchored on the component's own root class. The source rule lived in a\n\t * compiler-scoped block, so it only ever matched this component's own\n\t * segments; a bare `.ft-fresh` in a shipped stylesheet would hand the\n\t * 350ms tint to any consumer element that happens to carry the class.\n\t */\n\t.ft-stream .ft-fresh {\n\t\tanimation: ft-tint var(--ft-settle, 350ms) ease-out;\n\t}\n\n\t@keyframes ft-tint {\n\t\tfrom {\n\t\t\tcolor: var(--ft-tint-color, oklch(0.65 0.15 250));\n\t\t\topacity: 0.6;\n\t\t}\n\t\tto {\n\t\t\tcolor: inherit;\n\t\t\topacity: 1;\n\t\t}\n\t}\n}\n","type":"registry:lib","target":"@ui/fancy/internals/stream-text.css"},{"path":"react/src/internals/use-anchor-position.ts","content":"\"use client\";\n\n// React binding for `attachAnchorPosition`. The core in `anchor-position.ts`\n// owns the geometry and the listeners; this file owns nothing but the\n// lifecycle and the one piece of state twelve anchored surfaces all need —\n// the placement as it ACTUALLY resolved, after a flip and after a clamp.\n//\n// Usage:\n//   const [panel, panelRef] = useElementRef<HTMLDivElement>();\n//   const { side, align } = useAnchorPosition(panel, { anchor: triggerEl, side: \"bottom\" });\n//   <div ref={panelRef} style={{ transformOrigin: originFor(side, align) }} />\n\nimport { useCallback, useRef, useState } from \"react\";\nimport { attachAnchorPosition } from \"./anchor-position\";\nimport type { Align, AnchorPositionHandle, Side } from \"./anchor-position\";\nimport { useIsomorphicLayoutEffect } from \"./dom/ssr\";\nimport type { ElementRef } from \"./dom/types\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\n\nexport interface UseAnchorPositionOptions {\n\t/**\n\t * The anchor. A node, a ref, or a getter for a moving/virtual target —\n\t * the getter form is what a context-menu-style caller with no real\n\t * element to point at reaches for.\n\t */\n\tanchor: ElementRef<HTMLElement> | HTMLElement | null | (() => HTMLElement | null);\n\t/** Side of the anchor to place the element on. Defaults to \"bottom\". */\n\tside?: Side;\n\t/** Alignment along the cross axis of `side`. Defaults to \"center\". */\n\talign?: Align;\n\t/** Gap in pixels between the anchor and the element. Defaults to the core's 8. */\n\toffset?: number;\n\t/** Stop positioning without unmounting. Default true. */\n\tenabled?: boolean;\n\t/**\n\t * An opaque value the caller bumps to force a recompute when something the\n\t * geometry depends on moved but no option did — a context menu's pointer\n\t * coordinates, which slide the same virtual anchor element to a new place.\n\t */\n\trecomputeKey?: string | number;\n\t/**\n\t * Fires on first placement, then only when the resolved side or align\n\t * actually changes. Most consumers want the RETURN VALUE instead; this is\n\t * for the caller that has to publish the placement somewhere other than\n\t * its own render — a submenu telling its parent context which way it\n\t * opened.\n\t */\n\tonPlacement?: (side: Side, align: Align) => void;\n}\n\nexport interface ResolvedPlacement {\n\treadonly side: Side;\n\treadonly align: Align;\n}\n\n/**\n * Positions `node` with `position: fixed` against a live anchor, and returns\n * the placement as ACTUALLY resolved — flipped and/or clamped.\n *\n * The element comes in as the NODE, never a ref (convention C-1): every\n * anchored surface is conditionally rendered, so a `useRef` read inside a\n * `[]`-deps effect would still be null when that effect fires and the\n * position would never be applied.\n *\n * The initial value is the REQUESTED side and align, not a hardcoded\n * \"bottom\"/\"center\" — seeding with anything else shows as a one-frame\n * transform-origin jump on every open, when only a real flip may move the\n * origin.\n *\n * SSR-safe: nothing runs. The element renders unpositioned, exactly as under\n * an un-run Svelte action.\n */\nexport function useAnchorPosition(\n\tnode: HTMLElement | null,\n\toptions: UseAnchorPositionOptions\n): ResolvedPlacement {\n\tconst { side = \"bottom\", align = \"center\", offset, enabled = true, recomputeKey } = options;\n\n\tconst [placement, setPlacement] = useState<ResolvedPlacement>(() => ({ side, align }));\n\n\t// The anchor and the three geometry options are read through live refs so\n\t// the attach effect can stay keyed on `[node, enabled]` alone: a changed\n\t// `side` must recompute, never tear the scroll and resize listeners down\n\t// and build them again.\n\tconst anchorRef = useLiveRef(options.anchor);\n\tconst sideRef = useLiveRef(side);\n\tconst alignRef = useLiveRef(align);\n\tconst offsetRef = useLiveRef(offset);\n\tconst recomputeKeyRef = useLiveRef(recomputeKey);\n\n\tconst resolveAnchor = useCallback((): HTMLElement | null => {\n\t\tconst anchor = anchorRef.current;\n\t\tif (!anchor) return null;\n\t\tif (typeof anchor === \"function\") return anchor();\n\t\t// `\"current\" in x` rather than `instanceof HTMLElement`: the check must\n\t\t// not touch a browser global, and an element has no `current`.\n\t\tif (\"current\" in anchor) return anchor.current;\n\t\treturn anchor;\n\t}, [anchorRef]);\n\n\tconst onPlacement = useEventCallback(options.onPlacement);\n\n\t// One identity for the life of the component, which is what makes the\n\t// core's `onPlacement`-identity reset branch unreachable from here.\n\tconst handlePlacement = useCallback(\n\t\t(nextSide: Side, nextAlign: Align) => {\n\t\t\t// A fresh object only when a value actually moved, so a scroll storm\n\t\t\t// that keeps resolving to the same placement produces zero re-renders.\n\t\t\tsetPlacement((prev) =>\n\t\t\t\tprev.side === nextSide && prev.align === nextAlign\n\t\t\t\t\t? prev\n\t\t\t\t\t: { side: nextSide, align: nextAlign }\n\t\t\t);\n\t\t\tonPlacement(nextSide, nextAlign);\n\t\t},\n\t\t[onPlacement]\n\t);\n\n\tconst handleRef = useRef<AnchorPositionHandle | null>(null);\n\t// The geometry AND the anchor the live handle was last given. `null` while\n\t// nothing is attached; it is what keeps the update effect below from\n\t// spending a second layout read on the commit that just attached.\n\t//\n\t// `anchor` is the RESOLVED element, never the `anchor` option itself. The\n\t// option is routinely an inline arrow rebuilt on every render (a virtual\n\t// anchor's `() => root.anchorRef`), so its identity says nothing about\n\t// whether the surface still points at the same thing; the element it\n\t// resolves to says exactly that.\n\tconst appliedRef = useRef<{\n\t\tside: Side;\n\t\talign: Align;\n\t\toffset: number | undefined;\n\t\tanchor: HTMLElement | null;\n\t\trecomputeKey: string | number | undefined;\n\t} | null>(null);\n\n\t// A layout effect, not a passive one: a position applied after paint is a\n\t// visible jump from (0, 0).\n\tuseIsomorphicLayoutEffect(() => {\n\t\tif (!node || !enabled) return;\n\n\t\tconst handle = attachAnchorPosition(node, {\n\t\t\tanchor: resolveAnchor,\n\t\t\tside: sideRef.current,\n\t\t\talign: alignRef.current,\n\t\t\toffset: offsetRef.current,\n\t\t\tonPlacement: handlePlacement,\n\t\t});\n\t\thandleRef.current = handle;\n\t\tappliedRef.current = {\n\t\t\tside: sideRef.current,\n\t\t\talign: alignRef.current,\n\t\t\toffset: offsetRef.current,\n\t\t\tanchor: resolveAnchor(),\n\t\t\trecomputeKey: recomputeKeyRef.current,\n\t\t};\n\n\t\treturn () => {\n\t\t\thandleRef.current = null;\n\t\t\tappliedRef.current = null;\n\t\t\thandle.destroy();\n\t\t};\n\t}, [\n\t\tnode,\n\t\tenabled,\n\t\tresolveAnchor,\n\t\thandlePlacement,\n\t\tsideRef,\n\t\talignRef,\n\t\toffsetRef,\n\t\trecomputeKeyRef,\n\t]);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tconst handle = handleRef.current;\n\t\tconst applied = appliedRef.current;\n\t\tif (!handle || !applied) return;\n\t\t// Resolved here rather than compared as an option, so a surface\n\t\t// retargeted from one anchor onto another recomputes even though the\n\t\t// three geometry options never moved. Without it the panel stays pinned\n\t\t// where the previous anchor stood until a scroll or a resize happens to\n\t\t// fire, which for a surface over a static page is never.\n\t\tconst nextAnchor = resolveAnchor();\n\t\tif (\n\t\t\tapplied.side === side &&\n\t\t\tapplied.align === align &&\n\t\t\tapplied.offset === offset &&\n\t\t\tapplied.anchor === nextAnchor &&\n\t\t\tapplied.recomputeKey === recomputeKey\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tappliedRef.current = { side, align, offset, anchor: nextAnchor, recomputeKey };\n\t\thandle.update({\n\t\t\tanchor: resolveAnchor,\n\t\t\tside,\n\t\t\talign,\n\t\t\toffset,\n\t\t\tonPlacement: handlePlacement,\n\t\t});\n\t\t// `options.anchor` is listed for its CHANGES, not its value: the effect\n\t\t// reads the anchor through `resolveAnchor`'s live ref, and a new anchor\n\t\t// option is the only signal React gives that the resolved element may\n\t\t// have moved. An inline arrow's fresh identity re-runs this for one\n\t\t// pointer comparison and no layout read.\n\t}, [node, side, align, offset, recomputeKey, options.anchor, resolveAnchor, handlePlacement]);\n\n\treturn placement;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/use-anchor-position.ts"},{"path":"react/src/internals/use-autoscroll.ts","content":"\"use client\";\n\n/**\n * Autoscroll (scroll anchor)\n *\n * Keeps a scrollable container pinned to its bottom edge while new content\n * streams in, and lets go the moment the reader scrolls up to look back.\n *\n * \"Stuck\" is a pure function of the distance from the bottom, recomputed on\n * every scroll event. There is no programmatic-scroll flag to get out of\n * sync: whatever the scrollbar says is the truth. It stays a closure\n * variable in `attachAutoscroll` — never React state — for exactly that\n * reason.\n */\n\nimport { useRef } from \"react\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useIsomorphicLayoutEffect } from \"./dom/ssr\";\n\nexport interface AutoscrollOptions {\n\t/** Set to false to release the container and disconnect every listener. */\n\tenabled?: boolean;\n\t/** How close to the bottom (px) still counts as pinned. */\n\tbottomThreshold?: number;\n\t/**\n\t * Start pinned and jump to the bottom on connect, whatever the\n\t * container's scroll position says. For a region that mounts with\n\t * content already in it — a reasoning trace joined mid-stream, a\n\t * replayed transcript — a fresh container sits at scrollTop 0, which\n\t * reads as \"the reader scrolled up\" and would leave every later chunk\n\t * stranded at the top.\n\t */\n\tpinOnConnect?: boolean;\n\t/** Called only when the pinned state flips, never on every scroll. */\n\tonStickChange?: (stuck: boolean) => void;\n}\n\nconst DEFAULT_BOTTOM_THRESHOLD = 40;\n\n/** Jump a container to its bottom. Smooth by default. */\nexport function scrollToBottom(node: HTMLElement, behavior: ScrollBehavior = \"smooth\"): void {\n\tif (typeof node.scrollTo === \"function\") {\n\t\tnode.scrollTo({ top: node.scrollHeight, behavior });\n\t} else {\n\t\tnode.scrollTop = node.scrollHeight;\n\t}\n}\n\nexport interface AutoscrollHandle {\n\tupdate(next: AutoscrollOptions): void;\n\tdestroy(): void;\n}\n\nexport function attachAutoscroll(node: HTMLElement, opts: AutoscrollOptions = {}): AutoscrollHandle {\n\tlet options = opts;\n\tlet frame: number | null = null;\n\tlet mutations: MutationObserver | null = null;\n\tlet resizes: ResizeObserver | null = null;\n\tlet connected = false;\n\n\tfunction isAtBottom(): boolean {\n\t\tconst threshold = options.bottomThreshold ?? DEFAULT_BOTTOM_THRESHOLD;\n\t\treturn node.scrollHeight - node.scrollTop - node.clientHeight <= threshold;\n\t}\n\n\t// Content that fits its container counts as pinned.\n\tlet stuck = isAtBottom();\n\n\tfunction handleScroll(): void {\n\t\tconst next = isAtBottom();\n\t\tif (next === stuck) return;\n\t\tstuck = next;\n\t\toptions.onStickChange?.(next);\n\t}\n\n\tfunction pin(): void {\n\t\tframe = null;\n\t\t// The reader may have scrolled away between the mutation and this\n\t\t// frame.\n\t\tif (!stuck) return;\n\t\t// Always instant: a smooth scroll still in flight reads as \"not at\n\t\t// the bottom\" on the next scroll event, which would unstick us\n\t\t// mid-animation.\n\t\tnode.scrollTop = node.scrollHeight;\n\t}\n\n\tfunction schedulePin(): void {\n\t\tif (!stuck || frame !== null) return;\n\t\tframe = requestAnimationFrame(pin);\n\t}\n\n\t/*\n\t * The container itself has a fixed height, so watching only it misses\n\t * every way already-rendered content grows without touching the child\n\t * list: an image finishing its download, a web font swapping in, a row\n\t * expanding under CSS. Watching the rows too catches those, and tracking\n\t * them through the mutation records keeps the cost proportional to what\n\t * changed rather than re-walking the whole transcript on every streamed\n\t * token.\n\t */\n\tfunction observeRows(records: MutationRecord[]): void {\n\t\tif (!resizes) return;\n\t\tfor (const record of records) {\n\t\t\tif (record.target !== node) continue;\n\t\t\tfor (const added of record.addedNodes) {\n\t\t\t\tif (added instanceof Element) resizes.observe(added);\n\t\t\t}\n\t\t\tfor (const removed of record.removedNodes) {\n\t\t\t\tif (removed instanceof Element) resizes.unobserve(removed);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Content can reach the bottom edge without anyone scrolling — a row\n\t * removed, a collapsed block, a container that grew taller than its\n\t * content. Nothing fires a scroll event for that, so without this the\n\t * container stays released for good. Only ever re-sticks: growth\n\t * momentarily puts new content below the viewport, and unsticking on\n\t * that would cancel the very pin it is about to do.\n\t */\n\tfunction restick(): void {\n\t\tif (stuck || !isAtBottom()) return;\n\t\tstuck = true;\n\t\toptions.onStickChange?.(true);\n\t}\n\n\tfunction handleMutations(records: MutationRecord[]): void {\n\t\tobserveRows(records);\n\t\trestick();\n\t\tschedulePin();\n\t}\n\n\tfunction handleResize(): void {\n\t\trestick();\n\t\tschedulePin();\n\t}\n\n\tfunction connect(): void {\n\t\tif (connected) return;\n\t\tconnected = true;\n\t\tif (options.pinOnConnect) {\n\t\t\tstuck = true;\n\t\t\tnode.scrollTop = node.scrollHeight;\n\t\t}\n\t\tnode.addEventListener(\"scroll\", handleScroll, { passive: true });\n\t\tmutations = new MutationObserver(handleMutations);\n\t\tmutations.observe(node, { childList: true, subtree: true, characterData: true });\n\t\tif (typeof ResizeObserver !== \"undefined\") {\n\t\t\tresizes = new ResizeObserver(handleResize);\n\t\t\tresizes.observe(node);\n\t\t\tfor (const row of node.children) resizes.observe(row);\n\t\t}\n\t}\n\n\tfunction disconnect(): void {\n\t\tconnected = false;\n\t\tnode.removeEventListener(\"scroll\", handleScroll);\n\t\tmutations?.disconnect();\n\t\tmutations = null;\n\t\tresizes?.disconnect();\n\t\tresizes = null;\n\t\tif (frame !== null) {\n\t\t\tcancelAnimationFrame(frame);\n\t\t\tframe = null;\n\t\t}\n\t}\n\n\tif (options.enabled !== false) connect();\n\n\treturn {\n\t\tupdate(next: AutoscrollOptions = {}) {\n\t\t\tconst wasConnected = connected;\n\t\t\toptions = next;\n\t\t\tif (next.enabled === false) {\n\t\t\t\tdisconnect();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconnect();\n\t\t\t// A threshold handed over mid-flight changes the answer to \"is\n\t\t\t// this pinned?\" with nothing else moving, and connect() is a\n\t\t\t// no-op on an already-connected container, so the reading is\n\t\t\t// refreshed here.\n\t\t\tif (wasConnected) handleScroll();\n\t\t},\n\t\tdestroy: disconnect,\n\t};\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\n/**\n * Keeps `node` pinned to its bottom edge while content streams in. Mounts\n * and destroys the core in a layout effect — `pinOnConnect`'s jump writes\n * `scrollTop`, and a post-paint write is a visible jump — and re-syncs\n * whenever an option that changes the pinning rules changes.\n */\nexport function useAutoscroll(node: HTMLElement | null, options: AutoscrollOptions = {}): void {\n\tconst handleRef = useRef<AutoscrollHandle | null>(null);\n\tconst onStickChange = useEventCallback(options.onStickChange);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tif (!node) return;\n\t\tconst handle = attachAutoscroll(node, { ...options, onStickChange });\n\t\thandleRef.current = handle;\n\t\treturn () => {\n\t\t\thandle.destroy();\n\t\t\thandleRef.current = null;\n\t\t};\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [node]);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\thandleRef.current?.update({ ...options, onStickChange });\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [node, options.enabled, options.bottomThreshold, onStickChange]);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/use-autoscroll.ts"},{"path":"react/src/internals/use-copy.ts","content":"\"use client\";\n\n/**\n * Copy-to-clipboard state.\n *\n * Wraps the async clipboard write in a `copied` flag that falls back to\n * `false` on its own, so a button can show a transient \"Copied!\" label\n * without owning a timer. Nothing is scheduled at construction, and the\n * clipboard API is only touched inside `copy()`, which keeps `createCopy`\n * safe to call during a render.\n */\n\nimport { useEffect, useSyncExternalStore } from \"react\";\nimport { useConstant } from \"./dom/ssr\";\n\nexport interface CopyState {\n\t/** True from a successful copy until `resetMs` has elapsed. */\n\treadonly copied: boolean;\n\t/** Writes `text` to the clipboard. Resolves false instead of throwing. */\n\tcopy(text: string): Promise<boolean>;\n\t/** Cancels a pending reset. Call from the consumer's teardown. */\n\tdestroy(): void;\n\t/**\n\t * Undoes a `destroy()`, so the instance accepts copies again.\n\t *\n\t * Not part of the Svelte source's surface, and needed for the same\n\t * reason `subscribe` is: Svelte runs a teardown exactly once, at the end\n\t * of the owner's life, so `destroyed` there is a one-way latch. React\n\t * runs the whole mount/teardown/mount rehearsal in development\n\t * StrictMode, which latches `destroyed` on an instance that is about to\n\t * be used for real — after which `copy()` returns early forever and\n\t * `copied` never flips. `useCopy` pairs `arm()` with `destroy()` in one\n\t * effect so the rehearsal is a no-op; a pure-factory consumer that calls\n\t * `destroy()` once never touches this.\n\t */\n\tarm(): void;\n\t/**\n\t * Subscribe to every change of `copied`. Not part of the Svelte source's\n\t * surface — the React counterpart of the `$state` rune that made `copied`\n\t * reactive there; `useCopy` is what actually reads this.\n\t */\n\tsubscribe(listener: () => void): () => void;\n}\n\nexport function createCopy(resetMs = 2000): CopyState {\n\tlet copied = false;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet destroyed = false;\n\t// A permission prompt can hold a write open for as long as the reader\n\t// takes to answer it, which is long enough to unmount the owner or start\n\t// another copy.\n\tlet ticket = 0;\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify(): void {\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\tfunction clearTimer(): void {\n\t\tif (timer !== undefined) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t}\n\n\treturn {\n\t\tget copied() {\n\t\t\treturn copied;\n\t\t},\n\n\t\tasync copy(text: string): Promise<boolean> {\n\t\t\tif (typeof navigator === \"undefined\" || !navigator.clipboard?.writeText) return false;\n\t\t\tconst mine = ++ticket;\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(text);\n\t\t\t} catch {\n\t\t\t\t// Denied permission, insecure context, or a user-agent that\n\t\t\t\t// rejects writes outside a user gesture.\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// The write landed, so the caller is told so either way; it just no\n\t\t\t// longer owns the flag. Writing it here would either resurrect\n\t\t\t// state on a destroyed helper or arm a timer teardown can no\n\t\t\t// longer cancel.\n\t\t\tif (destroyed || mine !== ticket) return true;\n\t\t\tcopied = true;\n\t\t\tnotify();\n\t\t\t// A re-copy restarts the window rather than inheriting the old\n\t\t\t// deadline.\n\t\t\tclearTimer();\n\t\t\ttimer = setTimeout(() => {\n\t\t\t\tcopied = false;\n\t\t\t\ttimer = undefined;\n\t\t\t\tnotify();\n\t\t\t}, resetMs);\n\t\t\treturn true;\n\t\t},\n\n\t\tdestroy() {\n\t\t\tdestroyed = true;\n\t\t\tclearTimer();\n\t\t},\n\n\t\tarm() {\n\t\t\tdestroyed = false;\n\t\t},\n\n\t\tsubscribe(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\nexport interface UseCopyResult {\n\treadonly copied: boolean;\n\tcopy(text: string): Promise<boolean>;\n}\n\n/**\n * `copied` flips true on a successful `copy()` and resets after `resetMs`.\n * Built once per component instance; `destroy()` — the direct analogue of\n * the source's \"call from the consumer's teardown\" — runs in the hook's own\n * cleanup, so it can never be forgotten (D-5).\n *\n * The effect arms the instance on the way in and destroys it on the way out,\n * as one pair. StrictMode's mount/teardown/mount rehearsal therefore leaves\n * a live, usable instance behind instead of a permanently destroyed one; a\n * real unmount still ends on `destroy()`, since nothing arms it again.\n */\nexport function useCopy(resetMs = 2000): UseCopyResult {\n\tconst state = useConstant(() => createCopy(resetMs));\n\tconst copied = useSyncExternalStore(state.subscribe, () => state.copied, () => state.copied);\n\n\tuseEffect(() => {\n\t\tstate.arm();\n\t\treturn state.destroy;\n\t}, [state]);\n\n\treturn { copied, copy: state.copy };\n}\n","type":"registry:lib","target":"@ui/fancy/internals/use-copy.ts"},{"path":"react/src/internals/use-elapsed.ts","content":"\"use client\";\n\n/**\n * Elapsed-time state.\n *\n * Every value is derived from the wall clock (`Date.now() - since`) on each\n * tick rather than accumulated tick by tick, so a throttled background tab\n * that fires one interval instead of sixty still reports the true elapsed\n * duration.\n *\n * Nothing is scheduled at construction time: timers only exist between\n * `start()` and `stop()`, which keeps `createElapsed`/`createNow` safe to\n * build during a render. Consumers start them from an effect — `useElapsed`\n * and `useNow` do this for you.\n */\n\nimport { useEffect, useReducer, useSyncExternalStore } from \"react\";\nimport { useConstant, useIsomorphicLayoutEffect } from \"./dom/ssr\";\nimport { useLiveRef } from \"./dom/use-live-ref\";\n\nconst MINUTE = 60_000;\nconst HOUR = 3_600_000;\n\nfunction pad(value: number): string {\n\treturn value < 10 ? `0${value}` : String(value);\n}\n\n/**\n * Format a duration in milliseconds as a compact stopwatch string:\n * `\"0s\"`, `\"42s\"`, `\"1m 05s\"`, `\"1h 03m\"`. Negative and non-finite input\n * collapses to `\"0s\"`.\n */\nexport function formatElapsed(ms: number): string {\n\tif (!Number.isFinite(ms) || ms <= 0) return \"0s\";\n\tconst seconds = Math.floor(ms / 1000);\n\tif (ms < MINUTE) return `${seconds}s`;\n\tif (ms < HOUR) return `${Math.floor(ms / MINUTE)}m ${pad(seconds % 60)}s`;\n\treturn `${Math.floor(ms / HOUR)}h ${pad(Math.floor((ms % HOUR) / MINUTE))}m`;\n}\n\nexport interface ElapsedOptions {\n\t/** Epoch ms the duration is measured from. Defaults to the moment `start()` runs. */\n\tsince?: number;\n\t/** How often the reported value refreshes. Defaults to 1000. */\n\ttickMs?: number;\n}\n\nexport interface ElapsedState {\n\treadonly ms: number;\n\treadonly text: string;\n\treadonly running: boolean;\n\t/** Start (or restart) ticking. Returns the matching stop function. */\n\tstart(since?: number): () => void;\n\tstop(): void;\n\t/**\n\t * Subscribe to every change of `ms`/`running`. Not part of the Svelte\n\t * source's surface — the React counterpart of the `$state` runes that\n\t * made `ms`/`running` reactive there; `useElapsed` is what actually reads\n\t * this. Pure factory consumers never need it.\n\t */\n\tsubscribe(listener: () => void): () => void;\n}\n\n/** Reactive stopwatch: milliseconds since `since`, refreshed every `tickMs`. */\nexport function createElapsed(opts: ElapsedOptions = {}): ElapsedState {\n\tconst tickMs = opts.tickMs ?? 1000;\n\tlet since = opts.since;\n\t// A caller-supplied `since` is already in the past, so the first paint\n\t// shows the real duration instead of zero.\n\tlet ms = since === undefined ? 0 : Math.max(0, Date.now() - since);\n\tlet running = false;\n\tlet timer: ReturnType<typeof setInterval> | undefined;\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify(): void {\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\tfunction sync(): void {\n\t\tms = Math.max(0, Date.now() - (since as number));\n\t\tnotify();\n\t}\n\n\tfunction stop(): void {\n\t\tif (timer !== undefined) {\n\t\t\tclearInterval(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t\tif (running) {\n\t\t\trunning = false;\n\t\t\tnotify();\n\t\t}\n\t}\n\n\tfunction start(nextSince?: number): () => void {\n\t\tstop();\n\t\tsince = nextSince ?? since ?? Date.now();\n\t\tsync();\n\t\trunning = true;\n\t\ttimer = setInterval(sync, tickMs);\n\t\tnotify();\n\t\treturn stop;\n\t}\n\n\treturn {\n\t\tget ms() {\n\t\t\treturn ms;\n\t\t},\n\t\tget text() {\n\t\t\treturn formatElapsed(ms);\n\t\t},\n\t\tget running() {\n\t\t\treturn running;\n\t\t},\n\t\tstart,\n\t\tstop,\n\t\tsubscribe(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n}\n\nexport interface NowState {\n\treadonly value: number;\n\t/** Start refreshing. Returns the matching stop function. */\n\tstart(): () => void;\n\tstop(): void;\n\t/** Subscribe to every refresh. See `ElapsedState.subscribe`. */\n\tsubscribe(listener: () => void): () => void;\n}\n\n/**\n * A single shared \"now\" that a whole list can read, so a thread of fifty\n * timestamps costs one interval instead of fifty.\n */\nexport function createNow(refreshMs = 30_000): NowState {\n\tlet value = Date.now();\n\tlet timer: ReturnType<typeof setInterval> | undefined;\n\tconst listeners = new Set<() => void>();\n\n\tfunction notify(): void {\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\tfunction stop(): void {\n\t\tif (timer !== undefined) {\n\t\t\tclearInterval(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t}\n\n\tfunction start(): () => void {\n\t\tstop();\n\t\tvalue = Date.now();\n\t\ttimer = setInterval(() => {\n\t\t\tvalue = Date.now();\n\t\t\tnotify();\n\t\t}, refreshMs);\n\t\treturn stop;\n\t}\n\n\treturn {\n\t\tget value() {\n\t\t\treturn value;\n\t\t},\n\t\tstart,\n\t\tstop,\n\t\tsubscribe(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\nexport interface UseElapsedResult {\n\treadonly ms: number;\n\treadonly text: string;\n\treadonly running: boolean;\n\tstart(since?: number): () => void;\n\tstop(): void;\n}\n\n/**\n * `useElapsed`'s server snapshot, and therefore also the value React reads\n * during the hydration render: a flat zero, which `formatElapsed` renders as\n * `\"0s\"`.\n *\n * `createElapsed` seeds itself from the wall clock when `since` is given —\n * \"a caller-supplied `since` is already in the past, so the first paint shows\n * the real duration instead of zero\". On the server that seed is the\n * SERVER's clock, and the hydration render on the client re-runs the same\n * factory against the CLIENT's clock some hundreds of milliseconds later, so\n * the two renders disagree by exactly the transport time and React reports a\n * hydration mismatch on every stopwatch on the page (§7: nothing may differ\n * between a server render and its hydration).\n *\n * Zero is the one value both sides are guaranteed to produce, and it is the\n * value `createElapsed` itself starts at with no `since` at all — so the\n * server HTML ships the honest \"not yet counting\" label rather than one\n * measured against a clock the client cannot reproduce. This is the same\n * trade `useNow` makes below, with `0` in place of `NaN` because `ms` is\n * documented as a number consumers may do arithmetic with, and because\n * `formatElapsed` collapses both to `\"0s\"` anyway.\n *\n * DIVERGENCE from Svelte, whose SSR pass ships the server-measured duration.\n */\nfunction getServerElapsed(): number {\n\treturn 0;\n}\n\n/**\n * Reactive stopwatch. Built once (`ElapsedOptions` is read only at mount,\n * matching the Svelte source's `createElapsed(opts)` call site — a changed\n * `tickMs`/`since` prop does not retarget a running timer) and subscribed\n * through `useSyncExternalStore`; `text` is derived per render from `ms`,\n * exactly as the source's getter does. Nothing is scheduled by the hook\n * itself — call the returned `start()` from your own effect or handler,\n * same as the Svelte side.\n *\n * A client-only render reads the live value straight away, exactly as\n * before; only a hydration render takes the deterministic seed, and the\n * layout effect below replaces it before the first paint.\n */\nexport function useElapsed(options: ElapsedOptions = {}): UseElapsedResult {\n\tconst elapsed = useConstant(() => createElapsed(options));\n\tconst ms = useSyncExternalStore(elapsed.subscribe, () => elapsed.ms, getServerElapsed);\n\tconst running = useSyncExternalStore(\n\t\telapsed.subscribe,\n\t\t() => elapsed.running,\n\t\t// Deterministic on both sides for a different reason: nothing has\n\t\t// started the stopwatch by the time the first render runs, so the\n\t\t// store's own value is `false` here too.\n\t\t() => false\n\t);\n\n\t// Written in an insertion effect, never in the render body: an insertion\n\t// effect runs before every layout effect in the same commit, so the\n\t// comparison below still reads the value this commit rendered, and a\n\t// concurrent render React throws away can no longer publish one the commit\n\t// never used. A stale value here either bumps for nothing or, in the\n\t// missed direction, skips the bump and paints the very frame it exists to\n\t// close.\n\tconst rendered = useLiveRef(ms);\n\tconst [, bump] = useReducer(bumpReducer, 0);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\t// React only notices that an external store disagrees with its server\n\t\t// snapshot in the passive phase, which is a phase too late: the\n\t\t// browser would paint one frame of \"0s\" over a stopwatch that already\n\t\t// knows its real duration. Re-rendering here, in the layout phase,\n\t\t// closes that frame. Only a hydrated tree can ever see the gap — a\n\t\t// client-only render read the live value to begin with, so the\n\t\t// comparison is false and nothing is scheduled.\n\t\tif (elapsed.ms !== rendered.current) bump();\n\t}, [elapsed, bump]);\n\n\tuseEffect(() => elapsed.stop, [elapsed]);\n\n\treturn { ms, text: formatElapsed(ms), running, start: elapsed.start, stop: elapsed.stop };\n}\n\n/**\n * The one shared clock behind `useNow`.\n *\n * Its listener set and its published value outlive any individual `createNow`\n * instance. That separation is the whole point: a retain count that reaches\n * zero and climbs back to one — which is exactly what StrictMode's\n * mount/teardown/mount rehearsal does — swaps the underlying interval without\n * ever stranding a subscriber on a dead instance, and no consumer holds a\n * reference to an instance that can go stale.\n *\n * Nothing here is touched from a render path: `retain()` is called only from\n * a layout effect and `subscribe()` only from React's own store\n * subscription, so no `Date.now()` and no module-state write happens while\n * rendering (C-7).\n */\nconst sharedClock = (() => {\n\tconst listeners = new Set<() => void>();\n\tlet clock: NowState | null = null;\n\tlet stopClock: (() => void) | null = null;\n\tlet retained = 0;\n\t/*\n\t * Seeded to `NaN` — the documented \"no clock yet\" sentinel — never to\n\t * `Date.now()`: sampling the wall clock here would be a `Date.now()` read\n\t * on a render path (C-7), and a server render could never agree with the\n\t * hydration render that follows it. `NaN` is the one value both renders\n\t * are guaranteed to produce, `Object.is(NaN, NaN)` is true so\n\t * `useSyncExternalStore` sees a stable snapshot, and\n\t * `formatRelativeTime` renders a non-finite `now` as the empty string —\n\t * so a pre-clock render emits no label rather than the \"in 57 years\" a\n\t * seed of 0 produces for every present-day timestamp. The first retain\n\t * replaces it with a real timestamp in the layout phase, before the first\n\t * paint.\n\t */\n\tlet value = Number.NaN;\n\n\tfunction publish(): void {\n\t\tif (clock) value = clock.value;\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\treturn {\n\t\tgetValue(): number {\n\t\t\treturn value;\n\t\t},\n\n\t\tsubscribe(listener: () => void): () => void {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t};\n\t\t},\n\n\t\t/**\n\t\t * Keep the interval running for as long as the returned release is\n\t\t * uncalled. Each release is idempotent and belongs to exactly one\n\t\t * retain, so however React interleaves mounts, remounts and\n\t\t * rehearsals, the count cannot drift.\n\t\t */\n\t\tretain(refreshMs: number): () => void {\n\t\t\tretained += 1;\n\t\t\tif (retained === 1) {\n\t\t\t\t// The first consumer to arrive owns the cadence; later ones\n\t\t\t\t// share the interval already running rather than starting a\n\t\t\t\t// second.\n\t\t\t\tclock = createNow(refreshMs);\n\t\t\t\tclock.subscribe(publish);\n\t\t\t\tstopClock = clock.start();\n\t\t\t\tpublish();\n\t\t\t}\n\t\t\tlet released = false;\n\t\t\treturn () => {\n\t\t\t\tif (released) return;\n\t\t\t\treleased = true;\n\t\t\t\tretained -= 1;\n\t\t\t\tif (retained === 0) {\n\t\t\t\t\tstopClock?.();\n\t\t\t\t\tstopClock = null;\n\t\t\t\t\tclock = null;\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t};\n})();\n\n/**\n * `useNow`'s server snapshot, and therefore also the value React reads\n * during hydration: the `NaN` sentinel, so the two renders cannot disagree.\n * The real clock arrives in the first commit after hydration.\n *\n * DIVERGENCE from Svelte, registered in `migration-matrix.json` and the\n * README: `createNow` seeds itself with `Date.now()` at construction, so a\n * Svelte server render ships real relative labels. React cannot — the client\n * has no way to reproduce the server's timestamp, so any real value here is\n * a hydration mismatch. The sentinel makes the server HTML carry an empty\n * label instead of a wrong one; every consumer fills it in during the layout\n * phase of hydration, before the first paint.\n */\nfunction getServerNow(): number {\n\treturn Number.NaN;\n}\n\nfunction bumpReducer(n: number): number {\n\treturn n + 1;\n}\n\n/**\n * A shared \"now\", refreshed every `refreshMs` (30s by default) and reused by\n * every `useNow` call in the tree — the React-native form of `createNow`'s\n * whole reason for existing: a thread of fifty timestamps shares one\n * interval instead of paying for fifty. The refresh cadence is set by\n * whichever consumer mounts first; a later `useNow` with a different\n * `refreshMs` shares the interval already running rather than starting a\n * second one. The interval stops once the last consumer unmounts.\n *\n * Before the first consumer anywhere on the page has mounted, the clock has\n * no value to give and the hook returns `NaN` — the sentinel a server render\n * and the hydration render that follows it are guaranteed to agree on, and\n * the one `formatRelativeTime` turns into an empty label rather than a wrong\n * one. Callers must therefore either pass the value straight to\n * `formatRelativeTime` (which guards it) or check `Number.isFinite` before\n * doing arithmetic with it. Every later consumer, including one that mounts\n * after the clock has been torn down and rebuilt, renders a real timestamp\n * immediately.\n */\nexport function useNow(refreshMs = 30_000): number {\n\tconst value = useSyncExternalStore(sharedClock.subscribe, sharedClock.getValue, getServerNow);\n\t// An insertion effect rather than the render body, for the reason spelled\n\t// out on `useElapsed`'s copy above.\n\tconst rendered = useLiveRef(value);\n\tconst [, bump] = useReducer(bumpReducer, 0);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\tconst release = sharedClock.retain(refreshMs);\n\t\t// React subscribes to an external store in the passive phase, which\n\t\t// is a phase too late: the browser would paint one frame of the\n\t\t// pre-clock sentinel before the clock this effect just started is heard\n\t\t// from. Re-rendering here, in the layout phase, closes that frame.\n\t\t// Only the first consumer on a page can ever see the gap — from then\n\t\t// on the clock's last value survives its interval.\n\t\tif (sharedClock.getValue() !== rendered.current) bump();\n\t\treturn release;\n\t}, [refreshMs, bump]);\n\n\treturn value;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/use-elapsed.ts"},{"path":"react/src/internals/use-float.ts","content":"\"use client\";\n\n/**\n * Floating element positioning — the DOM-observing half of `float.ts`.\n *\n * `attachFloat` is the framework-free core (the Svelte `float` action's exact\n * body, ported as-is: same rAF coalescing, same ResizeObserver watch on the\n * float and its anchor, same visibility hiding while a getter anchor has\n * nothing to point at). `useFloat` is a thin React binding on top, shaped\n * like `use-anchor-position.ts`: a node-first hook that mounts and destroys\n * the core in a layout effect (a post-paint position is a visible jump from\n * the origin) and returns the placement as actually resolved.\n */\n\nimport { useRef, useState } from \"react\";\nimport { useEventCallback } from \"./dom/use-event-callback\";\nimport { useIsomorphicLayoutEffect } from \"./dom/ssr\";\nimport { computeFloatPosition } from \"./float\";\nimport type { FloatOptions, FloatPlacement, FloatRect } from \"./float\";\n\nconst DEFAULT_PLACEMENT: FloatPlacement = \"bottom-start\";\n\n// =============================================================================\n// Core (verbatim body of the Svelte `float` action)\n// =============================================================================\n\n/**\n * Internal-only extension of `FloatOptions`: a hook can't observe the\n * placement `attachFloat` writes onto `node.dataset.placement` without a\n * callback, so the hook layer threads one through here. Not part of the\n * public `FloatOptions` shape — the ported action test never passes it, and\n * omitting it reproduces the exact original behaviour.\n */\ninterface AttachFloatOptions extends FloatOptions {\n\tonPlacement?: (placement: FloatPlacement) => void;\n}\n\nexport interface FloatHandle {\n\t/** Swaps the options and re-syncs — the action's `update` under a new name. */\n\tupdate(next: AttachFloatOptions): void;\n\t/** Detaches every listener/observer and strips the node's own styles. */\n\tdestroy(): void;\n}\n\nfunction readAnchor(anchor: FloatOptions[\"anchor\"]): FloatRect | null {\n\tif (typeof anchor === \"function\") return anchor();\n\tif (typeof (anchor as HTMLElement).getBoundingClientRect === \"function\") {\n\t\tconst { x, y, width, height } = (anchor as HTMLElement).getBoundingClientRect();\n\t\treturn { x, y, width, height };\n\t}\n\treturn anchor as FloatRect;\n}\n\nfunction anchorElement(anchor: FloatOptions[\"anchor\"]): HTMLElement | null {\n\tif (typeof anchor !== \"object\" || anchor === null) return null;\n\treturn typeof (anchor as HTMLElement).getBoundingClientRect === \"function\"\n\t\t? (anchor as HTMLElement)\n\t\t: null;\n}\n\n/**\n * Positions `node` with `position: fixed` against a live anchor, using\n * `computeFloatPosition`. Recomputes on scroll/resize (coalesced into one\n * rAF) and on a ResizeObserver watching both the float and its anchor\n * element. SSR-safe: does nothing when `window` is unavailable.\n */\nexport function attachFloat(node: HTMLElement, opts: AttachFloatOptions): FloatHandle {\n\tif (typeof window === \"undefined\") {\n\t\treturn { update() {}, destroy() {} };\n\t}\n\n\tlet options = opts;\n\tlet frame: number | null = null;\n\tlet listening = false;\n\tlet sizes: ResizeObserver | null = null;\n\tlet reportedPlacement: FloatPlacement | null = null;\n\n\tconst position = () => {\n\t\t// Out of flow *before* the anchor is measured. A float rendered as a\n\t\t// sibling of its anchor still occupies a slot in the layout until this\n\t\t// line runs, and that slot pushes the anchor somewhere it will not be\n\t\t// once the float is fixed — so a rect read first describes a position\n\t\t// that no longer exists, and the float lands beside it for good.\n\t\tnode.style.position = \"fixed\";\n\t\tnode.style.visibility = \"\";\n\n\t\tconst anchor = readAnchor(options.anchor);\n\t\tif (!anchor) {\n\t\t\tnode.style.visibility = \"hidden\";\n\t\t\treturn;\n\t\t}\n\t\t// Still ahead of the node's own measurement: a forced width changes how\n\t\t// the content wraps, and therefore the height the placement is computed\n\t\t// from.\n\t\tnode.style.width = options.matchWidth ? `${anchor.width}px` : \"\";\n\n\t\tconst box = node.getBoundingClientRect();\n\t\tconst { top, left, placement } = computeFloatPosition(\n\t\t\tanchor,\n\t\t\t{ width: box.width, height: box.height },\n\t\t\t{ width: window.innerWidth, height: window.innerHeight },\n\t\t\t{\n\t\t\t\tplacement: options.placement ?? \"bottom-start\",\n\t\t\t\toffset: options.offset ?? 6,\n\t\t\t\tpadding: options.padding ?? 8,\n\t\t\t}\n\t\t);\n\t\tnode.style.top = `${top}px`;\n\t\tnode.style.left = `${left}px`;\n\t\tnode.dataset.placement = placement;\n\n\t\tif (placement !== reportedPlacement) {\n\t\t\treportedPlacement = placement;\n\t\t\toptions.onPlacement?.(placement);\n\t\t}\n\t};\n\n\tconst schedule = () => {\n\t\tif (frame !== null) return;\n\t\tframe = requestAnimationFrame(() => {\n\t\t\tframe = null;\n\t\t\tposition();\n\t\t});\n\t};\n\n\t/*\n\t * Scroll and resize only cover the viewport moving under the pair. A menu\n\t * whose results arrive asynchronously, a font swap, or an anchor that grows\n\t * changes the geometry with no global event to hear, leaving the float\n\t * stale against its anchor or overflowing the edge it was flipped away\n\t * from. Re-observed on every sync because `update` may hand over another\n\t * anchor.\n\t */\n\tconst observeSizes = () => {\n\t\tif (typeof ResizeObserver === \"undefined\") return;\n\t\tsizes ??= new ResizeObserver(schedule);\n\t\tsizes.disconnect();\n\t\tsizes.observe(node);\n\t\tconst anchor = anchorElement(options.anchor);\n\t\tif (anchor) sizes.observe(anchor);\n\t};\n\n\tconst listen = (on: boolean) => {\n\t\tif (on === listening) return;\n\t\tlistening = on;\n\t\tif (on) {\n\t\t\twindow.addEventListener(\"scroll\", schedule, { capture: true, passive: true });\n\t\t\twindow.addEventListener(\"resize\", schedule, { passive: true });\n\t\t} else {\n\t\t\twindow.removeEventListener(\"scroll\", schedule, { capture: true });\n\t\t\twindow.removeEventListener(\"resize\", schedule);\n\t\t\tsizes?.disconnect();\n\t\t\tsizes = null;\n\t\t}\n\t};\n\n\tconst reset = () => {\n\t\tif (frame !== null) cancelAnimationFrame(frame);\n\t\tframe = null;\n\t\tnode.style.position = \"\";\n\t\tnode.style.top = \"\";\n\t\tnode.style.left = \"\";\n\t\tnode.style.width = \"\";\n\t\tnode.style.visibility = \"\";\n\t\tdelete node.dataset.placement;\n\t};\n\n\tconst sync = () => {\n\t\tif (options.enabled === false) {\n\t\t\tlisten(false);\n\t\t\treset();\n\t\t\treturn;\n\t\t}\n\t\tlisten(true);\n\t\tobserveSizes();\n\t\tposition();\n\t};\n\n\tsync();\n\n\treturn {\n\t\tupdate(next: AttachFloatOptions) {\n\t\t\toptions = next;\n\t\t\tsync();\n\t\t},\n\t\tdestroy() {\n\t\t\tlisten(false);\n\t\t\tsizes?.disconnect();\n\t\t\tsizes = null;\n\t\t\t// `reset()` rather than an inline frame cancel: it cancels the same\n\t\t\t// pending frame AND strips `position`/`top`/`left`/`width`/\n\t\t\t// `visibility` and `data-placement`, which is what this handle's\n\t\t\t// own documentation promises and what the `enabled: false` path\n\t\t\t// already does through `sync()`. A destroy that only unhooks\n\t\t\t// leaves a node the caller keeps mounted fixed at its last\n\t\t\t// coordinates, sized to an anchor it no longer tracks.\n\t\t\t//\n\t\t\t// DIVERGENCE from the Svelte action, deliberate: there, destroy\n\t\t\t// coincides with the node's removal, so the leftovers are\n\t\t\t// unobservable.\n\t\t\treset();\n\t\t},\n\t};\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\nexport interface UseFloatResult {\n\t/** The placement as actually resolved — flipped when the requested side ran out of room. */\n\treadonly placement: FloatPlacement;\n}\n\n/**\n * Positions `node` with `position: fixed` against `options.anchor`. Mirrors\n * `useAnchorPosition`'s shape: one layout effect keyed `[node]` mounts and\n * destroys the core, a second re-syncs whenever an option that affects\n * geometry changes, and the resolved placement is returned rather than\n * discarded — the same collapse `useAnchorPosition`'s `onPlacement` return\n * value buys its own callers.\n */\nexport function useFloat(node: HTMLElement | null, options: FloatOptions): UseFloatResult {\n\tconst handleRef = useRef<FloatHandle | null>(null);\n\tconst [placement, setPlacement] = useState<FloatPlacement>(options.placement ?? DEFAULT_PLACEMENT);\n\tconst onPlacement = useEventCallback((next: FloatPlacement) => setPlacement(next));\n\n\t// Mount/destroy the core once per node. The update effect below runs on\n\t// the same commit and re-syncs against the current options immediately,\n\t// so this only ever positions with a momentarily stale option set when\n\t// both effects fire together at mount — exactly the anchor-position\n\t// pattern this hook mirrors.\n\tuseIsomorphicLayoutEffect(() => {\n\t\tif (!node) return;\n\t\tconst handle = attachFloat(node, { ...options, onPlacement });\n\t\thandleRef.current = handle;\n\t\treturn () => {\n\t\t\thandle.destroy();\n\t\t\thandleRef.current = null;\n\t\t};\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [node]);\n\n\tuseIsomorphicLayoutEffect(() => {\n\t\thandleRef.current?.update({ ...options, onPlacement });\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [\n\t\tnode,\n\t\toptions.anchor,\n\t\toptions.placement,\n\t\toptions.offset,\n\t\toptions.padding,\n\t\toptions.matchWidth,\n\t\toptions.enabled,\n\t\tonPlacement,\n\t]);\n\n\treturn { placement };\n}\n\n// Re-exported so a consumer of the hook module never needs a second import\n// from \"./float.js\" for the option/placement types it already has to name.\nexport type { FloatOptions, FloatPlacement, FloatRect } from \"./float\";\n","type":"registry:lib","target":"@ui/fancy/internals/use-float.ts"},{"path":"react/src/internals/use-id.ts","content":"\"use client\";\n\n// Ids for components that need to wire up aria-labelledby / aria-describedby\n// without colliding across instances.\n//\n// Two generators, and the choice between them is not a matter of taste:\n//\n// `useFancyId()` is THE id source a component reaches for. It wraps React's\n// `useId()`, so the id is identical in the server HTML and in the hydration\n// render — the counterpart of the Svelte side's `$props.id()`. Derive every\n// sub-id by suffixing one seed (`${id}-description`, `${id}-error`) rather\n// than calling it once per id.\n//\n// `uid()` is the module-scoped counter, kept for an id minted inside an event\n// handler or an effect. CLIENT-ONLY, and it throws rather than letting the\n// mistake through: the counter is shared by every request on a long-lived\n// server while a freshly loaded client bundle always restarts at 1, so an id\n// generated during SSR would never match the one the client regenerates on\n// hydration.\n//\n// The output of `useFancyId()` is NOT transformed. React's ids contain\n// delimiters (`:r0:` on 18, `«r0»` on 19) which are legal in `id`/`aria-*`\n// and in `getElementById`, and illegal in an unescaped `querySelector` — so\n// no id from here may ever become a CSS selector.\n\nimport { useId } from \"react\";\n\nlet n = 0;\n\n/**\n * A unique, SSR-stable id string for the calling component instance, e.g.\n * \"fui-«r0»\". Stable across the server render and hydration, and stable for\n * the life of the component.\n *\n * Call it once and suffix the result for every id the component needs; a\n * second call is a second seed, not a second id off the same one.\n *\n * @param prefix - Prefix for the generated id (defaults to \"fui\").\n */\nexport function useFancyId(prefix = \"fui\"): string {\n\tconst id = useId();\n\treturn `${prefix}-${id}`;\n}\n\n/**\n * Returns a unique, stable id string, e.g. \"fui-1\", \"fui-2\", ...\n *\n * Client-only: throws when called on the server, since the id produced\n * there would not match the one the client regenerates on hydration. Call\n * this only from browser-only code paths (effects, event handlers) — use\n * `useFancyId()` for ids that must survive SSR + hydration.\n *\n * @param prefix - Prefix for the generated id (defaults to \"fui\").\n */\nexport function uid(prefix = \"fui\"): string {\n\tif (typeof window === \"undefined\") {\n\t\tthrow new Error(\n\t\t\t\"uid() is client-only and must not be called during SSR; use useFancyId() for SSR-stable ids.\"\n\t\t);\n\t}\n\n\tn += 1;\n\treturn `${prefix}-${n}`;\n}\n","type":"registry:lib","target":"@ui/fancy/internals/use-id.ts"},{"path":"react/src/internals/use-text-stream.ts","content":"\"use client\";\n\n/**\n * Text stream\n *\n * The consumer pushes a growing string — the whole text so far, not the\n * delta — and this turns each growth step into a short-lived \"fresh\" segment\n * so a view can tint what just arrived. After `settleMs` the segment stops\n * being fresh and is merged back into its settled neighbours, so a long\n * stream never accumulates more than a handful of spans.\n *\n * A push that is not a continuation of the current text (a regenerated\n * answer, or chunks arriving out of order) is treated as a replacement: the\n * new text lands already settled, with nothing to animate from.\n *\n * Nothing is scheduled until the first push, so building one during a render\n * is safe.\n */\n\nimport { useEffect, useSyncExternalStore } from \"react\";\nimport { useConstant } from \"./dom/ssr\";\n\nconst DEFAULT_SETTLE_MS = 350;\n\nexport interface StreamSegment {\n\t/** Stable key for a keyed list; segments keep their id across merges. */\n\tid: number;\n\ttext: string;\n\t/** True while the segment is still animating in. */\n\tfresh: boolean;\n}\n\nexport interface TextStreamOptions {\n\t/**\n\t * How long a delta stays fresh before it settles, in ms. Pass a getter\n\t * when the value can change after construction: it is read once per\n\t * push, so a later duration applies to later chunks instead of only to\n\t * the CSS.\n\t */\n\tsettleMs?: number | (() => number);\n\t/** Set false to skip the animation entirely: every push settles at once. */\n\tanimate?: boolean;\n}\n\nexport interface TextStream {\n\t/** The current segments, oldest first. Reactive. */\n\treadonly segments: StreamSegment[];\n\t/** The full text pushed so far. Reactive. */\n\treadonly text: string;\n\t/** Hand over the whole text so far; the delta is worked out from it. */\n\tpush(fullText: string): void;\n\t/** Drop everything and start again from `text`, already settled. */\n\treset(text?: string): void;\n\t/** Settle every currently-fresh segment immediately, cancelling their timers. */\n\tflush(): void;\n\t/** Cancel pending settle timers. Call from the consumer's teardown. */\n\tdestroy(): void;\n\t/**\n\t * Re-arm a settle timer for every segment still marked fresh with nothing\n\t * left to settle it. Not part of the Svelte source's surface: it exists\n\t * because a React effect can be torn down and replayed without the\n\t * component ever unmounting (StrictMode's mount rehearsal), which runs\n\t * `destroy()` between a push and its settle. The replayed push is a no-op\n\t * — the full text is already stored — so without this the segment would\n\t * stay `fresh` for ever and `done` would never become true.\n\t */\n\tresume(): void;\n\t/**\n\t * Subscribe to every change of `segments`/`text`. Not part of the Svelte\n\t * source's surface — the React counterpart of the `$state.raw` runes that\n\t * made them reactive there; `useTextStream` is what actually reads this.\n\t */\n\tsubscribe(listener: () => void): () => void;\n}\n\nexport function createTextStream(initial = \"\", opts: TextStreamOptions = {}): TextStream {\n\tconst settleOption = opts.settleMs;\n\tconst settleAt =\n\t\ttypeof settleOption === \"function\" ? settleOption : () => settleOption ?? DEFAULT_SETTLE_MS;\n\tconst animate = opts.animate !== false;\n\n\t// `list` and `full` are the authoritative copies and are deliberately\n\t// ordinary variables: push() reads them but only ever writes the\n\t// published view below. That keeps push() safe to call from inside a\n\t// React effect, which would otherwise invalidate itself by reading the\n\t// same state it writes.\n\tlet list: StreamSegment[] = [];\n\tlet full = \"\";\n\tlet nextId = 0;\n\tconst timers = new Set<ReturnType<typeof setTimeout>>();\n\tconst listeners = new Set<() => void>();\n\n\tlet view: StreamSegment[] = [];\n\tlet textView = \"\";\n\n\tfunction notify(): void {\n\t\tfor (const listener of listeners) listener();\n\t}\n\n\t// Fresh objects on every publish: a keyed list compares item identity, so\n\t// reusing them would leave a settled segment rendered as fresh.\n\tfunction publish(): void {\n\t\tview = list.map((s) => ({ ...s }));\n\t\ttextView = full;\n\t\tnotify();\n\t}\n\n\tfunction clearTimers(): void {\n\t\tfor (const timer of timers) clearTimeout(timer);\n\t\ttimers.clear();\n\t}\n\n\t/** Fold every run of contiguous settled segments into its first segment. */\n\tfunction merge(): void {\n\t\tconst merged: StreamSegment[] = [];\n\t\tfor (const seg of list) {\n\t\t\tconst last = merged[merged.length - 1];\n\t\t\tif (last && !last.fresh && !seg.fresh) last.text += seg.text;\n\t\t\telse merged.push({ ...seg });\n\t\t}\n\t\tlist = merged;\n\t}\n\n\tfunction settle(id: number): void {\n\t\tconst seg = list.find((s) => s.id === id);\n\t\tif (!seg) return;\n\t\tseg.fresh = false;\n\t\tmerge();\n\t\tpublish();\n\t}\n\n\tfunction reset(text = \"\"): void {\n\t\tclearTimers();\n\t\tfull = text;\n\t\tlist = text ? [{ id: nextId++, text, fresh: false }] : [];\n\t\tpublish();\n\t}\n\n\tfunction scheduleSettle(id: number): void {\n\t\tconst timer = setTimeout(\n\t\t\t() => {\n\t\t\t\ttimers.delete(timer);\n\t\t\t\tsettle(id);\n\t\t\t},\n\t\t\tMath.max(0, settleAt())\n\t\t);\n\t\ttimers.add(timer);\n\t}\n\n\tfunction push(fullText: string): void {\n\t\tif (fullText === full) return;\n\t\tif (!fullText.startsWith(full)) {\n\t\t\treset(fullText);\n\t\t\treturn;\n\t\t}\n\n\t\tconst seg: StreamSegment = {\n\t\t\tid: nextId++,\n\t\t\ttext: fullText.slice(full.length),\n\t\t\tfresh: animate,\n\t\t};\n\t\tfull = fullText;\n\t\tlist.push(seg);\n\n\t\tif (!animate) {\n\t\t\tmerge();\n\t\t\tpublish();\n\t\t\treturn;\n\t\t}\n\n\t\tpublish();\n\t\tscheduleSettle(seg.id);\n\t}\n\n\t/**\n\t * Give every still-fresh segment a settle timer again. Only ever true\n\t * after `destroy()` cancelled them: `settle` removes its own timer as it\n\t * fires, `flush` and `reset` clear the timers AND the freshness together,\n\t * so `timers.size === 0` alongside a fresh segment is exactly the\n\t * \"cancelled but never settled\" state and nothing else. A non-empty timer\n\t * set therefore means a stream mid-flight, which must be left alone.\n\t */\n\tfunction resume(): void {\n\t\tif (!animate || timers.size > 0) return;\n\t\tfor (const seg of list) {\n\t\t\tif (seg.fresh) scheduleSettle(seg.id);\n\t\t}\n\t}\n\n\tfunction flush(): void {\n\t\tif (timers.size === 0 && !list.some((s) => s.fresh)) return;\n\t\tclearTimers();\n\t\tfor (const seg of list) seg.fresh = false;\n\t\tmerge();\n\t\tpublish();\n\t}\n\n\treset(initial);\n\n\treturn {\n\t\tget segments() {\n\t\t\treturn view;\n\t\t},\n\t\tget text() {\n\t\t\treturn textView;\n\t\t},\n\t\tpush,\n\t\treset,\n\t\tflush,\n\t\tdestroy: clearTimers,\n\t\tresume,\n\t\tsubscribe(listener) {\n\t\t\tlisteners.add(listener);\n\t\t\treturn () => listeners.delete(listener);\n\t\t},\n\t};\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\nexport interface UseTextStreamResult {\n\treadonly text: string;\n\treadonly segments: StreamSegment[];\n\tpush(fullText: string): void;\n\treset(text?: string): void;\n\tflush(): void;\n\t/** True once nothing in `segments` is still animating in. */\n\treadonly done: boolean;\n}\n\n/**\n * Built once from `initial`/`options` (matching `createTextStream`'s own\n * single construction call on the Svelte side) and subscribed through\n * `useSyncExternalStore`; the segment-list snapshot is identity-cached by\n * the store itself — unchanged between publishes — so React never loops.\n * `destroy()` is removed from the returned surface and called in the hook's\n * own cleanup instead (D-5): a pacing timer left running past unmount can no\n * longer happen.\n *\n * That cleanup can run WITHOUT an unmount, though — StrictMode rehearses\n * every effect as mount/cleanup/mount — and the typical consumer pushes from\n * a mount effect of its own. First pass: push stores the text and starts a\n * settle timer. Cleanup: the timer is cancelled. Replay: the push is a no-op,\n * because the full text is already stored, so nothing reschedules the settle\n * and the segment stays `fresh` for ever — `done` never turns true and the\n * enter animation never ends. `resume()` on the way back in is what closes\n * that, and it is a no-op on a first mount and on any stream with timers\n * still in flight.\n */\nexport function useTextStream(initial = \"\", options: TextStreamOptions = {}): UseTextStreamResult {\n\tconst stream = useConstant(() => createTextStream(initial, options));\n\tconst segments = useSyncExternalStore(stream.subscribe, () => stream.segments, () => stream.segments);\n\tconst text = useSyncExternalStore(stream.subscribe, () => stream.text, () => stream.text);\n\n\tuseEffect(() => {\n\t\tstream.resume();\n\t\treturn stream.destroy;\n\t}, [stream]);\n\n\treturn {\n\t\ttext,\n\t\tsegments,\n\t\tpush: stream.push,\n\t\treset: stream.reset,\n\t\tflush: stream.flush,\n\t\tdone: !segments.some((s) => s.fresh),\n\t};\n}\n","type":"registry:lib","target":"@ui/fancy/internals/use-text-stream.ts"},{"path":"react/src/internals/waveform-core.ts","content":"\"use client\";\n\n/**\n * Waveform rendering primitives.\n *\n * Pure drawing math kept out of the component so it can be unit-tested against\n * a stub 2D context: given a context and a set of 0..1 samples, paint one frame\n * of vertical bars. No canvas, timing, or DOM access lives here.\n */\n\nexport interface WaveformStyle {\n\t/** Any canvas fill style — solid colour, gradient string, etc. */\n\tcolor: string;\n\t/** Bar thickness in pixels. */\n\tbarWidth: number;\n\t/** Empty space between bars, in pixels. */\n\tgap: number;\n\t/** Amplitude floor (0..1) so an idle signal still reads as a waveform. */\n\tminAmp: number;\n\t/** True centres each bar vertically; false grows it up from the bottom. */\n\tmirror: boolean;\n}\n\nfunction clamp01(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\tif (value < 0) return 0;\n\tif (value > 1) return 1;\n\treturn value;\n}\n\n/**\n * Paints one frame: clears the surface, then draws `floor(width / (barWidth +\n * gap))` bars. Each bar covers its own slice of the buffer and takes that\n * slice's peak, so the last bar reaches the end of the buffer and a transient\n * between two sample points is never skipped. Bar height is\n * `max(minAmp, sample) * height`, so a silent signal still shows a floor.\n */\nexport function drawWaveformFrame(\n\tctx: CanvasRenderingContext2D,\n\tsamples: ArrayLike<number>,\n\twidth: number,\n\theight: number,\n\tstyle: WaveformStyle\n): void {\n\tctx.clearRect(0, 0, width, height);\n\n\tconst step = style.barWidth + style.gap;\n\tif (step <= 0 || width <= 0 || height <= 0) return;\n\n\tconst barCount = Math.floor(width / step);\n\tif (barCount <= 0) return;\n\n\tconst floorAmp = clamp01(style.minAmp);\n\tconst sampleCount = samples.length;\n\tctx.fillStyle = style.color;\n\n\tconst perBar = sampleCount / barCount;\n\n\tfor (let i = 0; i < barCount; i++) {\n\t\tlet sample = 0;\n\t\tif (sampleCount > 0) {\n\t\t\t// More bars than samples leaves empty slices: those fall back to the one\n\t\t\t// sample the slice starts on. The last bar always closes on the buffer's\n\t\t\t// end so recent audio cannot fall off the right edge.\n\t\t\tconst from = Math.min(Math.floor(i * perBar), sampleCount - 1);\n\t\t\tconst to =\n\t\t\t\ti === barCount - 1 ? sampleCount : Math.max(Math.floor((i + 1) * perBar), from + 1);\n\t\t\tfor (let s = from; s < to; s++) sample = Math.max(sample, clamp01(samples[s] ?? 0));\n\t\t}\n\n\t\tconst barHeight = Math.max(floorAmp, sample) * height;\n\t\tconst x = i * step;\n\t\tconst y = style.mirror ? (height - barHeight) / 2 : height - barHeight;\n\t\tctx.fillRect(x, y, style.barWidth, barHeight);\n\t}\n}\n\n/**\n * Stand-in amplitude for an idle or unmetered source: layered sines of the bar\n * index and the elapsed time. Deterministic — same arguments, same value — so\n * frames stay reproducible in tests and across a re-render.\n */\nexport function fakeWaveSample(i: number, tMs: number): number {\n\treturn clamp01(\n\t\t0.5 +\n\t\t\t0.2 * Math.sin(i * 0.35 + tMs * 0.004) +\n\t\t\t0.15 * Math.sin(i * 0.13 - tMs * 0.002) +\n\t\t\t0.1 * Math.sin(tMs * 0.008)\n\t);\n}\n","type":"registry:lib","target":"@ui/fancy/internals/waveform-core.ts"}]}