@harbour-enterprises/superdoc 0.21.0-next.4 → 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 +1 -1
|
@@ -83552,6 +83552,115 @@ runCommandWithArgumentOnly_fn = function({ item, argument, noArgumentCallback =
|
|
|
83552
83552
|
this.updateToolbarState();
|
|
83553
83553
|
}
|
|
83554
83554
|
};
|
|
83555
|
+
const onMarginClickCursorChange = (event, editor) => {
|
|
83556
|
+
const y2 = event.clientY;
|
|
83557
|
+
const x = event.clientX;
|
|
83558
|
+
const { view } = editor;
|
|
83559
|
+
const editorRect = view.dom.getBoundingClientRect();
|
|
83560
|
+
let coords = {
|
|
83561
|
+
left: 0,
|
|
83562
|
+
top: y2
|
|
83563
|
+
};
|
|
83564
|
+
let isRightMargin = false;
|
|
83565
|
+
if (x > editorRect.right) {
|
|
83566
|
+
coords.left = editorRect.left + editorRect.width - 1;
|
|
83567
|
+
isRightMargin = true;
|
|
83568
|
+
} else if (x < editorRect.left) {
|
|
83569
|
+
coords.left = editorRect.left;
|
|
83570
|
+
}
|
|
83571
|
+
const pos = view.posAtCoords(coords)?.pos;
|
|
83572
|
+
if (pos) {
|
|
83573
|
+
let cursorPos = pos;
|
|
83574
|
+
if (isRightMargin) {
|
|
83575
|
+
const $pos = view.state.doc.resolve(pos);
|
|
83576
|
+
const charOffset = $pos.textOffset;
|
|
83577
|
+
const node = view.state.doc.nodeAt(pos);
|
|
83578
|
+
const text = node?.text;
|
|
83579
|
+
const charAtPos = text?.charAt(charOffset);
|
|
83580
|
+
cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
|
|
83581
|
+
}
|
|
83582
|
+
const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
|
|
83583
|
+
view.dispatch(transaction);
|
|
83584
|
+
view.focus();
|
|
83585
|
+
}
|
|
83586
|
+
};
|
|
83587
|
+
const checkNodeSpecificClicks = (editor, event, popoverControls) => {
|
|
83588
|
+
if (!editor) return;
|
|
83589
|
+
if (selectionHasNodeOrMark(editor.view.state, "link", { requireEnds: true })) {
|
|
83590
|
+
popoverControls.component = LinkInput;
|
|
83591
|
+
popoverControls.position = {
|
|
83592
|
+
left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
|
|
83593
|
+
top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
|
|
83594
|
+
};
|
|
83595
|
+
popoverControls.props = {
|
|
83596
|
+
showInput: true
|
|
83597
|
+
};
|
|
83598
|
+
popoverControls.visible = true;
|
|
83599
|
+
}
|
|
83600
|
+
};
|
|
83601
|
+
function selectionHasNodeOrMark(state2, name, options = {}) {
|
|
83602
|
+
const { requireEnds = false } = options;
|
|
83603
|
+
const $from = state2.selection.$from;
|
|
83604
|
+
const $to = state2.selection.$to;
|
|
83605
|
+
if (requireEnds) {
|
|
83606
|
+
for (let d2 = $from.depth; d2 > 0; d2--) {
|
|
83607
|
+
if ($from.node(d2).type.name === name) {
|
|
83608
|
+
return true;
|
|
83609
|
+
}
|
|
83610
|
+
}
|
|
83611
|
+
for (let d2 = $to.depth; d2 > 0; d2--) {
|
|
83612
|
+
if ($to.node(d2).type.name === name) {
|
|
83613
|
+
return true;
|
|
83614
|
+
}
|
|
83615
|
+
}
|
|
83616
|
+
} else {
|
|
83617
|
+
for (let d2 = $from.depth; d2 > 0; d2--) {
|
|
83618
|
+
if ($from.node(d2).type.name === name) {
|
|
83619
|
+
return true;
|
|
83620
|
+
}
|
|
83621
|
+
}
|
|
83622
|
+
}
|
|
83623
|
+
const markType = state2.schema.marks[name];
|
|
83624
|
+
if (markType) {
|
|
83625
|
+
const { from: from2, to, empty: empty2 } = state2.selection;
|
|
83626
|
+
if (requireEnds) {
|
|
83627
|
+
const fromMarks = markType.isInSet($from.marks());
|
|
83628
|
+
const toMarks = markType.isInSet($to.marks());
|
|
83629
|
+
if (fromMarks || toMarks) {
|
|
83630
|
+
return true;
|
|
83631
|
+
}
|
|
83632
|
+
if (empty2 && markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83633
|
+
return true;
|
|
83634
|
+
}
|
|
83635
|
+
} else {
|
|
83636
|
+
if (empty2) {
|
|
83637
|
+
if (markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83638
|
+
return true;
|
|
83639
|
+
}
|
|
83640
|
+
} else {
|
|
83641
|
+
let hasMark = false;
|
|
83642
|
+
state2.doc.nodesBetween(from2, to, (node) => {
|
|
83643
|
+
if (markType.isInSet(node.marks)) {
|
|
83644
|
+
hasMark = true;
|
|
83645
|
+
return false;
|
|
83646
|
+
}
|
|
83647
|
+
});
|
|
83648
|
+
if (hasMark) return true;
|
|
83649
|
+
}
|
|
83650
|
+
}
|
|
83651
|
+
}
|
|
83652
|
+
return false;
|
|
83653
|
+
}
|
|
83654
|
+
function moveCursorToMouseEvent(event, editor) {
|
|
83655
|
+
const { view } = editor;
|
|
83656
|
+
const coords = { left: event.clientX, top: event.clientY };
|
|
83657
|
+
const pos = view.posAtCoords(coords)?.pos;
|
|
83658
|
+
if (typeof pos === "number") {
|
|
83659
|
+
const tr = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, pos));
|
|
83660
|
+
view.dispatch(tr);
|
|
83661
|
+
view.focus();
|
|
83662
|
+
}
|
|
83663
|
+
}
|
|
83555
83664
|
const ICONS = {
|
|
83556
83665
|
addRowBefore: plusIconSvg,
|
|
83557
83666
|
addRowAfter: plusIconSvg,
|
|
@@ -83751,6 +83860,30 @@ const getPropsByItemId = (itemId, props) => {
|
|
|
83751
83860
|
return baseProps;
|
|
83752
83861
|
}
|
|
83753
83862
|
};
|
|
83863
|
+
function normalizeClipboardContent(rawClipboardContent) {
|
|
83864
|
+
if (!rawClipboardContent) {
|
|
83865
|
+
return {
|
|
83866
|
+
html: null,
|
|
83867
|
+
text: null,
|
|
83868
|
+
hasContent: false,
|
|
83869
|
+
raw: null
|
|
83870
|
+
};
|
|
83871
|
+
}
|
|
83872
|
+
const html = typeof rawClipboardContent.html === "string" ? rawClipboardContent.html : null;
|
|
83873
|
+
const text = typeof rawClipboardContent.text === "string" ? rawClipboardContent.text : null;
|
|
83874
|
+
const hasHtml = !!html && html.trim().length > 0;
|
|
83875
|
+
const hasText = !!text && text.length > 0;
|
|
83876
|
+
const isObject2 = typeof rawClipboardContent === "object" && rawClipboardContent !== null;
|
|
83877
|
+
const fragmentSize = typeof rawClipboardContent.size === "number" ? rawClipboardContent.size : null;
|
|
83878
|
+
const nestedSize = isObject2 && rawClipboardContent.content && typeof rawClipboardContent.content.size === "number" ? rawClipboardContent.content.size : null;
|
|
83879
|
+
const hasFragmentContent = (fragmentSize ?? nestedSize ?? 0) > 0;
|
|
83880
|
+
return {
|
|
83881
|
+
html,
|
|
83882
|
+
text,
|
|
83883
|
+
hasContent: hasHtml || hasText || hasFragmentContent,
|
|
83884
|
+
raw: rawClipboardContent
|
|
83885
|
+
};
|
|
83886
|
+
}
|
|
83754
83887
|
async function getEditorContext(editor, event) {
|
|
83755
83888
|
const { view } = editor;
|
|
83756
83889
|
const { state: state2 } = view;
|
|
@@ -83766,123 +83899,144 @@ async function getEditorContext(editor, event) {
|
|
|
83766
83899
|
pos = from2;
|
|
83767
83900
|
node = state2.doc.nodeAt(pos);
|
|
83768
83901
|
}
|
|
83769
|
-
const
|
|
83902
|
+
const rawClipboardContent = await readFromClipboard(state2);
|
|
83903
|
+
const clipboardContent = normalizeClipboardContent(rawClipboardContent);
|
|
83904
|
+
const structureFromResolvedPos = pos !== null ? getStructureFromResolvedPos(state2, pos) : null;
|
|
83905
|
+
const isInTable2 = structureFromResolvedPos?.isInTable ?? selectionHasNodeOrMark(state2, "table", { requireEnds: true });
|
|
83906
|
+
const isInList = structureFromResolvedPos?.isInList ?? (selectionHasNodeOrMark(state2, "bulletList", { requireEnds: false }) || selectionHasNodeOrMark(state2, "orderedList", { requireEnds: false }));
|
|
83907
|
+
const isInSectionNode = structureFromResolvedPos?.isInSectionNode ?? selectionHasNodeOrMark(state2, "documentSection", { requireEnds: true });
|
|
83908
|
+
const currentNodeType = node?.type?.name || null;
|
|
83909
|
+
const activeMarks = [];
|
|
83910
|
+
if (event && pos !== null) {
|
|
83911
|
+
const $pos = state2.doc.resolve(pos);
|
|
83912
|
+
if ($pos.marks && typeof $pos.marks === "function") {
|
|
83913
|
+
$pos.marks().forEach((mark) => activeMarks.push(mark.type.name));
|
|
83914
|
+
}
|
|
83915
|
+
if (node && node.marks) {
|
|
83916
|
+
node.marks.forEach((mark) => activeMarks.push(mark.type.name));
|
|
83917
|
+
}
|
|
83918
|
+
} else {
|
|
83919
|
+
state2.storedMarks?.forEach((mark) => activeMarks.push(mark.type.name));
|
|
83920
|
+
state2.selection.$head.marks().forEach((mark) => activeMarks.push(mark.type.name));
|
|
83921
|
+
}
|
|
83922
|
+
const isTrackedChange = activeMarks.includes("trackInsert") || activeMarks.includes("trackDelete");
|
|
83923
|
+
let trackedChangeId = null;
|
|
83924
|
+
if (isTrackedChange && event && pos !== null) {
|
|
83925
|
+
const $pos = state2.doc.resolve(pos);
|
|
83926
|
+
const marksAtPos = $pos.marks();
|
|
83927
|
+
const trackedMark = marksAtPos.find((mark) => mark.type.name === "trackInsert" || mark.type.name === "trackDelete");
|
|
83928
|
+
if (trackedMark) {
|
|
83929
|
+
trackedChangeId = trackedMark.attrs.id;
|
|
83930
|
+
}
|
|
83931
|
+
}
|
|
83932
|
+
const cursorCoords = pos ? view.coordsAtPos(pos) : null;
|
|
83933
|
+
const cursorPosition = cursorCoords ? {
|
|
83934
|
+
x: cursorCoords.left,
|
|
83935
|
+
y: cursorCoords.top
|
|
83936
|
+
} : null;
|
|
83770
83937
|
return {
|
|
83771
|
-
|
|
83938
|
+
// Selection info
|
|
83772
83939
|
selectedText,
|
|
83940
|
+
hasSelection: !empty2,
|
|
83941
|
+
selectionStart: from2,
|
|
83942
|
+
selectionEnd: to,
|
|
83943
|
+
// Document structure
|
|
83944
|
+
isInTable: isInTable2,
|
|
83945
|
+
isInList,
|
|
83946
|
+
isInSectionNode,
|
|
83947
|
+
currentNodeType,
|
|
83948
|
+
activeMarks,
|
|
83949
|
+
// Document state
|
|
83950
|
+
isTrackedChange,
|
|
83951
|
+
trackedChangeId,
|
|
83952
|
+
documentMode: editor.options?.documentMode || "editing",
|
|
83953
|
+
canUndo: computeCanUndo(editor, state2),
|
|
83954
|
+
canRedo: computeCanRedo(editor, state2),
|
|
83955
|
+
isEditable: editor.isEditable,
|
|
83956
|
+
// Clipboard
|
|
83957
|
+
clipboardContent,
|
|
83958
|
+
// Position and trigger info
|
|
83959
|
+
cursorPosition,
|
|
83773
83960
|
pos,
|
|
83774
83961
|
node,
|
|
83775
83962
|
event,
|
|
83776
|
-
|
|
83963
|
+
// Editor reference for advanced use cases
|
|
83964
|
+
editor
|
|
83777
83965
|
};
|
|
83778
83966
|
}
|
|
83779
|
-
|
|
83780
|
-
|
|
83781
|
-
|
|
83782
|
-
|
|
83783
|
-
|
|
83784
|
-
|
|
83785
|
-
|
|
83786
|
-
|
|
83787
|
-
|
|
83788
|
-
|
|
83789
|
-
if (x > editorRect.right) {
|
|
83790
|
-
coords.left = editorRect.left + editorRect.width - 1;
|
|
83791
|
-
isRightMargin = true;
|
|
83792
|
-
} else if (x < editorRect.left) {
|
|
83793
|
-
coords.left = editorRect.left;
|
|
83967
|
+
function computeCanUndo(editor, state2) {
|
|
83968
|
+
if (typeof editor?.can === "function") {
|
|
83969
|
+
try {
|
|
83970
|
+
const can = editor.can();
|
|
83971
|
+
if (can && typeof can.undo === "function") {
|
|
83972
|
+
return !!can.undo();
|
|
83973
|
+
}
|
|
83974
|
+
} catch (error) {
|
|
83975
|
+
console.warn("[SlashMenu] Unable to determine undo availability via editor.can():", error);
|
|
83976
|
+
}
|
|
83794
83977
|
}
|
|
83795
|
-
|
|
83796
|
-
|
|
83797
|
-
|
|
83798
|
-
|
|
83799
|
-
|
|
83800
|
-
|
|
83801
|
-
const node = view.state.doc.nodeAt(pos);
|
|
83802
|
-
const text = node?.text;
|
|
83803
|
-
const charAtPos = text?.charAt(charOffset);
|
|
83804
|
-
cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
|
|
83978
|
+
if (isCollaborationEnabled(editor)) {
|
|
83979
|
+
try {
|
|
83980
|
+
const undoManager = yUndoPluginKey.getState(state2)?.undoManager;
|
|
83981
|
+
return !!undoManager && undoManager.undoStack.length > 0;
|
|
83982
|
+
} catch (error) {
|
|
83983
|
+
console.warn("[SlashMenu] Unable to determine undo availability via y-prosemirror:", error);
|
|
83805
83984
|
}
|
|
83806
|
-
const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
|
|
83807
|
-
view.dispatch(transaction);
|
|
83808
|
-
view.focus();
|
|
83809
83985
|
}
|
|
83810
|
-
|
|
83811
|
-
|
|
83812
|
-
|
|
83813
|
-
|
|
83814
|
-
|
|
83815
|
-
popoverControls.position = {
|
|
83816
|
-
left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
|
|
83817
|
-
top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
|
|
83818
|
-
};
|
|
83819
|
-
popoverControls.props = {
|
|
83820
|
-
showInput: true
|
|
83821
|
-
};
|
|
83822
|
-
popoverControls.visible = true;
|
|
83986
|
+
try {
|
|
83987
|
+
return undoDepth(state2) > 0;
|
|
83988
|
+
} catch (error) {
|
|
83989
|
+
console.warn("[SlashMenu] Unable to determine undo availability via history plugin:", error);
|
|
83990
|
+
return false;
|
|
83823
83991
|
}
|
|
83824
|
-
}
|
|
83825
|
-
function
|
|
83826
|
-
|
|
83827
|
-
|
|
83828
|
-
|
|
83829
|
-
|
|
83830
|
-
|
|
83831
|
-
if ($from.node(d2).type.name === name) {
|
|
83832
|
-
return true;
|
|
83833
|
-
}
|
|
83834
|
-
}
|
|
83835
|
-
for (let d2 = $to.depth; d2 > 0; d2--) {
|
|
83836
|
-
if ($to.node(d2).type.name === name) {
|
|
83837
|
-
return true;
|
|
83838
|
-
}
|
|
83839
|
-
}
|
|
83840
|
-
} else {
|
|
83841
|
-
for (let d2 = $from.depth; d2 > 0; d2--) {
|
|
83842
|
-
if ($from.node(d2).type.name === name) {
|
|
83843
|
-
return true;
|
|
83992
|
+
}
|
|
83993
|
+
function computeCanRedo(editor, state2) {
|
|
83994
|
+
if (typeof editor?.can === "function") {
|
|
83995
|
+
try {
|
|
83996
|
+
const can = editor.can();
|
|
83997
|
+
if (can && typeof can.redo === "function") {
|
|
83998
|
+
return !!can.redo();
|
|
83844
83999
|
}
|
|
84000
|
+
} catch (error) {
|
|
84001
|
+
console.warn("[SlashMenu] Unable to determine redo availability via editor.can():", error);
|
|
83845
84002
|
}
|
|
83846
84003
|
}
|
|
83847
|
-
|
|
83848
|
-
|
|
83849
|
-
|
|
83850
|
-
|
|
83851
|
-
|
|
83852
|
-
|
|
83853
|
-
if (fromMarks || toMarks) {
|
|
83854
|
-
return true;
|
|
83855
|
-
}
|
|
83856
|
-
if (empty2 && markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83857
|
-
return true;
|
|
83858
|
-
}
|
|
83859
|
-
} else {
|
|
83860
|
-
if (empty2) {
|
|
83861
|
-
if (markType.isInSet(state2.storedMarks || $from.marks())) {
|
|
83862
|
-
return true;
|
|
83863
|
-
}
|
|
83864
|
-
} else {
|
|
83865
|
-
let hasMark = false;
|
|
83866
|
-
state2.doc.nodesBetween(from2, to, (node) => {
|
|
83867
|
-
if (markType.isInSet(node.marks)) {
|
|
83868
|
-
hasMark = true;
|
|
83869
|
-
return false;
|
|
83870
|
-
}
|
|
83871
|
-
});
|
|
83872
|
-
if (hasMark) return true;
|
|
83873
|
-
}
|
|
84004
|
+
if (isCollaborationEnabled(editor)) {
|
|
84005
|
+
try {
|
|
84006
|
+
const undoManager = yUndoPluginKey.getState(state2)?.undoManager;
|
|
84007
|
+
return !!undoManager && undoManager.redoStack.length > 0;
|
|
84008
|
+
} catch (error) {
|
|
84009
|
+
console.warn("[SlashMenu] Unable to determine redo availability via y-prosemirror:", error);
|
|
83874
84010
|
}
|
|
83875
84011
|
}
|
|
83876
|
-
|
|
84012
|
+
try {
|
|
84013
|
+
return redoDepth(state2) > 0;
|
|
84014
|
+
} catch (error) {
|
|
84015
|
+
console.warn("[SlashMenu] Unable to determine redo availability via history plugin:", error);
|
|
84016
|
+
return false;
|
|
84017
|
+
}
|
|
83877
84018
|
}
|
|
83878
|
-
function
|
|
83879
|
-
|
|
83880
|
-
|
|
83881
|
-
|
|
83882
|
-
|
|
83883
|
-
const
|
|
83884
|
-
|
|
83885
|
-
|
|
84019
|
+
function isCollaborationEnabled(editor) {
|
|
84020
|
+
return Boolean(editor?.options?.collaborationProvider && editor?.options?.ydoc);
|
|
84021
|
+
}
|
|
84022
|
+
function getStructureFromResolvedPos(state2, pos) {
|
|
84023
|
+
try {
|
|
84024
|
+
const $pos = state2.doc.resolve(pos);
|
|
84025
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
84026
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
84027
|
+
ancestors.add($pos.node(depth).type.name);
|
|
84028
|
+
}
|
|
84029
|
+
const isInList = ancestors.has("bulletList") || ancestors.has("orderedList");
|
|
84030
|
+
const isInTable2 = ancestors.has("table") || ancestors.has("tableRow") || ancestors.has("tableCell") || ancestors.has("tableHeader");
|
|
84031
|
+
const isInSectionNode = ancestors.has("documentSection");
|
|
84032
|
+
return {
|
|
84033
|
+
isInTable: isInTable2,
|
|
84034
|
+
isInList,
|
|
84035
|
+
isInSectionNode
|
|
84036
|
+
};
|
|
84037
|
+
} catch (error) {
|
|
84038
|
+
console.warn("[SlashMenu] Unable to resolve position for structural context:", error);
|
|
84039
|
+
return null;
|
|
83886
84040
|
}
|
|
83887
84041
|
}
|
|
83888
84042
|
const isModuleEnabled = (editorOptions, moduleName) => {
|
|
@@ -83896,8 +84050,52 @@ const isModuleEnabled = (editorOptions, moduleName) => {
|
|
|
83896
84050
|
return true;
|
|
83897
84051
|
}
|
|
83898
84052
|
};
|
|
84053
|
+
function applyCustomMenuConfiguration(defaultSections, context) {
|
|
84054
|
+
const { editor } = context;
|
|
84055
|
+
const slashMenuConfig = editor.options?.slashMenuConfig;
|
|
84056
|
+
if (!slashMenuConfig) {
|
|
84057
|
+
return defaultSections;
|
|
84058
|
+
}
|
|
84059
|
+
let sections = [];
|
|
84060
|
+
if (slashMenuConfig.includeDefaultItems !== false) {
|
|
84061
|
+
sections = [...defaultSections];
|
|
84062
|
+
}
|
|
84063
|
+
if (slashMenuConfig.customItems && Array.isArray(slashMenuConfig.customItems)) {
|
|
84064
|
+
sections = [...sections, ...slashMenuConfig.customItems];
|
|
84065
|
+
}
|
|
84066
|
+
if (typeof slashMenuConfig.menuProvider === "function") {
|
|
84067
|
+
try {
|
|
84068
|
+
sections = slashMenuConfig.menuProvider(context, sections) || sections;
|
|
84069
|
+
} catch (error) {
|
|
84070
|
+
console.warn("[SlashMenu] Error in custom menuProvider:", error);
|
|
84071
|
+
}
|
|
84072
|
+
}
|
|
84073
|
+
return sections;
|
|
84074
|
+
}
|
|
84075
|
+
function filterCustomItems(sections, context) {
|
|
84076
|
+
return sections.map((section) => {
|
|
84077
|
+
const filteredItems = section.items.filter((item) => {
|
|
84078
|
+
if (typeof item.showWhen === "function") {
|
|
84079
|
+
try {
|
|
84080
|
+
return item.showWhen(context);
|
|
84081
|
+
} catch (error) {
|
|
84082
|
+
console.warn(`[SlashMenu] Error in showWhen for item ${item.id}:`, error);
|
|
84083
|
+
return false;
|
|
84084
|
+
}
|
|
84085
|
+
}
|
|
84086
|
+
return true;
|
|
84087
|
+
});
|
|
84088
|
+
return {
|
|
84089
|
+
...section,
|
|
84090
|
+
items: filteredItems
|
|
84091
|
+
};
|
|
84092
|
+
}).filter((section) => section.items.length > 0);
|
|
84093
|
+
}
|
|
83899
84094
|
function getItems(context) {
|
|
83900
84095
|
const { editor, selectedText, trigger: trigger2, clipboardContent } = context;
|
|
84096
|
+
const clipboardHasContent = Boolean(
|
|
84097
|
+
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
|
|
84098
|
+
);
|
|
83901
84099
|
const isInTable2 = selectionHasNodeOrMark(editor.view.state, "table", { requireEnds: true });
|
|
83902
84100
|
const isInSectionNode = selectionHasNodeOrMark(editor.view.state, "documentSection", { requireEnds: true });
|
|
83903
84101
|
const sections = [
|
|
@@ -84034,12 +84232,13 @@ function getItems(context) {
|
|
|
84034
84232
|
]
|
|
84035
84233
|
}
|
|
84036
84234
|
];
|
|
84037
|
-
|
|
84235
|
+
let allSections = applyCustomMenuConfiguration(sections, context);
|
|
84236
|
+
const filteredSections = allSections.map((section) => {
|
|
84038
84237
|
const filteredItems = section.items.filter((item) => {
|
|
84039
84238
|
if (item.requiresModule && !isModuleEnabled(editor?.options, item.requiresModule)) return false;
|
|
84040
84239
|
if (item.requiresSelection && !selectedText) return false;
|
|
84041
84240
|
if (!item.allowedTriggers.includes(trigger2)) return false;
|
|
84042
|
-
if (item.requiresClipboard && !
|
|
84241
|
+
if (item.requiresClipboard && !clipboardHasContent) return false;
|
|
84043
84242
|
if (item.requiresTableParent && !isInTable2 || item.id === "insert-table" && isInTable2) return false;
|
|
84044
84243
|
if (item.requiresSectionParent && !isInSectionNode) return false;
|
|
84045
84244
|
return true;
|
|
@@ -84049,7 +84248,8 @@ function getItems(context) {
|
|
|
84049
84248
|
items: filteredItems
|
|
84050
84249
|
};
|
|
84051
84250
|
}).filter((section) => section.items.length > 0);
|
|
84052
|
-
|
|
84251
|
+
const finalSections = filterCustomItems(filteredSections, context);
|
|
84252
|
+
return finalSections;
|
|
84053
84253
|
}
|
|
84054
84254
|
const _hoisted_1$3 = { class: "slash-menu-items" };
|
|
84055
84255
|
const _hoisted_2$1 = {
|
|
@@ -84084,6 +84284,7 @@ const _sfc_main$4 = {
|
|
|
84084
84284
|
const menuRef = ref$1(null);
|
|
84085
84285
|
const sections = ref$1([]);
|
|
84086
84286
|
const selectedId = ref$1(null);
|
|
84287
|
+
const currentContext = ref$1(null);
|
|
84087
84288
|
const handleEditorUpdate = () => {
|
|
84088
84289
|
if (!props.editor?.isEditable && isOpen.value) {
|
|
84089
84290
|
closeMenu({ restoreCursor: false });
|
|
@@ -84129,6 +84330,44 @@ const _sfc_main$4 = {
|
|
|
84129
84330
|
selectedId.value = newItems[0].id;
|
|
84130
84331
|
}
|
|
84131
84332
|
});
|
|
84333
|
+
const customItemRefs = /* @__PURE__ */ new Map();
|
|
84334
|
+
const setCustomItemRef = (el, item) => {
|
|
84335
|
+
if (el && item.render) {
|
|
84336
|
+
customItemRefs.set(item.id, { element: el, item });
|
|
84337
|
+
nextTick(() => {
|
|
84338
|
+
renderCustomItem(item.id);
|
|
84339
|
+
});
|
|
84340
|
+
}
|
|
84341
|
+
};
|
|
84342
|
+
const renderCustomItem = async (itemId) => {
|
|
84343
|
+
const refData = customItemRefs.get(itemId);
|
|
84344
|
+
if (!refData || refData.element.hasCustomContent) return;
|
|
84345
|
+
const { element, item } = refData;
|
|
84346
|
+
try {
|
|
84347
|
+
if (!currentContext.value) {
|
|
84348
|
+
currentContext.value = await getEditorContext(props.editor);
|
|
84349
|
+
}
|
|
84350
|
+
const context = currentContext.value;
|
|
84351
|
+
const customElement = item.render(context);
|
|
84352
|
+
if (customElement instanceof HTMLElement) {
|
|
84353
|
+
element.innerHTML = "";
|
|
84354
|
+
element.appendChild(customElement);
|
|
84355
|
+
element.hasCustomContent = true;
|
|
84356
|
+
}
|
|
84357
|
+
} catch (error) {
|
|
84358
|
+
console.warn(`[SlashMenu] Error rendering custom item ${itemId}:`, error);
|
|
84359
|
+
element.innerHTML = `<span>${item.label || "Custom Item"}</span>`;
|
|
84360
|
+
element.hasCustomContent = true;
|
|
84361
|
+
}
|
|
84362
|
+
};
|
|
84363
|
+
const cleanupCustomItems = () => {
|
|
84364
|
+
customItemRefs.forEach((refData) => {
|
|
84365
|
+
if (refData.element) {
|
|
84366
|
+
refData.element.hasCustomContent = false;
|
|
84367
|
+
}
|
|
84368
|
+
});
|
|
84369
|
+
customItemRefs.clear();
|
|
84370
|
+
};
|
|
84132
84371
|
const handleGlobalKeyDown = (event) => {
|
|
84133
84372
|
if (event.key === "Escape") {
|
|
84134
84373
|
event.preventDefault();
|
|
@@ -84179,22 +84418,23 @@ const _sfc_main$4 = {
|
|
|
84179
84418
|
return;
|
|
84180
84419
|
}
|
|
84181
84420
|
event.preventDefault();
|
|
84421
|
+
const context = await getEditorContext(props.editor, event);
|
|
84422
|
+
currentContext.value = context;
|
|
84423
|
+
sections.value = getItems({ ...context, trigger: "click" });
|
|
84424
|
+
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84425
|
+
searchQuery.value = "";
|
|
84182
84426
|
props.editor.view.dispatch(
|
|
84183
84427
|
props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
84184
84428
|
type: "open",
|
|
84185
|
-
pos: props.editor.view.state.selection.from,
|
|
84429
|
+
pos: context?.pos ?? props.editor.view.state.selection.from,
|
|
84186
84430
|
clientX: event.clientX,
|
|
84187
84431
|
clientY: event.clientY
|
|
84188
84432
|
})
|
|
84189
84433
|
);
|
|
84190
|
-
searchQuery.value = "";
|
|
84191
|
-
const context = await getEditorContext(props.editor, event);
|
|
84192
|
-
sections.value = getItems({ ...context, trigger: "click" });
|
|
84193
|
-
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84194
84434
|
};
|
|
84195
84435
|
const executeCommand = async (item) => {
|
|
84196
84436
|
if (props.editor) {
|
|
84197
|
-
item.action ? await item.action(props.editor) : null;
|
|
84437
|
+
item.action ? await item.action(props.editor, currentContext.value) : null;
|
|
84198
84438
|
if (item.component) {
|
|
84199
84439
|
menuRef.value;
|
|
84200
84440
|
const componentProps = getPropsByItemId(item.id, props);
|
|
@@ -84212,7 +84452,7 @@ const _sfc_main$4 = {
|
|
|
84212
84452
|
const closeMenu = (options = { restoreCursor: true }) => {
|
|
84213
84453
|
if (props.editor?.view) {
|
|
84214
84454
|
const pluginState = SlashMenuPluginKey.getState(props.editor.view.state);
|
|
84215
|
-
const
|
|
84455
|
+
const anchorPos = pluginState?.anchorPos;
|
|
84216
84456
|
props.editor.view.dispatch(
|
|
84217
84457
|
props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
|
|
84218
84458
|
type: "close"
|
|
@@ -84225,6 +84465,8 @@ const _sfc_main$4 = {
|
|
|
84225
84465
|
props.editor.view.dispatch(tr);
|
|
84226
84466
|
props.editor.view.focus();
|
|
84227
84467
|
}
|
|
84468
|
+
cleanupCustomItems();
|
|
84469
|
+
currentContext.value = null;
|
|
84228
84470
|
isOpen.value = false;
|
|
84229
84471
|
searchQuery.value = "";
|
|
84230
84472
|
sections.value = [];
|
|
@@ -84241,19 +84483,29 @@ const _sfc_main$4 = {
|
|
|
84241
84483
|
isOpen.value = true;
|
|
84242
84484
|
menuPosition.value = event.menuPosition;
|
|
84243
84485
|
searchQuery.value = "";
|
|
84244
|
-
|
|
84245
|
-
|
|
84246
|
-
|
|
84486
|
+
if (!currentContext.value) {
|
|
84487
|
+
const context = await getEditorContext(props.editor);
|
|
84488
|
+
currentContext.value = context;
|
|
84489
|
+
sections.value = getItems({ ...context, trigger: "slash" });
|
|
84490
|
+
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84491
|
+
} else if (sections.value.length === 0) {
|
|
84492
|
+
const trigger2 = currentContext.value.event?.type === "contextmenu" ? "click" : "slash";
|
|
84493
|
+
sections.value = getItems({ ...currentContext.value, trigger: trigger2 });
|
|
84494
|
+
selectedId.value = flattenedItems.value[0]?.id || null;
|
|
84495
|
+
}
|
|
84247
84496
|
});
|
|
84248
84497
|
props.editor.view.dom.addEventListener("contextmenu", handleRightClick);
|
|
84249
84498
|
props.editor.on("slashMenu:close", () => {
|
|
84499
|
+
cleanupCustomItems();
|
|
84250
84500
|
isOpen.value = false;
|
|
84251
84501
|
searchQuery.value = "";
|
|
84502
|
+
currentContext.value = null;
|
|
84252
84503
|
});
|
|
84253
84504
|
});
|
|
84254
84505
|
onBeforeUnmount(() => {
|
|
84255
84506
|
document.removeEventListener("keydown", handleGlobalKeyDown);
|
|
84256
84507
|
document.removeEventListener("mousedown", handleGlobalOutsideClick);
|
|
84508
|
+
cleanupCustomItems();
|
|
84257
84509
|
if (props.editor) {
|
|
84258
84510
|
try {
|
|
84259
84511
|
props.editor.off("slashMenu:open");
|
|
@@ -84300,12 +84552,19 @@ const _sfc_main$4 = {
|
|
|
84300
84552
|
class: normalizeClass(["slash-menu-item", { "is-selected": item.id === selectedId.value }]),
|
|
84301
84553
|
onClick: ($event) => executeCommand(item)
|
|
84302
84554
|
}, [
|
|
84303
|
-
item.
|
|
84555
|
+
item.render ? (openBlock(), createElementBlock("div", {
|
|
84304
84556
|
key: 0,
|
|
84305
|
-
|
|
84306
|
-
|
|
84307
|
-
|
|
84308
|
-
|
|
84557
|
+
ref_for: true,
|
|
84558
|
+
ref: (el) => setCustomItemRef(el, item),
|
|
84559
|
+
class: "slash-menu-custom-item"
|
|
84560
|
+
}, null, 512)) : (openBlock(), createElementBlock(Fragment$1, { key: 1 }, [
|
|
84561
|
+
item.icon ? (openBlock(), createElementBlock("span", {
|
|
84562
|
+
key: 0,
|
|
84563
|
+
class: "slash-menu-item-icon",
|
|
84564
|
+
innerHTML: item.icon
|
|
84565
|
+
}, null, 8, _hoisted_4)) : createCommentVNode("", true),
|
|
84566
|
+
createBaseVNode("span", null, toDisplayString(item.label), 1)
|
|
84567
|
+
], 64))
|
|
84309
84568
|
], 10, _hoisted_3$1);
|
|
84310
84569
|
}), 128))
|
|
84311
84570
|
], 64);
|
|
@@ -90,6 +90,14 @@ export type Modules = {
|
|
|
90
90
|
* Toolbar module configuration
|
|
91
91
|
*/
|
|
92
92
|
toolbar?: any;
|
|
93
|
+
/**
|
|
94
|
+
* Slash menu module configuration
|
|
95
|
+
*/
|
|
96
|
+
slashMenu?: {
|
|
97
|
+
customItems?: any[];
|
|
98
|
+
menuProvider?: Function;
|
|
99
|
+
includeDefaultItems?: boolean;
|
|
100
|
+
};
|
|
93
101
|
};
|
|
94
102
|
export type Editor = {
|
|
95
103
|
setHighContrastMode: (value: any) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/types/index.js"],"names":[],"mappings":";;;;;;;UAEc,MAAM;;;;WACN,MAAM;;;;YACN,MAAM,GAAG,IAAI;;;;;;;;;cAKb,OAAO;;;;iBACP,MAAM;;;;eACN,MAAM;;;;sBACN,MAAM;;;;;;SAKN,MAAM;;;;UACN,MAAM;;;;WACN,IAAI,GAAG,IAAI,GAAG,IAAI;;;;WAClB,MAAM;;;;UACN,MAAM;;;;gBACN,OAAO;;;;WACP,OAAO,KAAK,EAAE,GAAG;;;;eACjB,OAAO,sBAAsB,EAAE,kBAAkB;;;;;;;;;;SAO5D;QAAuB,MAAM,GAAlB,MAAM;QACM,QAAQ,GAApB,MAAM;KACjB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/types/index.js"],"names":[],"mappings":";;;;;;;UAEc,MAAM;;;;WACN,MAAM;;;;YACN,MAAM,GAAG,IAAI;;;;;;;;;cAKb,OAAO;;;;iBACP,MAAM;;;;eACN,MAAM;;;;sBACN,MAAM;;;;;;SAKN,MAAM;;;;UACN,MAAM;;;;WACN,IAAI,GAAG,IAAI,GAAG,IAAI;;;;WAClB,MAAM;;;;UACN,MAAM;;;;gBACN,OAAO;;;;WACP,OAAO,KAAK,EAAE,GAAG;;;;eACjB,OAAO,sBAAsB,EAAE,kBAAkB;;;;;;;;;;SAO5D;QAAuB,MAAM,GAAlB,MAAM;QACM,QAAQ,GAApB,MAAM;KACjB;;;;;;;;;;;;gBAGA;QAA6B,WAAW;QACR,YAAY;QACb,mBAAmB,GAAvC,OAAO;KACpB;;;;;;;;;;;;;;sBAiEmo/e,aAAa;;;;;;;;;;;yBAA8vJ,aAAa;;;;;;;;;;;;;;;;+BAAu2U,aAAa;sBAAh8nB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;6CAAst+B,UAAU;8CAAuV,UAAU,aAA+E,UAAU;gCAAgZ,UAAU;;;;;;;;;;uBA9Dn41gB,OAAO,gBAAgB,EAAE,QAAQ;2BAGlC,MAAM;;;;;iBAQL,MAAM;;;;cACN,MAAM;;;;kBACN,YAAY;;;;WACZ,QAAQ,GAAG,QAAQ,GAAG,WAAW;;;;eACjC,MAAS,MAAM,GAAG,IAAI,GAAG,IAAI;;;;eAC7B,KAAK,CAAC,QAAQ,CAAC;;;;WACf,IAAI;;;;YACJ,KAAK,CAAC,IAAI,CAAC;;;;aACX,KAAK,CAAC,MAAM,CAAC;;;;cACb,OAAO;;;;iBACP,OAAO;;;;cACP,MAAM;;;;oBACN,KAAK,CAAC,MAAM,CAAC;;;;;;;;;;;;YAGb,OAAO;;;;gBACP,eAAe;;;;2BACf,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI;;;;qBACxB,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI;;;;oBACxB,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,GAAG,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;;;;sBACxE,MAAM,IAAI;;;;qBACV,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI;;;;cACnF,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAA;KAAE,KAAK,IAAI;;;;uBACxC,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,KAAK,IAAI;;;;wBAC/C,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,QAAQ,CAAC;QAAC,MAAM,QAAO;KAAE,KAAK,IAAI;;;;eACtD,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI;;;;yBACvD,MAAM,IAAI;;;;sBACV,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI;;;;2BAC3B,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;;;;qBACpC,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;;;;kBACpC,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI;;;;2BAClC,CAAC,MAAM,EAAE;QAAE,UAAU,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI;;;;8BACzC,CAAC,MAAM,EAAE,EAAE,KAAC,GAAA;;;;aACZ,MAAM;;;;uBACN,KAAQ;;;;iBACR,OAAO;;;;YACP,MAAM;;;;oBACN,KAAQ;;;;eACR,OAAO;;;;wBACP,CAAS,IAAI,EAAJ,IAAI,KAAG,OAAO,CAAC,MAAM,CAAC;;;;eAC/B,IAAI;;;;aACJ,OAAO;;;;gCACP,OAAO;;;;;;;;yBAEP,OAAO;;;;WACP,MAAM;;;;eACN,MAAM;;;;cACN,OAAO"}
|