@ai-matrx/alchemy 0.12.3 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/actions.cjs.map +1 -1
- package/dist/actions.d.cts +1 -1
- package/dist/actions.d.ts +1 -1
- package/dist/actions.js.map +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/declare.cjs.map +1 -1
- package/dist/declare.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/menu.d.cts +1 -1
- package/dist/menu.d.ts +1 -1
- package/dist/operate.cjs.map +1 -1
- package/dist/operate.js.map +1 -1
- package/dist/react-bar.cjs.map +1 -1
- package/dist/react-bar.d.cts +1 -1
- package/dist/react-bar.d.ts +1 -1
- package/dist/react-bar.js.map +1 -1
- package/dist/react-host.d.cts +1 -1
- package/dist/react-host.d.ts +1 -1
- package/dist/react-menu.cjs.map +1 -1
- package/dist/react-menu.d.cts +1 -1
- package/dist/react-menu.d.ts +1 -1
- package/dist/react-menu.js.map +1 -1
- package/dist/react-overflow.cjs.map +1 -1
- package/dist/react-overflow.d.cts +1 -1
- package/dist/react-overflow.d.ts +1 -1
- package/dist/react-overflow.js.map +1 -1
- package/dist/react-palette.cjs.map +1 -1
- package/dist/react-palette.d.cts +1 -1
- package/dist/react-palette.d.ts +1 -1
- package/dist/react-palette.js.map +1 -1
- package/dist/react-selection.cjs.map +1 -1
- package/dist/react-selection.d.cts +1 -1
- package/dist/react-selection.d.ts +1 -1
- package/dist/react-selection.js.map +1 -1
- package/dist/react-sheet.cjs.map +1 -1
- package/dist/react-sheet.d.cts +1 -1
- package/dist/react-sheet.d.ts +1 -1
- package/dist/react-sheet.js.map +1 -1
- package/dist/react-workspace.cjs +7 -0
- package/dist/react-workspace.cjs.map +1 -0
- package/dist/react-workspace.d.cts +441 -0
- package/dist/react-workspace.d.ts +441 -0
- package/dist/react-workspace.js +7 -0
- package/dist/react-workspace.js.map +1 -0
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/surface.cjs.map +1 -1
- package/dist/surface.js.map +1 -1
- package/package.json +13 -3
package/dist/react-bar.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react-bar.ts","../src/react/bar.tsx","../src/menu/layouts.ts","../src/react/engine.tsx","../src/declare/sensitivity.ts","../src/actions/projection.ts","../src/actions/run.ts","../src/menu/headings.ts","../src/menu/model.ts","../src/react/context.ts","../src/react/expansion-latest.ts","../src/react/dropdown-nodes.tsx","../src/react/menu-size.tsx"],"sourcesContent":["/** `@ai-matrx/alchemy/react/bar` — the action bar layout (primary + ⋯). */\nexport { ActionBar, type ActionBarProps } from \"./react/bar\";\n","\"use client\";\n/**\n * `@ai-matrx/alchemy/react/bar` — the action bar layout (CONTRACT §2.5):\n * primary actions inline, everything else under ⋯, one model.\n */\nimport * as React from \"react\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, TooltipProvider } from \"@ai-matrx/design-system\";\nimport { bar } from \"../menu/layouts\";\nimport type { ClickTarget } from \"../actions/types\";\nimport type { MenuSubmenuNode } from \"../menu/types\";\nimport { useMenuEngine, type MenuEngine, type MenuEngineOptions } from \"./engine\";\nimport { LeafButton, NodeList, SectionList } from \"./dropdown-nodes\";\n\nexport interface ActionBarProps extends MenuEngineOptions {\n target: ClickTarget;\n /** Compact presentation (smaller gaps); membership is identical. */\n mini?: boolean;\n className?: string;\n /** Hide the ⋯ (the host turned the options off); the primaries still render. */\n hideOverflow?: boolean;\n /**\n * Below this viewport width the ⋯ opens the mobile bottom sheet\n * (`/react/sheet`, loaded on first tap) instead of a dropdown. Default 768.\n */\n sheetBelow?: number;\n /** Override the sheet loader (tests, custom bundlers). */\n loadSheet?: () => Promise<{ ActionSheet: React.ComponentType<import(\"./sheet\").ActionSheetProps> }>;\n}\n\nfunction isNarrow(width: number): boolean {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia?.(`(max-width: ${width - 1}px)`).matches ?? false;\n}\n\n// 28px under a mouse; 44px under touch (a thumb needs the platform floor —\n// page-pass 2026-09-27, the rich-document Read view row on phones).\nconst TRIGGER_CLASS =\n \"inline-flex h-7 min-w-7 pointer-coarse:h-11 pointer-coarse:min-w-11 items-center justify-center gap-1 rounded-md px-1.5 text-muted-foreground hover:bg-accent hover:text-foreground\";\n\nfunction PrimarySubmenu({ node, engine }: { node: MenuSubmenuNode; engine: MenuEngine }): React.ReactElement {\n return (\n <DropdownMenu\n onOpenChange={(open) => {\n if (open && node.lazy && !node.loading) void engine.expand(node.id);\n }}\n >\n <DropdownMenuTrigger asChild>\n <button type=\"button\" aria-label={node.label} data-alchemy-node={node.id} className={TRIGGER_CLASS}>\n {engine.icon(node.icon) ?? <span className=\"text-sm\">{node.label}</span>}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto\">\n {node.loading ? <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">Loading…</div> : <NodeList nodes={node.children} engine={engine} />}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport function ActionBar({\n target,\n mini = false,\n className,\n hideOverflow = false,\n sheetBelow = 768,\n loadSheet = () => import(\"@ai-matrx/alchemy/react/sheet\"),\n ...options\n}: ActionBarProps): React.ReactElement | null {\n const engine = useMenuEngine(target, options);\n const [sheetOpen, setSheetOpen] = React.useState(false);\n const [Sheet, setSheet] = React.useState<React.ComponentType<import(\"./sheet\").ActionSheetProps> | null>(null);\n if (!engine.model) return null;\n const arranged = bar(engine.model, { mini });\n if (arranged.primary.length === 0 && arranged.overflow.length === 0) return null;\n return (\n <TooltipProvider>\n <div\n role=\"toolbar\"\n aria-label=\"Actions\"\n data-alchemy-layout=\"bar\"\n className={`flex items-center ${mini ? \"gap-0\" : \"gap-0.5\"} ${className ?? \"\"}`}\n >\n {arranged.primary.map((node) =>\n node.kind === \"submenu\" ? (\n <PrimarySubmenu key={node.id} node={node} engine={engine} />\n ) : (\n <LeafButton key={node.id} node={node} engine={engine} showLabel={false} />\n ),\n )}\n {hideOverflow || arranged.overflow.length === 0 ? null : isNarrow(sheetBelow) ? (\n <>\n <button\n type=\"button\"\n aria-label=\"More actions\"\n data-alchemy-trigger=\"overflow\"\n className={TRIGGER_CLASS}\n onClick={() => {\n setSheetOpen(true);\n if (!Sheet) void loadSheet().then((m) => setSheet(() => m.ActionSheet));\n }}\n >\n <span aria-hidden className=\"text-base leading-none\">⋯</span>\n </button>\n {Sheet ? <Sheet {...options} target={target} open={sheetOpen} onOpenChange={setSheetOpen} /> : null}\n </>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button type=\"button\" aria-label=\"More actions\" data-alchemy-trigger=\"overflow\" className={TRIGGER_CLASS}>\n <span aria-hidden className=\"text-base leading-none\">⋯</span>\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto\">\n <SectionList sections={arranged.overflow} engine={engine} />\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </TooltipProvider>\n );\n}\n","/**\n * Layouts — pure arrangements of one MenuModel (CONTRACT §2.5).\n *\n * Every layout is a function over the SAME model: it decides which nodes sit\n * at the top level, which fold under a named submenu and which go into a\n * strip. None adds, drops or renames a leaf — `leafIds(arranged)` equals\n * `leafIds(model)` for every layout (THE LOSSLESS LAW, proven by test).\n *\n * The clipboard group IS the universal verb strip: in the strip layouts it is\n * drawn icon-only; elsewhere its rows are drawn in place. Unavailable verbs\n * (the only greyed nodes, R1 c) appear in every layout identically.\n */\nimport type {\n ArrangedBar,\n ArrangedContext,\n ArrangedPalette,\n ArrangedSelectionToolbar,\n ArrangedSheet,\n ContextArrangement,\n MenuLeafNode,\n MenuModel,\n MenuNode,\n MenuSection,\n MenuSubmenuNode,\n} from \"./types\";\n\n/** A section with more rows than this folds under its label in tiered/command/sheet. */\nexport const INLINE_SECTION_MAX = 3;\n\n/**\n * A section's heading is ONLY the name its actions declare (an approved\n * heading the classic menu already uses: \"Save as\", \"Copy as\", \"History\").\n * A group with no declared name has no heading and is never folded — its rows\n * show inline. The package never coins a heading (chair ruling, ALC-15).\n */\nexport function sectionLabel(section: MenuSection): string | null {\n return section.label ?? null;\n}\n\nfunction isLeaf(node: MenuNode): node is MenuLeafNode {\n return node.kind === \"item\" || node.kind === \"checkbox\" || node.kind === \"link\";\n}\n\n/** Every actionable id in a node list, depth-first. A lazy submenu counts as one leaf. */\nfunction collect(nodes: readonly MenuNode[], out: string[]): void {\n for (const n of nodes) {\n if (isLeaf(n)) out.push(n.id);\n else if (n.kind === \"submenu\") {\n if (n.lazy) out.push(n.id);\n else collect(n.children, out);\n }\n }\n}\n\ntype Arranged =\n | MenuModel\n | ArrangedBar\n | ArrangedContext\n | ArrangedSheet\n | ArrangedPalette\n | ArrangedSelectionToolbar\n | MenuSection[];\n\n/** Proof obligation for every layout: its leaf set equals the model's (sorted, de-duplicated). */\nexport function leafIds(arranged: Arranged): readonly string[] {\n const out: string[] = [];\n if (Array.isArray(arranged)) {\n for (const s of arranged) collect(s.nodes, out);\n } else if (\"leaves\" in arranged) {\n for (const l of arranged.leaves) out.push(l.node.id);\n } else if (\"primary\" in arranged && \"overflow\" in arranged) {\n collect(arranged.primary, out);\n for (const s of arranged.overflow) collect(s.nodes, out);\n } else if (\"root\" in arranged) {\n collect(arranged.strip, out);\n collect(arranged.root, out);\n } else if (\"more\" in arranged) {\n collect(arranged.strip, out);\n for (const s of arranged.more) collect(s.nodes, out);\n } else if (\"filterable\" in arranged) {\n collect(arranged.strip, out);\n for (const s of arranged.sections) collect(s.nodes, out);\n } else {\n for (const s of arranged.sections) collect(s.nodes, out);\n }\n return [...new Set(out)].sort();\n}\n\n/** Only a NAMED section folds; callers check `section.label` first. */\nfunction fold(section: MenuSection & { label: string }): MenuSubmenuNode {\n return {\n kind: \"submenu\",\n id: `${section.id}:fold`,\n label: section.label,\n ...(section.icon !== undefined ? { icon: section.icon } : {}),\n children: section.nodes,\n };\n}\n\nfunction rowCount(nodes: readonly MenuNode[]): number {\n return nodes.filter((n) => n.kind !== \"separator\" && n.kind !== \"label\").length;\n}\n\nfunction stripOf(model: MenuModel): MenuLeafNode[] {\n const clipboard = model.sections.find((s) => s.group === \"clipboard\" && !s.primary);\n return clipboard ? clipboard.nodes.filter(isLeaf) : [];\n}\n\nfunction clipboardRest(model: MenuModel): MenuNode[] {\n const clipboard = model.sections.find((s) => s.group === \"clipboard\" && !s.primary);\n return clipboard ? clipboard.nodes.filter((n) => !isLeaf(n) && n.kind === \"submenu\") : [];\n}\n\nfunction placementOf(node: MenuNode): \"primary\" | \"overflow\" | \"both\" {\n return \"placement\" in node && node.placement ? node.placement : \"overflow\";\n}\n\n/** The historical flat column: every section top-level. */\nfunction classic(model: MenuModel): ArrangedContext {\n return { strip: [], sections: model.sections, filterable: false };\n}\n\n/**\n * Tiered / command: the universal verbs as an icon strip; every other row by\n * its own name; the clicked target's (primary) section first, inline, heading\n * kept; a long non-primary section folds under ITS OWN label (never a coined\n * heading); History is the one approved grouping and already a group.\n */\nfunction tiered(model: MenuModel, filterable: boolean): ArrangedContext {\n const strip = stripOf(model);\n const sections: MenuSection[] = [];\n const rest = clipboardRest(model);\n for (const s of model.sections) {\n if (s.group === \"clipboard\" && !s.primary) {\n if (rest.length) sections.push({ ...s, nodes: rest });\n continue;\n }\n if (s.primary) {\n sections.push(s);\n continue;\n }\n if (!s.label || s.group === \"surface-info\" || rowCount(s.nodes) <= INLINE_SECTION_MAX) {\n // A section keeps its declared heading in EVERY layout (the Lossless\n // Law covers headings: ⋯, the bar's ⋯ and the phone sheet show it too).\n sections.push(s);\n continue;\n }\n sections.push({ id: s.id, group: s.group, nodes: [fold({ ...s, label: s.label })] });\n }\n return { strip, sections, filterable };\n}\n\nexport function context(model: MenuModel, arrangement: ContextArrangement): ArrangedContext {\n if (arrangement === \"classic\") return classic(model);\n return tiered(model, arrangement === \"command\");\n}\n\n/**\n * FOLD UNDER THE SUBJECT — a control that belongs to a CONTAINER of the thing\n * (a tab's \"…\" over the note it shows) draws the container's own rows (the\n * primary sections) on top, and EVERY other row — the verb strip included —\n * under ONE submenu named for the subject (\"Note ▸\"). The label is the\n * subject's name the host supplies (the menu header's label), never a coined\n * group heading. Lossless: rows move, none is dropped or renamed. With no\n * primary section there is nothing to put first, so the arrangement is left\n * as it was. (page-pass /notes, 2026-09-28, Arman's ruling for the tab \"…\".)\n */\nexport function foldUnderSubject(arranged: ArrangedContext, subject: string): ArrangedContext {\n const label = subject.trim();\n const primary = arranged.sections.filter((s) => s.primary);\n const rest = arranged.sections.filter((s) => !s.primary);\n if (!label || primary.length === 0 || (rest.length === 0 && arranged.strip.length === 0)) return arranged;\n const children: MenuNode[] = [];\n if (arranged.strip.length) children.push(...arranged.strip);\n for (const s of rest) {\n if (rowCount(s.nodes) === 0) continue;\n if (children.length) children.push({ kind: \"separator\", id: `${s.id}:subject-sep` });\n if (s.label) children.push({ kind: \"label\", id: `${s.id}:subject-label`, label: s.label });\n children.push(...s.nodes);\n }\n if (rowCount(children) === 0) return { ...arranged, strip: [] };\n return {\n strip: [],\n filterable: false,\n sections: [\n ...primary,\n { id: \"subject\", group: rest[0]?.group ?? primary[0]!.group, nodes: [{ kind: \"submenu\", id: \"subject:fold\", label, children }] },\n ],\n };\n}\n\n/**\n * A long NAMED section folds under its own name (\"Save as ▸\", \"Copy as ▸\");\n * primary sections and unnamed groups stay inline. Folding moves rows, never\n * renames or drops them, and never under a coined heading.\n */\nfunction foldNamed(sections: readonly MenuSection[]): MenuSection[] {\n return sections.map((s) =>\n s.label && !s.primary && rowCount(s.nodes) > INLINE_SECTION_MAX ? { id: s.id, group: s.group, nodes: [fold({ ...s, label: s.label })] } : s,\n );\n}\n\n/** ⋯ overflow: every section in classic order; long named sections fold under their own name. */\nexport function overflow(model: MenuModel): MenuSection[] {\n return foldNamed(model.sections);\n}\n\n/**\n * The action bar: primary buttons inline, EVERYTHING else under ⋯. A \"both\"\n * action is mirrored in both halves (the leaf set is still the model's).\n * `mini` changes presentation only (icon-only primaries), never membership.\n */\nexport function bar(model: MenuModel, _options: { mini?: boolean } = {}): ArrangedBar {\n const primary: MenuNode[] = [];\n const overflowSections: MenuSection[] = [];\n for (const s of model.sections) {\n const rest: MenuNode[] = [];\n for (const n of s.nodes) {\n if (n.kind === \"separator\" || n.kind === \"label\") {\n rest.push(n);\n continue;\n }\n const p = placementOf(n);\n if (p === \"primary\" || p === \"both\") primary.push(n);\n if (p === \"overflow\" || p === \"both\") rest.push(n);\n }\n if (rowCount(rest) > 0) overflowSections.push({ ...s, nodes: rest });\n }\n return { primary, overflow: foldNamed(overflowSections) };\n}\n\n/** Selection toolbar: the verbs plus primary actions as a strip; the rest under More. */\nexport function selectionToolbar(model: MenuModel): ArrangedSelectionToolbar {\n const strip: MenuNode[] = [];\n const more: MenuSection[] = [];\n for (const s of model.sections) {\n const rest: MenuNode[] = [];\n for (const n of s.nodes) {\n const inStrip = (s.group === \"clipboard\" && !s.primary && isLeaf(n)) || placementOf(n) !== \"overflow\";\n if (inStrip) strip.push(n);\n else rest.push(n);\n }\n if (rowCount(rest) > 0) more.push({ ...s, nodes: rest });\n }\n return { strip, more };\n}\n\n/**\n * Mobile bottom sheet: the verb strip on top; primary and short sections\n * inline; longer sections become one drill-down row named by the section.\n * Consumes the model directly, so it can never drift from desktop.\n */\nexport function sheet(model: MenuModel): ArrangedSheet {\n const strip = stripOf(model);\n const root: MenuNode[] = [];\n const rest = clipboardRest(model);\n for (const s of model.sections) {\n const nodes = s.group === \"clipboard\" && !s.primary ? rest : s.nodes;\n if (rowCount(nodes) === 0) continue;\n if (root.length) root.push({ kind: \"separator\", id: `${s.id}:sep` });\n if (s.primary || !s.label || rowCount(nodes) <= INLINE_SECTION_MAX) {\n if (s.label) root.push({ kind: \"label\", id: `${s.id}:label`, label: s.label });\n root.push(...nodes);\n } else {\n root.push(fold({ ...s, label: s.label, nodes }));\n }\n }\n return { strip, root };\n}\n\n/** Command palette: every leaf flattened with its breadcrumb (Linear). */\nexport function palette(model: MenuModel): ArrangedPalette {\n const leaves: ArrangedPalette[\"leaves\"] = [];\n const walk = (nodes: readonly MenuNode[], trail: string[]) => {\n for (const n of nodes) {\n if (isLeaf(n)) leaves.push({ node: n, breadcrumb: trail });\n else if (n.kind === \"submenu\") {\n if (n.lazy) leaves.push({ node: n, breadcrumb: trail });\n else walk(n.children, [...trail, n.label]);\n }\n }\n };\n for (const s of model.sections) walk(s.nodes, s.label ? [s.label] : []);\n return { leaves };\n}\n\n/**\n * A SEARCH REACHES EVERY ROW (clone 2026-10-01: \"Patient\" found nothing while\n * \"Patient reminder card\" sat under AI Actions ▸ My Personal). `palette` lists a\n * lazy submenu as ONE leaf — its label only — because its rows load on open.\n * A layout that searches opens every lazy submenu it can see: these are the\n * ones still to open (not already loading).\n */\nexport function lazySubmenuIds(model: MenuModel | null): string[] {\n if (!model) return [];\n const out: string[] = [];\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) {\n if (n.kind !== \"submenu\") continue;\n if (n.lazy) {\n if (!n.loading) out.push(n.id);\n } else walk(n.children);\n }\n };\n for (const s of model.sections) walk(s.nodes);\n return out;\n}\n\n/** True while some submenu's rows are not in the model yet (a search could still find more). */\nexport function paletteStillOpening(model: MenuModel | null): boolean {\n if (!model) return true;\n const walk = (nodes: readonly MenuNode[]): boolean =>\n nodes.some((n) => n.kind === \"submenu\" && (n.lazy || n.loading || n.pending || walk(n.children)));\n return model.sections.some((s) => walk(s.nodes));\n}\n\n/** Filter the palette by a query (every word must match label or breadcrumb). */\nexport function filterPalette(arranged: ArrangedPalette, query: string): ArrangedPalette {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (!words.length) return arranged;\n return {\n leaves: arranged.leaves.filter((l) => {\n const hay = `${l.node.label} ${l.breadcrumb.join(\" \")}`.toLowerCase();\n return words.every((w) => hay.includes(w));\n }),\n };\n}\n\nexport const layouts = { bar, overflow, context, selectionToolbar, sheet, palette };\n","\"use client\";\n/**\n * The React half of T1e: one hook every renderer uses to resolve the registry\n * at a target, build the model and run a node. Handlers never live in a\n * renderer — they live in providers and run through `runAction`.\n *\n * The context object is shared through globalThis so every per-layout entry\n * (each bundled separately) reads the same provider (module state is banned\n * across dual-loader graphs).\n */\nimport * as React from \"react\";\nimport { runAction, type RunResult } from \"../actions/run\";\nimport type { ProjectionSource } from \"../actions/projection\";\nimport type { Action, ClickTarget, ResolveRestriction, ResolvedAction } from \"../actions/types\";\nimport { actionToNode, buildMenuModel, findNode, withExpandedChildren, withGroupDividers } from \"../menu/model\";\nimport type { MenuModel, MenuNode } from \"../menu/types\";\nimport { useAlchemyActions } from \"./context\";\nimport { isLatestExpansion } from \"./expansion-latest\";\n\nexport interface MenuEngineOptions {\n restrict?: ResolveRestriction;\n /** Raw sources for projection (the host's mounted surface / clicked item). */\n source?: ProjectionSource;\n /** Content the menu acts on when nothing is selected (header text). */\n content?: string | null;\n /** The field's name, when the content is a field's text (see buildMenuModel). */\n contentLabel?: string | null;\n contentFingerprint?: string;\n /**\n * Called after a node ran (close the menu, announce). `keepOpen` is true for a row that reloads\n * the menu it sits in (`Action.keepsMenuOpen`): a layout never closes on it.\n */\n onRan?: (nodeId: string, result: RunResult, ran?: { keepOpen: boolean }) => void;\n /** Resolve only while true (renderers resolve on open). Default true. */\n active?: boolean;\n /**\n * Re-resolve when this changes even if the target object is the same (a\n * host that keeps one target per mount and reads live state through it).\n */\n revision?: string | number;\n}\n\nexport interface MenuEngine {\n model: MenuModel | null;\n resolved: readonly ResolvedAction[];\n run(nodeId: string): Promise<RunResult | null>;\n expand(nodeId: string): Promise<void>;\n /** The host's glyph for a key; `tone` is the action's colour class (iconTone). */\n icon(key: string | undefined, tone?: string): React.ReactNode;\n /** Say why a greyed verb is greyed (a tap on touch, where tooltips never open). */\n explain(sentence: string): void;\n}\n\nfunction nodeInModel(model: MenuModel, id: string): MenuNode | null {\n for (const s of model.sections) {\n const hit = findNode(s.nodes, id);\n if (hit) return hit;\n }\n return null;\n}\n\nfunction hasLoadedRows(model: MenuModel, id: string): boolean {\n const n = nodeInModel(model, id);\n return Boolean(n && n.kind === \"submenu\" && !n.lazy && !n.loading);\n}\n\nfunction loadedChildren(model: MenuModel, id: string): readonly MenuNode[] {\n const n = nodeInModel(model, id);\n return n && n.kind === \"submenu\" && !n.lazy ? n.children : [];\n}\n\n/**\n * The rebuilt rows, with every OPENED submenu that came back lazy keeping the\n * rows it last showed (its re-expansion replaces them when it lands).\n */\nexport function carryOpened(prev: readonly MenuNode[], next: MenuNode[], opened: ReadonlySet<string>): MenuNode[] {\n return next.map((n) => {\n if (n.kind !== \"submenu\") return n;\n const old = prev.find((o) => o.id === n.id);\n if (!old || old.kind !== \"submenu\" || old.lazy) return n;\n if (n.lazy) {\n return opened.has(n.id) ? { ...n, lazy: false, loading: false, pending: false, children: old.children } : n;\n }\n return { ...n, children: carryOpened(old.children, n.children, opened) };\n });\n}\n\nfunction carryOpenedModel(prev: MenuModel, next: MenuModel, opened: ReadonlySet<string>): MenuModel {\n if (opened.size === 0) return next;\n const prevNodes = prev.sections.flatMap((s) => s.nodes);\n return { ...next, sections: next.sections.map((s) => ({ ...s, nodes: carryOpened(prevNodes, s.nodes, opened) })) };\n}\n\nexport function useMenuEngine(target: ClickTarget | null, options: MenuEngineOptions = {}): MenuEngine {\n const { registry, ports } = useAlchemyActions();\n const [resolved, setResolved] = React.useState<readonly ResolvedAction[]>([]);\n const [model, setModel] = React.useState<MenuModel | null>(null);\n const [tick, setTick] = React.useState(0);\n // Every action an expansion returned, by id (a nested row is found here).\n const expanded = React.useRef(new Map<string, Action>());\n // Every submenu the person (or a search) opened, at ANY depth. A re-resolve\n // rebuilds the model with each of them lazy again; these are re-opened, and\n // their last rows are carried over meanwhile so an open submenu never blanks.\n const opened = React.useRef(new Set<string>());\n const expandSeq = React.useRef(new Map<string, number>());\n const targetEpoch = React.useRef(0);\n const currentTarget = React.useRef(target);\n if (currentTarget.current !== target) {\n currentTarget.current = target;\n targetEpoch.current += 1;\n }\n const active = options.active ?? true;\n const optionsRef = React.useRef(options);\n optionsRef.current = options;\n\n React.useEffect(() => registry.subscribe(() => setTick((t) => t + 1)), [registry]);\n\n const expandAction = React.useCallback(\n async (action: Action, nodeId: string) => {\n if (!target || !action.expand) return;\n const epoch = targetEpoch.current;\n const seq = (expandSeq.current.get(nodeId) ?? 0) + 1;\n expandSeq.current.set(nodeId, seq);\n const latest = () => isLatestExpansion(epoch, targetEpoch.current, seq, expandSeq.current.get(nodeId));\n // \"Loading…\" only over a submenu with no rows yet: a refresh keeps the\n // rows on screen until the new ones land (a blank flash unmounts the\n // focused row and Radix closes the parent submenu under the pointer).\n setModel((m) => (m && !hasLoadedRows(m, nodeId) ? withExpandedChildren(m, nodeId, \"loading\") : m));\n try {\n // A programmatic-only Action (surfaces without \"menu\") never becomes a row, even inside a submenu.\n const children = (await action.expand(target, new AbortController().signal)).filter(\n (child) => !child.surfaces || child.surfaces.includes(\"menu\"),\n );\n if (!latest()) return;\n const nodes: MenuNode[] = withGroupDividers(\n children,\n children.map((child) => {\n expanded.current.set(child.id, child);\n return actionToNode({ action: child, eligibility: { status: \"available\" } }, target, ports.i18n ? { i18n: ports.i18n } : {});\n }),\n );\n setModel((m) => (m ? withExpandedChildren(m, nodeId, carryOpened(loadedChildren(m, nodeId), nodes, opened.current)) : m));\n // A nested submenu that was open stays open: re-open it under its new parent rows.\n for (const child of children) if (child.expand && opened.current.has(child.id)) void expandAction(child, child.id);\n } catch (error) {\n if (!latest()) return;\n ports.diagnostics.capture(error, { area: \"menu\", detail: { nodeId, stage: \"expand\" } });\n setModel((m) => (m ? withExpandedChildren(m, nodeId, []) : m));\n }\n },\n [target, ports],\n );\n\n React.useEffect(() => {\n expanded.current.clear();\n opened.current.clear();\n }, [target]);\n\n React.useEffect(() => {\n if (!target || !active) return;\n let live = true;\n void registry.resolve(target, optionsRef.current.restrict).then((list) => {\n if (!live) return;\n setResolved(list);\n const built = buildMenuModel(target, list, { ...(ports.i18n ? { i18n: ports.i18n } : {}), content: optionsRef.current.content ?? null, contentLabel: optionsRef.current.contentLabel ?? null });\n setModel((prev) => (prev ? carryOpenedModel(prev, built, opened.current) : built));\n for (const { action } of list) {\n if (opened.current.has(action.id) && action.expand) void expandAction(action, action.id);\n }\n });\n return () => {\n live = false;\n };\n }, [registry, ports, target, active, tick, options.revision, expandAction]);\n\n // Live toggles (read-aloud, thumbs): re-resolve when an action's store\n // changes. Subscriptions are keyed by the resolved ids (not the array, which\n // every resolve replaces) and a notify fired synchronously INSIDE subscribe\n // (a store's hydration read) is ignored — otherwise subscribe → notify →\n // resolve → resubscribe never ends.\n const resolvedRef = React.useRef(resolved);\n resolvedRef.current = resolved;\n const subscribedIds = resolved.map((r) => r.action.id).join(\"\\n\");\n React.useEffect(() => {\n if (!target) return;\n let subscribing = true;\n const onChange = () => {\n if (!subscribing) setTick((t) => t + 1);\n };\n const offs = resolvedRef.current\n .map((r) => r.action.subscribe?.(onChange, target))\n .filter((off): off is () => void => typeof off === \"function\");\n subscribing = false;\n return () => offs.forEach((off) => off());\n }, [subscribedIds, target]);\n\n const findAction = React.useCallback(\n (id: string): Action | undefined => resolved.find((r) => r.action.id === id)?.action ?? expanded.current.get(id) ?? undefined,\n [resolved],\n );\n\n const run = React.useCallback(\n async (nodeId: string) => {\n if (!target || !model) return null;\n const node = model.sections.map((s) => findNode(s.nodes, nodeId)).find(Boolean) ?? null;\n const action = findAction(node && \"actionId\" in node && node.actionId ? node.actionId : nodeId);\n if (!action) return null;\n const o = optionsRef.current;\n const result = await runAction(action, target, {\n ports,\n ...(o.source ? { source: o.source } : {}),\n ...(o.contentFingerprint ? { contentFingerprint: o.contentFingerprint } : {}),\n });\n o.onRan?.(nodeId, result, { keepOpen: Boolean(action.keepsMenuOpen) });\n return result;\n },\n [target, model, findAction, ports],\n );\n\n const expand = React.useCallback(\n async (nodeId: string) => {\n const action = findAction(nodeId);\n if (!target || !action?.expand) return;\n // Remembered so late resolver data (a re-resolve) re-opens it, at any depth.\n opened.current.add(nodeId);\n await expandAction(action, nodeId);\n },\n [findAction, target, expandAction],\n );\n\n const icon = React.useCallback(\n (key: string | undefined, tone?: string): React.ReactNode => {\n if (!key || !ports.icons) return null;\n const Resolved = ports.icons.resolve(key) as React.ComponentType<{ className?: string; \"aria-hidden\"?: boolean }> | null;\n return Resolved ? <Resolved className={`h-4 w-4 shrink-0 ${tone ?? \"\"}`} aria-hidden /> : null;\n },\n [ports.icons],\n );\n\n const explain = React.useCallback(\n (sentence: string) => {\n if (ports.notify) ports.notify.info(sentence);\n else ports.diagnostics.capture(new Error(`No notify port to explain: ${sentence}`), { area: \"menu\", detail: { sentence } });\n },\n [ports],\n );\n\n return { model, resolved, run, expand, icon, explain };\n}\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * PROJECTION BEFORE PROVIDERS (CONTRACT §2.4).\n *\n * The only place a raw read (`MountedSurface.readValues`,\n * `InternalResolvedItem.readValues`) is consumed on behalf of an action.\n * What leaves is projected: a value is kept only when it is DECLARED, its\n * classification is \"ordinary\" and it is exportable. Everything removed is\n * recorded as an omission, so the person and the agent can see what was held\n * back. No caller can relax this.\n */\nimport { resolveSensitivity } from \"../declare/sensitivity\";\nimport type { InternalResolvedItem, MountedSurface } from \"../declare/host\";\nimport type { DeclaredValue, Json, LiveValues, ResolvedSurfaceDeclaration } from \"../declare/types\";\nimport type { ProjectedReads, ReadOmission } from \"./types\";\n\nexport interface ProjectionSource {\n surface: MountedSurface | null;\n declaration: ResolvedSurfaceDeclaration | null;\n item: InternalResolvedItem | null;\n}\n\nfunction toJson(value: unknown): Json | undefined {\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") return undefined;\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n if (typeof value === \"number\") return Number.isFinite(value) ? value : null;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map((v) => toJson(v) ?? null);\n if (typeof value === \"object\") {\n const out: { [key: string]: Json } = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n const j = toJson(v);\n if (j !== undefined) out[k] = j;\n }\n return out;\n }\n return undefined;\n}\n\n/** Keep declared, ordinary, exportable values; record every removal. */\nexport function projectValues(\n raw: Record<string, unknown>,\n declared: readonly Pick<DeclaredValue, \"name\" | \"sensitivity\">[],\n pathPrefix = \"\",\n): { values: Record<string, Json>; omissions: ReadOmission[] } {\n const byName = new Map(declared.map((d) => [d.name, d]));\n const values: Record<string, Json> = {};\n const omissions: ReadOmission[] = [];\n for (const [name, value] of Object.entries(raw)) {\n const path = pathPrefix ? `${pathPrefix}.${name}` : name;\n const decl = byName.get(name);\n if (!decl) {\n omissions.push({ path, reason: \"filtered\" });\n continue;\n }\n const sensitivity = resolveSensitivity(decl);\n if (sensitivity.classification !== \"ordinary\") {\n omissions.push({ path, reason: \"excluded\", classification: sensitivity.classification });\n continue;\n }\n if (!sensitivity.exportable) {\n omissions.push({ path, reason: \"excluded\" });\n continue;\n }\n const json = toJson(value);\n if (json === undefined) continue;\n values[name] = json;\n }\n return { values, omissions };\n}\n\nexport function createProjectedReads(source: ProjectionSource): ProjectedReads {\n return {\n async values(signal) {\n if (!source.surface || !source.declaration) return { values: {}, omissions: [] };\n const raw = await source.surface.readValues(signal);\n const screenValues = source.declaration.values;\n return projectValues(raw, screenValues);\n },\n async item(signal) {\n const item = source.item;\n if (!item || !source.declaration) return null;\n const type = source.declaration.itemTypes?.find((t) => t.name === item.itemType);\n if (!type) return { values: {}, omissions: [{ path: item.itemType, reason: \"filtered\" }] };\n const raw = await item.readValues(signal);\n return projectValues(raw, type.values, item.itemType);\n },\n async live(signal): Promise<LiveValues> {\n if (!source.surface?.readLive) return {};\n return source.surface.readLive(signal);\n },\n };\n}\n","/**\n * The one run path (T1e). Every layout runs an action through here, so the\n * sign-in-then-resume rule, projection and failure capture live once.\n */\nimport type { TransferOutcome } from \"@ai-matrx/kit/content-transfer\";\nimport type { AlchemyHostPorts } from \"../ports\";\nimport { createProjectedReads, type ProjectionSource } from \"./projection\";\nimport type { Action, ClickTarget } from \"./types\";\n\nexport interface RunActionOptions {\n ports: AlchemyHostPorts;\n /** Raw sources; projected before the action sees them. */\n source?: ProjectionSource;\n /** Stable fingerprint of the content, for sign-in-then-resume. */\n contentFingerprint?: string;\n signal?: AbortSignal;\n}\n\nexport type RunResult =\n | { status: \"ran\"; outcome: TransferOutcome | void }\n | { status: \"auth-pending\" }\n | { status: \"failed\"; error: unknown };\n\nexport async function runAction(action: Action, target: ClickTarget, options: RunActionOptions): Promise<RunResult> {\n const { ports } = options;\n if (action.requiresAuth && !target.auth.authenticated) {\n if (!ports.auth) {\n // Unreachable through resolve (the action is absent without the port); guard direct callers.\n ports.diagnostics.capture(new Error(`requiresAuth action \"${action.id}\" ran signed out with no auth port`), {\n area: \"actions\",\n detail: { actionId: action.id },\n });\n return { status: \"failed\", error: new Error(\"sign-in unavailable\") };\n }\n ports.auth.signInThenResume({ actionId: action.id, contentFingerprint: options.contentFingerprint ?? action.id });\n return { status: \"auth-pending\" };\n }\n const reads = createProjectedReads(options.source ?? { surface: null, declaration: target.declaration, item: null });\n const signal = options.signal ?? new AbortController().signal;\n try {\n const outcome = await action.run(target, { reads, ports, signal });\n return { status: \"ran\", outcome };\n } catch (error) {\n ports.diagnostics.capture(error, { area: \"actions\", detail: { actionId: action.id, stage: \"run\" } });\n const label = typeof action.label === \"string\" ? action.label : action.id;\n ports.notify?.error(`${label} did not finish.`, \"Try again; if it keeps failing, report it from the feedback button.\");\n return { status: \"failed\", error };\n }\n}\n","/**\n * THE ONE APPROVED-HEADING LIST (ALC-15, chair rulings 7 and D1; the Lossless\n * Law and the vocabulary law). A heading a person sees above or around rows\n * must be a name the classic menus used before agents started coining names.\n *\n * 🚨 ADDING A HEADING TO THIS LIST IS ARMAN'S CALL — never an agent's.\n *\n * Two kinds of section heading exist:\n * - a GROUP heading (\"Copy as\", \"History\"): must be in APPROVED_HEADINGS;\n * - a TARGET label, the thing the person clicked, supplied by the surface at\n * run time (\"Cell · Visit date\", \"Row · Widget A\", \"This finding\", the\n * surface's own label): allowed as declared (`section.kind: \"target\"`, or\n * the \"<Target> · <name>\" shape), except a generic container word.\n * A generic container word (\"More…\", \"Other\", \"Actions\") is never a heading.\n * An unapproved heading renders its rows INLINE in production; in development\n * and tests `buildMenuModel` throws with the remedy.\n */\nimport type { MenuModel, MenuNode } from \"./types\";\n\n/** Names with their provenance (the commit where each classic menu used them). */\nexport const APPROVED_HEADINGS: ReadonlySet<string> = new Set([\n \"Save\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Copy as\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Export\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Edit\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Creator tools\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Admin\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"App\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Compare\", // rich-document menuStructure, 2e3a8a9fdf (2026-06-11)\n \"History\", // context-menu-v3 tiered layout — the one grouping Arman approved, 2026-08-22\n]);\n\n// Ruling (chair, 2026-09-26, per R26): \"Conversation\" is a TARGET label (`kind: \"target\"`) — it names the thing its rows act on (the whole conversation), like \"Cell · …\" and \"Table · …\"; it is not a group heading and is not added above.\n\nconst CONTAINER_WORD =\n /^(more|more…|more\\.\\.\\.|other|others|misc|miscellaneous|additional|extra|extras|actions|options|advanced|stuff|everything else)$/i;\n\n/** \"Cell · Visit date\", \"Row · Widget A\", \"Column · Price\", \"Table · Route sheet\". */\nconst TARGET_SHAPE = /^(Cell|Row|Column|Table|Range|Selection|Record) · .+$/;\n\nexport function isContainerWord(label: string): boolean {\n return CONTAINER_WORD.test(label.trim());\n}\n\nexport type HeadingKind = \"group\" | \"target\";\n\n/** Is this heading allowed? */\nexport function isApprovedHeading(label: string, kind: HeadingKind = \"group\", approved: ReadonlySet<string> = APPROVED_HEADINGS): boolean {\n const l = label.trim();\n if (!l || isContainerWord(l)) return false;\n if (approved.has(l)) return true;\n return kind === \"target\" || TARGET_SHAPE.test(l);\n}\n\nexport type HeadingPolicy = \"throw\" | \"inline\";\n\n/** Development and tests throw; production shows the rows inline. */\nexport function defaultHeadingPolicy(): HeadingPolicy {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.NODE_ENV;\n return env === \"production\" ? \"inline\" : \"throw\";\n}\n\nexport class UnapprovedHeadingError extends Error {\n readonly heading: string;\n constructor(heading: string, where: string) {\n super(\n `Menu heading \"${heading}\" (${where}) is not an approved heading. Remedy: show these rows inline — declare no section ` +\n `(or kind \"target\" for the clicked thing's own label) — or ask Arman to add the name to APPROVED_HEADINGS in ` +\n `@ai-matrx/alchemy/menu. A generic container word (\"More…\", \"Other\") is never approved.`,\n );\n this.name = \"UnapprovedHeadingError\";\n this.heading = heading;\n }\n}\n\n/** Every heading in a model: section labels, folds, and submenu rows at any depth. */\nexport function menuHeadings(model: Pick<MenuModel, \"sections\">): string[] {\n const out: string[] = [];\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) {\n if (n.kind === \"submenu\") {\n out.push(n.label);\n walk(n.children);\n }\n }\n };\n for (const s of model.sections) {\n if (s.label) out.push(s.label);\n walk(s.nodes);\n }\n return [...new Set(out)];\n}\n\n/** Section headings not in the approved set (container words are never approved). */\nexport function unapprovedHeadings(model: Pick<MenuModel, \"sections\">, approved: ReadonlySet<string> = APPROVED_HEADINGS): string[] {\n const out = new Set<string>();\n for (const s of model.sections) {\n if (s.label && !isApprovedHeading(s.label, s.primary || s.target ? \"target\" : \"group\", approved)) out.add(s.label);\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) if (n.kind === \"submenu\") {\n if (isContainerWord(n.label)) out.add(n.label);\n walk(n.children);\n }\n };\n walk(s.nodes);\n }\n return [...out];\n}\n","/**\n * buildMenuModel — WHAT exists at a click target, as one framework-neutral\n * tree (CONTRACT §2.5). Categories GROUP, never gate: eligibility already ran\n * in the registry; this only arranges the resolved set into sections.\n */\nimport type { Action, ActionCategory, ClickTarget, ResolvedAction } from \"../actions/types\";\nimport type { I18nPort } from \"../ports\";\nimport type { MenuGroup, MenuModel, MenuNode, MenuSection, MenuSubmenuNode } from \"./types\";\nimport { UnapprovedHeadingError, defaultHeadingPolicy, isApprovedHeading, isContainerWord, type HeadingPolicy } from \"./headings\";\n\n/** THE category → menu group table (CONTRACT §2.5). */\nexport const CATEGORY_GROUP: Readonly<Record<ActionCategory, MenuGroup>> = {\n clipboard: \"clipboard\",\n copy: \"transfer\",\n export: \"transfer\",\n save: \"document\",\n share: \"document\",\n edit: \"editable\",\n history: \"history\",\n ai: \"ai\",\n ask: \"ai\",\n listen: \"tools\",\n study: \"tools\",\n app: \"tools\",\n applet: \"tools\",\n feedback: \"quick\",\n creator: \"admin\",\n admin: \"admin\",\n \"surface-info\": \"surface-info\",\n};\n\n/** Classic order of the groups. `surface-info` is engine-built and always last. */\nexport const GROUP_ORDER: readonly MenuGroup[] = [\n \"clipboard\",\n \"editable\",\n \"transfer\",\n \"document\",\n \"history\",\n \"ai\",\n \"tools\",\n \"quick\",\n \"surface\",\n \"admin\",\n \"surface-info\",\n];\n\nconst CATEGORY_ORDER: readonly ActionCategory[] = [\n \"clipboard\",\n \"edit\",\n \"copy\",\n \"export\",\n \"save\",\n \"share\",\n \"history\",\n \"ask\",\n \"ai\",\n \"listen\",\n \"study\",\n \"app\",\n \"applet\",\n \"feedback\",\n \"creator\",\n \"admin\",\n \"surface-info\",\n];\n\nexport interface BuildMenuModelOptions {\n /** What an unapproved heading does: \"throw\" (development/tests) or \"inline\" (production). */\n headingPolicy?: HeadingPolicy;\n i18n?: I18nPort;\n /** Content the menu acts on when nothing is selected. */\n content?: string | null;\n /**\n * The name of the field the content is (a text box's label, \"Body\"). The\n * header then names the field — never \"Content: {{reply.body}}\", its raw text.\n */\n contentLabel?: string | null;\n}\n\nfunction translate(i18n: I18nPort | undefined, key: string, fallback: string): string {\n if (!i18n) return fallback;\n try {\n return i18n.t(key, fallback);\n } catch {\n return fallback;\n }\n}\n\n/** One resolved action → one model node (item, checkbox, link or lazy submenu). */\nexport function actionToNode(\n resolved: ResolvedAction,\n target: ClickTarget,\n options: BuildMenuModelOptions = {},\n): MenuNode {\n const { action, eligibility } = resolved;\n const rawLabel = typeof action.label === \"function\" ? action.label(target) : action.label;\n const label = translate(options.i18n, action.labelKey ?? action.id, rawLabel);\n const base = {\n id: action.id,\n actionId: action.id,\n ...(action.icon !== undefined ? { icon: action.icon } : {}),\n ...(action.placement !== undefined ? { placement: action.placement } : {}),\n };\n if (action.expand) {\n const node: MenuSubmenuNode = {\n ...base,\n kind: \"submenu\",\n label,\n lazy: true,\n loading: false,\n ...(action.pending?.(target) ? { pending: true } : {}),\n children: [],\n ...(action.emptyLabel !== undefined ? { emptyLabel: action.emptyLabel } : {}),\n };\n return node;\n }\n if (action.href !== undefined) {\n const href = typeof action.href === \"function\" ? action.href(target) : action.href;\n return { ...base, kind: \"link\", label, href };\n }\n if (action.toggle) {\n return {\n ...base,\n kind: \"checkbox\",\n label,\n checked: action.pressed?.(target) ?? false,\n ...(action.description !== undefined ? { description: action.description } : {}),\n };\n }\n const state = action.stateIcon?.(target) ?? null;\n const pressed = action.pressed?.(target);\n const hint = action.hint !== undefined ? translate(options.i18n, action.hintKey ?? `${action.id}.hint`, action.hint) : undefined;\n return {\n ...base,\n kind: \"item\",\n label,\n ...(action.iconTone !== undefined ? { iconTone: action.iconTone } : {}),\n ...(state ? { stateIcon: state } : {}),\n ...(action.description !== undefined ? { description: action.description } : {}),\n ...(hint !== undefined ? { hint } : {}),\n ...(pressed !== undefined ? { pressed } : {}),\n ...(action.destructive ? { destructive: true } : {}),\n ...(action.preserveSelection ? { preserveSelection: true } : {}),\n ...(action.keepsMenuOpen ? { keepsMenuOpen: true } : {}),\n ...(eligibility.status === \"unavailable-verb\" || eligibility.status === \"unavailable\"\n ? { unavailable: { sentence: eligibility.sentence } }\n : {}),\n };\n}\n\nexport function buildMenuModel(\n target: ClickTarget,\n resolved: readonly ResolvedAction[],\n options: BuildMenuModelOptions = {},\n): MenuModel {\n // THE ONE HEADING CHECK, for every host: an unapproved heading's rows go\n // inline (production) or the build throws with the remedy (dev/tests).\n const policy = options.headingPolicy ?? defaultHeadingPolicy();\n resolved = resolved.map((r) => {\n const sec = r.action.section;\n if (r.action.expand && isContainerWord(typeof r.action.label === \"string\" ? r.action.label : \"\") && policy === \"throw\") {\n throw new UnapprovedHeadingError(r.action.label as string, `submenu of ${r.action.id}`);\n }\n if (!sec) return r;\n const kind = sec.kind ?? (sec.primary ? \"target\" : \"group\");\n if (isApprovedHeading(sec.label, kind)) return r;\n if (policy === \"throw\") throw new UnapprovedHeadingError(sec.label, `section of ${r.action.id}`);\n const { section: _dropped, ...rest } = r.action;\n return { ...r, action: rest };\n });\n const ordered = resolved\n .map((r, index) => ({ r, index }))\n .sort((a, b) => {\n const ca = CATEGORY_ORDER.indexOf(a.r.action.category);\n const cb = CATEGORY_ORDER.indexOf(b.r.action.category);\n if (ca !== cb) return ca - cb;\n const oa = a.r.action.order ?? 0;\n const ob = b.r.action.order ?? 0;\n if (oa !== ob) return oa - ob;\n return a.index - b.index;\n })\n .map((x) => x.r);\n\n const sections = new Map<string, MenuSection>();\n const roles: Record<string, string> = {};\n // An explicit section sits in the group of its first-registered action and\n // keeps its own row order (order, then registration) across categories.\n const explicit = new Map<string, { group: MenuGroup; rows: { r: ResolvedAction; index: number }[] }>();\n resolved.forEach((r, index) => {\n const sec = r.action.section;\n if (!sec) return;\n const entry = explicit.get(sec.id) ?? { group: CATEGORY_GROUP[r.action.category], rows: [] };\n entry.rows.push({ r, index });\n explicit.set(sec.id, entry);\n });\n const placed = new Set<string>();\n for (const r of ordered) {\n const sec = r.action.section;\n if (sec && placed.has(sec.id)) continue;\n const group = sec ? (explicit.get(sec.id)?.group ?? CATEGORY_GROUP[r.action.category]) : CATEGORY_GROUP[r.action.category];\n const sectionId = sec ? `section:${sec.id}` : group;\n let section = sections.get(sectionId);\n if (!section) {\n section = {\n id: sectionId,\n group,\n nodes: [],\n ...(sec ? { label: translate(options.i18n, sec.labelKey ?? `section.${sec.id}`, sec.label) } : {}),\n ...(sec?.icon !== undefined ? { icon: sec.icon } : {}),\n ...(sec?.primary ? { primary: true } : {}),\n ...(sec && (sec.kind ?? (sec.primary ? \"target\" : \"group\")) === \"target\" ? { target: true } : {}),\n };\n sections.set(sectionId, section);\n }\n const rows = sec\n ? (explicit.get(sec.id)?.rows ?? [])\n .sort((x, y) => (x.r.action.order ?? 0) - (y.r.action.order ?? 0) || x.index - y.index)\n .map((x) => x.r)\n : [r];\n if (sec) placed.add(sec.id);\n for (const row of rows) {\n if (row.action.startsGroup && section.nodes.length > 0) {\n section.nodes.push({ kind: \"separator\", id: `${row.action.id}:group` });\n }\n section.nodes.push(actionToNode(row, target, options));\n if (row.action.verb) roles[row.action.verb] = row.action.id;\n }\n }\n\n const list = [...sections.values()].sort((a, b) => {\n if (Boolean(a.primary) !== Boolean(b.primary)) return a.primary ? -1 : 1;\n return GROUP_ORDER.indexOf(a.group) - GROUP_ORDER.indexOf(b.group);\n });\n\n const selected = target.selection?.text?.trim();\n const content = options.content?.trim();\n const fieldName = options.contentLabel?.trim();\n const header = selected\n ? { label: \"Selected\", text: target.selection?.text ?? \"\" }\n : fieldName\n ? { label: fieldName, text: options.content ?? \"\" }\n : content\n ? { label: \"Content\", text: options.content ?? \"\" }\n : null;\n\n return { header, sections: list, roles };\n}\n\n/** Fill a lazy submenu's rows once they load (pure: returns a new model). */\n/**\n * AN EXPANDED SUBMENU KEEPS ITS GROUPS (DATA-V2-BASICS-2, 2026-09-28). A provider's rows arrive flat,\n * so a submenu drew \"Highlight row\" and \"Delete row…\" as neighbours with no divider, while the same\n * rows in a top-level menu sit in their sections. A divider now goes wherever the rows' `section`\n * changes — a row with no section and a row with one are different groups too.\n */\nexport function withGroupDividers(children: readonly Action[], nodes: readonly MenuNode[]): MenuNode[] {\n const out: MenuNode[] = [];\n children.forEach((child, i) => {\n const node = nodes[i];\n if (!node) return;\n if (i > 0 && (child.startsGroup || (children[i - 1]!.section?.id ?? null) !== (child.section?.id ?? null))) {\n out.push({ kind: \"separator\", id: `${child.id}:group` });\n }\n out.push(node);\n });\n return out;\n}\n\nexport function withExpandedChildren(model: MenuModel, nodeId: string, children: MenuNode[] | \"loading\"): MenuModel {\n const visit = (nodes: MenuNode[]): MenuNode[] =>\n nodes.map((n) => {\n if (n.kind !== \"submenu\") return n;\n if (n.id === nodeId) {\n return children === \"loading\" ? { ...n, loading: true } : { ...n, lazy: false, loading: false, pending: false, children };\n }\n return { ...n, children: visit(n.children) };\n });\n return { ...model, sections: model.sections.map((s) => ({ ...s, nodes: visit(s.nodes) })) };\n}\n\n/** Find a node anywhere in a tree. */\nexport function findNode(nodes: readonly MenuNode[], id: string): MenuNode | null {\n for (const n of nodes) {\n if (n.id === id) return n;\n if (n.kind === \"submenu\") {\n const hit = findNode(n.children, id);\n if (hit) return hit;\n }\n }\n return null;\n}\n","/**\n * The shared React context (T0-safe: imports only React and types). Shared\n * through globalThis so every per-layout bundle reads the same provider.\n */\nimport * as React from \"react\";\nimport type { ActionRegistry } from \"../actions/types\";\nimport type { AlchemyHostPorts } from \"../ports\";\n\nexport interface AlchemyActionsValue {\n registry: ActionRegistry;\n ports: AlchemyHostPorts;\n}\n\nconst KEY = Symbol.for(\"ai-matrx.alchemy.actions-context\");\ntype Holder = { [KEY]?: React.Context<AlchemyActionsValue | null> };\nexport const AlchemyActionsContext: React.Context<AlchemyActionsValue | null> =\n ((globalThis as Holder)[KEY] ??= React.createContext<AlchemyActionsValue | null>(null));\n\nexport function useAlchemyActions(): AlchemyActionsValue {\n const value = React.useContext(AlchemyActionsContext);\n if (!value) throw new Error(\"Alchemy actions: render inside <AlchemyActionsProvider> (@ai-matrx/alchemy/react/host).\");\n return value;\n}\n\n/**\n * The registry + ports when rendered inside `<AlchemyActionsProvider>`, else null. For callers that\n * must never crash a render outside the host (a kind component, an assist chip, a bare test render):\n * they answer honestly (\"actions aren't available here\") instead of throwing.\n */\nexport function useOptionalAlchemyActions(): AlchemyActionsValue | null {\n return React.useContext(AlchemyActionsContext);\n}\n","/**\n * The completion of an expansion belongs to both the target that started it\n * and that node's most recent request. Either identity changing makes a late\n * result stale.\n */\nexport function isLatestExpansion(\n capturedTargetEpoch: number,\n currentTargetEpoch: number,\n capturedNodeSequence: number,\n currentNodeSequence: number | undefined,\n): boolean {\n return capturedTargetEpoch === currentTargetEpoch && capturedNodeSequence === currentNodeSequence;\n}\n","\"use client\";\n/**\n * Drawing model nodes inside a Radix dropdown (menu / overflow / bar / selection).\n * Pure presentation: every choice goes back to the engine by node id.\n */\nimport * as React from \"react\";\nimport {\n DropdownMenuCheckboxItem,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@ai-matrx/design-system\";\nimport type { MenuEngine } from \"./engine\";\nimport { MENU_SIZE_CLASSES, useMenuSize } from \"./menu-size\";\nimport { sectionLabel } from \"../menu/layouts\";\nimport type { MenuLeafNode, MenuNode, MenuSection } from \"../menu/types\";\n\nexport function NodeList({ nodes, engine }: { nodes: readonly MenuNode[]; engine: MenuEngine }): React.ReactElement {\n return (\n <>\n {nodes.map((node) => (\n <MenuNodeView key={node.id} node={node} engine={engine} />\n ))}\n </>\n );\n}\n\nexport function SectionList({\n sections,\n engine,\n}: {\n sections: readonly MenuSection[];\n engine: MenuEngine;\n}): React.ReactElement {\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n return (\n <>\n {sections.map((section, index) => (\n <React.Fragment key={section.id}>\n {index > 0 ? <DropdownMenuSeparator /> : null}\n {sectionLabel(section) ? (\n <DropdownMenuLabel className={`${size.label} font-medium text-muted-foreground`}>{sectionLabel(section)}</DropdownMenuLabel>\n ) : null}\n <NodeList nodes={section.nodes} engine={engine} />\n </React.Fragment>\n ))}\n </>\n );\n}\n\n/**\n * A toggle's ON state must be a real visual signal, never just its tooltip\n * text — an inactive thumbs-up rendered in the same green as an active one\n * lies about being rated (RC-B11). Two ways a registered action shows it,\n * and both are honored here, in the ONE place every layout draws a glyph:\n *\n * 1. A distinct glyph for the active state (`stateIcon`, e.g. pin-message\n * swaps Pin -> PinOff while pinned, tts-play swaps Volume2 -> Pause).\n * The glyph change IS the signal, so its tone is untouched here —\n * exactly the pre-existing behavior for every action that already\n * draws one.\n * 2. A single glyph with an accent tone (`iconTone`) that has no natural\n * \"undo\" icon (thumbs up/down, star, favorite) — nothing but the tone\n * can carry the state, so it is withheld while the action is an\n * explicit, currently-off toggle (`pressed === false`): the glyph\n * falls back to the bar's ordinary muted color, and lights up in its\n * registered tone only once `pressed` is true.\n *\n * `pressed === undefined` (not a toggle at all — copy, export, run…) keeps\n * its tone unconditionally, exactly as before.\n */\nfunction iconOf(node: MenuNode, engine: MenuEngine): React.ReactNode {\n if (node.kind !== \"item\") {\n if (!(\"icon\" in node)) return null;\n return engine.icon(node.icon);\n }\n if (node.stateIcon) {\n const glyph = engine.icon(node.stateIcon.icon);\n return node.stateIcon.spin ? <span className=\"inline-flex animate-spin\">{glyph}</span> : glyph;\n }\n if (!(\"icon\" in node)) return null;\n const tone = node.pressed === false ? undefined : node.iconTone;\n return engine.icon(node.icon, tone);\n}\n\nexport function MenuNodeView({ node, engine }: { node: MenuNode; engine: MenuEngine }): React.ReactElement | null {\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n switch (node.kind) {\n case \"separator\":\n return <DropdownMenuSeparator />;\n case \"label\":\n return <DropdownMenuLabel className={`${size.label} font-medium text-muted-foreground`}>{node.label}</DropdownMenuLabel>;\n case \"submenu\":\n return <SubmenuView node={node} engine={engine} />;\n case \"checkbox\":\n return (\n <DropdownMenuCheckboxItem\n data-alchemy-node={node.id}\n checked={node.checked}\n onSelect={() => void engine.run(node.id)}\n className={size.row}\n >\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n </DropdownMenuCheckboxItem>\n );\n case \"link\":\n return (\n <DropdownMenuItem asChild data-alchemy-node={node.id}>\n <a href={node.href} target={node.target} className={size.row}>\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n </a>\n </DropdownMenuItem>\n );\n case \"item\":\n return <LeafItem node={node} engine={engine} />;\n }\n}\n\n/**\n * A SUBMENU NEVER CLOSES BECAUSE ITS PARENT PANEL TOOK FOCUS (PB-04, /notes, 2026-10-02: at a\n * 1024 px viewport AI Actions ▸ Text Operations ▸ Text Tools closed under the pointer).\n *\n * Radix keeps a submenu open while the pointer leaves its trigger only when the pointer's last\n * horizontal move inside the parent panel points at the side the submenu is drawn on. A narrow\n * viewport FLIPS the submenu to the left; a pointer that last moved right (or jumped) and heads for\n * it is \"not moving to the submenu\", so Radix focuses the parent PANEL itself, the submenu reads\n * that as focus outside and closes, and the click meant for it lands on the page and closes the\n * whole menu. Focus on the parent panel (role=\"menu\", the panel that holds this trigger) means\n * only \"the pointer left a row without entering another one\" — that never closes a submenu, on\n * either side. Focus on another ROW (a sibling hovered or arrowed to) still closes it, as before.\n */\nfunction SubmenuView({ node, engine }: { node: Extract<MenuNode, { kind: \"submenu\" }>; engine: MenuEngine }): React.ReactElement {\n const triggerRef = React.useRef<HTMLDivElement>(null);\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n return (\n <DropdownMenuSub\n onOpenChange={(open) => {\n if (open && node.lazy && !node.loading) void engine.expand(node.id);\n }}\n >\n <DropdownMenuSubTrigger ref={triggerRef} data-alchemy-node={node.id} className={size.row} aria-busy={node.pending ? true : undefined}>\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n {node.pending ? <span className=\"ml-auto text-xs text-muted-foreground\">Loading…</span> : null}\n </DropdownMenuSubTrigger>\n {/* As wide as the menu it opens from: a row's long reason is cut short on one line (the\n whole of it is the row's tooltip), never a 727 px panel across the grid (review 2). */}\n <DropdownMenuSubContent\n data-alchemy-submenu={node.id}\n onFocusOutside={(event) => {\n const to = event.target;\n const trigger = triggerRef.current;\n if (to instanceof Element && trigger && to.getAttribute(\"role\") === \"menu\" && to.contains(trigger)) event.preventDefault();\n }}\n className={`${size.panel} max-w-[calc(100vw-1rem)] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto`}\n >\n {node.loading ? (\n <DropdownMenuLabel className=\"text-xs text-muted-foreground\">Loading…</DropdownMenuLabel>\n ) : node.children.length === 0 && !node.lazy ? (\n <DropdownMenuLabel className=\"text-xs text-muted-foreground\">{node.emptyLabel ?? \"Nothing here yet\"}</DropdownMenuLabel>\n ) : (\n <NodeList nodes={node.children} engine={engine} />\n )}\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n );\n}\n\nfunction LeafItem({ node, engine }: { node: Extract<MenuLeafNode, { kind: \"item\" }>; engine: MenuEngine }): React.ReactElement {\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n const row = (\n <DropdownMenuItem\n data-alchemy-node={node.id}\n aria-disabled={node.unavailable ? true : undefined}\n aria-pressed={node.pressed}\n onSelect={(event) => {\n if (node.unavailable) {\n event.preventDefault();\n return;\n }\n // An in-place reload (Retry) keeps the menu and this submenu open: Radix closes on every\n // select unless it is prevented (a-retry-row-keeps-its-menu-open.test.tsx).\n if (node.keepsMenuOpen) event.preventDefault();\n void engine.run(node.id);\n }}\n className={`${size.row} ${node.unavailable ? \"opacity-50\" : \"\"} ${node.destructive ? \"text-destructive\" : \"\"}`}\n >\n {iconOf(node, engine)}\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate\">{node.label}</span>\n {node.description ? <span className=\"truncate text-xs text-muted-foreground\">{node.description}</span> : null}\n </span>\n {node.hint ? <span className={`ml-auto ${size.hint} text-muted-foreground`}>{node.hint}</span> : null}\n </DropdownMenuItem>\n );\n if (!node.unavailable) return row;\n return (\n <Tooltip>\n <TooltipTrigger asChild>{row}</TooltipTrigger>\n <TooltipContent>{node.unavailable.sentence}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** An icon button for a strip / bar leaf (greyed verb carries its sentence). */\nexport function LeafButton({\n node,\n engine,\n showLabel,\n}: {\n node: MenuNode;\n engine: MenuEngine;\n showLabel: boolean;\n}): React.ReactElement | null {\n if (node.kind !== \"item\" && node.kind !== \"checkbox\" && node.kind !== \"link\") return null;\n const unavailable = node.kind === \"item\" ? node.unavailable : undefined;\n const pressed = node.kind === \"item\" ? node.pressed : node.kind === \"checkbox\" ? node.checked : undefined;\n const glyph = iconOf(node, engine);\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n const destructive = node.kind === \"item\" && node.destructive;\n const button = (\n <button\n type=\"button\"\n data-alchemy-node={node.id}\n // THE BUTTON TOUCH FLOOR (design-system styles.css): 44px on coarse\n // pointers, desktop density unchanged.\n data-matrx-button=\"\"\n data-tap-floor=\"\"\n data-tap-floor-square=\"\"\n aria-label={node.label}\n aria-disabled={unavailable ? true : undefined}\n aria-pressed={pressed}\n onMouseDown={(e) => {\n if (node.kind === \"item\" && node.preserveSelection) e.preventDefault();\n }}\n onClick={() => {\n if (unavailable) {\n engine.explain(unavailable.sentence);\n return;\n }\n if (node.kind === \"link\") {\n window.location.assign(node.href);\n return;\n }\n void engine.run(node.id);\n }}\n className={`inline-flex ${size.stripButton} pointer-coarse:h-11 pointer-coarse:min-w-11 shrink-0 items-center justify-center gap-1.5 rounded-md text-sm ${destructive ? \"text-destructive hover:bg-destructive/10\" : \"text-muted-foreground hover:bg-accent hover:text-foreground\"} ${\n unavailable ? \"cursor-default opacity-50 hover:bg-transparent\" : \"\"\n } ${pressed ? \"text-foreground\" : \"\"}`}\n >\n {glyph}\n {showLabel || !glyph ? <span className=\"whitespace-nowrap\">{node.label}</span> : null}\n </button>\n );\n return (\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent>{unavailable ? unavailable.sentence : node.label}</TooltipContent>\n </Tooltip>\n );\n}\n","\"use client\";\n/**\n * Menu size — \"standard\" (the original 288 px menu) or \"large\": the Google Docs / Sheets class of\n * menu for a feature-heavy app (Arman, 2026-10-02: \"our menu is too small… the one place where we\n * have essentially unlimited space, we're suddenly cheap about it\"). Measured on Google Sheets:\n * 322 px wide, 32 px rows, 14 px text, 18 px icons. Large goes one step past it: 360 px, 36 px rows,\n * 15 px text. A context, so submenus (portalled) draw at the same size as the menu they open from.\n */\nimport * as React from \"react\";\n\nexport type MenuSize = \"standard\" | \"large\";\n\nexport const MenuSizeContext = React.createContext<MenuSize>(\"standard\");\n\nexport function useMenuSize(): MenuSize {\n return React.useContext(MenuSizeContext);\n}\n\nexport const MENU_SIZE_CLASSES: Record<\n MenuSize,\n { panel: string; row: string; strip: string; stripButton: string; label: string; filter: string; hint: string }\n> = {\n standard: {\n panel: \"w-72\",\n row: \"gap-2\",\n strip: \"flex items-center gap-0.5 px-1 py-1\",\n stripButton: \"h-7 min-w-7 px-1.5\",\n label: \"text-xs\",\n filter: \"h-7 text-sm\",\n hint: \"text-xs\",\n },\n large: {\n panel: \"w-[22.5rem] [&_svg]:size-[18px]\",\n row: \"gap-3 min-h-9 px-3 text-[15px]\",\n strip: \"flex items-center justify-between gap-1 px-2 py-1.5\",\n stripButton: \"h-9 min-w-9 px-2\",\n label: \"text-[13px]\",\n filter: \"h-9 text-[15px]\",\n hint: \"text-[13px]\",\n },\n};\n"],"mappings":"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","names":["React","import_design_system","React","React","React","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/react-bar.ts","../src/react/bar.tsx","../src/menu/layouts.ts","../src/react/engine.tsx","../src/declare/sensitivity.ts","../src/actions/projection.ts","../src/actions/run.ts","../src/menu/headings.ts","../src/menu/model.ts","../src/react/context.ts","../src/react/expansion-latest.ts","../src/react/dropdown-nodes.tsx","../src/react/menu-size.tsx"],"sourcesContent":["/** `@ai-matrx/alchemy/react/bar` — the action bar layout (primary + ⋯). */\nexport { ActionBar, type ActionBarProps } from \"./react/bar\";\n","\"use client\";\n/**\n * `@ai-matrx/alchemy/react/bar` — the action bar layout (CONTRACT §2.5):\n * primary actions inline, everything else under ⋯, one model.\n */\nimport * as React from \"react\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, TooltipProvider } from \"@ai-matrx/design-system\";\nimport { bar } from \"../menu/layouts\";\nimport type { ClickTarget } from \"../actions/types\";\nimport type { MenuSubmenuNode } from \"../menu/types\";\nimport { useMenuEngine, type MenuEngine, type MenuEngineOptions } from \"./engine\";\nimport { LeafButton, NodeList, SectionList } from \"./dropdown-nodes\";\n\nexport interface ActionBarProps extends MenuEngineOptions {\n target: ClickTarget;\n /** Compact presentation (smaller gaps); membership is identical. */\n mini?: boolean;\n className?: string;\n /** Hide the ⋯ (the host turned the options off); the primaries still render. */\n hideOverflow?: boolean;\n /**\n * Below this viewport width the ⋯ opens the mobile bottom sheet\n * (`/react/sheet`, loaded on first tap) instead of a dropdown. Default 768.\n */\n sheetBelow?: number;\n /** Override the sheet loader (tests, custom bundlers). */\n loadSheet?: () => Promise<{ ActionSheet: React.ComponentType<import(\"./sheet\").ActionSheetProps> }>;\n}\n\nfunction isNarrow(width: number): boolean {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia?.(`(max-width: ${width - 1}px)`).matches ?? false;\n}\n\n// 28px under a mouse; 44px under touch (a thumb needs the platform floor —\n// page-pass 2026-09-27, the rich-document Read view row on phones).\nconst TRIGGER_CLASS =\n \"inline-flex h-7 min-w-7 pointer-coarse:h-11 pointer-coarse:min-w-11 items-center justify-center gap-1 rounded-md px-1.5 text-muted-foreground hover:bg-accent hover:text-foreground\";\n\nfunction PrimarySubmenu({ node, engine }: { node: MenuSubmenuNode; engine: MenuEngine }): React.ReactElement {\n return (\n <DropdownMenu\n onOpenChange={(open) => {\n if (open && node.lazy && !node.loading) void engine.expand(node.id);\n }}\n >\n <DropdownMenuTrigger asChild>\n <button type=\"button\" aria-label={node.label} data-alchemy-node={node.id} className={TRIGGER_CLASS}>\n {engine.icon(node.icon) ?? <span className=\"text-sm\">{node.label}</span>}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto\">\n {node.loading ? <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">Loading…</div> : <NodeList nodes={node.children} engine={engine} />}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport function ActionBar({\n target,\n mini = false,\n className,\n hideOverflow = false,\n sheetBelow = 768,\n loadSheet = () => import(\"@ai-matrx/alchemy/react/sheet\"),\n ...options\n}: ActionBarProps): React.ReactElement | null {\n const engine = useMenuEngine(target, options);\n const [sheetOpen, setSheetOpen] = React.useState(false);\n const [Sheet, setSheet] = React.useState<React.ComponentType<import(\"./sheet\").ActionSheetProps> | null>(null);\n if (!engine.model) return null;\n const arranged = bar(engine.model, { mini });\n if (arranged.primary.length === 0 && arranged.overflow.length === 0) return null;\n return (\n <TooltipProvider>\n <div\n role=\"toolbar\"\n aria-label=\"Actions\"\n data-alchemy-layout=\"bar\"\n className={`flex items-center ${mini ? \"gap-0\" : \"gap-0.5\"} ${className ?? \"\"}`}\n >\n {arranged.primary.map((node) =>\n node.kind === \"submenu\" ? (\n <PrimarySubmenu key={node.id} node={node} engine={engine} />\n ) : (\n <LeafButton key={node.id} node={node} engine={engine} showLabel={false} />\n ),\n )}\n {hideOverflow || arranged.overflow.length === 0 ? null : isNarrow(sheetBelow) ? (\n <>\n <button\n type=\"button\"\n aria-label=\"More actions\"\n data-alchemy-trigger=\"overflow\"\n className={TRIGGER_CLASS}\n onClick={() => {\n setSheetOpen(true);\n if (!Sheet) void loadSheet().then((m) => setSheet(() => m.ActionSheet));\n }}\n >\n <span aria-hidden className=\"text-base leading-none\">⋯</span>\n </button>\n {Sheet ? <Sheet {...options} target={target} open={sheetOpen} onOpenChange={setSheetOpen} /> : null}\n </>\n ) : (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button type=\"button\" aria-label=\"More actions\" data-alchemy-trigger=\"overflow\" className={TRIGGER_CLASS}>\n <span aria-hidden className=\"text-base leading-none\">⋯</span>\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-64 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto\">\n <SectionList sections={arranged.overflow} engine={engine} />\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </TooltipProvider>\n );\n}\n","/**\n * Layouts — pure arrangements of one MenuModel (CONTRACT §2.5).\n *\n * Every layout is a function over the SAME model: it decides which nodes sit\n * at the top level, which fold under a named submenu and which go into a\n * strip. None adds, drops or renames a leaf — `leafIds(arranged)` equals\n * `leafIds(model)` for every layout (THE LOSSLESS LAW, proven by test).\n *\n * The clipboard group IS the universal verb strip: in the strip layouts it is\n * drawn icon-only; elsewhere its rows are drawn in place. Unavailable verbs\n * (the only greyed nodes, R1 c) appear in every layout identically.\n */\nimport type {\n ArrangedBar,\n ArrangedContext,\n ArrangedPalette,\n ArrangedSelectionToolbar,\n ArrangedSheet,\n ContextArrangement,\n MenuLeafNode,\n MenuModel,\n MenuNode,\n MenuSection,\n MenuSubmenuNode,\n} from \"./types\";\n\n/** A section with more rows than this folds under its label in tiered/command/sheet. */\nexport const INLINE_SECTION_MAX = 3;\n\n/**\n * A section's heading is ONLY the name its actions declare (an approved\n * heading the classic menu already uses: \"Save as\", \"Copy as\", \"History\").\n * A group with no declared name has no heading and is never folded — its rows\n * show inline. The package never coins a heading (chair ruling, ALC-15).\n */\nexport function sectionLabel(section: MenuSection): string | null {\n return section.label ?? null;\n}\n\nfunction isLeaf(node: MenuNode): node is MenuLeafNode {\n return node.kind === \"item\" || node.kind === \"checkbox\" || node.kind === \"link\";\n}\n\n/** Every actionable id in a node list, depth-first. A lazy submenu counts as one leaf. */\nfunction collect(nodes: readonly MenuNode[], out: string[]): void {\n for (const n of nodes) {\n if (isLeaf(n)) out.push(n.id);\n else if (n.kind === \"submenu\") {\n if (n.lazy) out.push(n.id);\n else collect(n.children, out);\n }\n }\n}\n\ntype Arranged =\n | MenuModel\n | ArrangedBar\n | ArrangedContext\n | ArrangedSheet\n | ArrangedPalette\n | ArrangedSelectionToolbar\n | MenuSection[];\n\n/** Proof obligation for every layout: its leaf set equals the model's (sorted, de-duplicated). */\nexport function leafIds(arranged: Arranged): readonly string[] {\n const out: string[] = [];\n if (Array.isArray(arranged)) {\n for (const s of arranged) collect(s.nodes, out);\n } else if (\"leaves\" in arranged) {\n for (const l of arranged.leaves) out.push(l.node.id);\n } else if (\"primary\" in arranged && \"overflow\" in arranged) {\n collect(arranged.primary, out);\n for (const s of arranged.overflow) collect(s.nodes, out);\n } else if (\"root\" in arranged) {\n collect(arranged.strip, out);\n collect(arranged.root, out);\n } else if (\"more\" in arranged) {\n collect(arranged.strip, out);\n for (const s of arranged.more) collect(s.nodes, out);\n } else if (\"filterable\" in arranged) {\n collect(arranged.strip, out);\n for (const s of arranged.sections) collect(s.nodes, out);\n } else {\n for (const s of arranged.sections) collect(s.nodes, out);\n }\n return [...new Set(out)].sort();\n}\n\n/** Only a NAMED section folds; callers check `section.label` first. */\nfunction fold(section: MenuSection & { label: string }): MenuSubmenuNode {\n return {\n kind: \"submenu\",\n id: `${section.id}:fold`,\n label: section.label,\n ...(section.icon !== undefined ? { icon: section.icon } : {}),\n children: section.nodes,\n };\n}\n\nfunction rowCount(nodes: readonly MenuNode[]): number {\n return nodes.filter((n) => n.kind !== \"separator\" && n.kind !== \"label\").length;\n}\n\nfunction stripOf(model: MenuModel): MenuLeafNode[] {\n const clipboard = model.sections.find((s) => s.group === \"clipboard\" && !s.primary);\n return clipboard ? clipboard.nodes.filter(isLeaf) : [];\n}\n\nfunction clipboardRest(model: MenuModel): MenuNode[] {\n const clipboard = model.sections.find((s) => s.group === \"clipboard\" && !s.primary);\n return clipboard ? clipboard.nodes.filter((n) => !isLeaf(n) && n.kind === \"submenu\") : [];\n}\n\nfunction placementOf(node: MenuNode): \"primary\" | \"overflow\" | \"both\" {\n return \"placement\" in node && node.placement ? node.placement : \"overflow\";\n}\n\n/** The historical flat column: every section top-level. */\nfunction classic(model: MenuModel): ArrangedContext {\n return { strip: [], sections: model.sections, filterable: false };\n}\n\n/**\n * Tiered / command: the universal verbs as an icon strip; every other row by\n * its own name; the clicked target's (primary) section first, inline, heading\n * kept; a long non-primary section folds under ITS OWN label (never a coined\n * heading); History is the one approved grouping and already a group.\n */\nfunction tiered(model: MenuModel, filterable: boolean): ArrangedContext {\n const strip = stripOf(model);\n const sections: MenuSection[] = [];\n const rest = clipboardRest(model);\n for (const s of model.sections) {\n if (s.group === \"clipboard\" && !s.primary) {\n if (rest.length) sections.push({ ...s, nodes: rest });\n continue;\n }\n if (s.primary) {\n sections.push(s);\n continue;\n }\n if (!s.label || s.group === \"surface-info\" || rowCount(s.nodes) <= INLINE_SECTION_MAX) {\n // A section keeps its declared heading in EVERY layout (the Lossless\n // Law covers headings: ⋯, the bar's ⋯ and the phone sheet show it too).\n sections.push(s);\n continue;\n }\n sections.push({ id: s.id, group: s.group, nodes: [fold({ ...s, label: s.label })] });\n }\n return { strip, sections, filterable };\n}\n\nexport function context(model: MenuModel, arrangement: ContextArrangement): ArrangedContext {\n if (arrangement === \"classic\") return classic(model);\n return tiered(model, arrangement === \"command\");\n}\n\n/**\n * FOLD UNDER THE SUBJECT — a control that belongs to a CONTAINER of the thing\n * (a tab's \"…\" over the note it shows) draws the container's own rows (the\n * primary sections) on top, and EVERY other row — the verb strip included —\n * under ONE submenu named for the subject (\"Note ▸\"). The label is the\n * subject's name the host supplies (the menu header's label), never a coined\n * group heading. Lossless: rows move, none is dropped or renamed. With no\n * primary section there is nothing to put first, so the arrangement is left\n * as it was. (page-pass /notes, 2026-09-28, Arman's ruling for the tab \"…\".)\n */\nexport function foldUnderSubject(arranged: ArrangedContext, subject: string): ArrangedContext {\n const label = subject.trim();\n const primary = arranged.sections.filter((s) => s.primary);\n const rest = arranged.sections.filter((s) => !s.primary);\n if (!label || primary.length === 0 || (rest.length === 0 && arranged.strip.length === 0)) return arranged;\n const children: MenuNode[] = [];\n if (arranged.strip.length) children.push(...arranged.strip);\n for (const s of rest) {\n if (rowCount(s.nodes) === 0) continue;\n if (children.length) children.push({ kind: \"separator\", id: `${s.id}:subject-sep` });\n if (s.label) children.push({ kind: \"label\", id: `${s.id}:subject-label`, label: s.label });\n children.push(...s.nodes);\n }\n if (rowCount(children) === 0) return { ...arranged, strip: [] };\n return {\n strip: [],\n filterable: false,\n sections: [\n ...primary,\n { id: \"subject\", group: rest[0]?.group ?? primary[0]!.group, nodes: [{ kind: \"submenu\", id: \"subject:fold\", label, children }] },\n ],\n };\n}\n\n/**\n * A long NAMED section folds under its own name (\"Save as ▸\", \"Copy as ▸\");\n * primary sections and unnamed groups stay inline. Folding moves rows, never\n * renames or drops them, and never under a coined heading.\n */\nfunction foldNamed(sections: readonly MenuSection[]): MenuSection[] {\n return sections.map((s) =>\n s.label && !s.primary && rowCount(s.nodes) > INLINE_SECTION_MAX ? { id: s.id, group: s.group, nodes: [fold({ ...s, label: s.label })] } : s,\n );\n}\n\n/** ⋯ overflow: every section in classic order; long named sections fold under their own name. */\nexport function overflow(model: MenuModel): MenuSection[] {\n return foldNamed(model.sections);\n}\n\n/**\n * The action bar: primary buttons inline, EVERYTHING else under ⋯. A \"both\"\n * action is mirrored in both halves (the leaf set is still the model's).\n * `mini` changes presentation only (icon-only primaries), never membership.\n */\nexport function bar(model: MenuModel, _options: { mini?: boolean } = {}): ArrangedBar {\n const primary: MenuNode[] = [];\n const overflowSections: MenuSection[] = [];\n for (const s of model.sections) {\n const rest: MenuNode[] = [];\n for (const n of s.nodes) {\n if (n.kind === \"separator\" || n.kind === \"label\") {\n rest.push(n);\n continue;\n }\n const p = placementOf(n);\n if (p === \"primary\" || p === \"both\") primary.push(n);\n if (p === \"overflow\" || p === \"both\") rest.push(n);\n }\n if (rowCount(rest) > 0) overflowSections.push({ ...s, nodes: rest });\n }\n return { primary, overflow: foldNamed(overflowSections) };\n}\n\n/** Selection toolbar: the verbs plus primary actions as a strip; the rest under More. */\nexport function selectionToolbar(model: MenuModel): ArrangedSelectionToolbar {\n const strip: MenuNode[] = [];\n const more: MenuSection[] = [];\n for (const s of model.sections) {\n const rest: MenuNode[] = [];\n for (const n of s.nodes) {\n const inStrip = (s.group === \"clipboard\" && !s.primary && isLeaf(n)) || placementOf(n) !== \"overflow\";\n if (inStrip) strip.push(n);\n else rest.push(n);\n }\n if (rowCount(rest) > 0) more.push({ ...s, nodes: rest });\n }\n return { strip, more };\n}\n\n/**\n * Mobile bottom sheet: the verb strip on top; primary and short sections\n * inline; longer sections become one drill-down row named by the section.\n * Consumes the model directly, so it can never drift from desktop.\n */\nexport function sheet(model: MenuModel): ArrangedSheet {\n const strip = stripOf(model);\n const root: MenuNode[] = [];\n const rest = clipboardRest(model);\n for (const s of model.sections) {\n const nodes = s.group === \"clipboard\" && !s.primary ? rest : s.nodes;\n if (rowCount(nodes) === 0) continue;\n if (root.length) root.push({ kind: \"separator\", id: `${s.id}:sep` });\n if (s.primary || !s.label || rowCount(nodes) <= INLINE_SECTION_MAX) {\n if (s.label) root.push({ kind: \"label\", id: `${s.id}:label`, label: s.label });\n root.push(...nodes);\n } else {\n root.push(fold({ ...s, label: s.label, nodes }));\n }\n }\n return { strip, root };\n}\n\n/** Command palette: every leaf flattened with its breadcrumb (Linear). */\nexport function palette(model: MenuModel): ArrangedPalette {\n const leaves: ArrangedPalette[\"leaves\"] = [];\n const walk = (nodes: readonly MenuNode[], trail: string[]) => {\n for (const n of nodes) {\n if (isLeaf(n)) leaves.push({ node: n, breadcrumb: trail });\n else if (n.kind === \"submenu\") {\n if (n.lazy) leaves.push({ node: n, breadcrumb: trail });\n else walk(n.children, [...trail, n.label]);\n }\n }\n };\n for (const s of model.sections) walk(s.nodes, s.label ? [s.label] : []);\n return { leaves };\n}\n\n/**\n * A SEARCH REACHES EVERY ROW (clone 2026-10-01: \"Patient\" found nothing while\n * \"Patient reminder card\" sat under AI Actions ▸ My Personal). `palette` lists a\n * lazy submenu as ONE leaf — its label only — because its rows load on open.\n * A layout that searches opens every lazy submenu it can see: these are the\n * ones still to open (not already loading).\n */\nexport function lazySubmenuIds(model: MenuModel | null): string[] {\n if (!model) return [];\n const out: string[] = [];\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) {\n if (n.kind !== \"submenu\") continue;\n if (n.lazy) {\n if (!n.loading) out.push(n.id);\n } else walk(n.children);\n }\n };\n for (const s of model.sections) walk(s.nodes);\n return out;\n}\n\n/** True while some submenu's rows are not in the model yet (a search could still find more). */\nexport function paletteStillOpening(model: MenuModel | null): boolean {\n if (!model) return true;\n const walk = (nodes: readonly MenuNode[]): boolean =>\n nodes.some((n) => n.kind === \"submenu\" && (n.lazy || n.loading || n.pending || walk(n.children)));\n return model.sections.some((s) => walk(s.nodes));\n}\n\n/** Filter the palette by a query (every word must match label or breadcrumb). */\nexport function filterPalette(arranged: ArrangedPalette, query: string): ArrangedPalette {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (!words.length) return arranged;\n return {\n leaves: arranged.leaves.filter((l) => {\n const hay = `${l.node.label} ${l.breadcrumb.join(\" \")}`.toLowerCase();\n return words.every((w) => hay.includes(w));\n }),\n };\n}\n\nexport const layouts = { bar, overflow, context, selectionToolbar, sheet, palette };\n","\"use client\";\n/**\n * The React half of T1e: one hook every renderer uses to resolve the registry\n * at a target, build the model and run a node. Handlers never live in a\n * renderer — they live in providers and run through `runAction`.\n *\n * The context object is shared through globalThis so every per-layout entry\n * (each bundled separately) reads the same provider (module state is banned\n * across dual-loader graphs).\n */\nimport * as React from \"react\";\nimport { runAction, type RunResult } from \"../actions/run\";\nimport type { ProjectionSource } from \"../actions/projection\";\nimport type { Action, ClickTarget, ResolveRestriction, ResolvedAction } from \"../actions/types\";\nimport { actionToNode, buildMenuModel, findNode, withExpandedChildren, withGroupDividers } from \"../menu/model\";\nimport type { MenuModel, MenuNode } from \"../menu/types\";\nimport { useAlchemyActions } from \"./context\";\nimport { isLatestExpansion } from \"./expansion-latest\";\n\nexport interface MenuEngineOptions {\n restrict?: ResolveRestriction;\n /** Raw sources for projection (the host's mounted surface / clicked item). */\n source?: ProjectionSource;\n /** Content the menu acts on when nothing is selected (header text). */\n content?: string | null;\n /** The field's name, when the content is a field's text (see buildMenuModel). */\n contentLabel?: string | null;\n contentFingerprint?: string;\n /**\n * Called after a node ran (close the menu, announce). `keepOpen` is true for a row that reloads\n * the menu it sits in (`Action.keepsMenuOpen`): a layout never closes on it.\n */\n onRan?: (nodeId: string, result: RunResult, ran?: { keepOpen: boolean }) => void;\n /** Resolve only while true (renderers resolve on open). Default true. */\n active?: boolean;\n /**\n * Re-resolve when this changes even if the target object is the same (a\n * host that keeps one target per mount and reads live state through it).\n */\n revision?: string | number;\n}\n\nexport interface MenuEngine {\n model: MenuModel | null;\n resolved: readonly ResolvedAction[];\n run(nodeId: string): Promise<RunResult | null>;\n expand(nodeId: string): Promise<void>;\n /** The host's glyph for a key; `tone` is the action's colour class (iconTone). */\n icon(key: string | undefined, tone?: string): React.ReactNode;\n /** Say why a greyed verb is greyed (a tap on touch, where tooltips never open). */\n explain(sentence: string): void;\n}\n\nfunction nodeInModel(model: MenuModel, id: string): MenuNode | null {\n for (const s of model.sections) {\n const hit = findNode(s.nodes, id);\n if (hit) return hit;\n }\n return null;\n}\n\nfunction hasLoadedRows(model: MenuModel, id: string): boolean {\n const n = nodeInModel(model, id);\n return Boolean(n && n.kind === \"submenu\" && !n.lazy && !n.loading);\n}\n\nfunction loadedChildren(model: MenuModel, id: string): readonly MenuNode[] {\n const n = nodeInModel(model, id);\n return n && n.kind === \"submenu\" && !n.lazy ? n.children : [];\n}\n\n/**\n * The rebuilt rows, with every OPENED submenu that came back lazy keeping the\n * rows it last showed (its re-expansion replaces them when it lands).\n */\nexport function carryOpened(prev: readonly MenuNode[], next: MenuNode[], opened: ReadonlySet<string>): MenuNode[] {\n return next.map((n) => {\n if (n.kind !== \"submenu\") return n;\n const old = prev.find((o) => o.id === n.id);\n if (!old || old.kind !== \"submenu\" || old.lazy) return n;\n if (n.lazy) {\n return opened.has(n.id) ? { ...n, lazy: false, loading: false, pending: false, children: old.children } : n;\n }\n return { ...n, children: carryOpened(old.children, n.children, opened) };\n });\n}\n\nfunction carryOpenedModel(prev: MenuModel, next: MenuModel, opened: ReadonlySet<string>): MenuModel {\n if (opened.size === 0) return next;\n const prevNodes = prev.sections.flatMap((s) => s.nodes);\n return { ...next, sections: next.sections.map((s) => ({ ...s, nodes: carryOpened(prevNodes, s.nodes, opened) })) };\n}\n\nexport function useMenuEngine(target: ClickTarget | null, options: MenuEngineOptions = {}): MenuEngine {\n const { registry, ports } = useAlchemyActions();\n const [resolved, setResolved] = React.useState<readonly ResolvedAction[]>([]);\n const [model, setModel] = React.useState<MenuModel | null>(null);\n const [tick, setTick] = React.useState(0);\n // Every action an expansion returned, by id (a nested row is found here).\n const expanded = React.useRef(new Map<string, Action>());\n // Every submenu the person (or a search) opened, at ANY depth. A re-resolve\n // rebuilds the model with each of them lazy again; these are re-opened, and\n // their last rows are carried over meanwhile so an open submenu never blanks.\n const opened = React.useRef(new Set<string>());\n const expandSeq = React.useRef(new Map<string, number>());\n const targetEpoch = React.useRef(0);\n const currentTarget = React.useRef(target);\n if (currentTarget.current !== target) {\n currentTarget.current = target;\n targetEpoch.current += 1;\n }\n const active = options.active ?? true;\n const optionsRef = React.useRef(options);\n optionsRef.current = options;\n\n React.useEffect(() => registry.subscribe(() => setTick((t) => t + 1)), [registry]);\n\n const expandAction = React.useCallback(\n async (action: Action, nodeId: string) => {\n if (!target || !action.expand) return;\n const epoch = targetEpoch.current;\n const seq = (expandSeq.current.get(nodeId) ?? 0) + 1;\n expandSeq.current.set(nodeId, seq);\n const latest = () => isLatestExpansion(epoch, targetEpoch.current, seq, expandSeq.current.get(nodeId));\n // \"Loading…\" only over a submenu with no rows yet: a refresh keeps the\n // rows on screen until the new ones land (a blank flash unmounts the\n // focused row and Radix closes the parent submenu under the pointer).\n setModel((m) => (m && !hasLoadedRows(m, nodeId) ? withExpandedChildren(m, nodeId, \"loading\") : m));\n try {\n // A programmatic-only Action (surfaces without \"menu\") never becomes a row, even inside a submenu.\n const children = (await action.expand(target, new AbortController().signal)).filter(\n (child) => !child.surfaces || child.surfaces.includes(\"menu\"),\n );\n if (!latest()) return;\n const nodes: MenuNode[] = withGroupDividers(\n children,\n children.map((child) => {\n expanded.current.set(child.id, child);\n return actionToNode({ action: child, eligibility: { status: \"available\" } }, target, ports.i18n ? { i18n: ports.i18n } : {});\n }),\n );\n setModel((m) => (m ? withExpandedChildren(m, nodeId, carryOpened(loadedChildren(m, nodeId), nodes, opened.current)) : m));\n // A nested submenu that was open stays open: re-open it under its new parent rows.\n for (const child of children) if (child.expand && opened.current.has(child.id)) void expandAction(child, child.id);\n } catch (error) {\n if (!latest()) return;\n ports.diagnostics.capture(error, { area: \"menu\", detail: { nodeId, stage: \"expand\" } });\n setModel((m) => (m ? withExpandedChildren(m, nodeId, []) : m));\n }\n },\n [target, ports],\n );\n\n React.useEffect(() => {\n expanded.current.clear();\n opened.current.clear();\n }, [target]);\n\n React.useEffect(() => {\n if (!target || !active) return;\n let live = true;\n void registry.resolve(target, optionsRef.current.restrict).then((list) => {\n if (!live) return;\n setResolved(list);\n const built = buildMenuModel(target, list, { ...(ports.i18n ? { i18n: ports.i18n } : {}), content: optionsRef.current.content ?? null, contentLabel: optionsRef.current.contentLabel ?? null });\n setModel((prev) => (prev ? carryOpenedModel(prev, built, opened.current) : built));\n for (const { action } of list) {\n if (opened.current.has(action.id) && action.expand) void expandAction(action, action.id);\n }\n });\n return () => {\n live = false;\n };\n }, [registry, ports, target, active, tick, options.revision, expandAction]);\n\n // Live toggles (read-aloud, thumbs): re-resolve when an action's store\n // changes. Subscriptions are keyed by the resolved ids (not the array, which\n // every resolve replaces) and a notify fired synchronously INSIDE subscribe\n // (a store's hydration read) is ignored — otherwise subscribe → notify →\n // resolve → resubscribe never ends.\n const resolvedRef = React.useRef(resolved);\n resolvedRef.current = resolved;\n const subscribedIds = resolved.map((r) => r.action.id).join(\"\\n\");\n React.useEffect(() => {\n if (!target) return;\n let subscribing = true;\n const onChange = () => {\n if (!subscribing) setTick((t) => t + 1);\n };\n const offs = resolvedRef.current\n .map((r) => r.action.subscribe?.(onChange, target))\n .filter((off): off is () => void => typeof off === \"function\");\n subscribing = false;\n return () => offs.forEach((off) => off());\n }, [subscribedIds, target]);\n\n const findAction = React.useCallback(\n (id: string): Action | undefined => resolved.find((r) => r.action.id === id)?.action ?? expanded.current.get(id) ?? undefined,\n [resolved],\n );\n\n const run = React.useCallback(\n async (nodeId: string) => {\n if (!target || !model) return null;\n const node = model.sections.map((s) => findNode(s.nodes, nodeId)).find(Boolean) ?? null;\n const action = findAction(node && \"actionId\" in node && node.actionId ? node.actionId : nodeId);\n if (!action) return null;\n const o = optionsRef.current;\n const result = await runAction(action, target, {\n ports,\n ...(o.source ? { source: o.source } : {}),\n ...(o.contentFingerprint ? { contentFingerprint: o.contentFingerprint } : {}),\n });\n o.onRan?.(nodeId, result, { keepOpen: Boolean(action.keepsMenuOpen) });\n return result;\n },\n [target, model, findAction, ports],\n );\n\n const expand = React.useCallback(\n async (nodeId: string) => {\n const action = findAction(nodeId);\n if (!target || !action?.expand) return;\n // Remembered so late resolver data (a re-resolve) re-opens it, at any depth.\n opened.current.add(nodeId);\n await expandAction(action, nodeId);\n },\n [findAction, target, expandAction],\n );\n\n const icon = React.useCallback(\n (key: string | undefined, tone?: string): React.ReactNode => {\n if (!key || !ports.icons) return null;\n const Resolved = ports.icons.resolve(key) as React.ComponentType<{ className?: string; \"aria-hidden\"?: boolean }> | null;\n return Resolved ? <Resolved className={`h-4 w-4 shrink-0 ${tone ?? \"\"}`} aria-hidden /> : null;\n },\n [ports.icons],\n );\n\n const explain = React.useCallback(\n (sentence: string) => {\n if (ports.notify) ports.notify.info(sentence);\n else ports.diagnostics.capture(new Error(`No notify port to explain: ${sentence}`), { area: \"menu\", detail: { sentence } });\n },\n [ports],\n );\n\n return { model, resolved, run, expand, icon, explain };\n}\n","/**\n * Sensitivity defaults and resolution (CONTRACT §2.1). Its own module so the\n * lightweight entries (`/actions`, the T0 React host) can project without\n * pulling the declaration registry.\n */\nimport type { DeclaredValue, Sensitivity } from \"./types\";\n\nexport const DEFAULT_SENSITIVITY: Sensitivity = Object.freeze({\n exportable: true,\n classification: \"ordinary\",\n includedByDefault: true,\n});\n\nexport function resolveSensitivity(value: Pick<DeclaredValue, \"sensitivity\">): Sensitivity {\n return {\n exportable: value.sensitivity?.exportable ?? DEFAULT_SENSITIVITY.exportable,\n classification: value.sensitivity?.classification ?? DEFAULT_SENSITIVITY.classification,\n includedByDefault: value.sensitivity?.includedByDefault ?? DEFAULT_SENSITIVITY.includedByDefault,\n };\n}\n","/**\n * PROJECTION BEFORE PROVIDERS (CONTRACT §2.4).\n *\n * The only place a raw read (`MountedSurface.readValues`,\n * `InternalResolvedItem.readValues`) is consumed on behalf of an action.\n * What leaves is projected: a value is kept only when it is DECLARED, its\n * classification is \"ordinary\" and it is exportable. Everything removed is\n * recorded as an omission, so the person and the agent can see what was held\n * back. No caller can relax this.\n */\nimport { resolveSensitivity } from \"../declare/sensitivity\";\nimport type { InternalResolvedItem, MountedSurface } from \"../declare/host\";\nimport type { DeclaredValue, Json, LiveValues, ResolvedSurfaceDeclaration } from \"../declare/types\";\nimport type { ProjectedReads, ReadOmission } from \"./types\";\n\nexport interface ProjectionSource {\n surface: MountedSurface | null;\n declaration: ResolvedSurfaceDeclaration | null;\n item: InternalResolvedItem | null;\n}\n\nfunction toJson(value: unknown): Json | undefined {\n if (value === undefined || typeof value === \"function\" || typeof value === \"symbol\") return undefined;\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value;\n if (typeof value === \"number\") return Number.isFinite(value) ? value : null;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map((v) => toJson(v) ?? null);\n if (typeof value === \"object\") {\n const out: { [key: string]: Json } = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n const j = toJson(v);\n if (j !== undefined) out[k] = j;\n }\n return out;\n }\n return undefined;\n}\n\n/** Keep declared, ordinary, exportable values; record every removal. */\nexport function projectValues(\n raw: Record<string, unknown>,\n declared: readonly Pick<DeclaredValue, \"name\" | \"sensitivity\">[],\n pathPrefix = \"\",\n): { values: Record<string, Json>; omissions: ReadOmission[] } {\n const byName = new Map(declared.map((d) => [d.name, d]));\n const values: Record<string, Json> = {};\n const omissions: ReadOmission[] = [];\n for (const [name, value] of Object.entries(raw)) {\n const path = pathPrefix ? `${pathPrefix}.${name}` : name;\n const decl = byName.get(name);\n if (!decl) {\n omissions.push({ path, reason: \"filtered\" });\n continue;\n }\n const sensitivity = resolveSensitivity(decl);\n if (sensitivity.classification !== \"ordinary\") {\n omissions.push({ path, reason: \"excluded\", classification: sensitivity.classification });\n continue;\n }\n if (!sensitivity.exportable) {\n omissions.push({ path, reason: \"excluded\" });\n continue;\n }\n const json = toJson(value);\n if (json === undefined) continue;\n values[name] = json;\n }\n return { values, omissions };\n}\n\nexport function createProjectedReads(source: ProjectionSource): ProjectedReads {\n return {\n async values(signal) {\n if (!source.surface || !source.declaration) return { values: {}, omissions: [] };\n const raw = await source.surface.readValues(signal);\n const screenValues = source.declaration.values;\n return projectValues(raw, screenValues);\n },\n async item(signal) {\n const item = source.item;\n if (!item || !source.declaration) return null;\n const type = source.declaration.itemTypes?.find((t) => t.name === item.itemType);\n if (!type) return { values: {}, omissions: [{ path: item.itemType, reason: \"filtered\" }] };\n const raw = await item.readValues(signal);\n return projectValues(raw, type.values, item.itemType);\n },\n async live(signal): Promise<LiveValues> {\n if (!source.surface?.readLive) return {};\n return source.surface.readLive(signal);\n },\n };\n}\n","/**\n * The one run path (T1e). Every layout runs an action through here, so the\n * sign-in-then-resume rule, projection and failure capture live once.\n */\nimport type { TransferOutcome } from \"@ai-matrx/alchemy/operate\";\nimport type { AlchemyHostPorts } from \"../ports\";\nimport { createProjectedReads, type ProjectionSource } from \"./projection\";\nimport type { Action, ClickTarget } from \"./types\";\n\nexport interface RunActionOptions {\n ports: AlchemyHostPorts;\n /** Raw sources; projected before the action sees them. */\n source?: ProjectionSource;\n /** Stable fingerprint of the content, for sign-in-then-resume. */\n contentFingerprint?: string;\n signal?: AbortSignal;\n}\n\nexport type RunResult =\n | { status: \"ran\"; outcome: TransferOutcome | void }\n | { status: \"auth-pending\" }\n | { status: \"failed\"; error: unknown };\n\nexport async function runAction(action: Action, target: ClickTarget, options: RunActionOptions): Promise<RunResult> {\n const { ports } = options;\n if (action.requiresAuth && !target.auth.authenticated) {\n if (!ports.auth) {\n // Unreachable through resolve (the action is absent without the port); guard direct callers.\n ports.diagnostics.capture(new Error(`requiresAuth action \"${action.id}\" ran signed out with no auth port`), {\n area: \"actions\",\n detail: { actionId: action.id },\n });\n return { status: \"failed\", error: new Error(\"sign-in unavailable\") };\n }\n ports.auth.signInThenResume({ actionId: action.id, contentFingerprint: options.contentFingerprint ?? action.id });\n return { status: \"auth-pending\" };\n }\n const reads = createProjectedReads(options.source ?? { surface: null, declaration: target.declaration, item: null });\n const signal = options.signal ?? new AbortController().signal;\n try {\n const outcome = await action.run(target, { reads, ports, signal });\n return { status: \"ran\", outcome };\n } catch (error) {\n ports.diagnostics.capture(error, { area: \"actions\", detail: { actionId: action.id, stage: \"run\" } });\n const label = typeof action.label === \"string\" ? action.label : action.id;\n ports.notify?.error(`${label} did not finish.`, \"Try again; if it keeps failing, report it from the feedback button.\");\n return { status: \"failed\", error };\n }\n}\n","/**\n * THE ONE APPROVED-HEADING LIST (ALC-15, chair rulings 7 and D1; the Lossless\n * Law and the vocabulary law). A heading a person sees above or around rows\n * must be a name the classic menus used before agents started coining names.\n *\n * 🚨 ADDING A HEADING TO THIS LIST IS ARMAN'S CALL — never an agent's.\n *\n * Two kinds of section heading exist:\n * - a GROUP heading (\"Copy as\", \"History\"): must be in APPROVED_HEADINGS;\n * - a TARGET label, the thing the person clicked, supplied by the surface at\n * run time (\"Cell · Visit date\", \"Row · Widget A\", \"This finding\", the\n * surface's own label): allowed as declared (`section.kind: \"target\"`, or\n * the \"<Target> · <name>\" shape), except a generic container word.\n * A generic container word (\"More…\", \"Other\", \"Actions\") is never a heading.\n * An unapproved heading renders its rows INLINE in production; in development\n * and tests `buildMenuModel` throws with the remedy.\n */\nimport type { MenuModel, MenuNode } from \"./types\";\n\n/** Names with their provenance (the commit where each classic menu used them). */\nexport const APPROVED_HEADINGS: ReadonlySet<string> = new Set([\n \"Save\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Copy as\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Export\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Edit\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Creator tools\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Admin\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"App\", // rich-document menuStructure, e5b8d01229 (2026-05-19)\n \"Compare\", // rich-document menuStructure, 2e3a8a9fdf (2026-06-11)\n \"History\", // context-menu-v3 tiered layout — the one grouping Arman approved, 2026-08-22\n]);\n\n// Ruling (chair, 2026-09-26, per R26): \"Conversation\" is a TARGET label (`kind: \"target\"`) — it names the thing its rows act on (the whole conversation), like \"Cell · …\" and \"Table · …\"; it is not a group heading and is not added above.\n\nconst CONTAINER_WORD =\n /^(more|more…|more\\.\\.\\.|other|others|misc|miscellaneous|additional|extra|extras|actions|options|advanced|stuff|everything else)$/i;\n\n/** \"Cell · Visit date\", \"Row · Widget A\", \"Column · Price\", \"Table · Route sheet\". */\nconst TARGET_SHAPE = /^(Cell|Row|Column|Table|Range|Selection|Record) · .+$/;\n\nexport function isContainerWord(label: string): boolean {\n return CONTAINER_WORD.test(label.trim());\n}\n\nexport type HeadingKind = \"group\" | \"target\";\n\n/** Is this heading allowed? */\nexport function isApprovedHeading(label: string, kind: HeadingKind = \"group\", approved: ReadonlySet<string> = APPROVED_HEADINGS): boolean {\n const l = label.trim();\n if (!l || isContainerWord(l)) return false;\n if (approved.has(l)) return true;\n return kind === \"target\" || TARGET_SHAPE.test(l);\n}\n\nexport type HeadingPolicy = \"throw\" | \"inline\";\n\n/** Development and tests throw; production shows the rows inline. */\nexport function defaultHeadingPolicy(): HeadingPolicy {\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env?.NODE_ENV;\n return env === \"production\" ? \"inline\" : \"throw\";\n}\n\nexport class UnapprovedHeadingError extends Error {\n readonly heading: string;\n constructor(heading: string, where: string) {\n super(\n `Menu heading \"${heading}\" (${where}) is not an approved heading. Remedy: show these rows inline — declare no section ` +\n `(or kind \"target\" for the clicked thing's own label) — or ask Arman to add the name to APPROVED_HEADINGS in ` +\n `@ai-matrx/alchemy/menu. A generic container word (\"More…\", \"Other\") is never approved.`,\n );\n this.name = \"UnapprovedHeadingError\";\n this.heading = heading;\n }\n}\n\n/** Every heading in a model: section labels, folds, and submenu rows at any depth. */\nexport function menuHeadings(model: Pick<MenuModel, \"sections\">): string[] {\n const out: string[] = [];\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) {\n if (n.kind === \"submenu\") {\n out.push(n.label);\n walk(n.children);\n }\n }\n };\n for (const s of model.sections) {\n if (s.label) out.push(s.label);\n walk(s.nodes);\n }\n return [...new Set(out)];\n}\n\n/** Section headings not in the approved set (container words are never approved). */\nexport function unapprovedHeadings(model: Pick<MenuModel, \"sections\">, approved: ReadonlySet<string> = APPROVED_HEADINGS): string[] {\n const out = new Set<string>();\n for (const s of model.sections) {\n if (s.label && !isApprovedHeading(s.label, s.primary || s.target ? \"target\" : \"group\", approved)) out.add(s.label);\n const walk = (nodes: readonly MenuNode[]) => {\n for (const n of nodes) if (n.kind === \"submenu\") {\n if (isContainerWord(n.label)) out.add(n.label);\n walk(n.children);\n }\n };\n walk(s.nodes);\n }\n return [...out];\n}\n","/**\n * buildMenuModel — WHAT exists at a click target, as one framework-neutral\n * tree (CONTRACT §2.5). Categories GROUP, never gate: eligibility already ran\n * in the registry; this only arranges the resolved set into sections.\n */\nimport type { Action, ActionCategory, ClickTarget, ResolvedAction } from \"../actions/types\";\nimport type { I18nPort } from \"../ports\";\nimport type { MenuGroup, MenuModel, MenuNode, MenuSection, MenuSubmenuNode } from \"./types\";\nimport { UnapprovedHeadingError, defaultHeadingPolicy, isApprovedHeading, isContainerWord, type HeadingPolicy } from \"./headings\";\n\n/** THE category → menu group table (CONTRACT §2.5). */\nexport const CATEGORY_GROUP: Readonly<Record<ActionCategory, MenuGroup>> = {\n clipboard: \"clipboard\",\n copy: \"transfer\",\n export: \"transfer\",\n save: \"document\",\n share: \"document\",\n edit: \"editable\",\n history: \"history\",\n ai: \"ai\",\n ask: \"ai\",\n listen: \"tools\",\n study: \"tools\",\n app: \"tools\",\n applet: \"tools\",\n feedback: \"quick\",\n creator: \"admin\",\n admin: \"admin\",\n \"surface-info\": \"surface-info\",\n};\n\n/** Classic order of the groups. `surface-info` is engine-built and always last. */\nexport const GROUP_ORDER: readonly MenuGroup[] = [\n \"clipboard\",\n \"editable\",\n \"transfer\",\n \"document\",\n \"history\",\n \"ai\",\n \"tools\",\n \"quick\",\n \"surface\",\n \"admin\",\n \"surface-info\",\n];\n\nconst CATEGORY_ORDER: readonly ActionCategory[] = [\n \"clipboard\",\n \"edit\",\n \"copy\",\n \"export\",\n \"save\",\n \"share\",\n \"history\",\n \"ask\",\n \"ai\",\n \"listen\",\n \"study\",\n \"app\",\n \"applet\",\n \"feedback\",\n \"creator\",\n \"admin\",\n \"surface-info\",\n];\n\nexport interface BuildMenuModelOptions {\n /** What an unapproved heading does: \"throw\" (development/tests) or \"inline\" (production). */\n headingPolicy?: HeadingPolicy;\n i18n?: I18nPort;\n /** Content the menu acts on when nothing is selected. */\n content?: string | null;\n /**\n * The name of the field the content is (a text box's label, \"Body\"). The\n * header then names the field — never \"Content: {{reply.body}}\", its raw text.\n */\n contentLabel?: string | null;\n}\n\nfunction translate(i18n: I18nPort | undefined, key: string, fallback: string): string {\n if (!i18n) return fallback;\n try {\n return i18n.t(key, fallback);\n } catch {\n return fallback;\n }\n}\n\n/** One resolved action → one model node (item, checkbox, link or lazy submenu). */\nexport function actionToNode(\n resolved: ResolvedAction,\n target: ClickTarget,\n options: BuildMenuModelOptions = {},\n): MenuNode {\n const { action, eligibility } = resolved;\n const rawLabel = typeof action.label === \"function\" ? action.label(target) : action.label;\n const label = translate(options.i18n, action.labelKey ?? action.id, rawLabel);\n const base = {\n id: action.id,\n actionId: action.id,\n ...(action.icon !== undefined ? { icon: action.icon } : {}),\n ...(action.placement !== undefined ? { placement: action.placement } : {}),\n };\n if (action.expand) {\n const node: MenuSubmenuNode = {\n ...base,\n kind: \"submenu\",\n label,\n lazy: true,\n loading: false,\n ...(action.pending?.(target) ? { pending: true } : {}),\n children: [],\n ...(action.emptyLabel !== undefined ? { emptyLabel: action.emptyLabel } : {}),\n };\n return node;\n }\n if (action.href !== undefined) {\n const href = typeof action.href === \"function\" ? action.href(target) : action.href;\n return { ...base, kind: \"link\", label, href };\n }\n if (action.toggle) {\n return {\n ...base,\n kind: \"checkbox\",\n label,\n checked: action.pressed?.(target) ?? false,\n ...(action.description !== undefined ? { description: action.description } : {}),\n };\n }\n const state = action.stateIcon?.(target) ?? null;\n const pressed = action.pressed?.(target);\n const hint = action.hint !== undefined ? translate(options.i18n, action.hintKey ?? `${action.id}.hint`, action.hint) : undefined;\n return {\n ...base,\n kind: \"item\",\n label,\n ...(action.iconTone !== undefined ? { iconTone: action.iconTone } : {}),\n ...(state ? { stateIcon: state } : {}),\n ...(action.description !== undefined ? { description: action.description } : {}),\n ...(hint !== undefined ? { hint } : {}),\n ...(pressed !== undefined ? { pressed } : {}),\n ...(action.destructive ? { destructive: true } : {}),\n ...(action.preserveSelection ? { preserveSelection: true } : {}),\n ...(action.keepsMenuOpen ? { keepsMenuOpen: true } : {}),\n ...(eligibility.status === \"unavailable-verb\" || eligibility.status === \"unavailable\"\n ? { unavailable: { sentence: eligibility.sentence } }\n : {}),\n };\n}\n\nexport function buildMenuModel(\n target: ClickTarget,\n resolved: readonly ResolvedAction[],\n options: BuildMenuModelOptions = {},\n): MenuModel {\n // THE ONE HEADING CHECK, for every host: an unapproved heading's rows go\n // inline (production) or the build throws with the remedy (dev/tests).\n const policy = options.headingPolicy ?? defaultHeadingPolicy();\n resolved = resolved.map((r) => {\n const sec = r.action.section;\n if (r.action.expand && isContainerWord(typeof r.action.label === \"string\" ? r.action.label : \"\") && policy === \"throw\") {\n throw new UnapprovedHeadingError(r.action.label as string, `submenu of ${r.action.id}`);\n }\n if (!sec) return r;\n const kind = sec.kind ?? (sec.primary ? \"target\" : \"group\");\n if (isApprovedHeading(sec.label, kind)) return r;\n if (policy === \"throw\") throw new UnapprovedHeadingError(sec.label, `section of ${r.action.id}`);\n const { section: _dropped, ...rest } = r.action;\n return { ...r, action: rest };\n });\n const ordered = resolved\n .map((r, index) => ({ r, index }))\n .sort((a, b) => {\n const ca = CATEGORY_ORDER.indexOf(a.r.action.category);\n const cb = CATEGORY_ORDER.indexOf(b.r.action.category);\n if (ca !== cb) return ca - cb;\n const oa = a.r.action.order ?? 0;\n const ob = b.r.action.order ?? 0;\n if (oa !== ob) return oa - ob;\n return a.index - b.index;\n })\n .map((x) => x.r);\n\n const sections = new Map<string, MenuSection>();\n const roles: Record<string, string> = {};\n // An explicit section sits in the group of its first-registered action and\n // keeps its own row order (order, then registration) across categories.\n const explicit = new Map<string, { group: MenuGroup; rows: { r: ResolvedAction; index: number }[] }>();\n resolved.forEach((r, index) => {\n const sec = r.action.section;\n if (!sec) return;\n const entry = explicit.get(sec.id) ?? { group: CATEGORY_GROUP[r.action.category], rows: [] };\n entry.rows.push({ r, index });\n explicit.set(sec.id, entry);\n });\n const placed = new Set<string>();\n for (const r of ordered) {\n const sec = r.action.section;\n if (sec && placed.has(sec.id)) continue;\n const group = sec ? (explicit.get(sec.id)?.group ?? CATEGORY_GROUP[r.action.category]) : CATEGORY_GROUP[r.action.category];\n const sectionId = sec ? `section:${sec.id}` : group;\n let section = sections.get(sectionId);\n if (!section) {\n section = {\n id: sectionId,\n group,\n nodes: [],\n ...(sec ? { label: translate(options.i18n, sec.labelKey ?? `section.${sec.id}`, sec.label) } : {}),\n ...(sec?.icon !== undefined ? { icon: sec.icon } : {}),\n ...(sec?.primary ? { primary: true } : {}),\n ...(sec && (sec.kind ?? (sec.primary ? \"target\" : \"group\")) === \"target\" ? { target: true } : {}),\n };\n sections.set(sectionId, section);\n }\n const rows = sec\n ? (explicit.get(sec.id)?.rows ?? [])\n .sort((x, y) => (x.r.action.order ?? 0) - (y.r.action.order ?? 0) || x.index - y.index)\n .map((x) => x.r)\n : [r];\n if (sec) placed.add(sec.id);\n for (const row of rows) {\n if (row.action.startsGroup && section.nodes.length > 0) {\n section.nodes.push({ kind: \"separator\", id: `${row.action.id}:group` });\n }\n section.nodes.push(actionToNode(row, target, options));\n if (row.action.verb) roles[row.action.verb] = row.action.id;\n }\n }\n\n const list = [...sections.values()].sort((a, b) => {\n if (Boolean(a.primary) !== Boolean(b.primary)) return a.primary ? -1 : 1;\n return GROUP_ORDER.indexOf(a.group) - GROUP_ORDER.indexOf(b.group);\n });\n\n const selected = target.selection?.text?.trim();\n const content = options.content?.trim();\n const fieldName = options.contentLabel?.trim();\n const header = selected\n ? { label: \"Selected\", text: target.selection?.text ?? \"\" }\n : fieldName\n ? { label: fieldName, text: options.content ?? \"\" }\n : content\n ? { label: \"Content\", text: options.content ?? \"\" }\n : null;\n\n return { header, sections: list, roles };\n}\n\n/** Fill a lazy submenu's rows once they load (pure: returns a new model). */\n/**\n * AN EXPANDED SUBMENU KEEPS ITS GROUPS (DATA-V2-BASICS-2, 2026-09-28). A provider's rows arrive flat,\n * so a submenu drew \"Highlight row\" and \"Delete row…\" as neighbours with no divider, while the same\n * rows in a top-level menu sit in their sections. A divider now goes wherever the rows' `section`\n * changes — a row with no section and a row with one are different groups too.\n */\nexport function withGroupDividers(children: readonly Action[], nodes: readonly MenuNode[]): MenuNode[] {\n const out: MenuNode[] = [];\n children.forEach((child, i) => {\n const node = nodes[i];\n if (!node) return;\n if (i > 0 && (child.startsGroup || (children[i - 1]!.section?.id ?? null) !== (child.section?.id ?? null))) {\n out.push({ kind: \"separator\", id: `${child.id}:group` });\n }\n out.push(node);\n });\n return out;\n}\n\nexport function withExpandedChildren(model: MenuModel, nodeId: string, children: MenuNode[] | \"loading\"): MenuModel {\n const visit = (nodes: MenuNode[]): MenuNode[] =>\n nodes.map((n) => {\n if (n.kind !== \"submenu\") return n;\n if (n.id === nodeId) {\n return children === \"loading\" ? { ...n, loading: true } : { ...n, lazy: false, loading: false, pending: false, children };\n }\n return { ...n, children: visit(n.children) };\n });\n return { ...model, sections: model.sections.map((s) => ({ ...s, nodes: visit(s.nodes) })) };\n}\n\n/** Find a node anywhere in a tree. */\nexport function findNode(nodes: readonly MenuNode[], id: string): MenuNode | null {\n for (const n of nodes) {\n if (n.id === id) return n;\n if (n.kind === \"submenu\") {\n const hit = findNode(n.children, id);\n if (hit) return hit;\n }\n }\n return null;\n}\n","/**\n * The shared React context (T0-safe: imports only React and types). Shared\n * through globalThis so every per-layout bundle reads the same provider.\n */\nimport * as React from \"react\";\nimport type { ActionRegistry } from \"../actions/types\";\nimport type { AlchemyHostPorts } from \"../ports\";\n\nexport interface AlchemyActionsValue {\n registry: ActionRegistry;\n ports: AlchemyHostPorts;\n}\n\nconst KEY = Symbol.for(\"ai-matrx.alchemy.actions-context\");\ntype Holder = { [KEY]?: React.Context<AlchemyActionsValue | null> };\nexport const AlchemyActionsContext: React.Context<AlchemyActionsValue | null> =\n ((globalThis as Holder)[KEY] ??= React.createContext<AlchemyActionsValue | null>(null));\n\nexport function useAlchemyActions(): AlchemyActionsValue {\n const value = React.useContext(AlchemyActionsContext);\n if (!value) throw new Error(\"Alchemy actions: render inside <AlchemyActionsProvider> (@ai-matrx/alchemy/react/host).\");\n return value;\n}\n\n/**\n * The registry + ports when rendered inside `<AlchemyActionsProvider>`, else null. For callers that\n * must never crash a render outside the host (a kind component, an assist chip, a bare test render):\n * they answer honestly (\"actions aren't available here\") instead of throwing.\n */\nexport function useOptionalAlchemyActions(): AlchemyActionsValue | null {\n return React.useContext(AlchemyActionsContext);\n}\n","/**\n * The completion of an expansion belongs to both the target that started it\n * and that node's most recent request. Either identity changing makes a late\n * result stale.\n */\nexport function isLatestExpansion(\n capturedTargetEpoch: number,\n currentTargetEpoch: number,\n capturedNodeSequence: number,\n currentNodeSequence: number | undefined,\n): boolean {\n return capturedTargetEpoch === currentTargetEpoch && capturedNodeSequence === currentNodeSequence;\n}\n","\"use client\";\n/**\n * Drawing model nodes inside a Radix dropdown (menu / overflow / bar / selection).\n * Pure presentation: every choice goes back to the engine by node id.\n */\nimport * as React from \"react\";\nimport {\n DropdownMenuCheckboxItem,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"@ai-matrx/design-system\";\nimport type { MenuEngine } from \"./engine\";\nimport { MENU_SIZE_CLASSES, useMenuSize } from \"./menu-size\";\nimport { sectionLabel } from \"../menu/layouts\";\nimport type { MenuLeafNode, MenuNode, MenuSection } from \"../menu/types\";\n\nexport function NodeList({ nodes, engine }: { nodes: readonly MenuNode[]; engine: MenuEngine }): React.ReactElement {\n return (\n <>\n {nodes.map((node) => (\n <MenuNodeView key={node.id} node={node} engine={engine} />\n ))}\n </>\n );\n}\n\nexport function SectionList({\n sections,\n engine,\n}: {\n sections: readonly MenuSection[];\n engine: MenuEngine;\n}): React.ReactElement {\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n return (\n <>\n {sections.map((section, index) => (\n <React.Fragment key={section.id}>\n {index > 0 ? <DropdownMenuSeparator /> : null}\n {sectionLabel(section) ? (\n <DropdownMenuLabel className={`${size.label} font-medium text-muted-foreground`}>{sectionLabel(section)}</DropdownMenuLabel>\n ) : null}\n <NodeList nodes={section.nodes} engine={engine} />\n </React.Fragment>\n ))}\n </>\n );\n}\n\n/**\n * A toggle's ON state must be a real visual signal, never just its tooltip\n * text — an inactive thumbs-up rendered in the same green as an active one\n * lies about being rated (RC-B11). Two ways a registered action shows it,\n * and both are honored here, in the ONE place every layout draws a glyph:\n *\n * 1. A distinct glyph for the active state (`stateIcon`, e.g. pin-message\n * swaps Pin -> PinOff while pinned, tts-play swaps Volume2 -> Pause).\n * The glyph change IS the signal, so its tone is untouched here —\n * exactly the pre-existing behavior for every action that already\n * draws one.\n * 2. A single glyph with an accent tone (`iconTone`) that has no natural\n * \"undo\" icon (thumbs up/down, star, favorite) — nothing but the tone\n * can carry the state, so it is withheld while the action is an\n * explicit, currently-off toggle (`pressed === false`): the glyph\n * falls back to the bar's ordinary muted color, and lights up in its\n * registered tone only once `pressed` is true.\n *\n * `pressed === undefined` (not a toggle at all — copy, export, run…) keeps\n * its tone unconditionally, exactly as before.\n */\nfunction iconOf(node: MenuNode, engine: MenuEngine): React.ReactNode {\n if (node.kind !== \"item\") {\n if (!(\"icon\" in node)) return null;\n return engine.icon(node.icon);\n }\n if (node.stateIcon) {\n const glyph = engine.icon(node.stateIcon.icon);\n return node.stateIcon.spin ? <span className=\"inline-flex animate-spin\">{glyph}</span> : glyph;\n }\n if (!(\"icon\" in node)) return null;\n const tone = node.pressed === false ? undefined : node.iconTone;\n return engine.icon(node.icon, tone);\n}\n\nexport function MenuNodeView({ node, engine }: { node: MenuNode; engine: MenuEngine }): React.ReactElement | null {\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n switch (node.kind) {\n case \"separator\":\n return <DropdownMenuSeparator />;\n case \"label\":\n return <DropdownMenuLabel className={`${size.label} font-medium text-muted-foreground`}>{node.label}</DropdownMenuLabel>;\n case \"submenu\":\n return <SubmenuView node={node} engine={engine} />;\n case \"checkbox\":\n return (\n <DropdownMenuCheckboxItem\n data-alchemy-node={node.id}\n checked={node.checked}\n onSelect={() => void engine.run(node.id)}\n className={size.row}\n >\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n </DropdownMenuCheckboxItem>\n );\n case \"link\":\n return (\n <DropdownMenuItem asChild data-alchemy-node={node.id}>\n <a href={node.href} target={node.target} className={size.row}>\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n </a>\n </DropdownMenuItem>\n );\n case \"item\":\n return <LeafItem node={node} engine={engine} />;\n }\n}\n\n/**\n * A SUBMENU NEVER CLOSES BECAUSE ITS PARENT PANEL TOOK FOCUS (PB-04, /notes, 2026-10-02: at a\n * 1024 px viewport AI Actions ▸ Text Operations ▸ Text Tools closed under the pointer).\n *\n * Radix keeps a submenu open while the pointer leaves its trigger only when the pointer's last\n * horizontal move inside the parent panel points at the side the submenu is drawn on. A narrow\n * viewport FLIPS the submenu to the left; a pointer that last moved right (or jumped) and heads for\n * it is \"not moving to the submenu\", so Radix focuses the parent PANEL itself, the submenu reads\n * that as focus outside and closes, and the click meant for it lands on the page and closes the\n * whole menu. Focus on the parent panel (role=\"menu\", the panel that holds this trigger) means\n * only \"the pointer left a row without entering another one\" — that never closes a submenu, on\n * either side. Focus on another ROW (a sibling hovered or arrowed to) still closes it, as before.\n */\nfunction SubmenuView({ node, engine }: { node: Extract<MenuNode, { kind: \"submenu\" }>; engine: MenuEngine }): React.ReactElement {\n const triggerRef = React.useRef<HTMLDivElement>(null);\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n return (\n <DropdownMenuSub\n onOpenChange={(open) => {\n if (open && node.lazy && !node.loading) void engine.expand(node.id);\n }}\n >\n <DropdownMenuSubTrigger ref={triggerRef} data-alchemy-node={node.id} className={size.row} aria-busy={node.pending ? true : undefined}>\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n {node.pending ? <span className=\"ml-auto text-xs text-muted-foreground\">Loading…</span> : null}\n </DropdownMenuSubTrigger>\n {/* As wide as the menu it opens from: a row's long reason is cut short on one line (the\n whole of it is the row's tooltip), never a 727 px panel across the grid (review 2). */}\n <DropdownMenuSubContent\n data-alchemy-submenu={node.id}\n onFocusOutside={(event) => {\n const to = event.target;\n const trigger = triggerRef.current;\n if (to instanceof Element && trigger && to.getAttribute(\"role\") === \"menu\" && to.contains(trigger)) event.preventDefault();\n }}\n className={`${size.panel} max-w-[calc(100vw-1rem)] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto`}\n >\n {node.loading ? (\n <DropdownMenuLabel className=\"text-xs text-muted-foreground\">Loading…</DropdownMenuLabel>\n ) : node.children.length === 0 && !node.lazy ? (\n <DropdownMenuLabel className=\"text-xs text-muted-foreground\">{node.emptyLabel ?? \"Nothing here yet\"}</DropdownMenuLabel>\n ) : (\n <NodeList nodes={node.children} engine={engine} />\n )}\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n );\n}\n\nfunction LeafItem({ node, engine }: { node: Extract<MenuLeafNode, { kind: \"item\" }>; engine: MenuEngine }): React.ReactElement {\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n const row = (\n <DropdownMenuItem\n data-alchemy-node={node.id}\n aria-disabled={node.unavailable ? true : undefined}\n aria-pressed={node.pressed}\n onSelect={(event) => {\n if (node.unavailable) {\n event.preventDefault();\n return;\n }\n // An in-place reload (Retry) keeps the menu and this submenu open: Radix closes on every\n // select unless it is prevented (a-retry-row-keeps-its-menu-open.test.tsx).\n if (node.keepsMenuOpen) event.preventDefault();\n void engine.run(node.id);\n }}\n className={`${size.row} ${node.unavailable ? \"opacity-50\" : \"\"} ${node.destructive ? \"text-destructive\" : \"\"}`}\n >\n {iconOf(node, engine)}\n <span className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"truncate\">{node.label}</span>\n {node.description ? <span className=\"truncate text-xs text-muted-foreground\">{node.description}</span> : null}\n </span>\n {node.hint ? <span className={`ml-auto ${size.hint} text-muted-foreground`}>{node.hint}</span> : null}\n </DropdownMenuItem>\n );\n if (!node.unavailable) return row;\n return (\n <Tooltip>\n <TooltipTrigger asChild>{row}</TooltipTrigger>\n <TooltipContent>{node.unavailable.sentence}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** An icon button for a strip / bar leaf (greyed verb carries its sentence). */\nexport function LeafButton({\n node,\n engine,\n showLabel,\n}: {\n node: MenuNode;\n engine: MenuEngine;\n showLabel: boolean;\n}): React.ReactElement | null {\n if (node.kind !== \"item\" && node.kind !== \"checkbox\" && node.kind !== \"link\") return null;\n const unavailable = node.kind === \"item\" ? node.unavailable : undefined;\n const pressed = node.kind === \"item\" ? node.pressed : node.kind === \"checkbox\" ? node.checked : undefined;\n const glyph = iconOf(node, engine);\n const size = MENU_SIZE_CLASSES[useMenuSize()];\n const destructive = node.kind === \"item\" && node.destructive;\n const button = (\n <button\n type=\"button\"\n data-alchemy-node={node.id}\n // THE BUTTON TOUCH FLOOR (design-system styles.css): 44px on coarse\n // pointers, desktop density unchanged.\n data-matrx-button=\"\"\n data-tap-floor=\"\"\n data-tap-floor-square=\"\"\n aria-label={node.label}\n aria-disabled={unavailable ? true : undefined}\n aria-pressed={pressed}\n onMouseDown={(e) => {\n if (node.kind === \"item\" && node.preserveSelection) e.preventDefault();\n }}\n onClick={() => {\n if (unavailable) {\n engine.explain(unavailable.sentence);\n return;\n }\n if (node.kind === \"link\") {\n window.location.assign(node.href);\n return;\n }\n void engine.run(node.id);\n }}\n className={`inline-flex ${size.stripButton} pointer-coarse:h-11 pointer-coarse:min-w-11 shrink-0 items-center justify-center gap-1.5 rounded-md text-sm ${destructive ? \"text-destructive hover:bg-destructive/10\" : \"text-muted-foreground hover:bg-accent hover:text-foreground\"} ${\n unavailable ? \"cursor-default opacity-50 hover:bg-transparent\" : \"\"\n } ${pressed ? \"text-foreground\" : \"\"}`}\n >\n {glyph}\n {showLabel || !glyph ? <span className=\"whitespace-nowrap\">{node.label}</span> : null}\n </button>\n );\n return (\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent>{unavailable ? unavailable.sentence : node.label}</TooltipContent>\n </Tooltip>\n );\n}\n","\"use client\";\n/**\n * Menu size — \"standard\" (the original 288 px menu) or \"large\": the Google Docs / Sheets class of\n * menu for a feature-heavy app (Arman, 2026-10-02: \"our menu is too small… the one place where we\n * have essentially unlimited space, we're suddenly cheap about it\"). Measured on Google Sheets:\n * 322 px wide, 32 px rows, 14 px text, 18 px icons. Large goes one step past it: 360 px, 36 px rows,\n * 15 px text. A context, so submenus (portalled) draw at the same size as the menu they open from.\n */\nimport * as React from \"react\";\n\nexport type MenuSize = \"standard\" | \"large\";\n\nexport const MenuSizeContext = React.createContext<MenuSize>(\"standard\");\n\nexport function useMenuSize(): MenuSize {\n return React.useContext(MenuSizeContext);\n}\n\nexport const MENU_SIZE_CLASSES: Record<\n MenuSize,\n { panel: string; row: string; strip: string; stripButton: string; label: string; filter: string; hint: string }\n> = {\n standard: {\n panel: \"w-72\",\n row: \"gap-2\",\n strip: \"flex items-center gap-0.5 px-1 py-1\",\n stripButton: \"h-7 min-w-7 px-1.5\",\n label: \"text-xs\",\n filter: \"h-7 text-sm\",\n hint: \"text-xs\",\n },\n large: {\n panel: \"w-[22.5rem] [&_svg]:size-[18px]\",\n row: \"gap-3 min-h-9 px-3 text-[15px]\",\n strip: \"flex items-center justify-between gap-1 px-2 py-1.5\",\n stripButton: \"h-9 min-w-9 px-2\",\n label: \"text-[13px]\",\n filter: \"h-9 text-[15px]\",\n hint: \"text-[13px]\",\n },\n};\n"],"mappings":";y5BAAA,8HCKA,IAAAA,OAAuB,4BACvBC,sBAAwF,mCC6BjF,SAAS,aAAa,QAAqC,CAChE,OAAO,QAAQ,OAAS,IAC1B,CAoDA,SAAS,KAAK,QAA2D,CACvE,MAAO,CACL,KAAM,UACN,GAAI,GAAG,QAAQ,EAAE,QACjB,MAAO,QAAQ,MACf,GAAI,QAAQ,OAAS,OAAY,CAAE,KAAM,QAAQ,IAAK,EAAI,CAAC,EAC3D,SAAU,QAAQ,KACpB,CACF,CAEA,SAAS,SAAS,MAAoC,CACpD,OAAO,MAAM,OAAQ,GAAM,EAAE,OAAS,aAAe,EAAE,OAAS,OAAO,EAAE,MAC3E,CAYA,SAAS,YAAY,KAAiD,CACpE,MAAO,cAAe,MAAQ,KAAK,UAAY,KAAK,UAAY,UAClE,CAiFA,SAAS,UAAU,SAAiD,CAClE,OAAO,SAAS,IAAK,GACnB,EAAE,OAAS,CAAC,EAAE,SAAW,SAAS,EAAE,KAAK,EAAI,EAAqB,CAAE,GAAI,EAAE,GAAI,MAAO,EAAE,MAAO,MAAO,CAAC,KAAK,CAAE,GAAG,EAAG,MAAO,EAAE,KAAM,CAAC,CAAC,CAAE,EAAI,CAC5I,CACF,CAYO,SAAS,IAAI,MAAkB,SAA+B,CAAC,EAAgB,CACpF,IAAM,QAAsB,CAAC,EACvB,iBAAkC,CAAC,EACzC,QAAW,KAAK,MAAM,SAAU,CAC9B,IAAM,KAAmB,CAAC,EAC1B,QAAW,KAAK,EAAE,MAAO,CACvB,GAAI,EAAE,OAAS,aAAe,EAAE,OAAS,QAAS,CAChD,KAAK,KAAK,CAAC,EACX,QACF,CACA,IAAM,EAAI,YAAY,CAAC,GACnB,IAAM,WAAa,IAAM,SAAQ,QAAQ,KAAK,CAAC,GAC/C,IAAM,YAAc,IAAM,SAAQ,KAAK,KAAK,CAAC,CACnD,CACI,SAAS,IAAI,EAAI,GAAG,iBAAiB,KAAK,CAAE,GAAG,EAAG,MAAO,IAAK,CAAC,CACrE,CACA,MAAO,CAAE,QAAS,SAAU,UAAU,gBAAgB,CAAE,CAC1D,CC3NA,IAAAC,OAAuB,4BCHhB,IAAM,oBAAmC,OAAO,OAAO,CAC5D,WAAY,GACZ,eAAgB,WAChB,kBAAmB,EACrB,CAAC,EAEM,SAAS,mBAAmB,MAAwD,CACzF,MAAO,CACL,WAAY,MAAM,aAAa,YAAc,oBAAoB,WACjE,eAAgB,MAAM,aAAa,gBAAkB,oBAAoB,eACzE,kBAAmB,MAAM,aAAa,mBAAqB,oBAAoB,iBACjF,CACF,CCEA,SAAS,OAAO,MAAkC,CAChD,GAAI,UAAU,QAAa,OAAO,OAAU,YAAc,OAAO,OAAU,UAC3E,IAAI,QAAU,MAAQ,OAAO,OAAU,UAAY,OAAO,OAAU,UAAW,OAAO,MACtF,GAAI,OAAO,OAAU,SAAU,OAAO,OAAO,SAAS,KAAK,EAAI,MAAQ,KACvE,GAAI,OAAO,OAAU,SAAU,OAAO,MAAM,SAAS,EACrD,GAAI,iBAAiB,KAAM,OAAO,MAAM,YAAY,EACpD,GAAI,MAAM,QAAQ,KAAK,EAAG,OAAO,MAAM,IAAK,GAAM,OAAO,CAAC,GAAK,IAAI,EACnE,GAAI,OAAO,OAAU,SAAU,CAC7B,IAAM,IAA+B,CAAC,EACtC,OAAW,CAAC,EAAG,CAAC,IAAK,OAAO,QAAQ,KAAgC,EAAG,CACrE,IAAM,EAAI,OAAO,CAAC,EACd,IAAM,SAAW,IAAI,CAAC,EAAI,EAChC,CACA,OAAO,GACT,EAEF,CAGO,SAAS,cACd,IACA,SACA,WAAa,GACgD,CAC7D,IAAM,OAAS,IAAI,IAAI,SAAS,IAAK,GAAM,CAAC,EAAE,KAAM,CAAC,CAAC,CAAC,EACjD,OAA+B,CAAC,EAChC,UAA4B,CAAC,EACnC,OAAW,CAAC,KAAM,KAAK,IAAK,OAAO,QAAQ,GAAG,EAAG,CAC/C,IAAM,KAAO,WAAa,GAAG,UAAU,IAAI,IAAI,GAAK,KAC9C,KAAO,OAAO,IAAI,IAAI,EAC5B,GAAI,CAAC,KAAM,CACT,UAAU,KAAK,CAAE,KAAM,OAAQ,UAAW,CAAC,EAC3C,QACF,CACA,IAAM,YAAc,mBAAmB,IAAI,EAC3C,GAAI,YAAY,iBAAmB,WAAY,CAC7C,UAAU,KAAK,CAAE,KAAM,OAAQ,WAAY,eAAgB,YAAY,cAAe,CAAC,EACvF,QACF,CACA,GAAI,CAAC,YAAY,WAAY,CAC3B,UAAU,KAAK,CAAE,KAAM,OAAQ,UAAW,CAAC,EAC3C,QACF,CACA,IAAM,KAAO,OAAO,KAAK,EACrB,OAAS,SACb,OAAO,IAAI,EAAI,KACjB,CACA,MAAO,CAAE,OAAQ,SAAU,CAC7B,CAEO,SAAS,qBAAqB,OAA0C,CAC7E,MAAO,CACL,MAAM,OAAO,OAAQ,CACnB,GAAI,CAAC,OAAO,SAAW,CAAC,OAAO,YAAa,MAAO,CAAE,OAAQ,CAAC,EAAG,UAAW,CAAC,CAAE,EAC/E,IAAM,IAAM,MAAM,OAAO,QAAQ,WAAW,MAAM,EAC5C,aAAe,OAAO,YAAY,OACxC,OAAO,cAAc,IAAK,YAAY,CACxC,EACA,MAAM,KAAK,OAAQ,CACjB,IAAM,KAAO,OAAO,KACpB,GAAI,CAAC,MAAQ,CAAC,OAAO,YAAa,OAAO,KACzC,IAAM,KAAO,OAAO,YAAY,WAAW,KAAM,GAAM,EAAE,OAAS,KAAK,QAAQ,EAC/E,GAAI,CAAC,KAAM,MAAO,CAAE,OAAQ,CAAC,EAAG,UAAW,CAAC,CAAE,KAAM,KAAK,SAAU,OAAQ,UAAW,CAAC,CAAE,EACzF,IAAM,IAAM,MAAM,KAAK,WAAW,MAAM,EACxC,OAAO,cAAc,IAAK,KAAK,OAAQ,KAAK,QAAQ,CACtD,EACA,MAAM,KAAK,OAA6B,CACtC,OAAK,OAAO,SAAS,SACd,OAAO,QAAQ,SAAS,MAAM,EADC,CAAC,CAEzC,CACF,CACF,CCrEA,eAAsB,UAAU,OAAgB,OAAqB,QAA+C,CAClH,GAAM,CAAE,KAAM,EAAI,QAClB,GAAI,OAAO,cAAgB,CAAC,OAAO,KAAK,cACtC,OAAK,MAAM,MAQX,MAAM,KAAK,iBAAiB,CAAE,SAAU,OAAO,GAAI,mBAAoB,QAAQ,oBAAsB,OAAO,EAAG,CAAC,EACzG,CAAE,OAAQ,cAAe,IAP9B,MAAM,YAAY,QAAQ,IAAI,MAAM,wBAAwB,OAAO,EAAE,oCAAoC,EAAG,CAC1G,KAAM,UACN,OAAQ,CAAE,SAAU,OAAO,EAAG,CAChC,CAAC,EACM,CAAE,OAAQ,SAAU,MAAO,IAAI,MAAM,qBAAqB,CAAE,GAKvE,IAAM,MAAQ,qBAAqB,QAAQ,QAAU,CAAE,QAAS,KAAM,YAAa,OAAO,YAAa,KAAM,IAAK,CAAC,EAC7G,OAAS,QAAQ,QAAU,IAAI,gBAAgB,EAAE,OACvD,GAAI,CAEF,MAAO,CAAE,OAAQ,MAAO,QADR,MAAM,OAAO,IAAI,OAAQ,CAAE,MAAO,MAAO,MAAO,CAAC,CACjC,CAClC,OAAS,MAAO,CACd,MAAM,YAAY,QAAQ,MAAO,CAAE,KAAM,UAAW,OAAQ,CAAE,SAAU,OAAO,GAAI,MAAO,KAAM,CAAE,CAAC,EACnG,IAAM,MAAQ,OAAO,OAAO,OAAU,SAAW,OAAO,MAAQ,OAAO,GACvE,aAAM,QAAQ,MAAM,GAAG,KAAK,mBAAoB,qEAAqE,EAC9G,CAAE,OAAQ,SAAU,KAAM,CACnC,CACF,CC5BO,IAAM,kBAAyC,IAAI,IAAI,CAC5D,OACA,UACA,SACA,OACA,gBACA,QACA,MACA,UACA,SACF,CAAC,EAIK,eACJ,oIAGI,aAAe,wDAEd,SAAS,gBAAgB,MAAwB,CACtD,OAAO,eAAe,KAAK,MAAM,KAAK,CAAC,CACzC,CAKO,SAAS,kBAAkB,MAAe,KAAoB,QAAS,SAAgC,kBAA4B,CACxI,IAAM,EAAI,MAAM,KAAK,EACrB,MAAI,CAAC,GAAK,gBAAgB,CAAC,EAAU,GACjC,SAAS,IAAI,CAAC,EAAU,GACrB,OAAS,UAAY,aAAa,KAAK,CAAC,CACjD,CAKO,SAAS,sBAAsC,CAEpD,OADa,WAA0E,SAAS,KAAK,WACtF,aAAe,SAAW,OAC3C,CAEO,IAAM,uBAAN,cAAqC,KAAM,CACvC,QACT,YAAY,QAAiB,MAAe,CAC1C,MACE,iBAAiB,OAAO,MAAM,KAAK,qSAGrC,EACA,KAAK,KAAO,yBACZ,KAAK,QAAU,OACjB,CACF,EC9DO,IAAM,eAA8D,CACzE,UAAW,YACX,KAAM,WACN,OAAQ,WACR,KAAM,WACN,MAAO,WACP,KAAM,WACN,QAAS,UACT,GAAI,KACJ,IAAK,KACL,OAAQ,QACR,MAAO,QACP,IAAK,QACL,OAAQ,QACR,SAAU,QACV,QAAS,QACT,MAAO,QACP,eAAgB,cAClB,EAGa,YAAoC,CAC/C,YACA,WACA,WACA,WACA,UACA,KACA,QACA,QACA,UACA,QACA,cACF,EAEM,eAA4C,CAChD,YACA,OACA,OACA,SACA,OACA,QACA,UACA,MACA,KACA,SACA,QACA,MACA,SACA,WACA,UACA,QACA,cACF,EAeA,SAAS,UAAU,KAA4B,IAAa,SAA0B,CACpF,GAAI,CAAC,KAAM,OAAO,SAClB,GAAI,CACF,OAAO,KAAK,EAAE,IAAK,QAAQ,CAC7B,MAAQ,CACN,OAAO,QACT,CACF,CAGO,SAAS,aACd,SACA,OACA,QAAiC,CAAC,EACxB,CACV,GAAM,CAAE,OAAQ,WAAY,EAAI,SAC1B,SAAW,OAAO,OAAO,OAAU,WAAa,OAAO,MAAM,MAAM,EAAI,OAAO,MAC9E,MAAQ,UAAU,QAAQ,KAAM,OAAO,UAAY,OAAO,GAAI,QAAQ,EACtE,KAAO,CACX,GAAI,OAAO,GACX,SAAU,OAAO,GACjB,GAAI,OAAO,OAAS,OAAY,CAAE,KAAM,OAAO,IAAK,EAAI,CAAC,EACzD,GAAI,OAAO,YAAc,OAAY,CAAE,UAAW,OAAO,SAAU,EAAI,CAAC,CAC1E,EACA,GAAI,OAAO,OAWT,MAV8B,CAC5B,GAAG,KACH,KAAM,UACN,MACA,KAAM,GACN,QAAS,GACT,GAAI,OAAO,UAAU,MAAM,EAAI,CAAE,QAAS,EAAK,EAAI,CAAC,EACpD,SAAU,CAAC,EACX,GAAI,OAAO,aAAe,OAAY,CAAE,WAAY,OAAO,UAAW,EAAI,CAAC,CAC7E,EAGF,GAAI,OAAO,OAAS,OAAW,CAC7B,IAAM,KAAO,OAAO,OAAO,MAAS,WAAa,OAAO,KAAK,MAAM,EAAI,OAAO,KAC9E,MAAO,CAAE,GAAG,KAAM,KAAM,OAAQ,MAAO,IAAK,CAC9C,CACA,GAAI,OAAO,OACT,MAAO,CACL,GAAG,KACH,KAAM,WACN,MACA,QAAS,OAAO,UAAU,MAAM,GAAK,GACrC,GAAI,OAAO,cAAgB,OAAY,CAAE,YAAa,OAAO,WAAY,EAAI,CAAC,CAChF,EAEF,IAAM,MAAQ,OAAO,YAAY,MAAM,GAAK,KACtC,QAAU,OAAO,UAAU,MAAM,EACjC,KAAO,OAAO,OAAS,OAAY,UAAU,QAAQ,KAAM,OAAO,SAAW,GAAG,OAAO,EAAE,QAAS,OAAO,IAAI,EAAI,OACvH,MAAO,CACL,GAAG,KACH,KAAM,OACN,MACA,GAAI,OAAO,WAAa,OAAY,CAAE,SAAU,OAAO,QAAS,EAAI,CAAC,EACrE,GAAI,MAAQ,CAAE,UAAW,KAAM,EAAI,CAAC,EACpC,GAAI,OAAO,cAAgB,OAAY,CAAE,YAAa,OAAO,WAAY,EAAI,CAAC,EAC9E,GAAI,OAAS,OAAY,CAAE,IAAK,EAAI,CAAC,EACrC,GAAI,UAAY,OAAY,CAAE,OAAQ,EAAI,CAAC,EAC3C,GAAI,OAAO,YAAc,CAAE,YAAa,EAAK,EAAI,CAAC,EAClD,GAAI,OAAO,kBAAoB,CAAE,kBAAmB,EAAK,EAAI,CAAC,EAC9D,GAAI,OAAO,cAAgB,CAAE,cAAe,EAAK,EAAI,CAAC,EACtD,GAAI,YAAY,SAAW,oBAAsB,YAAY,SAAW,cACpE,CAAE,YAAa,CAAE,SAAU,YAAY,QAAS,CAAE,EAClD,CAAC,CACP,CACF,CAEO,SAAS,eACd,OACA,SACA,QAAiC,CAAC,EACvB,CAGX,IAAM,OAAS,QAAQ,eAAiB,qBAAqB,EAC7D,SAAW,SAAS,IAAK,GAAM,CAC7B,IAAM,IAAM,EAAE,OAAO,QACrB,GAAI,EAAE,OAAO,QAAU,gBAAgB,OAAO,EAAE,OAAO,OAAU,SAAW,EAAE,OAAO,MAAQ,EAAE,GAAK,SAAW,QAC7G,MAAM,IAAI,uBAAuB,EAAE,OAAO,MAAiB,cAAc,EAAE,OAAO,EAAE,EAAE,EAExF,GAAI,CAAC,IAAK,OAAO,EACjB,IAAM,KAAO,IAAI,OAAS,IAAI,QAAU,SAAW,SACnD,GAAI,kBAAkB,IAAI,MAAO,IAAI,EAAG,OAAO,EAC/C,GAAI,SAAW,QAAS,MAAM,IAAI,uBAAuB,IAAI,MAAO,cAAc,EAAE,OAAO,EAAE,EAAE,EAC/F,GAAM,CAAE,QAAS,SAAU,GAAG,IAAK,EAAI,EAAE,OACzC,MAAO,CAAE,GAAG,EAAG,OAAQ,IAAK,CAC9B,CAAC,EACD,IAAM,QAAU,SACb,IAAI,CAAC,EAAG,SAAW,CAAE,EAAG,KAAM,EAAE,EAChC,KAAK,CAAC,EAAG,IAAM,CACd,IAAM,GAAK,eAAe,QAAQ,EAAE,EAAE,OAAO,QAAQ,EAC/C,GAAK,eAAe,QAAQ,EAAE,EAAE,OAAO,QAAQ,EACrD,GAAI,KAAO,GAAI,OAAO,GAAK,GAC3B,IAAM,GAAK,EAAE,EAAE,OAAO,OAAS,EACzB,GAAK,EAAE,EAAE,OAAO,OAAS,EAC/B,OAAI,KAAO,GAAW,GAAK,GACpB,EAAE,MAAQ,EAAE,KACrB,CAAC,EACA,IAAK,GAAM,EAAE,CAAC,EAEX,SAAW,IAAI,IACf,MAAgC,CAAC,EAGjC,SAAW,IAAI,IACrB,SAAS,QAAQ,CAAC,EAAG,QAAU,CAC7B,IAAM,IAAM,EAAE,OAAO,QACrB,GAAI,CAAC,IAAK,OACV,IAAM,MAAQ,SAAS,IAAI,IAAI,EAAE,GAAK,CAAE,MAAO,eAAe,EAAE,OAAO,QAAQ,EAAG,KAAM,CAAC,CAAE,EAC3F,MAAM,KAAK,KAAK,CAAE,EAAG,KAAM,CAAC,EAC5B,SAAS,IAAI,IAAI,GAAI,KAAK,CAC5B,CAAC,EACD,IAAM,OAAS,IAAI,IACnB,QAAW,KAAK,QAAS,CACvB,IAAM,IAAM,EAAE,OAAO,QACrB,GAAI,KAAO,OAAO,IAAI,IAAI,EAAE,EAAG,SAC/B,IAAM,MAAQ,IAAO,SAAS,IAAI,IAAI,EAAE,GAAG,OAAS,eAAe,EAAE,OAAO,QAAQ,EAAK,eAAe,EAAE,OAAO,QAAQ,EACnH,UAAY,IAAM,WAAW,IAAI,EAAE,GAAK,MAC1C,QAAU,SAAS,IAAI,SAAS,EAC/B,UACH,QAAU,CACR,GAAI,UACJ,MACA,MAAO,CAAC,EACR,GAAI,IAAM,CAAE,MAAO,UAAU,QAAQ,KAAM,IAAI,UAAY,WAAW,IAAI,EAAE,GAAI,IAAI,KAAK,CAAE,EAAI,CAAC,EAChG,GAAI,KAAK,OAAS,OAAY,CAAE,KAAM,IAAI,IAAK,EAAI,CAAC,EACpD,GAAI,KAAK,QAAU,CAAE,QAAS,EAAK,EAAI,CAAC,EACxC,GAAI,MAAQ,IAAI,OAAS,IAAI,QAAU,SAAW,YAAc,SAAW,CAAE,OAAQ,EAAK,EAAI,CAAC,CACjG,EACA,SAAS,IAAI,UAAW,OAAO,GAEjC,IAAM,KAAO,KACR,SAAS,IAAI,IAAI,EAAE,GAAG,MAAQ,CAAC,GAC7B,KAAK,CAAC,EAAG,KAAO,EAAE,EAAE,OAAO,OAAS,IAAM,EAAE,EAAE,OAAO,OAAS,IAAM,EAAE,MAAQ,EAAE,KAAK,EACrF,IAAK,GAAM,EAAE,CAAC,EACjB,CAAC,CAAC,EACF,KAAK,OAAO,IAAI,IAAI,EAAE,EAC1B,QAAW,OAAO,KACZ,IAAI,OAAO,aAAe,QAAQ,MAAM,OAAS,GACnD,QAAQ,MAAM,KAAK,CAAE,KAAM,YAAa,GAAI,GAAG,IAAI,OAAO,EAAE,QAAS,CAAC,EAExE,QAAQ,MAAM,KAAK,aAAa,IAAK,OAAQ,OAAO,CAAC,EACjD,IAAI,OAAO,OAAM,MAAM,IAAI,OAAO,IAAI,EAAI,IAAI,OAAO,GAE7D,CAEA,IAAM,KAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE,KAAK,CAAC,EAAG,IACvC,EAAQ,EAAE,SAAa,EAAQ,EAAE,QAAiB,EAAE,QAAU,GAAK,EAChE,YAAY,QAAQ,EAAE,KAAK,EAAI,YAAY,QAAQ,EAAE,KAAK,CAClE,EAEK,SAAW,OAAO,WAAW,MAAM,KAAK,EACxC,QAAU,QAAQ,SAAS,KAAK,EAChC,UAAY,QAAQ,cAAc,KAAK,EAS7C,MAAO,CAAE,OARM,SACX,CAAE,MAAO,WAAY,KAAM,OAAO,WAAW,MAAQ,EAAG,EACxD,UACE,CAAE,MAAO,UAAW,KAAM,QAAQ,SAAW,EAAG,EAChD,QACE,CAAE,MAAO,UAAW,KAAM,QAAQ,SAAW,EAAG,EAChD,KAES,SAAU,KAAM,KAAM,CACzC,CASO,SAAS,kBAAkB,SAA6B,MAAwC,CACrG,IAAM,IAAkB,CAAC,EACzB,gBAAS,QAAQ,CAAC,MAAO,IAAM,CAC7B,IAAM,KAAO,MAAM,CAAC,EACf,OACD,EAAI,IAAM,MAAM,cAAgB,SAAS,EAAI,CAAC,EAAG,SAAS,IAAM,SAAW,MAAM,SAAS,IAAM,QAClG,IAAI,KAAK,CAAE,KAAM,YAAa,GAAI,GAAG,MAAM,EAAE,QAAS,CAAC,EAEzD,IAAI,KAAK,IAAI,EACf,CAAC,EACM,GACT,CAEO,SAAS,qBAAqB,MAAkB,OAAgB,SAA6C,CAClH,IAAM,MAAS,OACb,MAAM,IAAK,GACL,EAAE,OAAS,UAAkB,EAC7B,EAAE,KAAO,OACJ,WAAa,UAAY,CAAE,GAAG,EAAG,QAAS,EAAK,EAAI,CAAE,GAAG,EAAG,KAAM,GAAO,QAAS,GAAO,QAAS,GAAO,QAAS,EAEnH,CAAE,GAAG,EAAG,SAAU,MAAM,EAAE,QAAQ,CAAE,CAC5C,EACH,MAAO,CAAE,GAAG,MAAO,SAAU,MAAM,SAAS,IAAK,IAAO,CAAE,GAAG,EAAG,MAAO,MAAM,EAAE,KAAK,CAAE,EAAE,CAAE,CAC5F,CAGO,SAAS,SAAS,MAA4B,GAA6B,CAChF,QAAW,KAAK,MAAO,CACrB,GAAI,EAAE,KAAO,GAAI,OAAO,EACxB,GAAI,EAAE,OAAS,UAAW,CACxB,IAAM,IAAM,SAAS,EAAE,SAAU,EAAE,EACnC,GAAI,IAAK,OAAO,GAClB,CACF,CACA,OAAO,IACT,CC9RA,UAAuB,4BASjB,IAAM,OAAO,IAAI,kCAAkC,EAE5C,sBACT,WAAsB,GAAG,IAAY,oBAA0C,IAAI,EAEhF,SAAS,mBAAyC,CACvD,IAAM,MAAc,iBAAW,qBAAqB,EACpD,GAAI,CAAC,MAAO,MAAM,IAAI,MAAM,yFAAyF,EACrH,OAAO,KACT,CCjBO,SAAS,kBACd,oBACA,mBACA,qBACA,oBACS,CACT,OAAO,sBAAwB,oBAAsB,uBAAyB,mBAChF,CP8NwB,oDArLxB,SAAS,YAAY,MAAkB,GAA6B,CAClE,QAAW,KAAK,MAAM,SAAU,CAC9B,IAAM,IAAM,SAAS,EAAE,MAAO,EAAE,EAChC,GAAI,IAAK,OAAO,GAClB,CACA,OAAO,IACT,CAEA,SAAS,cAAc,MAAkB,GAAqB,CAC5D,IAAM,EAAI,YAAY,MAAO,EAAE,EAC/B,MAAO,GAAQ,GAAK,EAAE,OAAS,WAAa,CAAC,EAAE,MAAQ,CAAC,EAAE,QAC5D,CAEA,SAAS,eAAe,MAAkB,GAAiC,CACzE,IAAM,EAAI,YAAY,MAAO,EAAE,EAC/B,OAAO,GAAK,EAAE,OAAS,WAAa,CAAC,EAAE,KAAO,EAAE,SAAW,CAAC,CAC9D,CAMO,SAAS,YAAY,KAA2B,KAAkB,OAAyC,CAChH,OAAO,KAAK,IAAK,GAAM,CACrB,GAAI,EAAE,OAAS,UAAW,OAAO,EACjC,IAAM,IAAM,KAAK,KAAM,GAAM,EAAE,KAAO,EAAE,EAAE,EAC1C,MAAI,CAAC,KAAO,IAAI,OAAS,WAAa,IAAI,KAAa,EACnD,EAAE,KACG,OAAO,IAAI,EAAE,EAAE,EAAI,CAAE,GAAG,EAAG,KAAM,GAAO,QAAS,GAAO,QAAS,GAAO,SAAU,IAAI,QAAS,EAAI,EAErG,CAAE,GAAG,EAAG,SAAU,YAAY,IAAI,SAAU,EAAE,SAAU,MAAM,CAAE,CACzE,CAAC,CACH,CAEA,SAAS,iBAAiB,KAAiB,KAAiB,OAAwC,CAClG,GAAI,OAAO,OAAS,EAAG,OAAO,KAC9B,IAAM,UAAY,KAAK,SAAS,QAAS,GAAM,EAAE,KAAK,EACtD,MAAO,CAAE,GAAG,KAAM,SAAU,KAAK,SAAS,IAAK,IAAO,CAAE,GAAG,EAAG,MAAO,YAAY,UAAW,EAAE,MAAO,MAAM,CAAE,EAAE,CAAE,CACnH,CAEO,SAAS,cAAc,OAA4B,QAA6B,CAAC,EAAe,CACrG,GAAM,CAAE,SAAU,KAAM,EAAI,kBAAkB,EACxC,CAAC,SAAU,WAAW,EAAU,gBAAoC,CAAC,CAAC,EACtE,CAAC,MAAO,QAAQ,EAAU,gBAA2B,IAAI,EACzD,CAAC,KAAM,OAAO,EAAU,gBAAS,CAAC,EAElC,SAAiB,cAAO,IAAI,GAAqB,EAIjD,OAAe,cAAO,IAAI,GAAa,EACvC,UAAkB,cAAO,IAAI,GAAqB,EAClD,YAAoB,cAAO,CAAC,EAC5B,cAAsB,cAAO,MAAM,EACrC,cAAc,UAAY,SAC5B,cAAc,QAAU,OACxB,YAAY,SAAW,GAEzB,IAAM,OAAS,QAAQ,QAAU,GAC3B,WAAmB,cAAO,OAAO,EACvC,WAAW,QAAU,QAEf,iBAAU,IAAM,SAAS,UAAU,IAAM,QAAS,GAAM,EAAI,CAAC,CAAC,EAAG,CAAC,QAAQ,CAAC,EAEjF,IAAM,aAAqB,mBACzB,MAAO,OAAgB,SAAmB,CACxC,GAAI,CAAC,QAAU,CAAC,OAAO,OAAQ,OAC/B,IAAM,MAAQ,YAAY,QACpB,KAAO,UAAU,QAAQ,IAAI,MAAM,GAAK,GAAK,EACnD,UAAU,QAAQ,IAAI,OAAQ,GAAG,EACjC,IAAM,OAAS,IAAM,kBAAkB,MAAO,YAAY,QAAS,IAAK,UAAU,QAAQ,IAAI,MAAM,CAAC,EAIrG,SAAU,GAAO,GAAK,CAAC,cAAc,EAAG,MAAM,EAAI,qBAAqB,EAAG,OAAQ,SAAS,EAAI,CAAE,EACjG,GAAI,CAEF,IAAM,UAAY,MAAM,OAAO,OAAO,OAAQ,IAAI,gBAAgB,EAAE,MAAM,GAAG,OAC1E,OAAU,CAAC,MAAM,UAAY,MAAM,SAAS,SAAS,MAAM,CAC9D,EACA,GAAI,CAAC,OAAO,EAAG,OACf,IAAM,MAAoB,kBACxB,SACA,SAAS,IAAK,QACZ,SAAS,QAAQ,IAAI,MAAM,GAAI,KAAK,EAC7B,aAAa,CAAE,OAAQ,MAAO,YAAa,CAAE,OAAQ,WAAY,CAAE,EAAG,OAAQ,MAAM,KAAO,CAAE,KAAM,MAAM,IAAK,EAAI,CAAC,CAAC,EAC5H,CACH,EACA,SAAU,GAAO,GAAI,qBAAqB,EAAG,OAAQ,YAAY,eAAe,EAAG,MAAM,EAAG,MAAO,OAAO,OAAO,CAAC,CAAM,EAExH,QAAW,SAAS,SAAc,MAAM,QAAU,OAAO,QAAQ,IAAI,MAAM,EAAE,GAAQ,aAAa,MAAO,MAAM,EAAE,CACnH,OAAS,MAAO,CACd,GAAI,CAAC,OAAO,EAAG,OACf,MAAM,YAAY,QAAQ,MAAO,CAAE,KAAM,OAAQ,OAAQ,CAAE,OAAQ,MAAO,QAAS,CAAE,CAAC,EACtF,SAAU,GAAO,GAAI,qBAAqB,EAAG,OAAQ,CAAC,CAAC,CAAM,CAC/D,CACF,EACA,CAAC,OAAQ,KAAK,CAChB,EAEM,iBAAU,IAAM,CACpB,SAAS,QAAQ,MAAM,EACvB,OAAO,QAAQ,MAAM,CACvB,EAAG,CAAC,MAAM,CAAC,EAEL,iBAAU,IAAM,CACpB,GAAI,CAAC,QAAU,CAAC,OAAQ,OACxB,IAAI,KAAO,GACX,OAAK,SAAS,QAAQ,OAAQ,WAAW,QAAQ,QAAQ,EAAE,KAAM,MAAS,CACxE,GAAI,CAAC,KAAM,OACX,YAAY,IAAI,EAChB,IAAM,MAAQ,eAAe,OAAQ,KAAM,CAAE,GAAI,MAAM,KAAO,CAAE,KAAM,MAAM,IAAK,EAAI,CAAC,EAAI,QAAS,WAAW,QAAQ,SAAW,KAAM,aAAc,WAAW,QAAQ,cAAgB,IAAK,CAAC,EAC9L,SAAU,MAAU,KAAO,iBAAiB,KAAM,MAAO,OAAO,OAAO,EAAI,KAAM,EACjF,OAAW,CAAE,MAAO,IAAK,KACnB,OAAO,QAAQ,IAAI,OAAO,EAAE,GAAK,OAAO,QAAa,aAAa,OAAQ,OAAO,EAAE,CAE3F,CAAC,EACM,IAAM,CACX,KAAO,EACT,CACF,EAAG,CAAC,SAAU,MAAO,OAAQ,OAAQ,KAAM,QAAQ,SAAU,YAAY,CAAC,EAO1E,IAAM,YAAoB,cAAO,QAAQ,EACzC,YAAY,QAAU,SACtB,IAAM,cAAgB,SAAS,IAAK,GAAM,EAAE,OAAO,EAAE,EAAE,KAAK;AAAA,CAAI,EAC1D,iBAAU,IAAM,CACpB,GAAI,CAAC,OAAQ,OACb,IAAI,YAAc,GACZ,SAAW,IAAM,CAChB,aAAa,QAAS,GAAM,EAAI,CAAC,CACxC,EACM,KAAO,YAAY,QACtB,IAAK,GAAM,EAAE,OAAO,YAAY,SAAU,MAAM,CAAC,EACjD,OAAQ,KAA2B,OAAO,KAAQ,UAAU,EAC/D,mBAAc,GACP,IAAM,KAAK,QAAS,KAAQ,IAAI,CAAC,CAC1C,EAAG,CAAC,cAAe,MAAM,CAAC,EAE1B,IAAM,WAAmB,mBACtB,IAAmC,SAAS,KAAM,GAAM,EAAE,OAAO,KAAO,EAAE,GAAG,QAAU,SAAS,QAAQ,IAAI,EAAE,GAAK,OACpH,CAAC,QAAQ,CACX,EAEM,IAAY,mBAChB,MAAO,QAAmB,CACxB,GAAI,CAAC,QAAU,CAAC,MAAO,OAAO,KAC9B,IAAM,KAAO,MAAM,SAAS,IAAK,GAAM,SAAS,EAAE,MAAO,MAAM,CAAC,EAAE,KAAK,OAAO,GAAK,KAC7E,OAAS,WAAW,MAAQ,aAAc,MAAQ,KAAK,SAAW,KAAK,SAAW,MAAM,EAC9F,GAAI,CAAC,OAAQ,OAAO,KACpB,IAAM,EAAI,WAAW,QACf,OAAS,MAAM,UAAU,OAAQ,OAAQ,CAC7C,MACA,GAAI,EAAE,OAAS,CAAE,OAAQ,EAAE,MAAO,EAAI,CAAC,EACvC,GAAI,EAAE,mBAAqB,CAAE,mBAAoB,EAAE,kBAAmB,EAAI,CAAC,CAC7E,CAAC,EACD,SAAE,QAAQ,OAAQ,OAAQ,CAAE,SAAU,EAAQ,OAAO,aAAe,CAAC,EAC9D,MACT,EACA,CAAC,OAAQ,MAAO,WAAY,KAAK,CACnC,EAEM,OAAe,mBACnB,MAAO,QAAmB,CACxB,IAAM,OAAS,WAAW,MAAM,EAC5B,CAAC,QAAU,CAAC,QAAQ,SAExB,OAAO,QAAQ,IAAI,MAAM,EACzB,MAAM,aAAa,OAAQ,MAAM,EACnC,EACA,CAAC,WAAY,OAAQ,YAAY,CACnC,EAEM,KAAa,mBACjB,CAAC,IAAyB,OAAmC,CAC3D,GAAI,CAAC,KAAO,CAAC,MAAM,MAAO,OAAO,KACjC,IAAM,SAAW,MAAM,MAAM,QAAQ,GAAG,EACxC,OAAO,YAAW,wBAAC,UAAS,UAAW,oBAAoB,MAAQ,EAAE,GAAI,cAAW,GAAC,EAAK,IAC5F,EACA,CAAC,MAAM,KAAK,CACd,EAEM,QAAgB,mBACnB,UAAqB,CAChB,MAAM,OAAQ,MAAM,OAAO,KAAK,QAAQ,EACvC,MAAM,YAAY,QAAQ,IAAI,MAAM,8BAA8B,QAAQ,EAAE,EAAG,CAAE,KAAM,OAAQ,OAAQ,CAAE,QAAS,CAAE,CAAC,CAC5H,EACA,CAAC,KAAK,CACR,EAEA,MAAO,CAAE,MAAO,SAAU,IAAK,OAAQ,KAAM,OAAQ,CACvD,CQnPA,IAAAC,OAAuB,4BACvB,qBAWO,mCCTP,IAAAC,OAAuB,4BAIV,gBAAwB,qBAAwB,UAAU,EAEhE,SAAS,aAAwB,CACtC,OAAa,kBAAW,eAAe,CACzC,CAEO,IAAM,kBAGT,CACF,SAAU,CACR,MAAO,OACP,IAAK,QACL,MAAO,sCACP,YAAa,qBACb,MAAO,UACP,OAAQ,cACR,KAAM,SACR,EACA,MAAO,CACL,MAAO,kCACP,IAAK,iCACL,MAAO,sDACP,YAAa,mBACb,MAAO,cACP,OAAQ,kBACR,KAAM,aACR,CACF,EDfI,IAAAC,oBAAA,6BAFG,SAAS,SAAS,CAAE,MAAO,MAAO,EAA2E,CAClH,SACE,uDACG,eAAM,IAAK,SACV,yBAAC,cAA2B,KAAY,QAArB,KAAK,EAAgC,CACzD,EACH,CAEJ,CAEO,SAAS,YAAY,CAC1B,SACA,MACF,EAGuB,CACrB,IAAM,KAAO,kBAAkB,YAAY,CAAC,EAC5C,SACE,uDACG,kBAAS,IAAI,CAAC,QAAS,WACtB,0BAAO,gBAAN,CACE,gBAAQ,KAAI,yBAAC,6CAAsB,EAAK,KACxC,aAAa,OAAO,KACnB,yBAAC,wCAAkB,UAAW,GAAG,KAAK,KAAK,qCAAuC,sBAAa,OAAO,EAAE,EACtG,QACJ,yBAAC,UAAS,MAAO,QAAQ,MAAO,OAAgB,IAL7B,QAAQ,EAM7B,CACD,EACH,CAEJ,CAuBA,SAAS,OAAO,KAAgB,OAAqC,CACnE,GAAI,KAAK,OAAS,OAChB,MAAM,SAAU,KACT,OAAO,KAAK,KAAK,IAAI,EADE,KAGhC,GAAI,KAAK,UAAW,CAClB,IAAM,MAAQ,OAAO,KAAK,KAAK,UAAU,IAAI,EAC7C,OAAO,KAAK,UAAU,QAAO,yBAAC,QAAK,UAAU,2BAA4B,eAAM,EAAU,KAC3F,CACA,GAAI,EAAE,SAAU,MAAO,OAAO,KAC9B,IAAM,KAAO,KAAK,UAAY,GAAQ,OAAY,KAAK,SACvD,OAAO,OAAO,KAAK,KAAK,KAAM,IAAI,CACpC,CAEO,SAAS,aAAa,CAAE,KAAM,MAAO,EAAsE,CAChH,IAAM,KAAO,kBAAkB,YAAY,CAAC,EAC5C,OAAQ,KAAK,KAAM,CACjB,IAAK,YACH,SAAO,yBAAC,6CAAsB,EAChC,IAAK,QACH,SAAO,yBAAC,wCAAkB,UAAW,GAAG,KAAK,KAAK,qCAAuC,cAAK,MAAM,EACtG,IAAK,UACH,SAAO,yBAAC,aAAY,KAAY,OAAgB,EAClD,IAAK,WACH,SACE,0BAAC,+CACC,oBAAmB,KAAK,GACxB,QAAS,KAAK,QACd,SAAU,IAAG,CAAQ,OAAO,IAAI,KAAK,EAAE,GACvC,UAAW,KAAK,IAEf,iBAAO,KAAM,MAAM,KACpB,yBAAC,QAAK,UAAU,WAAY,cAAK,MAAM,GACzC,EAEJ,IAAK,OACH,SACE,yBAAC,uCAAiB,QAAO,GAAC,oBAAmB,KAAK,GAChD,sCAAC,KAAE,KAAM,KAAK,KAAM,OAAQ,KAAK,OAAQ,UAAW,KAAK,IACtD,iBAAO,KAAM,MAAM,KACpB,yBAAC,QAAK,UAAU,WAAY,cAAK,MAAM,GACzC,EACF,EAEJ,IAAK,OACH,SAAO,yBAAC,UAAS,KAAY,OAAgB,CACjD,CACF,CAeA,SAAS,YAAY,CAAE,KAAM,MAAO,EAA6F,CAC/H,IAAM,WAAmB,cAAuB,IAAI,EAC9C,KAAO,kBAAkB,YAAY,CAAC,EAC5C,SACE,0BAAC,sCACC,aAAe,MAAS,CAClB,MAAQ,KAAK,MAAQ,CAAC,KAAK,SAAc,OAAO,OAAO,KAAK,EAAE,CACpE,EAEA,uCAAC,6CAAuB,IAAK,WAAY,oBAAmB,KAAK,GAAI,UAAW,KAAK,IAAK,YAAW,KAAK,QAAU,GAAO,OACxH,iBAAO,KAAM,MAAM,KACpB,yBAAC,QAAK,UAAU,WAAY,cAAK,MAAM,EACtC,KAAK,WAAU,yBAAC,QAAK,UAAU,wCAAwC,yBAAQ,EAAU,MAC5F,KAGA,yBAAC,6CACC,uBAAsB,KAAK,GAC3B,eAAiB,OAAU,CACzB,IAAM,GAAK,MAAM,OACX,QAAU,WAAW,QACvB,cAAc,SAAW,SAAW,GAAG,aAAa,MAAM,IAAM,QAAU,GAAG,SAAS,OAAO,GAAG,MAAM,eAAe,CAC3H,EACA,UAAW,GAAG,KAAK,KAAK,wGAEvB,cAAK,WACJ,yBAAC,wCAAkB,UAAU,gCAAgC,yBAAQ,EACnE,KAAK,SAAS,SAAW,GAAK,CAAC,KAAK,QACtC,yBAAC,wCAAkB,UAAU,gCAAiC,cAAK,YAAc,mBAAmB,KAEpG,yBAAC,UAAS,MAAO,KAAK,SAAU,OAAgB,EAEpD,GACF,CAEJ,CAEA,SAAS,SAAS,CAAE,KAAM,MAAO,EAA8F,CAC7H,IAAM,KAAO,kBAAkB,YAAY,CAAC,EACtC,OACJ,0BAAC,uCACC,oBAAmB,KAAK,GACxB,gBAAe,KAAK,YAAc,GAAO,OACzC,eAAc,KAAK,QACnB,SAAW,OAAU,CACnB,GAAI,KAAK,YAAa,CACpB,MAAM,eAAe,EACrB,MACF,CAGI,KAAK,eAAe,MAAM,eAAe,EACxC,OAAO,IAAI,KAAK,EAAE,CACzB,EACA,UAAW,GAAG,KAAK,GAAG,IAAI,KAAK,YAAc,aAAe,EAAE,IAAI,KAAK,YAAc,mBAAqB,EAAE,GAE3G,iBAAO,KAAM,MAAM,KACpB,0BAAC,QAAK,UAAU,+BACd,sCAAC,QAAK,UAAU,WAAY,cAAK,MAAM,EACtC,KAAK,eAAc,yBAAC,QAAK,UAAU,yCAA0C,cAAK,YAAY,EAAU,MAC3G,EACC,KAAK,QAAO,yBAAC,QAAK,UAAW,WAAW,KAAK,IAAI,yBAA2B,cAAK,KAAK,EAAU,MACnG,EAEF,OAAK,KAAK,eAER,0BAAC,8BACC,sCAAC,qCAAe,QAAO,GAAE,aAAI,KAC7B,yBAAC,qCAAgB,cAAK,YAAY,SAAS,GAC7C,EAL4B,GAOhC,CAGO,SAAS,WAAW,CACzB,KACA,OACA,SACF,EAI8B,CAC5B,GAAI,KAAK,OAAS,QAAU,KAAK,OAAS,YAAc,KAAK,OAAS,OAAQ,OAAO,KACrF,IAAM,YAAc,KAAK,OAAS,OAAS,KAAK,YAAc,OACxD,QAAU,KAAK,OAAS,OAAS,KAAK,QAAU,KAAK,OAAS,WAAa,KAAK,QAAU,OAC1F,MAAQ,OAAO,KAAM,MAAM,EAC3B,KAAO,kBAAkB,YAAY,CAAC,EACtC,YAAc,KAAK,OAAS,QAAU,KAAK,YAC3C,UACJ,0BAAC,UACC,KAAK,SACL,oBAAmB,KAAK,GAGxB,oBAAkB,GAClB,iBAAe,GACf,wBAAsB,GACtB,aAAY,KAAK,MACjB,gBAAe,YAAc,GAAO,OACpC,eAAc,QACd,YAAc,GAAM,CACd,KAAK,OAAS,QAAU,KAAK,mBAAmB,EAAE,eAAe,CACvE,EACA,QAAS,IAAM,CACb,GAAI,YAAa,CACf,OAAO,QAAQ,YAAY,QAAQ,EACnC,MACF,CACA,GAAI,KAAK,OAAS,OAAQ,CACxB,OAAO,SAAS,OAAO,KAAK,IAAI,EAChC,MACF,CACK,OAAO,IAAI,KAAK,EAAE,CACzB,EACA,UAAW,eAAe,KAAK,WAAW,gHAAgH,YAAc,2CAA6C,6DAA6D,IAChR,YAAc,iDAAmD,EACnE,IAAI,QAAU,kBAAoB,EAAE,GAEnC,gBACA,WAAa,CAAC,SAAQ,yBAAC,QAAK,UAAU,oBAAqB,cAAK,MAAM,EAAU,MACnF,EAEF,SACE,0BAAC,8BACC,sCAAC,qCAAe,QAAO,GAAE,gBAAO,KAChC,yBAAC,qCAAgB,qBAAc,YAAY,SAAW,KAAK,MAAM,GACnE,CAEJ,CVnOI,IAAAC,oBAAA,6BAZJ,SAAS,SAAS,MAAwB,CACxC,OAAI,OAAO,OAAW,IAAoB,GACnC,OAAO,aAAa,eAAe,MAAQ,CAAC,KAAK,EAAE,SAAW,EACvE,CAIA,IAAM,cACJ,sLAEF,SAAS,eAAe,CAAE,KAAM,MAAO,EAAsE,CAC3G,SACE,0BAAC,oCACC,aAAe,MAAS,CAClB,MAAQ,KAAK,MAAQ,CAAC,KAAK,SAAc,OAAO,OAAO,KAAK,EAAE,CACpE,EAEA,sCAAC,2CAAoB,QAAO,GAC1B,qCAAC,UAAO,KAAK,SAAS,aAAY,KAAK,MAAO,oBAAmB,KAAK,GAAI,UAAW,cAClF,gBAAO,KAAK,KAAK,IAAI,MAAK,yBAAC,QAAK,UAAU,UAAW,cAAK,MAAM,EACnE,EACF,KACA,yBAAC,2CAAoB,MAAM,QAAQ,UAAU,mFAC1C,cAAK,WAAU,yBAAC,OAAI,UAAU,4CAA4C,yBAAQ,KAAS,yBAAC,UAAS,MAAO,KAAK,SAAU,OAAgB,EAC9I,GACF,CAEJ,CAEO,SAAS,UAAU,CACxB,OACA,KAAO,GACP,UACA,aAAe,GACf,WAAa,IACb,UAAY,IAAM,OAAO,+BAA+B,EACxD,GAAG,OACL,EAA8C,CAC5C,IAAM,OAAS,cAAc,OAAQ,OAAO,EACtC,CAAC,UAAW,YAAY,EAAU,gBAAS,EAAK,EAChD,CAAC,MAAO,QAAQ,EAAU,gBAAyE,IAAI,EAC7G,GAAI,CAAC,OAAO,MAAO,OAAO,KAC1B,IAAM,SAAW,IAAI,OAAO,MAAO,CAAE,IAAK,CAAC,EAC3C,OAAI,SAAS,QAAQ,SAAW,GAAK,SAAS,SAAS,SAAW,EAAU,QAE1E,yBAAC,uCACC,sCAAC,OACC,KAAK,UACL,aAAW,UACX,sBAAoB,MACpB,UAAW,qBAAqB,KAAO,QAAU,SAAS,IAAI,WAAa,EAAE,GAE5E,mBAAS,QAAQ,IAAK,MACrB,KAAK,OAAS,aACZ,yBAAC,gBAA6B,KAAY,QAArB,KAAK,EAAgC,KAE1D,yBAAC,YAAyB,KAAY,OAAgB,UAAW,IAAhD,KAAK,EAAkD,CAE5E,EACC,cAAgB,SAAS,SAAS,SAAW,EAAI,KAAO,SAAS,UAAU,KAC1E,wDACE,sCAAC,UACC,KAAK,SACL,aAAW,eACX,uBAAqB,WACrB,UAAW,cACX,QAAS,IAAM,CACb,aAAa,EAAI,EACZ,OAAY,UAAU,EAAE,KAAM,GAAM,SAAS,IAAM,EAAE,WAAW,CAAC,CACxE,EAEA,qCAAC,QAAK,cAAW,GAAC,UAAU,yBAAyB,kBAAC,EACxD,EACC,SAAQ,yBAAC,OAAO,GAAG,QAAS,OAAgB,KAAM,UAAW,aAAc,aAAc,EAAK,MACjG,KAEA,0BAAC,oCACC,sCAAC,2CAAoB,QAAO,GAC1B,qCAAC,UAAO,KAAK,SAAS,aAAW,eAAe,uBAAqB,WAAW,UAAW,cACzF,qCAAC,QAAK,cAAW,GAAC,UAAU,yBAAyB,kBAAC,EACxD,EACF,KACA,yBAAC,2CAAoB,MAAM,MAAM,UAAU,mFACzC,qCAAC,aAAY,SAAU,SAAS,SAAU,OAAgB,EAC5D,GACF,GAEJ,EACF,CAEJ","names":["React","import_design_system","React","React","React","import_jsx_runtime","import_jsx_runtime"]}
|
package/dist/react-bar.d.cts
CHANGED
package/dist/react-bar.d.ts
CHANGED