@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
package/dist/react.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
subscribeRecordMenus,
|
|
17
17
|
tableTextAtTarget,
|
|
18
18
|
toastPromise
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-EG23Y2KW.js";
|
|
20
20
|
import {
|
|
21
21
|
MenuRegroupContext,
|
|
22
22
|
MenuRegroupProvider,
|
|
@@ -24,16 +24,24 @@ import {
|
|
|
24
24
|
} from "./chunk-GJG2XEYY.js";
|
|
25
25
|
import "./chunk-FFIJ4TF4.js";
|
|
26
26
|
import {
|
|
27
|
+
CONTEXT_MENU_ENTITY_KEY,
|
|
28
|
+
CONTEXT_MENU_HEADING_KEY,
|
|
29
|
+
DEFAULT_MENU_DENSITY,
|
|
30
|
+
DEFAULT_MENU_LAYOUT,
|
|
31
|
+
captureDomSelection,
|
|
32
|
+
captureTextareaSelection,
|
|
27
33
|
compact,
|
|
34
|
+
extractElementText,
|
|
28
35
|
findComboMatch,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
getEditableSelectionOffsets,
|
|
37
|
+
getSelectionRect,
|
|
38
|
+
restoreDomSelection,
|
|
39
|
+
restoreTextareaSelection
|
|
40
|
+
} from "./chunk-SJWKMZEJ.js";
|
|
32
41
|
import {
|
|
33
42
|
getContextMenuHost,
|
|
34
43
|
loadContextMenuHost
|
|
35
44
|
} from "./chunk-5CSJ4Y3X.js";
|
|
36
|
-
import "./chunk-PE3ZHHM5.js";
|
|
37
45
|
|
|
38
46
|
// src/engine/ContextMenuV3.tsx
|
|
39
47
|
import React, { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
@@ -259,8 +267,8 @@ function ContextMenuV3({
|
|
|
259
267
|
scope = "global",
|
|
260
268
|
scopeId = null,
|
|
261
269
|
className,
|
|
262
|
-
menuLayout =
|
|
263
|
-
menuDensity =
|
|
270
|
+
menuLayout = DEFAULT_MENU_LAYOUT,
|
|
271
|
+
menuDensity = DEFAULT_MENU_DENSITY,
|
|
264
272
|
menuDesign,
|
|
265
273
|
menuFeatureTitle,
|
|
266
274
|
suppressed = false,
|
|
@@ -339,7 +347,7 @@ function ContextMenuV3({
|
|
|
339
347
|
contextData,
|
|
340
348
|
resolvedContext
|
|
341
349
|
);
|
|
342
|
-
const surfaceSpokeAboutEntity = !!resolvedContext &&
|
|
350
|
+
const surfaceSpokeAboutEntity = !!resolvedContext && CONTEXT_MENU_ENTITY_KEY in resolvedContext;
|
|
343
351
|
const effectiveEntity = surfaceSpokeAboutEntity ? resolveEffectiveEntity(entity, resolvedContext) : sniffedEntity ?? entity;
|
|
344
352
|
useEffect(() => {
|
|
345
353
|
if (!engaged) return;
|
|
@@ -362,11 +370,11 @@ function ContextMenuV3({
|
|
|
362
370
|
resolvePerTargetContext(target);
|
|
363
371
|
selectionLocked.current = true;
|
|
364
372
|
if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement) {
|
|
365
|
-
const captured =
|
|
373
|
+
const captured = captureTextareaSelection(target);
|
|
366
374
|
capturedSelection.current = captured;
|
|
367
375
|
setSelectedText(captured.text);
|
|
368
376
|
} else {
|
|
369
|
-
const captured =
|
|
377
|
+
const captured = captureDomSelection();
|
|
370
378
|
capturedSelection.current = captured;
|
|
371
379
|
setSelectedText(captured.text);
|
|
372
380
|
}
|
|
@@ -401,15 +409,15 @@ function ContextMenuV3({
|
|
|
401
409
|
captured = null;
|
|
402
410
|
}
|
|
403
411
|
if (!captured || !captured.text) {
|
|
404
|
-
captured = target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement ?
|
|
412
|
+
captured = target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement ? captureTextareaSelection(target) : captureDomSelection();
|
|
405
413
|
capturedSelection.current = captured;
|
|
406
414
|
selectionLocked.current = true;
|
|
407
415
|
}
|
|
408
416
|
if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement) {
|
|
409
417
|
const remembered = captured?.editable && captured.editable.element === target && captured.editable.start !== captured.editable.end ? captured.editable : null;
|
|
410
|
-
const { start, end } = remembered ??
|
|
418
|
+
const { start, end } = remembered ?? getEditableSelectionOffsets(target);
|
|
411
419
|
if (remembered) {
|
|
412
|
-
const live =
|
|
420
|
+
const live = getEditableSelectionOffsets(target);
|
|
413
421
|
if (live.start !== start || live.end !== end) {
|
|
414
422
|
try {
|
|
415
423
|
target.setSelectionRange(start, end);
|
|
@@ -448,7 +456,7 @@ function ContextMenuV3({
|
|
|
448
456
|
range: captured?.range || null,
|
|
449
457
|
containerElement
|
|
450
458
|
});
|
|
451
|
-
setFallbackContent(
|
|
459
|
+
setFallbackContent(extractElementText(containerElement));
|
|
452
460
|
}
|
|
453
461
|
};
|
|
454
462
|
const handleContextMenu = (e) => {
|
|
@@ -474,10 +482,10 @@ function ContextMenuV3({
|
|
|
474
482
|
if (selectionRange.type === "editable") {
|
|
475
483
|
const { element, start, end } = selectionRange;
|
|
476
484
|
if (element instanceof HTMLTextAreaElement || element instanceof HTMLInputElement) {
|
|
477
|
-
|
|
485
|
+
restoreTextareaSelection(element, start, end);
|
|
478
486
|
}
|
|
479
487
|
} else if (selectionRange.range) {
|
|
480
|
-
|
|
488
|
+
restoreDomSelection(selectionRange.range);
|
|
481
489
|
}
|
|
482
490
|
};
|
|
483
491
|
const handleDropdownClose = (open) => {
|
|
@@ -494,7 +502,7 @@ function ContextMenuV3({
|
|
|
494
502
|
const sel = window.getSelection();
|
|
495
503
|
const container = sel && sel.rangeCount > 0 ? sel.getRangeAt(0).commonAncestorContainer.parentElement ?? null : null;
|
|
496
504
|
resolvePerTargetContext(container);
|
|
497
|
-
setFallbackContent(
|
|
505
|
+
setFallbackContent(extractElementText(container));
|
|
498
506
|
if (isMobile) {
|
|
499
507
|
setSelectedText(sel?.toString().trim() || selectedText);
|
|
500
508
|
setSelectionRange({
|
|
@@ -510,7 +518,7 @@ function ContextMenuV3({
|
|
|
510
518
|
setSheetOpen(true);
|
|
511
519
|
return;
|
|
512
520
|
}
|
|
513
|
-
const rect =
|
|
521
|
+
const rect = getSelectionRect();
|
|
514
522
|
const at = rect ? { x: rect.left, y: rect.bottom + 4 } : lastMousePos.current ?? { x: 16, y: 16 };
|
|
515
523
|
setMenuPoint(at);
|
|
516
524
|
markMenuOpen();
|
|
@@ -818,12 +826,12 @@ function ContextMenuV3({
|
|
|
818
826
|
}
|
|
819
827
|
function recordHeadingAt(target, _revision) {
|
|
820
828
|
return readContextMenuHeading({
|
|
821
|
-
[
|
|
829
|
+
[CONTEXT_MENU_HEADING_KEY]: resolveRecordMenu(target)?.heading ?? null
|
|
822
830
|
});
|
|
823
831
|
}
|
|
824
832
|
function readContextMenuHeading(resolved) {
|
|
825
833
|
if (!resolved || typeof resolved !== "object") return null;
|
|
826
|
-
const heading = resolved[
|
|
834
|
+
const heading = resolved[CONTEXT_MENU_HEADING_KEY];
|
|
827
835
|
if (!heading || typeof heading !== "object") return null;
|
|
828
836
|
const { label, text } = heading;
|
|
829
837
|
return typeof label === "string" && typeof text === "string" && label.trim() ? { label: label.trim(), text } : null;
|
|
@@ -893,11 +901,11 @@ function ItemContextMenuV3({
|
|
|
893
901
|
const item = resolveItemOnOpen?.(target);
|
|
894
902
|
setResolved(resolveItemMenuConfig(item?.config ?? config));
|
|
895
903
|
const context = item?.context ?? null;
|
|
896
|
-
if (entity?.title && !(context && context[
|
|
904
|
+
if (entity?.title && !(context && context[CONTEXT_MENU_HEADING_KEY])) {
|
|
897
905
|
const type = String(entity.type ?? "Item").replace(/[_-]+/g, " ");
|
|
898
906
|
return {
|
|
899
907
|
...context ?? {},
|
|
900
|
-
[
|
|
908
|
+
[CONTEXT_MENU_HEADING_KEY]: {
|
|
901
909
|
label: type.charAt(0).toUpperCase() + type.slice(1),
|
|
902
910
|
text: entity.title
|
|
903
911
|
}
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine/ContextMenuV3.tsx","../src/engine/menu-presence.tsx","../src/engine/EditableContextMenu.tsx","../src/engine/NonEditableContextMenu.tsx","../src/engine/PageSurfaceMenu.tsx","../src/engine/item/ItemMenuHostBinding.tsx","../src/engine/item/ItemContextMenuV3.tsx","../src/engine/components/OpenSurfaceMenuButton.tsx"],"sourcesContent":["\"use client\";\n\n// features/context-menu-v3/ContextMenuV3.tsx\n//\n// The INERT shell. Mounted on every surface that wants a context menu, it must\n// stay near-empty on render — 99% of surface renders never open the menu, and\n// they must pay almost nothing. The shell contains ONLY:\n// - the Radix ContextMenu trigger wrapping the surface's children,\n// - lightweight selection capture (the hard-won macOS-safe logic),\n// - the DOM-text fallback capture that makes Copy/AI work with zero wiring,\n// - the floating-icon button + open state,\n//\n// On the FIRST open it renders `MenuContent` via next/dynamic({ssr:false}).\n// MenuContent owns ALL the weight — the unified-menu + bound-agent hooks (which\n// fire the single, deduped fetch on its mount), the launchers, the handlers,\n// the react-icons resolver, and every submenu. Every modal/window MenuContent\n// needs is dispatched through the OverlayController, so the shell carries zero\n// modal code. See `FEATURE.md` and the `code-splitting` skill.\n\nimport { compact } from \"./utils/compact\";\nimport React, { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { useIsMobile } from \"@ai-matrx/kit/media-query\";\nimport { useSelectionZone } from \"@ai-matrx/rich-content/selection-toolbar/selection-zones\";\nimport {\n CONTEXT_MENU_SELECTION_HOST_KEY,\n type ContextMenuSelectionHost,\n} from \"./selection-provider\";\nimport {\n captureTextareaSelection,\n getEditableSelectionOffsets,\n captureDomSelection,\n getSelectionRect,\n restoreTextareaSelection,\n restoreDomSelection,\n extractElementText,\n type CapturedSelection,\n type SelectionRange,\n} from \"./utils/selection-tracking\";\nimport {\n DEFAULT_MENU_DENSITY,\n DEFAULT_MENU_LAYOUT,\n type ContextMenuV3Props,\n type MenuContentProps,\n type ResolvedContextMenuContext,\n CONTEXT_MENU_ENTITY_KEY,\n CONTEXT_MENU_HEADING_KEY,\n type ContextMenuHeading,\n type ContextMenuEntityRef,\n} from \"./types\";\nimport {\n joinRowAndSurfaceContext,\n mergeResolvedContextData,\n resolveEffectiveEntity,\n sniffEntityFromDom,\n} from \"./utils/per-row-entity\";\nimport { MenuPresenceProvider, RegistryMenuSourceProvider, contentSourceKey } from \"./menu-presence\";\n\nimport { useOptionalWidgetHandle } from \"@ai-matrx/chat/agents/hooks/useWidgetHandle\";\nimport { buildEditableWidgetHandle } from \"./utils/widget-handle\";\nimport { resolveTableRowItem } from \"./table-row-item\";\nimport type { ResolvedItem } from \"@ai-matrx/alchemy/declare\";\nimport { recordMenusRevision, resolveRecordMenu, subscribeRecordMenus } from \"./record-menu-registry\";\nimport { joinExtraSections } from \"./utils/join-extra-sections\";\nimport { CONTEXT_REGION_TRIGGER_ATTRS } from \"./region-trigger-attrs\";\nimport { preloadTableShape, tableTextAtTarget } from \"./utils/table-at-target\";\nimport { findComboMatch } from \"./utils/key-combo\";\nimport { ReactReduxContext } from \"react-redux\";\nimport type { ChatAppStore as AppStore, ChatDispatch } from \"@ai-matrx/chat/store/root-state\";\nimport { getContextMenuHost, loadContextMenuHost } from \"./host/port\";\nimport { selectAllShortcutsArray } from \"@ai-matrx/chat/agents/redux/agent-shortcuts/selectors\";\n\n/**\n * Text-entry targets whose NATIVE menu we must never steal.\n *\n * A read-only menu (`isEditable === false`) offers Copy and AI actions; it\n * offers no Paste, no Undo, no spellcheck, no autofill — everything a user\n * right-clicks a live text field FOR. Swallowing that gesture makes the field\n * strictly less capable than an unwrapped one. Editable surfaces are the\n * opposite case: they wire text mutation into the menu deliberately, so they\n * keep it.\n *\n * Non-text `<input>` types (checkbox, button, range…) have no native text menu\n * to protect, so the record menu still wins there.\n */\nconst NON_TEXT_INPUT_TYPES = new Set([\n \"button\",\n \"checkbox\",\n \"color\",\n \"file\",\n \"image\",\n \"radio\",\n \"range\",\n \"reset\",\n \"submit\",\n]);\n\n/**\n * A right-click on a live text field inside a READ-ONLY menu: the innermost\n * such shell, recorded in the capture phase so every shell sees the same\n * answer in the bubble phase (see `onContextMenuCapture`).\n */\nconst NATIVE_TEXT_YIELD = new WeakMap<Event, HTMLElement>();\n\nfunction yieldsToNativeTextMenu(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n // A read-only or disabled field is NOT a live text field: its native menu\n // offers no Paste, no spellcheck, no autofill — nothing v3 lacks — so\n // yielding there trades a rich menu for a poorer one. Found live on the\n // notes tab strip (2026-08-29): the active tab's rename <input> swallowed\n // the tab's entire v3 menu even while the user wasn't renaming. Fields that\n // are only sometimes editable should render readOnly until editing intent\n // (e.g. focus) — then the yield correctly returns while they type.\n if (target instanceof HTMLTextAreaElement)\n return !target.readOnly && !target.disabled;\n if (target instanceof HTMLInputElement)\n return (\n !NON_TEXT_INPUT_TYPES.has(target.type) &&\n !target.readOnly &&\n !target.disabled\n );\n return false;\n}\n\n/**\n * A gesture that reached this shell only through a React PORTAL: its target is\n * not in the shell's DOM subtree (an open menu, a dialog or popover rendered by\n * something inside the region). React bubbles portal events to every React\n * ancestor, so a right-click — or a Mac two-finger tap mid-scroll — on an OPEN\n * message menu reached the transcript's shell around it, which opened the page\n * menu over it with both engines mounted: 18 `DuplicateActionError`s and \"the\n * menu swapped\" (blind run PB-06, /chat, 2026-10-01). A portal surface that\n * wants a menu mounts its own.\n */\nexport function reachedThroughPortal(e: { target: EventTarget | null; currentTarget: EventTarget | null }): boolean {\n const { target, currentTarget } = e;\n return target instanceof Node && currentTarget instanceof Node && !currentTarget.contains(target);\n}\n\n/** The moment a menu opens, for Inspect's open-to-paint timing (designed/DesignedMenu marks the paint). */\nfunction markMenuOpen(): void {\n try {\n performance.mark(\"ai-matrx.context-menu.open\");\n } catch {\n /* marks are best-effort */\n }\n}\n\n/** A right-click on an open menu: no native browser menu over ours. */\nfunction isInsideOpenMenu(target: EventTarget | null): boolean {\n return target instanceof Element && Boolean(target.closest('[data-alchemy-layout], [role=\"menu\"]'));\n}\n\n// THE single heavy boundary (T1 + T1e). ssr:false keeps it — the engine hook,\n// the agent fetch, the package renderers — off the server render and out of\n// the shell's chunk; it mounts on first open only. One boundary for the\n// right-click, the floating icon, the phone sheet and the palette (ALC-15 S3:\n// the package draws all four from one registry).\ntype MenuContentModule = typeof import(\"@ai-matrx/context-menu/menu-content\");\nconst MENU_CONTENT_SLOT = Symbol.for(\"ai-matrx.context-menu.menu-content\");\ntype MenuContentSlot = { module: MenuContentModule | null; warm: Promise<unknown> | null };\nfunction menuContentSlot(): MenuContentSlot {\n const g = globalThis as unknown as Record<symbol, MenuContentSlot | undefined>;\n return (g[MENU_CONTENT_SLOT] ??= { module: null, warm: null });\n}\nfunction loadMenuContent(): Promise<MenuContentModule> {\n // The host's heavier members (`loadOnOpen`) arrive WITH the body, never at boot.\n return Promise.all([import(\"@ai-matrx/context-menu/menu-content\"), loadContextMenuHost()]).then(([m]) => {\n menuContentSlot().module = m;\n return m;\n });\n}\n/** The loaded boundary, or null until it arrives (renders nothing meanwhile, like ssr:false). */\nfunction useMenuContentModule(): MenuContentModule | null {\n const [mod, setMod] = useState<MenuContentModule | null>(() => menuContentSlot().module);\n useEffect(() => {\n if (mod) return;\n let live = true;\n loadMenuContent().then(\n (m) => {\n if (live) setMod(m);\n },\n (error: unknown) => console.error(\"[ContextMenuV3] could not load the menu\", error),\n );\n return () => {\n live = false;\n };\n }, [mod]);\n return mod;\n}\ntype AlchemyMenuContentProps = React.ComponentProps<MenuContentModule[\"AlchemyMenuContent\"]>;\ntype ShortcutKeyRunnerProps = React.ComponentProps<MenuContentModule[\"ShortcutKeyRunner\"]>;\nfunction AlchemyMenuContent(props: AlchemyMenuContentProps) {\n const mod = useMenuContentModule();\n return mod ? <mod.AlchemyMenuContent {...props} /> : null;\n}\n\n/**\n * Warm THAT SAME chunk once per tab, when the browser is idle after the first\n * menu shell mounts — so the first right-click draws at once instead of\n * fetching (and, in dev, compiling) the engine under the pointer (G11A review,\n * 2026-10-07: the first open after a page load took 1–2 s). It is the same\n * specifier as the `dynamic()` above, so it adds no chunk and no boundary\n * (code-splitting rule 3); it only moves WHEN the browser fetches it. The\n * menu still renders only on open.\n */\nexport function warmMenuContent(): Promise<unknown> {\n const slot = menuContentSlot();\n if (!slot.warm) {\n slot.warm = loadMenuContent().catch((error: unknown) => {\n slot.warm = null;\n console.error(\"[ContextMenuV3] could not warm the menu; the first open will load it\", error);\n });\n }\n return menuContentSlot().warm ?? Promise.resolve();\n}\n\n// ── The one selectionchange listener ────────────────────────────────────────\ninterface SelectionTracker {\n owner: () => HTMLElement | null;\n locked: () => boolean;\n set: (text: string) => void;\n}\nconst selectionTrackers = new Set<SelectionTracker>();\n/** Trackers told they own the selection last time — the only ones to clear next time. */\nlet selectionHolders = new Set<SelectionTracker>();\n\nfunction onDocumentSelectionChange(): void {\n const selection = window.getSelection();\n const anchor = selection?.anchorNode ?? null;\n const active = document.activeElement;\n const field = active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement ? active : null;\n const holders = new Set<SelectionTracker>();\n if (anchor || field) {\n for (const tracker of selectionTrackers) {\n const owner = tracker.owner();\n if (!owner) continue;\n if ((anchor != null && owner.contains(anchor)) || (field != null && owner.contains(field))) holders.add(tracker);\n }\n }\n for (const tracker of selectionHolders) {\n if (!holders.has(tracker) && !tracker.locked()) tracker.set(\"\");\n }\n if (holders.size > 0) {\n // A collapsed selection (a caret — every keystroke in an editor) has no\n // text. `toString()` is not free: it serializes like innerText and forces\n // a synchronous layout of the whole page (2026-09-26).\n const text = !selection || selection.isCollapsed ? \"\" : selection.toString().trim();\n for (const tracker of holders) if (!tracker.locked()) tracker.set(text);\n }\n selectionHolders = holders;\n}\n\nfunction trackSelection(tracker: SelectionTracker): () => void {\n if (selectionTrackers.size === 0) document.addEventListener(\"selectionchange\", onDocumentSelectionChange);\n selectionTrackers.add(tracker);\n return () => {\n selectionTrackers.delete(tracker);\n selectionHolders.delete(tracker);\n if (selectionTrackers.size === 0) document.removeEventListener(\"selectionchange\", onDocumentSelectionChange);\n };\n}\n\n/**\n * Set by the first open of ANY menu on the page. Nothing that is only useful to\n * an opened menu (the shortcut list for key combos) loads before it: a menu is\n * opened on ~1 in 149 page loads, so until then it costs nothing.\n */\nlet menuEverOpened = false;\n\n// One advertised key combo pressed → that shortcut runs through the SAME\n// engine and launch handler as its menu item; mounted for one press only.\nfunction ShortcutKeyRunner(props: ShortcutKeyRunnerProps) {\n const mod = useMenuContentModule();\n return mod ? <mod.ShortcutKeyRunner {...props} /> : null;\n}\n/** A key press an inner menu already answered (nested surfaces). */\nconst KEY_RUN_CLAIMED = \"__alchemyShortcutKeyClaimed\";\n\n// The review-and-apply dialog behind \"Clean up\" / \"Help with this…\" when the\n// menu sits over a record that can be saved (a note's Write / Plain / Split\n// view, its tab, its list row) and the host supplied no dialog of its own. It must outlive the menu that asked, so the shell owns it —\n// mounted only after the first request, like every document dialog.\n// The component is the host's (`configureContextMenuHost({ DocumentAgentReview })`);\n// a host that registers none gets no review dialog and the request is announced.\nfunction DocumentAgentReviewHost(props: {\n actionId: TextAgentReviewRequest[\"actionId\"];\n ctx: TextAgentReviewRequest[\"ctx\"];\n onClose: () => void;\n}) {\n const Review = getContextMenuHost().DocumentAgentReview;\n React.useEffect(() => {\n if (!Review) {\n console.warn('[context-menu] host port \"DocumentAgentReview\" is not wired — the review request was dropped.');\n props.onClose();\n }\n }, [Review, props]);\n return Review ? <Review {...props} /> : null;\n}\ntype TextAgentReviewRequest = {\n actionId: \"cleanup\" | \"help\" | \"customAgent\";\n ctx: import(\"@ai-matrx/rich-content/rich-document/types\").RichDocumentActionContext;\n};\n\n// ── The palette opens from ANYWHERE on a surface with a menu (ALC-15) ───────\n// ⌘/Ctrl+Shift+K with focus on the page body (a read-only note) or over a grid\n// cell (cells are not focusable) opens the palette of the INNERMOST surface\n// under the pointer, resolved for the element under the pointer. One document\n// listener for the whole page (on globalThis — module state is per bundle).\ntype PaletteOpener = (element: HTMLElement) => void;\ntype SurfaceClaim = { id: symbol; element: HTMLElement; seq: number; at: number };\ninterface PaletteRegistry {\n openers: Map<symbol, PaletteOpener>;\n /** Innermost surface under the pointer (where a right-click would land). */\n pointer: SurfaceClaim | null;\n /** Innermost surface holding focus. */\n focus: SurfaceClaim | null;\n /** Last press — a focus it caused never outranks the pointer. */\n pointerDown: { element: HTMLElement; at: number } | null;\n seq: number;\n installed: boolean;\n}\nconst PALETTE_KEY = Symbol.for(\"ai-matrx.context-menu.palette\");\nfunction paletteRegistry(): PaletteRegistry {\n const g = globalThis as unknown as Record<symbol, PaletteRegistry | undefined>;\n let reg = g[PALETTE_KEY];\n if (!reg) {\n reg = { openers: new Map(), pointer: null, focus: null, pointerDown: null, seq: 0, installed: false };\n g[PALETTE_KEY] = reg;\n }\n if (!reg.installed && typeof document !== \"undefined\") {\n reg.installed = true;\n const r = reg;\n document.addEventListener(\"keydown\", (e) => {\n if (e.defaultPrevented) return;\n if (!(e.metaKey || e.ctrlKey) || !e.shiftKey || e.key.toLowerCase() !== \"k\") return;\n const target = paletteTarget(r);\n const open = target ? r.openers.get(target.id) : undefined;\n if (!target || !open) return;\n e.preventDefault();\n open(target.element);\n });\n }\n return reg;\n}\n/**\n * Where the palette opens — exactly where right-click would: the innermost\n * surface under the pointer. Focus wins only when it moved AFTER the pointer\n * by the keyboard (Tab), never the focus a click itself caused (clicking an\n * answer focuses its outer message article; round 2, finding 1).\n */\nfunction paletteTarget(r: PaletteRegistry): SurfaceClaim | null {\n const live = (c: SurfaceClaim | null) => (c && c.element.isConnected && r.openers.has(c.id) ? c : null);\n const pointer = live(r.pointer);\n const focus = live(r.focus);\n if (!focus) return pointer;\n if (!pointer) return focus;\n if (focus.seq < pointer.seq) return pointer;\n // A focus the last press caused (the pressed element sits inside what took\n // focus, moments later) is the click's side effect, not a keyboard move.\n const down = r.pointerDown;\n const causedByPress =\n !!down && focus.element.contains(down.element) && focus.at - down.at < 1000;\n return causedByPress ? pointer : focus;\n}\nconst CLAIMED = \"__alchemyPaletteClaimed\";\n\ntype OpenMenu = {\n mode: \"context\" | \"sheet\" | \"palette\";\n point: { x: number; y: number };\n};\n\nexport function ContextMenuV3({\n children,\n sourceFeature,\n surfaceName,\n menuVersion = 1,\n getApplicationScope,\n contextData = {},\n resolveContextOnOpen,\n contentSource,\n entity,\n excludedRichActions,\n recordActionsOnly = false,\n subjectFold,\n extraRichActions,\n richDocCtxExtras,\n placementMode,\n extraSections,\n resolveExtraSectionsOnOpen,\n onUndo,\n onRedo,\n canUndo = false,\n canRedo = false,\n undoHint,\n redoHint,\n onViewHistory,\n hasHistory = false,\n scope = \"global\",\n scopeId = null,\n className,\n menuLayout = DEFAULT_MENU_LAYOUT,\n menuDensity = DEFAULT_MENU_DENSITY,\n menuDesign,\n menuFeatureTitle,\n suppressed = false,\n onMenuOpenChange,\n onCloseAutoFocus,\n isEditable,\n editorId,\n getTextarea,\n insertAtCaret,\n onContentInserted,\n onTextReplace,\n onTextInsertBefore,\n onTextInsertAfter,\n onSave,\n onDelete,\n}: ContextMenuV3Props) {\n const [selectedText, setSelectedText] = useState<string>(\"\");\n const [selectionRange, setSelectionRange] = useState<SelectionRange | null>(\n null,\n );\n const [fallbackContent, setFallbackContent] = useState<string>(\"\");\n const [menuOpen, setMenuOpen] = useState(false);\n const [textAgentReview, setTextAgentReview] = useState<TextAgentReviewRequest | null>(null);\n const requestTextAgentReview = useCallback(\n (actionId: TextAgentReviewRequest[\"actionId\"], ctx: TextAgentReviewRequest[\"ctx\"]) =>\n setTextAgentReview({ actionId, ctx }),\n [],\n );\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const isMobile = useIsMobile();\n const [sheetOpen, setSheetOpen] = useState(false);\n const [paletteOpen, setPaletteOpen] = useState(false);\n const [keyRun, setKeyRun] = useState<{ id: string; label: string } | null>(null);\n // Read without subscribing, and without requiring a Provider (the shell also\n // renders in isolated hosts and tests).\n const store = React.useContext(ReactReduxContext)?.store as AppStore | undefined;\n // Where the desktop menu anchors (pointer, ⋯ button, floating icon) and a\n // counter so every open mounts a fresh engine over a fresh click target.\n const [menuPoint, setMenuPoint] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n const [openSeq, setOpenSeq] = useState(0);\n // Nothing runs before the person engages this surface (first pointer press,\n // focus or open). /notes mounts one shell per sidebar row; an idle shell owns\n // no document listener, no selection zone and no widget handle.\n const [engaged, setEngaged] = useState(false);\n const engage = () => setEngaged(true);\n\n const capturedSelection = useRef<CapturedSelection | null>(null);\n const selectionLocked = useRef(false);\n const lastMousePos = useRef<{ x: number; y: number } | null>(null);\n // The DOM element this instance wraps — the child element itself on both\n // desktop (Radix `ContextMenuTrigger asChild`) and mobile (`Slot`), falling\n // back to the display:contents wrapper only when mobile cannot slot onto a\n // single child. Selection tracking is scoped to it — see handleSelection.\n const selectionOwnerRef = useRef<HTMLElement | null>(null);\n // The same element, as state: it is this menu's zone of the ONE selection\n // toolbar (components/selection-toolbar), which replaced the floating icon.\n const [selectionOwner, setSelectionOwnerState] = useState<HTMLElement | null>(null);\n const setSelectionOwner = useCallback((node: HTMLElement | null) => {\n selectionOwnerRef.current = node;\n setSelectionOwnerState(node);\n }, []);\n // Mobile long-press → bottom sheet (no right-click on touch).\n const longPressTimer = useRef<number | null>(null);\n const touchStart = useRef<{\n x: number;\n y: number;\n target: HTMLElement;\n container: HTMLElement;\n } | null>(null);\n // Per-invocation context resolved by `resolveContextOnOpen` (single-instance\n // delegation). State, not a ref — it's written only at right-click (which\n // re-renders to open the menu anyway), and the lazy MenuContent must read it\n // during render to build the effective scope (a ref read in render is banned).\n /** The element the menu was opened on — its record's NAME is read live. */\n const [openTarget, setOpenTarget] = useState<HTMLElement | null>(null);\n // Bumps when a registered record's rows change (a rename) — an argument of\n // the heading read below, so it is re-read.\n // Only an OPEN menu listens: a closed one reads the rows fresh at its next\n // open anyway. Every mounted menu listening re-rendered every sidebar row and\n // folder header each time a new note's auto-label moved while typing — O(notes)\n // work per label change (the Write-mode freeze sweep, 2026-10-10).\n const anyMenuOpen = menuOpen || dropdownOpen || sheetOpen || paletteOpen;\n const subscribeWhileOpen = useCallback(\n (listener: () => void) => (anyMenuOpen ? subscribeRecordMenus(listener) : () => {}),\n [anyMenuOpen],\n );\n const recordRevision = useSyncExternalStore(\n subscribeWhileOpen,\n recordMenusRevision,\n recordMenusRevision,\n );\n const [resolvedContext, setResolvedContext] =\n useState<ResolvedContextMenuContext | null>(null);\n /** The declared item this open is on (a table row), handed to the click target. */\n const [resolvedItem, setResolvedItem] = useState<ResolvedItem | null>(null);\n const [resolvedExtraSections, setResolvedExtraSections] =\n useState<typeof extraSections>(undefined);\n /** This open is on a table row whose surface draws its own row sections (see resolvePerTargetContext). */\n const [rowJoinsSurfaceSections, setRowJoinsSurfaceSections] = useState(false);\n /**\n * The entity read straight off the right-clicked element's `data-entity-*`\n * attributes (Phase 0, 2026-08-25). State for the same reason as\n * `resolvedContext`: the lazy MenuContent must read it during the render\n * that opens the menu. Only the SHELL sees the clicked element, so the sniff\n * has to happen here. Fills a silence — never overrides a surface answer.\n */\n const [sniffedEntity, setSniffedEntity] =\n useState<ContextMenuEntityRef | null>(null);\n // Set by MenuContent (via suppressSelectionRestore) when an action opens an\n // overlay that should keep focus — so closing the menu doesn't yank it back.\n const skipSelectionRestoreRef = useRef(false);\n\n // ── Inline agent editing (WidgetHandle) ──────────────────────────────────\n // Editable surfaces get a widget handle derived from the SAME callbacks they\n // already pass the menu, registered here in the shell (NOT in the lazy\n // MenuContent — that unmounts on close, and the handle must outlive the menu\n // for the whole agent stream). Read-only surfaces register nothing. The\n // launch handlers pass the id as `runtime.widgetHandleId`, so agents\n // launched from this menu can stream `widget_text_*` edits into the surface.\n // Weight check: buildEditableWidgetHandle + useOptionalWidgetHandle pull in\n // only types, the callbackManager map, and selection-tracking — no data\n // hooks, no icons; the shell stays inert.\n const widgetHandle = isEditable\n ? buildEditableWidgetHandle({\n getTextarea,\n onTextReplace,\n onTextInsertBefore,\n onTextInsertAfter,\n getApplicationScope,\n })\n : null;\n const widgetHandleId = useOptionalWidgetHandle(engaged ? widgetHandle : null);\n\n // Effective contextData for THIS invocation: static prop + per-target merge,\n // minus the reserved `__entity` key (which is not a value — see below).\n const getEffectiveContextData = (): Record<string, unknown> =>\n mergeResolvedContextData(\n contextData as Record<string, unknown> | undefined,\n resolvedContext,\n );\n\n // Effective entity for THIS invocation. ONE menu serves N rows, so the row\n // the user actually right-clicked — not the pane — must own Attach To /\n // Share. `resolveContextOnOpen` supplies it via `CONTEXT_MENU_ENTITY_KEY`;\n // when it doesn't, the menu-level `entity` prop stands unchanged.\n // Precedence: an explicit `resolveContextOnOpen` answer (including a\n // deliberate `null`) wins; only when the surface said nothing about the\n // entity does the DOM sniff fill in; the menu-level prop is the floor.\n const surfaceSpokeAboutEntity =\n !!resolvedContext && CONTEXT_MENU_ENTITY_KEY in resolvedContext;\n const effectiveEntity = surfaceSpokeAboutEntity\n ? resolveEffectiveEntity(entity, resolvedContext)\n : (sniffedEntity ?? entity);\n\n // ── Selection tracking — SCOPED to this instance's wrapped subtree ───────\n // The listener is document-global (that's the only selectionchange there\n // is), but ALL work is gated on ownership: the selection's anchor node —\n // or, for textarea/input selections (where the DOM Range stays parked on\n // the host), the focused element — must live inside our wrapped children.\n // Without this gate every mounted instance on the page (on /notes: the\n // editor + EVERY sidebar row + folder headers) serialized the full\n // selected text via `selection.toString()` (O(document) on a triple-click\n // of a large paste), stored it in its own state, and rendered its own\n // floating selection icon (since replaced by the ONE selection toolbar) at the same coordinates — dozens of stacked\n // translucent buttons compounding into a black-shadowed blob, and N×\n // O(document) main-thread work per selection event: a browser-freeze\n // amplifier (2026-07 /notes freeze class).\n useEffect(() => {\n if (!engaged) return;\n // ONE document listener for every instance (selectionTracker below): a\n // selection change walks up from the anchor to the instances that own it,\n // so a keystroke costs O(depth), not O(mounted menus) — /notes mounts one\n // per sidebar row and folder header (the Write-mode freeze sweep, 2026-10-10).\n return trackSelection({\n owner: () => selectionOwnerRef.current,\n locked: () => selectionLocked.current,\n set: setSelectedText,\n });\n }, [engaged]);\n\n // The pointer position (the ⋯ / selection fallback anchor) is read off the\n // events this surface already receives — no page-wide mousemove listener.\n const rememberPointer = (e: { clientX: number; clientY: number }) => {\n lastMousePos.current = { x: e.clientX, y: e.clientY };\n };\n\n // ── Capture handlers ─────────────────────────────────────────────────────\n const handleMouseDown = (e: React.MouseEvent) => {\n if (suppressed) return; // yield to the native menu (e.g. streaming)\n if (reachedThroughPortal(e)) return;\n if (e.button !== 2) return; // right-click only\n // Engagement: start fetching the menu body now, in parallel with the open.\n void warmMenuContent();\n // Must mirror the capture guard exactly. Capturing here would set\n // `selectionLocked` for a menu that is never going to open, and only\n // `handleMenuClose` clears it — so selection tracking would stay frozen\n // for the rest of this instance's life.\n if (!isEditable && yieldsToNativeTextMenu(e.target)) return;\n const target = e.target as HTMLElement;\n resolvePerTargetContext(target);\n selectionLocked.current = true;\n\n if (\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLInputElement\n ) {\n const captured = captureTextareaSelection(target);\n capturedSelection.current = captured;\n setSelectedText(captured.text);\n } else {\n const captured = captureDomSelection();\n capturedSelection.current = captured;\n setSelectedText(captured.text);\n }\n };\n\n // Per-target context resolution — MUST run on EVERY open path (right-click,\n // keyboard contextmenu, mobile long-press/sheet, floating icon), not just\n // button-2 mousedown: single-instance consumers (ItemContextMenu, markdown,\n // PDF regions) build their menu items from this. A double call on the plain\n // right-click path (mousedown then contextmenu) is deliberate — re-resolving\n // is idempotent and keeps lazy configs fresh.\n const resolvePerTargetContext = (target: HTMLElement | null) => {\n // Every open path passes through here: this is the first open on the page.\n menuEverOpened = true;\n engage();\n // A table under the click: its shape reader loads now, ahead of \"Save to a table\".\n if (target?.closest(\"table\")) void preloadTableShape();\n const rowHit = resolveTableRowItem(target);\n const rowMenu = rowHit?.menu ?? null;\n setResolvedItem(rowHit?.item ?? null);\n // A table row has two owners: the table's descriptor names the row's values, the surface\n // names which RECORD the row is (and builds its own row doors from that same call). Both\n // are asked, always — `rowMenu?.context ?? surface` skipped the surface on every table row.\n const answered = joinRowAndSurfaceContext(\n rowMenu?.context,\n resolveContextOnOpen ? resolveContextOnOpen(target) : null,\n );\n // A record the content belongs to names the header when the target\n // names nothing itself (record-menu-registry.ts `heading`) — read at\n // RENDER from this target (`recordHeadingAt`), so a rename while the menu\n // is open or mounted reaches the header.\n setOpenTarget(target);\n setResolvedContext(answered);\n const surfaceSections = resolveExtraSectionsOnOpen?.(target);\n // Several owners, one menu: joined so a row id is drawn once (utils/join-extra-sections.ts).\n const ownSections = joinExtraSections(rowMenu?.extraSections, surfaceSections);\n // A surface that resolves per target draws its row's doors through the `extraSections` PROP\n // (rebuilt from the state its resolver just set), so on a table row they join the table's\n // own at RENDER, when the prop is fresh — never from this closure's previous row.\n // A surface's own STATIC sections (a per-row menu wrapping a table row: Files' Preview,\n // Rename, Move…) join the table's too — they used to be replaced by the row's sections.\n setRowJoinsSurfaceSections(!!rowMenu && !surfaceSections);\n // The record whose content this is (a note's tab rows, drawn apart from its\n // content): its rows join THIS menu, so the record's ⋯ and a right-click on\n // its content are one menu (record-menu-registry.ts, R26). The content's own\n // row wins over the record's row with the same id — never both.\n const record = resolveRecordMenu(target);\n setResolvedExtraSections(\n record?.extraSections.length\n ? joinExtraSections(ownSections ?? extraSections ?? [], record.extraSections)\n : ownSections,\n );\n // The record's entity fills a silence only — never over this menu's own.\n setSniffedEntity(sniffEntityFromDom(target) ?? (entity ? null : (record?.entity ?? null)));\n };\n\n // Shared capture — populates selection/content state from a right-click target\n // OR a long-press target (mobile). Does not open anything; the caller does.\n const captureContext = (target: HTMLElement, containerEl: HTMLElement) => {\n resolvePerTargetContext(target);\n let captured = capturedSelection.current;\n // A selection made somewhere ELSE is not what this right-click is about:\n // the Subject field's menu headed itself with the Message's selected text\n // (page-pass 2026-09-27). Keep a remembered selection only when it lies in\n // the field under the pointer (or, outside any field, in this menu's own\n // region); otherwise read afresh from the target.\n const scopeEl: Node =\n target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement\n ? target\n : (target.closest('[contenteditable=\"true\"], [contenteditable=\"\"]') ?? containerEl);\n if (captured?.range && !scopeEl.contains(captured.range.commonAncestorContainer)) {\n captured = null;\n }\n if (!captured || !captured.text) {\n captured =\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLInputElement\n ? captureTextareaSelection(target)\n : captureDomSelection();\n capturedSelection.current = captured;\n selectionLocked.current = true;\n }\n\n if (\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLInputElement\n ) {\n // THE SELECTION THE MENU OPENED ON IS THE ONE EVERY READER SEES. A right\n // mousedown outside the highlight moves the caret AFTER the mousedown\n // capture: the header said \"Selected: …\" while a surface's live scope\n // builder (notes reads the field's selectionStart/End) saw a caret, so\n // selection shortcuts vanished or ran on nothing (2026-10-02). Put the\n // captured range back on the field so the header, the scope, and the\n // restore-on-close all name the same text.\n const remembered =\n captured?.editable &&\n captured.editable.element === target &&\n captured.editable.start !== captured.editable.end\n ? captured.editable\n : null;\n const { start, end } = remembered ?? getEditableSelectionOffsets(target);\n if (remembered) {\n const live = getEditableSelectionOffsets(target);\n if (live.start !== start || live.end !== end) {\n try {\n target.setSelectionRange(start, end);\n } catch {\n // A field without a selection API keeps its whole-value range.\n }\n }\n }\n setSelectedText(captured?.text || \"\");\n setSelectionRange({\n type: \"editable\",\n element: target,\n start,\n end,\n range: null,\n containerElement: null,\n });\n // Fallback content = the whole field, so Copy/AI work even with no selection.\n setFallbackContent(target.value ?? \"\");\n } else {\n let containerElement = containerEl;\n if (!containerElement.hasAttribute(\"data-alchemy-trigger\")) {\n const trigger = containerElement.querySelector(\n \"[data-alchemy-trigger]\",\n );\n if (trigger instanceof HTMLElement) containerElement = trigger;\n }\n setSelectedText(captured?.text || \"\");\n setSelectionRange({\n type: \"non-editable\",\n // A contenteditable FIELD the right-click landed in (a rich or chip\n // editor): recorded so the menu header can name the field instead of\n // dumping its raw text. Every reader of `.element` gates on\n // `type === \"editable\"`, so this changes nothing else.\n element: target.closest<HTMLElement>('[contenteditable=\"true\"], [contenteditable=\"\"]'),\n start: 0,\n end: 0,\n range: captured?.range || null,\n containerElement,\n });\n // Fallback content = the right-clicked subtree's text — the net that\n // makes a read-only surface copyable with zero wiring (kills \"fake menu\").\n setFallbackContent(extractElementText(containerElement));\n }\n };\n\n const handleContextMenu = (e: React.MouseEvent) => {\n if (suppressed) return; // trigger is disabled; native menu shows\n // Radix's innermost trigger prevents the native event after it opens. Let\n // that event bubble so the inner Radix handler can run, then make every\n // outer shell yield when it sees the already-prevented event. Calling\n // stopPropagation here aborts the asChild-composed Radix handler on nested\n // rows, leaving the row with no menu at all.\n if (e.defaultPrevented) return;\n // The innermost eligible trigger owns the gesture: preventing here is what\n // makes every outer shell yield (and hides the native menu).\n e.preventDefault();\n captureContext(e.target as HTMLElement, e.currentTarget as HTMLElement);\n setMenuPoint({ x: e.clientX, y: e.clientY });\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setMenuOpen(true);\n onMenuOpenChange?.(true);\n };\n\n const handleMenuClose = () => {\n setMenuOpen(false);\n selectionLocked.current = false;\n capturedSelection.current = null;\n if (skipSelectionRestoreRef.current) {\n skipSelectionRestoreRef.current = false;\n return;\n }\n if (!selectionRange) return;\n if (selectionRange.type === \"editable\") {\n const { element, start, end } = selectionRange;\n if (\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLInputElement\n ) {\n restoreTextareaSelection(element, start, end);\n }\n } else if (selectionRange.range) {\n restoreDomSelection(selectionRange.range);\n }\n };\n\n const handleDropdownClose = (open: boolean) => {\n onMenuOpenChange?.(open);\n setDropdownOpen(open);\n if (!open) {\n selectionLocked.current = false;\n capturedSelection.current = null;\n }\n };\n\n // Opened from the ONE selection toolbar's \"Ask AI\" (components/selection-\n // toolbar; it replaced the floating selection icon): the same menu over the\n // selected text — a panel under the selection on desktop, the sheet on a phone.\n const openFromSelection = () => {\n if (suppressed) return;\n selectionLocked.current = true;\n const sel = window.getSelection();\n const container =\n sel && sel.rangeCount > 0\n ? (sel.getRangeAt(0).commonAncestorContainer.parentElement ?? null)\n : null;\n resolvePerTargetContext(container);\n setFallbackContent(extractElementText(container));\n if (isMobile) {\n setSelectedText(sel?.toString().trim() || selectedText);\n setSelectionRange({\n type: \"non-editable\",\n element: null,\n start: 0,\n end: 0,\n range: sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null,\n containerElement: container,\n });\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setSheetOpen(true);\n return;\n }\n const rect = getSelectionRect();\n const at = rect\n ? { x: rect.left, y: rect.bottom + 4 }\n : (lastMousePos.current ?? { x: 16, y: 16 });\n setMenuPoint(at);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setDropdownOpen(true);\n };\n\n const selectionHost: ContextMenuSelectionHost = { kind: \"context-menu-selection\", open: openFromSelection };\n // No `editable` flag: an editable menu often wraps a read-only preview too\n // (a note's split view), so the toolbar reads editing from the DOM (a text\n // field or contenteditable under the selection), never from the wrapper.\n // Registered only once the surface is engaged (a selection needs a press or focus first).\n useSelectionZone(\n selectionOwner,\n engaged\n ? {\n // A suppressed menu (the text is streaming) keeps the toolbar away until it settles.\n suppress: suppressed,\n host: { [CONTEXT_MENU_SELECTION_HOST_KEY]: selectionHost },\n }\n : null,\n );\n\n // ── Mobile triggers (no right-click on touch) ─────────────────────────────\n const clearLongPress = () => {\n if (longPressTimer.current !== null) {\n clearTimeout(longPressTimer.current);\n longPressTimer.current = null;\n }\n };\n const handleTouchStart = (e: React.TouchEvent) => {\n if (suppressed) return;\n if (reachedThroughPortal(e)) return;\n // The touch half of the native-menu rule. Long-press inside a text field IS\n // the OS text callout (Select / Paste / Look Up) — pre-empting it at 480ms\n // leaves a mobile user with no way to paste at all, which is worse than the\n // desktop case because there is no right-click to fall back to. The guard\n // shipped on the three pointer paths and missed this one, so the stated\n // invariant held on desktop only.\n if (!isEditable && yieldsToNativeTextMenu(e.target)) return;\n // Nested menus are deliberate (for example, a page-list menu around\n // per-row menus). The innermost eligible trigger owns the gesture; without\n // this both long-press timers fire and two mobile sheets open.\n e.stopPropagation();\n const t = e.touches[0];\n if (!t) return;\n touchStart.current = {\n x: t.clientX,\n y: t.clientY,\n target: e.target as HTMLElement,\n container: e.currentTarget as HTMLElement,\n };\n clearLongPress();\n longPressTimer.current = window.setTimeout(() => {\n const info = touchStart.current;\n if (!info) return;\n captureContext(info.target, info.container);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setSheetOpen(true);\n }, 480);\n };\n const handleTouchMove = (e: React.TouchEvent) => {\n const info = touchStart.current;\n const t = e.touches[0];\n if (!info || !t) return;\n // A drag means the user is scrolling or selecting — not a long-press.\n if (Math.abs(t.clientX - info.x) > 10 || Math.abs(t.clientY - info.y) > 10)\n clearLongPress();\n };\n const handleTouchEnd = () => clearLongPress();\n\n const handleSheetOpenChange = (open: boolean) => {\n onMenuOpenChange?.(open);\n setSheetOpen(open);\n if (!open) {\n selectionLocked.current = false;\n capturedSelection.current = null;\n }\n };\n\n // ── The single prop bag handed to the lazy MenuContent ───────────────────\n const menuContentProps = compact({\n sourceFeature,\n surfaceName,\n menuVersion,\n // A row descriptor owns this invocation's values. Preserve page-level live\n // values for empty space, but never let them overwrite the clicked row.\n getApplicationScope: resolvedContext\n ? () => ({ ...(getApplicationScope?.() ?? {}), ...getEffectiveContextData() })\n : getApplicationScope,\n contextData: getEffectiveContextData(),\n heading:\n readContextMenuHeading(resolvedContext) ??\n recordHeadingAt(openTarget, recordRevision),\n item: resolvedItem,\n contentSource,\n entity: effectiveEntity,\n excludedRichActions,\n recordActionsOnly,\n subjectFold,\n // The hook adds it only where the source can be saved and no host supplied one.\n requestTextAgentReview,\n extraRichActions,\n // The table the click landed on rides to \"Save to a table\" beside the host's own extras.\n richDocCtxExtras: {\n ...richDocCtxExtras,\n callbacks: {\n ...richDocCtxExtras?.callbacks,\n tableAtTarget: () => tableTextAtTarget(openTarget),\n },\n // Spreading an optional bag leaves its Pick'd keys optional; the hook spreads it over defaults.\n } as NonNullable<MenuContentProps[\"richDocCtxExtras\"]>,\n selectedText,\n selectionRange,\n fallbackContent,\n placementMode,\n scope,\n scopeId,\n extraSections: resolvedExtraSections\n ? rowJoinsSurfaceSections\n ? joinExtraSections(resolvedExtraSections, extraSections)\n : resolvedExtraSections\n : extraSections,\n menuLayout,\n menuDensity,\n menuDesign,\n menuFeatureTitle,\n isEditable,\n editorId,\n getTextarea,\n insertAtCaret,\n onContentInserted,\n onTextReplace,\n onTextInsertBefore,\n onTextInsertAfter,\n onSave,\n onDelete,\n onUndo,\n onRedo,\n canUndo,\n canRedo,\n undoHint,\n redoHint,\n onViewHistory,\n hasHistory,\n widgetHandleId,\n suppressSelectionRestore: () => {\n skipSelectionRestoreRef.current = true;\n },\n }) as Omit<MenuContentProps, \"variant\">;\n\n // Radix `asChild` is a strict one-element slot. Consumers may legitimately\n // wrap a surface plus sibling loading/empty states, so normalize that shape\n // to one layout-neutral element before either renderer reaches a Slot.\n //\n // THE ATTACH POINT (verify round 1, the ref-forwarding class): the menu's handlers\n // and its selection zone need a real DOM element. A slot onto a COMPONENT that does\n // not forward its ref (or spread its props) leaves none — the right-click menu and the\n // selection toolbar then silently do nothing. So the menu slots only onto an intrinsic\n // DOM element (`<div>`, `<tr>` — they always take a ref and props) and otherwise owns\n // its own `display: contents` wrapper. Guard: __tests__/attach-point.test.tsx.\n const canSlotChildren =\n React.Children.count(children) === 1 &&\n React.isValidElement(children) &&\n typeof children.type === \"string\";\n\n // The version footer is gone (Arman, 2026-08-22: dev/testing info, not for\n // users). The surface name + revision now live in the surface submenu the\n // engine builds (`surfaceSection`), admin-only for the revision.\n\n\n // Register this surface's palette opener; the innermost trigger under the\n // pointer (or holding focus) claims \"last surface\" for the page listener.\n const paletteIdRef = useRef<symbol | null>(null);\n paletteIdRef.current ??= Symbol(\"context-menu-surface\");\n const openPaletteAt = (element: HTMLElement) => {\n if (suppressed) return;\n const container = selectionOwnerRef.current ?? element;\n captureContext(element, container);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setPaletteOpen(true);\n onMenuOpenChange?.(true);\n };\n const openPaletteRef = useRef(openPaletteAt);\n useEffect(() => {\n openPaletteRef.current = openPaletteAt;\n });\n useEffect(() => {\n const reg = paletteRegistry();\n const id = paletteIdRef.current as symbol;\n reg.openers.set(id, (el) => openPaletteRef.current(el));\n return () => {\n reg.openers.delete(id);\n if (reg.pointer?.id === id) reg.pointer = null;\n if (reg.focus?.id === id) reg.focus = null;\n };\n }, []);\n const claim = (kind: \"pointer\" | \"focus\") => (e: React.SyntheticEvent<HTMLElement>) => {\n const native = e.nativeEvent as Event & { [CLAIMED]?: boolean };\n if (native[CLAIMED]) return; // an inner surface already claimed it\n native[CLAIMED] = true;\n const reg = paletteRegistry();\n const now = Date.now();\n if (e.type === \"pointerdown\") reg.pointerDown = { element: e.target as HTMLElement, at: now };\n if (e.type === \"pointerdown\" || e.type === \"focusin\" || e.type === \"focus\") engage();\n if (e.type === \"pointerover\" || e.type === \"pointerdown\") rememberPointer(e as unknown as React.PointerEvent);\n reg.seq += 1;\n reg[kind] = { id: paletteIdRef.current as symbol, element: e.target as HTMLElement, seq: reg.seq, at: now };\n };\n\n const mode: \"context\" | \"sheet\" | \"palette\" | null = sheetOpen\n ? \"sheet\"\n : paletteOpen\n ? \"palette\"\n : menuOpen || dropdownOpen\n ? \"context\"\n : null;\n const closeActive = () => {\n if (sheetOpen) handleSheetOpenChange(false);\n else if (paletteOpen) {\n setPaletteOpen(false);\n onMenuOpenChange?.(false);\n handleMenuClose();\n } else if (dropdownOpen) handleDropdownClose(false);\n else {\n onMenuOpenChange?.(false);\n handleMenuClose();\n }\n };\n\n // ── Advertised key combos run their shortcut ─────────────────────────────\n // The menu prints a shortcut's `keyboard_shortcut` (\"Alt+Shift+S\"); a press\n // with focus inside this surface runs it. Matched on `code` (key-combo.ts):\n // macOS Option turns Alt+Shift+S into \"Í\". The rows are read from the store\n // at press time (no subscription — the shell stays inert); an editable\n // surface loads them on first focus so the first press already works.\n const handleShortcutKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const native = e.nativeEvent as Event & { [KEY_RUN_CLAIMED]?: boolean };\n if (native[KEY_RUN_CLAIMED] || e.defaultPrevented || suppressed || e.repeat) return;\n if (reachedThroughPortal(e)) return;\n // Until a menu has been opened once on this page, no key combo loads or runs anything.\n if (!menuEverOpened) return;\n if (!store || (!e.altKey && !e.ctrlKey && !e.metaKey)) return;\n const matchOf = (event: KeyboardEvent) =>\n findComboMatch(\n event,\n selectAllShortcutsArray(store.getState()).filter((s) => s.isActive !== false),\n (s) => s.keyboardShortcut,\n );\n const target = e.target as HTMLElement;\n const owner = selectionOwnerRef.current ?? e.currentTarget;\n const run = (match: { id: string; label: string }) => {\n captureContext(target, owner);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setKeyRun({ id: match.id, label: match.label });\n };\n // The shortcut list loads on the first modifier press (the modifier key's\n // own keydown usually lands it before the combo key), never on focus — an\n // autofocused composer would otherwise read it on every page load.\n const loading = loadShortcuts();\n const match = matchOf(e.nativeEvent);\n if (!match) {\n // A combo pressed before the list arrived still runs, once it arrives.\n if (loading) {\n const event = e.nativeEvent;\n void loading.then(() => {\n const late = matchOf(event);\n if (late) run(late);\n });\n }\n return;\n }\n native[KEY_RUN_CLAIMED] = true;\n e.preventDefault();\n e.stopPropagation();\n run(match);\n };\n const shortcutsLoad = useRef<Promise<unknown> | null>(null);\n const shortcutsLoaded = useRef(false);\n /** The in-flight first load of the shortcut list, or null once it has landed. */\n const loadShortcuts = (): Promise<unknown> | null => {\n if (!store || !isEditable || shortcutsLoaded.current) return null;\n if (!shortcutsLoad.current) {\n // Deduped + condition-gated in the thunk: one request page-wide.\n shortcutsLoad.current = import(\"@ai-matrx/chat/agents/redux/agent-shortcuts/thunks\")\n .then(({ fetchUnifiedMenu }) => (store.dispatch as ChatDispatch)(fetchUnifiedMenu({ scope, scopeId })))\n .catch(() => undefined)\n .finally(() => {\n shortcutsLoaded.current = true;\n });\n }\n return shortcutsLoad.current;\n };\n const finishKeyRun = () => {\n setKeyRun(null);\n // The launched run owns focus now (its panel); only release the capture.\n selectionLocked.current = false;\n capturedSelection.current = null;\n };\n\n // The trigger props — merged ONTO the single child via Radix `Slot` (no\n // wrapper element: a `<div>` between `<tbody>` and a wrapped `<tr>` is\n // illegal), falling back to a `display:contents` wrapper for a Fragment or\n // multi-child payload, where a `<div>` is always legal.\n const triggerProps = {\n ...CONTEXT_REGION_TRIGGER_ATTRS,\n // Radix-compatible open state, for styles that key on it.\n \"data-state\": mode ? \"open\" : \"closed\",\n // Lets a ⋯ beside (not inside) this content open THIS menu.\n \"data-content-source\": contentSource ? contentSourceKey(contentSource) : undefined,\n onContextMenuCapture: (e: React.MouseEvent<HTMLElement>) => {\n if (reachedThroughPortal(e)) return;\n // A right-click IS engagement: fetch the menu body now, in parallel with the open.\n void warmMenuContent();\n // CAPTURE: a read-only menu never steals a live text field's native menu.\n // It MARKS the gesture instead of stopping it: a stopPropagation here\n // also killed the field's OWN editable menu nested inside (every window\n // body is a read-only menu, so every window's text box lost its menu).\n if (!isEditable && yieldsToNativeTextMenu(e.target))\n NATIVE_TEXT_YIELD.set(e.nativeEvent, e.currentTarget);\n },\n onContextMenu: (e: React.MouseEvent<HTMLElement>) => {\n if (reachedThroughPortal(e)) {\n if (isInsideOpenMenu(e.target)) e.preventDefault();\n return;\n }\n // A read-only shell over a live field yields; so does an editable shell\n // OUTSIDE the innermost read-only shell that asked to yield. An editable\n // menu nested inside that shell owns its own field.\n const yielder = NATIVE_TEXT_YIELD.get(e.nativeEvent);\n if (yielder && (!isEditable || !yielder.contains(e.currentTarget))) return;\n if (isMobile) {\n if (suppressed) return;\n if (!isEditable && yieldsToNativeTextMenu(e.target)) return;\n // A nested row trigger wins over its surrounding list-level trigger.\n e.stopPropagation();\n e.preventDefault();\n captureContext(e.target as HTMLElement, e.currentTarget);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setSheetOpen(true);\n return;\n }\n handleContextMenu(e);\n },\n onMouseDown: isMobile ? undefined : handleMouseDown,\n // The palette key is answered by the ONE page listener (paletteTarget), so\n // a click that focused an OUTER surface cannot steal it from the inner one.\n onPointerOver: claim(\"pointer\"),\n onPointerDown: claim(\"pointer\"),\n onFocus: claim(\"focus\"),\n onKeyDown: handleShortcutKeyDown,\n ...(isMobile\n ? {\n onTouchStart: handleTouchStart,\n onTouchMove: handleTouchMove,\n onTouchEnd: handleTouchEnd,\n onTouchCancel: handleTouchEnd,\n }\n : {}),\n };\n\n return (\n <MenuPresenceProvider value={true}>\n <RegistryMenuSourceProvider value={contentSource ?? null}>\n {canSlotChildren ? (\n <Slot ref={setSelectionOwner} {...triggerProps}>\n {children}\n </Slot>\n ) : (\n <div ref={setSelectionOwner} style={{ display: \"contents\" }} {...triggerProps}>\n {children}\n </div>\n )}\n\n\n {mode ? (\n <AlchemyMenuContent\n key={openSeq}\n {...menuContentProps}\n mode={mode}\n point={menuPoint}\n open\n onOpenChange={(open) => {\n if (!open) closeActive();\n }}\n />\n ) : null}\n {keyRun && !mode ? (\n <ShortcutKeyRunner\n key={`key-run-${openSeq}`}\n {...menuContentProps}\n shortcutId={keyRun.id}\n shortcutLabel={keyRun.label}\n onDone={finishKeyRun}\n />\n ) : null}\n {textAgentReview ? (\n <DocumentAgentReviewHost\n actionId={textAgentReview.actionId}\n ctx={textAgentReview.ctx}\n onClose={() => setTextAgentReview(null)}\n />\n ) : null}\n </RegistryMenuSourceProvider>\n </MenuPresenceProvider>\n );\n}\n\n/**\n * The name of the record whose content holds `target`, read NOW from its\n * registered rows. `_revision` is the registry's change counter: passing it\n * makes every caller (and the React Compiler's memo) re-read after a rename.\n */\nfunction recordHeadingAt(\n target: HTMLElement | null,\n _revision: number,\n): ContextMenuHeading | null {\n return readContextMenuHeading({\n [CONTEXT_MENU_HEADING_KEY]: resolveRecordMenu(target)?.heading ?? null,\n });\n}\n\n/** The header name a `resolveContextOnOpen` answer gave, when it is well-formed. */\nfunction readContextMenuHeading(resolved: unknown): ContextMenuHeading | null {\n if (!resolved || typeof resolved !== \"object\") return null;\n const heading = (resolved as Record<string, unknown>)[CONTEXT_MENU_HEADING_KEY];\n if (!heading || typeof heading !== \"object\") return null;\n const { label, text } = heading as Record<string, unknown>;\n return typeof label === \"string\" && typeof text === \"string\" && label.trim()\n ? { label: label.trim(), text }\n : null;\n}\n","\"use client\";\n\n// features/context-menu-v3/menu-presence.tsx\n//\n// 🚨 \"AM I ALREADY INSIDE A MENU?\"\n//\n// v3's nesting rule is THE INNERMOST WINS — every trigger stops propagation, so\n// an inner menu shadows every outer one. That rule is correct for the cases it\n// was written for, and it becomes a trap the moment a shared PRIMITIVE wants to\n// mount a menu of its own.\n//\n// `ProTextarea` is the case that forced this (2026-08-26). It has 387\n// consumers, 361 of which have no right-click menu at all — the single largest\n// coverage gap in the app, and every one of them is also a field agents cannot\n// stream edits into, because `EditableContextMenu` is what registers the\n// WidgetHandle. Mounting a menu inside ProTextarea fixes all 361 at once.\n//\n// But ~26 consumers ALREADY wrap their ProTextarea in a carefully-wired menu\n// carrying their own entity, surfaceName and extraSections. Under\n// innermost-wins, a menu inside ProTextarea would SHADOW every one of those —\n// silently replacing a rich, surface-specific menu with a generic one, on\n// exactly the surfaces someone took the trouble to wire properly.\n//\n// So the primitive has to be able to ask whether an ancestor already provides a\n// menu, and stand down when one does. That is all this module is: a boolean\n// context published by the shell.\n//\n// THE RULE FOR PRIMITIVES: a shared component may mount its own menu ONLY as a\n// FLOOR — when nothing above it has. A surface that wires its own menu always\n// wins, and never has to know the primitive exists.\n\nimport { createContext, useContext } from \"react\";\nimport type { ContentSource } from \"@ai-matrx/rich-content/rich-document/types\";\n\n/**\n * True anywhere inside a mounted v3 menu (either wrapper). Provided by the\n * shell; read by shared primitives that would otherwise nest.\n */\nconst MenuPresenceContext = createContext(false);\n\nexport const MenuPresenceProvider = MenuPresenceContext.Provider;\n\n/**\n * `true` when some ancestor already mounts a v3 menu.\n *\n * A shared primitive uses this to decide whether to provide its own floor:\n *\n * ```tsx\n * const insideMenu = useIsInsideContextMenu();\n * return insideMenu ? field : <EditableContextMenu …>{field}</EditableContextMenu>;\n * ```\n *\n * Do NOT use it to change what a menu CONTAINS — only whether a primitive\n * mounts one at all. Content decisions belong to the surface.\n */\nexport function useIsInsideContextMenu(): boolean {\n return useContext(MenuPresenceContext);\n}\n\n/**\n * THE ONE MENU (RC-B6). The content source of the innermost v3 menu that was\n * given one (`contentSource`) — null when none. A ⋯ button whose own content\n * is that same source opens THIS menu (openContextMenuForElement) instead of\n * drawing a second one, so the ⋯ menu and the right-click are the same menu\n * by construction: same registry tree, same agent libraries, same order.\n */\nconst RegistryMenuSourceContext = createContext<ContentSource | null>(null);\n\nexport const RegistryMenuSourceProvider = RegistryMenuSourceContext.Provider;\n\nexport function useRegistryMenuSource(): ContentSource | null {\n return useContext(RegistryMenuSourceContext);\n}\n\n/** Two sources name the same content (type + every identifying id). */\nexport function sameContentSource(\n a: ContentSource | null | undefined,\n b: ContentSource | null | undefined,\n): boolean {\n if (!a || !b || a.type !== b.type) return false;\n return contentSourceKey(a) === contentSourceKey(b);\n}\n\n/**\n * A content source's identity as one string (every identifying field, the\n * read-only flag excluded). The shell stamps it on its trigger\n * (`data-content-source`) so a ⋯ button can open the ONE menu that carries its\n * content even when the button renders beside that content, not inside it.\n */\nexport function contentSourceKey(s: ContentSource): string {\n return JSON.stringify(\n Object.fromEntries(\n Object.entries(s as Record<string, unknown>)\n .filter(([k]) => k !== \"readOnly\")\n .sort(([x], [y]) => x.localeCompare(y)),\n ),\n );\n}\n","\"use client\";\n\n// features/context-menu-v3/EditableContextMenu.tsx\n//\n// Thin wrapper for EDITABLE surfaces (textareas, code/note editors, builders).\n// Presets `isEditable` and accepts the text-mutation callbacks that light up\n// Cut / Paste / Insert / Save / Delete. All real logic lives in the shell +\n// lazy MenuContent — this only fixes the editable preset and narrows the props.\n\nimport { ContextMenuV3 } from \"./ContextMenuV3\";\nimport type { EditableContextMenuProps } from \"./types\";\n\nexport function EditableContextMenu(props: EditableContextMenuProps) {\n return <ContextMenuV3 {...props} isEditable />;\n}\n","\"use client\";\n\n// features/context-menu-v3/NonEditableContextMenu.tsx\n//\n// Thin wrapper for READ-ONLY surfaces (viewers, results, Knowledge/research output,\n// rendered markdown, message displays). No text mutation — but Copy, AI\n// Actions, Attach To, Share, Export and Convert all work, because the menu\n// self-resolves content from the DOM. Presets `isEditable: false`.\n\nimport { ContextMenuV3 } from \"./ContextMenuV3\";\nimport type { NonEditableContextMenuProps } from \"./types\";\n\nexport function NonEditableContextMenu(props: NonEditableContextMenuProps) {\n return <ContextMenuV3 {...props} isEditable={false} />;\n}\n","\"use client\";\n\n// features/context-menu-v3/PageSurfaceMenu.tsx\n//\n// THE PAGE-LEVEL MENU FLOOR. A page whose body is cards / charts / panels (no\n// table, no editor) has no right-click region, so a right-click on it opens\n// NOTHING and the person loses Copy, Agents, Surface Context and Bind. Mount\n// this ONCE in the section shell that wraps those pages: it resolves the live\n// surface the page registered (`useActivePageSurface`, the same answer the\n// header Agents menu uses) and answers with the canonical read-only menu bound\n// to that surface and its live scope. A deeper menu (table rows, editors)\n// still wins (innermost-wins), so wrapping never shadows a richer one.\n\nimport { compact } from \"./utils/compact\";\nimport type { ReactNode } from \"react\";\nimport { useActivePageSurface } from \"@ai-matrx/chat/surfaces/runtime/useActivePageSurface\";\nimport { NonEditableContextMenu } from \"./NonEditableContextMenu\";\n\ntype MenuProps = Parameters<typeof NonEditableContextMenu>[0];\n\nexport function PageSurfaceMenu({\n sourceFeature,\n children,\n}: {\n sourceFeature: MenuProps[\"sourceFeature\"];\n children: ReactNode;\n}) {\n const active = useActivePageSurface();\n return (\n <NonEditableContextMenu\n sourceFeature={sourceFeature}\n {...compact({ surfaceName: active.surfaceName ?? undefined })}\n getApplicationScope={() => {\n const scope = active.runtime?.getScope();\n // The menu reads the scope synchronously; an async scope is read by the Surface Context window.\n return scope && !(scope instanceof Promise) ? scope : {};\n }}\n contentSource={{ type: \"raw\" }}\n contextData={{ content: \"\" }}\n >\n {children}\n </NonEditableContextMenu>\n );\n}\n","\"use client\";\n\n/**\n * Gives every ItemRow / ItemContextMenu (@ai-matrx/design-system/item) the\n * website's right-click menu (v3) and promise toast. Mounted once at the root.\n */\n\nimport type { ComponentType, ReactNode } from \"react\";\nimport { ItemMenuHostProvider, type ItemContextMenuProps, type ItemMenuHost } from \"@ai-matrx/design-system/item\";\nimport { ItemContextMenuV3 } from \"./ItemContextMenuV3\";\nimport { itemToastPromise } from \"./itemMenuToV3\";\n\nconst HOST: ItemMenuHost = {\n // The package's surface fields are open strings; every website row passes chat's closed registries.\n ContextMenu: ItemContextMenuV3 as unknown as ComponentType<ItemContextMenuProps>,\n toastPromise: itemToastPromise,\n};\n\nexport function ItemMenuHostBinding({ children }: { children: ReactNode }) {\n return <ItemMenuHostProvider host={HOST}>{children}</ItemMenuHostProvider>;\n}\n","\"use client\";\n\n/**\n * The website's right-click menu for every ItemRow / ItemContextMenu\n * (@ai-matrx/design-system/item): the ONE universal v3 context menu, with the\n * row's schema-driven config riding in as extraSections (converted lazily at\n * open — resolveContextOnOpen fires before the menu mounts), so the row\n * inherits the standard extras (Copy, agents, Quick Actions, Attach To, Share,\n * admin). Mounted through `ItemMenuHostProvider` in ItemMenuHostBinding.\n * Moves into @ai-matrx/chat with the rest of v3 (package architecture step 2).\n */\n\nimport { compact } from \"../utils/compact\";\nimport { useState } from \"react\";\nimport { resolveItemMenuConfig, type ItemMenuConfig } from \"@ai-matrx/design-system/item\";\nimport type { ItemContextMenuProps } from \"@ai-matrx/chat/ui/item-types\";\nimport { NonEditableContextMenu } from \"../NonEditableContextMenu\";\nimport { CONTEXT_MENU_HEADING_KEY, type ResolvedContextMenuContext } from \"../types\";\nimport { itemMenuConfigToExtraSections } from \"./itemMenuToV3\";\n\nexport function ItemContextMenuV3({\n config,\n children,\n sourceFeature,\n surfaceName,\n entity,\n getApplicationScope,\n resolveItemOnOpen,\n onOpenChange,\n onCloseAutoFocus,\n}: ItemContextMenuProps) {\n const [resolved, setResolved] = useState<ItemMenuConfig | null>(null);\n\n return (\n <NonEditableContextMenu\n sourceFeature={sourceFeature}\n {...compact({ surfaceName, entity, getApplicationScope })}\n resolveContextOnOpen={(target) => {\n // Re-resolve on every open so lazy configs stay live.\n const item = resolveItemOnOpen?.(target);\n setResolved(resolveItemMenuConfig(item?.config ?? config));\n const context = item?.context ?? null;\n // A list row is a RECORD, not text: its menu is headed with the\n // record's name (\"Note · Clinic intake checklist\"), never \"Content:\"\n // plus the row's text — unless the row names itself already.\n if (\n entity?.title &&\n !(context && (context as Record<string, unknown>)[CONTEXT_MENU_HEADING_KEY])\n ) {\n const type = String(entity.type ?? \"Item\").replace(/[_-]+/g, \" \");\n return {\n ...((context as Record<string, unknown> | null) ?? {}),\n [CONTEXT_MENU_HEADING_KEY]: {\n label: type.charAt(0).toUpperCase() + type.slice(1),\n text: entity.title,\n },\n } as ResolvedContextMenuContext;\n }\n return context;\n }}\n extraSections={resolved ? itemMenuConfigToExtraSections(resolved) : []}\n {...compact({ onMenuOpenChange: onOpenChange, onCloseAutoFocus })}\n >\n {children}\n </NonEditableContextMenu>\n );\n}\n","\"use client\";\n\n// features/context-menu-v3/components/OpenSurfaceMenuButton.tsx\n//\n// A ⋯ for a surface whose ONE menu otherwise opens only by right-click (the\n// data grid): it opens that surface's own menu — the same shell, the same\n// engine, the same rows — anchored at the button, never a second menu\n// (ALC-15 verifier finding 3). The event lands ON the surface element, so a\n// per-target resolver answers at the surface level (the table, no cell).\n\nimport * as React from \"react\";\nimport { MoreHorizontal } from \"lucide-react\";\nimport { Button } from \"@ai-matrx/design-system\";\nimport { cn } from \"@ai-matrx/design-system/cn\";\n\nexport function OpenSurfaceMenuButton({\n getSurface,\n label = \"More actions\",\n className,\n}: {\n /** The element the surface's context-menu shell wraps. */\n getSurface: () => HTMLElement | null;\n label?: string | undefined;\n className?: string | undefined;\n}): React.ReactElement {\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n return (\n <Button\n ref={buttonRef}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\"h-8 w-8 p-0\", className)}\n aria-label={label}\n aria-haspopup=\"menu\"\n onClick={() => {\n const surface = getSurface();\n const button = buttonRef.current;\n if (!surface || !button) return;\n const rect = button.getBoundingClientRect();\n surface.dispatchEvent(\n new MouseEvent(\"contextmenu\", {\n bubbles: true,\n cancelable: true,\n view: window,\n button: 2,\n buttons: 2,\n clientX: rect.left + rect.width / 2,\n clientY: rect.bottom,\n }),\n );\n }}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n );\n}\n"],"mappings":"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","names":["match","jsx","jsx","jsx","useState","jsx","useState","jsx","React","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/engine/ContextMenuV3.tsx","../src/engine/menu-presence.tsx","../src/engine/EditableContextMenu.tsx","../src/engine/NonEditableContextMenu.tsx","../src/engine/PageSurfaceMenu.tsx","../src/engine/item/ItemMenuHostBinding.tsx","../src/engine/item/ItemContextMenuV3.tsx","../src/engine/components/OpenSurfaceMenuButton.tsx"],"sourcesContent":["\"use client\";\n\n// features/context-menu-v3/ContextMenuV3.tsx\n//\n// The INERT shell. Mounted on every surface that wants a context menu, it must\n// stay near-empty on render — 99% of surface renders never open the menu, and\n// they must pay almost nothing. The shell contains ONLY:\n// - the Radix ContextMenu trigger wrapping the surface's children,\n// - lightweight selection capture (the hard-won macOS-safe logic),\n// - the DOM-text fallback capture that makes Copy/AI work with zero wiring,\n// - the floating-icon button + open state,\n//\n// On the FIRST open it renders `MenuContent` via next/dynamic({ssr:false}).\n// MenuContent owns ALL the weight — the unified-menu + bound-agent hooks (which\n// fire the single, deduped fetch on its mount), the launchers, the handlers,\n// the react-icons resolver, and every submenu. Every modal/window MenuContent\n// needs is dispatched through the OverlayController, so the shell carries zero\n// modal code. See `FEATURE.md` and the `code-splitting` skill.\n\nimport { compact } from \"./utils/compact\";\nimport React, { useCallback, useEffect, useRef, useState, useSyncExternalStore } from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { useIsMobile } from \"@ai-matrx/kit/media-query\";\nimport { useSelectionZone } from \"@ai-matrx/rich-content/selection-toolbar/selection-zones\";\nimport {\n CONTEXT_MENU_SELECTION_HOST_KEY,\n type ContextMenuSelectionHost,\n} from \"./selection-provider\";\nimport {\n captureTextareaSelection,\n getEditableSelectionOffsets,\n captureDomSelection,\n getSelectionRect,\n restoreTextareaSelection,\n restoreDomSelection,\n extractElementText,\n type CapturedSelection,\n type SelectionRange,\n} from \"./utils/selection-tracking\";\nimport {\n DEFAULT_MENU_DENSITY,\n DEFAULT_MENU_LAYOUT,\n type ContextMenuV3Props,\n type MenuContentProps,\n type ResolvedContextMenuContext,\n CONTEXT_MENU_ENTITY_KEY,\n CONTEXT_MENU_HEADING_KEY,\n type ContextMenuHeading,\n type ContextMenuEntityRef,\n} from \"./types\";\nimport {\n joinRowAndSurfaceContext,\n mergeResolvedContextData,\n resolveEffectiveEntity,\n sniffEntityFromDom,\n} from \"./utils/per-row-entity\";\nimport { MenuPresenceProvider, RegistryMenuSourceProvider, contentSourceKey } from \"./menu-presence\";\n\nimport { useOptionalWidgetHandle } from \"@ai-matrx/chat/agents/hooks/useWidgetHandle\";\nimport { buildEditableWidgetHandle } from \"./utils/widget-handle\";\nimport { resolveTableRowItem } from \"./table-row-item\";\nimport type { ResolvedItem } from \"@ai-matrx/alchemy/declare\";\nimport { recordMenusRevision, resolveRecordMenu, subscribeRecordMenus } from \"./record-menu-registry\";\nimport { joinExtraSections } from \"./utils/join-extra-sections\";\nimport { CONTEXT_REGION_TRIGGER_ATTRS } from \"./region-trigger-attrs\";\nimport { preloadTableShape, tableTextAtTarget } from \"./utils/table-at-target\";\nimport { findComboMatch } from \"./utils/key-combo\";\nimport { ReactReduxContext } from \"react-redux\";\nimport type { ChatAppStore as AppStore, ChatDispatch } from \"@ai-matrx/chat/store/root-state\";\nimport { getContextMenuHost, loadContextMenuHost } from \"./host/port\";\nimport { selectAllShortcutsArray } from \"@ai-matrx/chat/agents/redux/agent-shortcuts/selectors\";\n\n/**\n * Text-entry targets whose NATIVE menu we must never steal.\n *\n * A read-only menu (`isEditable === false`) offers Copy and AI actions; it\n * offers no Paste, no Undo, no spellcheck, no autofill — everything a user\n * right-clicks a live text field FOR. Swallowing that gesture makes the field\n * strictly less capable than an unwrapped one. Editable surfaces are the\n * opposite case: they wire text mutation into the menu deliberately, so they\n * keep it.\n *\n * Non-text `<input>` types (checkbox, button, range…) have no native text menu\n * to protect, so the record menu still wins there.\n */\nconst NON_TEXT_INPUT_TYPES = new Set([\n \"button\",\n \"checkbox\",\n \"color\",\n \"file\",\n \"image\",\n \"radio\",\n \"range\",\n \"reset\",\n \"submit\",\n]);\n\n/**\n * A right-click on a live text field inside a READ-ONLY menu: the innermost\n * such shell, recorded in the capture phase so every shell sees the same\n * answer in the bubble phase (see `onContextMenuCapture`).\n */\nconst NATIVE_TEXT_YIELD = new WeakMap<Event, HTMLElement>();\n\nfunction yieldsToNativeTextMenu(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n if (target.isContentEditable) return true;\n // A read-only or disabled field is NOT a live text field: its native menu\n // offers no Paste, no spellcheck, no autofill — nothing v3 lacks — so\n // yielding there trades a rich menu for a poorer one. Found live on the\n // notes tab strip (2026-08-29): the active tab's rename <input> swallowed\n // the tab's entire v3 menu even while the user wasn't renaming. Fields that\n // are only sometimes editable should render readOnly until editing intent\n // (e.g. focus) — then the yield correctly returns while they type.\n if (target instanceof HTMLTextAreaElement)\n return !target.readOnly && !target.disabled;\n if (target instanceof HTMLInputElement)\n return (\n !NON_TEXT_INPUT_TYPES.has(target.type) &&\n !target.readOnly &&\n !target.disabled\n );\n return false;\n}\n\n/**\n * A gesture that reached this shell only through a React PORTAL: its target is\n * not in the shell's DOM subtree (an open menu, a dialog or popover rendered by\n * something inside the region). React bubbles portal events to every React\n * ancestor, so a right-click — or a Mac two-finger tap mid-scroll — on an OPEN\n * message menu reached the transcript's shell around it, which opened the page\n * menu over it with both engines mounted: 18 `DuplicateActionError`s and \"the\n * menu swapped\" (blind run PB-06, /chat, 2026-10-01). A portal surface that\n * wants a menu mounts its own.\n */\nexport function reachedThroughPortal(e: { target: EventTarget | null; currentTarget: EventTarget | null }): boolean {\n const { target, currentTarget } = e;\n return target instanceof Node && currentTarget instanceof Node && !currentTarget.contains(target);\n}\n\n/** The moment a menu opens, for Inspect's open-to-paint timing (designed/DesignedMenu marks the paint). */\nfunction markMenuOpen(): void {\n try {\n performance.mark(\"ai-matrx.context-menu.open\");\n } catch {\n /* marks are best-effort */\n }\n}\n\n/** A right-click on an open menu: no native browser menu over ours. */\nfunction isInsideOpenMenu(target: EventTarget | null): boolean {\n return target instanceof Element && Boolean(target.closest('[data-alchemy-layout], [role=\"menu\"]'));\n}\n\n// THE single heavy boundary (T1 + T1e). ssr:false keeps it — the engine hook,\n// the agent fetch, the package renderers — off the server render and out of\n// the shell's chunk; it mounts on first open only. One boundary for the\n// right-click, the floating icon, the phone sheet and the palette (ALC-15 S3:\n// the package draws all four from one registry).\ntype MenuContentModule = typeof import(\"@ai-matrx/context-menu/menu-content\");\nconst MENU_CONTENT_SLOT = Symbol.for(\"ai-matrx.context-menu.menu-content\");\ntype MenuContentSlot = { module: MenuContentModule | null; warm: Promise<unknown> | null };\nfunction menuContentSlot(): MenuContentSlot {\n const g = globalThis as unknown as Record<symbol, MenuContentSlot | undefined>;\n return (g[MENU_CONTENT_SLOT] ??= { module: null, warm: null });\n}\nfunction loadMenuContent(): Promise<MenuContentModule> {\n // The host's heavier members (`loadOnOpen`) arrive WITH the body, never at boot.\n return Promise.all([import(\"@ai-matrx/context-menu/menu-content\"), loadContextMenuHost()]).then(([m]) => {\n menuContentSlot().module = m;\n return m;\n });\n}\n/** The loaded boundary, or null until it arrives (renders nothing meanwhile, like ssr:false). */\nfunction useMenuContentModule(): MenuContentModule | null {\n const [mod, setMod] = useState<MenuContentModule | null>(() => menuContentSlot().module);\n useEffect(() => {\n if (mod) return;\n let live = true;\n loadMenuContent().then(\n (m) => {\n if (live) setMod(m);\n },\n (error: unknown) => console.error(\"[ContextMenuV3] could not load the menu\", error),\n );\n return () => {\n live = false;\n };\n }, [mod]);\n return mod;\n}\ntype AlchemyMenuContentProps = React.ComponentProps<MenuContentModule[\"AlchemyMenuContent\"]>;\ntype ShortcutKeyRunnerProps = React.ComponentProps<MenuContentModule[\"ShortcutKeyRunner\"]>;\nfunction AlchemyMenuContent(props: AlchemyMenuContentProps) {\n const mod = useMenuContentModule();\n return mod ? <mod.AlchemyMenuContent {...props} /> : null;\n}\n\n/**\n * Warm THAT SAME chunk once per tab, when the browser is idle after the first\n * menu shell mounts — so the first right-click draws at once instead of\n * fetching (and, in dev, compiling) the engine under the pointer (G11A review,\n * 2026-10-07: the first open after a page load took 1–2 s). It is the same\n * specifier as the `dynamic()` above, so it adds no chunk and no boundary\n * (code-splitting rule 3); it only moves WHEN the browser fetches it. The\n * menu still renders only on open.\n */\nexport function warmMenuContent(): Promise<unknown> {\n const slot = menuContentSlot();\n if (!slot.warm) {\n slot.warm = loadMenuContent().catch((error: unknown) => {\n slot.warm = null;\n console.error(\"[ContextMenuV3] could not warm the menu; the first open will load it\", error);\n });\n }\n return menuContentSlot().warm ?? Promise.resolve();\n}\n\n// ── The one selectionchange listener ────────────────────────────────────────\ninterface SelectionTracker {\n owner: () => HTMLElement | null;\n locked: () => boolean;\n set: (text: string) => void;\n}\nconst selectionTrackers = new Set<SelectionTracker>();\n/** Trackers told they own the selection last time — the only ones to clear next time. */\nlet selectionHolders = new Set<SelectionTracker>();\n\nfunction onDocumentSelectionChange(): void {\n const selection = window.getSelection();\n const anchor = selection?.anchorNode ?? null;\n const active = document.activeElement;\n const field = active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement ? active : null;\n const holders = new Set<SelectionTracker>();\n if (anchor || field) {\n for (const tracker of selectionTrackers) {\n const owner = tracker.owner();\n if (!owner) continue;\n if ((anchor != null && owner.contains(anchor)) || (field != null && owner.contains(field))) holders.add(tracker);\n }\n }\n for (const tracker of selectionHolders) {\n if (!holders.has(tracker) && !tracker.locked()) tracker.set(\"\");\n }\n if (holders.size > 0) {\n // A collapsed selection (a caret — every keystroke in an editor) has no\n // text. `toString()` is not free: it serializes like innerText and forces\n // a synchronous layout of the whole page (2026-09-26).\n const text = !selection || selection.isCollapsed ? \"\" : selection.toString().trim();\n for (const tracker of holders) if (!tracker.locked()) tracker.set(text);\n }\n selectionHolders = holders;\n}\n\nfunction trackSelection(tracker: SelectionTracker): () => void {\n if (selectionTrackers.size === 0) document.addEventListener(\"selectionchange\", onDocumentSelectionChange);\n selectionTrackers.add(tracker);\n return () => {\n selectionTrackers.delete(tracker);\n selectionHolders.delete(tracker);\n if (selectionTrackers.size === 0) document.removeEventListener(\"selectionchange\", onDocumentSelectionChange);\n };\n}\n\n/**\n * Set by the first open of ANY menu on the page. Nothing that is only useful to\n * an opened menu (the shortcut list for key combos) loads before it: a menu is\n * opened on ~1 in 149 page loads, so until then it costs nothing.\n */\nlet menuEverOpened = false;\n\n// One advertised key combo pressed → that shortcut runs through the SAME\n// engine and launch handler as its menu item; mounted for one press only.\nfunction ShortcutKeyRunner(props: ShortcutKeyRunnerProps) {\n const mod = useMenuContentModule();\n return mod ? <mod.ShortcutKeyRunner {...props} /> : null;\n}\n/** A key press an inner menu already answered (nested surfaces). */\nconst KEY_RUN_CLAIMED = \"__alchemyShortcutKeyClaimed\";\n\n// The review-and-apply dialog behind \"Clean up\" / \"Help with this…\" when the\n// menu sits over a record that can be saved (a note's Write / Plain / Split\n// view, its tab, its list row) and the host supplied no dialog of its own. It must outlive the menu that asked, so the shell owns it —\n// mounted only after the first request, like every document dialog.\n// The component is the host's (`configureContextMenuHost({ DocumentAgentReview })`);\n// a host that registers none gets no review dialog and the request is announced.\nfunction DocumentAgentReviewHost(props: {\n actionId: TextAgentReviewRequest[\"actionId\"];\n ctx: TextAgentReviewRequest[\"ctx\"];\n onClose: () => void;\n}) {\n const Review = getContextMenuHost().DocumentAgentReview;\n React.useEffect(() => {\n if (!Review) {\n console.warn('[context-menu] host port \"DocumentAgentReview\" is not wired — the review request was dropped.');\n props.onClose();\n }\n }, [Review, props]);\n return Review ? <Review {...props} /> : null;\n}\ntype TextAgentReviewRequest = {\n actionId: \"cleanup\" | \"help\" | \"customAgent\";\n ctx: import(\"@ai-matrx/rich-content/rich-document/types\").RichDocumentActionContext;\n};\n\n// ── The palette opens from ANYWHERE on a surface with a menu (ALC-15) ───────\n// ⌘/Ctrl+Shift+K with focus on the page body (a read-only note) or over a grid\n// cell (cells are not focusable) opens the palette of the INNERMOST surface\n// under the pointer, resolved for the element under the pointer. One document\n// listener for the whole page (on globalThis — module state is per bundle).\ntype PaletteOpener = (element: HTMLElement) => void;\ntype SurfaceClaim = { id: symbol; element: HTMLElement; seq: number; at: number };\ninterface PaletteRegistry {\n openers: Map<symbol, PaletteOpener>;\n /** Innermost surface under the pointer (where a right-click would land). */\n pointer: SurfaceClaim | null;\n /** Innermost surface holding focus. */\n focus: SurfaceClaim | null;\n /** Last press — a focus it caused never outranks the pointer. */\n pointerDown: { element: HTMLElement; at: number } | null;\n seq: number;\n installed: boolean;\n}\nconst PALETTE_KEY = Symbol.for(\"ai-matrx.context-menu.palette\");\nfunction paletteRegistry(): PaletteRegistry {\n const g = globalThis as unknown as Record<symbol, PaletteRegistry | undefined>;\n let reg = g[PALETTE_KEY];\n if (!reg) {\n reg = { openers: new Map(), pointer: null, focus: null, pointerDown: null, seq: 0, installed: false };\n g[PALETTE_KEY] = reg;\n }\n if (!reg.installed && typeof document !== \"undefined\") {\n reg.installed = true;\n const r = reg;\n document.addEventListener(\"keydown\", (e) => {\n if (e.defaultPrevented) return;\n if (!(e.metaKey || e.ctrlKey) || !e.shiftKey || e.key.toLowerCase() !== \"k\") return;\n const target = paletteTarget(r);\n const open = target ? r.openers.get(target.id) : undefined;\n if (!target || !open) return;\n e.preventDefault();\n open(target.element);\n });\n }\n return reg;\n}\n/**\n * Where the palette opens — exactly where right-click would: the innermost\n * surface under the pointer. Focus wins only when it moved AFTER the pointer\n * by the keyboard (Tab), never the focus a click itself caused (clicking an\n * answer focuses its outer message article; round 2, finding 1).\n */\nfunction paletteTarget(r: PaletteRegistry): SurfaceClaim | null {\n const live = (c: SurfaceClaim | null) => (c && c.element.isConnected && r.openers.has(c.id) ? c : null);\n const pointer = live(r.pointer);\n const focus = live(r.focus);\n if (!focus) return pointer;\n if (!pointer) return focus;\n if (focus.seq < pointer.seq) return pointer;\n // A focus the last press caused (the pressed element sits inside what took\n // focus, moments later) is the click's side effect, not a keyboard move.\n const down = r.pointerDown;\n const causedByPress =\n !!down && focus.element.contains(down.element) && focus.at - down.at < 1000;\n return causedByPress ? pointer : focus;\n}\nconst CLAIMED = \"__alchemyPaletteClaimed\";\n\ntype OpenMenu = {\n mode: \"context\" | \"sheet\" | \"palette\";\n point: { x: number; y: number };\n};\n\nexport function ContextMenuV3({\n children,\n sourceFeature,\n surfaceName,\n menuVersion = 1,\n getApplicationScope,\n contextData = {},\n resolveContextOnOpen,\n contentSource,\n entity,\n excludedRichActions,\n recordActionsOnly = false,\n subjectFold,\n extraRichActions,\n richDocCtxExtras,\n placementMode,\n extraSections,\n resolveExtraSectionsOnOpen,\n onUndo,\n onRedo,\n canUndo = false,\n canRedo = false,\n undoHint,\n redoHint,\n onViewHistory,\n hasHistory = false,\n scope = \"global\",\n scopeId = null,\n className,\n menuLayout = DEFAULT_MENU_LAYOUT,\n menuDensity = DEFAULT_MENU_DENSITY,\n menuDesign,\n menuFeatureTitle,\n suppressed = false,\n onMenuOpenChange,\n onCloseAutoFocus,\n isEditable,\n editorId,\n getTextarea,\n insertAtCaret,\n onContentInserted,\n onTextReplace,\n onTextInsertBefore,\n onTextInsertAfter,\n onSave,\n onDelete,\n}: ContextMenuV3Props) {\n const [selectedText, setSelectedText] = useState<string>(\"\");\n const [selectionRange, setSelectionRange] = useState<SelectionRange | null>(\n null,\n );\n const [fallbackContent, setFallbackContent] = useState<string>(\"\");\n const [menuOpen, setMenuOpen] = useState(false);\n const [textAgentReview, setTextAgentReview] = useState<TextAgentReviewRequest | null>(null);\n const requestTextAgentReview = useCallback(\n (actionId: TextAgentReviewRequest[\"actionId\"], ctx: TextAgentReviewRequest[\"ctx\"]) =>\n setTextAgentReview({ actionId, ctx }),\n [],\n );\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const isMobile = useIsMobile();\n const [sheetOpen, setSheetOpen] = useState(false);\n const [paletteOpen, setPaletteOpen] = useState(false);\n const [keyRun, setKeyRun] = useState<{ id: string; label: string } | null>(null);\n // Read without subscribing, and without requiring a Provider (the shell also\n // renders in isolated hosts and tests).\n const store = React.useContext(ReactReduxContext)?.store as AppStore | undefined;\n // Where the desktop menu anchors (pointer, ⋯ button, floating icon) and a\n // counter so every open mounts a fresh engine over a fresh click target.\n const [menuPoint, setMenuPoint] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n const [openSeq, setOpenSeq] = useState(0);\n // Nothing runs before the person engages this surface (first pointer press,\n // focus or open). /notes mounts one shell per sidebar row; an idle shell owns\n // no document listener, no selection zone and no widget handle.\n const [engaged, setEngaged] = useState(false);\n const engage = () => setEngaged(true);\n\n const capturedSelection = useRef<CapturedSelection | null>(null);\n const selectionLocked = useRef(false);\n const lastMousePos = useRef<{ x: number; y: number } | null>(null);\n // The DOM element this instance wraps — the child element itself on both\n // desktop (Radix `ContextMenuTrigger asChild`) and mobile (`Slot`), falling\n // back to the display:contents wrapper only when mobile cannot slot onto a\n // single child. Selection tracking is scoped to it — see handleSelection.\n const selectionOwnerRef = useRef<HTMLElement | null>(null);\n // The same element, as state: it is this menu's zone of the ONE selection\n // toolbar (components/selection-toolbar), which replaced the floating icon.\n const [selectionOwner, setSelectionOwnerState] = useState<HTMLElement | null>(null);\n const setSelectionOwner = useCallback((node: HTMLElement | null) => {\n selectionOwnerRef.current = node;\n setSelectionOwnerState(node);\n }, []);\n // Mobile long-press → bottom sheet (no right-click on touch).\n const longPressTimer = useRef<number | null>(null);\n const touchStart = useRef<{\n x: number;\n y: number;\n target: HTMLElement;\n container: HTMLElement;\n } | null>(null);\n // Per-invocation context resolved by `resolveContextOnOpen` (single-instance\n // delegation). State, not a ref — it's written only at right-click (which\n // re-renders to open the menu anyway), and the lazy MenuContent must read it\n // during render to build the effective scope (a ref read in render is banned).\n /** The element the menu was opened on — its record's NAME is read live. */\n const [openTarget, setOpenTarget] = useState<HTMLElement | null>(null);\n // Bumps when a registered record's rows change (a rename) — an argument of\n // the heading read below, so it is re-read.\n // Only an OPEN menu listens: a closed one reads the rows fresh at its next\n // open anyway. Every mounted menu listening re-rendered every sidebar row and\n // folder header each time a new note's auto-label moved while typing — O(notes)\n // work per label change (the Write-mode freeze sweep, 2026-10-10).\n const anyMenuOpen = menuOpen || dropdownOpen || sheetOpen || paletteOpen;\n const subscribeWhileOpen = useCallback(\n (listener: () => void) => (anyMenuOpen ? subscribeRecordMenus(listener) : () => {}),\n [anyMenuOpen],\n );\n const recordRevision = useSyncExternalStore(\n subscribeWhileOpen,\n recordMenusRevision,\n recordMenusRevision,\n );\n const [resolvedContext, setResolvedContext] =\n useState<ResolvedContextMenuContext | null>(null);\n /** The declared item this open is on (a table row), handed to the click target. */\n const [resolvedItem, setResolvedItem] = useState<ResolvedItem | null>(null);\n const [resolvedExtraSections, setResolvedExtraSections] =\n useState<typeof extraSections>(undefined);\n /** This open is on a table row whose surface draws its own row sections (see resolvePerTargetContext). */\n const [rowJoinsSurfaceSections, setRowJoinsSurfaceSections] = useState(false);\n /**\n * The entity read straight off the right-clicked element's `data-entity-*`\n * attributes (Phase 0, 2026-08-25). State for the same reason as\n * `resolvedContext`: the lazy MenuContent must read it during the render\n * that opens the menu. Only the SHELL sees the clicked element, so the sniff\n * has to happen here. Fills a silence — never overrides a surface answer.\n */\n const [sniffedEntity, setSniffedEntity] =\n useState<ContextMenuEntityRef | null>(null);\n // Set by MenuContent (via suppressSelectionRestore) when an action opens an\n // overlay that should keep focus — so closing the menu doesn't yank it back.\n const skipSelectionRestoreRef = useRef(false);\n\n // ── Inline agent editing (WidgetHandle) ──────────────────────────────────\n // Editable surfaces get a widget handle derived from the SAME callbacks they\n // already pass the menu, registered here in the shell (NOT in the lazy\n // MenuContent — that unmounts on close, and the handle must outlive the menu\n // for the whole agent stream). Read-only surfaces register nothing. The\n // launch handlers pass the id as `runtime.widgetHandleId`, so agents\n // launched from this menu can stream `widget_text_*` edits into the surface.\n // Weight check: buildEditableWidgetHandle + useOptionalWidgetHandle pull in\n // only types, the callbackManager map, and selection-tracking — no data\n // hooks, no icons; the shell stays inert.\n const widgetHandle = isEditable\n ? buildEditableWidgetHandle({\n getTextarea,\n onTextReplace,\n onTextInsertBefore,\n onTextInsertAfter,\n getApplicationScope,\n })\n : null;\n const widgetHandleId = useOptionalWidgetHandle(engaged ? widgetHandle : null);\n\n // Effective contextData for THIS invocation: static prop + per-target merge,\n // minus the reserved `__entity` key (which is not a value — see below).\n const getEffectiveContextData = (): Record<string, unknown> =>\n mergeResolvedContextData(\n contextData as Record<string, unknown> | undefined,\n resolvedContext,\n );\n\n // Effective entity for THIS invocation. ONE menu serves N rows, so the row\n // the user actually right-clicked — not the pane — must own Attach To /\n // Share. `resolveContextOnOpen` supplies it via `CONTEXT_MENU_ENTITY_KEY`;\n // when it doesn't, the menu-level `entity` prop stands unchanged.\n // Precedence: an explicit `resolveContextOnOpen` answer (including a\n // deliberate `null`) wins; only when the surface said nothing about the\n // entity does the DOM sniff fill in; the menu-level prop is the floor.\n const surfaceSpokeAboutEntity =\n !!resolvedContext && CONTEXT_MENU_ENTITY_KEY in resolvedContext;\n const effectiveEntity = surfaceSpokeAboutEntity\n ? resolveEffectiveEntity(entity, resolvedContext)\n : (sniffedEntity ?? entity);\n\n // ── Selection tracking — SCOPED to this instance's wrapped subtree ───────\n // The listener is document-global (that's the only selectionchange there\n // is), but ALL work is gated on ownership: the selection's anchor node —\n // or, for textarea/input selections (where the DOM Range stays parked on\n // the host), the focused element — must live inside our wrapped children.\n // Without this gate every mounted instance on the page (on /notes: the\n // editor + EVERY sidebar row + folder headers) serialized the full\n // selected text via `selection.toString()` (O(document) on a triple-click\n // of a large paste), stored it in its own state, and rendered its own\n // floating selection icon (since replaced by the ONE selection toolbar) at the same coordinates — dozens of stacked\n // translucent buttons compounding into a black-shadowed blob, and N×\n // O(document) main-thread work per selection event: a browser-freeze\n // amplifier (2026-07 /notes freeze class).\n useEffect(() => {\n if (!engaged) return;\n // ONE document listener for every instance (selectionTracker below): a\n // selection change walks up from the anchor to the instances that own it,\n // so a keystroke costs O(depth), not O(mounted menus) — /notes mounts one\n // per sidebar row and folder header (the Write-mode freeze sweep, 2026-10-10).\n return trackSelection({\n owner: () => selectionOwnerRef.current,\n locked: () => selectionLocked.current,\n set: setSelectedText,\n });\n }, [engaged]);\n\n // The pointer position (the ⋯ / selection fallback anchor) is read off the\n // events this surface already receives — no page-wide mousemove listener.\n const rememberPointer = (e: { clientX: number; clientY: number }) => {\n lastMousePos.current = { x: e.clientX, y: e.clientY };\n };\n\n // ── Capture handlers ─────────────────────────────────────────────────────\n const handleMouseDown = (e: React.MouseEvent) => {\n if (suppressed) return; // yield to the native menu (e.g. streaming)\n if (reachedThroughPortal(e)) return;\n if (e.button !== 2) return; // right-click only\n // Engagement: start fetching the menu body now, in parallel with the open.\n void warmMenuContent();\n // Must mirror the capture guard exactly. Capturing here would set\n // `selectionLocked` for a menu that is never going to open, and only\n // `handleMenuClose` clears it — so selection tracking would stay frozen\n // for the rest of this instance's life.\n if (!isEditable && yieldsToNativeTextMenu(e.target)) return;\n const target = e.target as HTMLElement;\n resolvePerTargetContext(target);\n selectionLocked.current = true;\n\n if (\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLInputElement\n ) {\n const captured = captureTextareaSelection(target);\n capturedSelection.current = captured;\n setSelectedText(captured.text);\n } else {\n const captured = captureDomSelection();\n capturedSelection.current = captured;\n setSelectedText(captured.text);\n }\n };\n\n // Per-target context resolution — MUST run on EVERY open path (right-click,\n // keyboard contextmenu, mobile long-press/sheet, floating icon), not just\n // button-2 mousedown: single-instance consumers (ItemContextMenu, markdown,\n // PDF regions) build their menu items from this. A double call on the plain\n // right-click path (mousedown then contextmenu) is deliberate — re-resolving\n // is idempotent and keeps lazy configs fresh.\n const resolvePerTargetContext = (target: HTMLElement | null) => {\n // Every open path passes through here: this is the first open on the page.\n menuEverOpened = true;\n engage();\n // A table under the click: its shape reader loads now, ahead of \"Save to a table\".\n if (target?.closest(\"table\")) void preloadTableShape();\n const rowHit = resolveTableRowItem(target);\n const rowMenu = rowHit?.menu ?? null;\n setResolvedItem(rowHit?.item ?? null);\n // A table row has two owners: the table's descriptor names the row's values, the surface\n // names which RECORD the row is (and builds its own row doors from that same call). Both\n // are asked, always — `rowMenu?.context ?? surface` skipped the surface on every table row.\n const answered = joinRowAndSurfaceContext(\n rowMenu?.context,\n resolveContextOnOpen ? resolveContextOnOpen(target) : null,\n );\n // A record the content belongs to names the header when the target\n // names nothing itself (record-menu-registry.ts `heading`) — read at\n // RENDER from this target (`recordHeadingAt`), so a rename while the menu\n // is open or mounted reaches the header.\n setOpenTarget(target);\n setResolvedContext(answered);\n const surfaceSections = resolveExtraSectionsOnOpen?.(target);\n // Several owners, one menu: joined so a row id is drawn once (utils/join-extra-sections.ts).\n const ownSections = joinExtraSections(rowMenu?.extraSections, surfaceSections);\n // A surface that resolves per target draws its row's doors through the `extraSections` PROP\n // (rebuilt from the state its resolver just set), so on a table row they join the table's\n // own at RENDER, when the prop is fresh — never from this closure's previous row.\n // A surface's own STATIC sections (a per-row menu wrapping a table row: Files' Preview,\n // Rename, Move…) join the table's too — they used to be replaced by the row's sections.\n setRowJoinsSurfaceSections(!!rowMenu && !surfaceSections);\n // The record whose content this is (a note's tab rows, drawn apart from its\n // content): its rows join THIS menu, so the record's ⋯ and a right-click on\n // its content are one menu (record-menu-registry.ts, R26). The content's own\n // row wins over the record's row with the same id — never both.\n const record = resolveRecordMenu(target);\n setResolvedExtraSections(\n record?.extraSections.length\n ? joinExtraSections(ownSections ?? extraSections ?? [], record.extraSections)\n : ownSections,\n );\n // The record's entity fills a silence only — never over this menu's own.\n setSniffedEntity(sniffEntityFromDom(target) ?? (entity ? null : (record?.entity ?? null)));\n };\n\n // Shared capture — populates selection/content state from a right-click target\n // OR a long-press target (mobile). Does not open anything; the caller does.\n const captureContext = (target: HTMLElement, containerEl: HTMLElement) => {\n resolvePerTargetContext(target);\n let captured = capturedSelection.current;\n // A selection made somewhere ELSE is not what this right-click is about:\n // the Subject field's menu headed itself with the Message's selected text\n // (page-pass 2026-09-27). Keep a remembered selection only when it lies in\n // the field under the pointer (or, outside any field, in this menu's own\n // region); otherwise read afresh from the target.\n const scopeEl: Node =\n target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement\n ? target\n : (target.closest('[contenteditable=\"true\"], [contenteditable=\"\"]') ?? containerEl);\n if (captured?.range && !scopeEl.contains(captured.range.commonAncestorContainer)) {\n captured = null;\n }\n if (!captured || !captured.text) {\n captured =\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLInputElement\n ? captureTextareaSelection(target)\n : captureDomSelection();\n capturedSelection.current = captured;\n selectionLocked.current = true;\n }\n\n if (\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLInputElement\n ) {\n // THE SELECTION THE MENU OPENED ON IS THE ONE EVERY READER SEES. A right\n // mousedown outside the highlight moves the caret AFTER the mousedown\n // capture: the header said \"Selected: …\" while a surface's live scope\n // builder (notes reads the field's selectionStart/End) saw a caret, so\n // selection shortcuts vanished or ran on nothing (2026-10-02). Put the\n // captured range back on the field so the header, the scope, and the\n // restore-on-close all name the same text.\n const remembered =\n captured?.editable &&\n captured.editable.element === target &&\n captured.editable.start !== captured.editable.end\n ? captured.editable\n : null;\n const { start, end } = remembered ?? getEditableSelectionOffsets(target);\n if (remembered) {\n const live = getEditableSelectionOffsets(target);\n if (live.start !== start || live.end !== end) {\n try {\n target.setSelectionRange(start, end);\n } catch {\n // A field without a selection API keeps its whole-value range.\n }\n }\n }\n setSelectedText(captured?.text || \"\");\n setSelectionRange({\n type: \"editable\",\n element: target,\n start,\n end,\n range: null,\n containerElement: null,\n });\n // Fallback content = the whole field, so Copy/AI work even with no selection.\n setFallbackContent(target.value ?? \"\");\n } else {\n let containerElement = containerEl;\n if (!containerElement.hasAttribute(\"data-alchemy-trigger\")) {\n const trigger = containerElement.querySelector(\n \"[data-alchemy-trigger]\",\n );\n if (trigger instanceof HTMLElement) containerElement = trigger;\n }\n setSelectedText(captured?.text || \"\");\n setSelectionRange({\n type: \"non-editable\",\n // A contenteditable FIELD the right-click landed in (a rich or chip\n // editor): recorded so the menu header can name the field instead of\n // dumping its raw text. Every reader of `.element` gates on\n // `type === \"editable\"`, so this changes nothing else.\n element: target.closest<HTMLElement>('[contenteditable=\"true\"], [contenteditable=\"\"]'),\n start: 0,\n end: 0,\n range: captured?.range || null,\n containerElement,\n });\n // Fallback content = the right-clicked subtree's text — the net that\n // makes a read-only surface copyable with zero wiring (kills \"fake menu\").\n setFallbackContent(extractElementText(containerElement));\n }\n };\n\n const handleContextMenu = (e: React.MouseEvent) => {\n if (suppressed) return; // trigger is disabled; native menu shows\n // Radix's innermost trigger prevents the native event after it opens. Let\n // that event bubble so the inner Radix handler can run, then make every\n // outer shell yield when it sees the already-prevented event. Calling\n // stopPropagation here aborts the asChild-composed Radix handler on nested\n // rows, leaving the row with no menu at all.\n if (e.defaultPrevented) return;\n // The innermost eligible trigger owns the gesture: preventing here is what\n // makes every outer shell yield (and hides the native menu).\n e.preventDefault();\n captureContext(e.target as HTMLElement, e.currentTarget as HTMLElement);\n setMenuPoint({ x: e.clientX, y: e.clientY });\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setMenuOpen(true);\n onMenuOpenChange?.(true);\n };\n\n const handleMenuClose = () => {\n setMenuOpen(false);\n selectionLocked.current = false;\n capturedSelection.current = null;\n if (skipSelectionRestoreRef.current) {\n skipSelectionRestoreRef.current = false;\n return;\n }\n if (!selectionRange) return;\n if (selectionRange.type === \"editable\") {\n const { element, start, end } = selectionRange;\n if (\n element instanceof HTMLTextAreaElement ||\n element instanceof HTMLInputElement\n ) {\n restoreTextareaSelection(element, start, end);\n }\n } else if (selectionRange.range) {\n restoreDomSelection(selectionRange.range);\n }\n };\n\n const handleDropdownClose = (open: boolean) => {\n onMenuOpenChange?.(open);\n setDropdownOpen(open);\n if (!open) {\n selectionLocked.current = false;\n capturedSelection.current = null;\n }\n };\n\n // Opened from the ONE selection toolbar's \"Ask AI\" (components/selection-\n // toolbar; it replaced the floating selection icon): the same menu over the\n // selected text — a panel under the selection on desktop, the sheet on a phone.\n const openFromSelection = () => {\n if (suppressed) return;\n selectionLocked.current = true;\n const sel = window.getSelection();\n const container =\n sel && sel.rangeCount > 0\n ? (sel.getRangeAt(0).commonAncestorContainer.parentElement ?? null)\n : null;\n resolvePerTargetContext(container);\n setFallbackContent(extractElementText(container));\n if (isMobile) {\n setSelectedText(sel?.toString().trim() || selectedText);\n setSelectionRange({\n type: \"non-editable\",\n element: null,\n start: 0,\n end: 0,\n range: sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null,\n containerElement: container,\n });\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setSheetOpen(true);\n return;\n }\n const rect = getSelectionRect();\n const at = rect\n ? { x: rect.left, y: rect.bottom + 4 }\n : (lastMousePos.current ?? { x: 16, y: 16 });\n setMenuPoint(at);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setDropdownOpen(true);\n };\n\n const selectionHost: ContextMenuSelectionHost = { kind: \"context-menu-selection\", open: openFromSelection };\n // No `editable` flag: an editable menu often wraps a read-only preview too\n // (a note's split view), so the toolbar reads editing from the DOM (a text\n // field or contenteditable under the selection), never from the wrapper.\n // Registered only once the surface is engaged (a selection needs a press or focus first).\n useSelectionZone(\n selectionOwner,\n engaged\n ? {\n // A suppressed menu (the text is streaming) keeps the toolbar away until it settles.\n suppress: suppressed,\n host: { [CONTEXT_MENU_SELECTION_HOST_KEY]: selectionHost },\n }\n : null,\n );\n\n // ── Mobile triggers (no right-click on touch) ─────────────────────────────\n const clearLongPress = () => {\n if (longPressTimer.current !== null) {\n clearTimeout(longPressTimer.current);\n longPressTimer.current = null;\n }\n };\n const handleTouchStart = (e: React.TouchEvent) => {\n if (suppressed) return;\n if (reachedThroughPortal(e)) return;\n // The touch half of the native-menu rule. Long-press inside a text field IS\n // the OS text callout (Select / Paste / Look Up) — pre-empting it at 480ms\n // leaves a mobile user with no way to paste at all, which is worse than the\n // desktop case because there is no right-click to fall back to. The guard\n // shipped on the three pointer paths and missed this one, so the stated\n // invariant held on desktop only.\n if (!isEditable && yieldsToNativeTextMenu(e.target)) return;\n // Nested menus are deliberate (for example, a page-list menu around\n // per-row menus). The innermost eligible trigger owns the gesture; without\n // this both long-press timers fire and two mobile sheets open.\n e.stopPropagation();\n const t = e.touches[0];\n if (!t) return;\n touchStart.current = {\n x: t.clientX,\n y: t.clientY,\n target: e.target as HTMLElement,\n container: e.currentTarget as HTMLElement,\n };\n clearLongPress();\n longPressTimer.current = window.setTimeout(() => {\n const info = touchStart.current;\n if (!info) return;\n captureContext(info.target, info.container);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setSheetOpen(true);\n }, 480);\n };\n const handleTouchMove = (e: React.TouchEvent) => {\n const info = touchStart.current;\n const t = e.touches[0];\n if (!info || !t) return;\n // A drag means the user is scrolling or selecting — not a long-press.\n if (Math.abs(t.clientX - info.x) > 10 || Math.abs(t.clientY - info.y) > 10)\n clearLongPress();\n };\n const handleTouchEnd = () => clearLongPress();\n\n const handleSheetOpenChange = (open: boolean) => {\n onMenuOpenChange?.(open);\n setSheetOpen(open);\n if (!open) {\n selectionLocked.current = false;\n capturedSelection.current = null;\n }\n };\n\n // ── The single prop bag handed to the lazy MenuContent ───────────────────\n const menuContentProps = compact({\n sourceFeature,\n surfaceName,\n menuVersion,\n // A row descriptor owns this invocation's values. Preserve page-level live\n // values for empty space, but never let them overwrite the clicked row.\n getApplicationScope: resolvedContext\n ? () => ({ ...(getApplicationScope?.() ?? {}), ...getEffectiveContextData() })\n : getApplicationScope,\n contextData: getEffectiveContextData(),\n heading:\n readContextMenuHeading(resolvedContext) ??\n recordHeadingAt(openTarget, recordRevision),\n item: resolvedItem,\n contentSource,\n entity: effectiveEntity,\n excludedRichActions,\n recordActionsOnly,\n subjectFold,\n // The hook adds it only where the source can be saved and no host supplied one.\n requestTextAgentReview,\n extraRichActions,\n // The table the click landed on rides to \"Save to a table\" beside the host's own extras.\n richDocCtxExtras: {\n ...richDocCtxExtras,\n callbacks: {\n ...richDocCtxExtras?.callbacks,\n tableAtTarget: () => tableTextAtTarget(openTarget),\n },\n // Spreading an optional bag leaves its Pick'd keys optional; the hook spreads it over defaults.\n } as NonNullable<MenuContentProps[\"richDocCtxExtras\"]>,\n selectedText,\n selectionRange,\n fallbackContent,\n placementMode,\n scope,\n scopeId,\n extraSections: resolvedExtraSections\n ? rowJoinsSurfaceSections\n ? joinExtraSections(resolvedExtraSections, extraSections)\n : resolvedExtraSections\n : extraSections,\n menuLayout,\n menuDensity,\n menuDesign,\n menuFeatureTitle,\n isEditable,\n editorId,\n getTextarea,\n insertAtCaret,\n onContentInserted,\n onTextReplace,\n onTextInsertBefore,\n onTextInsertAfter,\n onSave,\n onDelete,\n onUndo,\n onRedo,\n canUndo,\n canRedo,\n undoHint,\n redoHint,\n onViewHistory,\n hasHistory,\n widgetHandleId,\n suppressSelectionRestore: () => {\n skipSelectionRestoreRef.current = true;\n },\n }) as Omit<MenuContentProps, \"variant\">;\n\n // Radix `asChild` is a strict one-element slot. Consumers may legitimately\n // wrap a surface plus sibling loading/empty states, so normalize that shape\n // to one layout-neutral element before either renderer reaches a Slot.\n //\n // THE ATTACH POINT (verify round 1, the ref-forwarding class): the menu's handlers\n // and its selection zone need a real DOM element. A slot onto a COMPONENT that does\n // not forward its ref (or spread its props) leaves none — the right-click menu and the\n // selection toolbar then silently do nothing. So the menu slots only onto an intrinsic\n // DOM element (`<div>`, `<tr>` — they always take a ref and props) and otherwise owns\n // its own `display: contents` wrapper. Guard: __tests__/attach-point.test.tsx.\n const canSlotChildren =\n React.Children.count(children) === 1 &&\n React.isValidElement(children) &&\n typeof children.type === \"string\";\n\n // The version footer is gone (Arman, 2026-08-22: dev/testing info, not for\n // users). The surface name + revision now live in the surface submenu the\n // engine builds (`surfaceSection`), admin-only for the revision.\n\n\n // Register this surface's palette opener; the innermost trigger under the\n // pointer (or holding focus) claims \"last surface\" for the page listener.\n const paletteIdRef = useRef<symbol | null>(null);\n paletteIdRef.current ??= Symbol(\"context-menu-surface\");\n const openPaletteAt = (element: HTMLElement) => {\n if (suppressed) return;\n const container = selectionOwnerRef.current ?? element;\n captureContext(element, container);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setPaletteOpen(true);\n onMenuOpenChange?.(true);\n };\n const openPaletteRef = useRef(openPaletteAt);\n useEffect(() => {\n openPaletteRef.current = openPaletteAt;\n });\n useEffect(() => {\n const reg = paletteRegistry();\n const id = paletteIdRef.current as symbol;\n reg.openers.set(id, (el) => openPaletteRef.current(el));\n return () => {\n reg.openers.delete(id);\n if (reg.pointer?.id === id) reg.pointer = null;\n if (reg.focus?.id === id) reg.focus = null;\n };\n }, []);\n const claim = (kind: \"pointer\" | \"focus\") => (e: React.SyntheticEvent<HTMLElement>) => {\n const native = e.nativeEvent as Event & { [CLAIMED]?: boolean };\n if (native[CLAIMED]) return; // an inner surface already claimed it\n native[CLAIMED] = true;\n const reg = paletteRegistry();\n const now = Date.now();\n if (e.type === \"pointerdown\") reg.pointerDown = { element: e.target as HTMLElement, at: now };\n if (e.type === \"pointerdown\" || e.type === \"focusin\" || e.type === \"focus\") engage();\n if (e.type === \"pointerover\" || e.type === \"pointerdown\") rememberPointer(e as unknown as React.PointerEvent);\n reg.seq += 1;\n reg[kind] = { id: paletteIdRef.current as symbol, element: e.target as HTMLElement, seq: reg.seq, at: now };\n };\n\n const mode: \"context\" | \"sheet\" | \"palette\" | null = sheetOpen\n ? \"sheet\"\n : paletteOpen\n ? \"palette\"\n : menuOpen || dropdownOpen\n ? \"context\"\n : null;\n const closeActive = () => {\n if (sheetOpen) handleSheetOpenChange(false);\n else if (paletteOpen) {\n setPaletteOpen(false);\n onMenuOpenChange?.(false);\n handleMenuClose();\n } else if (dropdownOpen) handleDropdownClose(false);\n else {\n onMenuOpenChange?.(false);\n handleMenuClose();\n }\n };\n\n // ── Advertised key combos run their shortcut ─────────────────────────────\n // The menu prints a shortcut's `keyboard_shortcut` (\"Alt+Shift+S\"); a press\n // with focus inside this surface runs it. Matched on `code` (key-combo.ts):\n // macOS Option turns Alt+Shift+S into \"Í\". The rows are read from the store\n // at press time (no subscription — the shell stays inert); an editable\n // surface loads them on first focus so the first press already works.\n const handleShortcutKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n const native = e.nativeEvent as Event & { [KEY_RUN_CLAIMED]?: boolean };\n if (native[KEY_RUN_CLAIMED] || e.defaultPrevented || suppressed || e.repeat) return;\n if (reachedThroughPortal(e)) return;\n // Until a menu has been opened once on this page, no key combo loads or runs anything.\n if (!menuEverOpened) return;\n if (!store || (!e.altKey && !e.ctrlKey && !e.metaKey)) return;\n const matchOf = (event: KeyboardEvent) =>\n findComboMatch(\n event,\n selectAllShortcutsArray(store.getState()).filter((s) => s.isActive !== false),\n (s) => s.keyboardShortcut,\n );\n const target = e.target as HTMLElement;\n const owner = selectionOwnerRef.current ?? e.currentTarget;\n const run = (match: { id: string; label: string }) => {\n captureContext(target, owner);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setKeyRun({ id: match.id, label: match.label });\n };\n // The shortcut list loads on the first modifier press (the modifier key's\n // own keydown usually lands it before the combo key), never on focus — an\n // autofocused composer would otherwise read it on every page load.\n const loading = loadShortcuts();\n const match = matchOf(e.nativeEvent);\n if (!match) {\n // A combo pressed before the list arrived still runs, once it arrives.\n if (loading) {\n const event = e.nativeEvent;\n void loading.then(() => {\n const late = matchOf(event);\n if (late) run(late);\n });\n }\n return;\n }\n native[KEY_RUN_CLAIMED] = true;\n e.preventDefault();\n e.stopPropagation();\n run(match);\n };\n const shortcutsLoad = useRef<Promise<unknown> | null>(null);\n const shortcutsLoaded = useRef(false);\n /** The in-flight first load of the shortcut list, or null once it has landed. */\n const loadShortcuts = (): Promise<unknown> | null => {\n if (!store || !isEditable || shortcutsLoaded.current) return null;\n if (!shortcutsLoad.current) {\n // Deduped + condition-gated in the thunk: one request page-wide.\n shortcutsLoad.current = import(\"@ai-matrx/chat/agents/redux/agent-shortcuts/thunks\")\n .then(({ fetchUnifiedMenu }) => (store.dispatch as ChatDispatch)(fetchUnifiedMenu({ scope, scopeId })))\n .catch(() => undefined)\n .finally(() => {\n shortcutsLoaded.current = true;\n });\n }\n return shortcutsLoad.current;\n };\n const finishKeyRun = () => {\n setKeyRun(null);\n // The launched run owns focus now (its panel); only release the capture.\n selectionLocked.current = false;\n capturedSelection.current = null;\n };\n\n // The trigger props — merged ONTO the single child via Radix `Slot` (no\n // wrapper element: a `<div>` between `<tbody>` and a wrapped `<tr>` is\n // illegal), falling back to a `display:contents` wrapper for a Fragment or\n // multi-child payload, where a `<div>` is always legal.\n const triggerProps = {\n ...CONTEXT_REGION_TRIGGER_ATTRS,\n // Radix-compatible open state, for styles that key on it.\n \"data-state\": mode ? \"open\" : \"closed\",\n // Lets a ⋯ beside (not inside) this content open THIS menu.\n \"data-content-source\": contentSource ? contentSourceKey(contentSource) : undefined,\n onContextMenuCapture: (e: React.MouseEvent<HTMLElement>) => {\n if (reachedThroughPortal(e)) return;\n // A right-click IS engagement: fetch the menu body now, in parallel with the open.\n void warmMenuContent();\n // CAPTURE: a read-only menu never steals a live text field's native menu.\n // It MARKS the gesture instead of stopping it: a stopPropagation here\n // also killed the field's OWN editable menu nested inside (every window\n // body is a read-only menu, so every window's text box lost its menu).\n if (!isEditable && yieldsToNativeTextMenu(e.target))\n NATIVE_TEXT_YIELD.set(e.nativeEvent, e.currentTarget);\n },\n onContextMenu: (e: React.MouseEvent<HTMLElement>) => {\n if (reachedThroughPortal(e)) {\n if (isInsideOpenMenu(e.target)) e.preventDefault();\n return;\n }\n // A read-only shell over a live field yields; so does an editable shell\n // OUTSIDE the innermost read-only shell that asked to yield. An editable\n // menu nested inside that shell owns its own field.\n const yielder = NATIVE_TEXT_YIELD.get(e.nativeEvent);\n if (yielder && (!isEditable || !yielder.contains(e.currentTarget))) return;\n if (isMobile) {\n if (suppressed) return;\n if (!isEditable && yieldsToNativeTextMenu(e.target)) return;\n // A nested row trigger wins over its surrounding list-level trigger.\n e.stopPropagation();\n e.preventDefault();\n captureContext(e.target as HTMLElement, e.currentTarget);\n markMenuOpen();\n setOpenSeq((n) => n + 1);\n setSheetOpen(true);\n return;\n }\n handleContextMenu(e);\n },\n onMouseDown: isMobile ? undefined : handleMouseDown,\n // The palette key is answered by the ONE page listener (paletteTarget), so\n // a click that focused an OUTER surface cannot steal it from the inner one.\n onPointerOver: claim(\"pointer\"),\n onPointerDown: claim(\"pointer\"),\n onFocus: claim(\"focus\"),\n onKeyDown: handleShortcutKeyDown,\n ...(isMobile\n ? {\n onTouchStart: handleTouchStart,\n onTouchMove: handleTouchMove,\n onTouchEnd: handleTouchEnd,\n onTouchCancel: handleTouchEnd,\n }\n : {}),\n };\n\n return (\n <MenuPresenceProvider value={true}>\n <RegistryMenuSourceProvider value={contentSource ?? null}>\n {canSlotChildren ? (\n <Slot ref={setSelectionOwner} {...triggerProps}>\n {children}\n </Slot>\n ) : (\n <div ref={setSelectionOwner} style={{ display: \"contents\" }} {...triggerProps}>\n {children}\n </div>\n )}\n\n\n {mode ? (\n <AlchemyMenuContent\n key={openSeq}\n {...menuContentProps}\n mode={mode}\n point={menuPoint}\n open\n onOpenChange={(open) => {\n if (!open) closeActive();\n }}\n />\n ) : null}\n {keyRun && !mode ? (\n <ShortcutKeyRunner\n key={`key-run-${openSeq}`}\n {...menuContentProps}\n shortcutId={keyRun.id}\n shortcutLabel={keyRun.label}\n onDone={finishKeyRun}\n />\n ) : null}\n {textAgentReview ? (\n <DocumentAgentReviewHost\n actionId={textAgentReview.actionId}\n ctx={textAgentReview.ctx}\n onClose={() => setTextAgentReview(null)}\n />\n ) : null}\n </RegistryMenuSourceProvider>\n </MenuPresenceProvider>\n );\n}\n\n/**\n * The name of the record whose content holds `target`, read NOW from its\n * registered rows. `_revision` is the registry's change counter: passing it\n * makes every caller (and the React Compiler's memo) re-read after a rename.\n */\nfunction recordHeadingAt(\n target: HTMLElement | null,\n _revision: number,\n): ContextMenuHeading | null {\n return readContextMenuHeading({\n [CONTEXT_MENU_HEADING_KEY]: resolveRecordMenu(target)?.heading ?? null,\n });\n}\n\n/** The header name a `resolveContextOnOpen` answer gave, when it is well-formed. */\nfunction readContextMenuHeading(resolved: unknown): ContextMenuHeading | null {\n if (!resolved || typeof resolved !== \"object\") return null;\n const heading = (resolved as Record<string, unknown>)[CONTEXT_MENU_HEADING_KEY];\n if (!heading || typeof heading !== \"object\") return null;\n const { label, text } = heading as Record<string, unknown>;\n return typeof label === \"string\" && typeof text === \"string\" && label.trim()\n ? { label: label.trim(), text }\n : null;\n}\n","\"use client\";\n\n// features/context-menu-v3/menu-presence.tsx\n//\n// 🚨 \"AM I ALREADY INSIDE A MENU?\"\n//\n// v3's nesting rule is THE INNERMOST WINS — every trigger stops propagation, so\n// an inner menu shadows every outer one. That rule is correct for the cases it\n// was written for, and it becomes a trap the moment a shared PRIMITIVE wants to\n// mount a menu of its own.\n//\n// `ProTextarea` is the case that forced this (2026-08-26). It has 387\n// consumers, 361 of which have no right-click menu at all — the single largest\n// coverage gap in the app, and every one of them is also a field agents cannot\n// stream edits into, because `EditableContextMenu` is what registers the\n// WidgetHandle. Mounting a menu inside ProTextarea fixes all 361 at once.\n//\n// But ~26 consumers ALREADY wrap their ProTextarea in a carefully-wired menu\n// carrying their own entity, surfaceName and extraSections. Under\n// innermost-wins, a menu inside ProTextarea would SHADOW every one of those —\n// silently replacing a rich, surface-specific menu with a generic one, on\n// exactly the surfaces someone took the trouble to wire properly.\n//\n// So the primitive has to be able to ask whether an ancestor already provides a\n// menu, and stand down when one does. That is all this module is: a boolean\n// context published by the shell.\n//\n// THE RULE FOR PRIMITIVES: a shared component may mount its own menu ONLY as a\n// FLOOR — when nothing above it has. A surface that wires its own menu always\n// wins, and never has to know the primitive exists.\n\nimport { createContext, useContext } from \"react\";\nimport type { ContentSource } from \"@ai-matrx/rich-content/rich-document/types\";\n\n/**\n * True anywhere inside a mounted v3 menu (either wrapper). Provided by the\n * shell; read by shared primitives that would otherwise nest.\n */\nconst MenuPresenceContext = createContext(false);\n\nexport const MenuPresenceProvider = MenuPresenceContext.Provider;\n\n/**\n * `true` when some ancestor already mounts a v3 menu.\n *\n * A shared primitive uses this to decide whether to provide its own floor:\n *\n * ```tsx\n * const insideMenu = useIsInsideContextMenu();\n * return insideMenu ? field : <EditableContextMenu …>{field}</EditableContextMenu>;\n * ```\n *\n * Do NOT use it to change what a menu CONTAINS — only whether a primitive\n * mounts one at all. Content decisions belong to the surface.\n */\nexport function useIsInsideContextMenu(): boolean {\n return useContext(MenuPresenceContext);\n}\n\n/**\n * THE ONE MENU (RC-B6). The content source of the innermost v3 menu that was\n * given one (`contentSource`) — null when none. A ⋯ button whose own content\n * is that same source opens THIS menu (openContextMenuForElement) instead of\n * drawing a second one, so the ⋯ menu and the right-click are the same menu\n * by construction: same registry tree, same agent libraries, same order.\n */\nconst RegistryMenuSourceContext = createContext<ContentSource | null>(null);\n\nexport const RegistryMenuSourceProvider = RegistryMenuSourceContext.Provider;\n\nexport function useRegistryMenuSource(): ContentSource | null {\n return useContext(RegistryMenuSourceContext);\n}\n\n/** Two sources name the same content (type + every identifying id). */\nexport function sameContentSource(\n a: ContentSource | null | undefined,\n b: ContentSource | null | undefined,\n): boolean {\n if (!a || !b || a.type !== b.type) return false;\n return contentSourceKey(a) === contentSourceKey(b);\n}\n\n/**\n * A content source's identity as one string (every identifying field, the\n * read-only flag excluded). The shell stamps it on its trigger\n * (`data-content-source`) so a ⋯ button can open the ONE menu that carries its\n * content even when the button renders beside that content, not inside it.\n */\nexport function contentSourceKey(s: ContentSource): string {\n return JSON.stringify(\n Object.fromEntries(\n Object.entries(s as Record<string, unknown>)\n .filter(([k]) => k !== \"readOnly\")\n .sort(([x], [y]) => x.localeCompare(y)),\n ),\n );\n}\n","\"use client\";\n\n// features/context-menu-v3/EditableContextMenu.tsx\n//\n// Thin wrapper for EDITABLE surfaces (textareas, code/note editors, builders).\n// Presets `isEditable` and accepts the text-mutation callbacks that light up\n// Cut / Paste / Insert / Save / Delete. All real logic lives in the shell +\n// lazy MenuContent — this only fixes the editable preset and narrows the props.\n\nimport { ContextMenuV3 } from \"./ContextMenuV3\";\nimport type { EditableContextMenuProps } from \"./types\";\n\nexport function EditableContextMenu(props: EditableContextMenuProps) {\n return <ContextMenuV3 {...props} isEditable />;\n}\n","\"use client\";\n\n// features/context-menu-v3/NonEditableContextMenu.tsx\n//\n// Thin wrapper for READ-ONLY surfaces (viewers, results, Knowledge/research output,\n// rendered markdown, message displays). No text mutation — but Copy, AI\n// Actions, Attach To, Share, Export and Convert all work, because the menu\n// self-resolves content from the DOM. Presets `isEditable: false`.\n\nimport { ContextMenuV3 } from \"./ContextMenuV3\";\nimport type { NonEditableContextMenuProps } from \"./types\";\n\nexport function NonEditableContextMenu(props: NonEditableContextMenuProps) {\n return <ContextMenuV3 {...props} isEditable={false} />;\n}\n","\"use client\";\n\n// features/context-menu-v3/PageSurfaceMenu.tsx\n//\n// THE PAGE-LEVEL MENU FLOOR. A page whose body is cards / charts / panels (no\n// table, no editor) has no right-click region, so a right-click on it opens\n// NOTHING and the person loses Copy, Agents, Surface Context and Bind. Mount\n// this ONCE in the section shell that wraps those pages: it resolves the live\n// surface the page registered (`useActivePageSurface`, the same answer the\n// header Agents menu uses) and answers with the canonical read-only menu bound\n// to that surface and its live scope. A deeper menu (table rows, editors)\n// still wins (innermost-wins), so wrapping never shadows a richer one.\n\nimport { compact } from \"./utils/compact\";\nimport type { ReactNode } from \"react\";\nimport { useActivePageSurface } from \"@ai-matrx/chat/surfaces/runtime/useActivePageSurface\";\nimport { NonEditableContextMenu } from \"./NonEditableContextMenu\";\n\ntype MenuProps = Parameters<typeof NonEditableContextMenu>[0];\n\nexport function PageSurfaceMenu({\n sourceFeature,\n children,\n}: {\n sourceFeature: MenuProps[\"sourceFeature\"];\n children: ReactNode;\n}) {\n const active = useActivePageSurface();\n return (\n <NonEditableContextMenu\n sourceFeature={sourceFeature}\n {...compact({ surfaceName: active.surfaceName ?? undefined })}\n getApplicationScope={() => {\n const scope = active.runtime?.getScope();\n // The menu reads the scope synchronously; an async scope is read by the Surface Context window.\n return scope && !(scope instanceof Promise) ? scope : {};\n }}\n contentSource={{ type: \"raw\" }}\n contextData={{ content: \"\" }}\n >\n {children}\n </NonEditableContextMenu>\n );\n}\n","\"use client\";\n\n/**\n * Gives every ItemRow / ItemContextMenu (@ai-matrx/design-system/item) the\n * website's right-click menu (v3) and promise toast. Mounted once at the root.\n */\n\nimport type { ComponentType, ReactNode } from \"react\";\nimport { ItemMenuHostProvider, type ItemContextMenuProps, type ItemMenuHost } from \"@ai-matrx/design-system/item\";\nimport { ItemContextMenuV3 } from \"./ItemContextMenuV3\";\nimport { itemToastPromise } from \"./itemMenuToV3\";\n\nconst HOST: ItemMenuHost = {\n // The package's surface fields are open strings; every website row passes chat's closed registries.\n ContextMenu: ItemContextMenuV3 as unknown as ComponentType<ItemContextMenuProps>,\n toastPromise: itemToastPromise,\n};\n\nexport function ItemMenuHostBinding({ children }: { children: ReactNode }) {\n return <ItemMenuHostProvider host={HOST}>{children}</ItemMenuHostProvider>;\n}\n","\"use client\";\n\n/**\n * The website's right-click menu for every ItemRow / ItemContextMenu\n * (@ai-matrx/design-system/item): the ONE universal v3 context menu, with the\n * row's schema-driven config riding in as extraSections (converted lazily at\n * open — resolveContextOnOpen fires before the menu mounts), so the row\n * inherits the standard extras (Copy, agents, Quick Actions, Attach To, Share,\n * admin). Mounted through `ItemMenuHostProvider` in ItemMenuHostBinding.\n * Moves into @ai-matrx/chat with the rest of v3 (package architecture step 2).\n */\n\nimport { compact } from \"../utils/compact\";\nimport { useState } from \"react\";\nimport { resolveItemMenuConfig, type ItemMenuConfig } from \"@ai-matrx/design-system/item\";\nimport type { ItemContextMenuProps } from \"@ai-matrx/chat/ui/item-types\";\nimport { NonEditableContextMenu } from \"../NonEditableContextMenu\";\nimport { CONTEXT_MENU_HEADING_KEY, type ResolvedContextMenuContext } from \"../types\";\nimport { itemMenuConfigToExtraSections } from \"./itemMenuToV3\";\n\nexport function ItemContextMenuV3({\n config,\n children,\n sourceFeature,\n surfaceName,\n entity,\n getApplicationScope,\n resolveItemOnOpen,\n onOpenChange,\n onCloseAutoFocus,\n}: ItemContextMenuProps) {\n const [resolved, setResolved] = useState<ItemMenuConfig | null>(null);\n\n return (\n <NonEditableContextMenu\n sourceFeature={sourceFeature}\n {...compact({ surfaceName, entity, getApplicationScope })}\n resolveContextOnOpen={(target) => {\n // Re-resolve on every open so lazy configs stay live.\n const item = resolveItemOnOpen?.(target);\n setResolved(resolveItemMenuConfig(item?.config ?? config));\n const context = item?.context ?? null;\n // A list row is a RECORD, not text: its menu is headed with the\n // record's name (\"Note · Clinic intake checklist\"), never \"Content:\"\n // plus the row's text — unless the row names itself already.\n if (\n entity?.title &&\n !(context && (context as Record<string, unknown>)[CONTEXT_MENU_HEADING_KEY])\n ) {\n const type = String(entity.type ?? \"Item\").replace(/[_-]+/g, \" \");\n return {\n ...((context as Record<string, unknown> | null) ?? {}),\n [CONTEXT_MENU_HEADING_KEY]: {\n label: type.charAt(0).toUpperCase() + type.slice(1),\n text: entity.title,\n },\n } as ResolvedContextMenuContext;\n }\n return context;\n }}\n extraSections={resolved ? itemMenuConfigToExtraSections(resolved) : []}\n {...compact({ onMenuOpenChange: onOpenChange, onCloseAutoFocus })}\n >\n {children}\n </NonEditableContextMenu>\n );\n}\n","\"use client\";\n\n// features/context-menu-v3/components/OpenSurfaceMenuButton.tsx\n//\n// A ⋯ for a surface whose ONE menu otherwise opens only by right-click (the\n// data grid): it opens that surface's own menu — the same shell, the same\n// engine, the same rows — anchored at the button, never a second menu\n// (ALC-15 verifier finding 3). The event lands ON the surface element, so a\n// per-target resolver answers at the surface level (the table, no cell).\n\nimport * as React from \"react\";\nimport { MoreHorizontal } from \"lucide-react\";\nimport { Button } from \"@ai-matrx/design-system\";\nimport { cn } from \"@ai-matrx/design-system/cn\";\n\nexport function OpenSurfaceMenuButton({\n getSurface,\n label = \"More actions\",\n className,\n}: {\n /** The element the surface's context-menu shell wraps. */\n getSurface: () => HTMLElement | null;\n label?: string | undefined;\n className?: string | undefined;\n}): React.ReactElement {\n const buttonRef = React.useRef<HTMLButtonElement>(null);\n return (\n <Button\n ref={buttonRef}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\"h-8 w-8 p-0\", className)}\n aria-label={label}\n aria-haspopup=\"menu\"\n onClick={() => {\n const surface = getSurface();\n const button = buttonRef.current;\n if (!surface || !button) return;\n const rect = button.getBoundingClientRect();\n surface.dispatchEvent(\n new MouseEvent(\"contextmenu\", {\n bubbles: true,\n cancelable: true,\n view: window,\n button: 2,\n buttons: 2,\n clientX: rect.left + rect.width / 2,\n clientY: rect.bottom,\n }),\n );\n }}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n </Button>\n );\n}\n"],"mappings":"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","names":["match","jsx","jsx","jsx","useState","jsx","useState","jsx","React","jsx"]}
|