@harbour-enterprises/superdoc 0.21.0-next.3 → 0.21.0-next.5
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/dist/chunks/{PdfViewer-OZDJ7gwT.cjs → PdfViewer-DYQ6TKSD.cjs} +1 -1
- package/dist/chunks/{PdfViewer-D3zo7tPo.es.js → PdfViewer-p-D44U59.es.js} +1 -1
- package/dist/chunks/{index-MzW5BVNd.es.js → index-CDJb8aX-.es.js} +4 -3
- package/dist/chunks/{index-CfYf4T_z.cjs → index-CtZxITmf.cjs} +4 -3
- package/dist/chunks/{super-editor.es-U-GVCd_F.cjs → super-editor.es-Do6Vcsbv.cjs} +377 -118
- package/dist/chunks/{super-editor.es-Bntob7Wd.es.js → super-editor.es-HiSJrA0J.es.js} +377 -118
- package/dist/core/types/index.d.ts +8 -0
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/style.css +32 -27
- package/dist/super-editor/src/components/slash-menu/menuItems.d.ts +5 -1
- package/dist/super-editor/src/components/slash-menu/tests/testHelpers.d.ts +466 -0
- package/dist/super-editor/src/components/slash-menu/utils.d.ts +9 -2
- package/dist/super-editor/style.css +5 -0
- package/dist/super-editor/super-editor.es.js +377 -118
- package/dist/super-editor.cjs +1 -1
- package/dist/super-editor.es.js +1 -1
- package/dist/superdoc.cjs +2 -2
- package/dist/superdoc.es.js +2 -2
- package/dist/superdoc.umd.js +379 -119
- package/dist/superdoc.umd.js.map +1 -1
- package/package.json +3 -5
- package/npm-deprecation-notice.cjs +0 -2
|
@@ -83569,6 +83569,115 @@ runCommandWithArgumentOnly_fn = function({ item, argument, noArgumentCallback =
|
|
|
83569
83569
|
this.updateToolbarState();
|
|
83570
83570
|
}
|
|
83571
83571
|
};
|
|
83572
|
+
const onMarginClickCursorChange = (event, editor) => {
|
|
83573
|
+
const y2 = event.clientY;
|
|
83574
|
+
const x = event.clientX;
|
|
83575
|
+
const { view } = editor;
|
|
83576
|
+
const editorRect = view.dom.getBoundingClientRect();
|
|
83577
|
+
let coords = {
|
|
83578
|
+
left: 0,
|
|
83579
|
+
top: y2
|
|
83580
|
+
};
|
|
83581
|
+
let isRightMargin = false;
|
|
83582
|
+
if (x > editorRect.right) {
|
|
83583
|
+
coords.left = editorRect.left + editorRect.width - 1;
|
|
83584
|
+
isRightMargin = true;
|
|
83585
|
+
} else if (x < editorRect.left) {
|
|
83586
|
+
coords.left = editorRect.left;
|
|
83587
|
+
}
|
|
83588
|
+
const pos = view.posAtCoords(coords)?.pos;
|
|
83589
|
+
if (pos) {
|
|
83590
|
+
let cursorPos = pos;
|
|
83591
|
+
if (isRightMargin) {
|
|
83592
|
+
const $pos = view.state.doc.resolve(pos);
|
|
83593
|
+
const charOffset = $pos.textOffset;
|
|
83594
|
+
const node = view.state.doc.nodeAt(pos);
|
|
83595
|
+
const text = node?.text;
|
|
83596
|
+
const charAtPos = text?.charAt(charOffset);
|
|
83597
|
+
cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
|
|
83598
|
+
}
|
|
83599
|
+
const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
|
|
83600
|
+
view.dispatch(transaction);
|
|
83601
|
+
view.focus();
|
|
83602
|
+
}
|
|
83603
|
+
};
|
|
83604
|
+
const checkNodeSpecificClicks = (editor, event, popoverControls) => {
|
|
83605
|
+
if (!editor) return;
|
|
83606
|
+
if (selectionHasNodeOrMark(editor.view.state, "link", { requireEnds: true })) {
|
|
83607
|
+
popoverControls.component = LinkInput;
|
|
83608
|
+
popoverControls.position = {
|
|
83609
|
+
left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
|
|
83610
|
+
top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
|
|
83611
|
+
};
|
|
83612
|
+
popoverControls.props = {
|
|
83613
|
+
showInput: true
|
|
83614
|
+
};
|
|
83615
|
+
popoverControls.visible = true;
|
|
83616
|
+
}
|
|
83617
|
+
};
|
|
83618
|
+
function selectionHasNodeOrMark(state2, name, options = {}) {
|
|
83619
|
+
const { requireEnds = false } = options;
|
|
83620
|
+
const $from = state2.selection.$from;
|
|
83621
|
+
const $to = state2.selection.$to;
|
|
83622
|
+
if (requireEnds) {
|
|
83623
|
+
for (let d2 = $from.depth; d2 > 0; d2--) {
|
|
83624
|
+
if ($from.node(d2).type.name === name) {
|
|
83625
|
+
return true;
|
|
83626
|
+
}
|
|
83627
|
+
}
|
|
83628
|
+
for (let d2 = $to.depth; d2 > 0; d2--) {
|
|
83629
|
+
if ($to.node(d2).type.name === name) {
|
|
83630
|
+
return true;
|
|
83631
|
+
}
|
|
83632
|
+
}
|
|
83633
|
+
} else {
|
|
83634
|
+
for (let d2 = $from.depth; d2 > 0; d2--) {
|
|
83635
|
+
if ($from.node(d2).type.name === name) {
|
|
83636
|
+
return true;
|
|
83637
|
+
}
|
|
83638
|
+
}
|
|
83639
|
+
}
|
|
83640
|
+
const markType = state2.schema.marks[name];
|
|
83641
|
+
if (markType) {
|
|
83642
|
+
const { from: from2, to, empty: empty2 } = state2.selection;
|
|
83643
|
+
if (requireEnds) {
|
|
83644
|
+
const fromMarks = markType.isInSet($from.marks());
|
|
83645
|
+
const toMarks = markType.isInSet($to.marks());
|
|
83646
|
+
if (fromMarks || toMarks) {
|
|
83647
|
+
return true;
|
|
83648
|
+
}
|
|
83649
|
+
if (empty2 && markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83650
|
+
return true;
|
|
83651
|
+
}
|
|
83652
|
+
} else {
|
|
83653
|
+
if (empty2) {
|
|
83654
|
+
if (markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83655
|
+
return true;
|
|
83656
|
+
}
|
|
83657
|
+
} else {
|
|
83658
|
+
let hasMark = false;
|
|
83659
|
+
state2.doc.nodesBetween(from2, to, (node) => {
|
|
83660
|
+
if (markType.isInSet(node.marks)) {
|
|
83661
|
+
hasMark = true;
|
|
83662
|
+
return false;
|
|
83663
|
+
}
|
|
83664
|
+
});
|
|
83665
|
+
if (hasMark) return true;
|
|
83666
|
+
}
|
|
83667
|
+
}
|
|
83668
|
+
}
|
|
83669
|
+
return false;
|
|
83670
|
+
}
|
|
83671
|
+
function moveCursorToMouseEvent(event, editor) {
|
|
83672
|
+
const { view } = editor;
|
|
83673
|
+
const coords = { left: event.clientX, top: event.clientY };
|
|
83674
|
+
const pos = view.posAtCoords(coords)?.pos;
|
|
83675
|
+
if (typeof pos === "number") {
|
|
83676
|
+
const tr = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, pos));
|
|
83677
|
+
view.dispatch(tr);
|
|
83678
|
+
view.focus();
|
|
83679
|
+
}
|
|
83680
|
+
}
|
|
83572
83681
|
const ICONS = {
|
|
83573
83682
|
addRowBefore: plusIconSvg,
|
|
83574
83683
|
addRowAfter: plusIconSvg,
|
|
@@ -83768,6 +83877,30 @@ const getPropsByItemId = (itemId, props) => {
|
|
|
83768
83877
|
return baseProps;
|
|
83769
83878
|
}
|
|
83770
83879
|
};
|
|
83880
|
+
function normalizeClipboardContent(rawClipboardContent) {
|
|
83881
|
+
if (!rawClipboardContent) {
|
|
83882
|
+
return {
|
|
83883
|
+
html: null,
|
|
83884
|
+
text: null,
|
|
83885
|
+
hasContent: false,
|
|
83886
|
+
raw: null
|
|
83887
|
+
};
|
|
83888
|
+
}
|
|
83889
|
+
const html = typeof rawClipboardContent.html === "string" ? rawClipboardContent.html : null;
|
|
83890
|
+
const text = typeof rawClipboardContent.text === "string" ? rawClipboardContent.text : null;
|
|
83891
|
+
const hasHtml = !!html && html.trim().length > 0;
|
|
83892
|
+
const hasText = !!text && text.length > 0;
|
|
83893
|
+
const isObject2 = typeof rawClipboardContent === "object" && rawClipboardContent !== null;
|
|
83894
|
+
const fragmentSize = typeof rawClipboardContent.size === "number" ? rawClipboardContent.size : null;
|
|
83895
|
+
const nestedSize = isObject2 && rawClipboardContent.content && typeof rawClipboardContent.content.size === "number" ? rawClipboardContent.content.size : null;
|
|
83896
|
+
const hasFragmentContent = (fragmentSize ?? nestedSize ?? 0) > 0;
|
|
83897
|
+
return {
|
|
83898
|
+
html,
|
|
83899
|
+
text,
|
|
83900
|
+
hasContent: hasHtml || hasText || hasFragmentContent,
|
|
83901
|
+
raw: rawClipboardContent
|
|
83902
|
+
};
|
|
83903
|
+
}
|
|
83771
83904
|
async function getEditorContext(editor, event) {
|
|
83772
83905
|
const { view } = editor;
|
|
83773
83906
|
const { state: state2 } = view;
|
|
@@ -83783,123 +83916,144 @@ async function getEditorContext(editor, event) {
|
|
|
83783
83916
|
pos = from2;
|
|
83784
83917
|
node = state2.doc.nodeAt(pos);
|
|
83785
83918
|
}
|
|
83786
|
-
const
|
|
83919
|
+
const rawClipboardContent = await readFromClipboard(state2);
|
|
83920
|
+
const clipboardContent = normalizeClipboardContent(rawClipboardContent);
|
|
83921
|
+
const structureFromResolvedPos = pos !== null ? getStructureFromResolvedPos(state2, pos) : null;
|
|
83922
|
+
const isInTable2 = structureFromResolvedPos?.isInTable ?? selectionHasNodeOrMark(state2, "table", { requireEnds: true });
|
|
83923
|
+
const isInList = structureFromResolvedPos?.isInList ?? (selectionHasNodeOrMark(state2, "bulletList", { requireEnds: false }) || selectionHasNodeOrMark(state2, "orderedList", { requireEnds: false }));
|
|
83924
|
+
const isInSectionNode = structureFromResolvedPos?.isInSectionNode ?? selectionHasNodeOrMark(state2, "documentSection", { requireEnds: true });
|
|
83925
|
+
const currentNodeType = node?.type?.name || null;
|
|
83926
|
+
const activeMarks = [];
|
|
83927
|
+
if (event && pos !== null) {
|
|
83928
|
+
const $pos = state2.doc.resolve(pos);
|
|
83929
|
+
if ($pos.marks && typeof $pos.marks === "function") {
|
|
83930
|
+
$pos.marks().forEach((mark) => activeMarks.push(mark.type.name));
|
|
83931
|
+
}
|
|
83932
|
+
if (node && node.marks) {
|
|
83933
|
+
node.marks.forEach((mark) => activeMarks.push(mark.type.name));
|
|
83934
|
+
}
|
|
83935
|
+
} else {
|
|
83936
|
+
state2.storedMarks?.forEach((mark) => activeMarks.push(mark.type.name));
|
|
83937
|
+
state2.selection.$head.marks().forEach((mark) => activeMarks.push(mark.type.name));
|
|
83938
|
+
}
|
|
83939
|
+
const isTrackedChange = activeMarks.includes("trackInsert") || activeMarks.includes("trackDelete");
|
|
83940
|
+
let trackedChangeId = null;
|
|
83941
|
+
if (isTrackedChange && event && pos !== null) {
|
|
83942
|
+
const $pos = state2.doc.resolve(pos);
|
|
83943
|
+
const marksAtPos = $pos.marks();
|
|
83944
|
+
const trackedMark = marksAtPos.find((mark) => mark.type.name === "trackInsert" || mark.type.name === "trackDelete");
|
|
83945
|
+
if (trackedMark) {
|
|
83946
|
+
trackedChangeId = trackedMark.attrs.id;
|
|
83947
|
+
}
|
|
83948
|
+
}
|
|
83949
|
+
const cursorCoords = pos ? view.coordsAtPos(pos) : null;
|
|
83950
|
+
const cursorPosition = cursorCoords ? {
|
|
83951
|
+
x: cursorCoords.left,
|
|
83952
|
+
y: cursorCoords.top
|
|
83953
|
+
} : null;
|
|
83787
83954
|
return {
|
|
83788
|
-
|
|
83955
|
+
// Selection info
|
|
83789
83956
|
selectedText,
|
|
83957
|
+
hasSelection: !empty2,
|
|
83958
|
+
selectionStart: from2,
|
|
83959
|
+
selectionEnd: to,
|
|
83960
|
+
// Document structure
|
|
83961
|
+
isInTable: isInTable2,
|
|
83962
|
+
isInList,
|
|
83963
|
+
isInSectionNode,
|
|
83964
|
+
currentNodeType,
|
|
83965
|
+
activeMarks,
|
|
83966
|
+
// Document state
|
|
83967
|
+
isTrackedChange,
|
|
83968
|
+
trackedChangeId,
|
|
83969
|
+
documentMode: editor.options?.documentMode || "editing",
|
|
83970
|
+
canUndo: computeCanUndo(editor, state2),
|
|
83971
|
+
canRedo: computeCanRedo(editor, state2),
|
|
83972
|
+
isEditable: editor.isEditable,
|
|
83973
|
+
// Clipboard
|
|
83974
|
+
clipboardContent,
|
|
83975
|
+
// Position and trigger info
|
|
83976
|
+
cursorPosition,
|
|
83790
83977
|
pos,
|
|
83791
83978
|
node,
|
|
83792
83979
|
event,
|
|
83793
|
-
|
|
83980
|
+
// Editor reference for advanced use cases
|
|
83981
|
+
editor
|
|
83794
83982
|
};
|
|
83795
83983
|
}
|
|
83796
|
-
|
|
83797
|
-
|
|
83798
|
-
|
|
83799
|
-
|
|
83800
|
-
|
|
83801
|
-
|
|
83802
|
-
|
|
83803
|
-
|
|
83804
|
-
|
|
83805
|
-
|
|
83806
|
-
if (x > editorRect.right) {
|
|
83807
|
-
coords.left = editorRect.left + editorRect.width - 1;
|
|
83808
|
-
isRightMargin = true;
|
|
83809
|
-
} else if (x < editorRect.left) {
|
|
83810
|
-
coords.left = editorRect.left;
|
|
83984
|
+
function computeCanUndo(editor, state2) {
|
|
83985
|
+
if (typeof editor?.can === "function") {
|
|
83986
|
+
try {
|
|
83987
|
+
const can = editor.can();
|
|
83988
|
+
if (can && typeof can.undo === "function") {
|
|
83989
|
+
return !!can.undo();
|
|
83990
|
+
}
|
|
83991
|
+
} catch (error) {
|
|
83992
|
+
console.warn("[SlashMenu] Unable to determine undo availability via editor.can():", error);
|
|
83993
|
+
}
|
|
83811
83994
|
}
|
|
83812
|
-
|
|
83813
|
-
|
|
83814
|
-
|
|
83815
|
-
|
|
83816
|
-
|
|
83817
|
-
|
|
83818
|
-
const node = view.state.doc.nodeAt(pos);
|
|
83819
|
-
const text = node?.text;
|
|
83820
|
-
const charAtPos = text?.charAt(charOffset);
|
|
83821
|
-
cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
|
|
83995
|
+
if (isCollaborationEnabled(editor)) {
|
|
83996
|
+
try {
|
|
83997
|
+
const undoManager = yUndoPluginKey.getState(state2)?.undoManager;
|
|
83998
|
+
return !!undoManager && undoManager.undoStack.length > 0;
|
|
83999
|
+
} catch (error) {
|
|
84000
|
+
console.warn("[SlashMenu] Unable to determine undo availability via y-prosemirror:", error);
|
|
83822
84001
|
}
|
|
83823
|
-
const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
|
|
83824
|
-
view.dispatch(transaction);
|
|
83825
|
-
view.focus();
|
|
83826
84002
|
}
|
|
83827
|
-
|
|
83828
|
-
|
|
83829
|
-
|
|
83830
|
-
|
|
83831
|
-
|
|
83832
|
-
popoverControls.position = {
|
|
83833
|
-
left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
|
|
83834
|
-
top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
|
|
83835
|
-
};
|
|
83836
|
-
popoverControls.props = {
|
|
83837
|
-
showInput: true
|
|
83838
|
-
};
|
|
83839
|
-
popoverControls.visible = true;
|
|
84003
|
+
try {
|
|
84004
|
+
return undoDepth(state2) > 0;
|
|
84005
|
+
} catch (error) {
|
|
84006
|
+
console.warn("[SlashMenu] Unable to determine undo availability via history plugin:", error);
|
|
84007
|
+
return false;
|
|
83840
84008
|
}
|
|
83841
|
-
}
|
|
83842
|
-
function
|
|
83843
|
-
|
|
83844
|
-
|
|
83845
|
-
|
|
83846
|
-
|
|
83847
|
-
|
|
83848
|
-
if ($from.node(d2).type.name === name) {
|
|
83849
|
-
return true;
|
|
83850
|
-
}
|
|
83851
|
-
}
|
|
83852
|
-
for (let d2 = $to.depth; d2 > 0; d2--) {
|
|
83853
|
-
if ($to.node(d2).type.name === name) {
|
|
83854
|
-
return true;
|
|
83855
|
-
}
|
|
83856
|
-
}
|
|
83857
|
-
} else {
|
|
83858
|
-
for (let d2 = $from.depth; d2 > 0; d2--) {
|
|
83859
|
-
if ($from.node(d2).type.name === name) {
|
|
83860
|
-
return true;
|
|
84009
|
+
}
|
|
84010
|
+
function computeCanRedo(editor, state2) {
|
|
84011
|
+
if (typeof editor?.can === "function") {
|
|
84012
|
+
try {
|
|
84013
|
+
const can = editor.can();
|
|
84014
|
+
if (can && typeof can.redo === "function") {
|
|
84015
|
+
return !!can.redo();
|
|
83861
84016
|
}
|
|
84017
|
+
} catch (error) {
|
|
84018
|
+
console.warn("[SlashMenu] Unable to determine redo availability via editor.can():", error);
|
|
83862
84019
|
}
|
|
83863
84020
|
}
|
|
83864
|
-
|
|
83865
|
-
|
|
83866
|
-
|
|
83867
|
-
|
|
83868
|
-
|
|
83869
|
-
|
|
83870
|
-
if (fromMarks || toMarks) {
|
|
83871
|
-
return true;
|
|
83872
|
-
}
|
|
83873
|
-
if (empty2 && markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83874
|
-
return true;
|
|
83875
|
-
}
|
|
83876
|
-
} else {
|
|
83877
|
-
if (empty2) {
|
|
83878
|
-
if (markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83879
|
-
return true;
|
|
83880
|
-
}
|
|
83881
|
-
} else {
|
|
83882
|
-
let hasMark = false;
|
|
83883
|
-
state2.doc.nodesBetween(from2, to, (node) => {
|
|
83884
|
-
if (markType.isInSet(node.marks)) {
|
|
83885
|
-
hasMark = true;
|
|
83886
|
-
return false;
|
|
83887
|
-
}
|
|
83888
|
-
});
|
|
83889
|
-
if (hasMark) return true;
|
|
83890
|
-
}
|
|
84021
|
+
if (isCollaborationEnabled(editor)) {
|
|
84022
|
+
try {
|
|
84023
|
+
const undoManager = yUndoPluginKey.getState(state2)?.undoManager;
|
|
84024
|
+
return !!undoManager && undoManager.redoStack.length > 0;
|
|
84025
|
+
} catch (error) {
|
|
84026
|
+
console.warn("[SlashMenu] Unable to determine redo availability via y-prosemirror:", error);
|
|
83891
84027
|
}
|
|
83892
84028
|
}
|
|
83893
|
-
|
|
84029
|
+
try {
|
|
84030
|
+
return redoDepth(state2) > 0;
|
|
84031
|
+
} catch (error) {
|
|
84032
|
+
console.warn("[SlashMenu] Unable to determine redo availability via history plugin:", error);
|
|
84033
|
+
return false;
|
|
84034
|
+
}
|
|
83894
84035
|
}
|
|
83895
|
-
function
|
|
83896
|
-
|
|
83897
|
-
|
|
83898
|
-
|
|
83899
|
-
|
|
83900
|
-
const
|
|
83901
|
-
|
|
83902
|
-
|
|
84036
|
+
function isCollaborationEnabled(editor) {
|
|
84037
|
+
return Boolean(editor?.options?.collaborationProvider && editor?.options?.ydoc);
|
|
84038
|
+
}
|
|
84039
|
+
function getStructureFromResolvedPos(state2, pos) {
|
|
84040
|
+
try {
|
|
84041
|
+
const $pos = state2.doc.resolve(pos);
|
|
84042
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
84043
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
84044
|
+
ancestors.add($pos.node(depth).type.name);
|
|
84045
|
+
}
|
|
84046
|
+
const isInList = ancestors.has("bulletList") || ancestors.has("orderedList");
|
|
84047
|
+
const isInTable2 = ancestors.has("table") || ancestors.has("tableRow") || ancestors.has("tableCell") || ancestors.has("tableHeader");
|
|
84048
|
+
const isInSectionNode = ancestors.has("documentSection");
|
|
84049
|
+
return {
|
|
84050
|
+
isInTable: isInTable2,
|
|
84051
|
+
isInList,
|
|
84052
|
+
isInSectionNode
|
|
84053
|
+
};
|
|
84054
|
+
} catch (error) {
|
|
84055
|
+
console.warn("[SlashMenu] Unable to resolve position for structural context:", error);
|
|
84056
|
+
return null;
|
|
83903
84057
|
}
|
|
83904
84058
|
}
|
|
83905
84059
|
const isModuleEnabled = (editorOptions, moduleName) => {
|
|
@@ -83913,8 +84067,52 @@ const isModuleEnabled = (editorOptions, moduleName) => {
|
|
|
83913
84067
|
return true;
|
|
83914
84068
|
}
|
|
83915
84069
|
};
|
|
84070
|
+
function applyCustomMenuConfiguration(defaultSections, context) {
|
|
84071
|
+
const { editor } = context;
|
|
84072
|
+
const slashMenuConfig = editor.options?.slashMenuConfig;
|
|
84073
|
+
if (!slashMenuConfig) {
|
|
84074
|
+
return defaultSections;
|
|
84075
|
+
}
|
|
84076
|
+
let sections = [];
|
|
84077
|
+
if (slashMenuConfig.includeDefaultItems !== false) {
|
|
84078
|
+
sections = [...defaultSections];
|
|
84079
|
+
}
|
|
84080
|
+
if (slashMenuConfig.customItems && Array.isArray(slashMenuConfig.customItems)) {
|
|
84081
|
+
sections = [...sections, ...slashMenuConfig.customItems];
|
|
84082
|
+
}
|
|
84083
|
+
if (typeof slashMenuConfig.menuProvider === "function") {
|
|
84084
|
+
try {
|
|
84085
|
+
sections = slashMenuConfig.menuProvider(context, sections) || sections;
|
|
84086
|
+
} catch (error) {
|
|
84087
|
+
console.warn("[SlashMenu] Error in custom menuProvider:", error);
|
|
84088
|
+
}
|
|
84089
|
+
}
|
|
84090
|
+
return sections;
|
|
84091
|
+
}
|
|
84092
|
+
function filterCustomItems(sections, context) {
|
|
84093
|
+
return sections.map((section) => {
|
|
84094
|
+
const filteredItems = section.items.filter((item) => {
|
|
84095
|
+
if (typeof item.showWhen === "function") {
|
|
84096
|
+
try {
|
|
84097
|
+
return item.showWhen(context);
|
|
84098
|
+
} catch (error) {
|
|
84099
|
+
console.warn(`[SlashMenu] Error in showWhen for item ${item.id}:`, error);
|
|
84100
|
+
return false;
|
|
84101
|
+
}
|
|
84102
|
+
}
|
|
84103
|
+
return true;
|
|
84104
|
+
});
|
|
84105
|
+
return {
|
|
84106
|
+
...section,
|
|
84107
|
+
items: filteredItems
|
|
84108
|
+
};
|
|
84109
|
+
}).filter((section) => section.items.length > 0);
|
|
84110
|
+
}
|
|
83916
84111
|
function getItems(context) {
|
|
83917
84112
|
const { editor, selectedText, trigger: trigger2, clipboardContent } = context;
|
|
84113
|
+
const clipboardHasContent = Boolean(
|
|
84114
|
+
clipboardContent?.hasContent || clipboardContent?.html || clipboardContent?.text || typeof clipboardContent?.size === "number" && clipboardContent.size > 0 || clipboardContent && typeof clipboardContent?.content?.size === "number" && clipboardContent.content.size > 0 || clipboardContent?.raw && typeof clipboardContent.raw.size === "number" && clipboardContent.raw.size > 0 || clipboardContent?.raw && typeof clipboardContent.raw?.content?.size === "number" && clipboardContent.raw.content.size > 0
|
|
84115
|
+
);
|
|
83918
84116
|
const isInTable2 = selectionHasNodeOrMark(editor.view.state, "table", { requireEnds: true });
|
|
83919
84117
|
const isInSectionNode = selectionHasNodeOrMark(editor.view.state, "documentSection", { requireEnds: true });
|
|
83920
84118
|
const sections = [
|
|
@@ -84051,12 +84249,13 @@ function getItems(context) {
|
|
|
84051
84249
|
]
|
|
84052
84250
|
}
|
|
84053
84251
|
];
|
|
84054
|
-
|
|
84252
|
+
let allSections = applyCustomMenuConfiguration(sections, context);
|
|
84253
|
+
const filteredSections = allSections.map((section) => {
|
|
84055
84254
|
const filteredItems = section.items.filter((item) => {
|
|
84056
84255
|
if (item.requiresModule && !isModuleEnabled(editor?.options, item.requiresModule)) return false;
|
|
84057
84256
|
if (item.requiresSelection && !selectedText) return false;
|
|
84058
84257
|
if (!item.allowedTriggers.includes(trigger2)) return false;
|
|
84059
|
-
if (item.requiresClipboard && !
|
|
84258
|
+
if (item.requiresClipboard && !clipboardHasContent) return false;
|
|
84060
84259
|
if (item.requiresTableParent && !isInTable2 || item.id === "insert-table" && isInTable2) return false;
|
|
84061
84260
|
if (item.requiresSectionParent && !isInSectionNode) return false;
|
|
84062
84261
|
return true;
|
|
@@ -84066,7 +84265,8 @@ function getItems(context) {
|
|
|
84066
84265
|
items: filteredItems
|
|
84067
84266
|
};
|
|
84068
84267
|
}).filter((section) => section.items.length > 0);
|
|
84069
|
-
|
|
84268
|
+
const finalSections = filterCustomItems(filteredSections, context);
|
|
84269
|
+
return finalSections;
|
|
84070
84270
|
}
|
|
84071
84271
|
const _hoisted_1$3 = { class: "slash-menu-items" };
|
|
84072
84272
|
const _hoisted_2$1 = {
|
|
@@ -84101,6 +84301,7 @@ const _sfc_main$4 = {
|
|
|
84101
84301
|
const menuRef = vue.ref(null);
|
|
84102
84302
|
const sections = vue.ref([]);
|
|
84103
84303
|
const selectedId = vue.ref(null);
|
|
84304
|
+
const currentContext = vue.ref(null);
|
|
84104
84305
|
const handleEditorUpdate = () => {
|
|
84105
84306
|
if (!props.editor?.isEditable && isOpen.value) {
|
|
84106
84307
|
closeMenu({ restoreCursor: false });
|
|
@@ -84146,6 +84347,44 @@ const _sfc_main$4 = {
|
|
|
84146
84347
|
selectedId.value = newItems[0].id;
|
|
84147
84348
|
}
|
|
84148
84349
|
});
|
|
84350
|
+
const customItemRefs = /* @__PURE__ */ new Map();
|
|
84351
|
+
const setCustomItemRef = (el, item) => {
|
|
84352
|
+
if (el && item.render) {
|
|
84353
|
+
customItemRefs.set(item.id, { element: el, item });
|
|
84354
|
+
vue.nextTick(() => {
|
|
84355
|
+
renderCustomItem(item.id);
|
|
84356
|
+
});
|
|
84357
|
+
}
|
|
84358
|
+
};
|
|
84359
|
+
const renderCustomItem = async (itemId) => {
|
|
84360
|
+
const refData = customItemRefs.get(itemId);
|
|
84361
|
+
if (!refData || refData.element.hasCustomContent) return;
|
|
84362
|
+
const { element, item } = refData;
|
|
84363
|
+
try {
|
|
84364
|
+
if (!currentContext.value) {
|
|
84365
|
+
currentContext.value = await getEditorContext(props.editor);
|
|
84366
|
+
}
|
|
84367
|
+
const context = currentContext.value;
|
|
84368
|
+
const customElement = item.render(context);
|
|
84369
|
+
if (customElement instanceof HTMLElement) {
|
|
84370
|
+
element.innerHTML = "";
|
|
84371
|
+
element.appendChild(customElement);
|
|
84372
|
+
element.hasCustomContent = true;
|
|
84373
|
+
}
|
|
84374
|
+
} catch (error) {
|
|
84375
|
+
console.warn(`[SlashMenu] Error rendering custom item ${itemId}:`, error);
|
|
84376
|
+
element.innerHTML = `<span>${item.label || "Custom Item"}</span>`;
|
|
84377
|
+
element.hasCustomContent = true;
|
|
84378
|
+
}
|
|
84379
|
+
};
|
|
84380
|
+
const cleanupCustomItems = () => {
|
|
84381
|
+
customItemRefs.forEach((refData) => {
|
|
84382
|
+
if (refData.element) {
|
|
84383
|
+
refData.element.hasCustomContent = false;
|
|
84384
|
+
}
|
|
84385
|
+
});
|
|
84386
|
+
customItemRefs.clear();
|
|
84387
|
+
};
|
|
84149
84388
|
const handleGlobalKeyDown = (event) => {
|
|
84150
84389
|
if (event.key === "Escape") {
|
|
84151
84390
|
event.preventDefault();
|
|
@@ -84196,22 +84435,23 @@ const _sfc_main$4 = {
|
|
|
84196
84435
|
return;
|
|
84197
84436
|
}
|
|
84198
84437
|
event.preventDefault();
|
|
84438
|
+
const context = await getEditorContext(props.editor, event);
|
|
84439
|
+
currentContext.value = context;
|
|
84440
|
+
sections.value = getItems({ ...context, trigger: "click" });
|
|
84441
|
+
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84442
|
+
searchQuery.value = "";
|
|
84199
84443
|
props.editor.view.dispatch(
|
|
84200
84444
|
props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
84201
84445
|
type: "open",
|
|
84202
|
-
pos: props.editor.view.state.selection.from,
|
|
84446
|
+
pos: context?.pos ?? props.editor.view.state.selection.from,
|
|
84203
84447
|
clientX: event.clientX,
|
|
84204
84448
|
clientY: event.clientY
|
|
84205
84449
|
})
|
|
84206
84450
|
);
|
|
84207
|
-
searchQuery.value = "";
|
|
84208
|
-
const context = await getEditorContext(props.editor, event);
|
|
84209
|
-
sections.value = getItems({ ...context, trigger: "click" });
|
|
84210
|
-
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84211
84451
|
};
|
|
84212
84452
|
const executeCommand = async (item) => {
|
|
84213
84453
|
if (props.editor) {
|
|
84214
|
-
item.action ? await item.action(props.editor) : null;
|
|
84454
|
+
item.action ? await item.action(props.editor, currentContext.value) : null;
|
|
84215
84455
|
if (item.component) {
|
|
84216
84456
|
menuRef.value;
|
|
84217
84457
|
const componentProps = getPropsByItemId(item.id, props);
|
|
@@ -84229,7 +84469,7 @@ const _sfc_main$4 = {
|
|
|
84229
84469
|
const closeMenu = (options = { restoreCursor: true }) => {
|
|
84230
84470
|
if (props.editor?.view) {
|
|
84231
84471
|
const pluginState = SlashMenuPluginKey.getState(props.editor.view.state);
|
|
84232
|
-
const
|
|
84472
|
+
const anchorPos = pluginState?.anchorPos;
|
|
84233
84473
|
props.editor.view.dispatch(
|
|
84234
84474
|
props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
84235
84475
|
type: "close"
|
|
@@ -84242,6 +84482,8 @@ const _sfc_main$4 = {
|
|
|
84242
84482
|
props.editor.view.dispatch(tr);
|
|
84243
84483
|
props.editor.view.focus();
|
|
84244
84484
|
}
|
|
84485
|
+
cleanupCustomItems();
|
|
84486
|
+
currentContext.value = null;
|
|
84245
84487
|
isOpen.value = false;
|
|
84246
84488
|
searchQuery.value = "";
|
|
84247
84489
|
sections.value = [];
|
|
@@ -84258,19 +84500,29 @@ const _sfc_main$4 = {
|
|
|
84258
84500
|
isOpen.value = true;
|
|
84259
84501
|
menuPosition.value = event.menuPosition;
|
|
84260
84502
|
searchQuery.value = "";
|
|
84261
|
-
|
|
84262
|
-
|
|
84263
|
-
|
|
84503
|
+
if (!currentContext.value) {
|
|
84504
|
+
const context = await getEditorContext(props.editor);
|
|
84505
|
+
currentContext.value = context;
|
|
84506
|
+
sections.value = getItems({ ...context, trigger: "slash" });
|
|
84507
|
+
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84508
|
+
} else if (sections.value.length === 0) {
|
|
84509
|
+
const trigger2 = currentContext.value.event?.type === "contextmenu" ? "click" : "slash";
|
|
84510
|
+
sections.value = getItems({ ...currentContext.value, trigger: trigger2 });
|
|
84511
|
+
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84512
|
+
}
|
|
84264
84513
|
});
|
|
84265
84514
|
props.editor.view.dom.addEventListener("contextmenu", handleRightClick);
|
|
84266
84515
|
props.editor.on("slashMenu:close", () => {
|
|
84516
|
+
cleanupCustomItems();
|
|
84267
84517
|
isOpen.value = false;
|
|
84268
84518
|
searchQuery.value = "";
|
|
84519
|
+
currentContext.value = null;
|
|
84269
84520
|
});
|
|
84270
84521
|
});
|
|
84271
84522
|
vue.onBeforeUnmount(() => {
|
|
84272
84523
|
document.removeEventListener("keydown", handleGlobalKeyDown);
|
|
84273
84524
|
document.removeEventListener("mousedown", handleGlobalOutsideClick);
|
|
84525
|
+
cleanupCustomItems();
|
|
84274
84526
|
if (props.editor) {
|
|
84275
84527
|
try {
|
|
84276
84528
|
props.editor.off("slashMenu:open");
|
|
@@ -84317,12 +84569,19 @@ const _sfc_main$4 = {
|
|
|
84317
84569
|
class: vue.normalizeClass(["slash-menu-item", { "is-selected": item.id === selectedId.value }]),
|
|
84318
84570
|
onClick: ($event) => executeCommand(item)
|
|
84319
84571
|
}, [
|
|
84320
|
-
item.
|
|
84572
|
+
item.render ? (vue.openBlock(), vue.createElementBlock("div", {
|
|
84321
84573
|
key: 0,
|
|
84322
|
-
|
|
84323
|
-
|
|
84324
|
-
|
|
84325
|
-
|
|
84574
|
+
ref_for: true,
|
|
84575
|
+
ref: (el) => setCustomItemRef(el, item),
|
|
84576
|
+
class: "slash-menu-custom-item"
|
|
84577
|
+
}, null, 512)) : (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 1 }, [
|
|
84578
|
+
item.icon ? (vue.openBlock(), vue.createElementBlock("span", {
|
|
84579
|
+
key: 0,
|
|
84580
|
+
class: "slash-menu-item-icon",
|
|
84581
|
+
innerHTML: item.icon
|
|
84582
|
+
}, null, 8, _hoisted_4)) : vue.createCommentVNode("", true),
|
|
84583
|
+
vue.createBaseVNode("span", null, vue.toDisplayString(item.label), 1)
|
|
84584
|
+
], 64))
|
|
84326
84585
|
], 10, _hoisted_3$1);
|
|
84327
84586
|
}), 128))
|
|
84328
84587
|
], 64);
|