@ai-matrx/alchemy 0.8.1 → 0.8.3
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 +21 -0
- package/dist/menu.cjs +8 -21
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.d.cts +7 -1
- package/dist/menu.d.ts +7 -1
- package/dist/menu.js +8 -21
- package/dist/menu.js.map +1 -1
- package/dist/react-bar.cjs +22 -23
- package/dist/react-bar.cjs.map +1 -1
- package/dist/react-bar.js +22 -23
- package/dist/react-bar.js.map +1 -1
- package/dist/react-host.cjs +5 -4
- package/dist/react-host.cjs.map +1 -1
- package/dist/react-host.d.cts +7 -1
- package/dist/react-host.d.ts +7 -1
- package/dist/react-host.js +5 -4
- package/dist/react-host.js.map +1 -1
- package/dist/react-menu.cjs +27 -25
- package/dist/react-menu.cjs.map +1 -1
- package/dist/react-menu.js +27 -25
- package/dist/react-menu.js.map +1 -1
- package/dist/react-overflow.cjs +22 -23
- package/dist/react-overflow.cjs.map +1 -1
- package/dist/react-overflow.d.cts +2 -1
- package/dist/react-overflow.d.ts +2 -1
- package/dist/react-overflow.js +22 -23
- package/dist/react-overflow.js.map +1 -1
- package/dist/react-palette.cjs +13 -21
- package/dist/react-palette.cjs.map +1 -1
- package/dist/react-palette.js +13 -21
- package/dist/react-palette.js.map +1 -1
- package/dist/react-selection.cjs +20 -21
- package/dist/react-selection.cjs.map +1 -1
- package/dist/react-selection.js +20 -21
- package/dist/react-selection.js.map +1 -1
- package/dist/react-sheet.cjs +17 -24
- package/dist/react-sheet.cjs.map +1 -1
- package/dist/react-sheet.js +17 -24
- package/dist/react-sheet.js.map +1 -1
- package/package.json +3 -3
package/dist/react-menu.js
CHANGED
|
@@ -14,21 +14,8 @@ import {
|
|
|
14
14
|
|
|
15
15
|
// src/menu/layouts.ts
|
|
16
16
|
var INLINE_SECTION_MAX = 3;
|
|
17
|
-
var GROUP_LABEL = {
|
|
18
|
-
clipboard: "Clipboard",
|
|
19
|
-
tools: "Tools",
|
|
20
|
-
history: "History",
|
|
21
|
-
document: "Save & share",
|
|
22
|
-
surface: "This page",
|
|
23
|
-
ai: "AI",
|
|
24
|
-
quick: "Feedback",
|
|
25
|
-
editable: "Edit",
|
|
26
|
-
admin: "Admin",
|
|
27
|
-
"surface-info": "About this page",
|
|
28
|
-
transfer: "Copy & export"
|
|
29
|
-
};
|
|
30
17
|
function sectionLabel(section) {
|
|
31
|
-
return section.label ??
|
|
18
|
+
return section.label ?? null;
|
|
32
19
|
}
|
|
33
20
|
function isLeaf(node) {
|
|
34
21
|
return node.kind === "item" || node.kind === "checkbox" || node.kind === "link";
|
|
@@ -37,7 +24,7 @@ function fold(section) {
|
|
|
37
24
|
return {
|
|
38
25
|
kind: "submenu",
|
|
39
26
|
id: `${section.id}:fold`,
|
|
40
|
-
label:
|
|
27
|
+
label: section.label,
|
|
41
28
|
...section.icon !== void 0 ? { icon: section.icon } : {},
|
|
42
29
|
children: section.nodes
|
|
43
30
|
};
|
|
@@ -70,7 +57,7 @@ function tiered(model, filterable) {
|
|
|
70
57
|
sections.push(s);
|
|
71
58
|
continue;
|
|
72
59
|
}
|
|
73
|
-
if (s.group === "surface-info" || rowCount(s.nodes) <= INLINE_SECTION_MAX) {
|
|
60
|
+
if (!s.label || s.group === "surface-info" || rowCount(s.nodes) <= INLINE_SECTION_MAX) {
|
|
74
61
|
if (hierarchical) sections.push(s);
|
|
75
62
|
else {
|
|
76
63
|
const { label: _label, ...unlabelled } = s;
|
|
@@ -78,7 +65,7 @@ function tiered(model, filterable) {
|
|
|
78
65
|
}
|
|
79
66
|
continue;
|
|
80
67
|
}
|
|
81
|
-
sections.push({ id: s.id, group: s.group, nodes: [fold(s)] });
|
|
68
|
+
sections.push({ id: s.id, group: s.group, nodes: [fold({ ...s, label: s.label })] });
|
|
82
69
|
}
|
|
83
70
|
return { strip, sections, filterable };
|
|
84
71
|
}
|
|
@@ -97,7 +84,7 @@ function palette(model) {
|
|
|
97
84
|
}
|
|
98
85
|
}
|
|
99
86
|
};
|
|
100
|
-
for (const s of model.sections) walk(s.nodes, [
|
|
87
|
+
for (const s of model.sections) walk(s.nodes, s.label ? [s.label] : []);
|
|
101
88
|
return { leaves };
|
|
102
89
|
}
|
|
103
90
|
function filterPalette(arranged, query) {
|
|
@@ -442,11 +429,19 @@ function useMenuEngine(target, options = {}) {
|
|
|
442
429
|
live = false;
|
|
443
430
|
};
|
|
444
431
|
}, [registry, ports, target, active, tick, options.revision]);
|
|
432
|
+
const resolvedRef = React2.useRef(resolved);
|
|
433
|
+
resolvedRef.current = resolved;
|
|
434
|
+
const subscribedIds = resolved.map((r) => r.action.id).join("\n");
|
|
445
435
|
React2.useEffect(() => {
|
|
446
436
|
if (!target) return;
|
|
447
|
-
|
|
437
|
+
let subscribing = true;
|
|
438
|
+
const onChange = () => {
|
|
439
|
+
if (!subscribing) setTick((t) => t + 1);
|
|
440
|
+
};
|
|
441
|
+
const offs = resolvedRef.current.map((r) => r.action.subscribe?.(onChange, target)).filter((off) => typeof off === "function");
|
|
442
|
+
subscribing = false;
|
|
448
443
|
return () => offs.forEach((off) => off());
|
|
449
|
-
}, [
|
|
444
|
+
}, [subscribedIds, target]);
|
|
450
445
|
const findAction = React2.useCallback(
|
|
451
446
|
(id) => resolved.find((r) => r.action.id === id)?.action ?? expanded.current.get(id),
|
|
452
447
|
[resolved]
|
|
@@ -488,10 +483,10 @@ function useMenuEngine(target, options = {}) {
|
|
|
488
483
|
[findAction, target, ports]
|
|
489
484
|
);
|
|
490
485
|
const icon = React2.useCallback(
|
|
491
|
-
(key) => {
|
|
486
|
+
(key, tone) => {
|
|
492
487
|
if (!key || !ports.icons) return null;
|
|
493
488
|
const Resolved = ports.icons.resolve(key);
|
|
494
|
-
return Resolved ? /* @__PURE__ */ jsx(Resolved, { className:
|
|
489
|
+
return Resolved ? /* @__PURE__ */ jsx(Resolved, { className: `h-4 w-4 shrink-0 ${tone ?? ""}`, "aria-hidden": true }) : null;
|
|
495
490
|
},
|
|
496
491
|
[ports.icons]
|
|
497
492
|
);
|
|
@@ -522,7 +517,7 @@ function SectionList({
|
|
|
522
517
|
}) {
|
|
523
518
|
return /* @__PURE__ */ jsx2(Fragment2, { children: sections.map((section, index) => /* @__PURE__ */ jsxs(React3.Fragment, { children: [
|
|
524
519
|
index > 0 ? /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}) : null,
|
|
525
|
-
section
|
|
520
|
+
sectionLabel(section) ? /* @__PURE__ */ jsx2(DropdownMenuLabel, { className: "text-xs font-medium text-muted-foreground", children: sectionLabel(section) }) : null,
|
|
526
521
|
/* @__PURE__ */ jsx2(NodeList, { nodes: section.nodes, engine })
|
|
527
522
|
] }, section.id)) });
|
|
528
523
|
}
|
|
@@ -531,7 +526,8 @@ function iconOf(node, engine) {
|
|
|
531
526
|
const glyph = engine.icon(node.stateIcon.icon);
|
|
532
527
|
return node.stateIcon.spin ? /* @__PURE__ */ jsx2("span", { className: "inline-flex animate-spin", children: glyph }) : glyph;
|
|
533
528
|
}
|
|
534
|
-
|
|
529
|
+
if (!("icon" in node)) return null;
|
|
530
|
+
return engine.icon(node.icon, node.kind === "item" ? node.iconTone : void 0);
|
|
535
531
|
}
|
|
536
532
|
function MenuNodeView({ node, engine }) {
|
|
537
533
|
switch (node.kind) {
|
|
@@ -595,7 +591,10 @@ function LeafItem({ node, engine }) {
|
|
|
595
591
|
className: `gap-2 ${node.unavailable ? "opacity-50" : ""} ${node.destructive ? "text-destructive" : ""}`,
|
|
596
592
|
children: [
|
|
597
593
|
iconOf(node, engine),
|
|
598
|
-
/* @__PURE__ */
|
|
594
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
595
|
+
/* @__PURE__ */ jsx2("span", { className: "truncate", children: node.label }),
|
|
596
|
+
node.description ? /* @__PURE__ */ jsx2("span", { className: "truncate text-xs text-muted-foreground", children: node.description }) : null
|
|
597
|
+
] }),
|
|
599
598
|
node.hint ? /* @__PURE__ */ jsx2("span", { className: "ml-auto text-xs text-muted-foreground", children: node.hint }) : null
|
|
600
599
|
]
|
|
601
600
|
}
|
|
@@ -672,6 +671,9 @@ function ContextMenuPanel({
|
|
|
672
671
|
{
|
|
673
672
|
align: "start",
|
|
674
673
|
"data-alchemy-layout": `context-${arrangement}`,
|
|
674
|
+
onPointerUpCapture: (event) => {
|
|
675
|
+
if (event.button === 2) event.preventDefault();
|
|
676
|
+
},
|
|
675
677
|
className: `w-72 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto ${density === "compact" ? "text-xs" : ""}`,
|
|
676
678
|
children: /* @__PURE__ */ jsxs2(TooltipProvider, { children: [
|
|
677
679
|
engine.model?.header ? /* @__PURE__ */ jsxs2(DropdownMenuLabel2, { className: "truncate text-xs font-normal text-muted-foreground", title: engine.model.header.text, children: [
|
package/dist/react-menu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/menu.tsx","../src/menu/layouts.ts","../src/react/engine.tsx","../src/declare/sensitivity.ts","../src/actions/projection.ts","../src/actions/run.ts","../src/menu/model.ts","../src/react/context.ts","../src/react/dropdown-nodes.tsx"],"sourcesContent":["\"use client\";\n/**\n * `@ai-matrx/alchemy/react/menu` — the right-click (context) layout, T1.\n * Reached only through the T0 shell's dynamic import (`/react/host`); it\n * draws `context(model, arrangement)` at the pointer. classic · tiered ·\n * command (type-to-filter over every leaf with its breadcrumb).\n */\nimport * as React from \"react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n TooltipProvider,\n} from \"@ai-matrx/design-system\";\nimport { context, filterPalette, palette } from \"../menu/layouts\";\nimport type { ContextArrangement, Density } from \"../menu/types\";\nimport type { ClickTarget } from \"../actions/types\";\nimport { useMenuEngine, type MenuEngineOptions } from \"./engine\";\nimport { LeafButton, SectionList } from \"./dropdown-nodes\";\n\nexport interface ContextMenuPanelProps extends MenuEngineOptions {\n target: ClickTarget;\n /** Viewport coordinates of the gesture. */\n point: { x: number; y: number };\n open: boolean;\n onOpenChange(open: boolean): void;\n arrangement?: ContextArrangement;\n density?: Density;\n}\n\nexport function ContextMenuPanel({\n target,\n point,\n open,\n onOpenChange,\n arrangement = \"command\",\n density = \"comfortable\",\n ...options\n}: ContextMenuPanelProps): React.ReactElement {\n const engine = useMenuEngine(target, { ...options, onRan: (id, r) => { options.onRan?.(id, r); onOpenChange(false); } });\n const [query, setQuery] = React.useState(\"\");\n const arranged = engine.model ? context(engine.model, arrangement) : null;\n const filtered = engine.model && query.trim() ? filterPalette(palette(engine.model), query) : null;\n return (\n <DropdownMenu open={open} onOpenChange={onOpenChange} modal={false}>\n <DropdownMenuTrigger asChild>\n <span aria-hidden style={{ position: \"fixed\", left: point.x, top: point.y, width: 0, height: 0 }} />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align=\"start\"\n data-alchemy-layout={`context-${arrangement}`}\n className={`w-72 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto ${density === \"compact\" ? \"text-xs\" : \"\"}`}\n >\n <TooltipProvider>\n {engine.model?.header ? (\n <DropdownMenuLabel className=\"truncate text-xs font-normal text-muted-foreground\" title={engine.model.header.text}>\n {engine.model.header.label}: {engine.model.header.text}\n </DropdownMenuLabel>\n ) : null}\n {!arranged ? (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">Loading…</div>\n ) : (\n <>\n {arranged.strip.length ? (\n <div role=\"toolbar\" aria-label=\"Clipboard\" className=\"flex items-center gap-0.5 px-1 py-1\">\n {arranged.strip.map((node) => (\n <LeafButton key={node.id} node={node} engine={engine} showLabel={false} />\n ))}\n </div>\n ) : null}\n {arranged.filterable ? (\n <div className=\"px-1 pb-1\">\n <input\n aria-label=\"Filter actions\"\n placeholder=\"Type to filter…\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Enter\" && filtered?.leaves[0]) void engine.run(filtered.leaves[0].node.id);\n }}\n className=\"h-7 w-full rounded-md border border-border bg-transparent px-2 text-sm outline-none\"\n />\n </div>\n ) : null}\n {(arranged.strip.length || arranged.filterable) && arranged.sections.length ? <DropdownMenuSeparator /> : null}\n {filtered ? (\n filtered.leaves.length ? (\n filtered.leaves.map(({ node, breadcrumb }) => (\n <DropdownMenuItem\n key={node.id}\n data-alchemy-node={node.id}\n onSelect={() => {\n if (node.kind === \"submenu\") void engine.expand(node.id);\n else void engine.run(node.id);\n }}\n className=\"flex-col items-start gap-0\"\n >\n <span>{node.label}</span>\n <span className=\"text-xs text-muted-foreground\">{breadcrumb.join(\" › \")}</span>\n </DropdownMenuItem>\n ))\n ) : (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">No action matches “{query}”.</div>\n )\n ) : (\n <SectionList sections={arranged.sections} engine={engine} />\n )}\n </>\n )}\n </TooltipProvider>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport default ContextMenuPanel;\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\nconst GROUP_LABEL: Record<MenuSection[\"group\"], string> = {\n clipboard: \"Clipboard\",\n tools: \"Tools\",\n history: \"History\",\n document: \"Save & share\",\n surface: \"This page\",\n ai: \"AI\",\n quick: \"Feedback\",\n editable: \"Edit\",\n admin: \"Admin\",\n \"surface-info\": \"About this page\",\n transfer: \"Copy & export\",\n};\n\nexport function sectionLabel(section: MenuSection): string {\n return section.label ?? GROUP_LABEL[section.group];\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\nfunction fold(section: MenuSection): MenuSubmenuNode {\n return {\n kind: \"submenu\",\n id: `${section.id}:fold`,\n label: sectionLabel(section),\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 hierarchical = model.sections.some((s) => s.primary);\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.group === \"surface-info\" || rowCount(s.nodes) <= INLINE_SECTION_MAX) {\n if (hierarchical) sections.push(s);\n else {\n const { label: _label, ...unlabelled } = s;\n sections.push(unlabelled);\n }\n continue;\n }\n sections.push({ id: s.id, group: s.group, nodes: [fold(s)] });\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 * 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)] } : 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 || 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, 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, [sectionLabel(s)]);\n return { leaves };\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 } from \"../menu/model\";\nimport type { MenuModel, MenuNode } from \"../menu/types\";\nimport { useAlchemyActions } from \"./context\";\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 contentFingerprint?: string;\n /** Called after a node ran (close the menu, announce). */\n onRan?: (nodeId: string, result: RunResult) => 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 icon(key: string | undefined): React.ReactNode;\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 const expanded = React.useRef(new Map<string, Action>());\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 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 expanded.current.clear();\n setResolved(list);\n setModel(buildMenuModel(target, list, { ...(ports.i18n ? { i18n: ports.i18n } : {}), content: optionsRef.current.content ?? null }));\n });\n return () => {\n live = false;\n };\n }, [registry, ports, target, active, tick, options.revision]);\n\n // Live toggles (read-aloud, thumbs): re-build when an action's store changes.\n React.useEffect(() => {\n if (!target) return;\n const offs = resolved\n .map((r) => r.action.subscribe?.(() => setTick((t) => t + 1), target))\n .filter((off): off is () => void => typeof off === \"function\");\n return () => offs.forEach((off) => off());\n }, [resolved, target]);\n\n const findAction = React.useCallback(\n (id: string): Action | undefined => resolved.find((r) => r.action.id === id)?.action ?? expanded.current.get(id),\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);\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 setModel((m) => (m ? withExpandedChildren(m, nodeId, \"loading\") : m));\n try {\n const children = await action.expand(target, new AbortController().signal);\n const nodes: MenuNode[] = 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 setModel((m) => (m ? withExpandedChildren(m, nodeId, nodes) : m));\n } catch (error) {\n ports.diagnostics.capture(error, { area: \"menu\", detail: { nodeId, stage: \"expand\" } });\n setModel((m) => (m ? withExpandedChildren(m, nodeId, []) : m));\n }\n },\n [findAction, target, ports],\n );\n\n const icon = React.useCallback(\n (key: string | undefined): 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\" aria-hidden /> : null;\n },\n [ports.icons],\n );\n\n return { model, resolved, run, expand, icon };\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 * 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 { ActionCategory, ClickTarget, ResolvedAction } from \"../actions/types\";\nimport type { I18nPort } from \"../ports\";\nimport type { MenuGroup, MenuModel, MenuNode, MenuSection, MenuSubmenuNode } from \"./types\";\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 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 \"feedback\",\n \"creator\",\n \"admin\",\n \"surface-info\",\n];\n\nexport interface BuildMenuModelOptions {\n i18n?: I18nPort;\n /** Content the menu acts on when nothing is selected. */\n content?: 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 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 ...(eligibility.status === \"unavailable-verb\" ? { unavailable: { sentence: eligibility.sentence } } : {}),\n };\n}\n\nexport function buildMenuModel(\n target: ClickTarget,\n resolved: readonly ResolvedAction[],\n options: BuildMenuModelOptions = {},\n): MenuModel {\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 };\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 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 header = selected\n ? { label: \"Selected\" as const, text: target.selection?.text ?? \"\" }\n : content\n ? { label: \"Content\" as const, 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). */\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, 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","\"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 { 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 return (\n <>\n {sections.map((section, index) => (\n <React.Fragment key={section.id}>\n {index > 0 ? <DropdownMenuSeparator /> : null}\n {section.label || section.primary ? (\n <DropdownMenuLabel className=\"text-xs 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\nfunction iconOf(node: MenuNode, engine: MenuEngine): React.ReactNode {\n if (node.kind === \"item\" && 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 return \"icon\" in node ? engine.icon(node.icon) : null;\n}\n\nexport function MenuNodeView({ node, engine }: { node: MenuNode; engine: MenuEngine }): React.ReactElement | null {\n switch (node.kind) {\n case \"separator\":\n return <DropdownMenuSeparator />;\n case \"label\":\n return <DropdownMenuLabel className=\"text-xs font-medium text-muted-foreground\">{node.label}</DropdownMenuLabel>;\n case \"submenu\":\n return (\n <DropdownMenuSub\n onOpenChange={(open) => {\n if (open && node.lazy && !node.loading) void engine.expand(node.id);\n }}\n >\n <DropdownMenuSubTrigger data-alchemy-node={node.id} className=\"gap-2\">\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto\">\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 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=\"gap-2\"\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=\"gap-2\">\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\nfunction LeafItem({ node, engine }: { node: Extract<MenuLeafNode, { kind: \"item\" }>; engine: MenuEngine }): React.ReactElement {\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 void engine.run(node.id);\n }}\n className={`gap-2 ${node.unavailable ? \"opacity-50\" : \"\"} ${node.destructive ? \"text-destructive\" : \"\"}`}\n >\n {iconOf(node, engine)}\n <span className=\"min-w-0 flex-1 truncate\">{node.label}</span>\n {node.hint ? <span className=\"ml-auto text-xs 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 button = (\n <button\n type=\"button\"\n data-alchemy-node={node.id}\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) return;\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 h-7 min-w-7 items-center justify-center gap-1.5 rounded-md px-1.5 text-sm 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>{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"],"mappings":"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","names":["React","DropdownMenuItem","DropdownMenuLabel","DropdownMenuSeparator","React","React","Fragment","jsx","Fragment","jsx","jsxs","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuItem"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/menu.tsx","../src/menu/layouts.ts","../src/react/engine.tsx","../src/declare/sensitivity.ts","../src/actions/projection.ts","../src/actions/run.ts","../src/menu/model.ts","../src/react/context.ts","../src/react/dropdown-nodes.tsx"],"sourcesContent":["\"use client\";\n/**\n * `@ai-matrx/alchemy/react/menu` — the right-click (context) layout, T1.\n * Reached only through the T0 shell's dynamic import (`/react/host`); it\n * draws `context(model, arrangement)` at the pointer. classic · tiered ·\n * command (type-to-filter over every leaf with its breadcrumb).\n */\nimport * as React from \"react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n TooltipProvider,\n} from \"@ai-matrx/design-system\";\nimport { context, filterPalette, palette } from \"../menu/layouts\";\nimport type { ContextArrangement, Density } from \"../menu/types\";\nimport type { ClickTarget } from \"../actions/types\";\nimport { useMenuEngine, type MenuEngineOptions } from \"./engine\";\nimport { LeafButton, SectionList } from \"./dropdown-nodes\";\n\nexport interface ContextMenuPanelProps extends MenuEngineOptions {\n target: ClickTarget;\n /** Viewport coordinates of the gesture. */\n point: { x: number; y: number };\n open: boolean;\n onOpenChange(open: boolean): void;\n arrangement?: ContextArrangement;\n density?: Density;\n}\n\nexport function ContextMenuPanel({\n target,\n point,\n open,\n onOpenChange,\n arrangement = \"command\",\n density = \"comfortable\",\n ...options\n}: ContextMenuPanelProps): React.ReactElement {\n const engine = useMenuEngine(target, { ...options, onRan: (id, r) => { options.onRan?.(id, r); onOpenChange(false); } });\n const [query, setQuery] = React.useState(\"\");\n const arranged = engine.model ? context(engine.model, arrangement) : null;\n const filtered = engine.model && query.trim() ? filterPalette(palette(engine.model), query) : null;\n return (\n <DropdownMenu open={open} onOpenChange={onOpenChange} modal={false}>\n <DropdownMenuTrigger asChild>\n <span aria-hidden style={{ position: \"fixed\", left: point.x, top: point.y, width: 0, height: 0 }} />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align=\"start\"\n data-alchemy-layout={`context-${arrangement}`}\n // The menu opens before the right-button release; Radix treats an item\n // pointer-up with no pointer-down as a click, so that release would run\n // whatever row opened beneath the pointer. Consume only the secondary\n // release; primary clicks and the keyboard follow Radix's normal path.\n onPointerUpCapture={(event) => {\n if (event.button === 2) event.preventDefault();\n }}\n className={`w-72 max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto ${density === \"compact\" ? \"text-xs\" : \"\"}`}\n >\n <TooltipProvider>\n {engine.model?.header ? (\n <DropdownMenuLabel className=\"truncate text-xs font-normal text-muted-foreground\" title={engine.model.header.text}>\n {engine.model.header.label}: {engine.model.header.text}\n </DropdownMenuLabel>\n ) : null}\n {!arranged ? (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">Loading…</div>\n ) : (\n <>\n {arranged.strip.length ? (\n <div role=\"toolbar\" aria-label=\"Clipboard\" className=\"flex items-center gap-0.5 px-1 py-1\">\n {arranged.strip.map((node) => (\n <LeafButton key={node.id} node={node} engine={engine} showLabel={false} />\n ))}\n </div>\n ) : null}\n {arranged.filterable ? (\n <div className=\"px-1 pb-1\">\n <input\n aria-label=\"Filter actions\"\n placeholder=\"Type to filter…\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n onKeyDown={(e) => {\n e.stopPropagation();\n if (e.key === \"Enter\" && filtered?.leaves[0]) void engine.run(filtered.leaves[0].node.id);\n }}\n className=\"h-7 w-full rounded-md border border-border bg-transparent px-2 text-sm outline-none\"\n />\n </div>\n ) : null}\n {(arranged.strip.length || arranged.filterable) && arranged.sections.length ? <DropdownMenuSeparator /> : null}\n {filtered ? (\n filtered.leaves.length ? (\n filtered.leaves.map(({ node, breadcrumb }) => (\n <DropdownMenuItem\n key={node.id}\n data-alchemy-node={node.id}\n onSelect={() => {\n if (node.kind === \"submenu\") void engine.expand(node.id);\n else void engine.run(node.id);\n }}\n className=\"flex-col items-start gap-0\"\n >\n <span>{node.label}</span>\n <span className=\"text-xs text-muted-foreground\">{breadcrumb.join(\" › \")}</span>\n </DropdownMenuItem>\n ))\n ) : (\n <div className=\"px-2 py-1.5 text-xs text-muted-foreground\">No action matches “{query}”.</div>\n )\n ) : (\n <SectionList sections={arranged.sections} engine={engine} />\n )}\n </>\n )}\n </TooltipProvider>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport default ContextMenuPanel;\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 hierarchical = model.sections.some((s) => s.primary);\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 if (hierarchical) sections.push(s);\n else {\n const { label: _label, ...unlabelled } = s;\n sections.push(unlabelled);\n }\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 * 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/** 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 } from \"../menu/model\";\nimport type { MenuModel, MenuNode } from \"../menu/types\";\nimport { useAlchemyActions } from \"./context\";\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 contentFingerprint?: string;\n /** Called after a node ran (close the menu, announce). */\n onRan?: (nodeId: string, result: RunResult) => 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}\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 const expanded = React.useRef(new Map<string, Action>());\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 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 expanded.current.clear();\n setResolved(list);\n setModel(buildMenuModel(target, list, { ...(ports.i18n ? { i18n: ports.i18n } : {}), content: optionsRef.current.content ?? null }));\n });\n return () => {\n live = false;\n };\n }, [registry, ports, target, active, tick, options.revision]);\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),\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);\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 setModel((m) => (m ? withExpandedChildren(m, nodeId, \"loading\") : m));\n try {\n const children = await action.expand(target, new AbortController().signal);\n const nodes: MenuNode[] = 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 setModel((m) => (m ? withExpandedChildren(m, nodeId, nodes) : m));\n } catch (error) {\n ports.diagnostics.capture(error, { area: \"menu\", detail: { nodeId, stage: \"expand\" } });\n setModel((m) => (m ? withExpandedChildren(m, nodeId, []) : m));\n }\n },\n [findAction, target, ports],\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 return { model, resolved, run, expand, icon };\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 * 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 { ActionCategory, ClickTarget, ResolvedAction } from \"../actions/types\";\nimport type { I18nPort } from \"../ports\";\nimport type { MenuGroup, MenuModel, MenuNode, MenuSection, MenuSubmenuNode } from \"./types\";\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 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 \"feedback\",\n \"creator\",\n \"admin\",\n \"surface-info\",\n];\n\nexport interface BuildMenuModelOptions {\n i18n?: I18nPort;\n /** Content the menu acts on when nothing is selected. */\n content?: 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 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 ...(eligibility.status === \"unavailable-verb\" ? { unavailable: { sentence: eligibility.sentence } } : {}),\n };\n}\n\nexport function buildMenuModel(\n target: ClickTarget,\n resolved: readonly ResolvedAction[],\n options: BuildMenuModelOptions = {},\n): MenuModel {\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 };\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 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 header = selected\n ? { label: \"Selected\" as const, text: target.selection?.text ?? \"\" }\n : content\n ? { label: \"Content\" as const, 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). */\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, 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","\"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 { 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 return (\n <>\n {sections.map((section, index) => (\n <React.Fragment key={section.id}>\n {index > 0 ? <DropdownMenuSeparator /> : null}\n {sectionLabel(section) ? (\n <DropdownMenuLabel className=\"text-xs 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\nfunction iconOf(node: MenuNode, engine: MenuEngine): React.ReactNode {\n if (node.kind === \"item\" && 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 return engine.icon(node.icon, node.kind === \"item\" ? node.iconTone : undefined);\n}\n\nexport function MenuNodeView({ node, engine }: { node: MenuNode; engine: MenuEngine }): React.ReactElement | null {\n switch (node.kind) {\n case \"separator\":\n return <DropdownMenuSeparator />;\n case \"label\":\n return <DropdownMenuLabel className=\"text-xs font-medium text-muted-foreground\">{node.label}</DropdownMenuLabel>;\n case \"submenu\":\n return (\n <DropdownMenuSub\n onOpenChange={(open) => {\n if (open && node.lazy && !node.loading) void engine.expand(node.id);\n }}\n >\n <DropdownMenuSubTrigger data-alchemy-node={node.id} className=\"gap-2\">\n {iconOf(node, engine)}\n <span className=\"truncate\">{node.label}</span>\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto\">\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 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=\"gap-2\"\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=\"gap-2\">\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\nfunction LeafItem({ node, engine }: { node: Extract<MenuLeafNode, { kind: \"item\" }>; engine: MenuEngine }): React.ReactElement {\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 void engine.run(node.id);\n }}\n className={`gap-2 ${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 text-xs 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 button = (\n <button\n type=\"button\"\n data-alchemy-node={node.id}\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) return;\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 h-7 min-w-7 items-center justify-center gap-1.5 rounded-md px-1.5 text-sm 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>{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"],"mappings":"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","names":["React","DropdownMenuItem","DropdownMenuLabel","DropdownMenuSeparator","React","React","Fragment","jsx","Fragment","jsx","jsxs","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuItem"]}
|
package/dist/react-overflow.cjs
CHANGED
|
@@ -42,27 +42,14 @@ var import_design_system2 = require("@ai-matrx/design-system");
|
|
|
42
42
|
|
|
43
43
|
// src/menu/layouts.ts
|
|
44
44
|
var INLINE_SECTION_MAX = 3;
|
|
45
|
-
var GROUP_LABEL = {
|
|
46
|
-
clipboard: "Clipboard",
|
|
47
|
-
tools: "Tools",
|
|
48
|
-
history: "History",
|
|
49
|
-
document: "Save & share",
|
|
50
|
-
surface: "This page",
|
|
51
|
-
ai: "AI",
|
|
52
|
-
quick: "Feedback",
|
|
53
|
-
editable: "Edit",
|
|
54
|
-
admin: "Admin",
|
|
55
|
-
"surface-info": "About this page",
|
|
56
|
-
transfer: "Copy & export"
|
|
57
|
-
};
|
|
58
45
|
function sectionLabel(section) {
|
|
59
|
-
return section.label ??
|
|
46
|
+
return section.label ?? null;
|
|
60
47
|
}
|
|
61
48
|
function fold(section) {
|
|
62
49
|
return {
|
|
63
50
|
kind: "submenu",
|
|
64
51
|
id: `${section.id}:fold`,
|
|
65
|
-
label:
|
|
52
|
+
label: section.label,
|
|
66
53
|
...section.icon !== void 0 ? { icon: section.icon } : {},
|
|
67
54
|
children: section.nodes
|
|
68
55
|
};
|
|
@@ -72,7 +59,7 @@ function rowCount(nodes) {
|
|
|
72
59
|
}
|
|
73
60
|
function foldNamed(sections) {
|
|
74
61
|
return sections.map(
|
|
75
|
-
(s) => s.label && !s.primary && rowCount(s.nodes) > INLINE_SECTION_MAX ? { id: s.id, group: s.group, nodes: [fold(s)] } : s
|
|
62
|
+
(s) => s.label && !s.primary && rowCount(s.nodes) > INLINE_SECTION_MAX ? { id: s.id, group: s.group, nodes: [fold({ ...s, label: s.label })] } : s
|
|
76
63
|
);
|
|
77
64
|
}
|
|
78
65
|
function overflow(model) {
|
|
@@ -410,11 +397,19 @@ function useMenuEngine(target, options = {}) {
|
|
|
410
397
|
live = false;
|
|
411
398
|
};
|
|
412
399
|
}, [registry, ports, target, active, tick, options.revision]);
|
|
400
|
+
const resolvedRef = React2.useRef(resolved);
|
|
401
|
+
resolvedRef.current = resolved;
|
|
402
|
+
const subscribedIds = resolved.map((r) => r.action.id).join("\n");
|
|
413
403
|
React2.useEffect(() => {
|
|
414
404
|
if (!target) return;
|
|
415
|
-
|
|
405
|
+
let subscribing = true;
|
|
406
|
+
const onChange = () => {
|
|
407
|
+
if (!subscribing) setTick((t) => t + 1);
|
|
408
|
+
};
|
|
409
|
+
const offs = resolvedRef.current.map((r) => r.action.subscribe?.(onChange, target)).filter((off) => typeof off === "function");
|
|
410
|
+
subscribing = false;
|
|
416
411
|
return () => offs.forEach((off) => off());
|
|
417
|
-
}, [
|
|
412
|
+
}, [subscribedIds, target]);
|
|
418
413
|
const findAction = React2.useCallback(
|
|
419
414
|
(id) => resolved.find((r) => r.action.id === id)?.action ?? expanded.current.get(id),
|
|
420
415
|
[resolved]
|
|
@@ -456,10 +451,10 @@ function useMenuEngine(target, options = {}) {
|
|
|
456
451
|
[findAction, target, ports]
|
|
457
452
|
);
|
|
458
453
|
const icon = React2.useCallback(
|
|
459
|
-
(key) => {
|
|
454
|
+
(key, tone) => {
|
|
460
455
|
if (!key || !ports.icons) return null;
|
|
461
456
|
const Resolved = ports.icons.resolve(key);
|
|
462
|
-
return Resolved ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Resolved, { className:
|
|
457
|
+
return Resolved ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Resolved, { className: `h-4 w-4 shrink-0 ${tone ?? ""}`, "aria-hidden": true }) : null;
|
|
463
458
|
},
|
|
464
459
|
[ports.icons]
|
|
465
460
|
);
|
|
@@ -479,7 +474,7 @@ function SectionList({
|
|
|
479
474
|
}) {
|
|
480
475
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: sections.map((section, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(React3.Fragment, { children: [
|
|
481
476
|
index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.DropdownMenuSeparator, {}) : null,
|
|
482
|
-
section
|
|
477
|
+
sectionLabel(section) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.DropdownMenuLabel, { className: "text-xs font-medium text-muted-foreground", children: sectionLabel(section) }) : null,
|
|
483
478
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NodeList, { nodes: section.nodes, engine })
|
|
484
479
|
] }, section.id)) });
|
|
485
480
|
}
|
|
@@ -488,7 +483,8 @@ function iconOf(node, engine) {
|
|
|
488
483
|
const glyph = engine.icon(node.stateIcon.icon);
|
|
489
484
|
return node.stateIcon.spin ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "inline-flex animate-spin", children: glyph }) : glyph;
|
|
490
485
|
}
|
|
491
|
-
|
|
486
|
+
if (!("icon" in node)) return null;
|
|
487
|
+
return engine.icon(node.icon, node.kind === "item" ? node.iconTone : void 0);
|
|
492
488
|
}
|
|
493
489
|
function MenuNodeView({ node, engine }) {
|
|
494
490
|
switch (node.kind) {
|
|
@@ -552,7 +548,10 @@ function LeafItem({ node, engine }) {
|
|
|
552
548
|
className: `gap-2 ${node.unavailable ? "opacity-50" : ""} ${node.destructive ? "text-destructive" : ""}`,
|
|
553
549
|
children: [
|
|
554
550
|
iconOf(node, engine),
|
|
555
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
552
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate", children: node.label }),
|
|
553
|
+
node.description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: node.description }) : null
|
|
554
|
+
] }),
|
|
556
555
|
node.hint ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ml-auto text-xs text-muted-foreground", children: node.hint }) : null
|
|
557
556
|
]
|
|
558
557
|
}
|