@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.
@@ -91267,6 +91267,115 @@ ${style2}
91267
91267
  this.updateToolbarState();
91268
91268
  }
91269
91269
  };
91270
+ const onMarginClickCursorChange = (event, editor) => {
91271
+ const y2 = event.clientY;
91272
+ const x = event.clientX;
91273
+ const { view } = editor;
91274
+ const editorRect = view.dom.getBoundingClientRect();
91275
+ let coords = {
91276
+ left: 0,
91277
+ top: y2
91278
+ };
91279
+ let isRightMargin = false;
91280
+ if (x > editorRect.right) {
91281
+ coords.left = editorRect.left + editorRect.width - 1;
91282
+ isRightMargin = true;
91283
+ } else if (x < editorRect.left) {
91284
+ coords.left = editorRect.left;
91285
+ }
91286
+ const pos = view.posAtCoords(coords)?.pos;
91287
+ if (pos) {
91288
+ let cursorPos = pos;
91289
+ if (isRightMargin) {
91290
+ const $pos = view.state.doc.resolve(pos);
91291
+ const charOffset = $pos.textOffset;
91292
+ const node = view.state.doc.nodeAt(pos);
91293
+ const text = node?.text;
91294
+ const charAtPos = text?.charAt(charOffset);
91295
+ cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
91296
+ }
91297
+ const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
91298
+ view.dispatch(transaction);
91299
+ view.focus();
91300
+ }
91301
+ };
91302
+ const checkNodeSpecificClicks = (editor, event, popoverControls) => {
91303
+ if (!editor) return;
91304
+ if (selectionHasNodeOrMark(editor.view.state, "link", { requireEnds: true })) {
91305
+ popoverControls.component = LinkInput;
91306
+ popoverControls.position = {
91307
+ left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
91308
+ top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
91309
+ };
91310
+ popoverControls.props = {
91311
+ showInput: true
91312
+ };
91313
+ popoverControls.visible = true;
91314
+ }
91315
+ };
91316
+ function selectionHasNodeOrMark(state2, name, options = {}) {
91317
+ const { requireEnds = false } = options;
91318
+ const $from = state2.selection.$from;
91319
+ const $to = state2.selection.$to;
91320
+ if (requireEnds) {
91321
+ for (let d2 = $from.depth; d2 > 0; d2--) {
91322
+ if ($from.node(d2).type.name === name) {
91323
+ return true;
91324
+ }
91325
+ }
91326
+ for (let d2 = $to.depth; d2 > 0; d2--) {
91327
+ if ($to.node(d2).type.name === name) {
91328
+ return true;
91329
+ }
91330
+ }
91331
+ } else {
91332
+ for (let d2 = $from.depth; d2 > 0; d2--) {
91333
+ if ($from.node(d2).type.name === name) {
91334
+ return true;
91335
+ }
91336
+ }
91337
+ }
91338
+ const markType = state2.schema.marks[name];
91339
+ if (markType) {
91340
+ const { from: from2, to, empty: empty2 } = state2.selection;
91341
+ if (requireEnds) {
91342
+ const fromMarks = markType.isInSet($from.marks());
91343
+ const toMarks = markType.isInSet($to.marks());
91344
+ if (fromMarks || toMarks) {
91345
+ return true;
91346
+ }
91347
+ if (empty2 && markType.isInSet(state2.storedMarks || $from.marks())) {
91348
+ return true;
91349
+ }
91350
+ } else {
91351
+ if (empty2) {
91352
+ if (markType.isInSet(state2.storedMarks || $from.marks())) {
91353
+ return true;
91354
+ }
91355
+ } else {
91356
+ let hasMark = false;
91357
+ state2.doc.nodesBetween(from2, to, (node) => {
91358
+ if (markType.isInSet(node.marks)) {
91359
+ hasMark = true;
91360
+ return false;
91361
+ }
91362
+ });
91363
+ if (hasMark) return true;
91364
+ }
91365
+ }
91366
+ }
91367
+ return false;
91368
+ }
91369
+ function moveCursorToMouseEvent(event, editor) {
91370
+ const { view } = editor;
91371
+ const coords = { left: event.clientX, top: event.clientY };
91372
+ const pos = view.posAtCoords(coords)?.pos;
91373
+ if (typeof pos === "number") {
91374
+ const tr = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, pos));
91375
+ view.dispatch(tr);
91376
+ view.focus();
91377
+ }
91378
+ }
91270
91379
  const ICONS = {
91271
91380
  addRowBefore: plusIconSvg,
91272
91381
  addRowAfter: plusIconSvg,
@@ -91466,6 +91575,30 @@ ${style2}
91466
91575
  return baseProps;
91467
91576
  }
91468
91577
  };
91578
+ function normalizeClipboardContent(rawClipboardContent) {
91579
+ if (!rawClipboardContent) {
91580
+ return {
91581
+ html: null,
91582
+ text: null,
91583
+ hasContent: false,
91584
+ raw: null
91585
+ };
91586
+ }
91587
+ const html = typeof rawClipboardContent.html === "string" ? rawClipboardContent.html : null;
91588
+ const text = typeof rawClipboardContent.text === "string" ? rawClipboardContent.text : null;
91589
+ const hasHtml = !!html && html.trim().length > 0;
91590
+ const hasText = !!text && text.length > 0;
91591
+ const isObject2 = typeof rawClipboardContent === "object" && rawClipboardContent !== null;
91592
+ const fragmentSize = typeof rawClipboardContent.size === "number" ? rawClipboardContent.size : null;
91593
+ const nestedSize = isObject2 && rawClipboardContent.content && typeof rawClipboardContent.content.size === "number" ? rawClipboardContent.content.size : null;
91594
+ const hasFragmentContent = (fragmentSize ?? nestedSize ?? 0) > 0;
91595
+ return {
91596
+ html,
91597
+ text,
91598
+ hasContent: hasHtml || hasText || hasFragmentContent,
91599
+ raw: rawClipboardContent
91600
+ };
91601
+ }
91469
91602
  async function getEditorContext(editor, event) {
91470
91603
  const { view } = editor;
91471
91604
  const { state: state2 } = view;
@@ -91481,123 +91614,144 @@ ${style2}
91481
91614
  pos = from2;
91482
91615
  node = state2.doc.nodeAt(pos);
91483
91616
  }
91484
- const clipboardContent = await readFromClipboard(state2);
91617
+ const rawClipboardContent = await readFromClipboard(state2);
91618
+ const clipboardContent = normalizeClipboardContent(rawClipboardContent);
91619
+ const structureFromResolvedPos = pos !== null ? getStructureFromResolvedPos(state2, pos) : null;
91620
+ const isInTable2 = structureFromResolvedPos?.isInTable ?? selectionHasNodeOrMark(state2, "table", { requireEnds: true });
91621
+ const isInList = structureFromResolvedPos?.isInList ?? (selectionHasNodeOrMark(state2, "bulletList", { requireEnds: false }) || selectionHasNodeOrMark(state2, "orderedList", { requireEnds: false }));
91622
+ const isInSectionNode = structureFromResolvedPos?.isInSectionNode ?? selectionHasNodeOrMark(state2, "documentSection", { requireEnds: true });
91623
+ const currentNodeType = node?.type?.name || null;
91624
+ const activeMarks = [];
91625
+ if (event && pos !== null) {
91626
+ const $pos = state2.doc.resolve(pos);
91627
+ if ($pos.marks && typeof $pos.marks === "function") {
91628
+ $pos.marks().forEach((mark) => activeMarks.push(mark.type.name));
91629
+ }
91630
+ if (node && node.marks) {
91631
+ node.marks.forEach((mark) => activeMarks.push(mark.type.name));
91632
+ }
91633
+ } else {
91634
+ state2.storedMarks?.forEach((mark) => activeMarks.push(mark.type.name));
91635
+ state2.selection.$head.marks().forEach((mark) => activeMarks.push(mark.type.name));
91636
+ }
91637
+ const isTrackedChange = activeMarks.includes("trackInsert") || activeMarks.includes("trackDelete");
91638
+ let trackedChangeId = null;
91639
+ if (isTrackedChange && event && pos !== null) {
91640
+ const $pos = state2.doc.resolve(pos);
91641
+ const marksAtPos = $pos.marks();
91642
+ const trackedMark = marksAtPos.find((mark) => mark.type.name === "trackInsert" || mark.type.name === "trackDelete");
91643
+ if (trackedMark) {
91644
+ trackedChangeId = trackedMark.attrs.id;
91645
+ }
91646
+ }
91647
+ const cursorCoords = pos ? view.coordsAtPos(pos) : null;
91648
+ const cursorPosition = cursorCoords ? {
91649
+ x: cursorCoords.left,
91650
+ y: cursorCoords.top
91651
+ } : null;
91485
91652
  return {
91486
- editor,
91653
+ // Selection info
91487
91654
  selectedText,
91655
+ hasSelection: !empty2,
91656
+ selectionStart: from2,
91657
+ selectionEnd: to,
91658
+ // Document structure
91659
+ isInTable: isInTable2,
91660
+ isInList,
91661
+ isInSectionNode,
91662
+ currentNodeType,
91663
+ activeMarks,
91664
+ // Document state
91665
+ isTrackedChange,
91666
+ trackedChangeId,
91667
+ documentMode: editor.options?.documentMode || "editing",
91668
+ canUndo: computeCanUndo(editor, state2),
91669
+ canRedo: computeCanRedo(editor, state2),
91670
+ isEditable: editor.isEditable,
91671
+ // Clipboard
91672
+ clipboardContent,
91673
+ // Position and trigger info
91674
+ cursorPosition,
91488
91675
  pos,
91489
91676
  node,
91490
91677
  event,
91491
- clipboardContent
91678
+ // Editor reference for advanced use cases
91679
+ editor
91492
91680
  };
91493
91681
  }
91494
- const onMarginClickCursorChange = (event, editor) => {
91495
- const y2 = event.clientY;
91496
- const x = event.clientX;
91497
- const { view } = editor;
91498
- const editorRect = view.dom.getBoundingClientRect();
91499
- let coords = {
91500
- left: 0,
91501
- top: y2
91502
- };
91503
- let isRightMargin = false;
91504
- if (x > editorRect.right) {
91505
- coords.left = editorRect.left + editorRect.width - 1;
91506
- isRightMargin = true;
91507
- } else if (x < editorRect.left) {
91508
- coords.left = editorRect.left;
91682
+ function computeCanUndo(editor, state2) {
91683
+ if (typeof editor?.can === "function") {
91684
+ try {
91685
+ const can = editor.can();
91686
+ if (can && typeof can.undo === "function") {
91687
+ return !!can.undo();
91688
+ }
91689
+ } catch (error) {
91690
+ console.warn("[SlashMenu] Unable to determine undo availability via editor.can():", error);
91691
+ }
91509
91692
  }
91510
- const pos = view.posAtCoords(coords)?.pos;
91511
- if (pos) {
91512
- let cursorPos = pos;
91513
- if (isRightMargin) {
91514
- const $pos = view.state.doc.resolve(pos);
91515
- const charOffset = $pos.textOffset;
91516
- const node = view.state.doc.nodeAt(pos);
91517
- const text = node?.text;
91518
- const charAtPos = text?.charAt(charOffset);
91519
- cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
91693
+ if (isCollaborationEnabled(editor)) {
91694
+ try {
91695
+ const undoManager = yUndoPluginKey.getState(state2)?.undoManager;
91696
+ return !!undoManager && undoManager.undoStack.length > 0;
91697
+ } catch (error) {
91698
+ console.warn("[SlashMenu] Unable to determine undo availability via y-prosemirror:", error);
91520
91699
  }
91521
- const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
91522
- view.dispatch(transaction);
91523
- view.focus();
91524
91700
  }
91525
- };
91526
- const checkNodeSpecificClicks = (editor, event, popoverControls) => {
91527
- if (!editor) return;
91528
- if (selectionHasNodeOrMark(editor.view.state, "link", { requireEnds: true })) {
91529
- popoverControls.component = LinkInput;
91530
- popoverControls.position = {
91531
- left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
91532
- top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
91533
- };
91534
- popoverControls.props = {
91535
- showInput: true
91536
- };
91537
- popoverControls.visible = true;
91701
+ try {
91702
+ return undoDepth(state2) > 0;
91703
+ } catch (error) {
91704
+ console.warn("[SlashMenu] Unable to determine undo availability via history plugin:", error);
91705
+ return false;
91538
91706
  }
91539
- };
91540
- function selectionHasNodeOrMark(state2, name, options = {}) {
91541
- const { requireEnds = false } = options;
91542
- const $from = state2.selection.$from;
91543
- const $to = state2.selection.$to;
91544
- if (requireEnds) {
91545
- for (let d2 = $from.depth; d2 > 0; d2--) {
91546
- if ($from.node(d2).type.name === name) {
91547
- return true;
91548
- }
91549
- }
91550
- for (let d2 = $to.depth; d2 > 0; d2--) {
91551
- if ($to.node(d2).type.name === name) {
91552
- return true;
91553
- }
91554
- }
91555
- } else {
91556
- for (let d2 = $from.depth; d2 > 0; d2--) {
91557
- if ($from.node(d2).type.name === name) {
91558
- return true;
91707
+ }
91708
+ function computeCanRedo(editor, state2) {
91709
+ if (typeof editor?.can === "function") {
91710
+ try {
91711
+ const can = editor.can();
91712
+ if (can && typeof can.redo === "function") {
91713
+ return !!can.redo();
91559
91714
  }
91715
+ } catch (error) {
91716
+ console.warn("[SlashMenu] Unable to determine redo availability via editor.can():", error);
91560
91717
  }
91561
91718
  }
91562
- const markType = state2.schema.marks[name];
91563
- if (markType) {
91564
- const { from: from2, to, empty: empty2 } = state2.selection;
91565
- if (requireEnds) {
91566
- const fromMarks = markType.isInSet($from.marks());
91567
- const toMarks = markType.isInSet($to.marks());
91568
- if (fromMarks || toMarks) {
91569
- return true;
91570
- }
91571
- if (empty2 && markType.isInSet(state2.storedMarks || $from.marks())) {
91572
- return true;
91573
- }
91574
- } else {
91575
- if (empty2) {
91576
- if (markType.isInSet(state2.storedMarks || $from.marks())) {
91577
- return true;
91578
- }
91579
- } else {
91580
- let hasMark = false;
91581
- state2.doc.nodesBetween(from2, to, (node) => {
91582
- if (markType.isInSet(node.marks)) {
91583
- hasMark = true;
91584
- return false;
91585
- }
91586
- });
91587
- if (hasMark) return true;
91588
- }
91719
+ if (isCollaborationEnabled(editor)) {
91720
+ try {
91721
+ const undoManager = yUndoPluginKey.getState(state2)?.undoManager;
91722
+ return !!undoManager && undoManager.redoStack.length > 0;
91723
+ } catch (error) {
91724
+ console.warn("[SlashMenu] Unable to determine redo availability via y-prosemirror:", error);
91589
91725
  }
91590
91726
  }
91591
- return false;
91727
+ try {
91728
+ return redoDepth(state2) > 0;
91729
+ } catch (error) {
91730
+ console.warn("[SlashMenu] Unable to determine redo availability via history plugin:", error);
91731
+ return false;
91732
+ }
91592
91733
  }
91593
- function moveCursorToMouseEvent(event, editor) {
91594
- const { view } = editor;
91595
- const coords = { left: event.clientX, top: event.clientY };
91596
- const pos = view.posAtCoords(coords)?.pos;
91597
- if (typeof pos === "number") {
91598
- const tr = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, pos));
91599
- view.dispatch(tr);
91600
- view.focus();
91734
+ function isCollaborationEnabled(editor) {
91735
+ return Boolean(editor?.options?.collaborationProvider && editor?.options?.ydoc);
91736
+ }
91737
+ function getStructureFromResolvedPos(state2, pos) {
91738
+ try {
91739
+ const $pos = state2.doc.resolve(pos);
91740
+ const ancestors = /* @__PURE__ */ new Set();
91741
+ for (let depth = $pos.depth; depth > 0; depth--) {
91742
+ ancestors.add($pos.node(depth).type.name);
91743
+ }
91744
+ const isInList = ancestors.has("bulletList") || ancestors.has("orderedList");
91745
+ const isInTable2 = ancestors.has("table") || ancestors.has("tableRow") || ancestors.has("tableCell") || ancestors.has("tableHeader");
91746
+ const isInSectionNode = ancestors.has("documentSection");
91747
+ return {
91748
+ isInTable: isInTable2,
91749
+ isInList,
91750
+ isInSectionNode
91751
+ };
91752
+ } catch (error) {
91753
+ console.warn("[SlashMenu] Unable to resolve position for structural context:", error);
91754
+ return null;
91601
91755
  }
91602
91756
  }
91603
91757
  const isModuleEnabled = (editorOptions, moduleName) => {
@@ -91611,8 +91765,52 @@ ${style2}
91611
91765
  return true;
91612
91766
  }
91613
91767
  };
91768
+ function applyCustomMenuConfiguration(defaultSections, context) {
91769
+ const { editor } = context;
91770
+ const slashMenuConfig = editor.options?.slashMenuConfig;
91771
+ if (!slashMenuConfig) {
91772
+ return defaultSections;
91773
+ }
91774
+ let sections = [];
91775
+ if (slashMenuConfig.includeDefaultItems !== false) {
91776
+ sections = [...defaultSections];
91777
+ }
91778
+ if (slashMenuConfig.customItems && Array.isArray(slashMenuConfig.customItems)) {
91779
+ sections = [...sections, ...slashMenuConfig.customItems];
91780
+ }
91781
+ if (typeof slashMenuConfig.menuProvider === "function") {
91782
+ try {
91783
+ sections = slashMenuConfig.menuProvider(context, sections) || sections;
91784
+ } catch (error) {
91785
+ console.warn("[SlashMenu] Error in custom menuProvider:", error);
91786
+ }
91787
+ }
91788
+ return sections;
91789
+ }
91790
+ function filterCustomItems(sections, context) {
91791
+ return sections.map((section) => {
91792
+ const filteredItems = section.items.filter((item) => {
91793
+ if (typeof item.showWhen === "function") {
91794
+ try {
91795
+ return item.showWhen(context);
91796
+ } catch (error) {
91797
+ console.warn(`[SlashMenu] Error in showWhen for item ${item.id}:`, error);
91798
+ return false;
91799
+ }
91800
+ }
91801
+ return true;
91802
+ });
91803
+ return {
91804
+ ...section,
91805
+ items: filteredItems
91806
+ };
91807
+ }).filter((section) => section.items.length > 0);
91808
+ }
91614
91809
  function getItems(context) {
91615
91810
  const { editor, selectedText, trigger: trigger2, clipboardContent } = context;
91811
+ const clipboardHasContent = Boolean(
91812
+ 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
91813
+ );
91616
91814
  const isInTable2 = selectionHasNodeOrMark(editor.view.state, "table", { requireEnds: true });
91617
91815
  const isInSectionNode = selectionHasNodeOrMark(editor.view.state, "documentSection", { requireEnds: true });
91618
91816
  const sections = [
@@ -91749,12 +91947,13 @@ ${style2}
91749
91947
  ]
91750
91948
  }
91751
91949
  ];
91752
- const filteredSections = sections.map((section) => {
91950
+ let allSections = applyCustomMenuConfiguration(sections, context);
91951
+ const filteredSections = allSections.map((section) => {
91753
91952
  const filteredItems = section.items.filter((item) => {
91754
91953
  if (item.requiresModule && !isModuleEnabled(editor?.options, item.requiresModule)) return false;
91755
91954
  if (item.requiresSelection && !selectedText) return false;
91756
91955
  if (!item.allowedTriggers.includes(trigger2)) return false;
91757
- if (item.requiresClipboard && !clipboardContent) return false;
91956
+ if (item.requiresClipboard && !clipboardHasContent) return false;
91758
91957
  if (item.requiresTableParent && !isInTable2 || item.id === "insert-table" && isInTable2) return false;
91759
91958
  if (item.requiresSectionParent && !isInSectionNode) return false;
91760
91959
  return true;
@@ -91764,7 +91963,8 @@ ${style2}
91764
91963
  items: filteredItems
91765
91964
  };
91766
91965
  }).filter((section) => section.items.length > 0);
91767
- return filteredSections;
91966
+ const finalSections = filterCustomItems(filteredSections, context);
91967
+ return finalSections;
91768
91968
  }
91769
91969
  const _hoisted_1$3$1 = { class: "slash-menu-items" };
91770
91970
  const _hoisted_2$1$1 = {
@@ -91799,6 +91999,7 @@ ${style2}
91799
91999
  const menuRef = ref$1(null);
91800
92000
  const sections = ref$1([]);
91801
92001
  const selectedId = ref$1(null);
92002
+ const currentContext = ref$1(null);
91802
92003
  const handleEditorUpdate = () => {
91803
92004
  if (!props.editor?.isEditable && isOpen.value) {
91804
92005
  closeMenu({ restoreCursor: false });
@@ -91844,6 +92045,44 @@ ${style2}
91844
92045
  selectedId.value = newItems[0].id;
91845
92046
  }
91846
92047
  });
92048
+ const customItemRefs = /* @__PURE__ */ new Map();
92049
+ const setCustomItemRef = (el, item) => {
92050
+ if (el && item.render) {
92051
+ customItemRefs.set(item.id, { element: el, item });
92052
+ nextTick(() => {
92053
+ renderCustomItem(item.id);
92054
+ });
92055
+ }
92056
+ };
92057
+ const renderCustomItem = async (itemId) => {
92058
+ const refData = customItemRefs.get(itemId);
92059
+ if (!refData || refData.element.hasCustomContent) return;
92060
+ const { element, item } = refData;
92061
+ try {
92062
+ if (!currentContext.value) {
92063
+ currentContext.value = await getEditorContext(props.editor);
92064
+ }
92065
+ const context = currentContext.value;
92066
+ const customElement = item.render(context);
92067
+ if (customElement instanceof HTMLElement) {
92068
+ element.innerHTML = "";
92069
+ element.appendChild(customElement);
92070
+ element.hasCustomContent = true;
92071
+ }
92072
+ } catch (error) {
92073
+ console.warn(`[SlashMenu] Error rendering custom item ${itemId}:`, error);
92074
+ element.innerHTML = `<span>${item.label || "Custom Item"}</span>`;
92075
+ element.hasCustomContent = true;
92076
+ }
92077
+ };
92078
+ const cleanupCustomItems = () => {
92079
+ customItemRefs.forEach((refData) => {
92080
+ if (refData.element) {
92081
+ refData.element.hasCustomContent = false;
92082
+ }
92083
+ });
92084
+ customItemRefs.clear();
92085
+ };
91847
92086
  const handleGlobalKeyDown = (event) => {
91848
92087
  if (event.key === "Escape") {
91849
92088
  event.preventDefault();
@@ -91894,22 +92133,23 @@ ${style2}
91894
92133
  return;
91895
92134
  }
91896
92135
  event.preventDefault();
92136
+ const context = await getEditorContext(props.editor, event);
92137
+ currentContext.value = context;
92138
+ sections.value = getItems({ ...context, trigger: "click" });
92139
+ selectedId.value = flattenedItems.value[0]?.id || null;
92140
+ searchQuery.value = "";
91897
92141
  props.editor.view.dispatch(
91898
92142
  props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
91899
92143
  type: "open",
91900
- pos: props.editor.view.state.selection.from,
92144
+ pos: context?.pos ?? props.editor.view.state.selection.from,
91901
92145
  clientX: event.clientX,
91902
92146
  clientY: event.clientY
91903
92147
  })
91904
92148
  );
91905
- searchQuery.value = "";
91906
- const context = await getEditorContext(props.editor, event);
91907
- sections.value = getItems({ ...context, trigger: "click" });
91908
- selectedId.value = flattenedItems.value[0]?.id || null;
91909
92149
  };
91910
92150
  const executeCommand = async (item) => {
91911
92151
  if (props.editor) {
91912
- item.action ? await item.action(props.editor) : null;
92152
+ item.action ? await item.action(props.editor, currentContext.value) : null;
91913
92153
  if (item.component) {
91914
92154
  menuRef.value;
91915
92155
  const componentProps = getPropsByItemId(item.id, props);
@@ -91927,7 +92167,7 @@ ${style2}
91927
92167
  const closeMenu = (options = { restoreCursor: true }) => {
91928
92168
  if (props.editor?.view) {
91929
92169
  const pluginState = SlashMenuPluginKey.getState(props.editor.view.state);
91930
- const { anchorPos } = pluginState;
92170
+ const anchorPos = pluginState?.anchorPos;
91931
92171
  props.editor.view.dispatch(
91932
92172
  props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
91933
92173
  type: "close"
@@ -91940,6 +92180,8 @@ ${style2}
91940
92180
  props.editor.view.dispatch(tr);
91941
92181
  props.editor.view.focus();
91942
92182
  }
92183
+ cleanupCustomItems();
92184
+ currentContext.value = null;
91943
92185
  isOpen.value = false;
91944
92186
  searchQuery.value = "";
91945
92187
  sections.value = [];
@@ -91956,19 +92198,29 @@ ${style2}
91956
92198
  isOpen.value = true;
91957
92199
  menuPosition.value = event.menuPosition;
91958
92200
  searchQuery.value = "";
91959
- const context = await getEditorContext(props.editor);
91960
- sections.value = getItems({ ...context, trigger: "slash" });
91961
- selectedId.value = flattenedItems.value[0]?.id || null;
92201
+ if (!currentContext.value) {
92202
+ const context = await getEditorContext(props.editor);
92203
+ currentContext.value = context;
92204
+ sections.value = getItems({ ...context, trigger: "slash" });
92205
+ selectedId.value = flattenedItems.value[0]?.id || null;
92206
+ } else if (sections.value.length === 0) {
92207
+ const trigger2 = currentContext.value.event?.type === "contextmenu" ? "click" : "slash";
92208
+ sections.value = getItems({ ...currentContext.value, trigger: trigger2 });
92209
+ selectedId.value = flattenedItems.value[0]?.id || null;
92210
+ }
91962
92211
  });
91963
92212
  props.editor.view.dom.addEventListener("contextmenu", handleRightClick);
91964
92213
  props.editor.on("slashMenu:close", () => {
92214
+ cleanupCustomItems();
91965
92215
  isOpen.value = false;
91966
92216
  searchQuery.value = "";
92217
+ currentContext.value = null;
91967
92218
  });
91968
92219
  });
91969
92220
  onBeforeUnmount(() => {
91970
92221
  document.removeEventListener("keydown", handleGlobalKeyDown);
91971
92222
  document.removeEventListener("mousedown", handleGlobalOutsideClick);
92223
+ cleanupCustomItems();
91972
92224
  if (props.editor) {
91973
92225
  try {
91974
92226
  props.editor.off("slashMenu:open");
@@ -92015,12 +92267,19 @@ ${style2}
92015
92267
  class: normalizeClass(["slash-menu-item", { "is-selected": item.id === selectedId.value }]),
92016
92268
  onClick: ($event) => executeCommand(item)
92017
92269
  }, [
92018
- item.icon ? (openBlock(), createElementBlock("span", {
92270
+ item.render ? (openBlock(), createElementBlock("div", {
92019
92271
  key: 0,
92020
- class: "slash-menu-item-icon",
92021
- innerHTML: item.icon
92022
- }, null, 8, _hoisted_4$5)) : createCommentVNode("", true),
92023
- createBaseVNode("span", null, toDisplayString(item.label), 1)
92272
+ ref_for: true,
92273
+ ref: (el) => setCustomItemRef(el, item),
92274
+ class: "slash-menu-custom-item"
92275
+ }, null, 512)) : (openBlock(), createElementBlock(Fragment$1, { key: 1 }, [
92276
+ item.icon ? (openBlock(), createElementBlock("span", {
92277
+ key: 0,
92278
+ class: "slash-menu-item-icon",
92279
+ innerHTML: item.icon
92280
+ }, null, 8, _hoisted_4$5)) : createCommentVNode("", true),
92281
+ createBaseVNode("span", null, toDisplayString(item.label), 1)
92282
+ ], 64))
92024
92283
  ], 10, _hoisted_3$1$1);
92025
92284
  }), 128))
92026
92285
  ], 64);
@@ -109582,6 +109841,7 @@ ${style2}
109582
109841
  annotations: proxy.$superdoc.config.annotations,
109583
109842
  isCommentsEnabled: proxy.$superdoc.config.modules?.comments,
109584
109843
  isAiEnabled: proxy.$superdoc.config.modules?.ai,
109844
+ slashMenuConfig: proxy.$superdoc.config.modules?.slashMenu,
109585
109845
  onBeforeCreate: onEditorBeforeCreate,
109586
109846
  onCreate: onEditorCreate,
109587
109847
  onDestroy: onEditorDestroy,
@@ -109943,7 +110203,7 @@ ${style2}
109943
110203
  };
109944
110204
  }
109945
110205
  };
109946
- const App = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-07532c12"]]);
110206
+ const App = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-dbfba5b9"]]);
109947
110207
  const createSuperdocVueApp = () => {
109948
110208
  const app = createApp(App);
109949
110209
  const pinia = createPinia();