@ai-matrx/context-menu 0.1.5 → 0.1.7
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/engine.cjs +24 -3
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +3 -1
- package/dist/engine.d.ts +3 -1
- package/dist/engine.js +15 -3
- package/dist/engine.js.map +1 -1
- package/dist/menu-content.cjs +31 -7
- package/dist/menu-content.cjs.map +1 -1
- package/dist/menu-content.js +31 -7
- package/dist/menu-content.js.map +1 -1
- package/dist/react.cjs +73 -41
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +72 -40
- package/dist/react.js.map +1 -1
- package/package.json +3 -3
package/dist/react.cjs
CHANGED
|
@@ -427,11 +427,21 @@ var CONTEXT_REGION_TRIGGER_ATTRS = {
|
|
|
427
427
|
};
|
|
428
428
|
|
|
429
429
|
// src/engine/utils/table-at-target.ts
|
|
430
|
-
var
|
|
430
|
+
var shapeReader = null;
|
|
431
|
+
var shapeLoad = null;
|
|
432
|
+
function preloadTableShape() {
|
|
433
|
+
shapeLoad ??= import("@ai-matrx/records-ui/table-shape").then((m) => {
|
|
434
|
+
shapeReader = m.shapeTextOfNode;
|
|
435
|
+
}).catch((error) => {
|
|
436
|
+
shapeLoad = null;
|
|
437
|
+
console.error("[ContextMenuV3] could not load the table shape reader", error);
|
|
438
|
+
});
|
|
439
|
+
return shapeLoad;
|
|
440
|
+
}
|
|
431
441
|
function tableTextAtTarget(target) {
|
|
432
442
|
const table = target?.closest("table");
|
|
433
|
-
if (!table) return null;
|
|
434
|
-
const text = (
|
|
443
|
+
if (!table || !shapeReader) return null;
|
|
444
|
+
const text = shapeReader(table.cloneNode(true));
|
|
435
445
|
return text.trim() ? text : null;
|
|
436
446
|
}
|
|
437
447
|
|
|
@@ -570,7 +580,6 @@ function useContextMenuHostBindings() {
|
|
|
570
580
|
|
|
571
581
|
// src/engine/ContextMenuV3.tsx
|
|
572
582
|
var import_selectors = require("@ai-matrx/chat/agents/redux/agent-shortcuts/selectors");
|
|
573
|
-
var import_thunks = require("@ai-matrx/chat/agents/redux/agent-shortcuts/thunks");
|
|
574
583
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
575
584
|
var NON_TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
576
585
|
"button",
|
|
@@ -642,17 +651,7 @@ function warmMenuContent() {
|
|
|
642
651
|
}
|
|
643
652
|
return menuContentSlot().warm ?? Promise.resolve();
|
|
644
653
|
}
|
|
645
|
-
|
|
646
|
-
(0, import_react2.useEffect)(() => {
|
|
647
|
-
if (menuContentSlot().warm) return;
|
|
648
|
-
if (typeof window.requestIdleCallback === "function") {
|
|
649
|
-
const id2 = window.requestIdleCallback(() => void warmMenuContent(), { timeout: 4e3 });
|
|
650
|
-
return () => window.cancelIdleCallback(id2);
|
|
651
|
-
}
|
|
652
|
-
const id = window.setTimeout(() => void warmMenuContent(), 1500);
|
|
653
|
-
return () => window.clearTimeout(id);
|
|
654
|
-
}, []);
|
|
655
|
-
}
|
|
654
|
+
var menuEverOpened = false;
|
|
656
655
|
function ShortcutKeyRunner(props) {
|
|
657
656
|
const mod = useMenuContentModule();
|
|
658
657
|
return mod ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(mod.ShortcutKeyRunner, { ...props }) : null;
|
|
@@ -767,7 +766,8 @@ function ContextMenuV3({
|
|
|
767
766
|
const store = import_react2.default.useContext(import_react_redux.ReactReduxContext)?.store;
|
|
768
767
|
const [menuPoint, setMenuPoint] = (0, import_react2.useState)({ x: 0, y: 0 });
|
|
769
768
|
const [openSeq, setOpenSeq] = (0, import_react2.useState)(0);
|
|
770
|
-
|
|
769
|
+
const [engaged, setEngaged] = (0, import_react2.useState)(false);
|
|
770
|
+
const engage = () => setEngaged(true);
|
|
771
771
|
const capturedSelection = (0, import_react2.useRef)(null);
|
|
772
772
|
const selectionLocked = (0, import_react2.useRef)(false);
|
|
773
773
|
const lastMousePos = (0, import_react2.useRef)(null);
|
|
@@ -798,7 +798,7 @@ function ContextMenuV3({
|
|
|
798
798
|
onTextInsertAfter,
|
|
799
799
|
getApplicationScope
|
|
800
800
|
}) : null;
|
|
801
|
-
const widgetHandleId = (0, import_useWidgetHandle.useOptionalWidgetHandle)(widgetHandle);
|
|
801
|
+
const widgetHandleId = (0, import_useWidgetHandle.useOptionalWidgetHandle)(engaged ? widgetHandle : null);
|
|
802
802
|
const getEffectiveContextData = () => mergeResolvedContextData(
|
|
803
803
|
contextData,
|
|
804
804
|
resolvedContext
|
|
@@ -806,6 +806,7 @@ function ContextMenuV3({
|
|
|
806
806
|
const surfaceSpokeAboutEntity = !!resolvedContext && types_exports.CONTEXT_MENU_ENTITY_KEY in resolvedContext;
|
|
807
807
|
const effectiveEntity = surfaceSpokeAboutEntity ? resolveEffectiveEntity(entity, resolvedContext) : sniffedEntity ?? entity;
|
|
808
808
|
(0, import_react2.useEffect)(() => {
|
|
809
|
+
if (!engaged) return;
|
|
809
810
|
const handleSelection = () => {
|
|
810
811
|
if (selectionLocked.current) return;
|
|
811
812
|
const owner = selectionOwnerRef.current;
|
|
@@ -822,18 +823,15 @@ function ContextMenuV3({
|
|
|
822
823
|
};
|
|
823
824
|
document.addEventListener("selectionchange", handleSelection);
|
|
824
825
|
return () => document.removeEventListener("selectionchange", handleSelection);
|
|
825
|
-
}, []);
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
};
|
|
830
|
-
document.addEventListener("mousemove", handleMouseMove, { passive: true });
|
|
831
|
-
return () => document.removeEventListener("mousemove", handleMouseMove);
|
|
832
|
-
}, []);
|
|
826
|
+
}, [engaged]);
|
|
827
|
+
const rememberPointer = (e) => {
|
|
828
|
+
lastMousePos.current = { x: e.clientX, y: e.clientY };
|
|
829
|
+
};
|
|
833
830
|
const handleMouseDown = (e) => {
|
|
834
831
|
if (suppressed) return;
|
|
835
832
|
if (reachedThroughPortal(e)) return;
|
|
836
833
|
if (e.button !== 2) return;
|
|
834
|
+
void warmMenuContent();
|
|
837
835
|
if (!isEditable && yieldsToNativeTextMenu(e.target)) return;
|
|
838
836
|
const target = e.target;
|
|
839
837
|
resolvePerTargetContext(target);
|
|
@@ -849,6 +847,9 @@ function ContextMenuV3({
|
|
|
849
847
|
}
|
|
850
848
|
};
|
|
851
849
|
const resolvePerTargetContext = (target) => {
|
|
850
|
+
menuEverOpened = true;
|
|
851
|
+
engage();
|
|
852
|
+
if (target?.closest("table")) void preloadTableShape();
|
|
852
853
|
const rowHit = resolveTableRowItem(target);
|
|
853
854
|
const rowMenu = rowHit?.menu ?? null;
|
|
854
855
|
setResolvedItem(rowHit?.item ?? null);
|
|
@@ -989,11 +990,14 @@ function ContextMenuV3({
|
|
|
989
990
|
setDropdownOpen(true);
|
|
990
991
|
};
|
|
991
992
|
const selectionHost = { kind: "context-menu-selection", open: openFromSelection };
|
|
992
|
-
(0, import_selection_zones.useSelectionZone)(
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
993
|
+
(0, import_selection_zones.useSelectionZone)(
|
|
994
|
+
selectionOwner,
|
|
995
|
+
engaged ? {
|
|
996
|
+
// A suppressed menu (the text is streaming) keeps the toolbar away until it settles.
|
|
997
|
+
suppress: suppressed,
|
|
998
|
+
host: { [CONTEXT_MENU_SELECTION_HOST_KEY]: selectionHost }
|
|
999
|
+
} : null
|
|
1000
|
+
);
|
|
997
1001
|
const clearLongPress = () => {
|
|
998
1002
|
if (longPressTimer.current !== null) {
|
|
999
1003
|
clearTimeout(longPressTimer.current);
|
|
@@ -1129,6 +1133,8 @@ function ContextMenuV3({
|
|
|
1129
1133
|
const reg = paletteRegistry();
|
|
1130
1134
|
const now = Date.now();
|
|
1131
1135
|
if (e.type === "pointerdown") reg.pointerDown = { element: e.target, at: now };
|
|
1136
|
+
if (e.type === "pointerdown" || e.type === "focusin" || e.type === "focus") engage();
|
|
1137
|
+
if (e.type === "pointerover" || e.type === "pointerdown") rememberPointer(e);
|
|
1132
1138
|
reg.seq += 1;
|
|
1133
1139
|
reg[kind] = { id: paletteIdRef.current, element: e.target, seq: reg.seq, at: now };
|
|
1134
1140
|
};
|
|
@@ -1149,6 +1155,7 @@ function ContextMenuV3({
|
|
|
1149
1155
|
const native = e.nativeEvent;
|
|
1150
1156
|
if (native[KEY_RUN_CLAIMED] || e.defaultPrevented || suppressed || e.repeat) return;
|
|
1151
1157
|
if (reachedThroughPortal(e)) return;
|
|
1158
|
+
if (!menuEverOpened) return;
|
|
1152
1159
|
if (!store || !e.altKey && !e.ctrlKey && !e.metaKey) return;
|
|
1153
1160
|
const matchOf = (event) => findComboMatch(
|
|
1154
1161
|
event,
|
|
@@ -1184,7 +1191,7 @@ function ContextMenuV3({
|
|
|
1184
1191
|
const loadShortcuts = () => {
|
|
1185
1192
|
if (!store || !isEditable || shortcutsLoaded.current) return null;
|
|
1186
1193
|
if (!shortcutsLoad.current) {
|
|
1187
|
-
shortcutsLoad.current =
|
|
1194
|
+
shortcutsLoad.current = import("@ai-matrx/chat/agents/redux/agent-shortcuts/thunks").then(({ fetchUnifiedMenu: fetchUnifiedMenu2 }) => store.dispatch(fetchUnifiedMenu2({ scope, scopeId }))).catch(() => void 0).finally(() => {
|
|
1188
1195
|
shortcutsLoaded.current = true;
|
|
1189
1196
|
});
|
|
1190
1197
|
}
|
|
@@ -1203,6 +1210,7 @@ function ContextMenuV3({
|
|
|
1203
1210
|
"data-content-source": contentSource ? contentSourceKey(contentSource) : void 0,
|
|
1204
1211
|
onContextMenuCapture: (e) => {
|
|
1205
1212
|
if (reachedThroughPortal(e)) return;
|
|
1213
|
+
void warmMenuContent();
|
|
1206
1214
|
if (!isEditable && yieldsToNativeTextMenu(e.target))
|
|
1207
1215
|
NATIVE_TEXT_YIELD.set(e.nativeEvent, e.currentTarget);
|
|
1208
1216
|
},
|
|
@@ -1820,6 +1828,17 @@ function toast2(props) {
|
|
|
1820
1828
|
else import_notify2.toast.message(message, options);
|
|
1821
1829
|
}
|
|
1822
1830
|
|
|
1831
|
+
// src/engine/utils/ensure-block-template.ts
|
|
1832
|
+
var import_db = require("@ai-matrx/chat/host/db");
|
|
1833
|
+
var import_ui_slots = require("@ai-matrx/chat/host/ui-slots");
|
|
1834
|
+
async function ensureBlockTemplate(blockId, dispatch) {
|
|
1835
|
+
const { data, error } = await import_db.supabase.schema("skill").from("render_definition").select("template").eq("id", blockId).single();
|
|
1836
|
+
if (error) throw new Error(error.message);
|
|
1837
|
+
const template = data?.template ?? "";
|
|
1838
|
+
dispatch(import_ui_slots.sklActions.renderDefinitionsMerged([{ id: blockId, template }]));
|
|
1839
|
+
return template;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1823
1842
|
// src/engine/hooks/useContextMenuActions.ts
|
|
1824
1843
|
var import_org = require("@ai-matrx/chat/host/org");
|
|
1825
1844
|
var import_useAgentLauncher = require("@ai-matrx/chat/agents/hooks/useAgentLauncher");
|
|
@@ -1951,7 +1970,7 @@ var import_constants2 = require("@ai-matrx/chat/agents/shortcuts/constants");
|
|
|
1951
1970
|
// src/engine/hooks/useUnifiedAgentContextMenu.ts
|
|
1952
1971
|
var import_react4 = require("react");
|
|
1953
1972
|
var import_hooks = require("@ai-matrx/chat/store/hooks");
|
|
1954
|
-
var
|
|
1973
|
+
var import_thunks = require("@ai-matrx/chat/agents/redux/agent-shortcuts/thunks");
|
|
1955
1974
|
|
|
1956
1975
|
// src/engine/utils/menu-deadline.ts
|
|
1957
1976
|
var menu_deadline_exports = {};
|
|
@@ -2109,7 +2128,7 @@ function useUnifiedAgentContextMenu(args) {
|
|
|
2109
2128
|
const categories = (0, import_hooks.useAppSelector)(import_selectors3.selectAllCategoriesArray);
|
|
2110
2129
|
const contentBlocks = (0, import_hooks.useAppSelector)((state) => getContextMenuHost().selectRenderDefinitions(state));
|
|
2111
2130
|
const rowsInHand = (0, import_hooks.useAppSelector)(
|
|
2112
|
-
(state) => state.agentShortcut.contextLoaded?.[(0,
|
|
2131
|
+
(state) => state.agentShortcut.contextLoaded?.[(0, import_thunks.unifiedMenuLoadedKey)({ scope, scopeId })] ?? false
|
|
2113
2132
|
);
|
|
2114
2133
|
const [error, setError] = (0, import_react4.useState)(null);
|
|
2115
2134
|
const refresh = (0, import_react4.useCallback)(async () => {
|
|
@@ -2117,7 +2136,7 @@ function useUnifiedAgentContextMenu(args) {
|
|
|
2117
2136
|
try {
|
|
2118
2137
|
setError(null);
|
|
2119
2138
|
await (0, menu_deadline_exports.withMenuDeadline)(
|
|
2120
|
-
dispatch((0,
|
|
2139
|
+
dispatch((0, import_thunks.fetchUnifiedMenu)({ scope, scopeId })).unwrap(),
|
|
2121
2140
|
"Loading the menu's AI actions"
|
|
2122
2141
|
);
|
|
2123
2142
|
} catch (err) {
|
|
@@ -3005,12 +3024,25 @@ function useContextMenuActions(props) {
|
|
|
3005
3024
|
};
|
|
3006
3025
|
const insertTargets = { editorId, getTextarea, insertAtCaret, onTextReplace };
|
|
3007
3026
|
const handleContentBlockInsert = (entry) => {
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3027
|
+
void (async () => {
|
|
3028
|
+
let template = entry.template;
|
|
3029
|
+
if (!template) {
|
|
3030
|
+
try {
|
|
3031
|
+
template = await ensureBlockTemplate(entry.id, dispatch);
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
toast2({
|
|
3034
|
+
title: "Couldn't load that block",
|
|
3035
|
+
description: error instanceof Error ? error.message : "Try again.",
|
|
3036
|
+
variant: "destructive"
|
|
3037
|
+
});
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
if (insertIntoEditor(insertTargets, template)) {
|
|
3042
|
+
onContentInserted?.();
|
|
3043
|
+
return;
|
|
3044
|
+
}
|
|
3045
|
+
const copied = await (0, import_clipboard.copyText)(template);
|
|
3014
3046
|
if (copied) {
|
|
3015
3047
|
toast2({
|
|
3016
3048
|
title: "Copied to clipboard",
|
|
@@ -3019,7 +3051,7 @@ function useContextMenuActions(props) {
|
|
|
3019
3051
|
} else {
|
|
3020
3052
|
getContextMenuHost().showManualCopy({ text: template });
|
|
3021
3053
|
}
|
|
3022
|
-
});
|
|
3054
|
+
})();
|
|
3023
3055
|
};
|
|
3024
3056
|
const handleEntrySelect = (entry) => {
|
|
3025
3057
|
if (entry.entryType === "agent_shortcut") void handleShortcutExecute(entry);
|