@ai-matrx/context-menu 0.1.9 → 0.1.11
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 +12 -0
- package/dist/builder.cjs +17 -18
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.js +2 -3
- package/dist/builder.js.map +1 -1
- package/dist/{chunk-ECKA474B.js → chunk-2B37SXQW.js} +21 -12
- package/dist/chunk-2B37SXQW.js.map +1 -0
- package/dist/{chunk-TSOUI723.cjs → chunk-7TIZAANU.cjs} +26 -11
- package/dist/chunk-7TIZAANU.cjs.map +1 -0
- package/dist/{chunk-A24SBKSA.js → chunk-EG23Y2KW.js} +14 -13
- package/dist/{chunk-A24SBKSA.js.map → chunk-EG23Y2KW.js.map} +1 -1
- package/dist/{chunk-7VDSMZWI.cjs → chunk-ERFH2RZC.cjs} +18 -17
- package/dist/chunk-ERFH2RZC.cjs.map +1 -0
- package/dist/{chunk-EIP5YS4Y.js → chunk-HJU3RU2B.js} +27 -12
- package/dist/chunk-HJU3RU2B.js.map +1 -0
- package/dist/{chunk-SWEWOUHK.cjs → chunk-IH5WN5JP.cjs} +31 -26
- package/dist/chunk-IH5WN5JP.cjs.map +1 -0
- package/dist/{chunk-QXHLM7SS.cjs → chunk-LDMYNYFC.cjs} +42 -33
- package/dist/chunk-LDMYNYFC.cjs.map +1 -0
- package/dist/{chunk-ANJYKQAA.cjs → chunk-MBU4Y22O.cjs} +3 -3
- package/dist/{chunk-ANJYKQAA.cjs.map → chunk-MBU4Y22O.cjs.map} +1 -1
- package/dist/{chunk-L6DPISFT.js → chunk-NBEXJ25Z.js} +24 -19
- package/dist/{chunk-L6DPISFT.js.map → chunk-NBEXJ25Z.js.map} +1 -1
- package/dist/{chunk-LE6ZUVCO.js → chunk-PB3PMDKV.js} +2 -2
- package/dist/{chunk-NOYMFNSU.js → chunk-SJWKMZEJ.js} +33 -12
- package/dist/chunk-SJWKMZEJ.js.map +1 -0
- package/dist/{chunk-XERD2YCJ.cjs → chunk-WROBL3DR.cjs} +32 -11
- package/dist/chunk-WROBL3DR.cjs.map +1 -0
- package/dist/design-store.cjs +0 -1
- package/dist/design-store.cjs.map +1 -1
- package/dist/design-store.js +0 -1
- package/dist/design-store.js.map +1 -1
- package/dist/engine.cjs +64 -96
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +7 -7
- package/dist/engine.d.ts +7 -7
- package/dist/engine.js +72 -104
- package/dist/engine.js.map +1 -1
- package/dist/index.cjs +3 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -3
- package/dist/menu-content.cjs +18 -19
- package/dist/menu-content.cjs.map +1 -1
- package/dist/menu-content.js +4 -5
- package/dist/menu-content.js.map +1 -1
- package/dist/menu-inspect.cjs +0 -1
- package/dist/menu-inspect.cjs.map +1 -1
- package/dist/menu-inspect.js +0 -1
- package/dist/menu-inspect.js.map +1 -1
- package/dist/model.cjs +4 -5
- package/dist/model.cjs.map +1 -1
- package/dist/model.js +3 -4
- package/dist/react.cjs +52 -44
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +30 -22
- package/dist/react.js.map +1 -1
- package/package.json +6 -6
- package/dist/chunk-7VDSMZWI.cjs.map +0 -1
- package/dist/chunk-CUODNUAD.cjs +0 -24
- package/dist/chunk-CUODNUAD.cjs.map +0 -1
- package/dist/chunk-ECKA474B.js.map +0 -1
- package/dist/chunk-EIP5YS4Y.js.map +0 -1
- package/dist/chunk-NOYMFNSU.js.map +0 -1
- package/dist/chunk-PE3ZHHM5.js +0 -24
- package/dist/chunk-PE3ZHHM5.js.map +0 -1
- package/dist/chunk-QXHLM7SS.cjs.map +0 -1
- package/dist/chunk-SWEWOUHK.cjs.map +0 -1
- package/dist/chunk-TSOUI723.cjs.map +0 -1
- package/dist/chunk-XERD2YCJ.cjs.map +0 -1
- /package/dist/{chunk-LE6ZUVCO.js.map → chunk-PB3PMDKV.js.map} +0 -0
|
@@ -107,13 +107,15 @@ function MenuPanel({ nodes, env, className, style, rootProps, panelRef }) {
|
|
|
107
107
|
const searchAt = nodes.findIndex((n) => n.kind === "search");
|
|
108
108
|
const hits = q ? env.search(q) : null;
|
|
109
109
|
const above = searchAt >= 0 ? nodes.slice(0, searchAt) : [];
|
|
110
|
-
return /* @__PURE__ */ jsx(Env.Provider, { value: env, children: /* @__PURE__ */ jsx(Panel, { className: `cm-menu ${className ?? ""}`, style: { width: env.look.width, ...style }, root: true, rootProps, panelRef, children: nodes.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "Empty menu \u2014 drag options in" }) :
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
110
|
+
return /* @__PURE__ */ jsx(Env.Provider, { value: env, children: /* @__PURE__ */ jsx(Panel, { className: `cm-menu ${className ?? ""}`, style: { width: env.look.width, ...style }, root: true, rootProps, panelRef, children: nodes.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "Empty menu \u2014 drag options in" }) : (
|
|
111
|
+
// The search box keeps ONE place in the tree whether or not a query is typed, so typing
|
|
112
|
+
// never remounts it (and never drops the caret).
|
|
113
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
114
|
+
searchAt >= 0 && /* @__PURE__ */ jsx(Nodes, { nodes: above }),
|
|
115
|
+
searchAt >= 0 && /* @__PURE__ */ jsx(SearchBox, { node: nodes[searchAt] }, "cm-search"),
|
|
116
|
+
hits ? hits.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cm-empty", children: "No matches" }) : hits.map((h) => h.node.kind === "item" ? /* @__PURE__ */ jsx(Item, { node: h.node, path: h.path, hit: true }, `hit:${h.node.id}`) : null) : /* @__PURE__ */ jsx(Nodes, { nodes: searchAt >= 0 ? nodes.slice(searchAt + 1) : nodes })
|
|
117
|
+
] })
|
|
118
|
+
) }) });
|
|
117
119
|
}
|
|
118
120
|
function Panel({
|
|
119
121
|
children,
|
|
@@ -138,10 +140,16 @@ function Panel({
|
|
|
138
140
|
const at = rows.indexOf(document.activeElement);
|
|
139
141
|
const focus = (i) => rows[(i + rows.length) % rows.length]?.focus();
|
|
140
142
|
switch (e.key) {
|
|
141
|
-
case "ArrowDown":
|
|
143
|
+
case "ArrowDown": {
|
|
142
144
|
e.preventDefault();
|
|
143
|
-
|
|
145
|
+
if (inSearch) {
|
|
146
|
+
const below = rows.find((r) => e.target.compareDocumentPosition(r) & Node.DOCUMENT_POSITION_FOLLOWING);
|
|
147
|
+
(below ?? rows[0])?.focus();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
focus(at < 0 ? 0 : at + 1);
|
|
144
151
|
return;
|
|
152
|
+
}
|
|
145
153
|
case "ArrowUp":
|
|
146
154
|
e.preventDefault();
|
|
147
155
|
if (inSearch) return;
|
|
@@ -183,7 +191,7 @@ function Panel({
|
|
|
183
191
|
case "Enter":
|
|
184
192
|
if (inSearch) {
|
|
185
193
|
e.preventDefault();
|
|
186
|
-
|
|
194
|
+
panel.querySelector('[data-cm-hit]:not([aria-disabled="true"])')?.click();
|
|
187
195
|
}
|
|
188
196
|
return;
|
|
189
197
|
default:
|
|
@@ -307,7 +315,7 @@ function Tile({ node }) {
|
|
|
307
315
|
)
|
|
308
316
|
);
|
|
309
317
|
}
|
|
310
|
-
function Item({ node, path }) {
|
|
318
|
+
function Item({ node, path, hit }) {
|
|
311
319
|
const env = useEnv();
|
|
312
320
|
const { look } = env;
|
|
313
321
|
const [checked, setChecked] = useState(Boolean(node.checked));
|
|
@@ -326,6 +334,7 @@ function Item({ node, path }) {
|
|
|
326
334
|
tabIndex: -1,
|
|
327
335
|
"data-cm-row": "",
|
|
328
336
|
"data-cm-label": node.label,
|
|
337
|
+
...hit ? { "data-cm-hit": "" } : {},
|
|
329
338
|
"aria-checked": settable ? checked : void 0,
|
|
330
339
|
"aria-disabled": node.disabled || void 0,
|
|
331
340
|
...reason ? { title: reason, "aria-description": reason } : {},
|
|
@@ -467,4 +476,4 @@ function FlyoutBody({ node, flyRef, side }) {
|
|
|
467
476
|
export {
|
|
468
477
|
MenuPanel
|
|
469
478
|
};
|
|
470
|
-
//# sourceMappingURL=chunk-
|
|
479
|
+
//# sourceMappingURL=chunk-2B37SXQW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/designed/MenuPanel.tsx"],"sourcesContent":["// src/designed/MenuPanel.tsx — @ai-matrx/context-menu: THE ONE MENU RENDERER.\n//\n// Draws a resolved menu (ResolvedNode[]) — the builder's preview and the live right-click menu are\n// both this component, so what the designer sees is what opens. It owns the menu's own behaviour:\n// submenus on hover with an intent delay and a safe triangle toward the open flyout, flyouts that\n// flip at the screen's edge, the keyboard (arrows, Enter, Esc / Left closes a submenu, Right opens\n// one, typeahead), the search box, and the status marks (partial / unmatched / needs-arman).\n// This file IS the menu component: its rows are the menu's own rows (hence the ui-exception marks).\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from \"react\";\nimport type { MenuLook, MenuTone } from \"../design/model\";\nimport type { IconRef, ResolvedItem, ResolvedNode, ResolvedSearch, ResolvedSection, ResolvedSubmenu } from \"./types\";\nimport type { ResolvedHit } from \"./bindings\";\n\nexport interface MenuPanelEnv {\n look: MenuLook;\n /** Draws a lucide icon by name (the design's icons). */\n renderIcon: (name: string, className?: string) => ReactNode;\n /** A row was chosen (live: run it and close; builder: the designer's pick). */\n onActivate: (item: ResolvedItem) => void;\n /** Builder: a click on any entry selects its design node. */\n onSelectNode?: ((designId: string) => void) | undefined;\n highlightId?: string | null | undefined;\n /** absolute: flyouts sit beside their row (the builder) · fixed: measured against the screen (live). */\n flyout: \"absolute\" | \"fixed\";\n query: string;\n setQuery: (q: string) => void;\n /** The search, over the bound entries. */\n search: (q: string) => ResolvedHit[];\n /** Esc at the top: close the whole menu. */\n onEscape?: (() => void) | undefined;\n}\n\nconst Env = createContext<MenuPanelEnv | null>(null);\nfunction useEnv(): MenuPanelEnv {\n const env = useContext(Env);\n if (!env) throw new Error(\"MenuPanel: rendered outside its menu\");\n return env;\n}\n\n// ── rows: focus, keyboard ────────────────────────────────────────────────────\n\nconst ROW = \"[data-cm-row]\";\n\n/** The rows of THIS panel (not those of a flyout inside it), in order. */\nfunction rowsOf(panel: HTMLElement): HTMLElement[] {\n return [...panel.querySelectorAll<HTMLElement>(ROW)].filter((el) => el.closest('[role=\"menu\"]') === panel && el.getAttribute(\"aria-disabled\") !== \"true\");\n}\n\nfunction labelOf(el: HTMLElement): string {\n return (el.getAttribute(\"data-cm-label\") ?? el.textContent ?? \"\").trim().toLowerCase();\n}\n\nfunction reasonOf(n: ResolvedItem | ResolvedSubmenu): string | undefined {\n const parts = [n.statusReason, n.disabled ? n.disabledReason : undefined].filter(Boolean);\n return parts.length ? parts.join(\" — \") : undefined;\n}\n\nfunction toneAttrs(tone: MenuTone | undefined, toneLabel: boolean | undefined) {\n return tone && tone !== \"default\" ? { \"data-tone\": tone, ...(toneLabel ? { \"data-tone-label\": \"\" } : {}) } : {};\n}\n\nfunction Icon({ icon, fallback }: { icon?: IconRef | undefined; fallback?: string }) {\n const env = useEnv();\n if (icon?.component) {\n const C = icon.component;\n return <C className={`cm-icon ${icon.className ?? \"\"}`} {...(icon.style ? { style: icon.style } : {})} />;\n }\n const name = icon?.name ?? fallback;\n return name ? <>{env.renderIcon(name, \"cm-icon\")}</> : null;\n}\n\n// ── submenu intent: open on hover after a beat, never steal a flyout the pointer is heading to ──\n\ninterface Intent {\n openId: string | null;\n viaKey: boolean;\n enter: (id: string | null, el: HTMLElement) => void;\n openNow: (id: string, viaKey: boolean) => void;\n close: () => void;\n track: (e: ReactPointerEvent) => void;\n}\n\nfunction useIntent(): Intent {\n const [state, setState] = useState<{ openId: string | null; viaKey: boolean }>({ openId: null, viaKey: false });\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const trail = useRef<{ x: number; y: number }[]>([]);\n const flyoutRect = useRef<DOMRect | null>(null);\n const stateRef = useRef(state);\n stateRef.current = state;\n useEffect(() => () => void (timer.current && clearTimeout(timer.current)), []);\n\n const heading = (): boolean => {\n const r = flyoutRect.current;\n const [a, b] = trail.current.slice(-2);\n if (!r || !a || !b) return false;\n // Is the pointer inside the triangle from where it was to the flyout's near edge?\n const towardRight = r.left >= a.x;\n const ex = towardRight ? r.left : r.right;\n const p = b;\n const t1 = { x: ex, y: r.top - 8 };\n const t2 = { x: ex, y: r.bottom + 8 };\n const sign = (p1: { x: number; y: number }, p2: { x: number; y: number }, p3: { x: number; y: number }) =>\n (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);\n const d1 = sign(p, a, t1);\n const d2 = sign(p, t1, t2);\n const d3 = sign(p, t2, a);\n const neg = d1 < 0 || d2 < 0 || d3 < 0;\n const pos = d1 > 0 || d2 > 0 || d3 > 0;\n return !(neg && pos);\n };\n\n const schedule = (fn: () => void, ms: number) => {\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(fn, ms);\n };\n\n return {\n openId: state.openId,\n viaKey: state.viaKey,\n track: (e) => {\n trail.current.push({ x: e.clientX, y: e.clientY });\n if (trail.current.length > 3) trail.current.shift();\n },\n enter: (id, el) => {\n const current = stateRef.current.openId;\n if (id === current) {\n if (timer.current) clearTimeout(timer.current);\n return;\n }\n const flyout = current ? el.closest('[role=\"menu\"]')?.querySelector<HTMLElement>(`[data-cm-flyout=\"${CSS.escape(current)}\"]`) : null;\n flyoutRect.current = flyout?.getBoundingClientRect() ?? null;\n const go = () => setState({ openId: id, viaKey: false });\n if (current && heading()) {\n // On the way to the open flyout: wait, then look again.\n schedule(() => {\n if (el.matches(\":hover\")) go();\n }, 300);\n } else schedule(go, current ? 60 : 90);\n },\n openNow: (id, viaKey) => {\n if (timer.current) clearTimeout(timer.current);\n setState({ openId: id, viaKey });\n },\n close: () => {\n if (timer.current) clearTimeout(timer.current);\n setState({ openId: null, viaKey: false });\n },\n };\n}\n\nconst PanelIntent = createContext<Intent | null>(null);\n\n// ── the panel ────────────────────────────────────────────────────────────────\n\nexport interface MenuPanelProps {\n nodes: readonly ResolvedNode[];\n env: MenuPanelEnv;\n className?: string;\n style?: CSSProperties;\n /** Props for the root element (position, data attributes). */\n rootProps?: Record<string, unknown>;\n /** The root element, for the owner's own measuring and outside-click test. */\n panelRef?: (el: HTMLDivElement | null) => void;\n}\n\n/** THE MENU: the root panel (with the search box), drawn from resolved nodes. */\nexport function MenuPanel({ nodes, env, className, style, rootProps, panelRef }: MenuPanelProps) {\n const q = env.query.trim().toLowerCase();\n const searchAt = nodes.findIndex((n) => n.kind === \"search\");\n const hits = q ? env.search(q) : null;\n const above = searchAt >= 0 ? nodes.slice(0, searchAt) : [];\n return (\n <Env.Provider value={env}>\n <Panel className={`cm-menu ${className ?? \"\"}`} style={{ width: env.look.width, ...style }} root rootProps={rootProps} panelRef={panelRef}>\n {nodes.length === 0 ? (\n <div className=\"cm-empty\">Empty menu — drag options in</div>\n ) : (\n // The search box keeps ONE place in the tree whether or not a query is typed, so typing\n // never remounts it (and never drops the caret).\n <>\n {searchAt >= 0 && <Nodes nodes={above} />}\n {searchAt >= 0 && <SearchBox key=\"cm-search\" node={nodes[searchAt] as ResolvedSearch} />}\n {hits ? (\n hits.length === 0 ? (\n <div className=\"cm-empty\">No matches</div>\n ) : (\n hits.map((h) => (h.node.kind === \"item\" ? <Item key={`hit:${h.node.id}`} node={h.node} path={h.path} hit /> : null))\n )\n ) : (\n <Nodes nodes={searchAt >= 0 ? nodes.slice(searchAt + 1) : nodes} />\n )}\n </>\n )}\n </Panel>\n </Env.Provider>\n );\n}\n\nfunction Panel({\n children,\n className,\n style,\n root,\n rootProps,\n onClose,\n flyoutId,\n panelRef,\n}: {\n panelRef?: ((el: HTMLDivElement | null) => void) | undefined;\n children: ReactNode;\n className: string;\n style?: CSSProperties | undefined;\n root?: boolean;\n rootProps?: Record<string, unknown> | undefined;\n /** A flyout: Esc / Left closes it (the parent focuses its row again). */\n onClose?: (() => void) | undefined;\n flyoutId?: string | undefined;\n}) {\n const env = useEnv();\n const intent = useIntent();\n const ref = useRef<HTMLDivElement>(null);\n const typed = useRef({ text: \"\", at: 0 });\n\n const onKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {\n const panel = ref.current;\n if (!panel) return;\n // A key that started in a flyout inside this panel belongs to that flyout.\n if ((e.target as HTMLElement).closest('[role=\"menu\"]') !== panel) return;\n const inSearch = (e.target as HTMLElement).tagName === \"INPUT\";\n const rows = rowsOf(panel);\n const at = rows.indexOf(document.activeElement as HTMLElement);\n const focus = (i: number) => rows[(i + rows.length) % rows.length]?.focus();\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (inSearch) {\n // From the search box: the first row below it.\n const below = rows.find((r) => (e.target as HTMLElement).compareDocumentPosition(r) & Node.DOCUMENT_POSITION_FOLLOWING);\n (below ?? rows[0])?.focus();\n return;\n }\n focus(at < 0 ? 0 : at + 1);\n return;\n }\n case \"ArrowUp\":\n e.preventDefault();\n if (inSearch) return;\n if (at <= 0 && root) {\n const search = panel.querySelector<HTMLInputElement>(\".cm-search input\");\n if (search) return search.focus();\n }\n focus(at < 0 ? rows.length - 1 : at - 1);\n return;\n case \"Home\":\n case \"End\":\n if (inSearch) return;\n e.preventDefault();\n focus(e.key === \"Home\" ? 0 : rows.length - 1);\n return;\n case \"ArrowRight\": {\n if (inSearch) return;\n const row = document.activeElement as HTMLElement | null;\n const sub = row?.getAttribute(\"data-cm-sub\");\n if (sub) {\n e.preventDefault();\n intent.openNow(sub, true);\n }\n return;\n }\n case \"ArrowLeft\":\n if (inSearch || !onClose) return;\n e.preventDefault();\n e.stopPropagation();\n onClose();\n return;\n case \"Escape\":\n e.preventDefault();\n e.stopPropagation();\n if (inSearch && env.query) return env.setQuery(\"\");\n if (onClose) onClose();\n else env.onEscape?.();\n return;\n case \"Enter\":\n if (inSearch) {\n e.preventDefault();\n // The first match runs (the rows above the search box are not matches).\n panel.querySelector<HTMLElement>('[data-cm-hit]:not([aria-disabled=\"true\"])')?.click();\n }\n return;\n default:\n break;\n }\n // Typeahead: a printable key jumps to the next row starting with what was typed. At the top\n // of a menu with a search box, it types into the search instead.\n if (e.key.length !== 1 || e.metaKey || e.ctrlKey || e.altKey || inSearch) return;\n const search = root ? panel.querySelector<HTMLInputElement>(\".cm-search input\") : null;\n if (search) {\n e.preventDefault();\n search.focus();\n env.setQuery(env.query + e.key);\n return;\n }\n const now = Date.now();\n typed.current = { text: now - typed.current.at > 700 ? e.key.toLowerCase() : typed.current.text + e.key.toLowerCase(), at: now };\n const start = at < 0 ? 0 : typed.current.text.length > 1 ? at : at + 1;\n for (let i = 0; i < rows.length; i++) {\n const row = rows[(start + i) % rows.length];\n if (row && labelOf(row).startsWith(typed.current.text)) {\n e.preventDefault();\n row.focus();\n return;\n }\n }\n };\n\n return (\n <PanelIntent.Provider value={intent}>\n <div\n ref={(el) => {\n ref.current = el;\n panelRef?.(el);\n }}\n role=\"menu\"\n tabIndex={-1}\n data-density={env.look.density}\n {...(flyoutId ? { \"data-cm-flyout\": flyoutId } : {})}\n className={className}\n style={style}\n onKeyDown={onKeyDown}\n onPointerMove={intent.track}\n {...(rootProps ?? {})}\n >\n {children}\n </div>\n </PanelIntent.Provider>\n );\n}\n\nfunction Nodes({ nodes }: { nodes: readonly ResolvedNode[] }) {\n return (\n <>\n {nodes.map((n) => {\n if (n.kind === \"divider\") return <div key={n.id} role=\"separator\" className=\"cm-divider\" />;\n if (n.kind === \"item\") return <Item key={n.id} node={n} />;\n if (n.kind === \"submenu\") return <Submenu key={n.id} node={n} />;\n if (n.kind === \"search\") return <SearchBox key={n.id} node={n} />;\n if (n.kind === \"note\") return <div key={n.id} className={n.tone === \"runtime\" ? \"cm-runtime\" : \"cm-empty\"}>{n.text}</div>;\n return <Section key={n.id} node={n} />;\n })}\n </>\n );\n}\n\nfunction SearchBox({ node }: { node: ResolvedSearch }) {\n const env = useEnv();\n const ref = useRef<HTMLInputElement>(null);\n useEffect(() => {\n if (node.autofocus) ref.current?.focus({ preventScroll: true });\n }, [node.autofocus]);\n return (\n <div className={`cm-search ${env.highlightId === node.designId ? \"cm-hl\" : \"\"}`} onClick={() => node.designId && env.onSelectNode?.(node.designId)}>\n {env.renderIcon(\"Search\", \"cm-icon\")}\n {/* ui-exception: the menu's own filter row — this file IS the menu component */}\n <input ref={ref} value={env.query} onChange={(e) => env.setQuery(e.target.value)} placeholder={node.placeholder || \"Type to filter…\"} aria-label=\"Filter menu\" />\n </div>\n );\n}\n\nfunction Section({ node }: { node: ResolvedSection }) {\n const env = useEnv();\n const [open, setOpen] = useState(!node.collapsible);\n const layout = node.layout;\n return (\n <div className={`cm-section ${env.highlightId && env.highlightId === node.designId ? \"cm-hl\" : \"\"}`} data-layout={layout} {...(node.feature ? { \"data-feature\": \"\" } : {})}>\n {node.label && (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n tabIndex={-1}\n className={`cm-section-label ${node.placeholder ? \"cm-slot-label\" : \"\"}`}\n onClick={() => {\n if (node.designId) env.onSelectNode?.(node.designId);\n if (node.collapsible) setOpen((o) => !o);\n }}\n >\n {node.label}\n {node.collapsible && <span className=\"cm-caret\">{open ? \"▾\" : \"▸\"}</span>}\n </button>\n )}\n {open && (\n <div className=\"cm-section-body\">\n {layout === \"list\" ? (\n <Nodes nodes={node.children} />\n ) : (\n node.children.map((c) => (c.kind === \"item\" ? <Tile key={c.id} node={c} /> : <Nodes key={c.id} nodes={[c]} />))\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction statusAttrs(n: ResolvedItem | ResolvedSubmenu) {\n const status = n.missingRequired ? \"required-missing\" : n.status && n.status !== \"works\" ? n.status : undefined;\n return status ? { \"data-status\": status } : {};\n}\n\nfunction Tile({ node }: { node: ResolvedItem }) {\n const env = useEnv();\n const reason = reasonOf(node);\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n data-cm-row=\"\"\n data-cm-label={node.label}\n title={[node.label + (node.shortcut ? ` ${node.shortcut}` : \"\"), reason].filter(Boolean).join(\"\\n\")}\n aria-label={node.label}\n aria-disabled={node.disabled || undefined}\n {...toneAttrs(node.tone, node.toneLabel)}\n {...statusAttrs(node)}\n className={`cm-tile ${node.danger ? \"cm-danger\" : \"\"} ${node.ai ? \"cm-ai\" : \"\"} ${env.highlightId && env.highlightId === node.designId ? \"cm-hl\" : \"\"}`}\n onClick={() => {\n if (node.designId) env.onSelectNode?.(node.designId);\n if (!node.disabled) env.onActivate(node);\n }}\n >\n <Icon icon={node.icon} fallback=\"Circle\" />\n </button>\n );\n}\n\nfunction Item({ node, path, hit }: { node: ResolvedItem; path?: string; hit?: boolean }) {\n const env = useEnv();\n const { look } = env;\n const [checked, setChecked] = useState(Boolean(node.checked));\n // A changed default shows at once (the designer flips \"On by default\" while looking at the row).\n useEffect(() => setChecked(Boolean(node.checked)), [node.checked]);\n const settable = node.toggle || node.switch;\n const hint = path || (look.showHints ? node.hint : undefined);\n const reason = reasonOf(node);\n const intent = useContext(PanelIntent);\n return (\n // ui-exception: a menu row of the menu component itself\n <button\n type=\"button\"\n role={settable ? \"menuitemcheckbox\" : \"menuitem\"}\n tabIndex={-1}\n data-cm-row=\"\"\n data-cm-label={node.label}\n {...(hit ? { \"data-cm-hit\": \"\" } : {})}\n aria-checked={settable ? checked : undefined}\n aria-disabled={node.disabled || undefined}\n {...(reason ? { title: reason, \"aria-description\": reason } : {})}\n {...toneAttrs(node.tone, node.toneLabel)}\n {...statusAttrs(node)}\n className={`cm-item ${node.placeholder ? \"cm-slot\" : \"\"} ${node.danger ? \"cm-danger\" : \"\"} ${node.ai ? \"cm-ai\" : \"\"} ${env.highlightId && env.highlightId === node.designId ? \"cm-hl\" : \"\"}`}\n onPointerEnter={(e) => intent?.enter(null, e.currentTarget)}\n onClick={() => {\n if (node.designId) env.onSelectNode?.(node.designId);\n if (node.disabled) return;\n if (settable) setChecked((c) => !c);\n env.onActivate(node);\n }}\n >\n {look.showIcons && (\n <span className=\"cm-icon-slot\">{node.toggle ? (checked ? env.renderIcon(\"Check\", \"cm-icon\") : null) : <Icon icon={node.icon} />}</span>\n )}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n {hint && <span className=\"cm-hint\">{hint}</span>}\n </span>\n {node.count && <span className=\"cm-count\">{node.count}</span>}\n {look.showShortcuts && node.shortcut && !node.switch && <kbd className=\"cm-shortcut\">{node.shortcut}</kbd>}\n {node.switch && <span className=\"cm-switch\" data-on={checked ? \"\" : undefined} aria-hidden=\"true\" />}\n </button>\n );\n}\n\ntype FlyoutSide = \"right\" | \"left\" | \"below\";\n\n/**\n * Builder: where a submenu opens beside its row — right when it fits, else left, else just under it.\n * \"Fits\" is measured against the nearest `[data-menu-bounds]` box (a panel that clips), else the window.\n */\nfunction flyoutSide(row: HTMLElement, width: number): FlyoutSide {\n const r = row.getBoundingClientRect();\n const bounds = row.closest<HTMLElement>(\"[data-menu-bounds]\")?.getBoundingClientRect() ?? { left: 0, right: window.innerWidth };\n if (r.right + width + 8 <= bounds.right) return \"right\";\n if (r.left - width - 8 >= bounds.left) return \"left\";\n return \"below\";\n}\n\n/** Live: the flyout's place on the screen — beside its row, flipped and clamped to stay on screen. */\nexport function placeFlyout(row: DOMRect, size: { width: number; height: number }, view: { width: number; height: number }) {\n const gap = 2;\n const margin = 8;\n let left = row.right + gap;\n let side: \"right\" | \"left\" = \"right\";\n if (left + size.width > view.width - margin) {\n const flipped = row.left - gap - size.width;\n if (flipped >= margin) {\n left = flipped;\n side = \"left\";\n } else left = Math.max(margin, view.width - margin - size.width);\n }\n let top = row.top - 5;\n if (top + size.height > view.height - margin) top = Math.max(margin, view.height - margin - size.height);\n return { left, top, side };\n}\n\nfunction Submenu({ node }: { node: ResolvedSubmenu }) {\n const env = useEnv();\n const intent = useContext(PanelIntent);\n const { look } = env;\n const open = intent?.openId === node.id;\n const [side, setSide] = useState<FlyoutSide>(\"right\");\n const [fixed, setFixed] = useState<{ left: number; top: number } | null>(null);\n const rowRef = useRef<HTMLButtonElement>(null);\n const flyRef = useRef<HTMLDivElement>(null);\n const reason = reasonOf(node);\n const greyed = node.disabled;\n\n useLayoutEffect(() => {\n if (!open || env.flyout !== \"fixed\" || !rowRef.current || !flyRef.current) return;\n const r = rowRef.current.getBoundingClientRect();\n const f = flyRef.current.getBoundingClientRect();\n const at = placeFlyout(r, { width: f.width || look.width, height: f.height }, { width: window.innerWidth, height: window.innerHeight });\n setFixed({ left: at.left, top: at.top });\n setSide(at.side);\n }, [open, env.flyout, look.width]);\n useEffect(() => {\n if (!open) setFixed(null);\n if (open && intent?.viaKey && flyRef.current) {\n const first = rowsOf(flyRef.current)[0];\n (first ?? flyRef.current).focus();\n }\n }, [open, intent?.viaKey]);\n\n const closeFlyout = useCallback(() => {\n intent?.close();\n rowRef.current?.focus();\n }, [intent]);\n\n const flyStyle: CSSProperties =\n env.flyout === \"fixed\"\n ? { position: \"fixed\", width: look.width, maxHeight: \"calc(100vh - 16px)\", overflowY: \"auto\", left: fixed?.left ?? -9999, top: fixed?.top ?? -9999, visibility: fixed ? \"visible\" : \"hidden\" }\n : { width: look.width };\n\n return (\n <div className=\"cm-sub\">\n {/* ui-exception: a menu row of the menu component itself */}\n <button\n ref={rowRef}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n data-cm-row=\"\"\n data-cm-label={node.label}\n {...(greyed ? {} : { \"data-cm-sub\": node.id })}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-disabled={greyed || undefined}\n {...(reason ? { title: reason, \"aria-description\": reason } : {})}\n {...toneAttrs(node.tone, node.toneLabel)}\n {...statusAttrs(node)}\n className={`cm-item ${node.placeholder ? \"cm-slot\" : \"\"} ${open ? \"cm-open\" : \"\"} ${env.highlightId && env.highlightId === node.designId ? \"cm-hl\" : \"\"}`}\n onPointerEnter={(e) => {\n if (env.flyout === \"absolute\") setSide(flyoutSide(e.currentTarget, look.width));\n if (greyed) intent?.enter(null, e.currentTarget);\n else intent?.enter(node.id, e.currentTarget);\n }}\n onClick={(e) => {\n if (node.designId) env.onSelectNode?.(node.designId);\n if (greyed) return;\n if (env.flyout === \"absolute\") setSide(flyoutSide(e.currentTarget, look.width));\n intent?.openNow(node.id, e.detail === 0);\n }}\n >\n {look.showIcons && <span className=\"cm-icon-slot\"><Icon icon={node.icon} /></span>}\n <span className=\"cm-text\">\n <span className=\"cm-label\">{node.label}</span>\n {look.showHints && node.hint && <span className=\"cm-hint\">{node.hint}</span>}\n </span>\n {node.loading && <span className=\"cm-count\">…</span>}\n {node.count && <span className=\"cm-count\">{node.count}</span>}\n {env.renderIcon(\"ChevronRight\", \"cm-icon cm-chev\")}\n </button>\n {open && (\n <Panel className=\"cm-menu cm-flyout\" flyoutId={node.id} style={flyStyle} onClose={closeFlyout}>\n <FlyoutBody node={node} flyRef={flyRef} side={env.flyout === \"absolute\" ? side : undefined} />\n </Panel>\n )}\n </div>\n );\n}\n\n/** The flyout's rows (kept apart so the panel element itself is what `flyRef` measures). */\nfunction FlyoutBody({ node, flyRef, side }: { node: ResolvedSubmenu; flyRef: React.RefObject<HTMLDivElement | null>; side: FlyoutSide | undefined }) {\n const ref = useRef<HTMLSpanElement>(null);\n useLayoutEffect(() => {\n const panel = ref.current?.closest<HTMLDivElement>('[role=\"menu\"]') ?? null;\n flyRef.current = panel;\n if (panel && side) panel.setAttribute(\"data-side\", side);\n });\n return (\n <>\n <span ref={ref} hidden />\n {node.loading && node.children.length === 0 ? (\n <div className=\"cm-empty\">Loading…</div>\n ) : node.children.length === 0 ? (\n <div className=\"cm-empty\">{node.emptyLabel ?? \"Empty submenu\"}</div>\n ) : (\n <Nodes nodes={node.children} />\n )}\n </>\n );\n}\n"],"mappings":"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","names":["search"]}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
|
+
|
|
3
|
+
// src/engine/utils/menu-deadline.ts
|
|
2
4
|
|
|
3
5
|
|
|
4
|
-
var _chunkCUODNUADcjs = require('./chunk-CUODNUAD.cjs');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
var
|
|
8
|
-
_chunkCUODNUADcjs.__reExport.call(void 0, menu_deadline_exports, menu_deadline_star);
|
|
9
|
-
var _menudeadline = require('@ai-matrx/chat/context-menu/utils/menu-deadline'); var menu_deadline_star = _interopRequireWildcard(_menudeadline);
|
|
7
|
+
|
|
8
|
+
var _menudeadline = require('@ai-matrx/chat/context-menu/utils/menu-deadline');
|
|
10
9
|
|
|
11
10
|
// src/engine/model/requirement-gate.ts
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
var _requirementgate = require('@ai-matrx/chat/context-menu/model/requirement-gate');
|
|
15
21
|
|
|
16
22
|
// src/engine/utils/already-here.ts
|
|
17
23
|
var SAVE_INTO_WHERE_YOU_ARE = [
|
|
@@ -196,5 +202,14 @@ var MANAGED_CONTEXT_MENU_AGENT_CONFIG = {
|
|
|
196
202
|
|
|
197
203
|
|
|
198
204
|
|
|
199
|
-
|
|
200
|
-
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
exports.MENU_LIBRARY_DEADLINE_MS = _menudeadline.MENU_LIBRARY_DEADLINE_MS; exports.MenuLibraryTimeoutError = _menudeadline.MenuLibraryTimeoutError; exports.withMenuDeadline = _menudeadline.withMenuDeadline; exports.GLOBAL_SCOPE = _requirementgate.GLOBAL_SCOPE; exports.buildAvailableKeys = _requirementgate.buildAvailableKeys; exports.decideOffer = _requirementgate.decideOffer; exports.domainOfSurfaceName = _requirementgate.domainOfSurfaceName; exports.readMenuScope = _requirementgate.readMenuScope; exports.requirementsOf = _requirementgate.requirementsOf; exports.scopeReaches = _requirementgate.scopeReaches; exports.writeMenuScope = _requirementgate.writeMenuScope; exports.actionsAlreadyHere = actionsAlreadyHere; exports.buildJsonMenuSection = buildJsonMenuSection; exports.jsonSectionLabel = jsonSectionLabel; exports.fieldLabelOf = fieldLabelOf; exports.mergeFieldName = mergeFieldName; exports.FIELD_PREVIEW_MAX = FIELD_PREVIEW_MAX; exports.fieldPreview = fieldPreview; exports.MANAGED_CONTEXT_MENU_AGENT_CONFIG = MANAGED_CONTEXT_MENU_AGENT_CONFIG;
|
|
215
|
+
//# sourceMappingURL=chunk-7TIZAANU.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/context-menu/dist/chunk-7TIZAANU.cjs","../src/engine/utils/menu-deadline.ts","../src/engine/model/requirement-gate.ts","../src/engine/utils/already-here.ts","../src/engine/utils/json-menu-actions.ts","../src/engine/utils/field-menu-header.ts","../src/engine/managed-agent-launch.ts"],"names":[],"mappings":"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ACM,QAAA;AACJ,QAAA;AACA,QAAA;AACA,QAAA;AACD,MAAA;AACH,IAAA;AACF,EAAA;AAEI,EAAA;AACK,EAAA;AACX;AAGgB;AACN,EAAA;AACH,EAAA;AACK,EAAA;AACJ,EAAA;AACC,EAAA;AACT;AJjDY;AACA;AK3II;AACT,EAAA;AACC,EAAA;AACA,EAAA;AACI,EAAA;AACJ,EAAA;AACF,EAAA;AACI,IAAA;AAIF,IAAA;AACN,EAAA;AACM,EAAA;AACF,EAAA;AACI,IAAA;AACF,IAAA;AACN,EAAA;AACM,EAAA;AACI,EAAA;AACF,IAAA;AACF,IAAA;AACN,EAAA;AACO,EAAA;AACT;AAEM;AAGU;AACR,EAAA;AACC,EAAA;AACT;AAEa;AAMG;AACR,EAAA;AACD,EAAA;AACC,EAAA;AACC,EAAA;AACT;ALiIY;AACA;AMnLC;AACX,EAAA;AACA,EAAA;AACA,EAAA;AACF;ANqLY;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/aidream/aidream/apps/shared/context-menu/dist/chunk-7TIZAANU.cjs","sourcesContent":[null,"// Named, never `export *`: the bundler (esbuild) cannot see through a nested\n// `export * from \"<external>\"`, so the names went missing from the ESM entry and\n// every internal reader went through a runtime namespace copy (a TDZ under ts-jest).\nexport {\n MENU_LIBRARY_DEADLINE_MS,\n MenuLibraryTimeoutError,\n withMenuDeadline,\n} from \"@ai-matrx/chat/context-menu/utils/menu-deadline\";\n","// Named, never `export *`: the bundler (esbuild) cannot see through a nested\n// `export * from \"<external>\"`, so the names went missing from the ESM entry and\n// every internal reader went through a runtime namespace copy (a TDZ under ts-jest).\nexport {\n GLOBAL_SCOPE,\n buildAvailableKeys,\n decideOffer,\n domainOfSurfaceName,\n readMenuScope,\n requirementsOf,\n scopeReaches,\n writeMenuScope,\n} from \"@ai-matrx/chat/context-menu/model/requirement-gate\";\nexport type {\n AvailableKeysArgs,\n GateableItem,\n MenuScope,\n MenuScopeLevel,\n OfferContext,\n OfferDecision,\n OfferRefusal,\n} from \"@ai-matrx/chat/context-menu/model/requirement-gate\";\n","// features/context-menu-v3/utils/already-here.ts\n//\n// ACTIONS THAT TARGET THE THING YOU ARE ALREADY IN ARE ABSENT (page-pass\n// 2026-09-27, /notes/<id>): the menu inside a note offered \"Save to Notes\", and\n// the menu inside the editor offered \"Edit content\" and \"Open in full-screen\n// editor\". Each rich-document action id listed here is excluded for the menu\n// instance that is already that place.\n\nexport interface WhereTheMenuIs {\n /** The rich-document source type (`note`, `task`, `chat-message`, `raw`, …). */\n sourceType: string;\n /** The registry surface the menu belongs to. */\n surfaceName?: string | null | undefined;\n /** The menu wraps an editor (EditableContextMenu). */\n isEditable: boolean;\n}\n\n/** \"Save to X\" where the menu already IS an X. */\nconst SAVE_INTO_WHERE_YOU_ARE: ReadonlyArray<{ sourceType: string; surface: string; actionId: string }> = [\n { sourceType: \"note\", surface: \"matrx-user/notes\", actionId: \"save-to-notes\" },\n { sourceType: \"task\", surface: \"matrx-user/tasks\", actionId: \"save-to-task\" },\n];\n\n/** Opening a window from inside that same window (surface-only rules). */\nconst OPEN_WHERE_YOU_ARE: ReadonlyArray<{ surface: string; actionId: string }> = [\n // The Feedback window's menus offered \"Submit feedback\" — reopening itself.\n { surface: \"matrx-user/feedback\", actionId: \"submit-feedback\" },\n];\n\n/** Opening an editor from inside the editor. */\nconst EDITOR_DOORS = [\"edit\", \"open-fullscreen-editor\"] as const;\n\nexport function actionsAlreadyHere(where: WhereTheMenuIs): string[] {\n const out: string[] = [];\n for (const rule of SAVE_INTO_WHERE_YOU_ARE) {\n if (where.sourceType === rule.sourceType || where.surfaceName === rule.surface) out.push(rule.actionId);\n }\n for (const rule of OPEN_WHERE_YOU_ARE) {\n if (where.surfaceName === rule.surface) out.push(rule.actionId);\n }\n // On a record's OWN page (a note's source on the notes surface) the page is\n // its editor — its Write / Read toggle is the door — so the preview offers no\n // second one (live 2026-09-27, /notes/<id> in Read mode). Editor and preview\n // menus now carry the same set.\n // Matched by the SOURCE as well as the surface: live, the Read-mode menu on\n // /notes/<id> carried the note source under a surface name other than the\n // notes one, so a surface-only match missed it.\n const ownPage = SAVE_INTO_WHERE_YOU_ARE.some(\n (rule) => where.sourceType === rule.sourceType || where.surfaceName === rule.surface,\n );\n if (where.isEditable || ownPage) out.push(...EDITOR_DOORS);\n return [...new Set(out)];\n}\n","// features/context-menu-v3/utils/json-menu-actions.ts\n//\n// The JSON section of the universal context menu. Highlight something that\n// looks like JSON — fenced or bare — and the menu offers the things you\n// actually want for JSON: condense it, squeeze it onto one line, open it back\n// up, sort its keys, add or strip the code fence.\n//\n// Design rules:\n// - The menu ASKS the engine, it does not sniff. Detection and formatting\n// both come from `lib/json-format` (the shared primitive), so the notes\n// cleanup pass and this menu can never disagree about what \"condensed\"\n// means.\n// - Every action carries a REAL before/after hint (\"13 lines -> 3 lines\"),\n// computed from the actual formatted output. No action promises a change\n// it will not make: one that would be a no-op is dropped.\n// - On an EDITABLE surface the action rewrites the text in place (the exact\n// selection when there is one, the whole field otherwise). On a read-only\n// surface it copies the formatted text instead — the same intent, the only\n// verb available.\n// - Unparseable-but-JSON-shaped text still produces a section: one disabled\n// row carrying the parse error. Silently showing nothing on a selection\n// the user clearly believes is JSON is the \"fake menu\" failure this\n// codebase kills on sight.\n//\n// Pure except for the two side-effect callbacks handed in by the hook.\n\nimport { detectJson } from \"@ai-matrx/kit/json-format\";\nimport { formatJsonText } from \"@ai-matrx/kit/json-format\";\nimport type {\n JsonDetection,\n JsonFenceMode,\n JsonFormatStyle,\n} from \"@ai-matrx/kit/json-format\";\n\nexport interface JsonMenuAction {\n id: string;\n label: string;\n /** Real before -> after size, e.g. \"13 lines -> 3 lines\". */\n hint?: string | undefined;\n disabled?: boolean | undefined;\n run: () => void | Promise<void>;\n}\n\nexport interface JsonMenuSection {\n /** The detection that produced this section (null when the text isn't JSON-ish). */\n detection: JsonDetection;\n /** True when the surface will rewrite text; false when actions copy instead. */\n writes: boolean;\n actions: JsonMenuAction[];\n}\n\nexport interface BuildJsonMenuActionsParams {\n /** The text the menu is acting on (selection, else resolved content). */\n text: string;\n /** True when the action should REWRITE the text rather than copy it. */\n canWrite: boolean;\n /** Rewrite the acted-on text with `next`. Only called when `canWrite`. */\n onReplace: (next: string) => void;\n /** Copy `next` to the clipboard. Used on read-only surfaces. */\n onCopy: (next: string) => void | Promise<void>;\n}\n\nfunction lineCount(text: string): number {\n let n = text === \"\" ? 0 : 1;\n for (let i = 0; i < text.length; i++) if (text[i] === \"\\n\") n++;\n return n;\n}\n\nfunction sizeHint(before: string, after: string): string {\n const b = lineCount(before);\n const a = lineCount(after);\n if (b !== a) {\n return `${b} line${b !== 1 ? \"s\" : \"\"} -> ${a} line${a !== 1 ? \"s\" : \"\"}`;\n }\n return `${before.length} -> ${after.length} chars`;\n}\n\n/**\n * The style that preserves the user's rough layout — used by actions whose\n * point is NOT re-layout (sort keys, fence toggling). Re-printing a hand-\n * formatted blob as something else because the user asked to sort its keys is\n * a change they did not request.\n */\nfunction shapePreservingStyle(detection: JsonDetection): JsonFormatStyle {\n return detection.payload.includes(\"\\n\") ? \"pretty\" : \"minify\";\n}\n\n/**\n * Build the JSON section for the given text, or `null` when the text is not\n * JSON-shaped at all (the overwhelmingly common case — the section simply\n * does not render).\n */\nexport function buildJsonMenuSection(\n params: BuildJsonMenuActionsParams,\n): JsonMenuSection | null {\n const { text, canWrite, onReplace, onCopy } = params;\n if (!text.trim()) return null;\n\n const detection = detectJson(text);\n if (!detection.looksLikeJson) return null;\n\n // JSON-shaped but broken: one honest, disabled row.\n if (!detection.ok) {\n return {\n detection,\n writes: false,\n actions: [\n {\n id: \"json-invalid\",\n label: \"Invalid JSON\",\n hint: detection.error,\n disabled: true,\n run: () => {},\n },\n ],\n };\n }\n\n const apply = (next: string) => {\n if (canWrite) onReplace(next);\n else void onCopy(next);\n };\n\n const verb = canWrite ? \"\" : \"Copy \";\n const actions: JsonMenuAction[] = [];\n\n const addFormat = (\n id: string,\n label: string,\n style: JsonFormatStyle,\n fence: JsonFenceMode = \"preserve\",\n sortKeys = false,\n ) => {\n const result = formatJsonText(text, { style, fence, sortKeys });\n if (!result.ok) return;\n // Copying an identical string is still useful; rewriting it is not.\n if (canWrite && !result.changed) return;\n actions.push({\n id,\n label,\n hint: result.changed ? sizeHint(text, result.text) : undefined,\n run: () => apply(result.text),\n });\n };\n\n addFormat(\"json-condense\", `${verb}Condense`, \"compact\");\n addFormat(\"json-minify\", `${verb}Minify (one line)`, \"minify\");\n addFormat(\"json-expand\", `${verb}Expand`, \"pretty\");\n addFormat(\n \"json-sort-keys\",\n `${verb}Sort keys A-Z`,\n shapePreservingStyle(detection),\n \"preserve\",\n true,\n );\n\n // Fence toggle — only the direction that applies.\n if (detection.fence) {\n addFormat(\n \"json-strip-fence\",\n `${verb}Remove code fence`,\n shapePreservingStyle(detection),\n \"strip\",\n );\n } else {\n addFormat(\n \"json-add-fence\",\n `${verb}Wrap in json code fence`,\n shapePreservingStyle(detection),\n \"add\",\n );\n }\n\n // An editable surface still benefits from a plain \"give me the one-liner on\n // the clipboard\" that does NOT touch the document.\n if (canWrite) {\n const minified = formatJsonText(text, { style: \"minify\", fence: \"strip\" });\n if (minified.ok) {\n actions.push({\n id: \"json-copy-minified\",\n label: \"Copy minified\",\n hint: sizeHint(text, minified.text),\n run: () => void onCopy(minified.text),\n });\n }\n }\n\n if (actions.length === 0) return null;\n return { detection, writes: canWrite, actions };\n}\n\n/** Short label for the submenu trigger, e.g. \"JSON · 13 lines\". */\nexport function jsonSectionLabel(section: JsonMenuSection): string {\n const { detection } = section;\n if (!detection.ok) return \"JSON (invalid)\";\n const n = detection.lineCount;\n const kind = detection.root === \"array\" ? \"array\" : \"object\";\n return `JSON ${kind} · ${n} line${n !== 1 ? \"s\" : \"\"}`;\n}\n","/**\n * THE MENU OPENED IN A FIELD NAMES THE FIELD (page-pass 2026-09-27,\n * /chat/message-templates/<id>). Right-clicking the Body box headed the menu\n * \"Content: {{reply.body}}\" — the field's raw text. The header is now the\n * field's own name (\"Body\"), with a short plain preview only when it helps:\n * merge fields read as their names (\"Reply body\"), and text that is ONLY merge\n * fields gets no preview (the name already says it). Pure, so it is tested\n * without a DOM menu.\n */\n\n/** A field's name, the way a person reads it on screen. `null` when it has none. */\nexport function fieldLabelOf(element: Element | null | undefined): string | null {\n if (!element) return null;\n const clean = (s: string | null | undefined) => (s ?? \"\").replace(/\\s+/g, \" \").replace(/\\s*\\*$/, \"\").trim() || null;\n const aria = clean(element.getAttribute(\"aria-label\"));\n if (aria) return aria;\n const labelledBy = element.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const text = labelledBy\n .split(/\\s+/)\n .map((id) => element.ownerDocument?.getElementById(id)?.textContent ?? \"\")\n .join(\" \");\n if (clean(text)) return clean(text);\n }\n const labels = (element as HTMLInputElement).labels;\n if (labels && labels.length > 0) {\n const text = clean(labels[0]?.textContent);\n if (text) return text;\n }\n const id = element.getAttribute(\"id\");\n if (id && element.ownerDocument) {\n const label = element.ownerDocument.querySelector(`label[for=\"${CSS.escape(id)}\"]`);\n if (clean(label?.textContent)) return clean(label?.textContent);\n }\n return null;\n}\n\nconst MERGE_FIELD = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\n/** \"reply.body\" / \"reply_body\" → \"Reply body\". */\nexport function mergeFieldName(token: string): string {\n const words = token.replace(/[._-]+/g, \" \").replace(/([a-z])([A-Z])/g, \"$1 $2\").trim().toLowerCase();\n return words ? words[0]!.toUpperCase() + words.slice(1) : token;\n}\n\nexport const FIELD_PREVIEW_MAX = 60;\n\n/**\n * The preview beside the field's name: plain words with merge fields named,\n * clipped; `\"\"` when the text holds nothing but merge fields (or nothing).\n */\nexport function fieldPreview(text: string): string {\n const withoutFields = text.replace(MERGE_FIELD, \"\").replace(/[\\s\\p{P}]+/gu, \"\");\n if (!withoutFields) return \"\";\n const readable = text.replace(MERGE_FIELD, (_, name: string) => mergeFieldName(name)).replace(/\\s+/g, \" \").trim();\n return readable.length > FIELD_PREVIEW_MAX ? `${readable.slice(0, FIELD_PREVIEW_MAX - 1).trimEnd()}…` : readable;\n}\n","import type { AgentExecutionConfig } from \"@ai-matrx/chat/agents/types/agent-execution-config.types\";\n\n/**\n * Framework-owned launch defaults for agents listed in the managed \"Agents\"\n * context-menu section. Shortcuts do not use this config: their persisted\n * execution definitions remain authoritative.\n */\nexport const MANAGED_CONTEXT_MENU_AGENT_CONFIG = {\n displayMode: \"flexible-panel\",\n allowChat: true,\n showVariablePanel: true,\n} as const satisfies Pick<\n AgentExecutionConfig,\n \"displayMode\" | \"allowChat\" | \"showVariablePanel\"\n>;\n"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
CONTEXT_MENU_ENTITY_KEY,
|
|
4
|
+
CONTEXT_MENU_HEADING_KEY,
|
|
5
|
+
compact
|
|
6
|
+
} from "./chunk-SJWKMZEJ.js";
|
|
6
7
|
|
|
7
8
|
// src/engine/table-row-item.ts
|
|
8
9
|
import { TABLE_ROW_ITEM } from "@ai-matrx/alchemy/declare";
|
|
@@ -108,12 +109,12 @@ function resolveTableRowMenuDescriptor(target) {
|
|
|
108
109
|
function headedMenu(descriptor, target, row) {
|
|
109
110
|
const cell = target?.closest("td, [role='gridcell']");
|
|
110
111
|
const shown = shownWords(cell ?? row);
|
|
111
|
-
const ownHeading = descriptor.context[
|
|
112
|
+
const ownHeading = descriptor.context[CONTEXT_MENU_HEADING_KEY];
|
|
112
113
|
const recordName = ownHeading ? "" : rowRecordName(row);
|
|
113
114
|
const context = {
|
|
114
115
|
...descriptor.context,
|
|
115
116
|
...shown ? { content: shown } : {},
|
|
116
|
-
...recordName ? { [
|
|
117
|
+
...recordName ? { [CONTEXT_MENU_HEADING_KEY]: { label: "Row", text: recordName } } : {}
|
|
117
118
|
};
|
|
118
119
|
const headed = ownHeading?.text ?? recordName;
|
|
119
120
|
const same = (label) => typeof headed === "string" && !!label && label.trim().toLowerCase() === headed.trim().toLowerCase();
|
|
@@ -207,14 +208,14 @@ function openRecordMenu(key, anchor) {
|
|
|
207
208
|
// src/engine/utils/per-row-entity.ts
|
|
208
209
|
var isDev = process.env.NODE_ENV !== "production";
|
|
209
210
|
function resolveEffectiveEntity(entityProp, resolved) {
|
|
210
|
-
if (!resolved || !(
|
|
211
|
-
const perRow = resolved[
|
|
211
|
+
if (!resolved || !(CONTEXT_MENU_ENTITY_KEY in resolved)) return entityProp;
|
|
212
|
+
const perRow = resolved[CONTEXT_MENU_ENTITY_KEY];
|
|
212
213
|
if (perRow === null || perRow === void 0) return void 0;
|
|
213
214
|
const candidate = perRow;
|
|
214
215
|
if (typeof perRow !== "object" || typeof candidate.type !== "string" || !candidate.type || typeof candidate.id !== "string" || !candidate.id) {
|
|
215
216
|
if (isDev) {
|
|
216
217
|
console.error(
|
|
217
|
-
`%c[ContextMenuV3] MALFORMED PER-ROW ENTITY%c \u2014 resolveContextOnOpen returned "${
|
|
218
|
+
`%c[ContextMenuV3] MALFORMED PER-ROW ENTITY%c \u2014 resolveContextOnOpen returned "${CONTEXT_MENU_ENTITY_KEY}" without a string type + id, so Attach To / Share would target nothing. Falling back to the menu-level entity.`,
|
|
218
219
|
"color:#ef4444;font-weight:bold",
|
|
219
220
|
"color:inherit",
|
|
220
221
|
{ received: perRow }
|
|
@@ -229,17 +230,17 @@ function mergeResolvedContextData(contextData, resolved) {
|
|
|
229
230
|
...contextData ?? {},
|
|
230
231
|
...resolved ?? {}
|
|
231
232
|
};
|
|
232
|
-
delete merged[
|
|
233
|
+
delete merged[CONTEXT_MENU_ENTITY_KEY];
|
|
233
234
|
return merged;
|
|
234
235
|
}
|
|
235
236
|
function joinRowAndSurfaceContext(row, surface) {
|
|
236
237
|
if (!row) return surface ?? null;
|
|
237
238
|
if (!surface) return row;
|
|
238
|
-
const rowNamesEntity = row[
|
|
239
|
+
const rowNamesEntity = row[CONTEXT_MENU_ENTITY_KEY] !== null && row[CONTEXT_MENU_ENTITY_KEY] !== void 0;
|
|
239
240
|
return {
|
|
240
241
|
...surface,
|
|
241
242
|
...row,
|
|
242
|
-
...!rowNamesEntity &&
|
|
243
|
+
...!rowNamesEntity && CONTEXT_MENU_ENTITY_KEY in surface ? { [CONTEXT_MENU_ENTITY_KEY]: surface[CONTEXT_MENU_ENTITY_KEY] } : {}
|
|
243
244
|
};
|
|
244
245
|
}
|
|
245
246
|
var TOKEN_SHAPE = /^[a-z][a-z0-9_]*$/;
|
|
@@ -270,7 +271,7 @@ function sniffEntityFromDom(target) {
|
|
|
270
271
|
};
|
|
271
272
|
}
|
|
272
273
|
function resolveEffectiveEntityWithDom(entityProp, resolved, target) {
|
|
273
|
-
const surfaceSpoke = !!resolved &&
|
|
274
|
+
const surfaceSpoke = !!resolved && CONTEXT_MENU_ENTITY_KEY in resolved;
|
|
274
275
|
if (surfaceSpoke) return resolveEffectiveEntity(entityProp, resolved);
|
|
275
276
|
return sniffEntityFromDom(target) ?? entityProp;
|
|
276
277
|
}
|
|
@@ -595,4 +596,4 @@ export {
|
|
|
595
596
|
CONTEXT_MENU_SELECTION_HOST_KEY,
|
|
596
597
|
contextMenuSelectionProvider
|
|
597
598
|
};
|
|
598
|
-
//# sourceMappingURL=chunk-
|
|
599
|
+
//# sourceMappingURL=chunk-EG23Y2KW.js.map
|