@harbour-enterprises/superdoc 0.28.1 → 0.28.3

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 (60) hide show
  1. package/dist/chunks/{PdfViewer-DJkdA-8o.es.js → PdfViewer-DUpLlOgk.es.js} +1 -1
  2. package/dist/chunks/{PdfViewer-Can0yoW4.cjs → PdfViewer-QTV3RJM1.cjs} +1 -1
  3. package/dist/chunks/{index-njnq8umX-DU2xcaHZ.es.js → index-B3rVM2bJ-B62R9mgx.es.js} +1 -1
  4. package/dist/chunks/{index-njnq8umX-_TfP84XP.cjs → index-B3rVM2bJ-BgYPFhrh.cjs} +1 -1
  5. package/dist/chunks/{index-BY-vlgKe.cjs → index-CuXB3dyN.cjs} +3 -3
  6. package/dist/chunks/{index-DidXsI6u.es.js → index-DKtyoTAq.es.js} +3 -3
  7. package/dist/chunks/{super-editor.es-ksiTgGLm.cjs → super-editor.es-BKCxu5-_.cjs} +1617 -1125
  8. package/dist/chunks/{super-editor.es-Br566URP.es.js → super-editor.es-BjTZa-cJ.es.js} +1617 -1125
  9. package/dist/core/types/index.d.ts.map +1 -1
  10. package/dist/super-editor/ai-writer.es.js +2 -2
  11. package/dist/super-editor/chunks/{converter-D6Z6OmA3.js → converter-CMtyH2w0.js} +654 -644
  12. package/dist/super-editor/chunks/{docx-zipper-Dni97kMT.js → docx-zipper-Pgf9i5kI.js} +1 -1
  13. package/dist/super-editor/chunks/{editor-D3TKfdXs.js → editor-C3KgN3zx.js} +616 -134
  14. package/dist/super-editor/chunks/{index-njnq8umX.js → index-B3rVM2bJ.js} +1 -1
  15. package/dist/super-editor/chunks/{toolbar-fNE3luLB.js → toolbar-TXkIPPvk.js} +2 -2
  16. package/dist/super-editor/converter.es.js +1 -1
  17. package/dist/super-editor/docx-zipper.es.js +2 -2
  18. package/dist/super-editor/editor.es.js +3 -3
  19. package/dist/super-editor/file-zipper.es.js +1 -1
  20. package/dist/super-editor/super-editor/src/core/helpers/rangeUtils.d.ts +2 -0
  21. package/dist/super-editor/super-editor/src/extensions/field-annotation/FieldAnnotationPlugin.d.ts +5 -1
  22. package/dist/super-editor/super-editor/src/extensions/image/imageHelpers/imagePositionPlugin.d.ts +2 -0
  23. package/dist/super-editor/super-editor/src/extensions/list-item/helpers/listItemTypography.d.ts +5 -0
  24. package/dist/super-editor/super-editor/src/extensions/list-item/helpers/styledListMarkerPlugin.d.ts +11 -2
  25. package/dist/super-editor/super-editor/src/extensions/tab/helpers/tabDecorations.d.ts +4 -1
  26. package/dist/super-editor/super-editor.es.js +6 -6
  27. package/dist/super-editor/toolbar.es.js +2 -2
  28. package/dist/super-editor.cjs +1 -1
  29. package/dist/super-editor.es.js +1 -1
  30. package/dist/superdoc.cjs +2 -2
  31. package/dist/superdoc.es.js +2 -2
  32. package/dist/superdoc.umd.js +1381 -889
  33. package/dist/superdoc.umd.js.map +1 -1
  34. package/package.json +1 -1
  35. package/dist/images/altText_add.svg +0 -3
  36. package/dist/images/altText_disclaimer.svg +0 -3
  37. package/dist/images/altText_done.svg +0 -3
  38. package/dist/images/altText_spinner.svg +0 -30
  39. package/dist/images/altText_warning.svg +0 -3
  40. package/dist/images/annotation-check.svg +0 -11
  41. package/dist/images/annotation-comment.svg +0 -16
  42. package/dist/images/annotation-help.svg +0 -26
  43. package/dist/images/annotation-insert.svg +0 -10
  44. package/dist/images/annotation-key.svg +0 -11
  45. package/dist/images/annotation-newparagraph.svg +0 -11
  46. package/dist/images/annotation-noicon.svg +0 -7
  47. package/dist/images/annotation-note.svg +0 -42
  48. package/dist/images/annotation-paperclip.svg +0 -6
  49. package/dist/images/annotation-paragraph.svg +0 -16
  50. package/dist/images/annotation-pushpin.svg +0 -7
  51. package/dist/images/cursor-editorFreeHighlight.svg +0 -6
  52. package/dist/images/cursor-editorFreeText.svg +0 -3
  53. package/dist/images/cursor-editorInk.svg +0 -4
  54. package/dist/images/cursor-editorTextHighlight.svg +0 -8
  55. package/dist/images/editor-toolbar-delete.svg +0 -5
  56. package/dist/images/loading-icon.gif +0 -0
  57. package/dist/images/messageBar_closingButton.svg +0 -3
  58. package/dist/images/messageBar_warning.svg +0 -3
  59. package/dist/images/toolbarButton-editorHighlight.svg +0 -6
  60. package/dist/images/toolbarButton-menuArrow.svg +0 -3
@@ -12,9 +12,9 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
12
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, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, checkFonts_fn, determineUnsupportedFonts_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, applyIndentStyling_fn, _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 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 docxNumberingHelpers, ap as parseIndentElement, aq as combineIndents, ar as twipsToPixels, as as PIXELS_PER_INCH, at as SelectionRange, au as Transform, av as isInTable$1, aw as generateDocxRandomId, ax as insertNewRelationship, ay as inchesToPixels } from "./converter-D6Z6OmA3.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 docxNumberingHelpers, ap as parseIndentElement, aq as combineIndents, ar as twipsToPixels, as as PIXELS_PER_INCH, at as SelectionRange, au as Transform, av as isInTable$1, aw as generateDocxRandomId, ax as insertNewRelationship, ay as inchesToPixels } from "./converter-CMtyH2w0.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-Dni97kMT.js";
17
+ import { D as DocxZipper } from "./docx-zipper-Pgf9i5kI.js";
18
18
  var GOOD_LEAF_SIZE = 200;
19
19
  var RopeSequence = function RopeSequence2() {
20
20
  };
@@ -11302,17 +11302,7 @@ const TrackChangesBasePlugin = () => {
11302
11302
  },
11303
11303
  apply(tr, oldState, prevEditorState, newEditorState) {
11304
11304
  const meta = tr.getMeta(TrackChangesBasePluginKey);
11305
- if (!meta) {
11306
- return {
11307
- ...oldState,
11308
- decorations: getTrackChangesDecorations(
11309
- newEditorState,
11310
- oldState.onlyOriginalShown,
11311
- oldState.onlyModifiedShown
11312
- )
11313
- };
11314
- }
11315
- if (meta.type === "TRACK_CHANGES_ENABLE") {
11305
+ if (meta && meta.type === "TRACK_CHANGES_ENABLE") {
11316
11306
  return {
11317
11307
  ...oldState,
11318
11308
  isTrackChangesActive: meta.value === true,
@@ -11323,7 +11313,7 @@ const TrackChangesBasePlugin = () => {
11323
11313
  )
11324
11314
  };
11325
11315
  }
11326
- if (meta.type === "SHOW_ONLY_ORIGINAL") {
11316
+ if (meta && meta.type === "SHOW_ONLY_ORIGINAL") {
11327
11317
  return {
11328
11318
  ...oldState,
11329
11319
  onlyOriginalShown: meta.value === true,
@@ -11331,7 +11321,7 @@ const TrackChangesBasePlugin = () => {
11331
11321
  decorations: getTrackChangesDecorations(newEditorState, meta.value === true, false)
11332
11322
  };
11333
11323
  }
11334
- if (meta.type === "SHOW_ONLY_MODIFIED") {
11324
+ if (meta && meta.type === "SHOW_ONLY_MODIFIED") {
11335
11325
  return {
11336
11326
  ...oldState,
11337
11327
  onlyOriginalShown: false,
@@ -11339,6 +11329,31 @@ const TrackChangesBasePlugin = () => {
11339
11329
  decorations: getTrackChangesDecorations(newEditorState, false, meta.value === true)
11340
11330
  };
11341
11331
  }
11332
+ if (!tr.docChanged) {
11333
+ return oldState;
11334
+ }
11335
+ if (!meta) {
11336
+ let mightAffectTrackChanges = false;
11337
+ tr.steps.forEach((step) => {
11338
+ if (step.slice || step.from !== step.to) {
11339
+ mightAffectTrackChanges = true;
11340
+ }
11341
+ });
11342
+ if (mightAffectTrackChanges) {
11343
+ return {
11344
+ ...oldState,
11345
+ decorations: getTrackChangesDecorations(
11346
+ newEditorState,
11347
+ oldState.onlyOriginalShown,
11348
+ oldState.onlyModifiedShown
11349
+ )
11350
+ };
11351
+ }
11352
+ return {
11353
+ ...oldState,
11354
+ decorations: oldState.decorations.map(tr.mapping, tr.doc)
11355
+ };
11356
+ }
11342
11357
  return {
11343
11358
  ...oldState,
11344
11359
  decorations: getTrackChangesDecorations(
@@ -12091,8 +12106,10 @@ const CommentsPlugin = Extension.create({
12091
12106
  }
12092
12107
  },
12093
12108
  view() {
12094
- let prevDoc;
12095
- let prevActiveThreadId;
12109
+ let prevDoc = null;
12110
+ let prevActiveThreadId = null;
12111
+ let prevAllCommentPositions = {};
12112
+ let hasEverEmitted = false;
12096
12113
  return {
12097
12114
  update(view) {
12098
12115
  const { state } = view;
@@ -12103,16 +12120,20 @@ const CommentsPlugin = Extension.create({
12103
12120
  if (meta?.type === "setActiveComment" || meta?.forceUpdate) {
12104
12121
  shouldUpdate = true;
12105
12122
  }
12106
- if (prevDoc && !prevDoc.eq(doc2)) shouldUpdate = true;
12107
- if (prevActiveThreadId !== currentActiveThreadId) {
12123
+ const docChanged = !prevDoc || !prevDoc.eq(doc2);
12124
+ if (docChanged) shouldUpdate = true;
12125
+ const activeThreadChanged = prevActiveThreadId !== currentActiveThreadId;
12126
+ if (activeThreadChanged) {
12108
12127
  shouldUpdate = true;
12109
12128
  prevActiveThreadId = currentActiveThreadId;
12110
12129
  }
12130
+ const isInitialLoad = prevDoc === null;
12131
+ const onlyActiveThreadChanged = !isInitialLoad && !docChanged && activeThreadChanged;
12111
12132
  if (!shouldUpdate) return;
12112
12133
  prevDoc = doc2;
12113
12134
  shouldUpdate = false;
12114
12135
  const decorations = [];
12115
- const allCommentPositions = {};
12136
+ const allCommentPositions = onlyActiveThreadChanged ? prevAllCommentPositions : {};
12116
12137
  doc2.descendants((node, pos) => {
12117
12138
  const { marks = [] } = node;
12118
12139
  const commentMarks = marks.filter((mark) => mark.type.name === CommentMarkName);
@@ -12120,14 +12141,16 @@ const CommentsPlugin = Extension.create({
12120
12141
  commentMarks.forEach((commentMark) => {
12121
12142
  const { attrs } = commentMark;
12122
12143
  const threadId = attrs.commentId || attrs.importedId;
12123
- const currentBounds = view.coordsAtPos(pos);
12124
- updatePosition({
12125
- allCommentPositions,
12126
- threadId,
12127
- pos,
12128
- currentBounds,
12129
- node
12130
- });
12144
+ if (!onlyActiveThreadChanged) {
12145
+ const currentBounds = view.coordsAtPos(pos);
12146
+ updatePosition({
12147
+ allCommentPositions,
12148
+ threadId,
12149
+ pos,
12150
+ currentBounds,
12151
+ node
12152
+ });
12153
+ }
12131
12154
  const isInternal = attrs.internal;
12132
12155
  if (!hasActive) hasActive = currentActiveThreadId === threadId;
12133
12156
  let color = getHighlightColor({
@@ -12150,20 +12173,22 @@ const CommentsPlugin = Extension.create({
12150
12173
  to: pos + node.nodeSize
12151
12174
  });
12152
12175
  if (trackedChangeMark) {
12153
- const currentBounds = view.coordsAtPos(pos);
12154
- const { id } = trackedChangeMark.mark.attrs;
12155
- updatePosition({
12156
- allCommentPositions,
12157
- threadId: id,
12158
- pos,
12159
- currentBounds,
12160
- node
12161
- });
12162
- const isActiveTrackedChange = currentActiveThreadId === id;
12176
+ if (!onlyActiveThreadChanged) {
12177
+ const currentBounds = view.coordsAtPos(pos);
12178
+ const { id } = trackedChangeMark.mark.attrs;
12179
+ updatePosition({
12180
+ allCommentPositions,
12181
+ threadId: id,
12182
+ pos,
12183
+ currentBounds,
12184
+ node
12185
+ });
12186
+ }
12187
+ const isActiveTrackedChange = currentActiveThreadId === trackedChangeMark.mark.attrs.id;
12163
12188
  if (isActiveTrackedChange) {
12164
12189
  const trackedChangeDeco = Decoration.inline(pos, pos + node.nodeSize, {
12165
12190
  style: `border-width: 2px;`,
12166
- "data-thread-id": id,
12191
+ "data-thread-id": trackedChangeMark.mark.attrs.id,
12167
12192
  class: "sd-editor-tracked-change-highlight"
12168
12193
  });
12169
12194
  decorations.push(trackedChangeDeco);
@@ -12181,7 +12206,16 @@ const CommentsPlugin = Extension.create({
12181
12206
  });
12182
12207
  view.dispatch(tr2);
12183
12208
  }
12184
- editor.emit("comment-positions", { allCommentPositions });
12209
+ if (!onlyActiveThreadChanged) {
12210
+ const positionsChanged = hasPositionsChanged(prevAllCommentPositions, allCommentPositions);
12211
+ const hasComments = Object.keys(allCommentPositions).length > 0;
12212
+ const shouldEmitPositions = positionsChanged || !hasEverEmitted && hasComments;
12213
+ if (shouldEmitPositions) {
12214
+ prevAllCommentPositions = allCommentPositions;
12215
+ hasEverEmitted = true;
12216
+ editor.emit("comment-positions", { allCommentPositions });
12217
+ }
12218
+ }
12185
12219
  }
12186
12220
  };
12187
12221
  }
@@ -12189,6 +12223,22 @@ const CommentsPlugin = Extension.create({
12189
12223
  return [commentsPlugin];
12190
12224
  }
12191
12225
  });
12226
+ const hasPositionsChanged = (prevPositions, currPositions) => {
12227
+ const prevKeys = Object.keys(prevPositions);
12228
+ const currKeys = Object.keys(currPositions);
12229
+ if (prevKeys.length !== currKeys.length) return true;
12230
+ for (const key2 of currKeys) {
12231
+ const prev = prevPositions[key2];
12232
+ const curr = currPositions[key2];
12233
+ if (!prev || !prev.bounds || !curr.bounds) {
12234
+ return true;
12235
+ }
12236
+ if (prev.bounds.top !== curr.bounds.top || prev.bounds.left !== curr.bounds.left) {
12237
+ return true;
12238
+ }
12239
+ }
12240
+ return false;
12241
+ };
12192
12242
  const getActiveCommentId = (doc2, selection) => {
12193
12243
  if (!selection) return;
12194
12244
  const { $from, $to } = selection;
@@ -15002,7 +15052,7 @@ const _Editor = class _Editor extends EventEmitter {
15002
15052
  { default: remarkStringify },
15003
15053
  { default: remarkGfm }
15004
15054
  ] = await Promise.all([
15005
- import("./index-njnq8umX.js"),
15055
+ import("./index-B3rVM2bJ.js"),
15006
15056
  import("./index-DRCvimau.js"),
15007
15057
  import("./index-C_x_N6Uh.js"),
15008
15058
  import("./index-D_sWOSiG.js"),
@@ -15220,7 +15270,7 @@ const _Editor = class _Editor extends EventEmitter {
15220
15270
  * @returns {Object | void} Migration results
15221
15271
  */
15222
15272
  processCollaborationMigrations() {
15223
- console.debug("[checkVersionMigrations] Current editor version", "0.28.0");
15273
+ console.debug("[checkVersionMigrations] Current editor version", "0.28.2");
15224
15274
  if (!this.options.ydoc) return;
15225
15275
  const metaMap = this.options.ydoc.getMap("meta");
15226
15276
  let docVersion = metaMap.get("version");
@@ -19561,8 +19611,36 @@ const createLinkedStylesPlugin = (editor) => {
19561
19611
  if (!editor.converter || editor.options.mode !== "docx") return { ...prev };
19562
19612
  let decorations = prev.decorations || DecorationSet.empty;
19563
19613
  if (tr.docChanged) {
19564
- const styles = LinkedStylesPluginKey.getState(editor.state).styles;
19565
- decorations = generateDecorations(newEditorState, styles);
19614
+ let mightAffectStyles = false;
19615
+ const styleRelatedMarks = /* @__PURE__ */ new Set(["textStyle", "bold", "italic", "underline", "strike"]);
19616
+ tr.steps.forEach((step) => {
19617
+ if (step.slice) {
19618
+ step.slice.content.descendants((node) => {
19619
+ if (node.attrs?.styleId) {
19620
+ mightAffectStyles = true;
19621
+ return false;
19622
+ }
19623
+ if (node.marks.length > 0) {
19624
+ const hasStyleMarks = node.marks.some((mark) => styleRelatedMarks.has(mark.type.name));
19625
+ if (hasStyleMarks) {
19626
+ mightAffectStyles = true;
19627
+ return false;
19628
+ }
19629
+ }
19630
+ });
19631
+ }
19632
+ if (step.jsonID === "addMark" || step.jsonID === "removeMark") {
19633
+ if (step.mark && styleRelatedMarks.has(step.mark.type.name)) {
19634
+ mightAffectStyles = true;
19635
+ }
19636
+ }
19637
+ });
19638
+ if (mightAffectStyles) {
19639
+ const styles = LinkedStylesPluginKey.getState(editor.state).styles;
19640
+ decorations = generateDecorations(newEditorState, styles);
19641
+ } else {
19642
+ decorations = decorations.map(tr.mapping, tr.doc);
19643
+ }
19566
19644
  }
19567
19645
  return { ...prev, decorations };
19568
19646
  }
@@ -19875,6 +19953,12 @@ function parseFontFamilyFromRunProperties(listRunProperties) {
19875
19953
  const eastAsia = listRunProperties?.["w:eastAsia"];
19876
19954
  return ascii || hAnsi || eastAsia || null;
19877
19955
  }
19956
+ const computedStylesCache = /* @__PURE__ */ new WeakMap();
19957
+ function clearComputedStyleCache(domNode) {
19958
+ if (domNode) {
19959
+ computedStylesCache.delete(domNode);
19960
+ }
19961
+ }
19878
19962
  function readNodeViewStyles(view) {
19879
19963
  const fallback = { fontSize: null, fontFamily: null, lineHeight: null };
19880
19964
  if (!view?.dom) return fallback;
@@ -19884,13 +19968,27 @@ function readNodeViewStyles(view) {
19884
19968
  lineHeight: view.dom.style?.lineHeight || null
19885
19969
  };
19886
19970
  if (inline.fontSize && inline.fontFamily && inline.lineHeight) return inline;
19971
+ if (computedStylesCache.has(view.dom)) {
19972
+ const cached = computedStylesCache.get(view.dom);
19973
+ return {
19974
+ fontSize: inline.fontSize || cached.fontSize,
19975
+ fontFamily: inline.fontFamily || cached.fontFamily,
19976
+ lineHeight: inline.lineHeight || cached.lineHeight
19977
+ };
19978
+ }
19887
19979
  const globalWindow = typeof window !== "undefined" ? window : void 0;
19888
19980
  if (globalWindow?.getComputedStyle) {
19889
19981
  const computed2 = globalWindow.getComputedStyle(view.dom);
19982
+ const computedStyles = {
19983
+ fontSize: computed2.fontSize,
19984
+ fontFamily: computed2.fontFamily,
19985
+ lineHeight: computed2.lineHeight
19986
+ };
19987
+ computedStylesCache.set(view.dom, computedStyles);
19890
19988
  return {
19891
- fontSize: inline.fontSize || computed2.fontSize,
19892
- fontFamily: inline.fontFamily || computed2.fontFamily,
19893
- lineHeight: inline.lineHeight || computed2.lineHeight
19989
+ fontSize: inline.fontSize || computedStyles.fontSize,
19990
+ fontFamily: inline.fontFamily || computedStyles.fontFamily,
19991
+ lineHeight: inline.lineHeight || computedStyles.lineHeight
19894
19992
  };
19895
19993
  }
19896
19994
  return inline;
@@ -20104,9 +20202,14 @@ class ListItemNodeView {
20104
20202
  });
20105
20203
  }
20106
20204
  update(node, decorations) {
20205
+ const prevNode = this.node;
20107
20206
  this.node = node;
20108
20207
  this.decorations = decorations;
20109
20208
  this.invalidateResolvedPos();
20209
+ const stylingAttrsChanged = !prevNode || prevNode.attrs.styleId !== node.attrs.styleId || prevNode.attrs.numId !== node.attrs.numId || prevNode.attrs.level !== node.attrs.level;
20210
+ if (stylingAttrsChanged) {
20211
+ clearComputedStyleCache(this.dom);
20212
+ }
20110
20213
  const { fontSize, fontFamily, lineHeight } = resolveListItemTypography({
20111
20214
  node,
20112
20215
  pos: this.getResolvedPos(),
@@ -20117,11 +20220,15 @@ class ListItemNodeView {
20117
20220
  this.dom.style.fontSize = fontSize;
20118
20221
  this.dom.style.fontFamily = fontFamily || "inherit";
20119
20222
  this.dom.style.lineHeight = lineHeight || "";
20120
- this.refreshIndentStyling();
20223
+ const attrsChanged = stylingAttrsChanged || prevNode?.attrs.indent !== node.attrs.indent;
20224
+ if (attrsChanged) {
20225
+ this.refreshIndentStyling();
20226
+ }
20121
20227
  }
20122
20228
  destroy() {
20123
20229
  activeListItemNodeViews.delete(this);
20124
20230
  this.numberingDOM.removeEventListener("click", this.handleNumberingClick);
20231
+ clearComputedStyleCache(this.dom);
20125
20232
  const caf = typeof globalThis !== "undefined" ? globalThis.cancelAnimationFrame : void 0;
20126
20233
  if (this._pendingIndentRefresh != null && typeof caf === "function") {
20127
20234
  caf(this._pendingIndentRefresh);
@@ -20240,8 +20347,11 @@ function calculateMarkerWidth(dom, numberingDOM, editor, { withPadding = true }
20240
20347
  if (!markerText.trim()) return 0;
20241
20348
  try {
20242
20349
  if (editor?.options?.isHeadless) return 0;
20350
+ if (typeof globalThis.CanvasRenderingContext2D === "undefined") return 0;
20243
20351
  const canvas = document.createElement("canvas");
20352
+ if (typeof canvas.getContext !== "function") return 0;
20244
20353
  const context = canvas.getContext("2d");
20354
+ if (!context) return 0;
20245
20355
  const fontSizePx = fontSize.includes("pt") ? Number.parseFloat(fontSize) * POINT_TO_PIXEL_CONVERSION_FACTOR : Number.parseFloat(fontSize);
20246
20356
  context.font = `${fontSizePx}px ${fontFamily}`;
20247
20357
  const textWidth = context.measureText(markerText).width;
@@ -20260,7 +20370,9 @@ function orderedListSync(editor) {
20260
20370
  appendTransaction(transactions, oldState, newState) {
20261
20371
  if (transactions.every((tr2) => tr2.getMeta("y-sync$"))) return null;
20262
20372
  const updateNodeViews = transactions.some((tr2) => tr2.getMeta("updatedListItemNodeViews"));
20263
- if (updateNodeViews || !hasInitialized) refreshAllListItemNodeViews();
20373
+ if (updateNodeViews || !hasInitialized) {
20374
+ refreshAllListItemNodeViews();
20375
+ }
20264
20376
  const isFromPlugin = transactions.some((tr2) => tr2.getMeta("orderedListSync"));
20265
20377
  const docChanged = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
20266
20378
  if (isFromPlugin || !docChanged) {
@@ -20272,10 +20384,24 @@ function orderedListSync(editor) {
20272
20384
  const listMap = /* @__PURE__ */ new Map();
20273
20385
  const listInitialized = /* @__PURE__ */ new Map();
20274
20386
  const shouldProcess = transactions.some((tr2) => {
20387
+ if (tr2.getMeta("updateListSync")) return true;
20275
20388
  return tr2.steps.some((step) => {
20276
20389
  const stepJSON = step.toJSON();
20277
- const hasUpdateMeta = tr2.getMeta("updateListSync");
20278
- return hasUpdateMeta || stepJSON && stepJSON.slice && JSON.stringify(stepJSON).includes('"listItem"');
20390
+ if (step.slice?.content) {
20391
+ let hasListItem = false;
20392
+ step.slice.content.descendants((node) => {
20393
+ if (node.type.name === "listItem") {
20394
+ hasListItem = true;
20395
+ return false;
20396
+ }
20397
+ });
20398
+ if (hasListItem) return true;
20399
+ }
20400
+ if (stepJSON && stepJSON.slice) {
20401
+ const jsonStr = JSON.stringify(stepJSON);
20402
+ if (jsonStr.includes('"listItem"')) return true;
20403
+ }
20404
+ return false;
20279
20405
  });
20280
20406
  });
20281
20407
  if (!shouldProcess) return null;
@@ -20745,17 +20871,68 @@ const Paragraph = OxmlNode.create({
20745
20871
  },
20746
20872
  addPmPlugins() {
20747
20873
  const { view } = this.editor;
20874
+ const dropcapWidthCache = /* @__PURE__ */ new Map();
20875
+ const hasDropcapParagraph = (node) => node.type.name === "paragraph" && node.attrs.dropcap?.type === "margin";
20876
+ const invalidateCacheForRange = (from2, to) => {
20877
+ for (const [pos] of dropcapWidthCache) {
20878
+ if (pos >= from2 && pos <= to) {
20879
+ dropcapWidthCache.delete(pos);
20880
+ }
20881
+ }
20882
+ };
20748
20883
  const dropcapPlugin = new Plugin({
20749
20884
  name: "dropcapPlugin",
20750
20885
  key: new PluginKey("dropcapPlugin"),
20751
20886
  state: {
20752
20887
  init(_, state) {
20753
- let decorations = getDropcapDecorations(state, view);
20888
+ const decorations = getDropcapDecorations(state, view, dropcapWidthCache);
20754
20889
  return DecorationSet.create(state.doc, decorations);
20755
20890
  },
20756
20891
  apply(tr, oldDecorationSet, oldState, newState) {
20757
20892
  if (!tr.docChanged) return oldDecorationSet;
20758
- const decorations = getDropcapDecorations(newState, view);
20893
+ let hasDropcaps = false;
20894
+ newState.doc.descendants((node) => {
20895
+ if (hasDropcapParagraph(node)) {
20896
+ hasDropcaps = true;
20897
+ return false;
20898
+ }
20899
+ });
20900
+ if (!hasDropcaps) {
20901
+ dropcapWidthCache.clear();
20902
+ return DecorationSet.empty;
20903
+ }
20904
+ let affectsDropcaps = false;
20905
+ tr.steps.forEach((step) => {
20906
+ if (step.slice?.content) {
20907
+ step.slice.content.descendants((node) => {
20908
+ if (hasDropcapParagraph(node)) {
20909
+ affectsDropcaps = true;
20910
+ return false;
20911
+ }
20912
+ });
20913
+ }
20914
+ if (step.jsonID === "replace" && step.from !== void 0 && step.to !== void 0) {
20915
+ try {
20916
+ oldState.doc.nodesBetween(step.from, step.to, (node) => {
20917
+ if (hasDropcapParagraph(node)) {
20918
+ affectsDropcaps = true;
20919
+ return false;
20920
+ }
20921
+ });
20922
+ } catch {
20923
+ affectsDropcaps = true;
20924
+ }
20925
+ }
20926
+ });
20927
+ if (!affectsDropcaps) {
20928
+ return oldDecorationSet.map(tr.mapping, tr.doc);
20929
+ }
20930
+ tr.steps.forEach((step) => {
20931
+ if (step.from !== void 0 && step.to !== void 0) {
20932
+ invalidateCacheForRange(step.from, step.to);
20933
+ }
20934
+ });
20935
+ const decorations = getDropcapDecorations(newState, view, dropcapWidthCache);
20759
20936
  return DecorationSet.create(newState.doc, decorations);
20760
20937
  }
20761
20938
  },
@@ -20768,12 +20945,12 @@ const Paragraph = OxmlNode.create({
20768
20945
  return [dropcapPlugin];
20769
20946
  }
20770
20947
  });
20771
- const getDropcapDecorations = (state, view) => {
20772
- let decorations = [];
20948
+ const getDropcapDecorations = (state, view, widthCache) => {
20949
+ const decorations = [];
20773
20950
  state.doc.descendants((node, pos) => {
20774
20951
  if (node.type.name === "paragraph") {
20775
20952
  if (node.attrs.dropcap?.type === "margin") {
20776
- const width = getDropcapWidth(view, pos);
20953
+ const width = getDropcapWidth(view, pos, widthCache);
20777
20954
  decorations.push(Decoration.inline(pos, pos + node.nodeSize, { style: `margin-left: -${width}px;` }));
20778
20955
  }
20779
20956
  return false;
@@ -20781,12 +20958,17 @@ const getDropcapDecorations = (state, view) => {
20781
20958
  });
20782
20959
  return decorations;
20783
20960
  };
20784
- function getDropcapWidth(view, pos) {
20961
+ function getDropcapWidth(view, pos, widthCache) {
20962
+ if (widthCache.has(pos)) {
20963
+ return widthCache.get(pos);
20964
+ }
20785
20965
  const domNode = view.nodeDOM(pos);
20786
20966
  if (domNode) {
20787
20967
  const range = document.createRange();
20788
20968
  range.selectNodeContents(domNode);
20789
- return range.getBoundingClientRect().width;
20969
+ const width = range.getBoundingClientRect().width;
20970
+ widthCache.set(pos, width);
20971
+ return width;
20790
20972
  }
20791
20973
  return 0;
20792
20974
  }
@@ -20972,10 +21154,16 @@ const getTabDecorations = (doc2, view, helpers2, from2 = 0, to = null) => {
20972
21154
  const paragraphContext = getParagraphContext($pos, paragraphCache, helpers2);
20973
21155
  if (!paragraphContext) return;
20974
21156
  try {
20975
- const { tabStops, flattened, startPos } = paragraphContext;
20976
- const entryIndex = flattened.findIndex((entry) => entry.pos === pos);
20977
- if (entryIndex === -1) return;
20978
- const indentWidth = getIndentWidth(view, startPos, paragraphContext.indent, coordCache, domPosCache);
21157
+ const { tabStops, flattened, positionMap, startPos } = paragraphContext;
21158
+ const entryIndex = positionMap.get(pos);
21159
+ if (entryIndex === void 0) return;
21160
+ if (paragraphContext.indentWidth === void 0) {
21161
+ paragraphContext.indentWidth = getIndentWidth(view, startPos, paragraphContext.indent, coordCache, domPosCache);
21162
+ }
21163
+ if (paragraphContext.tabHeight === void 0) {
21164
+ paragraphContext.tabHeight = calcTabHeight($pos);
21165
+ }
21166
+ const indentWidth = paragraphContext.indentWidth;
20979
21167
  const accumulatedTabWidth = paragraphContext.accumulatedTabWidth || 0;
20980
21168
  const currentWidth = indentWidth + measureRangeWidth(view, startPos + 1, pos, coordCache, domPosCache) + accumulatedTabWidth;
20981
21169
  let tabWidth;
@@ -21017,7 +21205,7 @@ const getTabDecorations = (doc2, view, helpers2, from2 = 0, to = null) => {
21017
21205
  tabWidth = defaultTabDistance - currentWidth % defaultLineLength % defaultTabDistance;
21018
21206
  if (tabWidth === 0) tabWidth = defaultTabDistance;
21019
21207
  }
21020
- const tabHeight = calcTabHeight($pos);
21208
+ const tabHeight = paragraphContext.tabHeight;
21021
21209
  decorations.push(
21022
21210
  Decoration.node(pos, pos + node.nodeSize, {
21023
21211
  style: `width: ${tabWidth}px; height: ${tabHeight};${extraStyles}`
@@ -21045,13 +21233,16 @@ function getParagraphContext($pos, cache, helpers2) {
21045
21233
  tabStops = style.definition.styles.tabStops;
21046
21234
  }
21047
21235
  }
21236
+ const { entries, positionMap } = flattenParagraph(node, startPos);
21048
21237
  cache.set(startPos, {
21049
21238
  paragraph: node,
21050
21239
  paragraphDepth: depth,
21051
21240
  startPos,
21052
21241
  indent: node.attrs?.indent || {},
21053
21242
  tabStops,
21054
- flattened: flattenParagraph(node, startPos),
21243
+ flattened: entries,
21244
+ positionMap,
21245
+ // Store position map for O(1) lookups
21055
21246
  accumulatedTabWidth: 0
21056
21247
  });
21057
21248
  }
@@ -21062,6 +21253,7 @@ function getParagraphContext($pos, cache, helpers2) {
21062
21253
  }
21063
21254
  function flattenParagraph(paragraph, paragraphStartPos) {
21064
21255
  const entries = [];
21256
+ const positionMap = /* @__PURE__ */ new Map();
21065
21257
  const walk = (node, basePos) => {
21066
21258
  if (!node) return;
21067
21259
  if (node.type?.name === "run") {
@@ -21071,13 +21263,16 @@ function flattenParagraph(paragraph, paragraphStartPos) {
21071
21263
  });
21072
21264
  return;
21073
21265
  }
21074
- entries.push({ node, pos: basePos - 1 });
21266
+ const pos = basePos - 1;
21267
+ const index2 = entries.length;
21268
+ entries.push({ node, pos });
21269
+ positionMap.set(pos, index2);
21075
21270
  };
21076
21271
  paragraph.forEach((child, offset2) => {
21077
21272
  const childPos = paragraphStartPos + offset2 + 1;
21078
21273
  walk(child, childPos);
21079
21274
  });
21080
- return entries;
21275
+ return { entries, positionMap };
21081
21276
  }
21082
21277
  function findNextTabIndex(flattened, fromIndex) {
21083
21278
  for (let i = fromIndex; i < flattened.length; i++) {
@@ -21235,6 +21430,21 @@ const TabNode = Node$1.create({
21235
21430
  },
21236
21431
  addPmPlugins() {
21237
21432
  const { view, helpers: helpers2 } = this.editor;
21433
+ const mergeRanges2 = (ranges) => {
21434
+ if (ranges.length === 0) return [];
21435
+ const sorted = ranges.slice().sort((a, b) => a[0] - b[0]);
21436
+ const merged = [sorted[0]];
21437
+ for (let i = 1; i < sorted.length; i++) {
21438
+ const [start2, end2] = sorted[i];
21439
+ const last = merged[merged.length - 1];
21440
+ if (start2 <= last[1]) {
21441
+ last[1] = Math.max(last[1], end2);
21442
+ } else {
21443
+ merged.push([start2, end2]);
21444
+ }
21445
+ }
21446
+ return merged;
21447
+ };
21238
21448
  const tabPlugin = new Plugin({
21239
21449
  name: "tabPlugin",
21240
21450
  key: new PluginKey("tabPlugin"),
@@ -21245,43 +21455,56 @@ const TabNode = Node$1.create({
21245
21455
  apply(tr, { decorations }, _oldState, newState) {
21246
21456
  if (!decorations) {
21247
21457
  decorations = DecorationSet.create(newState.doc, getTabDecorations(newState.doc, view, helpers2));
21458
+ return { decorations };
21248
21459
  }
21249
- if (!tr.docChanged || tr.getMeta("blockNodeInitialUpdate") === true) {
21460
+ if (!tr.docChanged || tr.getMeta("blockNodeInitialUpdate")) {
21250
21461
  return { decorations };
21251
21462
  }
21252
21463
  decorations = decorations.map(tr.mapping, tr.doc);
21253
- let rangesToRecalculate = [];
21464
+ const rangesToRecalculate = [];
21465
+ const containsTab = (node) => node.type.name === "tab";
21254
21466
  tr.steps.forEach((step, index2) => {
21255
- const stepMap = step.getMap();
21256
- if (step instanceof ReplaceStep || step instanceof ReplaceAroundStep$1) {
21257
- const $from = tr.docs[index2].resolve(step.from);
21258
- const $to = tr.docs[index2].resolve(step.to);
21259
- const start2 = $from.start(Math.min($from.depth, 1));
21260
- const end2 = $to.end(Math.min($to.depth, 1));
21261
- let addRange = false;
21262
- tr.docs[index2].nodesBetween(start2, end2, (node) => {
21263
- if (node.type.name === "tab") {
21264
- addRange = true;
21467
+ if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep$1)) {
21468
+ return;
21469
+ }
21470
+ let hasTabInRange = false;
21471
+ if (step.slice?.content) {
21472
+ step.slice.content.descendants((node) => {
21473
+ if (containsTab(node)) {
21474
+ hasTabInRange = true;
21475
+ return false;
21265
21476
  }
21266
21477
  });
21267
- if (!addRange && step.slice?.content) {
21268
- step.slice.content.descendants((node) => {
21269
- if (node.type.name === "tab") {
21270
- addRange = true;
21271
- }
21272
- });
21273
- }
21274
- if (addRange) {
21275
- rangesToRecalculate.push([start2, end2]);
21276
- }
21277
21478
  }
21278
- rangesToRecalculate = rangesToRecalculate.map(([from2, to]) => {
21279
- const mappedFrom = stepMap.map(from2, -1);
21280
- const mappedTo = stepMap.map(to, 1);
21281
- return [mappedFrom, mappedTo];
21282
- });
21479
+ if (!hasTabInRange) {
21480
+ tr.docs[index2].nodesBetween(step.from, step.to, (node) => {
21481
+ if (containsTab(node)) {
21482
+ hasTabInRange = true;
21483
+ return false;
21484
+ }
21485
+ });
21486
+ }
21487
+ if (!hasTabInRange) {
21488
+ return;
21489
+ }
21490
+ let fromPos = step.from;
21491
+ let toPos = step.to;
21492
+ for (let i = index2; i < tr.steps.length; i++) {
21493
+ const stepMap = tr.steps[i].getMap();
21494
+ fromPos = stepMap.map(fromPos, -1);
21495
+ toPos = stepMap.map(toPos, 1);
21496
+ }
21497
+ const $from = newState.doc.resolve(fromPos);
21498
+ const $to = newState.doc.resolve(toPos);
21499
+ const start2 = $from.start(Math.min($from.depth, 1));
21500
+ const end2 = $to.end(Math.min($to.depth, 1));
21501
+ rangesToRecalculate.push([start2, end2]);
21283
21502
  });
21284
- rangesToRecalculate.forEach(([start2, end2]) => {
21503
+ if (rangesToRecalculate.length === 0) {
21504
+ return { decorations };
21505
+ }
21506
+ const mergedRanges = mergeRanges2(rangesToRecalculate);
21507
+ mergedRanges.forEach(([start2, end2]) => {
21285
21508
  const oldDecorations = decorations.find(start2, end2);
21286
21509
  decorations = decorations.remove(oldDecorations);
21287
21510
  const newDecorations = getTabDecorations(newState.doc, view, helpers2, start2, end2);
@@ -25183,6 +25406,29 @@ createAnnotation_fn = function({ displayLabel } = {}) {
25183
25406
  content
25184
25407
  };
25185
25408
  };
25409
+ const mergeRanges = (ranges) => {
25410
+ if (ranges.length === 0) return [];
25411
+ const sorted = [...ranges].sort((a, b) => a[0] - b[0]).map((range) => [...range]);
25412
+ const merged = [sorted[0]];
25413
+ for (let i = 1; i < sorted.length; i++) {
25414
+ const current = sorted[i];
25415
+ const lastMerged = merged[merged.length - 1];
25416
+ if (current[0] <= lastMerged[1]) {
25417
+ lastMerged[1] = Math.max(lastMerged[1], current[1]);
25418
+ } else {
25419
+ merged.push(current);
25420
+ }
25421
+ }
25422
+ return merged;
25423
+ };
25424
+ const clampRange = (start2, end2, docSize) => {
25425
+ const safeStart = Math.max(0, Math.min(start2, docSize));
25426
+ const safeEnd = Math.max(0, Math.min(end2, docSize));
25427
+ if (safeStart >= safeEnd) {
25428
+ return null;
25429
+ }
25430
+ return [safeStart, safeEnd];
25431
+ };
25186
25432
  const FieldAnnotationPlugin = (options = {}) => {
25187
25433
  let { editor, annotationClass: annotationClass2 } = options;
25188
25434
  return new Plugin({
@@ -25257,24 +25503,104 @@ const FieldAnnotationPlugin = (options = {}) => {
25257
25503
  },
25258
25504
  /// For y-prosemirror support.
25259
25505
  appendTransaction: (transactions, oldState, newState) => {
25260
- let docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
25506
+ const docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
25261
25507
  if (!docChanges) {
25262
25508
  return;
25263
25509
  }
25264
- let { tr } = newState;
25265
- let changed = false;
25266
- let annotations = getAllFieldAnnotations(newState);
25267
- if (!annotations.length) {
25268
- return;
25510
+ const affectedRanges = [];
25511
+ let hasFieldAnnotationsInSlice = false;
25512
+ let hasSteps = false;
25513
+ transactions.forEach((transaction) => {
25514
+ if (!transaction.steps) return;
25515
+ hasSteps = true;
25516
+ transaction.steps.forEach((step) => {
25517
+ if (step.slice?.content) {
25518
+ step.slice.content.descendants((node) => {
25519
+ if (node.type.name === "fieldAnnotation") {
25520
+ hasFieldAnnotationsInSlice = true;
25521
+ return false;
25522
+ }
25523
+ });
25524
+ }
25525
+ if (typeof step.from === "number" && typeof step.to === "number") {
25526
+ const from2 = step.from;
25527
+ const to = step.from === step.to && step.slice?.size ? step.from + step.slice.size : step.to;
25528
+ affectedRanges.push([from2, to]);
25529
+ }
25530
+ });
25531
+ });
25532
+ if (hasSteps && !hasFieldAnnotationsInSlice && affectedRanges.length > 0) {
25533
+ const mergedRanges = mergeRanges(affectedRanges);
25534
+ let hasExistingAnnotations = false;
25535
+ for (const [start2, end2] of mergedRanges) {
25536
+ const clampedRange = clampRange(start2, end2, newState.doc.content.size);
25537
+ if (!clampedRange) continue;
25538
+ const [validStart, validEnd] = clampedRange;
25539
+ try {
25540
+ newState.doc.nodesBetween(validStart, validEnd, (node) => {
25541
+ if (node.type.name === "fieldAnnotation") {
25542
+ hasExistingAnnotations = true;
25543
+ return false;
25544
+ }
25545
+ });
25546
+ } catch (error) {
25547
+ console.warn("FieldAnnotationPlugin: range check failed, assuming annotations exist", error);
25548
+ hasExistingAnnotations = true;
25549
+ break;
25550
+ }
25551
+ if (hasExistingAnnotations) break;
25552
+ }
25553
+ if (!hasExistingAnnotations) {
25554
+ return;
25555
+ }
25269
25556
  }
25270
- annotations.forEach(({ node, pos }) => {
25271
- let { marks } = node;
25272
- let currentNode = tr.doc.nodeAt(pos);
25557
+ const { tr } = newState;
25558
+ let changed = false;
25559
+ const removeMarksFromAnnotation = (node, pos) => {
25560
+ const { marks } = node;
25561
+ const currentNode = tr.doc.nodeAt(pos);
25273
25562
  if (marks.length > 0 && node.eq(currentNode)) {
25274
25563
  tr.removeMark(pos, pos + node.nodeSize, null);
25275
25564
  changed = true;
25276
25565
  }
25277
- });
25566
+ };
25567
+ if (affectedRanges.length > 0) {
25568
+ const mergedRanges = mergeRanges(affectedRanges);
25569
+ let shouldFallbackToFullScan = false;
25570
+ for (const [start2, end2] of mergedRanges) {
25571
+ const clampedRange = clampRange(start2, end2, newState.doc.content.size);
25572
+ if (!clampedRange) continue;
25573
+ const [validStart, validEnd] = clampedRange;
25574
+ try {
25575
+ newState.doc.nodesBetween(validStart, validEnd, (node, pos) => {
25576
+ if (node.type.name === "fieldAnnotation") {
25577
+ removeMarksFromAnnotation(node, pos);
25578
+ }
25579
+ });
25580
+ } catch (error) {
25581
+ console.warn("FieldAnnotationPlugin: nodesBetween failed, falling back to full scan", error);
25582
+ shouldFallbackToFullScan = true;
25583
+ break;
25584
+ }
25585
+ }
25586
+ if (shouldFallbackToFullScan) {
25587
+ const annotations = getAllFieldAnnotations(newState);
25588
+ if (!annotations.length) {
25589
+ return changed ? tr : null;
25590
+ }
25591
+ annotations.forEach(({ node, pos }) => {
25592
+ removeMarksFromAnnotation(node, pos);
25593
+ });
25594
+ }
25595
+ } else {
25596
+ const annotations = getAllFieldAnnotations(newState);
25597
+ if (!annotations.length) {
25598
+ return;
25599
+ }
25600
+ annotations.forEach(({ node, pos }) => {
25601
+ removeMarksFromAnnotation(node, pos);
25602
+ });
25603
+ }
25278
25604
  return changed ? tr : null;
25279
25605
  }
25280
25606
  ///
@@ -27084,7 +27410,9 @@ const registerImages = async (foundImages, editor, view) => {
27084
27410
  }
27085
27411
  });
27086
27412
  };
27413
+ const stepHasSlice = (step) => "slice" in step && Boolean(step.slice);
27087
27414
  const ImagePositionPluginKey = new PluginKey("ImagePosition");
27415
+ const pageBreakPositionCache = /* @__PURE__ */ new WeakMap();
27088
27416
  const ImagePositionPlugin = ({ editor }) => {
27089
27417
  const { view } = editor;
27090
27418
  let shouldUpdate = false;
@@ -27097,6 +27425,20 @@ const ImagePositionPlugin = ({ editor }) => {
27097
27425
  },
27098
27426
  apply(tr, oldDecorationSet, oldState, newState) {
27099
27427
  if (!tr.docChanged && !shouldUpdate) return oldDecorationSet;
27428
+ let affectsImages = false;
27429
+ tr.steps.forEach((step) => {
27430
+ if (stepHasSlice(step)) {
27431
+ step.slice.content.descendants((node) => {
27432
+ if (node.type.name === "image" || node.attrs?.anchorData) {
27433
+ affectsImages = true;
27434
+ return false;
27435
+ }
27436
+ });
27437
+ }
27438
+ });
27439
+ if (!affectsImages && !shouldUpdate) {
27440
+ return oldDecorationSet.map(tr.mapping, tr.doc);
27441
+ }
27100
27442
  const decorations = getImagePositionDecorations(newState, view);
27101
27443
  shouldUpdate = false;
27102
27444
  return DecorationSet.create(newState.doc, decorations);
@@ -27126,6 +27468,16 @@ const ImagePositionPlugin = ({ editor }) => {
27126
27468
  };
27127
27469
  const getImagePositionDecorations = (state, view) => {
27128
27470
  let decorations = [];
27471
+ let hasAnchoredImages = false;
27472
+ state.doc.descendants((node) => {
27473
+ if (node.attrs?.anchorData) {
27474
+ hasAnchoredImages = true;
27475
+ return false;
27476
+ }
27477
+ });
27478
+ if (!hasAnchoredImages) {
27479
+ return decorations;
27480
+ }
27129
27481
  state.doc.descendants((node, pos) => {
27130
27482
  if (node.attrs.anchorData) {
27131
27483
  let style = "";
@@ -27134,7 +27486,15 @@ const getImagePositionDecorations = (state, view) => {
27134
27486
  const { size, padding } = node.attrs;
27135
27487
  const pageBreak = findPreviousDomNodeWithClass(view, pos, "pagination-break-wrapper");
27136
27488
  if (pageBreak && vRelativeFrom === "margin" && alignH) {
27137
- const topPos = pageBreak?.offsetTop + pageBreak?.offsetHeight;
27489
+ let pageBreakPos = pageBreakPositionCache.get(pageBreak);
27490
+ if (!pageBreakPos) {
27491
+ pageBreakPos = {
27492
+ top: pageBreak.offsetTop,
27493
+ height: pageBreak.offsetHeight
27494
+ };
27495
+ pageBreakPositionCache.set(pageBreak, pageBreakPos);
27496
+ }
27497
+ const topPos = pageBreakPos.top + pageBreakPos.height;
27138
27498
  let horizontalAlignment = `${alignH}: 0;`;
27139
27499
  if (alignH === "center") horizontalAlignment = "left: 50%; transform: translateX(-50%);";
27140
27500
  style += vRelativeFrom === "margin" ? `position: absolute; top: ${topPos}px; ${horizontalAlignment}` : "";
@@ -27445,15 +27805,15 @@ const Image = Node$1.create({
27445
27805
  style += "float: right;";
27446
27806
  floatRight = true;
27447
27807
  } else if (["largest", "bothSides"].includes(attrs.wrapText)) {
27448
- const pageStylesData2 = getDataFromPageStyles({
27808
+ const pageStylesData = getDataFromPageStyles({
27449
27809
  editor: this.editor,
27450
27810
  marginOffset,
27451
27811
  size,
27452
27812
  attrs
27453
27813
  });
27454
- style += pageStylesData2.style;
27455
- floatRight = pageStylesData2.floatRight;
27456
- baseHorizontal = pageStylesData2.baseHorizontal;
27814
+ style += pageStylesData.style;
27815
+ floatRight = pageStylesData.floatRight;
27816
+ baseHorizontal = pageStylesData.baseHorizontal;
27457
27817
  }
27458
27818
  if (attrs.distTop) margin.top += attrs.distTop;
27459
27819
  if (attrs.distBottom) margin.bottom += attrs.distBottom;
@@ -27461,7 +27821,7 @@ const Image = Node$1.create({
27461
27821
  if (attrs.distRight) margin.right += attrs.distRight;
27462
27822
  break;
27463
27823
  case "Through":
27464
- case "Tight":
27824
+ case "Tight": {
27465
27825
  style += "clear: both;";
27466
27826
  const pageStylesData = getDataFromPageStyles({
27467
27827
  editor: this.editor,
@@ -27498,11 +27858,14 @@ const Image = Node$1.create({
27498
27858
  style += `shape-outside: polygon(${points});`;
27499
27859
  }
27500
27860
  break;
27861
+ }
27501
27862
  case "TopAndBottom":
27502
27863
  style += "display: block; clear: both;";
27864
+ if (!anchorData) {
27865
+ centered = true;
27866
+ }
27503
27867
  if (attrs.distTop) margin.top += attrs.distTop;
27504
27868
  if (attrs.distBottom) margin.bottom += attrs.distBottom;
27505
- centered = true;
27506
27869
  break;
27507
27870
  }
27508
27871
  }
@@ -27522,6 +27885,20 @@ const Image = Node$1.create({
27522
27885
  style += `position: absolute; ${anchorData.alignH}: 0;`;
27523
27886
  }
27524
27887
  break;
27888
+ case "column":
27889
+ if (anchorData.alignH === "center") {
27890
+ centered = true;
27891
+ } else if (anchorData.alignH === "right") {
27892
+ floatRight = true;
27893
+ if (!style.includes("float: right;")) {
27894
+ style += "float: right;";
27895
+ }
27896
+ } else if (anchorData.alignH === "left") {
27897
+ if (!style.includes("float: left;")) {
27898
+ style += "float: left;";
27899
+ }
27900
+ }
27901
+ break;
27525
27902
  }
27526
27903
  }
27527
27904
  if (hasAnchorData || hasMarginOffsets) {
@@ -28609,11 +28986,22 @@ const BlockNode = Extension.create({
28609
28986
  },
28610
28987
  addPmPlugins() {
28611
28988
  let hasInitialized = false;
28989
+ const assignBlockId = (tr, node, pos) => {
28990
+ tr.setNodeMarkup(
28991
+ pos,
28992
+ void 0,
28993
+ {
28994
+ ...node.attrs,
28995
+ sdBlockId: v4()
28996
+ },
28997
+ node.marks
28998
+ );
28999
+ };
28612
29000
  return [
28613
29001
  new Plugin({
28614
29002
  key: BlockNodePluginKey,
28615
29003
  appendTransaction: (transactions, oldState, newState) => {
28616
- let docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
29004
+ const docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
28617
29005
  if (hasInitialized && !docChanges) {
28618
29006
  return;
28619
29007
  }
@@ -28622,21 +29010,87 @@ const BlockNode = Extension.create({
28622
29010
  }
28623
29011
  const { tr } = newState;
28624
29012
  let changed = false;
28625
- newState.doc.descendants((node, pos) => {
28626
- if (!nodeAllowsSdBlockIdAttr(node) || !nodeNeedsSdBlockId(node)) {
28627
- return;
29013
+ if (!hasInitialized) {
29014
+ newState.doc.descendants((node, pos) => {
29015
+ if (nodeAllowsSdBlockIdAttr(node) && nodeNeedsSdBlockId(node)) {
29016
+ assignBlockId(tr, node, pos);
29017
+ changed = true;
29018
+ }
29019
+ });
29020
+ } else {
29021
+ const rangesToCheck = [];
29022
+ let shouldFallbackToFullTraversal = false;
29023
+ transactions.forEach((transaction, txIndex) => {
29024
+ transaction.steps.forEach((step, stepIndex) => {
29025
+ if (!(step instanceof ReplaceStep)) return;
29026
+ const hasNewBlockNodes = step.slice?.content?.content?.some((node) => nodeAllowsSdBlockIdAttr(node));
29027
+ if (!hasNewBlockNodes) return;
29028
+ const stepMap = step.getMap();
29029
+ stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
29030
+ if (newEnd <= newStart) {
29031
+ if (process$1.env.NODE_ENV === "development") {
29032
+ console.debug("Block node: invalid range in step map, falling back to full traversal");
29033
+ }
29034
+ shouldFallbackToFullTraversal = true;
29035
+ return;
29036
+ }
29037
+ let rangeStart = newStart;
29038
+ let rangeEnd = newEnd;
29039
+ for (let i = stepIndex + 1; i < transaction.steps.length; i++) {
29040
+ const laterStepMap = transaction.steps[i].getMap();
29041
+ rangeStart = laterStepMap.map(rangeStart, -1);
29042
+ rangeEnd = laterStepMap.map(rangeEnd, 1);
29043
+ }
29044
+ for (let i = txIndex + 1; i < transactions.length; i++) {
29045
+ const laterTx = transactions[i];
29046
+ rangeStart = laterTx.mapping.map(rangeStart, -1);
29047
+ rangeEnd = laterTx.mapping.map(rangeEnd, 1);
29048
+ }
29049
+ if (rangeEnd <= rangeStart) {
29050
+ if (process$1.env.NODE_ENV === "development") {
29051
+ console.debug("Block node: invalid range after mapping, falling back to full traversal");
29052
+ }
29053
+ shouldFallbackToFullTraversal = true;
29054
+ return;
29055
+ }
29056
+ rangesToCheck.push([rangeStart, rangeEnd]);
29057
+ });
29058
+ });
29059
+ });
29060
+ const mergedRanges = mergeRanges(rangesToCheck);
29061
+ for (const [start2, end2] of mergedRanges) {
29062
+ const docSize = newState.doc.content.size;
29063
+ const clampedRange = clampRange(start2, end2, docSize);
29064
+ if (!clampedRange) {
29065
+ if (process$1.env.NODE_ENV === "development") {
29066
+ console.debug("Block node: invalid range after clamping, falling back to full traversal");
29067
+ }
29068
+ shouldFallbackToFullTraversal = true;
29069
+ break;
29070
+ }
29071
+ const [safeStart, safeEnd] = clampedRange;
29072
+ try {
29073
+ newState.doc.nodesBetween(safeStart, safeEnd, (node, pos) => {
29074
+ if (nodeAllowsSdBlockIdAttr(node) && nodeNeedsSdBlockId(node)) {
29075
+ assignBlockId(tr, node, pos);
29076
+ changed = true;
29077
+ }
29078
+ });
29079
+ } catch (error) {
29080
+ console.warn("Block node plugin: nodesBetween failed, falling back to full traversal", error);
29081
+ shouldFallbackToFullTraversal = true;
29082
+ break;
29083
+ }
28628
29084
  }
28629
- tr.setNodeMarkup(
28630
- pos,
28631
- void 0,
28632
- {
28633
- ...node.attrs,
28634
- sdBlockId: v4()
28635
- },
28636
- node.marks
28637
- );
28638
- changed = true;
28639
- });
29085
+ if (shouldFallbackToFullTraversal) {
29086
+ newState.doc.descendants((node, pos) => {
29087
+ if (nodeAllowsSdBlockIdAttr(node) && nodeNeedsSdBlockId(node)) {
29088
+ assignBlockId(tr, node, pos);
29089
+ changed = true;
29090
+ }
29091
+ });
29092
+ }
29093
+ }
28640
29094
  if (changed && !hasInitialized) {
28641
29095
  hasInitialized = true;
28642
29096
  tr.setMeta("blockNodeInitialUpdate", true);
@@ -35112,8 +35566,8 @@ const PopoverPlugin = Extension.create({
35112
35566
  return {};
35113
35567
  },
35114
35568
  apply: (tr, value) => {
35115
- let newValue = { ...value };
35116
- if (tr.docChanged) {
35569
+ const newValue = { ...value };
35570
+ if (tr.docChanged || tr.selectionSet) {
35117
35571
  newValue.shouldUpdate = true;
35118
35572
  } else {
35119
35573
  newValue.shouldUpdate = false;
@@ -36368,6 +36822,8 @@ const Pagination = Extension.create({
36368
36822
  let shouldUpdate = false;
36369
36823
  let hasInitialized = false;
36370
36824
  let shouldInitialize = false;
36825
+ let paginationTimeout = null;
36826
+ const PAGINATION_DEBOUNCE_MS = 150;
36371
36827
  const paginationPlugin = new Plugin({
36372
36828
  key: PaginationPluginKey,
36373
36829
  state: {
@@ -36395,6 +36851,9 @@ const Pagination = Extension.create({
36395
36851
  shouldUpdate = true;
36396
36852
  shouldInitialize = meta.isReadyToInit;
36397
36853
  }
36854
+ if (meta && meta.skipPagination) {
36855
+ return { ...oldState };
36856
+ }
36398
36857
  const syncMeta = tr.getMeta("y-sync$");
36399
36858
  const listSyncMeta = tr.getMeta("orderedListSync");
36400
36859
  if (syncMeta && syncMeta.isChangeOrigin || listSyncMeta) {
@@ -36426,11 +36885,23 @@ const Pagination = Extension.create({
36426
36885
  shouldUpdate = false;
36427
36886
  return { ...oldState };
36428
36887
  }
36888
+ if (!isForceUpdate && hasInitialized && tr.docChanged) {
36889
+ let isMarkOnlyChange = true;
36890
+ tr.steps.forEach((step) => {
36891
+ if (step.jsonID !== "addMark" && step.jsonID !== "removeMark") {
36892
+ isMarkOnlyChange = false;
36893
+ }
36894
+ });
36895
+ if (isMarkOnlyChange) {
36896
+ shouldUpdate = false;
36897
+ return { ...oldState };
36898
+ }
36899
+ }
36429
36900
  shouldUpdate = true;
36430
36901
  if (isForceUpdate) shouldUpdate = true;
36431
36902
  return {
36432
36903
  ...oldState,
36433
- decorations: meta?.decorations?.map(tr.mapping, tr.doc) || DecorationSet.empty,
36904
+ decorations: meta?.decorations?.map(tr.mapping, tr.doc) || oldState.decorations.map(tr.mapping, tr.doc),
36434
36905
  isReadyToInit: shouldInitialize
36435
36906
  };
36436
36907
  }
@@ -36442,11 +36913,22 @@ const Pagination = Extension.create({
36442
36913
  update: (view) => {
36443
36914
  if (!PaginationPluginKey.getState(view.state)?.isEnabled) return;
36444
36915
  if (!shouldUpdate || isUpdating) return;
36445
- isUpdating = true;
36446
- hasInitialized = true;
36447
- performUpdate(editor, view, previousDecorations);
36448
- isUpdating = false;
36449
- shouldUpdate = false;
36916
+ const performPaginationUpdate = () => {
36917
+ if (!shouldUpdate) return;
36918
+ isUpdating = true;
36919
+ hasInitialized = true;
36920
+ performUpdate(editor, view, previousDecorations);
36921
+ isUpdating = false;
36922
+ shouldUpdate = false;
36923
+ };
36924
+ if (!hasInitialized) {
36925
+ performPaginationUpdate();
36926
+ return;
36927
+ }
36928
+ if (paginationTimeout) {
36929
+ clearTimeout(paginationTimeout);
36930
+ }
36931
+ paginationTimeout = setTimeout(performPaginationUpdate, PAGINATION_DEBOUNCE_MS);
36450
36932
  }
36451
36933
  };
36452
36934
  },