@harbour-enterprises/superdoc 0.21.0 → 0.22.0-next.1

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.
Files changed (43) hide show
  1. package/dist/chunks/{PdfViewer-OZDJ7gwT.cjs → PdfViewer-B3KmcDup.cjs} +1 -1
  2. package/dist/chunks/{PdfViewer-D3zo7tPo.es.js → PdfViewer-BpwMPbUj.es.js} +1 -1
  3. package/dist/chunks/{index-CfYf4T_z.cjs → index-BOf6E2I4.cjs} +5 -4
  4. package/dist/chunks/{index-MzW5BVNd.es.js → index-Cw4YywoD.es.js} +5 -4
  5. package/dist/chunks/{super-editor.es-U-GVCd_F.cjs → super-editor.es-DHDx2fsy.cjs} +1181 -766
  6. package/dist/chunks/{super-editor.es-Bntob7Wd.es.js → super-editor.es-vfoWxyZL.es.js} +1181 -766
  7. package/dist/core/types/index.d.ts +8 -0
  8. package/dist/core/types/index.d.ts.map +1 -1
  9. package/dist/style.css +32 -27
  10. package/dist/super-editor/ai-writer.es.js +2 -2
  11. package/dist/super-editor/chunks/{converter-3xnF_NHq.js → converter-BcqEfCTg.js} +775 -645
  12. package/dist/super-editor/chunks/{docx-zipper-CZdELYi-.js → docx-zipper-DZ9ph0iQ.js} +1 -1
  13. package/dist/super-editor/chunks/{editor-BqYH4kDD.js → editor-BC2sSIVa.js} +19 -3
  14. package/dist/super-editor/chunks/{toolbar-TkaE2kKM.js → toolbar-DNTo5DDf.js} +2 -2
  15. package/dist/super-editor/converter.es.js +1 -1
  16. package/dist/super-editor/docx-zipper.es.js +2 -2
  17. package/dist/super-editor/editor.es.js +3 -3
  18. package/dist/super-editor/file-zipper.es.js +1 -1
  19. package/dist/super-editor/src/components/slash-menu/contextmenu-helpers.d.ts +1 -0
  20. package/dist/super-editor/src/components/slash-menu/menuItems.d.ts +5 -1
  21. package/dist/super-editor/src/components/slash-menu/tests/testHelpers.d.ts +466 -0
  22. package/dist/super-editor/src/components/slash-menu/utils.d.ts +9 -2
  23. package/dist/super-editor/src/core/commands/__tests__/schemaWithLists.d.ts +2 -0
  24. package/dist/super-editor/src/core/commands/__tests__/testHelpers.d.ts +4 -0
  25. package/dist/super-editor/src/core/commands/__tests__/testSchema.d.ts +2 -0
  26. package/dist/super-editor/src/core/commands/tests/commandTestUtils.d.ts +7 -0
  27. package/dist/super-editor/src/core/commands/tests/test-schema.d.ts +2 -0
  28. package/dist/super-editor/src/core/super-converter/v3/handlers/mc/altermateContent/alternate-content-translator.d.ts +6 -0
  29. package/dist/super-editor/src/core/super-converter/v3/handlers/mc/altermateContent/index.d.ts +1 -0
  30. package/dist/super-editor/src/extensions/custom-selection/custom-selection.d.ts +1 -0
  31. package/dist/super-editor/src/tests/helpers/helpers.d.ts +1 -0
  32. package/dist/super-editor/style.css +5 -0
  33. package/dist/super-editor/super-editor.es.js +461 -153
  34. package/dist/super-editor/toolbar.es.js +2 -2
  35. package/dist/super-editor.cjs +1 -1
  36. package/dist/super-editor.es.js +1 -1
  37. package/dist/superdoc.cjs +2 -2
  38. package/dist/superdoc.es.js +2 -2
  39. package/dist/superdoc.umd.js +1184 -768
  40. package/dist/superdoc.umd.js.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/super-editor/src/extensions/run-item/index.d.ts +0 -1
  43. package/dist/super-editor/src/extensions/run-item/run-item.d.ts +0 -26
@@ -9,14 +9,14 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
9
9
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
10
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
11
11
  var _SuperToolbar_instances, initToolbarGroups_fn, _interceptedCommands, makeToolbarItems_fn, initDefaultFonts_fn, updateHighlightColors_fn, deactivateAll_fn, updateToolbarHistory_fn, runCommandWithArgumentOnly_fn;
12
- import { av as getDefaultExportFromCjs, V as v4, T as TextSelection$1, v as getMarkRange, ay as vClickOutside, H as findParentNode, az as getActiveFormatting, ap as isInTable, aA as readFromClipboard, aB as handleClipboardPaste, aC as getFileObject, aD as runPropertyTranslators, aE as translator, aF as translator$1, aG as translator$2, aH as translator$3, aI as translator$4, aJ as translator$5, aK as translator$6, aL as translator$7, aM as translator$8, aN as translator$9, aO as translator$a, aP as translator$b, aQ as translator$c, aR as translator$d, aS as translator$e, aT as translator$f, aU as translator$g, aV as translator$h, aW as translator$i, aX as translator$j, aY as translator$k, aZ as translator$l, a_ as translator$m, a$ as translator$n, b0 as translator$o, b1 as translator$p, a as Plugin } from "./chunks/converter-3xnF_NHq.js";
13
- import { b2, a5, i, a2 } from "./chunks/converter-3xnF_NHq.js";
14
- import { _ as _export_sfc, u as useHighContrastMode, a as getQuickFormatList, b as generateLinkedStyleString, c as getFileOpener, d as checkAndProcessImage, r as replaceSelectionWithImagePlaceholder, e as uploadAndInsertImage, y as yUndoPluginKey, f as undoDepth, h as redoDepth, S as SlashMenuPluginKey, E as Editor, i as getStarterExtensions, P as Placeholder, j as getRichTextExtensions, M as Mark, k as Extension, A as Attribute, N as Node } from "./chunks/editor-BqYH4kDD.js";
15
- import { n, C, o, T, l, p, m } from "./chunks/editor-BqYH4kDD.js";
12
+ import { av as getDefaultExportFromCjs, V as v4, T as TextSelection$1, v as getMarkRange, ay as vClickOutside, H as findParentNode, az as getActiveFormatting, ap as isInTable, aA as readFromClipboard, aB as handleClipboardPaste, aC as getFileObject, aD as runPropertyTranslators, aE as translator, aF as translator$1, aG as translator$2, aH as translator$3, aI as translator$4, aJ as translator$5, aK as translator$6, aL as translator$7, aM as translator$8, aN as translator$9, aO as translator$a, aP as translator$b, aQ as translator$c, aR as translator$d, aS as translator$e, aT as translator$f, aU as translator$g, aV as translator$h, aW as translator$i, aX as translator$j, aY as translator$k, aZ as translator$l, a_ as translator$m, a$ as translator$n, b0 as translator$o, b1 as translator$p, b2 as translator$q, b3 as translator$r, b4 as translator$s, b5 as translator$t, b6 as translator$u, b7 as translator$v, b8 as translator$w, b9 as translator$x, ba as translator$y, bb as translator$z, bc as translator$A, bd as translator$B, be as translator$C, bf as translator$D, bg as translator$E, bh as translator$F, bi as translator$G, bj as translator$H, bk as translator$I, bl as translator$J, bm as translator$K, bn as translator$L, bo as translator$M, bp as translator$N, bq as translator$O, br as translator$P, bs as translator$Q, bt as translator$R, bu as translator$S, bv as translator$T, bw as translator$U, bx as translator$V, by as translator$W, bz as translator$X, bA as translator$Y, bB as translator$Z, bC as translator$_, bD as translator$$, bE as translator$10, a as Plugin } from "./chunks/converter-BcqEfCTg.js";
13
+ import { bF, a5, i, a2 } from "./chunks/converter-BcqEfCTg.js";
14
+ import { _ as _export_sfc, u as useHighContrastMode, a as getQuickFormatList, b as generateLinkedStyleString, c as getFileOpener, d as checkAndProcessImage, r as replaceSelectionWithImagePlaceholder, e as uploadAndInsertImage, y as yUndoPluginKey, f as undoDepth, h as redoDepth, S as SlashMenuPluginKey, E as Editor, i as getStarterExtensions, P as Placeholder, j as getRichTextExtensions, M as Mark, k as Extension, A as Attribute, N as Node } from "./chunks/editor-BC2sSIVa.js";
15
+ import { n, C, o, T, l, p, m } from "./chunks/editor-BC2sSIVa.js";
16
16
  import { ref, onMounted, createElementBlock, openBlock, normalizeClass, unref, Fragment, renderList, createElementVNode, withModifiers, toDisplayString, createCommentVNode, normalizeStyle, computed, watch, withDirectives, withKeys, vModelText, createTextVNode, createVNode, h, createApp, markRaw, nextTick, onBeforeUnmount, reactive, onUnmounted, renderSlot, shallowRef, createBlock, withCtx, resolveDynamicComponent, normalizeProps, guardReactiveProps } from "vue";
17
- import { t as toolbarIcons, s as sanitizeNumber, T as Toolbar, m as magicWandIcon, p as plusIconSvg, a as trashIconSvg, l as linkIconSvg, b as tableIconSvg, c as scissorsIconSvg, d as copyIconSvg, e as pasteIconSvg, f as borderNoneIconSvg, g as arrowsToDotIconSvg, h as arrowsLeftRightIconSvg, w as wrenchIconSvg, u as useMessage, N as NSkeleton } from "./chunks/toolbar-TkaE2kKM.js";
17
+ import { t as toolbarIcons, s as sanitizeNumber, T as Toolbar, m as magicWandIcon, p as plusIconSvg, a as trashIconSvg, l as linkIconSvg, b as tableIconSvg, c as scissorsIconSvg, d as copyIconSvg, e as pasteIconSvg, f as borderNoneIconSvg, g as arrowsToDotIconSvg, h as arrowsLeftRightIconSvg, w as wrenchIconSvg, u as useMessage, N as NSkeleton } from "./chunks/toolbar-DNTo5DDf.js";
18
18
  import AIWriter from "./ai-writer.es.js";
19
- import { D } from "./chunks/docx-zipper-CZdELYi-.js";
19
+ import { D } from "./chunks/docx-zipper-DZ9ph0iQ.js";
20
20
  import { createZip } from "./file-zipper.es.js";
21
21
  var eventemitter3 = { exports: {} };
22
22
  var hasRequiredEventemitter3;
@@ -3208,6 +3208,115 @@ runCommandWithArgumentOnly_fn = function({ item, argument, noArgumentCallback =
3208
3208
  this.updateToolbarState();
3209
3209
  }
3210
3210
  };
3211
+ const onMarginClickCursorChange = (event, editor) => {
3212
+ const y = event.clientY;
3213
+ const x = event.clientX;
3214
+ const { view } = editor;
3215
+ const editorRect = view.dom.getBoundingClientRect();
3216
+ let coords = {
3217
+ left: 0,
3218
+ top: y
3219
+ };
3220
+ let isRightMargin = false;
3221
+ if (x > editorRect.right) {
3222
+ coords.left = editorRect.left + editorRect.width - 1;
3223
+ isRightMargin = true;
3224
+ } else if (x < editorRect.left) {
3225
+ coords.left = editorRect.left;
3226
+ }
3227
+ const pos = view.posAtCoords(coords)?.pos;
3228
+ if (pos) {
3229
+ let cursorPos = pos;
3230
+ if (isRightMargin) {
3231
+ const $pos = view.state.doc.resolve(pos);
3232
+ const charOffset = $pos.textOffset;
3233
+ const node = view.state.doc.nodeAt(pos);
3234
+ const text = node?.text;
3235
+ const charAtPos = text?.charAt(charOffset);
3236
+ cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
3237
+ }
3238
+ const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
3239
+ view.dispatch(transaction);
3240
+ view.focus();
3241
+ }
3242
+ };
3243
+ const checkNodeSpecificClicks = (editor, event, popoverControls) => {
3244
+ if (!editor) return;
3245
+ if (selectionHasNodeOrMark(editor.view.state, "link", { requireEnds: true })) {
3246
+ popoverControls.component = LinkInput;
3247
+ popoverControls.position = {
3248
+ left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
3249
+ top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
3250
+ };
3251
+ popoverControls.props = {
3252
+ showInput: true
3253
+ };
3254
+ popoverControls.visible = true;
3255
+ }
3256
+ };
3257
+ function selectionHasNodeOrMark(state, name, options = {}) {
3258
+ const { requireEnds = false } = options;
3259
+ const $from = state.selection.$from;
3260
+ const $to = state.selection.$to;
3261
+ if (requireEnds) {
3262
+ for (let d = $from.depth; d > 0; d--) {
3263
+ if ($from.node(d).type.name === name) {
3264
+ return true;
3265
+ }
3266
+ }
3267
+ for (let d = $to.depth; d > 0; d--) {
3268
+ if ($to.node(d).type.name === name) {
3269
+ return true;
3270
+ }
3271
+ }
3272
+ } else {
3273
+ for (let d = $from.depth; d > 0; d--) {
3274
+ if ($from.node(d).type.name === name) {
3275
+ return true;
3276
+ }
3277
+ }
3278
+ }
3279
+ const markType = state.schema.marks[name];
3280
+ if (markType) {
3281
+ const { from, to, empty } = state.selection;
3282
+ if (requireEnds) {
3283
+ const fromMarks = markType.isInSet($from.marks());
3284
+ const toMarks = markType.isInSet($to.marks());
3285
+ if (fromMarks || toMarks) {
3286
+ return true;
3287
+ }
3288
+ if (empty && markType.isInSet(state.storedMarks || $from.marks())) {
3289
+ return true;
3290
+ }
3291
+ } else {
3292
+ if (empty) {
3293
+ if (markType.isInSet(state.storedMarks || $from.marks())) {
3294
+ return true;
3295
+ }
3296
+ } else {
3297
+ let hasMark = false;
3298
+ state.doc.nodesBetween(from, to, (node) => {
3299
+ if (markType.isInSet(node.marks)) {
3300
+ hasMark = true;
3301
+ return false;
3302
+ }
3303
+ });
3304
+ if (hasMark) return true;
3305
+ }
3306
+ }
3307
+ }
3308
+ return false;
3309
+ }
3310
+ function moveCursorToMouseEvent(event, editor) {
3311
+ const { view } = editor;
3312
+ const coords = { left: event.clientX, top: event.clientY };
3313
+ const pos = view.posAtCoords(coords)?.pos;
3314
+ if (typeof pos === "number") {
3315
+ const tr = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, pos));
3316
+ view.dispatch(tr);
3317
+ view.focus();
3318
+ }
3319
+ }
3211
3320
  const ICONS = {
3212
3321
  addRowBefore: plusIconSvg,
3213
3322
  addRowAfter: plusIconSvg,
@@ -3407,6 +3516,30 @@ const getPropsByItemId = (itemId, props) => {
3407
3516
  return baseProps;
3408
3517
  }
3409
3518
  };
3519
+ function normalizeClipboardContent(rawClipboardContent) {
3520
+ if (!rawClipboardContent) {
3521
+ return {
3522
+ html: null,
3523
+ text: null,
3524
+ hasContent: false,
3525
+ raw: null
3526
+ };
3527
+ }
3528
+ const html = typeof rawClipboardContent.html === "string" ? rawClipboardContent.html : null;
3529
+ const text = typeof rawClipboardContent.text === "string" ? rawClipboardContent.text : null;
3530
+ const hasHtml = !!html && html.trim().length > 0;
3531
+ const hasText = !!text && text.length > 0;
3532
+ const isObject = typeof rawClipboardContent === "object" && rawClipboardContent !== null;
3533
+ const fragmentSize = typeof rawClipboardContent.size === "number" ? rawClipboardContent.size : null;
3534
+ const nestedSize = isObject && rawClipboardContent.content && typeof rawClipboardContent.content.size === "number" ? rawClipboardContent.content.size : null;
3535
+ const hasFragmentContent = (fragmentSize ?? nestedSize ?? 0) > 0;
3536
+ return {
3537
+ html,
3538
+ text,
3539
+ hasContent: hasHtml || hasText || hasFragmentContent,
3540
+ raw: rawClipboardContent
3541
+ };
3542
+ }
3410
3543
  async function getEditorContext(editor, event) {
3411
3544
  const { view } = editor;
3412
3545
  const { state } = view;
@@ -3422,125 +3555,154 @@ async function getEditorContext(editor, event) {
3422
3555
  pos = from;
3423
3556
  node = state.doc.nodeAt(pos);
3424
3557
  }
3425
- const clipboardContent = await readFromClipboard(state);
3558
+ const rawClipboardContent = await readFromClipboard(state);
3559
+ const clipboardContent = normalizeClipboardContent(rawClipboardContent);
3560
+ const structureFromResolvedPos = pos !== null ? getStructureFromResolvedPos(state, pos) : null;
3561
+ const isInTable2 = structureFromResolvedPos?.isInTable ?? selectionHasNodeOrMark(state, "table", { requireEnds: true });
3562
+ const isInList = structureFromResolvedPos?.isInList ?? (selectionHasNodeOrMark(state, "bulletList", { requireEnds: false }) || selectionHasNodeOrMark(state, "orderedList", { requireEnds: false }));
3563
+ const isInSectionNode = structureFromResolvedPos?.isInSectionNode ?? selectionHasNodeOrMark(state, "documentSection", { requireEnds: true });
3564
+ const currentNodeType = node?.type?.name || null;
3565
+ const activeMarks = [];
3566
+ if (event && pos !== null) {
3567
+ const $pos = state.doc.resolve(pos);
3568
+ if ($pos.marks && typeof $pos.marks === "function") {
3569
+ $pos.marks().forEach((mark) => activeMarks.push(mark.type.name));
3570
+ }
3571
+ if (node && node.marks) {
3572
+ node.marks.forEach((mark) => activeMarks.push(mark.type.name));
3573
+ }
3574
+ } else {
3575
+ state.storedMarks?.forEach((mark) => activeMarks.push(mark.type.name));
3576
+ state.selection.$head.marks().forEach((mark) => activeMarks.push(mark.type.name));
3577
+ }
3578
+ const isTrackedChange = activeMarks.includes("trackInsert") || activeMarks.includes("trackDelete");
3579
+ let trackedChangeId = null;
3580
+ if (isTrackedChange && event && pos !== null) {
3581
+ const $pos = state.doc.resolve(pos);
3582
+ const marksAtPos = $pos.marks();
3583
+ const trackedMark = marksAtPos.find((mark) => mark.type.name === "trackInsert" || mark.type.name === "trackDelete");
3584
+ if (trackedMark) {
3585
+ trackedChangeId = trackedMark.attrs.id;
3586
+ }
3587
+ }
3588
+ const cursorCoords = pos ? view.coordsAtPos(pos) : null;
3589
+ const cursorPosition = cursorCoords ? {
3590
+ x: cursorCoords.left,
3591
+ y: cursorCoords.top
3592
+ } : null;
3426
3593
  return {
3427
- editor,
3594
+ // Selection info
3428
3595
  selectedText,
3596
+ hasSelection: !empty,
3597
+ selectionStart: from,
3598
+ selectionEnd: to,
3599
+ // Document structure
3600
+ isInTable: isInTable2,
3601
+ isInList,
3602
+ isInSectionNode,
3603
+ currentNodeType,
3604
+ activeMarks,
3605
+ // Document state
3606
+ isTrackedChange,
3607
+ trackedChangeId,
3608
+ documentMode: editor.options?.documentMode || "editing",
3609
+ canUndo: computeCanUndo(editor, state),
3610
+ canRedo: computeCanRedo(editor, state),
3611
+ isEditable: editor.isEditable,
3612
+ // Clipboard
3613
+ clipboardContent,
3614
+ // Position and trigger info
3615
+ cursorPosition,
3429
3616
  pos,
3430
3617
  node,
3431
3618
  event,
3432
- clipboardContent
3619
+ // Editor reference for advanced use cases
3620
+ editor
3433
3621
  };
3434
3622
  }
3435
- const onMarginClickCursorChange = (event, editor) => {
3436
- const y = event.clientY;
3437
- const x = event.clientX;
3438
- const { view } = editor;
3439
- const editorRect = view.dom.getBoundingClientRect();
3440
- let coords = {
3441
- left: 0,
3442
- top: y
3443
- };
3444
- let isRightMargin = false;
3445
- if (x > editorRect.right) {
3446
- coords.left = editorRect.left + editorRect.width - 1;
3447
- isRightMargin = true;
3448
- } else if (x < editorRect.left) {
3449
- coords.left = editorRect.left;
3623
+ function computeCanUndo(editor, state) {
3624
+ if (typeof editor?.can === "function") {
3625
+ try {
3626
+ const can = editor.can();
3627
+ if (can && typeof can.undo === "function") {
3628
+ return !!can.undo();
3629
+ }
3630
+ } catch (error) {
3631
+ console.warn("[SlashMenu] Unable to determine undo availability via editor.can():", error);
3632
+ }
3450
3633
  }
3451
- const pos = view.posAtCoords(coords)?.pos;
3452
- if (pos) {
3453
- let cursorPos = pos;
3454
- if (isRightMargin) {
3455
- const $pos = view.state.doc.resolve(pos);
3456
- const charOffset = $pos.textOffset;
3457
- const node = view.state.doc.nodeAt(pos);
3458
- const text = node?.text;
3459
- const charAtPos = text?.charAt(charOffset);
3460
- cursorPos = node?.isText && charAtPos !== " " ? pos - 1 : pos;
3634
+ if (isCollaborationEnabled(editor)) {
3635
+ try {
3636
+ const undoManager = yUndoPluginKey.getState(state)?.undoManager;
3637
+ return !!undoManager && undoManager.undoStack.length > 0;
3638
+ } catch (error) {
3639
+ console.warn("[SlashMenu] Unable to determine undo availability via y-prosemirror:", error);
3461
3640
  }
3462
- const transaction = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, cursorPos));
3463
- view.dispatch(transaction);
3464
- view.focus();
3465
3641
  }
3466
- };
3467
- const checkNodeSpecificClicks = (editor, event, popoverControls) => {
3468
- if (!editor) return;
3469
- if (selectionHasNodeOrMark(editor.view.state, "link", { requireEnds: true })) {
3470
- popoverControls.component = LinkInput;
3471
- popoverControls.position = {
3472
- left: `${event.clientX - editor.element.getBoundingClientRect().left}px`,
3473
- top: `${event.clientY - editor.element.getBoundingClientRect().top + 15}px`
3474
- };
3475
- popoverControls.props = {
3476
- showInput: true
3477
- };
3478
- popoverControls.visible = true;
3642
+ try {
3643
+ return undoDepth(state) > 0;
3644
+ } catch (error) {
3645
+ console.warn("[SlashMenu] Unable to determine undo availability via history plugin:", error);
3646
+ return false;
3479
3647
  }
3480
- };
3481
- function selectionHasNodeOrMark(state, name, options = {}) {
3482
- const { requireEnds = false } = options;
3483
- const $from = state.selection.$from;
3484
- const $to = state.selection.$to;
3485
- if (requireEnds) {
3486
- for (let d = $from.depth; d > 0; d--) {
3487
- if ($from.node(d).type.name === name) {
3488
- return true;
3489
- }
3490
- }
3491
- for (let d = $to.depth; d > 0; d--) {
3492
- if ($to.node(d).type.name === name) {
3493
- return true;
3494
- }
3495
- }
3496
- } else {
3497
- for (let d = $from.depth; d > 0; d--) {
3498
- if ($from.node(d).type.name === name) {
3499
- return true;
3648
+ }
3649
+ function computeCanRedo(editor, state) {
3650
+ if (typeof editor?.can === "function") {
3651
+ try {
3652
+ const can = editor.can();
3653
+ if (can && typeof can.redo === "function") {
3654
+ return !!can.redo();
3500
3655
  }
3656
+ } catch (error) {
3657
+ console.warn("[SlashMenu] Unable to determine redo availability via editor.can():", error);
3501
3658
  }
3502
3659
  }
3503
- const markType = state.schema.marks[name];
3504
- if (markType) {
3505
- const { from, to, empty } = state.selection;
3506
- if (requireEnds) {
3507
- const fromMarks = markType.isInSet($from.marks());
3508
- const toMarks = markType.isInSet($to.marks());
3509
- if (fromMarks || toMarks) {
3510
- return true;
3511
- }
3512
- if (empty && markType.isInSet(state.storedMarks || $from.marks())) {
3513
- return true;
3514
- }
3515
- } else {
3516
- if (empty) {
3517
- if (markType.isInSet(state.storedMarks || $from.marks())) {
3518
- return true;
3519
- }
3520
- } else {
3521
- let hasMark = false;
3522
- state.doc.nodesBetween(from, to, (node) => {
3523
- if (markType.isInSet(node.marks)) {
3524
- hasMark = true;
3525
- return false;
3526
- }
3527
- });
3528
- if (hasMark) return true;
3529
- }
3660
+ if (isCollaborationEnabled(editor)) {
3661
+ try {
3662
+ const undoManager = yUndoPluginKey.getState(state)?.undoManager;
3663
+ return !!undoManager && undoManager.redoStack.length > 0;
3664
+ } catch (error) {
3665
+ console.warn("[SlashMenu] Unable to determine redo availability via y-prosemirror:", error);
3530
3666
  }
3531
3667
  }
3532
- return false;
3668
+ try {
3669
+ return redoDepth(state) > 0;
3670
+ } catch (error) {
3671
+ console.warn("[SlashMenu] Unable to determine redo availability via history plugin:", error);
3672
+ return false;
3673
+ }
3533
3674
  }
3534
- function moveCursorToMouseEvent(event, editor) {
3535
- const { view } = editor;
3536
- const coords = { left: event.clientX, top: event.clientY };
3537
- const pos = view.posAtCoords(coords)?.pos;
3538
- if (typeof pos === "number") {
3539
- const tr = view.state.tr.setSelection(TextSelection$1.create(view.state.doc, pos));
3540
- view.dispatch(tr);
3541
- view.focus();
3675
+ function isCollaborationEnabled(editor) {
3676
+ return Boolean(editor?.options?.collaborationProvider && editor?.options?.ydoc);
3677
+ }
3678
+ function getStructureFromResolvedPos(state, pos) {
3679
+ try {
3680
+ const $pos = state.doc.resolve(pos);
3681
+ const ancestors = /* @__PURE__ */ new Set();
3682
+ for (let depth = $pos.depth; depth > 0; depth--) {
3683
+ ancestors.add($pos.node(depth).type.name);
3684
+ }
3685
+ const isInList = ancestors.has("bulletList") || ancestors.has("orderedList");
3686
+ const isInTable2 = ancestors.has("table") || ancestors.has("tableRow") || ancestors.has("tableCell") || ancestors.has("tableHeader");
3687
+ const isInSectionNode = ancestors.has("documentSection");
3688
+ return {
3689
+ isInTable: isInTable2,
3690
+ isInList,
3691
+ isInSectionNode
3692
+ };
3693
+ } catch (error) {
3694
+ console.warn("[SlashMenu] Unable to resolve position for structural context:", error);
3695
+ return null;
3542
3696
  }
3543
3697
  }
3698
+ const shouldBypassContextMenu = (event) => {
3699
+ if (!event) return false;
3700
+ if (event.ctrlKey || event.metaKey) {
3701
+ return true;
3702
+ }
3703
+ const isKeyboardInvocation = event.type === "contextmenu" && typeof event.detail === "number" && event.detail === 0 && (event.button === 0 || event.button === void 0) && event.clientX === 0 && event.clientY === 0;
3704
+ return Boolean(isKeyboardInvocation);
3705
+ };
3544
3706
  const isModuleEnabled = (editorOptions, moduleName) => {
3545
3707
  switch (moduleName) {
3546
3708
  case "ai":
@@ -3552,8 +3714,52 @@ const isModuleEnabled = (editorOptions, moduleName) => {
3552
3714
  return true;
3553
3715
  }
3554
3716
  };
3717
+ function applyCustomMenuConfiguration(defaultSections, context) {
3718
+ const { editor } = context;
3719
+ const slashMenuConfig = editor.options?.slashMenuConfig;
3720
+ if (!slashMenuConfig) {
3721
+ return defaultSections;
3722
+ }
3723
+ let sections = [];
3724
+ if (slashMenuConfig.includeDefaultItems !== false) {
3725
+ sections = [...defaultSections];
3726
+ }
3727
+ if (slashMenuConfig.customItems && Array.isArray(slashMenuConfig.customItems)) {
3728
+ sections = [...sections, ...slashMenuConfig.customItems];
3729
+ }
3730
+ if (typeof slashMenuConfig.menuProvider === "function") {
3731
+ try {
3732
+ sections = slashMenuConfig.menuProvider(context, sections) || sections;
3733
+ } catch (error) {
3734
+ console.warn("[SlashMenu] Error in custom menuProvider:", error);
3735
+ }
3736
+ }
3737
+ return sections;
3738
+ }
3739
+ function filterCustomItems(sections, context) {
3740
+ return sections.map((section) => {
3741
+ const filteredItems = section.items.filter((item) => {
3742
+ if (typeof item.showWhen === "function") {
3743
+ try {
3744
+ return item.showWhen(context);
3745
+ } catch (error) {
3746
+ console.warn(`[SlashMenu] Error in showWhen for item ${item.id}:`, error);
3747
+ return false;
3748
+ }
3749
+ }
3750
+ return true;
3751
+ });
3752
+ return {
3753
+ ...section,
3754
+ items: filteredItems
3755
+ };
3756
+ }).filter((section) => section.items.length > 0);
3757
+ }
3555
3758
  function getItems(context) {
3556
3759
  const { editor, selectedText, trigger, clipboardContent } = context;
3760
+ const clipboardHasContent = Boolean(
3761
+ 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
3762
+ );
3557
3763
  const isInTable2 = selectionHasNodeOrMark(editor.view.state, "table", { requireEnds: true });
3558
3764
  const isInSectionNode = selectionHasNodeOrMark(editor.view.state, "documentSection", { requireEnds: true });
3559
3765
  const sections = [
@@ -3690,12 +3896,13 @@ function getItems(context) {
3690
3896
  ]
3691
3897
  }
3692
3898
  ];
3693
- const filteredSections = sections.map((section) => {
3899
+ let allSections = applyCustomMenuConfiguration(sections, context);
3900
+ const filteredSections = allSections.map((section) => {
3694
3901
  const filteredItems = section.items.filter((item) => {
3695
3902
  if (item.requiresModule && !isModuleEnabled(editor?.options, item.requiresModule)) return false;
3696
3903
  if (item.requiresSelection && !selectedText) return false;
3697
3904
  if (!item.allowedTriggers.includes(trigger)) return false;
3698
- if (item.requiresClipboard && !clipboardContent) return false;
3905
+ if (item.requiresClipboard && !clipboardHasContent) return false;
3699
3906
  if (item.requiresTableParent && !isInTable2 || item.id === "insert-table" && isInTable2) return false;
3700
3907
  if (item.requiresSectionParent && !isInSectionNode) return false;
3701
3908
  return true;
@@ -3705,7 +3912,8 @@ function getItems(context) {
3705
3912
  items: filteredItems
3706
3913
  };
3707
3914
  }).filter((section) => section.items.length > 0);
3708
- return filteredSections;
3915
+ const finalSections = filterCustomItems(filteredSections, context);
3916
+ return finalSections;
3709
3917
  }
3710
3918
  const _hoisted_1$3 = { class: "slash-menu-items" };
3711
3919
  const _hoisted_2$1 = {
@@ -3740,6 +3948,7 @@ const _sfc_main$4 = {
3740
3948
  const menuRef = ref(null);
3741
3949
  const sections = ref([]);
3742
3950
  const selectedId = ref(null);
3951
+ const currentContext = ref(null);
3743
3952
  const handleEditorUpdate = () => {
3744
3953
  if (!props.editor?.isEditable && isOpen.value) {
3745
3954
  closeMenu({ restoreCursor: false });
@@ -3785,6 +3994,44 @@ const _sfc_main$4 = {
3785
3994
  selectedId.value = newItems[0].id;
3786
3995
  }
3787
3996
  });
3997
+ const customItemRefs = /* @__PURE__ */ new Map();
3998
+ const setCustomItemRef = (el, item) => {
3999
+ if (el && item.render) {
4000
+ customItemRefs.set(item.id, { element: el, item });
4001
+ nextTick(() => {
4002
+ renderCustomItem(item.id);
4003
+ });
4004
+ }
4005
+ };
4006
+ const renderCustomItem = async (itemId) => {
4007
+ const refData = customItemRefs.get(itemId);
4008
+ if (!refData || refData.element.hasCustomContent) return;
4009
+ const { element, item } = refData;
4010
+ try {
4011
+ if (!currentContext.value) {
4012
+ currentContext.value = await getEditorContext(props.editor);
4013
+ }
4014
+ const context = currentContext.value;
4015
+ const customElement = item.render(context);
4016
+ if (customElement instanceof HTMLElement) {
4017
+ element.innerHTML = "";
4018
+ element.appendChild(customElement);
4019
+ element.hasCustomContent = true;
4020
+ }
4021
+ } catch (error) {
4022
+ console.warn(`[SlashMenu] Error rendering custom item ${itemId}:`, error);
4023
+ element.innerHTML = `<span>${item.label || "Custom Item"}</span>`;
4024
+ element.hasCustomContent = true;
4025
+ }
4026
+ };
4027
+ const cleanupCustomItems = () => {
4028
+ customItemRefs.forEach((refData) => {
4029
+ if (refData.element) {
4030
+ refData.element.hasCustomContent = false;
4031
+ }
4032
+ });
4033
+ customItemRefs.clear();
4034
+ };
3788
4035
  const handleGlobalKeyDown = (event) => {
3789
4036
  if (event.key === "Escape") {
3790
4037
  event.preventDefault();
@@ -3830,27 +4077,27 @@ const _sfc_main$4 = {
3830
4077
  };
3831
4078
  const handleRightClick = async (event) => {
3832
4079
  const readOnly = !props.editor?.isEditable;
3833
- const isHoldingCtrl = event.ctrlKey;
3834
- if (readOnly || isHoldingCtrl) {
4080
+ if (readOnly || shouldBypassContextMenu(event)) {
3835
4081
  return;
3836
4082
  }
3837
4083
  event.preventDefault();
4084
+ const context = await getEditorContext(props.editor, event);
4085
+ currentContext.value = context;
4086
+ sections.value = getItems({ ...context, trigger: "click" });
4087
+ selectedId.value = flattenedItems.value[0]?.id || null;
4088
+ searchQuery.value = "";
3838
4089
  props.editor.view.dispatch(
3839
4090
  props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
3840
4091
  type: "open",
3841
- pos: props.editor.view.state.selection.from,
4092
+ pos: context?.pos ?? props.editor.view.state.selection.from,
3842
4093
  clientX: event.clientX,
3843
4094
  clientY: event.clientY
3844
4095
  })
3845
4096
  );
3846
- searchQuery.value = "";
3847
- const context = await getEditorContext(props.editor, event);
3848
- sections.value = getItems({ ...context, trigger: "click" });
3849
- selectedId.value = flattenedItems.value[0]?.id || null;
3850
4097
  };
3851
4098
  const executeCommand = async (item) => {
3852
4099
  if (props.editor) {
3853
- item.action ? await item.action(props.editor) : null;
4100
+ item.action ? await item.action(props.editor, currentContext.value) : null;
3854
4101
  if (item.component) {
3855
4102
  menuRef.value;
3856
4103
  const componentProps = getPropsByItemId(item.id, props);
@@ -3868,7 +4115,7 @@ const _sfc_main$4 = {
3868
4115
  const closeMenu = (options = { restoreCursor: true }) => {
3869
4116
  if (props.editor?.view) {
3870
4117
  const pluginState = SlashMenuPluginKey.getState(props.editor.view.state);
3871
- const { anchorPos } = pluginState;
4118
+ const anchorPos = pluginState?.anchorPos;
3872
4119
  props.editor.view.dispatch(
3873
4120
  props.editor.view.state.tr.setMeta(SlashMenuPluginKey, {
3874
4121
  type: "close"
@@ -3881,6 +4128,8 @@ const _sfc_main$4 = {
3881
4128
  props.editor.view.dispatch(tr);
3882
4129
  props.editor.view.focus();
3883
4130
  }
4131
+ cleanupCustomItems();
4132
+ currentContext.value = null;
3884
4133
  isOpen.value = false;
3885
4134
  searchQuery.value = "";
3886
4135
  sections.value = [];
@@ -3897,19 +4146,29 @@ const _sfc_main$4 = {
3897
4146
  isOpen.value = true;
3898
4147
  menuPosition.value = event.menuPosition;
3899
4148
  searchQuery.value = "";
3900
- const context = await getEditorContext(props.editor);
3901
- sections.value = getItems({ ...context, trigger: "slash" });
3902
- selectedId.value = flattenedItems.value[0]?.id || null;
4149
+ if (!currentContext.value) {
4150
+ const context = await getEditorContext(props.editor);
4151
+ currentContext.value = context;
4152
+ sections.value = getItems({ ...context, trigger: "slash" });
4153
+ selectedId.value = flattenedItems.value[0]?.id || null;
4154
+ } else if (sections.value.length === 0) {
4155
+ const trigger = currentContext.value.event?.type === "contextmenu" ? "click" : "slash";
4156
+ sections.value = getItems({ ...currentContext.value, trigger });
4157
+ selectedId.value = flattenedItems.value[0]?.id || null;
4158
+ }
3903
4159
  });
3904
4160
  props.editor.view.dom.addEventListener("contextmenu", handleRightClick);
3905
4161
  props.editor.on("slashMenu:close", () => {
4162
+ cleanupCustomItems();
3906
4163
  isOpen.value = false;
3907
4164
  searchQuery.value = "";
4165
+ currentContext.value = null;
3908
4166
  });
3909
4167
  });
3910
4168
  onBeforeUnmount(() => {
3911
4169
  document.removeEventListener("keydown", handleGlobalKeyDown);
3912
4170
  document.removeEventListener("mousedown", handleGlobalOutsideClick);
4171
+ cleanupCustomItems();
3913
4172
  if (props.editor) {
3914
4173
  try {
3915
4174
  props.editor.off("slashMenu:open");
@@ -3956,12 +4215,19 @@ const _sfc_main$4 = {
3956
4215
  class: normalizeClass(["slash-menu-item", { "is-selected": item.id === selectedId.value }]),
3957
4216
  onClick: ($event) => executeCommand(item)
3958
4217
  }, [
3959
- item.icon ? (openBlock(), createElementBlock("span", {
4218
+ item.render ? (openBlock(), createElementBlock("div", {
3960
4219
  key: 0,
3961
- class: "slash-menu-item-icon",
3962
- innerHTML: item.icon
3963
- }, null, 8, _hoisted_4)) : createCommentVNode("", true),
3964
- createElementVNode("span", null, toDisplayString(item.label), 1)
4220
+ ref_for: true,
4221
+ ref: (el) => setCustomItemRef(el, item),
4222
+ class: "slash-menu-custom-item"
4223
+ }, null, 512)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
4224
+ item.icon ? (openBlock(), createElementBlock("span", {
4225
+ key: 0,
4226
+ class: "slash-menu-item-icon",
4227
+ innerHTML: item.icon
4228
+ }, null, 8, _hoisted_4)) : createCommentVNode("", true),
4229
+ createElementVNode("span", null, toDisplayString(item.label), 1)
4230
+ ], 64))
3965
4231
  ], 10, _hoisted_3$1);
3966
4232
  }), 128))
3967
4233
  ], 64);
@@ -4656,34 +4922,76 @@ const _sfc_main = {
4656
4922
  }
4657
4923
  };
4658
4924
  const SuperInput = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-4d5cff52"]]);
4925
+ const additionalHandlers = Object.freeze({
4926
+ "mc:AlternateContent": translator$10,
4927
+ "w:b": translator$$,
4928
+ "w:bidiVisual": translator$_,
4929
+ "w:bookmarkEnd": translator$Z,
4930
+ "w:bookmarkStart": translator$Y,
4931
+ "w:bottom": translator$X,
4932
+ "w:br": translator$W,
4933
+ "w:cantSplit": translator$V,
4934
+ "w:cnfStyle": translator$U,
4935
+ "w:color": translator$T,
4936
+ "w:divId": translator$S,
4937
+ "w:drawing": translator$R,
4938
+ "w:end": translator$Q,
4939
+ "w:gridAfter": translator$P,
4940
+ "w:gridBefore": translator$O,
4941
+ "w:gridCol": translator$N,
4942
+ "w:hidden": translator$M,
4943
+ "w:highlight": translator$L,
4944
+ "w:hyperlink": translator$K,
4945
+ "w:i": translator$J,
4946
+ "w:insideH": translator$I,
4947
+ "w:insideV": translator$H,
4948
+ "w:jc": translator$G,
4949
+ "w:left": translator$F,
4950
+ "w:p": translator$E,
4951
+ "w:r": translator$D,
4952
+ "w:rFonts": translator$C,
4953
+ "w:rPr": translator$B,
4954
+ "w:rStyle": translator$A,
4955
+ "w:right": translator$z,
4956
+ "w:sdt": translator$y,
4957
+ "w:shd": translator$x,
4958
+ "w:start": translator$w,
4959
+ "w:strike": translator$v,
4960
+ "w:sz": translator$u,
4961
+ "w:szCs": translator$t,
4962
+ "w:tab": translator$s,
4963
+ "w:tbl": translator$r,
4964
+ "w:tblBorders": translator$q,
4965
+ "w:tblCaption": translator$p,
4966
+ "w:tblCellMar": translator$o,
4967
+ "w:tblCellSpacing": translator$n,
4968
+ "w:tblDescription": translator$m,
4969
+ "w:tblGrid": translator$l,
4970
+ "w:tblHeader": translator$k,
4971
+ "w:tblInd": translator$j,
4972
+ "w:tblLayout": translator$i,
4973
+ "w:tblLook": translator$h,
4974
+ "w:tblOverlap": translator$g,
4975
+ "w:tblPr": translator$f,
4976
+ "w:tblStyle": translator$e,
4977
+ "w:tblStyleColBandSize": translator$d,
4978
+ "w:tblStyleRowBandSize": translator$c,
4979
+ "w:tblW": translator$b,
4980
+ "w:tblpPr": translator$a,
4981
+ "w:tc": translator$9,
4982
+ "w:top": translator$8,
4983
+ "w:tr": translator$7,
4984
+ "w:trHeight": translator$6,
4985
+ "w:trPr": translator$5,
4986
+ "w:u": translator$4,
4987
+ "w:wAfter": translator$3,
4988
+ "w:wBefore": translator$2,
4989
+ "wp:anchor": translator$1,
4990
+ "wp:inline": translator
4991
+ });
4659
4992
  const baseHandlers = {
4660
4993
  ...runPropertyTranslators,
4661
- "w:br": translator$p,
4662
- "w:cantSplit": translator$o,
4663
- "w:cnfStyle": translator$n,
4664
- "w:divId": translator$m,
4665
- "w:gridAfter": translator$l,
4666
- "w:gridBefore": translator$k,
4667
- "w:hidden": translator$j,
4668
- "w:hyperlink": translator$i,
4669
- "w:jc": translator$h,
4670
- "w:p": translator$g,
4671
- "w:r": translator$f,
4672
- "w:rPr": translator$e,
4673
- "w:sdt": translator$d,
4674
- "w:tab": translator$c,
4675
- "w:tblCellSpacing": translator$b,
4676
- "w:tblHeader": translator$a,
4677
- "w:tc": translator$9,
4678
- "w:tr": translator$8,
4679
- "w:trHeight": translator$7,
4680
- "w:trPr": translator$6,
4681
- "w:wAfter": translator$5,
4682
- "w:wBefore": translator$4,
4683
- "wp:anchor": translator$3,
4684
- "wp:inline": translator$2,
4685
- "w:bookmarkStart": translator$1,
4686
- "w:bookmarkEnd": translator
4994
+ ...additionalHandlers
4687
4995
  };
4688
4996
  const registeredHandlers = Object.freeze(baseHandlers);
4689
4997
  const Extensions = {
@@ -4696,7 +5004,7 @@ const Extensions = {
4696
5004
  export {
4697
5005
  AIWriter,
4698
5006
  n as AnnotatorHelpers,
4699
- b2 as BasicUpload,
5007
+ bF as BasicUpload,
4700
5008
  C as CommentsPluginKey,
4701
5009
  D as DocxZipper,
4702
5010
  Editor,