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

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 (75) hide show
  1. package/dist/chunks/{PdfViewer-BpwMPbUj.es.js → PdfViewer-CS3pY_UR.es.js} +1 -1
  2. package/dist/chunks/{PdfViewer-B3KmcDup.cjs → PdfViewer-Cz3fT1qt.cjs} +1 -1
  3. package/dist/chunks/{index-Cw4YywoD.es.js → index-Bbqhu9ev.es.js} +53 -26
  4. package/dist/chunks/{index-BOf6E2I4.cjs → index-p73XAt11.cjs} +53 -26
  5. package/dist/chunks/{super-editor.es-DHDx2fsy.cjs → super-editor.es-CFD0lcOY.cjs} +3201 -2009
  6. package/dist/chunks/{super-editor.es-vfoWxyZL.es.js → super-editor.es-DK3l03fz.es.js} +3201 -2009
  7. package/dist/core/SuperDoc.d.ts +5 -0
  8. package/dist/core/SuperDoc.d.ts.map +1 -1
  9. package/dist/core/types/index.d.ts +4 -4
  10. package/dist/core/types/index.d.ts.map +1 -1
  11. package/dist/stores/comments-store.d.ts +4 -1
  12. package/dist/stores/comments-store.d.ts.map +1 -1
  13. package/dist/style.css +51 -44
  14. package/dist/super-editor/ai-writer.es.js +2 -2
  15. package/dist/super-editor/chunks/{converter-BcqEfCTg.js → converter-DFDRdFEB.js} +1880 -1169
  16. package/dist/super-editor/chunks/{docx-zipper-DZ9ph0iQ.js → docx-zipper-CplUdgI9.js} +73 -12
  17. package/dist/super-editor/chunks/{editor-BC2sSIVa.js → editor-BnpIdTLI.js} +1492 -1061
  18. package/dist/super-editor/chunks/{toolbar-DNTo5DDf.js → toolbar-5h-ljJ_h.js} +2 -2
  19. package/dist/super-editor/converter.es.js +1 -1
  20. package/dist/super-editor/docx-zipper.es.js +2 -2
  21. package/dist/super-editor/editor.es.js +3 -3
  22. package/dist/super-editor/file-zipper.es.js +1 -1
  23. package/dist/super-editor/src/core/DocxZipper.d.ts +1 -1
  24. package/dist/super-editor/src/core/helpers/generateDocxRandomId.d.ts +5 -0
  25. package/dist/super-editor/src/core/super-converter/SuperConverter.d.ts +1 -13
  26. package/dist/super-editor/src/core/super-converter/exporter.d.ts +5 -4
  27. package/dist/super-editor/src/core/super-converter/field-references/fld-preprocessors/hyperlink-preprocessor.d.ts +9 -0
  28. package/dist/super-editor/src/core/super-converter/field-references/fld-preprocessors/index.d.ts +2 -0
  29. package/dist/super-editor/src/core/super-converter/field-references/fld-preprocessors/num-pages-preprocessor.d.ts +9 -0
  30. package/dist/super-editor/src/core/super-converter/field-references/fld-preprocessors/page-preprocessor.d.ts +9 -0
  31. package/dist/super-editor/src/core/super-converter/field-references/fld-preprocessors/page-ref-preprocessor.d.ts +9 -0
  32. package/dist/super-editor/src/core/super-converter/field-references/fld-preprocessors/toc-preprocessor.d.ts +8 -0
  33. package/dist/super-editor/src/core/super-converter/field-references/index.d.ts +1 -0
  34. package/dist/super-editor/src/core/super-converter/field-references/preProcessNodesForFldChar.d.ts +21 -0
  35. package/dist/super-editor/src/core/super-converter/helpers/tableFallbackHelpers.d.ts +24 -0
  36. package/dist/super-editor/src/core/super-converter/v2/exporter/helpers/translateChildNodes.d.ts +3 -3
  37. package/dist/super-editor/src/core/super-converter/v2/importer/pageReferenceImporter.d.ts +4 -0
  38. package/dist/super-editor/src/core/super-converter/v2/importer/tableOfContentsImporter.d.ts +4 -0
  39. package/dist/super-editor/src/core/super-converter/v2/types/index.d.ts +7 -1
  40. package/dist/super-editor/src/core/super-converter/v3/handlers/sd/pageReference/index.d.ts +1 -0
  41. package/dist/super-editor/src/core/super-converter/v3/handlers/sd/pageReference/pageReference-translator.d.ts +7 -0
  42. package/dist/super-editor/src/core/super-converter/v3/handlers/sd/tableOfContents/index.d.ts +1 -0
  43. package/dist/super-editor/src/core/super-converter/v3/handlers/sd/tableOfContents/tableOfContents-translator.d.ts +10 -0
  44. package/dist/super-editor/src/core/super-converter/v3/handlers/w/caps/caps-translator.d.ts +7 -0
  45. package/dist/super-editor/src/core/super-converter/v3/handlers/w/p/helpers/w-p-helpers.d.ts +0 -2
  46. package/dist/super-editor/src/core/super-converter/v3/handlers/w/sdt/helpers/handle-doc-part-obj.d.ts +9 -1
  47. package/dist/super-editor/src/core/super-converter/v3/handlers/w/sdt/helpers/translate-document-part-obj.d.ts +6 -0
  48. package/dist/super-editor/src/core/super-converter/v3/node-translator/node-translator.d.ts +2 -2
  49. package/dist/super-editor/src/extensions/custom-selection/custom-selection.d.ts +5 -1
  50. package/dist/super-editor/src/extensions/index.d.ts +2 -1
  51. package/dist/super-editor/src/extensions/page-reference/index.d.ts +1 -0
  52. package/dist/super-editor/src/extensions/page-reference/page-reference.d.ts +2 -0
  53. package/dist/super-editor/src/extensions/structured-content/document-part-object.d.ts +2 -0
  54. package/dist/super-editor/src/extensions/structured-content/index.d.ts +2 -0
  55. package/dist/super-editor/src/extensions/structured-content/structured-content-commands.d.ts +67 -0
  56. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentBlockTags.d.ts +6 -0
  57. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentInlineTags.d.ts +6 -0
  58. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentTags.d.ts +6 -0
  59. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentTagsById.d.ts +7 -0
  60. package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/index.d.ts +4 -0
  61. package/dist/super-editor/src/extensions/tab/helpers/tabDecorations.d.ts +2 -2
  62. package/dist/super-editor/src/extensions/table-of-contents/index.d.ts +1 -0
  63. package/dist/super-editor/src/extensions/table-of-contents/table-of-contents.d.ts +2 -0
  64. package/dist/super-editor/src/utils/contextmenu-helpers.d.ts +24 -0
  65. package/dist/super-editor/style.css +7 -0
  66. package/dist/super-editor/super-editor.es.js +11 -17
  67. package/dist/super-editor/toolbar.es.js +2 -2
  68. package/dist/super-editor.cjs +1 -1
  69. package/dist/super-editor.es.js +1 -1
  70. package/dist/superdoc.cjs +2 -2
  71. package/dist/superdoc.es.js +2 -2
  72. package/dist/superdoc.umd.js +3245 -2026
  73. package/dist/superdoc.umd.js.map +1 -1
  74. package/package.json +1 -1
  75. package/dist/super-editor/src/components/slash-menu/contextmenu-helpers.d.ts +0 -1
@@ -9,12 +9,12 @@ 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 __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
11
11
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
12
- var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, registerPluginByNameIfNotExists_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, initPagination_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _ListItemNodeView_instances, init_fn2, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn, _DocumentSectionView_instances, init_fn3, addToolTip_fn;
12
+ var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, registerPluginByNameIfNotExists_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, initPagination_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _DocumentSectionView_instances, init_fn2, addToolTip_fn, _ListItemNodeView_instances, init_fn3, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn;
13
13
  import * as Y from "yjs";
14
14
  import { UndoManager, Item as Item$1, ContentType, Text as Text$1, XmlElement, encodeStateAsUpdate } from "yjs";
15
- import { P as PluginKey, a as Plugin, M as Mapping, N as NodeSelection, S as Selection, T as TextSelection, b as Slice, D as DOMSerializer, F as Fragment, c as DOMParser$1, d as Mark$1, e as dropPoint, A as AllSelection, p as process$1, B as Buffer2, f as callOrGet, g as getExtensionConfigField, h as getMarkType, i as getMarksFromSelection, j as getNodeType, k as getSchemaTypeNameByName, l as Schema$1, m as cleanSchemaItem, n as canSplit, o as defaultBlockAt$1, q as liftTarget, r as canJoin, s as joinPoint, t as replaceStep$1, R as ReplaceAroundStep$1, u as isTextSelection, v as getMarkRange, w as isMarkActive, x as isNodeActive, y as deleteProps, z as processContent, C as ReplaceStep, E as NodeRange, G as findWrapping, L as ListHelpers, H as findParentNode, I as isMacOS, J as isIOS, K as getSchemaTypeByName, O as inputRulesPlugin, Q as TrackDeleteMarkName, U as TrackInsertMarkName, V as v4, W as TrackFormatMarkName, X as comments_module_events, Y as findMark, Z as objectIncludes, _ as AddMarkStep, $ as RemoveMarkStep, a0 as twipsToLines, a1 as pixelsToTwips, a2 as helpers, a3 as posToDOMRect, a4 as CommandService, a5 as SuperConverter, a6 as createDocument, a7 as createDocFromMarkdown, a8 as createDocFromHTML, a9 as EditorState, aa as hasSomeParentWithClass, ab as isActive, ac as unflattenListsInHtml, ad as parseSizeUnit, ae as minMax, af as getLineHeightValueString, ag as InputRule, ah as kebabCase, ai as findParentNodeClosestToPos, aj as getListItemStyleDefinitions, ak as docxNumberigHelpers, al as parseIndentElement, am as combineIndents, an as SelectionRange, ao as Transform, ap as isInTable$1, aq as generateDocxRandomId, ar as insertNewRelationship, as as updateDOMAttributes, at as htmlHandler } from "./converter-BcqEfCTg.js";
15
+ import { P as PluginKey, a as Plugin, M as Mapping, N as NodeSelection, S as Selection, T as TextSelection, b as Slice, D as DOMSerializer, F as Fragment, c as DOMParser$1, d as Mark$1, e as dropPoint, A as AllSelection, p as process$1, B as Buffer2, f as callOrGet, g as getExtensionConfigField, h as getMarkType, i as getMarksFromSelection, j as getNodeType, k as getSchemaTypeNameByName, l as Schema$1, m as cleanSchemaItem, n as canSplit, o as defaultBlockAt$1, q as liftTarget, r as canJoin, s as joinPoint, t as replaceStep$1, R as ReplaceAroundStep$1, u as isTextSelection, v as getMarkRange, w as isMarkActive, x as isNodeActive, y as deleteProps, z as processContent, C as ReplaceStep, E as NodeRange, G as findWrapping, L as ListHelpers, H as findParentNode, I as isMacOS, J as isIOS, K as getSchemaTypeByName, O as inputRulesPlugin, Q as TrackDeleteMarkName, U as TrackInsertMarkName, V as v4, W as TrackFormatMarkName, X as comments_module_events, Y as findMark, Z as objectIncludes, _ as AddMarkStep, $ as RemoveMarkStep, a0 as twipsToLines, a1 as pixelsToTwips, a2 as helpers, a3 as posToDOMRect, a4 as CommandService, a5 as SuperConverter, a6 as createDocument, a7 as createDocFromMarkdown, a8 as createDocFromHTML, a9 as EditorState, aa as hasSomeParentWithClass, ab as isActive, ac as unflattenListsInHtml, ad as parseSizeUnit, ae as minMax, af as getLineHeightValueString, ag as updateDOMAttributes, ah as findChildren$5, ai as htmlHandler, aj as generateRandomSigned32BitIntStrId, ak as InputRule, al as kebabCase, am as findParentNodeClosestToPos, an as getListItemStyleDefinitions, ao as docxNumberigHelpers, ap as parseIndentElement, aq as combineIndents, ar as SelectionRange, as as Transform, at as isInTable$1, au as generateDocxRandomId, av as insertNewRelationship } from "./converter-DFDRdFEB.js";
16
16
  import { ref, computed, createElementBlock, openBlock, withModifiers, Fragment as Fragment$1, renderList, normalizeClass, createCommentVNode, toDisplayString, createElementVNode, createApp } from "vue";
17
- import { D as DocxZipper } from "./docx-zipper-DZ9ph0iQ.js";
17
+ import { D as DocxZipper } from "./docx-zipper-CplUdgI9.js";
18
18
  var GOOD_LEAF_SIZE = 200;
19
19
  var RopeSequence = function RopeSequence2() {
20
20
  };
@@ -11675,9 +11675,11 @@ const toggleHeaderFooterEditMode = ({ editor, focusedSectionEditor, isEditMode,
11675
11675
  item.editor.view.dom.setAttribute("documentmode", documentMode);
11676
11676
  });
11677
11677
  if (isEditMode) {
11678
- const pm = document.querySelector(".ProseMirror");
11679
- pm.classList.add("header-footer-edit");
11680
- pm.setAttribute("aria-readonly", true);
11678
+ const pm = editor.view?.dom || editor.options.element?.querySelector?.(".ProseMirror");
11679
+ if (pm) {
11680
+ pm.classList.add("header-footer-edit");
11681
+ pm.setAttribute("aria-readonly", true);
11682
+ }
11681
11683
  }
11682
11684
  if (focusedSectionEditor) {
11683
11685
  focusedSectionEditor.view.focus();
@@ -12105,28 +12107,25 @@ const handleTrackedChangeTransaction = (trackedChangeMeta, trackedChanges, newEd
12105
12107
  if (emitParams) editor.emit("commentsUpdate", emitParams);
12106
12108
  return newTrackedChanges;
12107
12109
  };
12108
- const getTrackedChangeText = ({ state, node, mark, marks, trackedChangeType, isDeletionInsertion }) => {
12110
+ const getTrackedChangeText = ({ nodes, mark, trackedChangeType, isDeletionInsertion }) => {
12109
12111
  let trackedChangeText = "";
12110
12112
  let deletionText = "";
12111
12113
  if (trackedChangeType === TrackInsertMarkName) {
12112
- trackedChangeText = node?.text ?? "";
12114
+ trackedChangeText = nodes.reduce((acc, node) => {
12115
+ if (!node.marks.find((nodeMark) => nodeMark.type.name === mark.type.name)) return acc;
12116
+ acc += node?.text || node?.textContent || "";
12117
+ return acc;
12118
+ }, "");
12113
12119
  }
12114
12120
  if (trackedChangeType === TrackFormatMarkName) {
12115
12121
  trackedChangeText = translateFormatChangesToEnglish(mark.attrs);
12116
12122
  }
12117
12123
  if (trackedChangeType === TrackDeleteMarkName || isDeletionInsertion) {
12118
- deletionText = node?.text ?? "";
12119
- if (isDeletionInsertion) {
12120
- let { id } = marks.deletionMark.attrs;
12121
- let deletionNode = findNode$1(state.doc, (node2) => {
12122
- const { marks: marks2 = [] } = node2;
12123
- const changeMarks = marks2.filter((mark2) => TRACK_CHANGE_MARKS.includes(mark2.type.name));
12124
- if (!changeMarks.length) return false;
12125
- const hasMatchingId = changeMarks.find((mark2) => mark2.attrs.id === id);
12126
- if (hasMatchingId) return true;
12127
- });
12128
- deletionText = deletionNode?.node.text ?? "";
12129
- }
12124
+ deletionText = nodes.reduce((acc, node) => {
12125
+ if (!node.marks.find((nodeMark) => nodeMark.type.name === TrackDeleteMarkName)) return acc;
12126
+ acc += node?.text || node?.textContent || "";
12127
+ return acc;
12128
+ }, "");
12130
12129
  }
12131
12130
  return {
12132
12131
  deletionText,
@@ -12141,20 +12140,17 @@ const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes
12141
12140
  const id = attrs.id;
12142
12141
  const node = nodes[0];
12143
12142
  const isDeletionInsertion = !!(marks.insertedMark && marks.deletionMark);
12144
- let existingNode;
12143
+ let nodesWithMark = [];
12145
12144
  newEditorState.doc.descendants((node2) => {
12146
12145
  const { marks: marks2 = [] } = node2;
12147
12146
  const changeMarks = marks2.filter((mark) => TRACK_CHANGE_MARKS.includes(mark.type.name));
12148
12147
  if (!changeMarks.length) return;
12149
12148
  const hasMatchingId = changeMarks.find((mark) => mark.attrs.id === id);
12150
- if (hasMatchingId) existingNode = node2;
12151
- if (existingNode) return false;
12149
+ if (hasMatchingId) nodesWithMark.push(node2);
12152
12150
  });
12153
12151
  const { deletionText, trackedChangeText } = getTrackedChangeText({
12154
- state: newEditorState,
12155
- node: existingNode || node,
12152
+ nodes: nodesWithMark.length ? nodesWithMark : [node],
12156
12153
  mark: trackedMark,
12157
- marks,
12158
12154
  trackedChangeType,
12159
12155
  isDeletionInsertion
12160
12156
  });
@@ -12182,14 +12178,6 @@ const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes
12182
12178
  else if (event === "update") params2.event = comments_module_events.UPDATE;
12183
12179
  return params2;
12184
12180
  };
12185
- function findNode$1(node, predicate) {
12186
- let found = null;
12187
- node.descendants((node2, pos) => {
12188
- if (predicate(node2)) found = { node: node2, pos };
12189
- if (found) return false;
12190
- });
12191
- return found;
12192
- }
12193
12181
  function findRangeById(doc2, id) {
12194
12182
  let from2 = null, to = null;
12195
12183
  doc2.descendants((node, pos) => {
@@ -12707,6 +12695,7 @@ const generateTableIfNecessary = ({ tableNode, annotationValues, tr, state }) =>
12707
12695
  const mappedRowStart = tr.mapping.map(absoluteRowStart);
12708
12696
  const rowEnd = mappedRowStart + rowNode.nodeSize;
12709
12697
  tr.replaceWith(mappedRowStart, rowEnd, Fragment.from(newRows));
12698
+ tr.setMeta("tableGeneration", true);
12710
12699
  } catch (error) {
12711
12700
  console.error("Error during row generation:", error);
12712
12701
  throw error;
@@ -13111,7 +13100,7 @@ function findFieldAnnotationsBetween(from2, to, doc2) {
13111
13100
  }
13112
13101
  function findRemovedFieldAnnotations(tr) {
13113
13102
  let removedNodes = [];
13114
- if (!tr.steps.length || tr.meta && !Object.keys(tr.meta).every((meta) => ["inputType", "uiEvent", "paste"].includes(meta)) || ["historyUndo", "historyRedo"].includes(tr.getMeta("inputType")) || ["drop"].includes(tr.getMeta("uiEvent")) || tr.getMeta("fieldAnnotationUpdate") === true) {
13103
+ if (!tr.steps.length || tr.meta && !Object.keys(tr.meta).every((meta) => ["inputType", "uiEvent", "paste"].includes(meta)) || ["historyUndo", "historyRedo"].includes(tr.getMeta("inputType")) || ["drop"].includes(tr.getMeta("uiEvent")) || tr.getMeta("fieldAnnotationUpdate") === true || tr.getMeta("tableGeneration") === true) {
13115
13104
  return removedNodes;
13116
13105
  }
13117
13106
  const hasDeletion = transactionDeletedAnything(tr);
@@ -14332,7 +14321,7 @@ const _Editor = class _Editor extends EventEmitter {
14332
14321
  setDocumentMode(documentMode) {
14333
14322
  let cleanedMode = documentMode?.toLowerCase() || "editing";
14334
14323
  if (!this.extensionService || !this.state) return;
14335
- const pm = document.querySelector(".ProseMirror");
14324
+ const pm = this.view?.dom || this.options.element?.querySelector?.(".ProseMirror");
14336
14325
  if (this.options.role === "viewer") cleanedMode = "viewing";
14337
14326
  if (this.options.role === "suggester" && cleanedMode === "editing") cleanedMode = "suggesting";
14338
14327
  if (cleanedMode === "viewing") {
@@ -14820,7 +14809,8 @@ const _Editor = class _Editor extends EventEmitter {
14820
14809
  files: this.options.content
14821
14810
  },
14822
14811
  media,
14823
- true
14812
+ true,
14813
+ updatedDocs
14824
14814
  );
14825
14815
  return updatedDocs;
14826
14816
  }
@@ -15380,9 +15370,11 @@ createView_fn = function(element) {
15380
15370
  isEditMode: false,
15381
15371
  documentMode: this.options.documentMode
15382
15372
  });
15383
- const pm = document.querySelector(".ProseMirror");
15384
- pm.classList.remove("header-footer-edit");
15385
- pm.setAttribute("aria-readonly", false);
15373
+ const pm = this.view?.dom || this.options.element?.querySelector?.(".ProseMirror");
15374
+ if (pm) {
15375
+ pm.classList.remove("header-footer-edit");
15376
+ pm.setAttribute("aria-readonly", false);
15377
+ }
15386
15378
  }
15387
15379
  setWordSelection(view, pos);
15388
15380
  }
@@ -16973,221 +16965,1258 @@ const SlashMenu = Extension.create({
16973
16965
  return this.editor.options.isHeadless ? [] : [slashMenuPlugin];
16974
16966
  }
16975
16967
  });
16976
- const Document = Node$1.create({
16977
- name: "doc",
16978
- topNode: true,
16979
- content: "block+",
16980
- parseDOM() {
16981
- return [{ tag: "doc" }];
16982
- },
16983
- renderDOM() {
16984
- return ["doc", 0];
16985
- },
16986
- addAttributes() {
16987
- return {
16988
- attributes: {
16989
- rendered: false,
16990
- "aria-label": "Document node"
16991
- }
16992
- };
16993
- },
16994
- addCommands() {
16995
- return {
16996
- /**
16997
- * Get document statistics
16998
- * @category Command
16999
- * @example
17000
- * // Get word and character count
17001
- * const stats = editor.commands.getDocumentStats()
17002
- * console.log(`${stats.words} words, ${stats.characters} characters`)
17003
- * @note Returns word count, character count, and paragraph count
17004
- */
17005
- getDocumentStats: () => ({ editor }) => {
17006
- const text = editor.getText();
17007
- const words = text.split(/\s+/).filter((word) => word.length > 0).length;
17008
- const characters = text.length;
17009
- const paragraphs = editor.state.doc.content.childCount;
17010
- return {
17011
- words,
17012
- characters,
17013
- paragraphs
17014
- };
17015
- },
17016
- /**
17017
- * Clear entire document
17018
- * @category Command
17019
- * @example
17020
- * editor.commands.clearDocument()
17021
- * @note Replaces all content with an empty paragraph
17022
- */
17023
- clearDocument: () => ({ commands: commands2 }) => {
17024
- return commands2.setContent("<p></p>");
16968
+ class StructuredContentViewBase {
16969
+ constructor(props) {
16970
+ __publicField(this, "node");
16971
+ __publicField(this, "view");
16972
+ __publicField(this, "getPos");
16973
+ __publicField(this, "decorations");
16974
+ __publicField(this, "innerDecorations");
16975
+ __publicField(this, "editor");
16976
+ __publicField(this, "extension");
16977
+ __publicField(this, "htmlAttributes");
16978
+ __publicField(this, "root");
16979
+ __publicField(this, "isDragging", false);
16980
+ this.node = props.node;
16981
+ this.view = props.editor.view;
16982
+ this.getPos = props.getPos;
16983
+ this.decorations = props.decorations;
16984
+ this.innerDecorations = props.innerDecorations;
16985
+ this.editor = props.editor;
16986
+ this.extension = props.extension;
16987
+ this.htmlAttributes = props.htmlAttributes;
16988
+ this.mount(props);
16989
+ }
16990
+ mount() {
16991
+ return;
16992
+ }
16993
+ get dom() {
16994
+ return this.root;
16995
+ }
16996
+ get contentDOM() {
16997
+ return null;
16998
+ }
16999
+ update(node, decorations, innerDecorations) {
17000
+ if (node.type !== this.node.type) {
17001
+ return false;
17002
+ }
17003
+ this.node = node;
17004
+ this.decorations = decorations;
17005
+ this.innerDecorations = innerDecorations;
17006
+ this.updateHTMLAttributes();
17007
+ return true;
17008
+ }
17009
+ stopEvent(event) {
17010
+ if (!this.dom) return false;
17011
+ const target = event.target;
17012
+ const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
17013
+ if (!isInElement) return false;
17014
+ const isDragEvent = event.type.startsWith("drag");
17015
+ const isDropEvent = event.type === "drop";
17016
+ const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
17017
+ if (isInput && !isDropEvent && !isDragEvent) return true;
17018
+ const { isEditable } = this.editor;
17019
+ const { isDragging } = this;
17020
+ const isDraggable = !!this.node.type.spec.draggable;
17021
+ const isSelectable = NodeSelection.isSelectable(this.node);
17022
+ const isCopyEvent = event.type === "copy";
17023
+ const isPasteEvent = event.type === "paste";
17024
+ const isCutEvent = event.type === "cut";
17025
+ const isClickEvent = event.type === "mousedown";
17026
+ if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
17027
+ event.preventDefault();
17028
+ }
17029
+ if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
17030
+ event.preventDefault();
17031
+ return false;
17032
+ }
17033
+ if (isDraggable && isEditable && !isDragging && isClickEvent) {
17034
+ const dragHandle = target.closest("[data-drag-handle]");
17035
+ const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
17036
+ if (isValidDragHandle) {
17037
+ this.isDragging = true;
17038
+ document.addEventListener(
17039
+ "dragend",
17040
+ () => {
17041
+ this.isDragging = false;
17042
+ },
17043
+ { once: true }
17044
+ );
17045
+ document.addEventListener(
17046
+ "drop",
17047
+ () => {
17048
+ this.isDragging = false;
17049
+ },
17050
+ { once: true }
17051
+ );
17052
+ document.addEventListener(
17053
+ "mouseup",
17054
+ () => {
17055
+ this.isDragging = false;
17056
+ },
17057
+ { once: true }
17058
+ );
17025
17059
  }
17026
- };
17060
+ }
17061
+ if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
17062
+ return false;
17063
+ }
17064
+ return true;
17027
17065
  }
17028
- });
17029
- const Text = Node$1.create({
17030
- name: "text",
17031
- group: "inline",
17032
- inline: true,
17033
- addOptions() {
17034
- return {};
17066
+ ignoreMutation(mutation) {
17067
+ if (!this.dom || !this.contentDOM) return true;
17068
+ if (this.node.isLeaf || this.node.isAtom) return true;
17069
+ if (mutation.type === "selection") return false;
17070
+ if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
17071
+ if (this.contentDOM.contains(mutation.target)) return false;
17072
+ return true;
17035
17073
  }
17036
- });
17037
- const splitRun = () => (props) => {
17038
- const { state, view, tr } = props;
17039
- const { $from, empty: empty2 } = state.selection;
17040
- if (!empty2) return false;
17041
- if ($from.parent.type.name !== "run") return false;
17042
- const handled = splitBlock(state, (transaction) => {
17074
+ destroy() {
17075
+ this.dom.remove();
17076
+ this.contentDOM?.remove();
17077
+ }
17078
+ updateAttributes(attrs) {
17079
+ const pos = this.getPos();
17080
+ if (typeof pos !== "number") {
17081
+ return;
17082
+ }
17083
+ return this.view.dispatch(
17084
+ this.view.state.tr.setNodeMarkup(pos, void 0, {
17085
+ ...this.node.attrs,
17086
+ ...attrs
17087
+ })
17088
+ );
17089
+ }
17090
+ updateHTMLAttributes() {
17091
+ const { extensionService } = this.editor;
17092
+ const { attributes } = extensionService;
17093
+ const extensionAttrs = attributes.filter((i) => i.type === this.node.type.name);
17094
+ this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
17095
+ }
17096
+ createDragHandle() {
17097
+ const dragHandle = document.createElement("span");
17098
+ dragHandle.classList.add("sd-structured-content-draggable");
17099
+ dragHandle.draggable = true;
17100
+ dragHandle.contentEditable = "false";
17101
+ dragHandle.dataset.dragHandle = "";
17102
+ const textElement = document.createElement("span");
17103
+ textElement.textContent = this.node.attrs.alias || "Structured content";
17104
+ dragHandle.append(textElement);
17105
+ return dragHandle;
17106
+ }
17107
+ onDragStart(event) {
17108
+ const { view } = this.editor;
17109
+ const target = event.target;
17110
+ const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
17111
+ if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
17112
+ return;
17113
+ }
17114
+ let x = 0;
17115
+ let y = 0;
17116
+ if (this.dom !== dragHandle) {
17117
+ const domBox = this.dom.getBoundingClientRect();
17118
+ const handleBox = dragHandle.getBoundingClientRect();
17119
+ const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
17120
+ const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
17121
+ x = handleBox.x - domBox.x + offsetX;
17122
+ y = handleBox.y - domBox.y + offsetY;
17123
+ }
17124
+ event.dataTransfer?.setDragImage(this.dom, x, y);
17125
+ const pos = this.getPos();
17126
+ if (typeof pos !== "number") {
17127
+ return;
17128
+ }
17129
+ const selection = NodeSelection.create(view.state.doc, pos);
17130
+ const transaction = view.state.tr.setSelection(selection);
17043
17131
  view.dispatch(transaction);
17044
- });
17045
- if (handled) {
17046
- tr.setMeta("preventDispatch", true);
17047
17132
  }
17048
- return handled;
17049
- };
17050
- const Run = OxmlNode.create({
17051
- name: "run",
17052
- oXmlName: "w:r",
17053
- group: "inline",
17133
+ }
17134
+ class StructuredContentInlineView extends StructuredContentViewBase {
17135
+ constructor(props) {
17136
+ super(props);
17137
+ }
17138
+ mount() {
17139
+ this.buildView();
17140
+ }
17141
+ get contentDOM() {
17142
+ const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
17143
+ return contentElement || null;
17144
+ }
17145
+ createElement() {
17146
+ const element = document.createElement("span");
17147
+ element.classList.add(structuredContentClass$1);
17148
+ element.setAttribute("data-structured-content", "");
17149
+ const contentElement = document.createElement("span");
17150
+ contentElement.classList.add(structuredContentInnerClass$1);
17151
+ element.append(contentElement);
17152
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
17153
+ updateDOMAttributes(element, { ...domAttrs });
17154
+ return { element, contentElement };
17155
+ }
17156
+ buildView() {
17157
+ const { element } = this.createElement();
17158
+ const dragHandle = this.createDragHandle();
17159
+ element.prepend(dragHandle);
17160
+ element.addEventListener("dragstart", (e) => this.onDragStart(e));
17161
+ this.root = element;
17162
+ }
17163
+ updateView() {
17164
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
17165
+ updateDOMAttributes(this.dom, { ...domAttrs });
17166
+ }
17167
+ update(node, decorations, innerDecorations) {
17168
+ const result = super.update(node, decorations, innerDecorations);
17169
+ if (!result) return false;
17170
+ this.updateView();
17171
+ return true;
17172
+ }
17173
+ }
17174
+ const structuredContentClass$1 = "sd-structured-content";
17175
+ const structuredContentInnerClass$1 = "sd-structured-content__content";
17176
+ const StructuredContent = Node$1.create({
17177
+ name: "structuredContent",
17178
+ group: "inline structuredContent",
17054
17179
  inline: true,
17055
17180
  content: "inline*",
17056
- selectable: false,
17057
- childToAttributes: ["runProperties"],
17181
+ isolating: true,
17182
+ atom: false,
17183
+ // false - has editable content.
17184
+ draggable: true,
17058
17185
  addOptions() {
17059
17186
  return {
17060
17187
  htmlAttributes: {
17061
- "data-run": "1"
17188
+ class: structuredContentClass$1,
17189
+ "aria-label": "Structured content node"
17062
17190
  }
17063
17191
  };
17064
17192
  },
17065
17193
  addAttributes() {
17066
17194
  return {
17067
- runProperties: {
17195
+ id: {
17068
17196
  default: null,
17069
- rendered: false,
17070
- keepOnSplit: true
17197
+ parseDOM: (elem) => elem.getAttribute("data-id"),
17198
+ renderDOM: (attrs) => {
17199
+ if (!attrs.id) return {};
17200
+ return { "data-id": attrs.id };
17201
+ }
17071
17202
  },
17072
- rsidR: {
17203
+ tag: {
17073
17204
  default: null,
17074
- rendered: false,
17075
- keepOnSplit: true
17205
+ parseDOM: (elem) => elem.getAttribute("data-tag"),
17206
+ renderDOM: (attrs) => {
17207
+ if (!attrs.tag) return {};
17208
+ return { "data-tag": attrs.tag };
17209
+ }
17076
17210
  },
17077
- rsidRPr: {
17211
+ alias: {
17078
17212
  default: null,
17079
- rendered: false,
17080
- keepOnSplit: true
17213
+ parseDOM: (elem) => elem.getAttribute("data-alias"),
17214
+ renderDOM: (attrs) => {
17215
+ if (!attrs.alias) return {};
17216
+ return { "data-alias": attrs.alias };
17217
+ }
17081
17218
  },
17082
- rsidDel: {
17083
- default: null,
17084
- rendered: false,
17085
- keepOnSplit: true
17219
+ sdtPr: {
17220
+ rendered: false
17086
17221
  }
17087
17222
  };
17088
17223
  },
17089
- addCommands() {
17090
- return {
17091
- splitRun
17092
- };
17093
- },
17094
17224
  parseDOM() {
17095
- return [{ tag: "span[data-run]" }];
17225
+ return [{ tag: "span[data-structured-content]" }];
17096
17226
  },
17097
17227
  renderDOM({ htmlAttributes }) {
17098
- const base2 = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
17099
- return ["span", base2, 0];
17228
+ return [
17229
+ "span",
17230
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
17231
+ "data-structured-content": ""
17232
+ }),
17233
+ 0
17234
+ ];
17235
+ },
17236
+ addNodeView() {
17237
+ return (props) => {
17238
+ return new StructuredContentInlineView({ ...props });
17239
+ };
17100
17240
  }
17101
17241
  });
17102
- const inputRegex$1 = /^\s*([-+*])\s$/;
17103
- const BulletList = Node$1.create({
17104
- name: "bulletList",
17105
- group: "block list",
17106
- selectable: false,
17107
- content() {
17108
- return `${this.options.itemTypeName}+`;
17109
- },
17242
+ class StructuredContentBlockView extends StructuredContentViewBase {
17243
+ constructor(props) {
17244
+ super(props);
17245
+ }
17246
+ mount() {
17247
+ this.buildView();
17248
+ }
17249
+ get contentDOM() {
17250
+ const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass}`);
17251
+ return contentElement || null;
17252
+ }
17253
+ createElement() {
17254
+ const element = document.createElement("div");
17255
+ element.classList.add(structuredContentClass);
17256
+ element.setAttribute("data-structured-content-block", "");
17257
+ const contentElement = document.createElement("div");
17258
+ contentElement.classList.add(structuredContentInnerClass);
17259
+ element.append(contentElement);
17260
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
17261
+ updateDOMAttributes(element, { ...domAttrs });
17262
+ return { element, contentElement };
17263
+ }
17264
+ buildView() {
17265
+ const { element } = this.createElement();
17266
+ const dragHandle = this.createDragHandle();
17267
+ element.prepend(dragHandle);
17268
+ element.addEventListener("dragstart", (e) => this.onDragStart(e));
17269
+ this.root = element;
17270
+ }
17271
+ updateView() {
17272
+ const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
17273
+ updateDOMAttributes(this.dom, { ...domAttrs });
17274
+ }
17275
+ update(node, decorations, innerDecorations) {
17276
+ const result = super.update(node, decorations, innerDecorations);
17277
+ if (!result) return false;
17278
+ this.updateView();
17279
+ return true;
17280
+ }
17281
+ }
17282
+ const structuredContentClass = "sd-structured-content-block";
17283
+ const structuredContentInnerClass = "sd-structured-content-block__content";
17284
+ const StructuredContentBlock = Node$1.create({
17285
+ name: "structuredContentBlock",
17286
+ group: "block structuredContent",
17287
+ content: "block*",
17288
+ isolating: true,
17289
+ atom: false,
17290
+ // false - has editable content.
17291
+ draggable: true,
17110
17292
  addOptions() {
17111
17293
  return {
17112
- itemTypeName: "listItem",
17113
17294
  htmlAttributes: {
17114
- "aria-label": "Bullet list node"
17115
- },
17116
- keepMarks: true,
17117
- keepAttributes: false
17295
+ class: structuredContentClass,
17296
+ "aria-label": "Structured content block node"
17297
+ }
17118
17298
  };
17119
17299
  },
17120
- parseDOM() {
17121
- return [{ tag: "ul" }];
17122
- },
17123
- renderDOM({ htmlAttributes }) {
17124
- const attributes = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
17125
- return ["ul", attributes, 0];
17126
- },
17127
17300
  addAttributes() {
17128
17301
  return {
17129
- "list-style-type": {
17130
- default: "bullet",
17131
- rendered: false
17302
+ id: {
17303
+ default: null,
17304
+ parseDOM: (elem) => elem.getAttribute("data-id"),
17305
+ renderDOM: (attrs) => {
17306
+ if (!attrs.id) return {};
17307
+ return { "data-id": attrs.id };
17308
+ }
17132
17309
  },
17133
- listId: {
17134
- rendered: false
17310
+ tag: {
17311
+ default: null,
17312
+ parseDOM: (elem) => elem.getAttribute("data-tag"),
17313
+ renderDOM: (attrs) => {
17314
+ if (!attrs.tag) return {};
17315
+ return { "data-tag": attrs.tag };
17316
+ }
17135
17317
  },
17136
- sdBlockId: {
17318
+ alias: {
17137
17319
  default: null,
17138
- keepOnSplit: false,
17139
- parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
17320
+ parseDOM: (elem) => elem.getAttribute("data-alias"),
17140
17321
  renderDOM: (attrs) => {
17141
- return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
17322
+ if (!attrs.alias) return {};
17323
+ return { "data-alias": attrs.alias };
17142
17324
  }
17143
17325
  },
17144
- attributes: {
17145
- rendered: false,
17146
- keepOnSplit: true
17326
+ sdtPr: {
17327
+ rendered: false
17147
17328
  }
17148
17329
  };
17149
17330
  },
17331
+ parseDOM() {
17332
+ return [{ tag: "div[data-structured-content-block]" }];
17333
+ },
17334
+ renderDOM({ htmlAttributes }) {
17335
+ return [
17336
+ "div",
17337
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
17338
+ "data-structured-content-block": ""
17339
+ }),
17340
+ 0
17341
+ ];
17342
+ },
17343
+ addNodeView() {
17344
+ return (props) => {
17345
+ return new StructuredContentBlockView({ ...props });
17346
+ };
17347
+ }
17348
+ });
17349
+ function getStructuredContentTagsById(idOrIds, state) {
17350
+ const result = findChildren$5(state.doc, (node) => {
17351
+ const isStructuredContent = ["structuredContent", "structuredContentBlock"].includes(node.type.name);
17352
+ if (Array.isArray(idOrIds)) {
17353
+ return isStructuredContent && idOrIds.includes(node.attrs.id);
17354
+ } else {
17355
+ return isStructuredContent && node.attrs.id === idOrIds;
17356
+ }
17357
+ });
17358
+ return result;
17359
+ }
17360
+ function getStructuredContentTags(state) {
17361
+ const result = findChildren$5(state.doc, (node) => {
17362
+ return node.type.name === "structuredContent" || node.type.name === "structuredContentBlock";
17363
+ });
17364
+ return result;
17365
+ }
17366
+ function getStructuredContentInlineTags(state) {
17367
+ const result = findChildren$5(state.doc, (node) => node.type.name === "structuredContent");
17368
+ return result;
17369
+ }
17370
+ function getStructuredContentBlockTags(state) {
17371
+ const result = findChildren$5(state.doc, (node) => node.type.name === "structuredContentBlock");
17372
+ return result;
17373
+ }
17374
+ const structuredContentHelpers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
17375
+ __proto__: null,
17376
+ getStructuredContentBlockTags,
17377
+ getStructuredContentInlineTags,
17378
+ getStructuredContentTags,
17379
+ getStructuredContentTagsById
17380
+ }, Symbol.toStringTag, { value: "Module" }));
17381
+ const STRUCTURED_CONTENT_NAMES = ["structuredContent", "structuredContentBlock"];
17382
+ const StructuredContentCommands = Extension.create({
17383
+ name: "structuredContentCommands",
17150
17384
  addCommands() {
17151
17385
  return {
17152
17386
  /**
17153
- * Toggle a bullet list at the current selection
17387
+ * Inserts a structured content inline at selection.
17154
17388
  * @category Command
17155
- * @example
17156
- * // Toggle bullet list on selected text
17157
- * editor.commands.toggleBulletList()
17158
- * @note Converts selected paragraphs to list items or removes list formatting
17389
+ * @param {StructuredContentInlineInsert} options
17159
17390
  */
17160
- toggleBulletList: () => (params2) => {
17161
- return toggleList(this.type)(params2);
17162
- }
17163
- };
17164
- },
17165
- addShortcuts() {
17166
- return {
17167
- "Mod-Shift-8": () => {
17168
- return this.editor.commands.toggleBulletList();
17169
- }
17170
- };
17171
- },
17172
- addInputRules() {
17173
- return [
17174
- new InputRule({
17175
- match: inputRegex$1,
17176
- handler: ({ state, range }) => {
17177
- const $pos = state.selection.$from;
17178
- const listItemType = state.schema.nodes.listItem;
17179
- for (let depth = $pos.depth; depth >= 0; depth--) {
17180
- if ($pos.node(depth).type === listItemType) {
17181
- return null;
17182
- }
17391
+ insertStructuredContentInline: (options = {}) => ({ editor, dispatch, state, tr }) => {
17392
+ const { schema } = editor;
17393
+ let { from: from2, to } = state.selection;
17394
+ if (dispatch) {
17395
+ const selectionText = state.doc.textBetween(from2, to);
17396
+ let content = null;
17397
+ if (selectionText) {
17398
+ content = schema.text(selectionText);
17183
17399
  }
17184
- const { tr } = state;
17185
- tr.delete(range.from, range.to);
17186
- ListHelpers.createNewList({
17187
- listType: this.type,
17188
- tr,
17189
- editor: this.editor
17190
- });
17400
+ if (options.text) {
17401
+ content = schema.text(options.text);
17402
+ }
17403
+ if (options.json) {
17404
+ content = schema.nodeFromJSON(options.json);
17405
+ }
17406
+ if (!content) {
17407
+ content = schema.text(" ");
17408
+ }
17409
+ const attrs = {
17410
+ ...options.attrs,
17411
+ id: options.attrs?.id || generateRandomSigned32BitIntStrId(),
17412
+ tag: "inline_text_sdt",
17413
+ alias: options.attrs?.alias || "Structured content"
17414
+ };
17415
+ const node = schema.nodes.structuredContent.create(attrs, content, null);
17416
+ const parent = findParentNode((node2) => node2.type.name === "structuredContent")(state.selection);
17417
+ if (parent) {
17418
+ const insertPos = parent.pos + parent.node.nodeSize;
17419
+ from2 = to = insertPos;
17420
+ }
17421
+ tr.replaceWith(from2, to, node);
17422
+ }
17423
+ return true;
17424
+ },
17425
+ /**
17426
+ * Inserts a structured content block at selection.
17427
+ * @category Command
17428
+ * @param {StructuredContentBlockInsert} options
17429
+ */
17430
+ insertStructuredContentBlock: (options = {}) => ({ editor, dispatch, state, tr }) => {
17431
+ const { schema } = editor;
17432
+ let { from: from2, to } = state.selection;
17433
+ if (dispatch) {
17434
+ const selectionContent = state.selection.content();
17435
+ let content = null;
17436
+ if (selectionContent.size) {
17437
+ content = selectionContent.content;
17438
+ }
17439
+ if (options.html) {
17440
+ const html = htmlHandler(options.html, editor);
17441
+ const doc2 = DOMParser$1.fromSchema(schema).parse(html);
17442
+ content = doc2.content;
17443
+ }
17444
+ if (options.json) {
17445
+ content = schema.nodeFromJSON(options.json);
17446
+ }
17447
+ if (!content) {
17448
+ content = schema.nodeFromJSON({ type: "paragraph", content: [] });
17449
+ }
17450
+ const attrs = {
17451
+ ...options.attrs,
17452
+ id: options.attrs?.id || generateRandomSigned32BitIntStrId(),
17453
+ tag: "block_table_sdt",
17454
+ alias: options.attrs?.alias || "Structured content"
17455
+ };
17456
+ const node = schema.nodes.structuredContentBlock.create(attrs, content, null);
17457
+ const parent = findParentNode((node2) => node2.type.name === "structuredContentBlock")(state.selection);
17458
+ if (parent) {
17459
+ const insertPos = parent.pos + parent.node.nodeSize;
17460
+ from2 = to = insertPos;
17461
+ }
17462
+ tr.replaceRangeWith(from2, to, node);
17463
+ }
17464
+ return true;
17465
+ },
17466
+ /**
17467
+ * Updates a structured content attributes or content.
17468
+ * If the updated node does not match the schema, it will not be updated.
17469
+ * @category Command
17470
+ * @param {string} id
17471
+ * @param {StructuredContentUpdate} options
17472
+ */
17473
+ updateStructuredContentById: (id, options = {}) => ({ editor, dispatch, state, tr }) => {
17474
+ const structuredContentTags = getStructuredContentTagsById(id, state);
17475
+ if (!structuredContentTags.length) {
17476
+ return true;
17477
+ }
17478
+ const { schema } = editor;
17479
+ if (dispatch) {
17480
+ const structuredContent = structuredContentTags[0];
17481
+ const { pos, node } = structuredContent;
17482
+ const posFrom = pos;
17483
+ const posTo = pos + node.nodeSize;
17484
+ let content = null;
17485
+ if (options.text) {
17486
+ content = schema.text(options.text);
17487
+ }
17488
+ if (options.html) {
17489
+ const html = htmlHandler(options.html, editor);
17490
+ const doc2 = DOMParser$1.fromSchema(schema).parse(html);
17491
+ content = doc2.content;
17492
+ }
17493
+ if (options.json) {
17494
+ content = schema.nodeFromJSON(options.json);
17495
+ }
17496
+ if (!content) {
17497
+ content = node.content;
17498
+ }
17499
+ const updatedNode = node.type.create({ ...node.attrs, ...options.attrs }, content, node.marks);
17500
+ try {
17501
+ updatedNode.check();
17502
+ } catch {
17503
+ console.error("Updated node does not conform to the schema");
17504
+ return false;
17505
+ }
17506
+ tr.replaceWith(posFrom, posTo, updatedNode);
17507
+ }
17508
+ return true;
17509
+ },
17510
+ /**
17511
+ * Removes a structured content.
17512
+ * @category Command
17513
+ * @param {Array<{ node: Node, pos: number }>} structuredContentTags
17514
+ */
17515
+ deleteStructuredContent: (structuredContentTags) => ({ dispatch, tr }) => {
17516
+ if (!structuredContentTags.length) {
17517
+ return true;
17518
+ }
17519
+ if (dispatch) {
17520
+ structuredContentTags.forEach((structuredContent) => {
17521
+ const { pos, node } = structuredContent;
17522
+ const posFrom = tr.mapping.map(pos);
17523
+ const posTo = tr.mapping.map(pos + node.nodeSize);
17524
+ const currentNode = tr.doc.nodeAt(posFrom);
17525
+ if (currentNode && node.eq(currentNode)) {
17526
+ tr.delete(posFrom, posTo);
17527
+ }
17528
+ });
17529
+ }
17530
+ return true;
17531
+ },
17532
+ /**
17533
+ * Removes a structured content by ID.
17534
+ * @category Command
17535
+ * @param {string | string[]} idOrIds
17536
+ */
17537
+ deleteStructuredContentById: (idOrIds) => ({ dispatch, state, tr }) => {
17538
+ const structuredContentTags = getStructuredContentTagsById(idOrIds, state);
17539
+ if (!structuredContentTags.length) {
17540
+ return true;
17541
+ }
17542
+ if (dispatch) {
17543
+ structuredContentTags.forEach((structuredContent) => {
17544
+ const { pos, node } = structuredContent;
17545
+ const posFrom = tr.mapping.map(pos);
17546
+ const posTo = tr.mapping.map(pos + node.nodeSize);
17547
+ const currentNode = tr.doc.nodeAt(posFrom);
17548
+ if (currentNode && node.eq(currentNode)) {
17549
+ tr.delete(posFrom, posTo);
17550
+ }
17551
+ });
17552
+ }
17553
+ return true;
17554
+ },
17555
+ /**
17556
+ * Removes a structured content at cursor, preserving its content.
17557
+ * @category Command
17558
+ */
17559
+ deleteStructuredContentAtSelection: () => ({ dispatch, state, tr }) => {
17560
+ const predicate = (node) => STRUCTURED_CONTENT_NAMES.includes(node.type.name);
17561
+ const structuredContent = findParentNode(predicate)(state.selection);
17562
+ if (!structuredContent) {
17563
+ return true;
17564
+ }
17565
+ if (dispatch) {
17566
+ const { node, pos } = structuredContent;
17567
+ const posFrom = pos;
17568
+ const posTo = posFrom + node.nodeSize;
17569
+ const content = node.content;
17570
+ tr.replaceWith(posFrom, posTo, content);
17571
+ }
17572
+ return true;
17573
+ }
17574
+ };
17575
+ },
17576
+ addHelpers() {
17577
+ return {
17578
+ ...structuredContentHelpers
17579
+ };
17580
+ }
17581
+ });
17582
+ class DocumentSectionView {
17583
+ constructor(node, getPos, decorations, editor) {
17584
+ __privateAdd(this, _DocumentSectionView_instances);
17585
+ this.node = node;
17586
+ this.editor = editor;
17587
+ this.decorations = decorations;
17588
+ this.view = editor.view;
17589
+ this.getPos = getPos;
17590
+ __privateMethod(this, _DocumentSectionView_instances, init_fn2).call(this);
17591
+ }
17592
+ }
17593
+ _DocumentSectionView_instances = new WeakSet();
17594
+ init_fn2 = function() {
17595
+ const { attrs } = this.node;
17596
+ const { id, title, description } = attrs;
17597
+ this.dom = document.createElement("div");
17598
+ this.dom.className = "sd-document-section-block";
17599
+ this.dom.setAttribute("data-id", id);
17600
+ this.dom.setAttribute("data-title", title);
17601
+ this.dom.setAttribute("data-description", description);
17602
+ this.dom.setAttribute("aria-label", "Document section");
17603
+ __privateMethod(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
17604
+ this.contentDOM = document.createElement("div");
17605
+ this.contentDOM.className = "sd-document-section-block-content";
17606
+ this.contentDOM.setAttribute("contenteditable", "true");
17607
+ this.dom.appendChild(this.contentDOM);
17608
+ };
17609
+ addToolTip_fn = function() {
17610
+ const { title } = this.node.attrs;
17611
+ this.infoDiv = document.createElement("div");
17612
+ this.infoDiv.className = "sd-document-section-block-info";
17613
+ const textSpan = document.createElement("span");
17614
+ textSpan.textContent = title || "Document section";
17615
+ this.infoDiv.appendChild(textSpan);
17616
+ this.infoDiv.setAttribute("contenteditable", "false");
17617
+ this.dom.appendChild(this.infoDiv);
17618
+ };
17619
+ const getAllSections = (editor) => {
17620
+ if (!editor) return [];
17621
+ const type = editor.schema.nodes.documentSection;
17622
+ if (!type) return [];
17623
+ const sections = [];
17624
+ const { state } = editor;
17625
+ state.doc.descendants((node, pos) => {
17626
+ if (node.type.name === type.name) {
17627
+ sections.push({ node, pos });
17628
+ }
17629
+ });
17630
+ return sections;
17631
+ };
17632
+ const exportSectionsToHTML = (editor) => {
17633
+ const sections = getAllSections(editor);
17634
+ const processedSections = /* @__PURE__ */ new Set();
17635
+ const result = [];
17636
+ sections.forEach(({ node }) => {
17637
+ const { attrs } = node;
17638
+ const { id, title, description } = attrs;
17639
+ if (processedSections.has(id)) return;
17640
+ processedSections.add(id);
17641
+ const html = getHTMLFromNode(node, editor);
17642
+ result.push({
17643
+ id,
17644
+ title,
17645
+ description,
17646
+ html
17647
+ });
17648
+ });
17649
+ return result;
17650
+ };
17651
+ const getHTMLFromNode = (node, editor) => {
17652
+ const tempDocument = document.implementation.createHTMLDocument();
17653
+ const container = tempDocument.createElement("div");
17654
+ const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
17655
+ container.appendChild(fragment);
17656
+ let html = container.innerHTML;
17657
+ return html;
17658
+ };
17659
+ const exportSectionsToJSON = (editor) => {
17660
+ const sections = getAllSections(editor);
17661
+ const processedSections = /* @__PURE__ */ new Set();
17662
+ const result = [];
17663
+ sections.forEach(({ node }) => {
17664
+ const { attrs } = node;
17665
+ const { id, title, description } = attrs;
17666
+ if (processedSections.has(id)) return;
17667
+ processedSections.add(id);
17668
+ result.push({
17669
+ id,
17670
+ title,
17671
+ description,
17672
+ content: node.toJSON()
17673
+ });
17674
+ });
17675
+ return result;
17676
+ };
17677
+ const getLinkedSectionEditor = (id, options, editor) => {
17678
+ const sections = getAllSections(editor);
17679
+ const section = sections.find((s) => s.node.attrs.id === id);
17680
+ if (!section) return null;
17681
+ const child = editor.createChildEditor({
17682
+ ...options,
17683
+ onUpdate: ({ editor: childEditor, transaction }) => {
17684
+ const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
17685
+ if (isFromtLinkedParent) return;
17686
+ const updatedContent = childEditor.state.doc.content;
17687
+ const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
17688
+ if (!sectionNode) return;
17689
+ const { pos, node } = sectionNode;
17690
+ const newNode = node.type.create(node.attrs, updatedContent, node.marks);
17691
+ const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
17692
+ tr.setMeta("fromLinkedChild", true);
17693
+ editor.view.dispatch(tr);
17694
+ }
17695
+ });
17696
+ editor.on("update", ({ transaction }) => {
17697
+ const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
17698
+ if (isFromLinkedChild) return;
17699
+ const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
17700
+ if (!sectionNode) return;
17701
+ const sectionContent = sectionNode.node.content;
17702
+ const json = {
17703
+ type: "doc",
17704
+ content: sectionContent.content.map((node) => node.toJSON())
17705
+ };
17706
+ const childTr = child.state.tr;
17707
+ childTr.setMeta("fromLinkedParent", true);
17708
+ childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
17709
+ child.view.dispatch(childTr);
17710
+ });
17711
+ return child;
17712
+ };
17713
+ const SectionHelpers = {
17714
+ getAllSections,
17715
+ exportSectionsToHTML,
17716
+ exportSectionsToJSON,
17717
+ getLinkedSectionEditor
17718
+ };
17719
+ const DocumentSection = Node$1.create({
17720
+ name: "documentSection",
17721
+ group: "block",
17722
+ content: "block*",
17723
+ atom: true,
17724
+ isolating: true,
17725
+ addOptions() {
17726
+ return {
17727
+ htmlAttributes: {
17728
+ class: "sd-document-section-block",
17729
+ "aria-label": "Structured content block"
17730
+ }
17731
+ };
17732
+ },
17733
+ parseDOM() {
17734
+ return [
17735
+ {
17736
+ tag: "div.sd-document-section-block",
17737
+ priority: 60
17738
+ }
17739
+ ];
17740
+ },
17741
+ renderDOM({ htmlAttributes }) {
17742
+ return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
17743
+ },
17744
+ addAttributes() {
17745
+ return {
17746
+ id: {},
17747
+ sdBlockId: {
17748
+ default: null,
17749
+ keepOnSplit: false,
17750
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
17751
+ renderDOM: (attrs) => {
17752
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
17753
+ }
17754
+ },
17755
+ title: {},
17756
+ description: {},
17757
+ sectionType: {},
17758
+ isLocked: { default: false }
17759
+ };
17760
+ },
17761
+ addNodeView() {
17762
+ return ({ node, editor, getPos, decorations }) => {
17763
+ return new DocumentSectionView(node, getPos, decorations, editor);
17764
+ };
17765
+ },
17766
+ addCommands() {
17767
+ return {
17768
+ /**
17769
+ * Create a lockable content section
17770
+ * @category Command
17771
+ * @param {SectionCreate} [options={}] - Section configuration
17772
+ * @example
17773
+ * editor.commands.createDocumentSection({
17774
+ * id: 1,
17775
+ * title: 'Terms & Conditions',
17776
+ * isLocked: true,
17777
+ * html: '<p>Legal content...</p>'
17778
+ * })
17779
+ */
17780
+ createDocumentSection: (options = {}) => ({ tr, state, dispatch, editor }) => {
17781
+ const { selection } = state;
17782
+ let { from: from2, to } = selection;
17783
+ let content = selection.content().content;
17784
+ const { html: optionsHTML, json: optionsJSON } = options;
17785
+ if (optionsHTML) {
17786
+ const html = htmlHandler(optionsHTML, this.editor);
17787
+ const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
17788
+ content = doc2.content;
17789
+ }
17790
+ if (optionsJSON) {
17791
+ content = this.editor.schema.nodeFromJSON(optionsJSON);
17792
+ }
17793
+ if (!content?.content?.length) {
17794
+ content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
17795
+ }
17796
+ if (!options.id) {
17797
+ const allSections = SectionHelpers.getAllSections(editor);
17798
+ options.id = allSections.length + 1;
17799
+ }
17800
+ if (!options.title) {
17801
+ options.title = "Document section";
17802
+ }
17803
+ const node = this.type.createAndFill(options, content);
17804
+ if (!node) return false;
17805
+ const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
17806
+ if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
17807
+ const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
17808
+ from2 = insertPos2;
17809
+ to = insertPos2;
17810
+ }
17811
+ tr.replaceRangeWith(from2, to, node);
17812
+ const nodeEnd = from2 + node.nodeSize;
17813
+ let shouldInsertParagraph = true;
17814
+ let insertPos = nodeEnd;
17815
+ if (nodeEnd >= tr.doc.content.size) {
17816
+ insertPos = tr.doc.content.size;
17817
+ if (insertPos > 0) {
17818
+ const $endPos = tr.doc.resolve(insertPos);
17819
+ if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
17820
+ shouldInsertParagraph = false;
17821
+ }
17822
+ }
17823
+ }
17824
+ if (shouldInsertParagraph) {
17825
+ const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
17826
+ tr.insert(insertPos, emptyParagraph);
17827
+ }
17828
+ if (dispatch) {
17829
+ tr.setMeta("documentSection", { action: "create" });
17830
+ dispatch(tr);
17831
+ setTimeout(() => {
17832
+ try {
17833
+ const currentState = editor.state;
17834
+ const docSize = currentState.doc.content.size;
17835
+ let targetPos = from2 + node.nodeSize;
17836
+ if (shouldInsertParagraph) {
17837
+ targetPos += 1;
17838
+ }
17839
+ targetPos = Math.min(targetPos, docSize);
17840
+ if (targetPos < docSize && targetPos > 0) {
17841
+ const newSelection = Selection.near(currentState.doc.resolve(targetPos));
17842
+ const newTr = currentState.tr.setSelection(newSelection);
17843
+ editor.view.dispatch(newTr);
17844
+ }
17845
+ } catch (e) {
17846
+ console.warn("Could not set delayed selection:", e);
17847
+ }
17848
+ }, 0);
17849
+ }
17850
+ return true;
17851
+ },
17852
+ /**
17853
+ * Remove section wrapper at cursor, preserving its content
17854
+ * @category Command
17855
+ * @example
17856
+ * editor.commands.removeSectionAtSelection()
17857
+ * @note Content stays in document, only section wrapper is removed
17858
+ */
17859
+ removeSectionAtSelection: () => ({ tr, dispatch }) => {
17860
+ const sdtNode = findParentNode((node2) => node2.type.name === "documentSection")(tr.selection);
17861
+ if (!sdtNode) return false;
17862
+ const { node, pos } = sdtNode;
17863
+ const nodeStart = pos;
17864
+ const nodeEnd = nodeStart + node.nodeSize;
17865
+ const contentToPreserve = node.content;
17866
+ tr.delete(nodeStart, nodeEnd);
17867
+ if (contentToPreserve.size > 0) {
17868
+ tr.insert(nodeStart, contentToPreserve);
17869
+ }
17870
+ const newPos = Math.min(nodeStart, tr.doc.content.size);
17871
+ tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
17872
+ if (dispatch) {
17873
+ tr.setMeta("documentSection", { action: "delete" });
17874
+ dispatch(tr);
17875
+ }
17876
+ return true;
17877
+ },
17878
+ /**
17879
+ * Delete section and all its content
17880
+ * @category Command
17881
+ * @param {number} id - Section to delete
17882
+ * @example
17883
+ * editor.commands.removeSectionById(123)
17884
+ */
17885
+ removeSectionById: (id) => ({ tr, dispatch }) => {
17886
+ const sections = SectionHelpers.getAllSections(this.editor);
17887
+ const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
17888
+ if (!sectionToRemove) return false;
17889
+ const { pos, node } = sectionToRemove;
17890
+ const nodeStart = pos;
17891
+ const nodeEnd = nodeStart + node.nodeSize;
17892
+ tr.delete(nodeStart, nodeEnd);
17893
+ if (dispatch) {
17894
+ tr.setMeta("documentSection", { action: "delete", id });
17895
+ dispatch(tr);
17896
+ }
17897
+ return true;
17898
+ },
17899
+ /**
17900
+ * Lock section against edits
17901
+ * @category Command
17902
+ * @param {number} id - Section to lock
17903
+ * @example
17904
+ * editor.commands.lockSectionById(123)
17905
+ */
17906
+ lockSectionById: (id) => ({ tr, dispatch }) => {
17907
+ const sections = SectionHelpers.getAllSections(this.editor);
17908
+ const sectionToLock = sections.find(({ node }) => node.attrs.id === id);
17909
+ if (!sectionToLock) return false;
17910
+ tr.setNodeMarkup(sectionToLock.pos, null, { ...sectionToLock.node.attrs, isLocked: true });
17911
+ if (dispatch) {
17912
+ tr.setMeta("documentSection", { action: "lock", id });
17913
+ dispatch(tr);
17914
+ }
17915
+ return true;
17916
+ },
17917
+ /**
17918
+ * Modify section attributes or content
17919
+ * @category Command
17920
+ * @param {SectionUpdate} options - Changes to apply
17921
+ * @example
17922
+ * editor.commands.updateSectionById({ id: 123, attrs: { isLocked: false } })
17923
+ * editor.commands.updateSectionById({ id: 123, html: '<p>New content</p>' })
17924
+ * editor.commands.updateSectionById({
17925
+ * id: 123,
17926
+ * html: '<p>Updated</p>',
17927
+ * attrs: { title: 'New Title' }
17928
+ * })
17929
+ */
17930
+ updateSectionById: ({ id, html, json, attrs }) => ({ tr, dispatch, editor }) => {
17931
+ const sections = SectionHelpers.getAllSections(editor || this.editor);
17932
+ const sectionToUpdate = sections.find(({ node: node2 }) => node2.attrs.id === id);
17933
+ if (!sectionToUpdate) return false;
17934
+ const { pos, node } = sectionToUpdate;
17935
+ let newContent = null;
17936
+ if (html) {
17937
+ const htmlDoc = htmlHandler(html, editor || this.editor);
17938
+ const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
17939
+ newContent = doc2.content;
17940
+ }
17941
+ if (json) {
17942
+ newContent = (editor || this.editor).schema.nodeFromJSON(json);
17943
+ }
17944
+ if (!newContent) {
17945
+ newContent = node.content;
17946
+ }
17947
+ const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
17948
+ tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
17949
+ if (dispatch) {
17950
+ tr.setMeta("documentSection", { action: "update", id, attrs });
17951
+ dispatch(tr);
17952
+ }
17953
+ return true;
17954
+ }
17955
+ };
17956
+ },
17957
+ addHelpers() {
17958
+ return {
17959
+ ...SectionHelpers
17960
+ };
17961
+ }
17962
+ });
17963
+ const DocumentPartObject = Node$1.create({
17964
+ name: "documentPartObject",
17965
+ group: "block",
17966
+ content: "block*",
17967
+ isolating: true,
17968
+ addOptions() {
17969
+ return {
17970
+ htmlAttributes: {
17971
+ class: "sd-document-part-object-block",
17972
+ "aria-label": "Structured document part block"
17973
+ }
17974
+ };
17975
+ },
17976
+ parseDOM() {
17977
+ return [
17978
+ {
17979
+ tag: "div.sd-document-part-object-block",
17980
+ priority: 60
17981
+ }
17982
+ ];
17983
+ },
17984
+ renderDOM({ htmlAttributes }) {
17985
+ return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
17986
+ },
17987
+ addAttributes() {
17988
+ return {
17989
+ sdBlockId: {
17990
+ default: null,
17991
+ keepOnSplit: false,
17992
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
17993
+ renderDOM: (attrs) => {
17994
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
17995
+ }
17996
+ },
17997
+ id: {},
17998
+ docPartGallery: {},
17999
+ docPartUnique: {
18000
+ default: true
18001
+ }
18002
+ };
18003
+ }
18004
+ });
18005
+ const Document = Node$1.create({
18006
+ name: "doc",
18007
+ topNode: true,
18008
+ content: "block+",
18009
+ parseDOM() {
18010
+ return [{ tag: "doc" }];
18011
+ },
18012
+ renderDOM() {
18013
+ return ["doc", 0];
18014
+ },
18015
+ addAttributes() {
18016
+ return {
18017
+ attributes: {
18018
+ rendered: false,
18019
+ "aria-label": "Document node"
18020
+ }
18021
+ };
18022
+ },
18023
+ addCommands() {
18024
+ return {
18025
+ /**
18026
+ * Get document statistics
18027
+ * @category Command
18028
+ * @example
18029
+ * // Get word and character count
18030
+ * const stats = editor.commands.getDocumentStats()
18031
+ * console.log(`${stats.words} words, ${stats.characters} characters`)
18032
+ * @note Returns word count, character count, and paragraph count
18033
+ */
18034
+ getDocumentStats: () => ({ editor }) => {
18035
+ const text = editor.getText();
18036
+ const words = text.split(/\s+/).filter((word) => word.length > 0).length;
18037
+ const characters = text.length;
18038
+ const paragraphs = editor.state.doc.content.childCount;
18039
+ return {
18040
+ words,
18041
+ characters,
18042
+ paragraphs
18043
+ };
18044
+ },
18045
+ /**
18046
+ * Clear entire document
18047
+ * @category Command
18048
+ * @example
18049
+ * editor.commands.clearDocument()
18050
+ * @note Replaces all content with an empty paragraph
18051
+ */
18052
+ clearDocument: () => ({ commands: commands2 }) => {
18053
+ return commands2.setContent("<p></p>");
18054
+ }
18055
+ };
18056
+ }
18057
+ });
18058
+ const Text = Node$1.create({
18059
+ name: "text",
18060
+ group: "inline",
18061
+ inline: true,
18062
+ addOptions() {
18063
+ return {};
18064
+ }
18065
+ });
18066
+ const splitRun = () => (props) => {
18067
+ const { state, view, tr } = props;
18068
+ const { $from, empty: empty2 } = state.selection;
18069
+ if (!empty2) return false;
18070
+ if ($from.parent.type.name !== "run") return false;
18071
+ const handled = splitBlock(state, (transaction) => {
18072
+ view.dispatch(transaction);
18073
+ });
18074
+ if (handled) {
18075
+ tr.setMeta("preventDispatch", true);
18076
+ }
18077
+ return handled;
18078
+ };
18079
+ const Run = OxmlNode.create({
18080
+ name: "run",
18081
+ oXmlName: "w:r",
18082
+ group: "inline",
18083
+ inline: true,
18084
+ content: "inline*",
18085
+ selectable: false,
18086
+ childToAttributes: ["runProperties"],
18087
+ addOptions() {
18088
+ return {
18089
+ htmlAttributes: {
18090
+ "data-run": "1"
18091
+ }
18092
+ };
18093
+ },
18094
+ addAttributes() {
18095
+ return {
18096
+ runProperties: {
18097
+ default: null,
18098
+ rendered: false,
18099
+ keepOnSplit: true
18100
+ },
18101
+ rsidR: {
18102
+ default: null,
18103
+ rendered: false,
18104
+ keepOnSplit: true
18105
+ },
18106
+ rsidRPr: {
18107
+ default: null,
18108
+ rendered: false,
18109
+ keepOnSplit: true
18110
+ },
18111
+ rsidDel: {
18112
+ default: null,
18113
+ rendered: false,
18114
+ keepOnSplit: true
18115
+ }
18116
+ };
18117
+ },
18118
+ addCommands() {
18119
+ return {
18120
+ splitRun
18121
+ };
18122
+ },
18123
+ parseDOM() {
18124
+ return [{ tag: "span[data-run]" }];
18125
+ },
18126
+ renderDOM({ htmlAttributes }) {
18127
+ const base2 = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
18128
+ return ["span", base2, 0];
18129
+ }
18130
+ });
18131
+ const inputRegex$1 = /^\s*([-+*])\s$/;
18132
+ const BulletList = Node$1.create({
18133
+ name: "bulletList",
18134
+ group: "block list",
18135
+ selectable: false,
18136
+ content() {
18137
+ return `${this.options.itemTypeName}+`;
18138
+ },
18139
+ addOptions() {
18140
+ return {
18141
+ itemTypeName: "listItem",
18142
+ htmlAttributes: {
18143
+ "aria-label": "Bullet list node"
18144
+ },
18145
+ keepMarks: true,
18146
+ keepAttributes: false
18147
+ };
18148
+ },
18149
+ parseDOM() {
18150
+ return [{ tag: "ul" }];
18151
+ },
18152
+ renderDOM({ htmlAttributes }) {
18153
+ const attributes = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
18154
+ return ["ul", attributes, 0];
18155
+ },
18156
+ addAttributes() {
18157
+ return {
18158
+ "list-style-type": {
18159
+ default: "bullet",
18160
+ rendered: false
18161
+ },
18162
+ listId: {
18163
+ rendered: false
18164
+ },
18165
+ sdBlockId: {
18166
+ default: null,
18167
+ keepOnSplit: false,
18168
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
18169
+ renderDOM: (attrs) => {
18170
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
18171
+ }
18172
+ },
18173
+ attributes: {
18174
+ rendered: false,
18175
+ keepOnSplit: true
18176
+ }
18177
+ };
18178
+ },
18179
+ addCommands() {
18180
+ return {
18181
+ /**
18182
+ * Toggle a bullet list at the current selection
18183
+ * @category Command
18184
+ * @example
18185
+ * // Toggle bullet list on selected text
18186
+ * editor.commands.toggleBulletList()
18187
+ * @note Converts selected paragraphs to list items or removes list formatting
18188
+ */
18189
+ toggleBulletList: () => (params2) => {
18190
+ return toggleList(this.type)(params2);
18191
+ }
18192
+ };
18193
+ },
18194
+ addShortcuts() {
18195
+ return {
18196
+ "Mod-Shift-8": () => {
18197
+ return this.editor.commands.toggleBulletList();
18198
+ }
18199
+ };
18200
+ },
18201
+ addInputRules() {
18202
+ return [
18203
+ new InputRule({
18204
+ match: inputRegex$1,
18205
+ handler: ({ state, range }) => {
18206
+ const $pos = state.selection.$from;
18207
+ const listItemType = state.schema.nodes.listItem;
18208
+ for (let depth = $pos.depth; depth >= 0; depth--) {
18209
+ if ($pos.node(depth).type === listItemType) {
18210
+ return null;
18211
+ }
18212
+ }
18213
+ const { tr } = state;
18214
+ tr.delete(range.from, range.to);
18215
+ ListHelpers.createNewList({
18216
+ listType: this.type,
18217
+ tr,
18218
+ editor: this.editor
18219
+ });
17191
18220
  }
17192
18221
  })
17193
18222
  ];
@@ -17480,15 +18509,31 @@ const intToJapaneseCounting = (num) => {
17480
18509
  }
17481
18510
  return result;
17482
18511
  };
17483
- const CustomSelectionPluginKey = new PluginKey("CustomSelection");
17484
- const shouldAllowNativeContextMenu = (event) => {
18512
+ const isKeyboardInvocation = (event) => {
18513
+ return event.type === "contextmenu" && typeof event.detail === "number" && event.detail === 0 && (event.button === 0 || event.button === void 0) && event.clientX === 0 && event.clientY === 0;
18514
+ };
18515
+ const prefersNativeMenu = (event) => {
17485
18516
  if (!event) return false;
17486
18517
  if (event.ctrlKey || event.metaKey) {
17487
18518
  return true;
17488
18519
  }
17489
- 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;
17490
- return Boolean(isKeyboardInvocation);
18520
+ return isKeyboardInvocation(event);
17491
18521
  };
18522
+ const shouldAllowNativeContextMenu = (event) => {
18523
+ return prefersNativeMenu(event);
18524
+ };
18525
+ const shouldBypassContextMenu = shouldAllowNativeContextMenu;
18526
+ const DEFAULT_SELECTION_STATE = Object.freeze({
18527
+ focused: false,
18528
+ preservedSelection: null,
18529
+ showVisualSelection: false,
18530
+ skipFocusReset: false
18531
+ });
18532
+ const normalizeSelectionState = (state = {}) => ({
18533
+ ...DEFAULT_SELECTION_STATE,
18534
+ ...state
18535
+ });
18536
+ const CustomSelectionPluginKey = new PluginKey("CustomSelection");
17492
18537
  const handleClickOutside = (event, editor) => {
17493
18538
  const editorElem = editor?.options?.element;
17494
18539
  if (!editorElem) return;
@@ -17525,11 +18570,7 @@ const CustomSelection = Extension.create({
17525
18570
  const customSelectionPlugin = new Plugin({
17526
18571
  key: CustomSelectionPluginKey,
17527
18572
  state: {
17528
- init: () => ({
17529
- focused: false,
17530
- preservedSelection: null,
17531
- showVisualSelection: false
17532
- }),
18573
+ init: () => ({ ...DEFAULT_SELECTION_STATE }),
17533
18574
  apply: (tr, value) => {
17534
18575
  const meta = getFocusMeta(tr);
17535
18576
  if (meta !== void 0) {
@@ -17560,7 +18601,8 @@ const CustomSelection = Extension.create({
17560
18601
  setFocusMeta(view.state.tr, {
17561
18602
  focused: true,
17562
18603
  preservedSelection: selection,
17563
- showVisualSelection: true
18604
+ showVisualSelection: true,
18605
+ skipFocusReset: true
17564
18606
  })
17565
18607
  );
17566
18608
  }
@@ -17581,7 +18623,8 @@ const CustomSelection = Extension.create({
17581
18623
  setFocusMeta(view.state.tr, {
17582
18624
  focused: true,
17583
18625
  preservedSelection: selection2,
17584
- showVisualSelection: true
18626
+ showVisualSelection: true,
18627
+ skipFocusReset: true
17585
18628
  })
17586
18629
  );
17587
18630
  this.editor.setOptions({
@@ -17604,7 +18647,8 @@ const CustomSelection = Extension.create({
17604
18647
  setFocusMeta(view.state.tr, {
17605
18648
  focused: true,
17606
18649
  preservedSelection: selection,
17607
- showVisualSelection: true
18650
+ showVisualSelection: true,
18651
+ skipFocusReset: false
17608
18652
  })
17609
18653
  );
17610
18654
  this.editor.setOptions({
@@ -17622,7 +18666,8 @@ const CustomSelection = Extension.create({
17622
18666
  setFocusMeta(view.state.tr, {
17623
18667
  focused: true,
17624
18668
  preservedSelection: selection,
17625
- showVisualSelection: true
18669
+ showVisualSelection: true,
18670
+ skipFocusReset: false
17626
18671
  })
17627
18672
  );
17628
18673
  }
@@ -17633,7 +18678,8 @@ const CustomSelection = Extension.create({
17633
18678
  setFocusMeta(view.state.tr, {
17634
18679
  focused: false,
17635
18680
  preservedSelection: null,
17636
- showVisualSelection: false
18681
+ showVisualSelection: false,
18682
+ skipFocusReset: false
17637
18683
  })
17638
18684
  );
17639
18685
  if (!selection.empty && !this.editor.options.element?.contains(target)) {
@@ -17650,12 +18696,20 @@ const CustomSelection = Extension.create({
17650
18696
  const isElement2 = target instanceof Element;
17651
18697
  const isToolbarBtn = isElement2 && isToolbarButton(target);
17652
18698
  const isToolbarInp = isElement2 && isToolbarInput(target);
18699
+ const focusState = getFocusState(view.state);
18700
+ if (focusState?.skipFocusReset) {
18701
+ view.dispatch(
18702
+ setFocusMeta(view.state.tr, normalizeSelectionState({ ...focusState, skipFocusReset: false }))
18703
+ );
18704
+ return false;
18705
+ }
17653
18706
  if (!isToolbarBtn && !isToolbarInp) {
17654
18707
  view.dispatch(
17655
18708
  setFocusMeta(view.state.tr, {
17656
18709
  focused: false,
17657
18710
  preservedSelection: null,
17658
- showVisualSelection: false
18711
+ showVisualSelection: false,
18712
+ skipFocusReset: false
17659
18713
  })
17660
18714
  );
17661
18715
  }
@@ -17666,12 +18720,16 @@ const CustomSelection = Extension.create({
17666
18720
  const isToolbarBtn = isElement2 && isToolbarButton(target);
17667
18721
  const isToolbarInp = isElement2 && isToolbarInput(target);
17668
18722
  const state = getFocusState(view.state);
18723
+ if (state?.skipFocusReset) {
18724
+ return false;
18725
+ }
17669
18726
  if (isToolbarBtn || isToolbarInp) {
17670
18727
  view.dispatch(
17671
18728
  setFocusMeta(view.state.tr, {
17672
18729
  focused: true,
17673
18730
  preservedSelection: state.preservedSelection || view.state.selection,
17674
- showVisualSelection: true
18731
+ showVisualSelection: true,
18732
+ skipFocusReset: false
17675
18733
  })
17676
18734
  );
17677
18735
  } else {
@@ -17679,7 +18737,8 @@ const CustomSelection = Extension.create({
17679
18737
  setFocusMeta(view.state.tr, {
17680
18738
  focused: false,
17681
18739
  preservedSelection: null,
17682
- showVisualSelection: false
18740
+ showVisualSelection: false,
18741
+ skipFocusReset: false
17683
18742
  })
17684
18743
  );
17685
18744
  }
@@ -18079,7 +19138,12 @@ const generateDecorations = (state, styles) => {
18079
19138
  return { ...base2, ...linkedStyle.definition?.styles || {} };
18080
19139
  };
18081
19140
  const pMap = buildStyleMap(paragraphStyleId);
18082
- const tMap = buildStyleMap(inlineTextStyleId);
19141
+ let tMap;
19142
+ if (paragraphStyleId?.startsWith("TOC")) {
19143
+ tMap = {};
19144
+ } else {
19145
+ tMap = buildStyleMap(inlineTextStyleId);
19146
+ }
18083
19147
  const rMap = buildStyleMap(runStyleId);
18084
19148
  const finalStyles = { ...pMap, ...tMap, ...rMap };
18085
19149
  if (Object.keys(finalStyles).length === 0) return;
@@ -18525,7 +19589,7 @@ class ListItemNodeView {
18525
19589
  this.decorations = decorations;
18526
19590
  this.view = editor.view;
18527
19591
  this.getPos = getPos;
18528
- __privateMethod(this, _ListItemNodeView_instances, init_fn2).call(this);
19592
+ __privateMethod(this, _ListItemNodeView_instances, init_fn3).call(this);
18529
19593
  activeListItemNodeViews.add(this);
18530
19594
  }
18531
19595
  refreshIndentStyling() {
@@ -18586,7 +19650,7 @@ class ListItemNodeView {
18586
19650
  }
18587
19651
  }
18588
19652
  _ListItemNodeView_instances = new WeakSet();
18589
- init_fn2 = function() {
19653
+ init_fn3 = function() {
18590
19654
  const { attrs } = this.node;
18591
19655
  const { listLevel, listNumberingType, lvlText, numId, level, customFormat } = attrs;
18592
19656
  let orderMarker = "";
@@ -19376,7 +20440,7 @@ const CommentsMark = Mark.create({
19376
20440
  });
19377
20441
  const defaultTabDistance = 48;
19378
20442
  const defaultLineLength = 816;
19379
- const getTabDecorations = (doc2, view, from2 = 0, to = null) => {
20443
+ const getTabDecorations = (doc2, view, helpers2, from2 = 0, to = null) => {
19380
20444
  const decorations = [];
19381
20445
  const paragraphCache = /* @__PURE__ */ new Map();
19382
20446
  const end2 = to ?? doc2.content.size;
@@ -19384,7 +20448,7 @@ const getTabDecorations = (doc2, view, from2 = 0, to = null) => {
19384
20448
  if (node.type.name !== "tab") return;
19385
20449
  let extraStyles = "";
19386
20450
  const $pos = doc2.resolve(pos);
19387
- const paragraphContext = getParagraphContext($pos, paragraphCache);
20451
+ const paragraphContext = getParagraphContext($pos, paragraphCache, helpers2);
19388
20452
  if (!paragraphContext) return;
19389
20453
  try {
19390
20454
  const { tabStops, flattened, startPos } = paragraphContext;
@@ -19439,18 +20503,27 @@ const getTabDecorations = (doc2, view, from2 = 0, to = null) => {
19439
20503
  });
19440
20504
  return decorations;
19441
20505
  };
19442
- function getParagraphContext($pos, cache) {
20506
+ function getParagraphContext($pos, cache, helpers2) {
19443
20507
  for (let depth = $pos.depth; depth >= 0; depth--) {
19444
20508
  const node = $pos.node(depth);
19445
20509
  if (node?.type?.name === "paragraph") {
19446
20510
  const startPos = $pos.start(depth);
19447
20511
  if (!cache.has(startPos)) {
20512
+ let tabStops = [];
20513
+ if (Array.isArray(node.attrs?.tabStops)) {
20514
+ tabStops = node.attrs.tabStops;
20515
+ } else {
20516
+ const style = helpers2.linkedStyles.getStyleById(node.attrs?.styleId);
20517
+ if (Array.isArray(style?.definition?.styles?.tabStops)) {
20518
+ tabStops = style.definition.styles.tabStops;
20519
+ }
20520
+ }
19448
20521
  cache.set(startPos, {
19449
20522
  paragraph: node,
19450
20523
  paragraphDepth: depth,
19451
20524
  startPos,
19452
20525
  indent: node.attrs?.indent || {},
19453
- tabStops: Array.isArray(node.attrs?.tabStops) ? node.attrs.tabStops : [],
20526
+ tabStops,
19454
20527
  flattened: flattenParagraph(node, startPos),
19455
20528
  accumulatedTabWidth: 0
19456
20529
  });
@@ -19616,7 +20689,7 @@ const TabNode = Node$1.create({
19616
20689
  };
19617
20690
  },
19618
20691
  addPmPlugins() {
19619
- const { view } = this.editor;
20692
+ const { view, helpers: helpers2 } = this.editor;
19620
20693
  const tabPlugin = new Plugin({
19621
20694
  name: "tabPlugin",
19622
20695
  key: new PluginKey("tabPlugin"),
@@ -19626,7 +20699,7 @@ const TabNode = Node$1.create({
19626
20699
  },
19627
20700
  apply(tr, { decorations }, _oldState, newState) {
19628
20701
  if (!decorations) {
19629
- decorations = DecorationSet.create(newState.doc, getTabDecorations(newState.doc, view));
20702
+ decorations = DecorationSet.create(newState.doc, getTabDecorations(newState.doc, view, helpers2));
19630
20703
  }
19631
20704
  if (!tr.docChanged) {
19632
20705
  return { decorations };
@@ -19666,7 +20739,7 @@ const TabNode = Node$1.create({
19666
20739
  rangesToRecalculate.forEach(([start2, end2]) => {
19667
20740
  const oldDecorations = decorations.find(start2, end2);
19668
20741
  decorations = decorations.remove(oldDecorations);
19669
- const newDecorations = getTabDecorations(newState.doc, view, start2, end2);
20742
+ const newDecorations = getTabDecorations(newState.doc, view, helpers2, start2, end2);
19670
20743
  decorations = decorations.add(newState.doc, newDecorations);
19671
20744
  });
19672
20745
  return { decorations };
@@ -25947,83 +27020,66 @@ const processMarks = (marks) => {
25947
27020
  });
25948
27021
  return styles;
25949
27022
  };
25950
- const ShapeContainer = Node$1.create({
25951
- name: "shapeContainer",
25952
- group: "block",
25953
- content: "block+",
25954
- isolating: true,
27023
+ const PageReference = Node$1.create({
27024
+ name: "pageReference",
27025
+ group: "inline",
27026
+ inline: true,
27027
+ atom: true,
27028
+ draggable: false,
27029
+ selectable: false,
27030
+ content: "inline*",
25955
27031
  addOptions() {
25956
27032
  return {
25957
27033
  htmlAttributes: {
25958
- class: "sd-editor-shape-container",
25959
- "aria-label": "Shape container node"
27034
+ contenteditable: false,
27035
+ "data-id": "auto-page-reference",
27036
+ "aria-label": "Page reference node",
27037
+ class: "sd-editor-page-reference"
25960
27038
  }
25961
27039
  };
25962
27040
  },
25963
27041
  addAttributes() {
25964
27042
  return {
25965
- fillcolor: {
25966
- renderDOM: (attrs) => {
25967
- if (!attrs.fillcolor) return {};
25968
- return {
25969
- style: `background-color: ${attrs.fillcolor}`
25970
- };
25971
- }
25972
- },
25973
- sdBlockId: {
27043
+ marksAsAttrs: {
25974
27044
  default: null,
25975
- keepOnSplit: false,
25976
- parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
25977
- renderDOM: (attrs) => {
25978
- return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
25979
- }
25980
- },
25981
- style: {
25982
- renderDOM: (attrs) => {
25983
- if (!attrs.style) return {};
25984
- return {
25985
- style: attrs.style
25986
- };
25987
- }
25988
- },
25989
- wrapAttributes: {
25990
27045
  rendered: false
25991
27046
  },
25992
- attributes: {
27047
+ instruction: {
27048
+ default: "",
25993
27049
  rendered: false
25994
27050
  }
25995
27051
  };
25996
27052
  },
25997
27053
  parseDOM() {
25998
- return [
25999
- {
26000
- tag: `div[data-type="${this.name}"]`
26001
- }
26002
- ];
27054
+ return [{ tag: 'span[data-id="auto-page-reference"]' }];
26003
27055
  },
26004
27056
  renderDOM({ htmlAttributes }) {
26005
- return [
26006
- "div",
26007
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
26008
- 0
26009
- ];
27057
+ return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
26010
27058
  }
26011
27059
  });
26012
- const ShapeTextbox = Node$1.create({
26013
- name: "shapeTextbox",
27060
+ const ShapeContainer = Node$1.create({
27061
+ name: "shapeContainer",
26014
27062
  group: "block",
26015
- content: "paragraph* block*",
27063
+ content: "block+",
26016
27064
  isolating: true,
26017
27065
  addOptions() {
26018
27066
  return {
26019
27067
  htmlAttributes: {
26020
- class: "sd-editor-shape-textbox",
26021
- "aria-label": "Shape textbox node"
27068
+ class: "sd-editor-shape-container",
27069
+ "aria-label": "Shape container node"
26022
27070
  }
26023
27071
  };
26024
27072
  },
26025
27073
  addAttributes() {
26026
27074
  return {
27075
+ fillcolor: {
27076
+ renderDOM: (attrs) => {
27077
+ if (!attrs.fillcolor) return {};
27078
+ return {
27079
+ style: `background-color: ${attrs.fillcolor}`
27080
+ };
27081
+ }
27082
+ },
26027
27083
  sdBlockId: {
26028
27084
  default: null,
26029
27085
  keepOnSplit: false,
@@ -26032,72 +27088,15 @@ const ShapeTextbox = Node$1.create({
26032
27088
  return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
26033
27089
  }
26034
27090
  },
26035
- attributes: {
26036
- rendered: false
26037
- }
26038
- };
26039
- },
26040
- parseDOM() {
26041
- return [
26042
- {
26043
- tag: `div[data-type="${this.name}"]`
26044
- }
26045
- ];
26046
- },
26047
- renderDOM({ htmlAttributes }) {
26048
- return [
26049
- "div",
26050
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
26051
- 0
26052
- ];
26053
- }
26054
- });
26055
- const ContentBlock = Node$1.create({
26056
- name: "contentBlock",
26057
- group: "inline",
26058
- content: "",
26059
- isolating: true,
26060
- atom: true,
26061
- inline: true,
26062
- addOptions() {
26063
- return {
26064
- htmlAttributes: {
26065
- contenteditable: false
26066
- }
26067
- };
26068
- },
26069
- addAttributes() {
26070
- return {
26071
- horizontalRule: {
26072
- default: false,
26073
- renderDOM: ({ horizontalRule }) => {
26074
- if (!horizontalRule) return {};
26075
- return { "data-horizontal-rule": "true" };
26076
- }
26077
- },
26078
- size: {
26079
- default: null,
26080
- renderDOM: ({ size }) => {
26081
- if (!size) return {};
26082
- let style = "";
26083
- if (size.top) style += `top: ${size.top}px; `;
26084
- if (size.left) style += `left: ${size.left}px; `;
26085
- if (size.width) style += `width: ${size.width.toString().endsWith("%") ? size.width : `${size.width}px`}; `;
26086
- if (size.height)
26087
- style += `height: ${size.height.toString().endsWith("%") ? size.height : `${size.height}px`}; `;
26088
- return { style };
26089
- }
26090
- },
26091
- background: {
26092
- default: null,
27091
+ style: {
26093
27092
  renderDOM: (attrs) => {
26094
- if (!attrs.background) return {};
27093
+ if (!attrs.style) return {};
26095
27094
  return {
26096
- style: `background-color: ${attrs.background}`
27095
+ style: attrs.style
26097
27096
  };
26098
27097
  }
26099
27098
  },
26100
- drawingContent: {
27099
+ wrapAttributes: {
26101
27100
  rendered: false
26102
27101
  },
26103
27102
  attributes: {
@@ -26107,786 +27106,167 @@ const ContentBlock = Node$1.create({
26107
27106
  },
26108
27107
  parseDOM() {
26109
27108
  return [
26110
- {
26111
- tag: `div[data-type="${this.name}"]`
26112
- }
26113
- ];
26114
- },
26115
- renderDOM({ htmlAttributes }) {
26116
- return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name })];
26117
- },
26118
- addCommands() {
26119
- return {
26120
- /**
26121
- * Insert a horizontal rule
26122
- * @category Command
26123
- * @example
26124
- * editor.commands.insertHorizontalRule()
26125
- * @note Creates a visual separator between content sections
26126
- */
26127
- insertHorizontalRule: () => ({ commands: commands2 }) => {
26128
- return commands2.insertContent({
26129
- type: this.name,
26130
- attrs: {
26131
- horizontalRule: true,
26132
- size: { width: "100%", height: 2 },
26133
- background: "#e5e7eb"
26134
- }
26135
- });
26136
- },
26137
- /**
26138
- * Insert a content block
26139
- * @category Command
26140
- * @param {ContentBlockConfig} config - Block configuration
26141
- * @example
26142
- * // Insert a spacer block
26143
- * editor.commands.insertContentBlock({ size: { height: 20 } })
26144
- *
26145
- * @example
26146
- * // Insert a colored divider
26147
- * editor.commands.insertContentBlock({
26148
- * size: { width: '50%', height: 3 },
26149
- * background: '#3b82f6'
26150
- * })
26151
- * @note Used for spacing, dividers, and special inline content
26152
- */
26153
- insertContentBlock: (config) => ({ commands: commands2 }) => {
26154
- return commands2.insertContent({
26155
- type: this.name,
26156
- attrs: config
26157
- });
26158
- }
26159
- };
26160
- }
26161
- });
26162
- class StructuredContentViewBase {
26163
- constructor(props) {
26164
- __publicField(this, "node");
26165
- __publicField(this, "view");
26166
- __publicField(this, "getPos");
26167
- __publicField(this, "decorations");
26168
- __publicField(this, "innerDecorations");
26169
- __publicField(this, "editor");
26170
- __publicField(this, "extension");
26171
- __publicField(this, "htmlAttributes");
26172
- __publicField(this, "root");
26173
- __publicField(this, "isDragging", false);
26174
- this.node = props.node;
26175
- this.view = props.editor.view;
26176
- this.getPos = props.getPos;
26177
- this.decorations = props.decorations;
26178
- this.innerDecorations = props.innerDecorations;
26179
- this.editor = props.editor;
26180
- this.extension = props.extension;
26181
- this.htmlAttributes = props.htmlAttributes;
26182
- this.mount(props);
26183
- }
26184
- mount() {
26185
- return;
26186
- }
26187
- get dom() {
26188
- return this.root;
26189
- }
26190
- get contentDOM() {
26191
- return null;
26192
- }
26193
- update(node, decorations, innerDecorations) {
26194
- if (node.type !== this.node.type) {
26195
- return false;
26196
- }
26197
- this.node = node;
26198
- this.decorations = decorations;
26199
- this.innerDecorations = innerDecorations;
26200
- this.updateHTMLAttributes();
26201
- return true;
26202
- }
26203
- stopEvent(event) {
26204
- if (!this.dom) return false;
26205
- const target = event.target;
26206
- const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
26207
- if (!isInElement) return false;
26208
- const isDragEvent = event.type.startsWith("drag");
26209
- const isDropEvent = event.type === "drop";
26210
- const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
26211
- if (isInput && !isDropEvent && !isDragEvent) return true;
26212
- const { isEditable } = this.editor;
26213
- const { isDragging } = this;
26214
- const isDraggable = !!this.node.type.spec.draggable;
26215
- const isSelectable = NodeSelection.isSelectable(this.node);
26216
- const isCopyEvent = event.type === "copy";
26217
- const isPasteEvent = event.type === "paste";
26218
- const isCutEvent = event.type === "cut";
26219
- const isClickEvent = event.type === "mousedown";
26220
- if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
26221
- event.preventDefault();
26222
- }
26223
- if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
26224
- event.preventDefault();
26225
- return false;
26226
- }
26227
- if (isDraggable && isEditable && !isDragging && isClickEvent) {
26228
- const dragHandle = target.closest("[data-drag-handle]");
26229
- const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
26230
- if (isValidDragHandle) {
26231
- this.isDragging = true;
26232
- document.addEventListener(
26233
- "dragend",
26234
- () => {
26235
- this.isDragging = false;
26236
- },
26237
- { once: true }
26238
- );
26239
- document.addEventListener(
26240
- "drop",
26241
- () => {
26242
- this.isDragging = false;
26243
- },
26244
- { once: true }
26245
- );
26246
- document.addEventListener(
26247
- "mouseup",
26248
- () => {
26249
- this.isDragging = false;
26250
- },
26251
- { once: true }
26252
- );
26253
- }
26254
- }
26255
- if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
26256
- return false;
26257
- }
26258
- return true;
26259
- }
26260
- ignoreMutation(mutation) {
26261
- if (!this.dom || !this.contentDOM) return true;
26262
- if (this.node.isLeaf || this.node.isAtom) return true;
26263
- if (mutation.type === "selection") return false;
26264
- if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
26265
- if (this.contentDOM.contains(mutation.target)) return false;
26266
- return true;
26267
- }
26268
- destroy() {
26269
- this.dom.remove();
26270
- this.contentDOM?.remove();
26271
- }
26272
- updateAttributes(attrs) {
26273
- const pos = this.getPos();
26274
- if (typeof pos !== "number") {
26275
- return;
26276
- }
26277
- return this.view.dispatch(
26278
- this.view.state.tr.setNodeMarkup(pos, void 0, {
26279
- ...this.node.attrs,
26280
- ...attrs
26281
- })
26282
- );
26283
- }
26284
- updateHTMLAttributes() {
26285
- const { extensionService } = this.editor;
26286
- const { attributes } = extensionService;
26287
- const extensionAttrs = attributes.filter((i) => i.type === this.node.type.name);
26288
- this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
26289
- }
26290
- createDragHandle() {
26291
- const dragHandle = document.createElement("span");
26292
- dragHandle.classList.add("sd-structured-content-draggable");
26293
- dragHandle.draggable = true;
26294
- dragHandle.contentEditable = "false";
26295
- dragHandle.dataset.dragHandle = "";
26296
- const textElement = document.createElement("span");
26297
- textElement.textContent = "Structured content";
26298
- dragHandle.append(textElement);
26299
- return dragHandle;
26300
- }
26301
- onDragStart(event) {
26302
- const { view } = this.editor;
26303
- const target = event.target;
26304
- const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
26305
- if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
26306
- return;
26307
- }
26308
- let x = 0;
26309
- let y = 0;
26310
- if (this.dom !== dragHandle) {
26311
- const domBox = this.dom.getBoundingClientRect();
26312
- const handleBox = dragHandle.getBoundingClientRect();
26313
- const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
26314
- const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
26315
- x = handleBox.x - domBox.x + offsetX;
26316
- y = handleBox.y - domBox.y + offsetY;
26317
- }
26318
- event.dataTransfer?.setDragImage(this.dom, x, y);
26319
- const pos = this.getPos();
26320
- if (typeof pos !== "number") {
26321
- return;
26322
- }
26323
- const selection = NodeSelection.create(view.state.doc, pos);
26324
- const transaction = view.state.tr.setSelection(selection);
26325
- view.dispatch(transaction);
26326
- }
26327
- }
26328
- class StructuredContentInlineView extends StructuredContentViewBase {
26329
- constructor(props) {
26330
- super(props);
26331
- }
26332
- mount() {
26333
- this.buildView();
26334
- }
26335
- get contentDOM() {
26336
- const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
26337
- return contentElement || null;
26338
- }
26339
- createElement() {
26340
- const element = document.createElement("span");
26341
- element.classList.add(structuredContentClass$1);
26342
- element.setAttribute("data-structured-content", "");
26343
- const contentElement = document.createElement("span");
26344
- contentElement.classList.add(structuredContentInnerClass$1);
26345
- element.append(contentElement);
26346
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
26347
- updateDOMAttributes(element, { ...domAttrs });
26348
- return { element, contentElement };
26349
- }
26350
- buildView() {
26351
- const { element } = this.createElement();
26352
- const dragHandle = this.createDragHandle();
26353
- element.prepend(dragHandle);
26354
- element.addEventListener("dragstart", (e) => this.onDragStart(e));
26355
- this.root = element;
26356
- }
26357
- updateView() {
26358
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
26359
- updateDOMAttributes(this.dom, { ...domAttrs });
26360
- }
26361
- update(node, decorations, innerDecorations) {
26362
- const result = super.update(node, decorations, innerDecorations);
26363
- if (!result) return false;
26364
- this.updateView();
26365
- return true;
26366
- }
26367
- }
26368
- const structuredContentClass$1 = "sd-structured-content";
26369
- const structuredContentInnerClass$1 = "sd-structured-content__content";
26370
- const StructuredContent = Node$1.create({
26371
- name: "structuredContent",
26372
- group: "inline structuredContent",
26373
- inline: true,
26374
- content: "inline*",
26375
- isolating: true,
26376
- atom: false,
26377
- // false - has editable content.
26378
- draggable: true,
26379
- addOptions() {
26380
- return {
26381
- htmlAttributes: {
26382
- class: structuredContentClass$1,
26383
- "aria-label": "Structured content node"
26384
- }
26385
- };
26386
- },
26387
- addAttributes() {
26388
- return {
26389
- id: {
26390
- default: null,
26391
- parseDOM: (elem) => elem.getAttribute("data-id"),
26392
- renderDOM: (attrs) => {
26393
- if (!attrs.id) return {};
26394
- return { "data-id": attrs.id };
26395
- }
26396
- },
26397
- sdtPr: {
26398
- rendered: false
26399
- }
26400
- };
26401
- },
26402
- parseDOM() {
26403
- return [{ tag: "span[data-structured-content]" }];
26404
- },
26405
- renderDOM({ htmlAttributes }) {
26406
- return [
26407
- "span",
26408
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
26409
- "data-structured-content": ""
26410
- }),
26411
- 0
26412
- ];
26413
- },
26414
- addNodeView() {
26415
- return (props) => {
26416
- return new StructuredContentInlineView({ ...props });
26417
- };
26418
- }
26419
- });
26420
- class StructuredContentBlockView extends StructuredContentViewBase {
26421
- constructor(props) {
26422
- super(props);
26423
- }
26424
- mount() {
26425
- this.buildView();
26426
- }
26427
- get contentDOM() {
26428
- const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass}`);
26429
- return contentElement || null;
26430
- }
26431
- createElement() {
26432
- const element = document.createElement("div");
26433
- element.classList.add(structuredContentClass);
26434
- element.setAttribute("data-structured-content-block", "");
26435
- const contentElement = document.createElement("div");
26436
- contentElement.classList.add(structuredContentInnerClass);
26437
- element.append(contentElement);
26438
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
26439
- updateDOMAttributes(element, { ...domAttrs });
26440
- return { element, contentElement };
26441
- }
26442
- buildView() {
26443
- const { element } = this.createElement();
26444
- const dragHandle = this.createDragHandle();
26445
- element.prepend(dragHandle);
26446
- element.addEventListener("dragstart", (e) => this.onDragStart(e));
26447
- this.root = element;
26448
- }
26449
- updateView() {
26450
- const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
26451
- updateDOMAttributes(this.dom, { ...domAttrs });
26452
- }
26453
- update(node, decorations, innerDecorations) {
26454
- const result = super.update(node, decorations, innerDecorations);
26455
- if (!result) return false;
26456
- this.updateView();
26457
- return true;
27109
+ {
27110
+ tag: `div[data-type="${this.name}"]`
27111
+ }
27112
+ ];
27113
+ },
27114
+ renderDOM({ htmlAttributes }) {
27115
+ return [
27116
+ "div",
27117
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
27118
+ 0
27119
+ ];
26458
27120
  }
26459
- }
26460
- const structuredContentClass = "sd-structured-content-block";
26461
- const structuredContentInnerClass = "sd-structured-content-block__content";
26462
- const StructuredContentBlock = Node$1.create({
26463
- name: "structuredContentBlock",
26464
- group: "block structuredContent",
26465
- content: "block*",
27121
+ });
27122
+ const ShapeTextbox = Node$1.create({
27123
+ name: "shapeTextbox",
27124
+ group: "block",
27125
+ content: "paragraph* block*",
26466
27126
  isolating: true,
26467
- atom: false,
26468
- // false - has editable content.
26469
- draggable: true,
26470
27127
  addOptions() {
26471
27128
  return {
26472
27129
  htmlAttributes: {
26473
- class: structuredContentClass,
26474
- "aria-label": "Structured content block node"
27130
+ class: "sd-editor-shape-textbox",
27131
+ "aria-label": "Shape textbox node"
26475
27132
  }
26476
27133
  };
26477
27134
  },
26478
27135
  addAttributes() {
26479
27136
  return {
26480
- id: {
27137
+ sdBlockId: {
26481
27138
  default: null,
26482
- parseDOM: (elem) => elem.getAttribute("data-id"),
27139
+ keepOnSplit: false,
27140
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
26483
27141
  renderDOM: (attrs) => {
26484
- if (!attrs.id) return {};
26485
- return { "data-id": attrs.id };
27142
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
26486
27143
  }
26487
27144
  },
26488
- sdtPr: {
27145
+ attributes: {
26489
27146
  rendered: false
26490
27147
  }
26491
27148
  };
26492
27149
  },
26493
27150
  parseDOM() {
26494
- return [{ tag: "div[data-structured-content-block]" }];
27151
+ return [
27152
+ {
27153
+ tag: `div[data-type="${this.name}"]`
27154
+ }
27155
+ ];
26495
27156
  },
26496
27157
  renderDOM({ htmlAttributes }) {
26497
27158
  return [
26498
27159
  "div",
26499
- Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
26500
- "data-structured-content-block": ""
26501
- }),
27160
+ Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
26502
27161
  0
26503
27162
  ];
26504
- },
26505
- addNodeView() {
26506
- return (props) => {
26507
- return new StructuredContentBlockView({ ...props });
26508
- };
26509
27163
  }
26510
27164
  });
26511
- class DocumentSectionView {
26512
- constructor(node, getPos, decorations, editor) {
26513
- __privateAdd(this, _DocumentSectionView_instances);
26514
- this.node = node;
26515
- this.editor = editor;
26516
- this.decorations = decorations;
26517
- this.view = editor.view;
26518
- this.getPos = getPos;
26519
- __privateMethod(this, _DocumentSectionView_instances, init_fn3).call(this);
26520
- }
26521
- }
26522
- _DocumentSectionView_instances = new WeakSet();
26523
- init_fn3 = function() {
26524
- const { attrs } = this.node;
26525
- const { id, title, description } = attrs;
26526
- this.dom = document.createElement("div");
26527
- this.dom.className = "sd-document-section-block";
26528
- this.dom.setAttribute("data-id", id);
26529
- this.dom.setAttribute("data-title", title);
26530
- this.dom.setAttribute("data-description", description);
26531
- this.dom.setAttribute("aria-label", "Document section");
26532
- __privateMethod(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
26533
- this.contentDOM = document.createElement("div");
26534
- this.contentDOM.className = "sd-document-section-block-content";
26535
- this.contentDOM.setAttribute("contenteditable", "true");
26536
- this.dom.appendChild(this.contentDOM);
26537
- };
26538
- addToolTip_fn = function() {
26539
- const { title } = this.node.attrs;
26540
- this.infoDiv = document.createElement("div");
26541
- this.infoDiv.className = "sd-document-section-block-info";
26542
- const textSpan = document.createElement("span");
26543
- textSpan.textContent = title || "Document section";
26544
- this.infoDiv.appendChild(textSpan);
26545
- this.infoDiv.setAttribute("contenteditable", "false");
26546
- this.dom.appendChild(this.infoDiv);
26547
- };
26548
- const getAllSections = (editor) => {
26549
- if (!editor) return [];
26550
- const type = editor.schema.nodes.documentSection;
26551
- if (!type) return [];
26552
- const sections = [];
26553
- const { state } = editor;
26554
- state.doc.descendants((node, pos) => {
26555
- if (node.type.name === type.name) {
26556
- sections.push({ node, pos });
26557
- }
26558
- });
26559
- return sections;
26560
- };
26561
- const exportSectionsToHTML = (editor) => {
26562
- const sections = getAllSections(editor);
26563
- const processedSections = /* @__PURE__ */ new Set();
26564
- const result = [];
26565
- sections.forEach(({ node }) => {
26566
- const { attrs } = node;
26567
- const { id, title, description } = attrs;
26568
- if (processedSections.has(id)) return;
26569
- processedSections.add(id);
26570
- const html = getHTMLFromNode(node, editor);
26571
- result.push({
26572
- id,
26573
- title,
26574
- description,
26575
- html
26576
- });
26577
- });
26578
- return result;
26579
- };
26580
- const getHTMLFromNode = (node, editor) => {
26581
- const tempDocument = document.implementation.createHTMLDocument();
26582
- const container = tempDocument.createElement("div");
26583
- const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
26584
- container.appendChild(fragment);
26585
- let html = container.innerHTML;
26586
- return html;
26587
- };
26588
- const exportSectionsToJSON = (editor) => {
26589
- const sections = getAllSections(editor);
26590
- const processedSections = /* @__PURE__ */ new Set();
26591
- const result = [];
26592
- sections.forEach(({ node }) => {
26593
- const { attrs } = node;
26594
- const { id, title, description } = attrs;
26595
- if (processedSections.has(id)) return;
26596
- processedSections.add(id);
26597
- result.push({
26598
- id,
26599
- title,
26600
- description,
26601
- content: node.toJSON()
26602
- });
26603
- });
26604
- return result;
26605
- };
26606
- const getLinkedSectionEditor = (id, options, editor) => {
26607
- const sections = getAllSections(editor);
26608
- const section = sections.find((s) => s.node.attrs.id === id);
26609
- if (!section) return null;
26610
- const child = editor.createChildEditor({
26611
- ...options,
26612
- onUpdate: ({ editor: childEditor, transaction }) => {
26613
- const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
26614
- if (isFromtLinkedParent) return;
26615
- const updatedContent = childEditor.state.doc.content;
26616
- const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
26617
- if (!sectionNode) return;
26618
- const { pos, node } = sectionNode;
26619
- const newNode = node.type.create(node.attrs, updatedContent, node.marks);
26620
- const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
26621
- tr.setMeta("fromLinkedChild", true);
26622
- editor.view.dispatch(tr);
26623
- }
26624
- });
26625
- editor.on("update", ({ transaction }) => {
26626
- const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
26627
- if (isFromLinkedChild) return;
26628
- const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
26629
- if (!sectionNode) return;
26630
- const sectionContent = sectionNode.node.content;
26631
- const json = {
26632
- type: "doc",
26633
- content: sectionContent.content.map((node) => node.toJSON())
26634
- };
26635
- const childTr = child.state.tr;
26636
- childTr.setMeta("fromLinkedParent", true);
26637
- childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
26638
- child.view.dispatch(childTr);
26639
- });
26640
- return child;
26641
- };
26642
- const SectionHelpers = {
26643
- getAllSections,
26644
- exportSectionsToHTML,
26645
- exportSectionsToJSON,
26646
- getLinkedSectionEditor
26647
- };
26648
- const DocumentSection = Node$1.create({
26649
- name: "documentSection",
26650
- group: "block",
26651
- content: "block*",
26652
- atom: true,
27165
+ const ContentBlock = Node$1.create({
27166
+ name: "contentBlock",
27167
+ group: "inline",
27168
+ content: "",
26653
27169
  isolating: true,
27170
+ atom: true,
27171
+ inline: true,
26654
27172
  addOptions() {
26655
27173
  return {
26656
27174
  htmlAttributes: {
26657
- class: "sd-document-section-block",
26658
- "aria-label": "Structured content block"
27175
+ contenteditable: false
26659
27176
  }
26660
27177
  };
26661
27178
  },
26662
- parseDOM() {
26663
- return [
26664
- {
26665
- tag: "div.sd-document-section-block",
26666
- priority: 60
26667
- }
26668
- ];
26669
- },
26670
- renderDOM({ htmlAttributes }) {
26671
- return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
26672
- },
26673
27179
  addAttributes() {
26674
27180
  return {
26675
- id: {},
26676
- sdBlockId: {
27181
+ horizontalRule: {
27182
+ default: false,
27183
+ renderDOM: ({ horizontalRule }) => {
27184
+ if (!horizontalRule) return {};
27185
+ return { "data-horizontal-rule": "true" };
27186
+ }
27187
+ },
27188
+ size: {
27189
+ default: null,
27190
+ renderDOM: ({ size }) => {
27191
+ if (!size) return {};
27192
+ let style = "";
27193
+ if (size.top) style += `top: ${size.top}px; `;
27194
+ if (size.left) style += `left: ${size.left}px; `;
27195
+ if (size.width) style += `width: ${size.width.toString().endsWith("%") ? size.width : `${size.width}px`}; `;
27196
+ if (size.height)
27197
+ style += `height: ${size.height.toString().endsWith("%") ? size.height : `${size.height}px`}; `;
27198
+ return { style };
27199
+ }
27200
+ },
27201
+ background: {
26677
27202
  default: null,
26678
- keepOnSplit: false,
26679
- parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
26680
27203
  renderDOM: (attrs) => {
26681
- return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
27204
+ if (!attrs.background) return {};
27205
+ return {
27206
+ style: `background-color: ${attrs.background}`
27207
+ };
26682
27208
  }
26683
27209
  },
26684
- title: {},
26685
- description: {},
26686
- sectionType: {},
26687
- isLocked: { default: false }
27210
+ drawingContent: {
27211
+ rendered: false
27212
+ },
27213
+ attributes: {
27214
+ rendered: false
27215
+ }
26688
27216
  };
26689
27217
  },
26690
- addNodeView() {
26691
- return ({ node, editor, getPos, decorations }) => {
26692
- return new DocumentSectionView(node, getPos, decorations, editor);
26693
- };
27218
+ parseDOM() {
27219
+ return [
27220
+ {
27221
+ tag: `div[data-type="${this.name}"]`
27222
+ }
27223
+ ];
27224
+ },
27225
+ renderDOM({ htmlAttributes }) {
27226
+ return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name })];
26694
27227
  },
26695
27228
  addCommands() {
26696
27229
  return {
26697
27230
  /**
26698
- * Create a lockable content section
27231
+ * Insert a horizontal rule
26699
27232
  * @category Command
26700
- * @param {SectionCreate} [options={}] - Section configuration
26701
27233
  * @example
26702
- * editor.commands.createDocumentSection({
26703
- * id: 1,
26704
- * title: 'Terms & Conditions',
26705
- * isLocked: true,
26706
- * html: '<p>Legal content...</p>'
26707
- * })
27234
+ * editor.commands.insertHorizontalRule()
27235
+ * @note Creates a visual separator between content sections
26708
27236
  */
26709
- createDocumentSection: (options = {}) => ({ tr, state, dispatch, editor }) => {
26710
- const { selection } = state;
26711
- let { from: from2, to } = selection;
26712
- let content = selection.content().content;
26713
- const { html: optionsHTML, json: optionsJSON } = options;
26714
- if (optionsHTML) {
26715
- const html = htmlHandler(optionsHTML, this.editor);
26716
- const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
26717
- content = doc2.content;
26718
- }
26719
- if (optionsJSON) {
26720
- content = this.editor.schema.nodeFromJSON(optionsJSON);
26721
- }
26722
- if (!content?.content?.length) {
26723
- content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
26724
- }
26725
- if (!options.id) {
26726
- const allSections = SectionHelpers.getAllSections(editor);
26727
- options.id = allSections.length + 1;
26728
- }
26729
- if (!options.title) {
26730
- options.title = "Document section";
26731
- }
26732
- const node = this.type.createAndFill(options, content);
26733
- if (!node) return false;
26734
- const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
26735
- if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
26736
- const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
26737
- from2 = insertPos2;
26738
- to = insertPos2;
26739
- }
26740
- tr.replaceRangeWith(from2, to, node);
26741
- const nodeEnd = from2 + node.nodeSize;
26742
- let shouldInsertParagraph = true;
26743
- let insertPos = nodeEnd;
26744
- if (nodeEnd >= tr.doc.content.size) {
26745
- insertPos = tr.doc.content.size;
26746
- if (insertPos > 0) {
26747
- const $endPos = tr.doc.resolve(insertPos);
26748
- if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
26749
- shouldInsertParagraph = false;
26750
- }
27237
+ insertHorizontalRule: () => ({ commands: commands2 }) => {
27238
+ return commands2.insertContent({
27239
+ type: this.name,
27240
+ attrs: {
27241
+ horizontalRule: true,
27242
+ size: { width: "100%", height: 2 },
27243
+ background: "#e5e7eb"
26751
27244
  }
26752
- }
26753
- if (shouldInsertParagraph) {
26754
- const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
26755
- tr.insert(insertPos, emptyParagraph);
26756
- }
26757
- if (dispatch) {
26758
- tr.setMeta("documentSection", { action: "create" });
26759
- dispatch(tr);
26760
- setTimeout(() => {
26761
- try {
26762
- const currentState = editor.state;
26763
- const docSize = currentState.doc.content.size;
26764
- let targetPos = from2 + node.nodeSize;
26765
- if (shouldInsertParagraph) {
26766
- targetPos += 1;
26767
- }
26768
- targetPos = Math.min(targetPos, docSize);
26769
- if (targetPos < docSize && targetPos > 0) {
26770
- const newSelection = Selection.near(currentState.doc.resolve(targetPos));
26771
- const newTr = currentState.tr.setSelection(newSelection);
26772
- editor.view.dispatch(newTr);
26773
- }
26774
- } catch (e) {
26775
- console.warn("Could not set delayed selection:", e);
26776
- }
26777
- }, 0);
26778
- }
26779
- return true;
26780
- },
26781
- /**
26782
- * Remove section wrapper at cursor, preserving its content
26783
- * @category Command
26784
- * @example
26785
- * editor.commands.removeSectionAtSelection()
26786
- * @note Content stays in document, only section wrapper is removed
26787
- */
26788
- removeSectionAtSelection: () => ({ tr, dispatch }) => {
26789
- const sdtNode = findParentNode((node2) => node2.type.name === "documentSection")(tr.selection);
26790
- if (!sdtNode) return false;
26791
- const { node, pos } = sdtNode;
26792
- const nodeStart = pos;
26793
- const nodeEnd = nodeStart + node.nodeSize;
26794
- const contentToPreserve = node.content;
26795
- tr.delete(nodeStart, nodeEnd);
26796
- if (contentToPreserve.size > 0) {
26797
- tr.insert(nodeStart, contentToPreserve);
26798
- }
26799
- const newPos = Math.min(nodeStart, tr.doc.content.size);
26800
- tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
26801
- if (dispatch) {
26802
- tr.setMeta("documentSection", { action: "delete" });
26803
- dispatch(tr);
26804
- }
26805
- return true;
26806
- },
26807
- /**
26808
- * Delete section and all its content
26809
- * @category Command
26810
- * @param {number} id - Section to delete
26811
- * @example
26812
- * editor.commands.removeSectionById(123)
26813
- */
26814
- removeSectionById: (id) => ({ tr, dispatch }) => {
26815
- const sections = SectionHelpers.getAllSections(this.editor);
26816
- const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
26817
- if (!sectionToRemove) return false;
26818
- const { pos, node } = sectionToRemove;
26819
- const nodeStart = pos;
26820
- const nodeEnd = nodeStart + node.nodeSize;
26821
- tr.delete(nodeStart, nodeEnd);
26822
- if (dispatch) {
26823
- tr.setMeta("documentSection", { action: "delete", id });
26824
- dispatch(tr);
26825
- }
26826
- return true;
27245
+ });
26827
27246
  },
26828
27247
  /**
26829
- * Lock section against edits
27248
+ * Insert a content block
26830
27249
  * @category Command
26831
- * @param {number} id - Section to lock
27250
+ * @param {ContentBlockConfig} config - Block configuration
26832
27251
  * @example
26833
- * editor.commands.lockSectionById(123)
26834
- */
26835
- lockSectionById: (id) => ({ tr, dispatch }) => {
26836
- const sections = SectionHelpers.getAllSections(this.editor);
26837
- const sectionToLock = sections.find(({ node }) => node.attrs.id === id);
26838
- if (!sectionToLock) return false;
26839
- tr.setNodeMarkup(sectionToLock.pos, null, { ...sectionToLock.node.attrs, isLocked: true });
26840
- if (dispatch) {
26841
- tr.setMeta("documentSection", { action: "lock", id });
26842
- dispatch(tr);
26843
- }
26844
- return true;
26845
- },
26846
- /**
26847
- * Modify section attributes or content
26848
- * @category Command
26849
- * @param {SectionUpdate} options - Changes to apply
27252
+ * // Insert a spacer block
27253
+ * editor.commands.insertContentBlock({ size: { height: 20 } })
27254
+ *
26850
27255
  * @example
26851
- * editor.commands.updateSectionById({ id: 123, attrs: { isLocked: false } })
26852
- * editor.commands.updateSectionById({ id: 123, html: '<p>New content</p>' })
26853
- * editor.commands.updateSectionById({
26854
- * id: 123,
26855
- * html: '<p>Updated</p>',
26856
- * attrs: { title: 'New Title' }
27256
+ * // Insert a colored divider
27257
+ * editor.commands.insertContentBlock({
27258
+ * size: { width: '50%', height: 3 },
27259
+ * background: '#3b82f6'
26857
27260
  * })
27261
+ * @note Used for spacing, dividers, and special inline content
26858
27262
  */
26859
- updateSectionById: ({ id, html, json, attrs }) => ({ tr, dispatch, editor }) => {
26860
- const sections = SectionHelpers.getAllSections(editor || this.editor);
26861
- const sectionToUpdate = sections.find(({ node: node2 }) => node2.attrs.id === id);
26862
- if (!sectionToUpdate) return false;
26863
- const { pos, node } = sectionToUpdate;
26864
- let newContent = null;
26865
- if (html) {
26866
- const htmlDoc = htmlHandler(html, editor || this.editor);
26867
- const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
26868
- newContent = doc2.content;
26869
- }
26870
- if (json) {
26871
- newContent = (editor || this.editor).schema.nodeFromJSON(json);
26872
- }
26873
- if (!newContent) {
26874
- newContent = node.content;
26875
- }
26876
- const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
26877
- tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
26878
- if (dispatch) {
26879
- tr.setMeta("documentSection", { action: "update", id, attrs });
26880
- dispatch(tr);
26881
- }
26882
- return true;
27263
+ insertContentBlock: (config) => ({ commands: commands2 }) => {
27264
+ return commands2.insertContent({
27265
+ type: this.name,
27266
+ attrs: config
27267
+ });
26883
27268
  }
26884
27269
  };
26885
- },
26886
- addHelpers() {
26887
- return {
26888
- ...SectionHelpers
26889
- };
26890
27270
  }
26891
27271
  });
26892
27272
  const { findChildren } = helpers;
@@ -27090,6 +27470,51 @@ const checkForNewBlockNodesInTrs = (transactions) => {
27090
27470
  });
27091
27471
  });
27092
27472
  };
27473
+ const TableOfContents = Node$1.create({
27474
+ name: "tableOfContents",
27475
+ group: "block",
27476
+ content: "paragraph+",
27477
+ inline: false,
27478
+ addOptions() {
27479
+ return {
27480
+ htmlAttributes: {
27481
+ "data-id": "table-of-contents",
27482
+ "aria-label": "Table of Contents"
27483
+ }
27484
+ };
27485
+ },
27486
+ parseDOM() {
27487
+ return [
27488
+ {
27489
+ tag: 'div[data-id="table-of-contents"]'
27490
+ }
27491
+ ];
27492
+ },
27493
+ renderDOM({ htmlAttributes }) {
27494
+ return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
27495
+ },
27496
+ addAttributes() {
27497
+ return {
27498
+ instruction: {
27499
+ default: null,
27500
+ rendered: false
27501
+ },
27502
+ /**
27503
+ * @private
27504
+ * @category Attribute
27505
+ * @param {string} [sdBlockId] - Internal block tracking ID (not user-configurable)
27506
+ */
27507
+ sdBlockId: {
27508
+ default: null,
27509
+ keepOnSplit: false,
27510
+ parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
27511
+ renderDOM: (attrs) => {
27512
+ return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
27513
+ }
27514
+ }
27515
+ };
27516
+ }
27517
+ });
27093
27518
  const TextStyle = Mark.create({
27094
27519
  name: "textStyle",
27095
27520
  addOptions() {
@@ -33454,7 +33879,8 @@ const nodeResizer = (nodeNames = ["image"], editor) => {
33454
33879
  const prevSelection = prevState.selection;
33455
33880
  if (selection.from !== prevSelection.from || selection.to !== prevSelection.to) {
33456
33881
  setTimeout(() => {
33457
- const selectedResizableWrapper = document.querySelector(".sd-editor-resizable-wrapper");
33882
+ const searchRoot = editorView?.dom;
33883
+ const selectedResizableWrapper = searchRoot?.querySelector(".sd-editor-resizable-wrapper");
33458
33884
  if (selectedResizableWrapper) {
33459
33885
  showResizeHandles(view2, selectedResizableWrapper);
33460
33886
  } else {
@@ -33695,6 +34121,7 @@ const getStarterExtensions = () => {
33695
34121
  SlashMenu,
33696
34122
  Strike,
33697
34123
  TabNode,
34124
+ TableOfContents,
33698
34125
  Text,
33699
34126
  TextAlign,
33700
34127
  TextIndent,
@@ -33729,13 +34156,16 @@ const getStarterExtensions = () => {
33729
34156
  AiLoaderNode,
33730
34157
  PageNumber,
33731
34158
  TotalPageCount,
34159
+ PageReference,
33732
34160
  ShapeContainer,
33733
34161
  ShapeTextbox,
33734
34162
  ContentBlock,
33735
34163
  Search,
33736
34164
  StructuredContent,
33737
34165
  StructuredContentBlock,
34166
+ StructuredContentCommands,
33738
34167
  DocumentSection,
34168
+ DocumentPartObject,
33739
34169
  NodeResizer,
33740
34170
  CustomSelection,
33741
34171
  TextTransform
@@ -33768,6 +34198,7 @@ export {
33768
34198
  SectionHelpers as o,
33769
34199
  getAllowedImageDimensions as p,
33770
34200
  replaceSelectionWithImagePlaceholder as r,
34201
+ shouldBypassContextMenu as s,
33771
34202
  useHighContrastMode as u,
33772
34203
  yUndoPluginKey as y
33773
34204
  };