@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.js
CHANGED
|
@@ -382,11 +382,21 @@ var CONTEXT_REGION_TRIGGER_ATTRS = {
|
|
|
382
382
|
};
|
|
383
383
|
|
|
384
384
|
// src/engine/utils/table-at-target.ts
|
|
385
|
-
|
|
385
|
+
var shapeReader = null;
|
|
386
|
+
var shapeLoad = null;
|
|
387
|
+
function preloadTableShape() {
|
|
388
|
+
shapeLoad ??= import("@ai-matrx/records-ui/table-shape").then((m) => {
|
|
389
|
+
shapeReader = m.shapeTextOfNode;
|
|
390
|
+
}).catch((error) => {
|
|
391
|
+
shapeLoad = null;
|
|
392
|
+
console.error("[ContextMenuV3] could not load the table shape reader", error);
|
|
393
|
+
});
|
|
394
|
+
return shapeLoad;
|
|
395
|
+
}
|
|
386
396
|
function tableTextAtTarget(target) {
|
|
387
397
|
const table = target?.closest("table");
|
|
388
|
-
if (!table) return null;
|
|
389
|
-
const text =
|
|
398
|
+
if (!table || !shapeReader) return null;
|
|
399
|
+
const text = shapeReader(table.cloneNode(true));
|
|
390
400
|
return text.trim() ? text : null;
|
|
391
401
|
}
|
|
392
402
|
|
|
@@ -525,7 +535,6 @@ function useContextMenuHostBindings() {
|
|
|
525
535
|
|
|
526
536
|
// src/engine/ContextMenuV3.tsx
|
|
527
537
|
import { selectAllShortcutsArray } from "@ai-matrx/chat/agents/redux/agent-shortcuts/selectors";
|
|
528
|
-
import { fetchUnifiedMenu } from "@ai-matrx/chat/agents/redux/agent-shortcuts/thunks";
|
|
529
538
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
530
539
|
var NON_TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
|
|
531
540
|
"button",
|
|
@@ -597,17 +606,7 @@ function warmMenuContent() {
|
|
|
597
606
|
}
|
|
598
607
|
return menuContentSlot().warm ?? Promise.resolve();
|
|
599
608
|
}
|
|
600
|
-
|
|
601
|
-
useEffect(() => {
|
|
602
|
-
if (menuContentSlot().warm) return;
|
|
603
|
-
if (typeof window.requestIdleCallback === "function") {
|
|
604
|
-
const id2 = window.requestIdleCallback(() => void warmMenuContent(), { timeout: 4e3 });
|
|
605
|
-
return () => window.cancelIdleCallback(id2);
|
|
606
|
-
}
|
|
607
|
-
const id = window.setTimeout(() => void warmMenuContent(), 1500);
|
|
608
|
-
return () => window.clearTimeout(id);
|
|
609
|
-
}, []);
|
|
610
|
-
}
|
|
609
|
+
var menuEverOpened = false;
|
|
611
610
|
function ShortcutKeyRunner(props) {
|
|
612
611
|
const mod = useMenuContentModule();
|
|
613
612
|
return mod ? /* @__PURE__ */ jsx(mod.ShortcutKeyRunner, { ...props }) : null;
|
|
@@ -722,7 +721,8 @@ function ContextMenuV3({
|
|
|
722
721
|
const store = React.useContext(ReactReduxContext)?.store;
|
|
723
722
|
const [menuPoint, setMenuPoint] = useState({ x: 0, y: 0 });
|
|
724
723
|
const [openSeq, setOpenSeq] = useState(0);
|
|
725
|
-
|
|
724
|
+
const [engaged, setEngaged] = useState(false);
|
|
725
|
+
const engage = () => setEngaged(true);
|
|
726
726
|
const capturedSelection = useRef(null);
|
|
727
727
|
const selectionLocked = useRef(false);
|
|
728
728
|
const lastMousePos = useRef(null);
|
|
@@ -753,7 +753,7 @@ function ContextMenuV3({
|
|
|
753
753
|
onTextInsertAfter,
|
|
754
754
|
getApplicationScope
|
|
755
755
|
}) : null;
|
|
756
|
-
const widgetHandleId = useOptionalWidgetHandle(widgetHandle);
|
|
756
|
+
const widgetHandleId = useOptionalWidgetHandle(engaged ? widgetHandle : null);
|
|
757
757
|
const getEffectiveContextData = () => mergeResolvedContextData(
|
|
758
758
|
contextData,
|
|
759
759
|
resolvedContext
|
|
@@ -761,6 +761,7 @@ function ContextMenuV3({
|
|
|
761
761
|
const surfaceSpokeAboutEntity = !!resolvedContext && types_exports.CONTEXT_MENU_ENTITY_KEY in resolvedContext;
|
|
762
762
|
const effectiveEntity = surfaceSpokeAboutEntity ? resolveEffectiveEntity(entity, resolvedContext) : sniffedEntity ?? entity;
|
|
763
763
|
useEffect(() => {
|
|
764
|
+
if (!engaged) return;
|
|
764
765
|
const handleSelection = () => {
|
|
765
766
|
if (selectionLocked.current) return;
|
|
766
767
|
const owner = selectionOwnerRef.current;
|
|
@@ -777,18 +778,15 @@ function ContextMenuV3({
|
|
|
777
778
|
};
|
|
778
779
|
document.addEventListener("selectionchange", handleSelection);
|
|
779
780
|
return () => document.removeEventListener("selectionchange", handleSelection);
|
|
780
|
-
}, []);
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
};
|
|
785
|
-
document.addEventListener("mousemove", handleMouseMove, { passive: true });
|
|
786
|
-
return () => document.removeEventListener("mousemove", handleMouseMove);
|
|
787
|
-
}, []);
|
|
781
|
+
}, [engaged]);
|
|
782
|
+
const rememberPointer = (e) => {
|
|
783
|
+
lastMousePos.current = { x: e.clientX, y: e.clientY };
|
|
784
|
+
};
|
|
788
785
|
const handleMouseDown = (e) => {
|
|
789
786
|
if (suppressed) return;
|
|
790
787
|
if (reachedThroughPortal(e)) return;
|
|
791
788
|
if (e.button !== 2) return;
|
|
789
|
+
void warmMenuContent();
|
|
792
790
|
if (!isEditable && yieldsToNativeTextMenu(e.target)) return;
|
|
793
791
|
const target = e.target;
|
|
794
792
|
resolvePerTargetContext(target);
|
|
@@ -804,6 +802,9 @@ function ContextMenuV3({
|
|
|
804
802
|
}
|
|
805
803
|
};
|
|
806
804
|
const resolvePerTargetContext = (target) => {
|
|
805
|
+
menuEverOpened = true;
|
|
806
|
+
engage();
|
|
807
|
+
if (target?.closest("table")) void preloadTableShape();
|
|
807
808
|
const rowHit = resolveTableRowItem(target);
|
|
808
809
|
const rowMenu = rowHit?.menu ?? null;
|
|
809
810
|
setResolvedItem(rowHit?.item ?? null);
|
|
@@ -944,11 +945,14 @@ function ContextMenuV3({
|
|
|
944
945
|
setDropdownOpen(true);
|
|
945
946
|
};
|
|
946
947
|
const selectionHost = { kind: "context-menu-selection", open: openFromSelection };
|
|
947
|
-
useSelectionZone(
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
948
|
+
useSelectionZone(
|
|
949
|
+
selectionOwner,
|
|
950
|
+
engaged ? {
|
|
951
|
+
// A suppressed menu (the text is streaming) keeps the toolbar away until it settles.
|
|
952
|
+
suppress: suppressed,
|
|
953
|
+
host: { [CONTEXT_MENU_SELECTION_HOST_KEY]: selectionHost }
|
|
954
|
+
} : null
|
|
955
|
+
);
|
|
952
956
|
const clearLongPress = () => {
|
|
953
957
|
if (longPressTimer.current !== null) {
|
|
954
958
|
clearTimeout(longPressTimer.current);
|
|
@@ -1084,6 +1088,8 @@ function ContextMenuV3({
|
|
|
1084
1088
|
const reg = paletteRegistry();
|
|
1085
1089
|
const now = Date.now();
|
|
1086
1090
|
if (e.type === "pointerdown") reg.pointerDown = { element: e.target, at: now };
|
|
1091
|
+
if (e.type === "pointerdown" || e.type === "focusin" || e.type === "focus") engage();
|
|
1092
|
+
if (e.type === "pointerover" || e.type === "pointerdown") rememberPointer(e);
|
|
1087
1093
|
reg.seq += 1;
|
|
1088
1094
|
reg[kind] = { id: paletteIdRef.current, element: e.target, seq: reg.seq, at: now };
|
|
1089
1095
|
};
|
|
@@ -1104,6 +1110,7 @@ function ContextMenuV3({
|
|
|
1104
1110
|
const native = e.nativeEvent;
|
|
1105
1111
|
if (native[KEY_RUN_CLAIMED] || e.defaultPrevented || suppressed || e.repeat) return;
|
|
1106
1112
|
if (reachedThroughPortal(e)) return;
|
|
1113
|
+
if (!menuEverOpened) return;
|
|
1107
1114
|
if (!store || !e.altKey && !e.ctrlKey && !e.metaKey) return;
|
|
1108
1115
|
const matchOf = (event) => findComboMatch(
|
|
1109
1116
|
event,
|
|
@@ -1139,7 +1146,7 @@ function ContextMenuV3({
|
|
|
1139
1146
|
const loadShortcuts = () => {
|
|
1140
1147
|
if (!store || !isEditable || shortcutsLoaded.current) return null;
|
|
1141
1148
|
if (!shortcutsLoad.current) {
|
|
1142
|
-
shortcutsLoad.current = store.dispatch(
|
|
1149
|
+
shortcutsLoad.current = import("@ai-matrx/chat/agents/redux/agent-shortcuts/thunks").then(({ fetchUnifiedMenu: fetchUnifiedMenu2 }) => store.dispatch(fetchUnifiedMenu2({ scope, scopeId }))).catch(() => void 0).finally(() => {
|
|
1143
1150
|
shortcutsLoaded.current = true;
|
|
1144
1151
|
});
|
|
1145
1152
|
}
|
|
@@ -1158,6 +1165,7 @@ function ContextMenuV3({
|
|
|
1158
1165
|
"data-content-source": contentSource ? contentSourceKey(contentSource) : void 0,
|
|
1159
1166
|
onContextMenuCapture: (e) => {
|
|
1160
1167
|
if (reachedThroughPortal(e)) return;
|
|
1168
|
+
void warmMenuContent();
|
|
1161
1169
|
if (!isEditable && yieldsToNativeTextMenu(e.target))
|
|
1162
1170
|
NATIVE_TEXT_YIELD.set(e.nativeEvent, e.currentTarget);
|
|
1163
1171
|
},
|
|
@@ -1796,6 +1804,17 @@ function toast2(props) {
|
|
|
1796
1804
|
else notify.message(message, options);
|
|
1797
1805
|
}
|
|
1798
1806
|
|
|
1807
|
+
// src/engine/utils/ensure-block-template.ts
|
|
1808
|
+
import { supabase } from "@ai-matrx/chat/host/db";
|
|
1809
|
+
import { sklActions } from "@ai-matrx/chat/host/ui-slots";
|
|
1810
|
+
async function ensureBlockTemplate(blockId, dispatch) {
|
|
1811
|
+
const { data, error } = await supabase.schema("skill").from("render_definition").select("template").eq("id", blockId).single();
|
|
1812
|
+
if (error) throw new Error(error.message);
|
|
1813
|
+
const template = data?.template ?? "";
|
|
1814
|
+
dispatch(sklActions.renderDefinitionsMerged([{ id: blockId, template }]));
|
|
1815
|
+
return template;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1799
1818
|
// src/engine/hooks/useContextMenuActions.ts
|
|
1800
1819
|
import { selectOrganizationId } from "@ai-matrx/chat/host/org";
|
|
1801
1820
|
import { useAgentLauncher } from "@ai-matrx/chat/agents/hooks/useAgentLauncher";
|
|
@@ -1932,7 +1951,7 @@ import {
|
|
|
1932
1951
|
import { useMemo, useState as useState4, useCallback as useCallback2 } from "react";
|
|
1933
1952
|
import { useAppDispatch, useAppSelector } from "@ai-matrx/chat/store/hooks";
|
|
1934
1953
|
import {
|
|
1935
|
-
fetchUnifiedMenu
|
|
1954
|
+
fetchUnifiedMenu,
|
|
1936
1955
|
unifiedMenuLoadedKey
|
|
1937
1956
|
} from "@ai-matrx/chat/agents/redux/agent-shortcuts/thunks";
|
|
1938
1957
|
|
|
@@ -2102,7 +2121,7 @@ function useUnifiedAgentContextMenu(args) {
|
|
|
2102
2121
|
try {
|
|
2103
2122
|
setError(null);
|
|
2104
2123
|
await (0, menu_deadline_exports.withMenuDeadline)(
|
|
2105
|
-
dispatch(
|
|
2124
|
+
dispatch(fetchUnifiedMenu({ scope, scopeId })).unwrap(),
|
|
2106
2125
|
"Loading the menu's AI actions"
|
|
2107
2126
|
);
|
|
2108
2127
|
} catch (err) {
|
|
@@ -2995,12 +3014,25 @@ function useContextMenuActions(props) {
|
|
|
2995
3014
|
};
|
|
2996
3015
|
const insertTargets = { editorId, getTextarea, insertAtCaret, onTextReplace };
|
|
2997
3016
|
const handleContentBlockInsert = (entry) => {
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3017
|
+
void (async () => {
|
|
3018
|
+
let template = entry.template;
|
|
3019
|
+
if (!template) {
|
|
3020
|
+
try {
|
|
3021
|
+
template = await ensureBlockTemplate(entry.id, dispatch);
|
|
3022
|
+
} catch (error) {
|
|
3023
|
+
toast2({
|
|
3024
|
+
title: "Couldn't load that block",
|
|
3025
|
+
description: error instanceof Error ? error.message : "Try again.",
|
|
3026
|
+
variant: "destructive"
|
|
3027
|
+
});
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
if (insertIntoEditor(insertTargets, template)) {
|
|
3032
|
+
onContentInserted?.();
|
|
3033
|
+
return;
|
|
3034
|
+
}
|
|
3035
|
+
const copied = await kitCopyText(template);
|
|
3004
3036
|
if (copied) {
|
|
3005
3037
|
toast2({
|
|
3006
3038
|
title: "Copied to clipboard",
|
|
@@ -3009,7 +3041,7 @@ function useContextMenuActions(props) {
|
|
|
3009
3041
|
} else {
|
|
3010
3042
|
getContextMenuHost().showManualCopy({ text: template });
|
|
3011
3043
|
}
|
|
3012
|
-
});
|
|
3044
|
+
})();
|
|
3013
3045
|
};
|
|
3014
3046
|
const handleEntrySelect = (entry) => {
|
|
3015
3047
|
if (entry.entryType === "agent_shortcut") void handleShortcutExecute(entry);
|