@harbour-enterprises/superdoc 0.28.0-next.13 → 0.28.0-next.14

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 (27) hide show
  1. package/dist/chunks/{PdfViewer-BsJq49rR.es.js → PdfViewer-C5N8ds3O.es.js} +1 -1
  2. package/dist/chunks/{PdfViewer-D8L8mpOs.cjs → PdfViewer-CTJIldpN.cjs} +1 -1
  3. package/dist/chunks/{index-BNr0wgOU-j0xGZdr7.es.js → index-BNr0wgOU-Bj1k6CCB.es.js} +1 -1
  4. package/dist/chunks/{index-BNr0wgOU-Bg5kSvF0.cjs → index-BNr0wgOU-DGdWV9Iz.cjs} +1 -1
  5. package/dist/chunks/{index-x4srxOl3.cjs → index-C2zCd-ai.cjs} +2 -2
  6. package/dist/chunks/{index-ByV1n--x.es.js → index-DOIFo7ao.es.js} +2 -2
  7. package/dist/chunks/{super-editor.es-C0LbO3l0.es.js → super-editor.es-CSyQAFrJ.es.js} +505 -89
  8. package/dist/chunks/{super-editor.es-CANt5-KH.cjs → super-editor.es-DAO9OQ4k.cjs} +505 -89
  9. package/dist/core/types/index.d.ts.map +1 -1
  10. package/dist/super-editor/ai-writer.es.js +1 -1
  11. package/dist/super-editor/chunks/{editor-BwNyV6ke.js → editor-DSQC1des.js} +504 -88
  12. package/dist/super-editor/chunks/{toolbar-Bx1rJX7n.js → toolbar-Dq-rYRTG.js} +1 -1
  13. package/dist/super-editor/editor.es.js +1 -1
  14. package/dist/super-editor/super-editor/src/core/helpers/rangeUtils.d.ts +2 -0
  15. package/dist/super-editor/super-editor/src/extensions/field-annotation/FieldAnnotationPlugin.d.ts +5 -1
  16. package/dist/super-editor/super-editor/src/extensions/image/imageHelpers/imagePositionPlugin.d.ts +2 -0
  17. package/dist/super-editor/super-editor/src/extensions/list-item/helpers/listItemTypography.d.ts +5 -0
  18. package/dist/super-editor/super-editor/src/extensions/list-item/helpers/styledListMarkerPlugin.d.ts +11 -2
  19. package/dist/super-editor/super-editor.es.js +3 -3
  20. package/dist/super-editor/toolbar.es.js +2 -2
  21. package/dist/super-editor.cjs +1 -1
  22. package/dist/super-editor.es.js +1 -1
  23. package/dist/superdoc.cjs +2 -2
  24. package/dist/superdoc.es.js +2 -2
  25. package/dist/superdoc.umd.js +504 -88
  26. package/dist/superdoc.umd.js.map +1 -1
  27. package/package.json +1 -1
@@ -49979,17 +49979,7 @@ const TrackChangesBasePlugin = () => {
49979
49979
  },
49980
49980
  apply(tr, oldState, prevEditorState, newEditorState) {
49981
49981
  const meta = tr.getMeta(TrackChangesBasePluginKey);
49982
- if (!meta) {
49983
- return {
49984
- ...oldState,
49985
- decorations: getTrackChangesDecorations(
49986
- newEditorState,
49987
- oldState.onlyOriginalShown,
49988
- oldState.onlyModifiedShown
49989
- )
49990
- };
49991
- }
49992
- if (meta.type === "TRACK_CHANGES_ENABLE") {
49982
+ if (meta && meta.type === "TRACK_CHANGES_ENABLE") {
49993
49983
  return {
49994
49984
  ...oldState,
49995
49985
  isTrackChangesActive: meta.value === true,
@@ -50000,7 +49990,7 @@ const TrackChangesBasePlugin = () => {
50000
49990
  )
50001
49991
  };
50002
49992
  }
50003
- if (meta.type === "SHOW_ONLY_ORIGINAL") {
49993
+ if (meta && meta.type === "SHOW_ONLY_ORIGINAL") {
50004
49994
  return {
50005
49995
  ...oldState,
50006
49996
  onlyOriginalShown: meta.value === true,
@@ -50008,7 +49998,7 @@ const TrackChangesBasePlugin = () => {
50008
49998
  decorations: getTrackChangesDecorations(newEditorState, meta.value === true, false)
50009
49999
  };
50010
50000
  }
50011
- if (meta.type === "SHOW_ONLY_MODIFIED") {
50001
+ if (meta && meta.type === "SHOW_ONLY_MODIFIED") {
50012
50002
  return {
50013
50003
  ...oldState,
50014
50004
  onlyOriginalShown: false,
@@ -50016,6 +50006,31 @@ const TrackChangesBasePlugin = () => {
50016
50006
  decorations: getTrackChangesDecorations(newEditorState, false, meta.value === true)
50017
50007
  };
50018
50008
  }
50009
+ if (!tr.docChanged) {
50010
+ return oldState;
50011
+ }
50012
+ if (!meta) {
50013
+ let mightAffectTrackChanges = false;
50014
+ tr.steps.forEach((step) => {
50015
+ if (step.slice || step.from !== step.to) {
50016
+ mightAffectTrackChanges = true;
50017
+ }
50018
+ });
50019
+ if (mightAffectTrackChanges) {
50020
+ return {
50021
+ ...oldState,
50022
+ decorations: getTrackChangesDecorations(
50023
+ newEditorState,
50024
+ oldState.onlyOriginalShown,
50025
+ oldState.onlyModifiedShown
50026
+ )
50027
+ };
50028
+ }
50029
+ return {
50030
+ ...oldState,
50031
+ decorations: oldState.decorations.map(tr.mapping, tr.doc)
50032
+ };
50033
+ }
50019
50034
  return {
50020
50035
  ...oldState,
50021
50036
  decorations: getTrackChangesDecorations(
@@ -50770,6 +50785,7 @@ const CommentsPlugin = Extension.create({
50770
50785
  view() {
50771
50786
  let prevDoc;
50772
50787
  let prevActiveThreadId;
50788
+ let prevAllCommentPositions = {};
50773
50789
  return {
50774
50790
  update(view) {
50775
50791
  const { state: state2 } = view;
@@ -50780,16 +50796,19 @@ const CommentsPlugin = Extension.create({
50780
50796
  if (meta?.type === "setActiveComment" || meta?.forceUpdate) {
50781
50797
  shouldUpdate = true;
50782
50798
  }
50783
- if (prevDoc && !prevDoc.eq(doc2)) shouldUpdate = true;
50784
- if (prevActiveThreadId !== currentActiveThreadId) {
50799
+ const docChanged = prevDoc && !prevDoc.eq(doc2);
50800
+ if (docChanged) shouldUpdate = true;
50801
+ const activeThreadChanged = prevActiveThreadId !== currentActiveThreadId;
50802
+ if (activeThreadChanged) {
50785
50803
  shouldUpdate = true;
50786
50804
  prevActiveThreadId = currentActiveThreadId;
50787
50805
  }
50806
+ const onlyActiveThreadChanged = !docChanged && activeThreadChanged;
50788
50807
  if (!shouldUpdate) return;
50789
50808
  prevDoc = doc2;
50790
50809
  shouldUpdate = false;
50791
50810
  const decorations = [];
50792
- const allCommentPositions = {};
50811
+ const allCommentPositions = onlyActiveThreadChanged ? prevAllCommentPositions : {};
50793
50812
  doc2.descendants((node, pos) => {
50794
50813
  const { marks = [] } = node;
50795
50814
  const commentMarks = marks.filter((mark) => mark.type.name === CommentMarkName);
@@ -50797,14 +50816,16 @@ const CommentsPlugin = Extension.create({
50797
50816
  commentMarks.forEach((commentMark) => {
50798
50817
  const { attrs } = commentMark;
50799
50818
  const threadId = attrs.commentId || attrs.importedId;
50800
- const currentBounds = view.coordsAtPos(pos);
50801
- updatePosition({
50802
- allCommentPositions,
50803
- threadId,
50804
- pos,
50805
- currentBounds,
50806
- node
50807
- });
50819
+ if (!onlyActiveThreadChanged) {
50820
+ const currentBounds = view.coordsAtPos(pos);
50821
+ updatePosition({
50822
+ allCommentPositions,
50823
+ threadId,
50824
+ pos,
50825
+ currentBounds,
50826
+ node
50827
+ });
50828
+ }
50808
50829
  const isInternal = attrs.internal;
50809
50830
  if (!hasActive) hasActive = currentActiveThreadId === threadId;
50810
50831
  let color = getHighlightColor({
@@ -50827,20 +50848,22 @@ const CommentsPlugin = Extension.create({
50827
50848
  to: pos + node.nodeSize
50828
50849
  });
50829
50850
  if (trackedChangeMark) {
50830
- const currentBounds = view.coordsAtPos(pos);
50831
- const { id } = trackedChangeMark.mark.attrs;
50832
- updatePosition({
50833
- allCommentPositions,
50834
- threadId: id,
50835
- pos,
50836
- currentBounds,
50837
- node
50838
- });
50839
- const isActiveTrackedChange = currentActiveThreadId === id;
50851
+ if (!onlyActiveThreadChanged) {
50852
+ const currentBounds = view.coordsAtPos(pos);
50853
+ const { id } = trackedChangeMark.mark.attrs;
50854
+ updatePosition({
50855
+ allCommentPositions,
50856
+ threadId: id,
50857
+ pos,
50858
+ currentBounds,
50859
+ node
50860
+ });
50861
+ }
50862
+ const isActiveTrackedChange = currentActiveThreadId === trackedChangeMark.mark.attrs.id;
50840
50863
  if (isActiveTrackedChange) {
50841
50864
  const trackedChangeDeco = Decoration.inline(pos, pos + node.nodeSize, {
50842
50865
  style: `border-width: 2px;`,
50843
- "data-thread-id": id,
50866
+ "data-thread-id": trackedChangeMark.mark.attrs.id,
50844
50867
  class: "sd-editor-tracked-change-highlight"
50845
50868
  });
50846
50869
  decorations.push(trackedChangeDeco);
@@ -50858,7 +50881,13 @@ const CommentsPlugin = Extension.create({
50858
50881
  });
50859
50882
  view.dispatch(tr2);
50860
50883
  }
50861
- editor.emit("comment-positions", { allCommentPositions });
50884
+ if (!onlyActiveThreadChanged) {
50885
+ const positionsChanged = hasPositionsChanged(prevAllCommentPositions, allCommentPositions);
50886
+ if (positionsChanged) {
50887
+ prevAllCommentPositions = allCommentPositions;
50888
+ editor.emit("comment-positions", { allCommentPositions });
50889
+ }
50890
+ }
50862
50891
  }
50863
50892
  };
50864
50893
  }
@@ -50866,6 +50895,19 @@ const CommentsPlugin = Extension.create({
50866
50895
  return [commentsPlugin];
50867
50896
  }
50868
50897
  });
50898
+ const hasPositionsChanged = (prevPositions, currPositions) => {
50899
+ const prevKeys = Object.keys(prevPositions);
50900
+ const currKeys = Object.keys(currPositions);
50901
+ if (prevKeys.length !== currKeys.length) return true;
50902
+ for (const key2 of currKeys) {
50903
+ const prev = prevPositions[key2];
50904
+ const curr = currPositions[key2];
50905
+ if (!prev || prev.top !== curr.top || prev.left !== curr.left) {
50906
+ return true;
50907
+ }
50908
+ }
50909
+ return false;
50910
+ };
50869
50911
  const getActiveCommentId = (doc2, selection) => {
50870
50912
  if (!selection) return;
50871
50913
  const { $from, $to } = selection;
@@ -53632,7 +53674,7 @@ const _Editor = class _Editor2 extends EventEmitter$1 {
53632
53674
  { default: remarkStringify },
53633
53675
  { default: remarkGfm }
53634
53676
  ] = await Promise.all([
53635
- import("./index-BNr0wgOU-j0xGZdr7.es.js"),
53677
+ import("./index-BNr0wgOU-Bj1k6CCB.es.js"),
53636
53678
  import("./index-DRCvimau-Cw339678.es.js"),
53637
53679
  import("./index-C_x_N6Uh-DJn8hIEt.es.js"),
53638
53680
  import("./index-D_sWOSiG-DE96TaT5.es.js"),
@@ -58070,8 +58112,36 @@ const createLinkedStylesPlugin = (editor) => {
58070
58112
  if (!editor.converter || editor.options.mode !== "docx") return { ...prev };
58071
58113
  let decorations = prev.decorations || DecorationSet.empty;
58072
58114
  if (tr.docChanged) {
58073
- const styles = LinkedStylesPluginKey.getState(editor.state).styles;
58074
- decorations = generateDecorations(newEditorState, styles);
58115
+ let mightAffectStyles = false;
58116
+ const styleRelatedMarks = /* @__PURE__ */ new Set(["textStyle", "bold", "italic", "underline", "strike"]);
58117
+ tr.steps.forEach((step) => {
58118
+ if (step.slice) {
58119
+ step.slice.content.descendants((node) => {
58120
+ if (node.attrs?.styleId) {
58121
+ mightAffectStyles = true;
58122
+ return false;
58123
+ }
58124
+ if (node.marks.length > 0) {
58125
+ const hasStyleMarks = node.marks.some((mark) => styleRelatedMarks.has(mark.type.name));
58126
+ if (hasStyleMarks) {
58127
+ mightAffectStyles = true;
58128
+ return false;
58129
+ }
58130
+ }
58131
+ });
58132
+ }
58133
+ if (step.jsonID === "addMark" || step.jsonID === "removeMark") {
58134
+ if (step.mark && styleRelatedMarks.has(step.mark.type.name)) {
58135
+ mightAffectStyles = true;
58136
+ }
58137
+ }
58138
+ });
58139
+ if (mightAffectStyles) {
58140
+ const styles = LinkedStylesPluginKey.getState(editor.state).styles;
58141
+ decorations = generateDecorations(newEditorState, styles);
58142
+ } else {
58143
+ decorations = decorations.map(tr.mapping, tr.doc);
58144
+ }
58075
58145
  }
58076
58146
  return { ...prev, decorations };
58077
58147
  }
@@ -58384,6 +58454,12 @@ function parseFontFamilyFromRunProperties(listRunProperties) {
58384
58454
  const eastAsia = listRunProperties?.["w:eastAsia"];
58385
58455
  return ascii || hAnsi || eastAsia || null;
58386
58456
  }
58457
+ const computedStylesCache = /* @__PURE__ */ new WeakMap();
58458
+ function clearComputedStyleCache(domNode) {
58459
+ if (domNode) {
58460
+ computedStylesCache.delete(domNode);
58461
+ }
58462
+ }
58387
58463
  function readNodeViewStyles(view) {
58388
58464
  const fallback = { fontSize: null, fontFamily: null, lineHeight: null };
58389
58465
  if (!view?.dom) return fallback;
@@ -58393,13 +58469,27 @@ function readNodeViewStyles(view) {
58393
58469
  lineHeight: view.dom.style?.lineHeight || null
58394
58470
  };
58395
58471
  if (inline.fontSize && inline.fontFamily && inline.lineHeight) return inline;
58472
+ if (computedStylesCache.has(view.dom)) {
58473
+ const cached = computedStylesCache.get(view.dom);
58474
+ return {
58475
+ fontSize: inline.fontSize || cached.fontSize,
58476
+ fontFamily: inline.fontFamily || cached.fontFamily,
58477
+ lineHeight: inline.lineHeight || cached.lineHeight
58478
+ };
58479
+ }
58396
58480
  const globalWindow = typeof window !== "undefined" ? window : void 0;
58397
58481
  if (globalWindow?.getComputedStyle) {
58398
58482
  const computed2 = globalWindow.getComputedStyle(view.dom);
58483
+ const computedStyles = {
58484
+ fontSize: computed2.fontSize,
58485
+ fontFamily: computed2.fontFamily,
58486
+ lineHeight: computed2.lineHeight
58487
+ };
58488
+ computedStylesCache.set(view.dom, computedStyles);
58399
58489
  return {
58400
- fontSize: inline.fontSize || computed2.fontSize,
58401
- fontFamily: inline.fontFamily || computed2.fontFamily,
58402
- lineHeight: inline.lineHeight || computed2.lineHeight
58490
+ fontSize: inline.fontSize || computedStyles.fontSize,
58491
+ fontFamily: inline.fontFamily || computedStyles.fontFamily,
58492
+ lineHeight: inline.lineHeight || computedStyles.lineHeight
58403
58493
  };
58404
58494
  }
58405
58495
  return inline;
@@ -58613,9 +58703,14 @@ class ListItemNodeView {
58613
58703
  });
58614
58704
  }
58615
58705
  update(node, decorations) {
58706
+ const prevNode = this.node;
58616
58707
  this.node = node;
58617
58708
  this.decorations = decorations;
58618
58709
  this.invalidateResolvedPos();
58710
+ const stylingAttrsChanged = !prevNode || prevNode.attrs.styleId !== node.attrs.styleId || prevNode.attrs.numId !== node.attrs.numId || prevNode.attrs.level !== node.attrs.level;
58711
+ if (stylingAttrsChanged) {
58712
+ clearComputedStyleCache(this.dom);
58713
+ }
58619
58714
  const { fontSize: fontSize2, fontFamily: fontFamily2, lineHeight: lineHeight2 } = resolveListItemTypography({
58620
58715
  node,
58621
58716
  pos: this.getResolvedPos(),
@@ -58626,11 +58721,15 @@ class ListItemNodeView {
58626
58721
  this.dom.style.fontSize = fontSize2;
58627
58722
  this.dom.style.fontFamily = fontFamily2 || "inherit";
58628
58723
  this.dom.style.lineHeight = lineHeight2 || "";
58629
- this.refreshIndentStyling();
58724
+ const attrsChanged = stylingAttrsChanged || prevNode?.attrs.indent !== node.attrs.indent;
58725
+ if (attrsChanged) {
58726
+ this.refreshIndentStyling();
58727
+ }
58630
58728
  }
58631
58729
  destroy() {
58632
58730
  activeListItemNodeViews.delete(this);
58633
58731
  this.numberingDOM.removeEventListener("click", this.handleNumberingClick);
58732
+ clearComputedStyleCache(this.dom);
58634
58733
  const caf = typeof globalThis !== "undefined" ? globalThis.cancelAnimationFrame : void 0;
58635
58734
  if (this._pendingIndentRefresh != null && typeof caf === "function") {
58636
58735
  caf(this._pendingIndentRefresh);
@@ -58749,8 +58848,11 @@ function calculateMarkerWidth(dom, numberingDOM, editor, { withPadding = true }
58749
58848
  if (!markerText.trim()) return 0;
58750
58849
  try {
58751
58850
  if (editor?.options?.isHeadless) return 0;
58851
+ if (typeof globalThis.CanvasRenderingContext2D === "undefined") return 0;
58752
58852
  const canvas = document.createElement("canvas");
58853
+ if (typeof canvas.getContext !== "function") return 0;
58753
58854
  const context = canvas.getContext("2d");
58855
+ if (!context) return 0;
58754
58856
  const fontSizePx = fontSize2.includes("pt") ? Number.parseFloat(fontSize2) * POINT_TO_PIXEL_CONVERSION_FACTOR : Number.parseFloat(fontSize2);
58755
58857
  context.font = `${fontSizePx}px ${fontFamily2}`;
58756
58858
  const textWidth = context.measureText(markerText).width;
@@ -58769,7 +58871,9 @@ function orderedListSync(editor) {
58769
58871
  appendTransaction(transactions, oldState, newState) {
58770
58872
  if (transactions.every((tr2) => tr2.getMeta("y-sync$"))) return null;
58771
58873
  const updateNodeViews = transactions.some((tr2) => tr2.getMeta("updatedListItemNodeViews"));
58772
- if (updateNodeViews || !hasInitialized) refreshAllListItemNodeViews();
58874
+ if (updateNodeViews || !hasInitialized) {
58875
+ refreshAllListItemNodeViews();
58876
+ }
58773
58877
  const isFromPlugin = transactions.some((tr2) => tr2.getMeta("orderedListSync"));
58774
58878
  const docChanged = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
58775
58879
  if (isFromPlugin || !docChanged) {
@@ -58781,10 +58885,24 @@ function orderedListSync(editor) {
58781
58885
  const listMap = /* @__PURE__ */ new Map();
58782
58886
  const listInitialized = /* @__PURE__ */ new Map();
58783
58887
  const shouldProcess = transactions.some((tr2) => {
58888
+ if (tr2.getMeta("updateListSync")) return true;
58784
58889
  return tr2.steps.some((step) => {
58785
58890
  const stepJSON = step.toJSON();
58786
- const hasUpdateMeta = tr2.getMeta("updateListSync");
58787
- return hasUpdateMeta || stepJSON && stepJSON.slice && JSON.stringify(stepJSON).includes('"listItem"');
58891
+ if (step.slice?.content) {
58892
+ let hasListItem = false;
58893
+ step.slice.content.descendants((node) => {
58894
+ if (node.type.name === "listItem") {
58895
+ hasListItem = true;
58896
+ return false;
58897
+ }
58898
+ });
58899
+ if (hasListItem) return true;
58900
+ }
58901
+ if (stepJSON && stepJSON.slice) {
58902
+ const jsonStr = JSON.stringify(stepJSON);
58903
+ if (jsonStr.includes('"listItem"')) return true;
58904
+ }
58905
+ return false;
58788
58906
  });
58789
58907
  });
58790
58908
  if (!shouldProcess) return null;
@@ -59254,17 +59372,68 @@ const Paragraph = OxmlNode.create({
59254
59372
  },
59255
59373
  addPmPlugins() {
59256
59374
  const { view } = this.editor;
59375
+ const dropcapWidthCache = /* @__PURE__ */ new Map();
59376
+ const hasDropcapParagraph = (node) => node.type.name === "paragraph" && node.attrs.dropcap?.type === "margin";
59377
+ const invalidateCacheForRange = (from2, to) => {
59378
+ for (const [pos] of dropcapWidthCache) {
59379
+ if (pos >= from2 && pos <= to) {
59380
+ dropcapWidthCache.delete(pos);
59381
+ }
59382
+ }
59383
+ };
59257
59384
  const dropcapPlugin = new Plugin({
59258
59385
  name: "dropcapPlugin",
59259
59386
  key: new PluginKey("dropcapPlugin"),
59260
59387
  state: {
59261
59388
  init(_2, state2) {
59262
- let decorations = getDropcapDecorations(state2, view);
59389
+ const decorations = getDropcapDecorations(state2, view, dropcapWidthCache);
59263
59390
  return DecorationSet.create(state2.doc, decorations);
59264
59391
  },
59265
59392
  apply(tr, oldDecorationSet, oldState, newState) {
59266
59393
  if (!tr.docChanged) return oldDecorationSet;
59267
- const decorations = getDropcapDecorations(newState, view);
59394
+ let hasDropcaps = false;
59395
+ newState.doc.descendants((node) => {
59396
+ if (hasDropcapParagraph(node)) {
59397
+ hasDropcaps = true;
59398
+ return false;
59399
+ }
59400
+ });
59401
+ if (!hasDropcaps) {
59402
+ dropcapWidthCache.clear();
59403
+ return DecorationSet.empty;
59404
+ }
59405
+ let affectsDropcaps = false;
59406
+ tr.steps.forEach((step) => {
59407
+ if (step.slice?.content) {
59408
+ step.slice.content.descendants((node) => {
59409
+ if (hasDropcapParagraph(node)) {
59410
+ affectsDropcaps = true;
59411
+ return false;
59412
+ }
59413
+ });
59414
+ }
59415
+ if (step.jsonID === "replace" && step.from !== void 0 && step.to !== void 0) {
59416
+ try {
59417
+ oldState.doc.nodesBetween(step.from, step.to, (node) => {
59418
+ if (hasDropcapParagraph(node)) {
59419
+ affectsDropcaps = true;
59420
+ return false;
59421
+ }
59422
+ });
59423
+ } catch {
59424
+ affectsDropcaps = true;
59425
+ }
59426
+ }
59427
+ });
59428
+ if (!affectsDropcaps) {
59429
+ return oldDecorationSet.map(tr.mapping, tr.doc);
59430
+ }
59431
+ tr.steps.forEach((step) => {
59432
+ if (step.from !== void 0 && step.to !== void 0) {
59433
+ invalidateCacheForRange(step.from, step.to);
59434
+ }
59435
+ });
59436
+ const decorations = getDropcapDecorations(newState, view, dropcapWidthCache);
59268
59437
  return DecorationSet.create(newState.doc, decorations);
59269
59438
  }
59270
59439
  },
@@ -59277,12 +59446,12 @@ const Paragraph = OxmlNode.create({
59277
59446
  return [dropcapPlugin];
59278
59447
  }
59279
59448
  });
59280
- const getDropcapDecorations = (state2, view) => {
59281
- let decorations = [];
59449
+ const getDropcapDecorations = (state2, view, widthCache) => {
59450
+ const decorations = [];
59282
59451
  state2.doc.descendants((node, pos) => {
59283
59452
  if (node.type.name === "paragraph") {
59284
59453
  if (node.attrs.dropcap?.type === "margin") {
59285
- const width = getDropcapWidth(view, pos);
59454
+ const width = getDropcapWidth(view, pos, widthCache);
59286
59455
  decorations.push(Decoration.inline(pos, pos + node.nodeSize, { style: `margin-left: -${width}px;` }));
59287
59456
  }
59288
59457
  return false;
@@ -59290,12 +59459,17 @@ const getDropcapDecorations = (state2, view) => {
59290
59459
  });
59291
59460
  return decorations;
59292
59461
  };
59293
- function getDropcapWidth(view, pos) {
59462
+ function getDropcapWidth(view, pos, widthCache) {
59463
+ if (widthCache.has(pos)) {
59464
+ return widthCache.get(pos);
59465
+ }
59294
59466
  const domNode = view.nodeDOM(pos);
59295
59467
  if (domNode) {
59296
59468
  const range2 = document.createRange();
59297
59469
  range2.selectNodeContents(domNode);
59298
- return range2.getBoundingClientRect().width;
59470
+ const width = range2.getBoundingClientRect().width;
59471
+ widthCache.set(pos, width);
59472
+ return width;
59299
59473
  }
59300
59474
  return 0;
59301
59475
  }
@@ -59757,7 +59931,7 @@ const TabNode = Node$1.create({
59757
59931
  },
59758
59932
  addPmPlugins() {
59759
59933
  const { view, helpers: helpers2 } = this.editor;
59760
- const mergeRanges = (ranges) => {
59934
+ const mergeRanges2 = (ranges) => {
59761
59935
  if (ranges.length === 0) return [];
59762
59936
  const sorted = ranges.slice().sort((a, b2) => a[0] - b2[0]);
59763
59937
  const merged = [sorted[0]];
@@ -59830,7 +60004,7 @@ const TabNode = Node$1.create({
59830
60004
  if (rangesToRecalculate.length === 0) {
59831
60005
  return { decorations };
59832
60006
  }
59833
- const mergedRanges = mergeRanges(rangesToRecalculate);
60007
+ const mergedRanges = mergeRanges2(rangesToRecalculate);
59834
60008
  mergedRanges.forEach(([start2, end2]) => {
59835
60009
  const oldDecorations = decorations.find(start2, end2);
59836
60010
  decorations = decorations.remove(oldDecorations);
@@ -63733,6 +63907,29 @@ createAnnotation_fn = function({ displayLabel } = {}) {
63733
63907
  content
63734
63908
  };
63735
63909
  };
63910
+ const mergeRanges = (ranges) => {
63911
+ if (ranges.length === 0) return [];
63912
+ const sorted = [...ranges].sort((a, b2) => a[0] - b2[0]).map((range2) => [...range2]);
63913
+ const merged = [sorted[0]];
63914
+ for (let i = 1; i < sorted.length; i++) {
63915
+ const current = sorted[i];
63916
+ const lastMerged = merged[merged.length - 1];
63917
+ if (current[0] <= lastMerged[1]) {
63918
+ lastMerged[1] = Math.max(lastMerged[1], current[1]);
63919
+ } else {
63920
+ merged.push(current);
63921
+ }
63922
+ }
63923
+ return merged;
63924
+ };
63925
+ const clampRange = (start2, end2, docSize) => {
63926
+ const safeStart = Math.max(0, Math.min(start2, docSize));
63927
+ const safeEnd = Math.max(0, Math.min(end2, docSize));
63928
+ if (safeStart >= safeEnd) {
63929
+ return null;
63930
+ }
63931
+ return [safeStart, safeEnd];
63932
+ };
63736
63933
  const FieldAnnotationPlugin = (options = {}) => {
63737
63934
  let { editor, annotationClass: annotationClass2 } = options;
63738
63935
  return new Plugin({
@@ -63807,24 +64004,104 @@ const FieldAnnotationPlugin = (options = {}) => {
63807
64004
  },
63808
64005
  /// For y-prosemirror support.
63809
64006
  appendTransaction: (transactions, oldState, newState) => {
63810
- let docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
64007
+ const docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
63811
64008
  if (!docChanges) {
63812
64009
  return;
63813
64010
  }
63814
- let { tr } = newState;
63815
- let changed = false;
63816
- let annotations = getAllFieldAnnotations(newState);
63817
- if (!annotations.length) {
63818
- return;
64011
+ const affectedRanges = [];
64012
+ let hasFieldAnnotationsInSlice = false;
64013
+ let hasSteps = false;
64014
+ transactions.forEach((transaction) => {
64015
+ if (!transaction.steps) return;
64016
+ hasSteps = true;
64017
+ transaction.steps.forEach((step) => {
64018
+ if (step.slice?.content) {
64019
+ step.slice.content.descendants((node) => {
64020
+ if (node.type.name === "fieldAnnotation") {
64021
+ hasFieldAnnotationsInSlice = true;
64022
+ return false;
64023
+ }
64024
+ });
64025
+ }
64026
+ if (typeof step.from === "number" && typeof step.to === "number") {
64027
+ const from2 = step.from;
64028
+ const to = step.from === step.to && step.slice?.size ? step.from + step.slice.size : step.to;
64029
+ affectedRanges.push([from2, to]);
64030
+ }
64031
+ });
64032
+ });
64033
+ if (hasSteps && !hasFieldAnnotationsInSlice && affectedRanges.length > 0) {
64034
+ const mergedRanges = mergeRanges(affectedRanges);
64035
+ let hasExistingAnnotations = false;
64036
+ for (const [start2, end2] of mergedRanges) {
64037
+ const clampedRange = clampRange(start2, end2, newState.doc.content.size);
64038
+ if (!clampedRange) continue;
64039
+ const [validStart, validEnd] = clampedRange;
64040
+ try {
64041
+ newState.doc.nodesBetween(validStart, validEnd, (node) => {
64042
+ if (node.type.name === "fieldAnnotation") {
64043
+ hasExistingAnnotations = true;
64044
+ return false;
64045
+ }
64046
+ });
64047
+ } catch (error) {
64048
+ console.warn("FieldAnnotationPlugin: range check failed, assuming annotations exist", error);
64049
+ hasExistingAnnotations = true;
64050
+ break;
64051
+ }
64052
+ if (hasExistingAnnotations) break;
64053
+ }
64054
+ if (!hasExistingAnnotations) {
64055
+ return;
64056
+ }
63819
64057
  }
63820
- annotations.forEach(({ node, pos }) => {
63821
- let { marks } = node;
63822
- let currentNode = tr.doc.nodeAt(pos);
64058
+ const { tr } = newState;
64059
+ let changed = false;
64060
+ const removeMarksFromAnnotation = (node, pos) => {
64061
+ const { marks } = node;
64062
+ const currentNode = tr.doc.nodeAt(pos);
63823
64063
  if (marks.length > 0 && node.eq(currentNode)) {
63824
64064
  tr.removeMark(pos, pos + node.nodeSize, null);
63825
64065
  changed = true;
63826
64066
  }
63827
- });
64067
+ };
64068
+ if (affectedRanges.length > 0) {
64069
+ const mergedRanges = mergeRanges(affectedRanges);
64070
+ let shouldFallbackToFullScan = false;
64071
+ for (const [start2, end2] of mergedRanges) {
64072
+ const clampedRange = clampRange(start2, end2, newState.doc.content.size);
64073
+ if (!clampedRange) continue;
64074
+ const [validStart, validEnd] = clampedRange;
64075
+ try {
64076
+ newState.doc.nodesBetween(validStart, validEnd, (node, pos) => {
64077
+ if (node.type.name === "fieldAnnotation") {
64078
+ removeMarksFromAnnotation(node, pos);
64079
+ }
64080
+ });
64081
+ } catch (error) {
64082
+ console.warn("FieldAnnotationPlugin: nodesBetween failed, falling back to full scan", error);
64083
+ shouldFallbackToFullScan = true;
64084
+ break;
64085
+ }
64086
+ }
64087
+ if (shouldFallbackToFullScan) {
64088
+ const annotations = getAllFieldAnnotations(newState);
64089
+ if (!annotations.length) {
64090
+ return changed ? tr : null;
64091
+ }
64092
+ annotations.forEach(({ node, pos }) => {
64093
+ removeMarksFromAnnotation(node, pos);
64094
+ });
64095
+ }
64096
+ } else {
64097
+ const annotations = getAllFieldAnnotations(newState);
64098
+ if (!annotations.length) {
64099
+ return;
64100
+ }
64101
+ annotations.forEach(({ node, pos }) => {
64102
+ removeMarksFromAnnotation(node, pos);
64103
+ });
64104
+ }
63828
64105
  return changed ? tr : null;
63829
64106
  }
63830
64107
  ///
@@ -65634,7 +65911,9 @@ const registerImages = async (foundImages, editor, view) => {
65634
65911
  }
65635
65912
  });
65636
65913
  };
65914
+ const stepHasSlice = (step) => "slice" in step && Boolean(step.slice);
65637
65915
  const ImagePositionPluginKey = new PluginKey("ImagePosition");
65916
+ const pageBreakPositionCache = /* @__PURE__ */ new WeakMap();
65638
65917
  const ImagePositionPlugin = ({ editor }) => {
65639
65918
  const { view } = editor;
65640
65919
  let shouldUpdate = false;
@@ -65647,6 +65926,20 @@ const ImagePositionPlugin = ({ editor }) => {
65647
65926
  },
65648
65927
  apply(tr, oldDecorationSet, oldState, newState) {
65649
65928
  if (!tr.docChanged && !shouldUpdate) return oldDecorationSet;
65929
+ let affectsImages = false;
65930
+ tr.steps.forEach((step) => {
65931
+ if (stepHasSlice(step)) {
65932
+ step.slice.content.descendants((node) => {
65933
+ if (node.type.name === "image" || node.attrs?.anchorData) {
65934
+ affectsImages = true;
65935
+ return false;
65936
+ }
65937
+ });
65938
+ }
65939
+ });
65940
+ if (!affectsImages && !shouldUpdate) {
65941
+ return oldDecorationSet.map(tr.mapping, tr.doc);
65942
+ }
65650
65943
  const decorations = getImagePositionDecorations(newState, view);
65651
65944
  shouldUpdate = false;
65652
65945
  return DecorationSet.create(newState.doc, decorations);
@@ -65676,6 +65969,16 @@ const ImagePositionPlugin = ({ editor }) => {
65676
65969
  };
65677
65970
  const getImagePositionDecorations = (state2, view) => {
65678
65971
  let decorations = [];
65972
+ let hasAnchoredImages = false;
65973
+ state2.doc.descendants((node) => {
65974
+ if (node.attrs?.anchorData) {
65975
+ hasAnchoredImages = true;
65976
+ return false;
65977
+ }
65978
+ });
65979
+ if (!hasAnchoredImages) {
65980
+ return decorations;
65981
+ }
65679
65982
  state2.doc.descendants((node, pos) => {
65680
65983
  if (node.attrs.anchorData) {
65681
65984
  let style2 = "";
@@ -65684,7 +65987,15 @@ const getImagePositionDecorations = (state2, view) => {
65684
65987
  const { size: size2, padding } = node.attrs;
65685
65988
  const pageBreak = findPreviousDomNodeWithClass(view, pos, "pagination-break-wrapper");
65686
65989
  if (pageBreak && vRelativeFrom === "margin" && alignH) {
65687
- const topPos = pageBreak?.offsetTop + pageBreak?.offsetHeight;
65990
+ let pageBreakPos = pageBreakPositionCache.get(pageBreak);
65991
+ if (!pageBreakPos) {
65992
+ pageBreakPos = {
65993
+ top: pageBreak.offsetTop,
65994
+ height: pageBreak.offsetHeight
65995
+ };
65996
+ pageBreakPositionCache.set(pageBreak, pageBreakPos);
65997
+ }
65998
+ const topPos = pageBreakPos.top + pageBreakPos.height;
65688
65999
  let horizontalAlignment = `${alignH}: 0;`;
65689
66000
  if (alignH === "center") horizontalAlignment = "left: 50%; transform: translateX(-50%);";
65690
66001
  style2 += vRelativeFrom === "margin" ? `position: absolute; top: ${topPos}px; ${horizontalAlignment}` : "";
@@ -67176,11 +67487,22 @@ const BlockNode = Extension.create({
67176
67487
  },
67177
67488
  addPmPlugins() {
67178
67489
  let hasInitialized = false;
67490
+ const assignBlockId = (tr, node, pos) => {
67491
+ tr.setNodeMarkup(
67492
+ pos,
67493
+ void 0,
67494
+ {
67495
+ ...node.attrs,
67496
+ sdBlockId: v4()
67497
+ },
67498
+ node.marks
67499
+ );
67500
+ };
67179
67501
  return [
67180
67502
  new Plugin({
67181
67503
  key: BlockNodePluginKey,
67182
67504
  appendTransaction: (transactions, oldState, newState) => {
67183
- let docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
67505
+ const docChanges = transactions.some((tr2) => tr2.docChanged) && !oldState.doc.eq(newState.doc);
67184
67506
  if (hasInitialized && !docChanges) {
67185
67507
  return;
67186
67508
  }
@@ -67189,21 +67511,87 @@ const BlockNode = Extension.create({
67189
67511
  }
67190
67512
  const { tr } = newState;
67191
67513
  let changed = false;
67192
- newState.doc.descendants((node, pos) => {
67193
- if (!nodeAllowsSdBlockIdAttr(node) || !nodeNeedsSdBlockId(node)) {
67194
- return;
67514
+ if (!hasInitialized) {
67515
+ newState.doc.descendants((node, pos) => {
67516
+ if (nodeAllowsSdBlockIdAttr(node) && nodeNeedsSdBlockId(node)) {
67517
+ assignBlockId(tr, node, pos);
67518
+ changed = true;
67519
+ }
67520
+ });
67521
+ } else {
67522
+ const rangesToCheck = [];
67523
+ let shouldFallbackToFullTraversal = false;
67524
+ transactions.forEach((transaction, txIndex) => {
67525
+ transaction.steps.forEach((step, stepIndex) => {
67526
+ if (!(step instanceof ReplaceStep)) return;
67527
+ const hasNewBlockNodes = step.slice?.content?.content?.some((node) => nodeAllowsSdBlockIdAttr(node));
67528
+ if (!hasNewBlockNodes) return;
67529
+ const stepMap = step.getMap();
67530
+ stepMap.forEach((_oldStart, _oldEnd, newStart, newEnd) => {
67531
+ if (newEnd <= newStart) {
67532
+ if (process$1$1.env.NODE_ENV === "development") {
67533
+ console.debug("Block node: invalid range in step map, falling back to full traversal");
67534
+ }
67535
+ shouldFallbackToFullTraversal = true;
67536
+ return;
67537
+ }
67538
+ let rangeStart = newStart;
67539
+ let rangeEnd = newEnd;
67540
+ for (let i = stepIndex + 1; i < transaction.steps.length; i++) {
67541
+ const laterStepMap = transaction.steps[i].getMap();
67542
+ rangeStart = laterStepMap.map(rangeStart, -1);
67543
+ rangeEnd = laterStepMap.map(rangeEnd, 1);
67544
+ }
67545
+ for (let i = txIndex + 1; i < transactions.length; i++) {
67546
+ const laterTx = transactions[i];
67547
+ rangeStart = laterTx.mapping.map(rangeStart, -1);
67548
+ rangeEnd = laterTx.mapping.map(rangeEnd, 1);
67549
+ }
67550
+ if (rangeEnd <= rangeStart) {
67551
+ if (process$1$1.env.NODE_ENV === "development") {
67552
+ console.debug("Block node: invalid range after mapping, falling back to full traversal");
67553
+ }
67554
+ shouldFallbackToFullTraversal = true;
67555
+ return;
67556
+ }
67557
+ rangesToCheck.push([rangeStart, rangeEnd]);
67558
+ });
67559
+ });
67560
+ });
67561
+ const mergedRanges = mergeRanges(rangesToCheck);
67562
+ for (const [start2, end2] of mergedRanges) {
67563
+ const docSize = newState.doc.content.size;
67564
+ const clampedRange = clampRange(start2, end2, docSize);
67565
+ if (!clampedRange) {
67566
+ if (process$1$1.env.NODE_ENV === "development") {
67567
+ console.debug("Block node: invalid range after clamping, falling back to full traversal");
67568
+ }
67569
+ shouldFallbackToFullTraversal = true;
67570
+ break;
67571
+ }
67572
+ const [safeStart, safeEnd] = clampedRange;
67573
+ try {
67574
+ newState.doc.nodesBetween(safeStart, safeEnd, (node, pos) => {
67575
+ if (nodeAllowsSdBlockIdAttr(node) && nodeNeedsSdBlockId(node)) {
67576
+ assignBlockId(tr, node, pos);
67577
+ changed = true;
67578
+ }
67579
+ });
67580
+ } catch (error) {
67581
+ console.warn("Block node plugin: nodesBetween failed, falling back to full traversal", error);
67582
+ shouldFallbackToFullTraversal = true;
67583
+ break;
67584
+ }
67195
67585
  }
67196
- tr.setNodeMarkup(
67197
- pos,
67198
- void 0,
67199
- {
67200
- ...node.attrs,
67201
- sdBlockId: v4()
67202
- },
67203
- node.marks
67204
- );
67205
- changed = true;
67206
- });
67586
+ if (shouldFallbackToFullTraversal) {
67587
+ newState.doc.descendants((node, pos) => {
67588
+ if (nodeAllowsSdBlockIdAttr(node) && nodeNeedsSdBlockId(node)) {
67589
+ assignBlockId(tr, node, pos);
67590
+ changed = true;
67591
+ }
67592
+ });
67593
+ }
67594
+ }
67207
67595
  if (changed && !hasInitialized) {
67208
67596
  hasInitialized = true;
67209
67597
  tr.setMeta("blockNodeInitialUpdate", true);
@@ -73679,8 +74067,8 @@ const PopoverPlugin = Extension.create({
73679
74067
  return {};
73680
74068
  },
73681
74069
  apply: (tr, value) => {
73682
- let newValue = { ...value };
73683
- if (tr.docChanged) {
74070
+ const newValue = { ...value };
74071
+ if (tr.docChanged || tr.selectionSet) {
73684
74072
  newValue.shouldUpdate = true;
73685
74073
  } else {
73686
74074
  newValue.shouldUpdate = false;
@@ -74935,6 +75323,8 @@ const Pagination = Extension.create({
74935
75323
  let shouldUpdate = false;
74936
75324
  let hasInitialized = false;
74937
75325
  let shouldInitialize = false;
75326
+ let paginationTimeout = null;
75327
+ const PAGINATION_DEBOUNCE_MS = 150;
74938
75328
  const paginationPlugin = new Plugin({
74939
75329
  key: PaginationPluginKey,
74940
75330
  state: {
@@ -74962,6 +75352,9 @@ const Pagination = Extension.create({
74962
75352
  shouldUpdate = true;
74963
75353
  shouldInitialize = meta.isReadyToInit;
74964
75354
  }
75355
+ if (meta && meta.skipPagination) {
75356
+ return { ...oldState };
75357
+ }
74965
75358
  const syncMeta = tr.getMeta("y-sync$");
74966
75359
  const listSyncMeta = tr.getMeta("orderedListSync");
74967
75360
  if (syncMeta && syncMeta.isChangeOrigin || listSyncMeta) {
@@ -74993,11 +75386,23 @@ const Pagination = Extension.create({
74993
75386
  shouldUpdate = false;
74994
75387
  return { ...oldState };
74995
75388
  }
75389
+ if (!isForceUpdate && hasInitialized && tr.docChanged) {
75390
+ let isMarkOnlyChange = true;
75391
+ tr.steps.forEach((step) => {
75392
+ if (step.jsonID !== "addMark" && step.jsonID !== "removeMark") {
75393
+ isMarkOnlyChange = false;
75394
+ }
75395
+ });
75396
+ if (isMarkOnlyChange) {
75397
+ shouldUpdate = false;
75398
+ return { ...oldState };
75399
+ }
75400
+ }
74996
75401
  shouldUpdate = true;
74997
75402
  if (isForceUpdate) shouldUpdate = true;
74998
75403
  return {
74999
75404
  ...oldState,
75000
- decorations: meta?.decorations?.map(tr.mapping, tr.doc) || DecorationSet.empty,
75405
+ decorations: meta?.decorations?.map(tr.mapping, tr.doc) || oldState.decorations.map(tr.mapping, tr.doc),
75001
75406
  isReadyToInit: shouldInitialize
75002
75407
  };
75003
75408
  }
@@ -75009,11 +75414,22 @@ const Pagination = Extension.create({
75009
75414
  update: (view) => {
75010
75415
  if (!PaginationPluginKey.getState(view.state)?.isEnabled) return;
75011
75416
  if (!shouldUpdate || isUpdating) return;
75012
- isUpdating = true;
75013
- hasInitialized = true;
75014
- performUpdate(editor, view, previousDecorations);
75015
- isUpdating = false;
75016
- shouldUpdate = false;
75417
+ const performPaginationUpdate = () => {
75418
+ if (!shouldUpdate) return;
75419
+ isUpdating = true;
75420
+ hasInitialized = true;
75421
+ performUpdate(editor, view, previousDecorations);
75422
+ isUpdating = false;
75423
+ shouldUpdate = false;
75424
+ };
75425
+ if (!hasInitialized) {
75426
+ performPaginationUpdate();
75427
+ return;
75428
+ }
75429
+ if (paginationTimeout) {
75430
+ clearTimeout(paginationTimeout);
75431
+ }
75432
+ paginationTimeout = setTimeout(performPaginationUpdate, PAGINATION_DEBOUNCE_MS);
75017
75433
  }
75018
75434
  };
75019
75435
  },