@pixerate/editor 0.23.0 → 0.25.0

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 (187) hide show
  1. package/README.md +167 -2
  2. package/THIRD_PARTY_NOTICES.md +80 -0
  3. package/dist/agent/index.cjs +10 -8
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +4 -3
  6. package/dist/agent/index.d.ts +4 -3
  7. package/dist/agent/index.js +4 -2
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/canvas/index.cjs +4437 -411
  10. package/dist/canvas/index.cjs.map +1 -1
  11. package/dist/canvas/index.d.cts +934 -4
  12. package/dist/canvas/index.d.ts +934 -4
  13. package/dist/canvas/index.js +4309 -283
  14. package/dist/canvas/index.js.map +1 -1
  15. package/dist/chunk-4BVP64JJ.cjs +1406 -0
  16. package/dist/chunk-4BVP64JJ.cjs.map +1 -0
  17. package/dist/chunk-664LQYFJ.js +115 -0
  18. package/dist/chunk-664LQYFJ.js.map +1 -0
  19. package/dist/chunk-7WISYZFO.cjs +740 -0
  20. package/dist/chunk-7WISYZFO.cjs.map +1 -0
  21. package/dist/chunk-AL6JMGWW.cjs +783 -0
  22. package/dist/chunk-AL6JMGWW.cjs.map +1 -0
  23. package/dist/chunk-BVP3TSLH.cjs +69 -0
  24. package/dist/chunk-BVP3TSLH.cjs.map +1 -0
  25. package/dist/{chunk-RIKBJLS2.cjs → chunk-C7P22VIP.cjs} +2001 -279
  26. package/dist/chunk-C7P22VIP.cjs.map +1 -0
  27. package/dist/chunk-D6FH2YAX.cjs +131 -0
  28. package/dist/chunk-D6FH2YAX.cjs.map +1 -0
  29. package/dist/chunk-ECCCYKGL.js +740 -0
  30. package/dist/chunk-ECCCYKGL.js.map +1 -0
  31. package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
  32. package/dist/chunk-FD4LPFAE.cjs.map +1 -0
  33. package/dist/{chunk-QBJ22YZR.js → chunk-FH6F67DN.js} +1999 -277
  34. package/dist/chunk-FH6F67DN.js.map +1 -0
  35. package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
  36. package/dist/chunk-FPENXAEJ.js.map +1 -0
  37. package/dist/chunk-HLIMTC6N.js +1 -0
  38. package/dist/chunk-HLIMTC6N.js.map +1 -0
  39. package/dist/chunk-HRMEDT2L.js +1406 -0
  40. package/dist/chunk-HRMEDT2L.js.map +1 -0
  41. package/dist/{chunk-QGHGJ56O.js → chunk-IXHSYOVY.js} +2518 -122
  42. package/dist/chunk-IXHSYOVY.js.map +1 -0
  43. package/dist/chunk-MKA3AHLV.cjs +256 -0
  44. package/dist/chunk-MKA3AHLV.cjs.map +1 -0
  45. package/dist/chunk-NAXVVS5I.js +783 -0
  46. package/dist/chunk-NAXVVS5I.js.map +1 -0
  47. package/dist/chunk-O5RYH2PG.js +69 -0
  48. package/dist/chunk-O5RYH2PG.js.map +1 -0
  49. package/dist/chunk-OXSV64JX.js +689 -0
  50. package/dist/chunk-OXSV64JX.js.map +1 -0
  51. package/dist/chunk-P3RQ5UJE.cjs +689 -0
  52. package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
  53. package/dist/chunk-P6ODPZ4W.js +256 -0
  54. package/dist/chunk-P6ODPZ4W.js.map +1 -0
  55. package/dist/chunk-PL4JB3BF.cjs +1 -0
  56. package/dist/chunk-PL4JB3BF.cjs.map +1 -0
  57. package/dist/{chunk-GVSMRPHB.cjs → chunk-PO6A6QQH.cjs} +2607 -211
  58. package/dist/chunk-PO6A6QQH.cjs.map +1 -0
  59. package/dist/{chunk-JJDLPEWL.js → chunk-QGYDWPRM.js} +2 -2
  60. package/dist/chunk-RR7F5GUM.js +5726 -0
  61. package/dist/chunk-RR7F5GUM.js.map +1 -0
  62. package/dist/chunk-TNNJXF46.cjs +115 -0
  63. package/dist/chunk-TNNJXF46.cjs.map +1 -0
  64. package/dist/chunk-U5HZSFCS.js +131 -0
  65. package/dist/chunk-U5HZSFCS.js.map +1 -0
  66. package/dist/{chunk-MJZBNWG7.js → chunk-UAKDG62Z.js} +309 -581
  67. package/dist/chunk-UAKDG62Z.js.map +1 -0
  68. package/dist/{chunk-CL37JGFW.cjs → chunk-V3CHHWOE.cjs} +4 -4
  69. package/dist/{chunk-CL37JGFW.cjs.map → chunk-V3CHHWOE.cjs.map} +1 -1
  70. package/dist/chunk-WSQKHXW7.cjs +5726 -0
  71. package/dist/chunk-WSQKHXW7.cjs.map +1 -0
  72. package/dist/{chunk-AA4ZEVCC.cjs → chunk-X4N4WUKB.cjs} +336 -608
  73. package/dist/chunk-X4N4WUKB.cjs.map +1 -0
  74. package/dist/commands/index.cjs +74 -1
  75. package/dist/commands/index.cjs.map +1 -1
  76. package/dist/commands/index.d.cts +38 -353
  77. package/dist/commands/index.d.ts +38 -353
  78. package/dist/commands/index.js +73 -0
  79. package/dist/commands/index.js.map +1 -1
  80. package/dist/comment-store-BEMgVlAA.d.cts +135 -0
  81. package/dist/comment-store-BEMgVlAA.d.ts +135 -0
  82. package/dist/compare/index.cjs +15 -0
  83. package/dist/compare/index.cjs.map +1 -0
  84. package/dist/compare/index.d.cts +58 -0
  85. package/dist/compare/index.d.ts +58 -0
  86. package/dist/compare/index.js +15 -0
  87. package/dist/compare/index.js.map +1 -0
  88. package/dist/controller-BIJiNoVs.d.cts +1842 -0
  89. package/dist/controller-BIJiNoVs.d.ts +1842 -0
  90. package/dist/documents-CHT1U5Vs.d.ts +86 -0
  91. package/dist/documents-Gp7wb0Me.d.cts +86 -0
  92. package/dist/extensions/index.cjs +100 -5
  93. package/dist/extensions/index.cjs.map +1 -1
  94. package/dist/extensions/index.d.cts +16 -4
  95. package/dist/extensions/index.d.ts +16 -4
  96. package/dist/extensions/index.js +100 -5
  97. package/dist/generation/index.cjs +2317 -0
  98. package/dist/generation/index.cjs.map +1 -0
  99. package/dist/generation/index.d.cts +1015 -0
  100. package/dist/generation/index.d.ts +1015 -0
  101. package/dist/generation/index.js +2317 -0
  102. package/dist/generation/index.js.map +1 -0
  103. package/dist/grammar/index.cjs +48 -3
  104. package/dist/grammar/index.cjs.map +1 -1
  105. package/dist/grammar/index.d.cts +322 -100
  106. package/dist/grammar/index.d.ts +322 -100
  107. package/dist/grammar/index.js +54 -9
  108. package/dist/image-editor/index.cjs +4392 -481
  109. package/dist/image-editor/index.cjs.map +1 -1
  110. package/dist/image-editor/index.d.cts +1249 -97
  111. package/dist/image-editor/index.d.ts +1249 -97
  112. package/dist/image-editor/index.js +4281 -370
  113. package/dist/image-editor/index.js.map +1 -1
  114. package/dist/index-7a6bHTLy.d.ts +1754 -0
  115. package/dist/index-Csd5qI8u.d.cts +1754 -0
  116. package/dist/index.cjs +1682 -99
  117. package/dist/index.cjs.map +1 -1
  118. package/dist/index.d.cts +118 -21
  119. package/dist/index.d.ts +118 -21
  120. package/dist/index.js +1630 -47
  121. package/dist/index.js.map +1 -1
  122. package/dist/mention-text-CDnCFd3c.d.cts +53 -0
  123. package/dist/mention-text-CDnCFd3c.d.ts +53 -0
  124. package/dist/migrate-iTlm3a8h.d.cts +112 -0
  125. package/dist/migrate-iTlm3a8h.d.ts +112 -0
  126. package/dist/model-C1zApQM8.d.cts +219 -0
  127. package/dist/model-C1zApQM8.d.ts +219 -0
  128. package/dist/persistence/index.cjs +676 -0
  129. package/dist/persistence/index.cjs.map +1 -0
  130. package/dist/persistence/index.d.cts +230 -0
  131. package/dist/persistence/index.d.ts +230 -0
  132. package/dist/persistence/index.js +676 -0
  133. package/dist/persistence/index.js.map +1 -0
  134. package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
  135. package/dist/{registry-GJI4gToU.d.ts → registry-CEgwXED1.d.cts} +12 -1
  136. package/dist/{registry-GJI4gToU.d.cts → registry-CEgwXED1.d.ts} +12 -1
  137. package/dist/registry-D32LpIc4.d.cts +354 -0
  138. package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
  139. package/dist/registry-evKTP4ls.d.ts +354 -0
  140. package/dist/schema-DYDGdYL9.d.cts +41 -0
  141. package/dist/schema-DYDGdYL9.d.ts +41 -0
  142. package/dist/serializers/index.cjs +12 -3
  143. package/dist/serializers/index.cjs.map +1 -1
  144. package/dist/serializers/index.d.cts +40 -12
  145. package/dist/serializers/index.d.ts +40 -12
  146. package/dist/serializers/index.js +12 -3
  147. package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
  148. package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
  149. package/dist/spreadsheet/index.cjs +161 -3
  150. package/dist/spreadsheet/index.cjs.map +1 -1
  151. package/dist/spreadsheet/index.d.cts +611 -20
  152. package/dist/spreadsheet/index.d.ts +611 -20
  153. package/dist/spreadsheet/index.js +168 -10
  154. package/dist/storage-BpFfspHm.d.cts +120 -0
  155. package/dist/storage-BpFfspHm.d.ts +120 -0
  156. package/dist/tokens/index.cjs +115 -0
  157. package/dist/tokens/index.cjs.map +1 -0
  158. package/dist/tokens/index.d.cts +212 -0
  159. package/dist/tokens/index.d.ts +212 -0
  160. package/dist/tokens/index.js +115 -0
  161. package/dist/tokens/index.js.map +1 -0
  162. package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
  163. package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
  164. package/dist/{track-changes-BSF58RK0.d.cts → track-changes-D_VAPELi.d.cts} +110 -144
  165. package/dist/{track-changes-BSF58RK0.d.ts → track-changes-Db_fGEvx.d.ts} +110 -144
  166. package/package.json +21 -1
  167. package/dist/chunk-4SUNJZWB.cjs.map +0 -1
  168. package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
  169. package/dist/chunk-AXV2ZW34.cjs +0 -118
  170. package/dist/chunk-AXV2ZW34.cjs.map +0 -1
  171. package/dist/chunk-B2ZRLN4S.js +0 -118
  172. package/dist/chunk-B2ZRLN4S.js.map +0 -1
  173. package/dist/chunk-GVSMRPHB.cjs.map +0 -1
  174. package/dist/chunk-K3R5NG2D.js +0 -3100
  175. package/dist/chunk-K3R5NG2D.js.map +0 -1
  176. package/dist/chunk-MJZBNWG7.js.map +0 -1
  177. package/dist/chunk-OYXSKQFR.js.map +0 -1
  178. package/dist/chunk-QBJ22YZR.js.map +0 -1
  179. package/dist/chunk-QGHGJ56O.js.map +0 -1
  180. package/dist/chunk-RIKBJLS2.cjs.map +0 -1
  181. package/dist/chunk-XDMXXC4Z.cjs +0 -3100
  182. package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
  183. package/dist/controller-pePCJLT1.d.cts +0 -959
  184. package/dist/controller-pePCJLT1.d.ts +0 -959
  185. package/dist/index-CCr_z9kF.d.cts +0 -899
  186. package/dist/index-Ck6ajwXh.d.ts +0 -899
  187. /package/dist/{chunk-JJDLPEWL.js.map → chunk-QGYDWPRM.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;// src/extensions/comment-store.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;// src/extensions/comment-store.ts
2
2
  var idCounter = 0;
3
3
  function createReviewId(prefix = "c") {
4
4
  idCounter = (idCounter + 1) % 1e6;
@@ -264,6 +264,7 @@ var INSERTION_MARK_NAME = "insertion";
264
264
  var DELETION_MARK_NAME = "deletion";
265
265
  var FORMAT_CHANGE_MARK_NAME = "formatChange";
266
266
  var BLOCK_CHANGE_ATTRIBUTE = "blockChange";
267
+ var MOVE_ID_ATTRIBUTE = "moveId";
267
268
  var REVIEW_MARK_NAMES = /* @__PURE__ */ new Set([
268
269
  INSERTION_MARK_NAME,
269
270
  DELETION_MARK_NAME,
@@ -337,6 +338,15 @@ var sharedAttributes = () => ({
337
338
  renderHTML: (attrs) => ({ "data-created-at": String(attrs.createdAt) })
338
339
  }
339
340
  });
341
+ var moveAttribute = () => ({
342
+ [MOVE_ID_ATTRIBUTE]: {
343
+ default: null,
344
+ parseHTML: (el) => el.getAttribute("data-move-id"),
345
+ renderHTML: (attrs) => attrs[MOVE_ID_ATTRIBUTE] ? { "data-move-id": attrs[MOVE_ID_ATTRIBUTE] } : {}
346
+ }
347
+ });
348
+ var MOVE_TO_CLASS = "pixerate-move-to underline decoration-double decoration-emerald-600 text-emerald-700 dark:text-emerald-400";
349
+ var MOVE_FROM_CLASS = "pixerate-move-from line-through decoration-double decoration-emerald-600 text-emerald-700 dark:text-emerald-400";
340
350
  var TrackedInsertion = _core.Mark.create({
341
351
  name: INSERTION_MARK_NAME,
342
352
  inclusive: false,
@@ -344,20 +354,22 @@ var TrackedInsertion = _core.Mark.create({
344
354
  return {
345
355
  HTMLAttributes: {
346
356
  class: "pixerate-insertion underline decoration-emerald-500 text-emerald-700 dark:text-emerald-400"
347
- }
357
+ },
358
+ moveHTMLAttributes: { class: MOVE_TO_CLASS }
348
359
  };
349
360
  },
350
361
  addStorage() {
351
362
  return { markdown: { serialize: { open: "", close: "" }, parse: {} } };
352
363
  },
353
- addAttributes: sharedAttributes,
364
+ addAttributes: () => ({ ...sharedAttributes(), ...moveAttribute() }),
354
365
  parseHTML() {
355
366
  return [{ tag: 'ins[data-change-type="insertion"]', priority: 100 }];
356
367
  },
357
- renderHTML({ HTMLAttributes }) {
368
+ renderHTML({ mark, HTMLAttributes }) {
369
+ const base = mark.attrs[MOVE_ID_ATTRIBUTE] ? this.options.moveHTMLAttributes : this.options.HTMLAttributes;
358
370
  return [
359
371
  "ins",
360
- _core.mergeAttributes.call(void 0, this.options.HTMLAttributes, HTMLAttributes, {
372
+ _core.mergeAttributes.call(void 0, base, HTMLAttributes, {
361
373
  "data-change-type": "insertion"
362
374
  }),
363
375
  0
@@ -371,7 +383,8 @@ var TrackedDeletion = _core.Mark.create({
371
383
  return {
372
384
  HTMLAttributes: {
373
385
  class: "pixerate-deletion line-through decoration-red-500 text-red-600 dark:text-red-400"
374
- }
386
+ },
387
+ moveHTMLAttributes: { class: MOVE_FROM_CLASS }
375
388
  };
376
389
  },
377
390
  addStorage() {
@@ -382,14 +395,15 @@ var TrackedDeletion = _core.Mark.create({
382
395
  }
383
396
  };
384
397
  },
385
- addAttributes: sharedAttributes,
398
+ addAttributes: () => ({ ...sharedAttributes(), ...moveAttribute() }),
386
399
  parseHTML() {
387
400
  return [{ tag: 'del[data-change-type="deletion"]', priority: 100 }];
388
401
  },
389
- renderHTML({ HTMLAttributes }) {
402
+ renderHTML({ mark, HTMLAttributes }) {
403
+ const base = mark.attrs[MOVE_ID_ATTRIBUTE] ? this.options.moveHTMLAttributes : this.options.HTMLAttributes;
390
404
  return [
391
405
  "del",
392
- _core.mergeAttributes.call(void 0, this.options.HTMLAttributes, HTMLAttributes, {
406
+ _core.mergeAttributes.call(void 0, base, HTMLAttributes, {
393
407
  "data-change-type": "deletion"
394
408
  }),
395
409
  0
@@ -539,6 +553,8 @@ function describeBlockChange(previous, current, ignoredAttributes = ["id"]) {
539
553
  keys.forEach((key) => {
540
554
  if (key === "textAlign") {
541
555
  parts.push(`Changed alignment to ${humanize(String(_nullishCoalesce(_optionalChain([current, 'access', _8 => _8.attrs, 'optionalAccess', _9 => _9.textAlign]), () => ( "default"))))}`);
556
+ } else if (key === "styleId") {
557
+ parts.push(`Changed style to ${_nullishCoalesce(_optionalChain([current, 'access', _10 => _10.attrs, 'optionalAccess', _11 => _11.styleId]), () => ( "default"))}`);
542
558
  } else {
543
559
  parts.push(`Changed ${humanize(key).toLowerCase()} of ${after}`);
544
560
  }
@@ -559,12 +575,26 @@ function describeBlockChange(previous, current, ignoredAttributes = ["id"]) {
559
575
  }
560
576
  return parts.join("; ") || `Changed ${after}`;
561
577
  }
578
+ function trackedChangeLabel(change) {
579
+ switch (change.type) {
580
+ case "insertion":
581
+ return "Inserted";
582
+ case "deletion":
583
+ return "Deleted";
584
+ case "format":
585
+ return "Formatted";
586
+ case "move":
587
+ return "Moved";
588
+ default:
589
+ return "Changed";
590
+ }
591
+ }
562
592
  function truncate(text, max = 40) {
563
593
  return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
564
594
  }
565
595
  function toDoc(source) {
566
596
  if (!source) return null;
567
- if (_optionalChain([source, 'access', _10 => _10.state, 'optionalAccess', _11 => _11.doc])) return source.state.doc;
597
+ if (_optionalChain([source, 'access', _12 => _12.state, 'optionalAccess', _13 => _13.doc])) return source.state.doc;
568
598
  if (source.doc && typeof source.doc.descendants === "function") return source.doc;
569
599
  if (typeof source.descendants === "function") return source;
570
600
  return null;
@@ -630,9 +660,11 @@ function getTrackedChanges(source) {
630
660
  change.text += text;
631
661
  return change;
632
662
  };
663
+ const blockCounts = /* @__PURE__ */ new Map();
633
664
  doc.descendants((node, pos) => {
634
- const block = _optionalChain([node, 'access', _12 => _12.attrs, 'optionalAccess', _13 => _13[BLOCK_CHANGE_ATTRIBUTE]]);
635
- if (_optionalChain([block, 'optionalAccess', _14 => _14.changeId]) && node.isTextblock) {
665
+ const block = _optionalChain([node, 'access', _14 => _14.attrs, 'optionalAccess', _15 => _15[BLOCK_CHANGE_ATTRIBUTE]]);
666
+ if (_optionalChain([block, 'optionalAccess', _16 => _16.changeId]) && node.isTextblock) {
667
+ blockCounts.set(block.changeId, (_nullishCoalesce(blockCounts.get(block.changeId), () => ( 0))) + 1);
636
668
  const change = add(
637
669
  `block:${block.changeId}`,
638
670
  "block",
@@ -642,7 +674,11 @@ function getTrackedChanges(source) {
642
674
  node.textContent
643
675
  );
644
676
  if (!change.block) {
645
- change.block = { previous: block.previous, current: blockSnapshot(doc, pos) };
677
+ change.block = {
678
+ previous: block.previous,
679
+ current: blockSnapshot(doc, pos),
680
+ ...block.operation ? { operation: block.operation } : {}
681
+ };
646
682
  }
647
683
  }
648
684
  if (!node.isInline) return;
@@ -651,6 +687,20 @@ function getTrackedChanges(source) {
651
687
  if (!isMarkChange(markType)) return;
652
688
  const attrs = changeAttributes(mark);
653
689
  if (!attrs.changeId) return;
690
+ const text = node.isText ? _nullishCoalesce(node.text, () => ( "")) : "";
691
+ const moveId = markType !== FORMAT_CHANGE_MARK_NAME ? attrs[MOVE_ID_ATTRIBUTE] : null;
692
+ if (moveId) {
693
+ const change2 = add(`move:${moveId}`, "move", { ...attrs, changeId: moveId }, pos, pos + node.nodeSize, text);
694
+ if (!change2.move) change2.move = { from: [], to: [], fromText: "", toText: "" };
695
+ const source2 = markType === DELETION_MARK_NAME;
696
+ const list = source2 ? change2.move.from : change2.move.to;
697
+ const last = list[list.length - 1];
698
+ if (last && last.to === pos) last.to = pos + node.nodeSize;
699
+ else list.push({ from: pos, to: pos + node.nodeSize });
700
+ if (source2) change2.move.fromText += text;
701
+ else change2.move.toText += text;
702
+ return;
703
+ }
654
704
  const type = markType === FORMAT_CHANGE_MARK_NAME ? "format" : markType;
655
705
  const change = add(
656
706
  `${type}:${attrs.changeId}`,
@@ -658,7 +708,7 @@ function getTrackedChanges(source) {
658
708
  attrs,
659
709
  pos,
660
710
  pos + node.nodeSize,
661
- node.isText ? _nullishCoalesce(node.text, () => ( "")) : ""
711
+ text
662
712
  );
663
713
  if (type === "format") {
664
714
  const summary = diffFormatting(_nullishCoalesce(mark.attrs.before, () => ( [])), _nullishCoalesce(mark.attrs.after, () => ( [])));
@@ -679,9 +729,23 @@ function getTrackedChanges(source) {
679
729
  case "format":
680
730
  change.description = describeFormatChange(change.format);
681
731
  break;
682
- case "block":
683
- change.description = describeBlockChange(change.block.previous, change.block.current);
732
+ case "move": {
733
+ const move = change.move;
734
+ change.text = move.toText || move.fromText;
735
+ change.description = change.text ? `Moved "${truncate(change.text)}"` : "Moved content";
684
736
  break;
737
+ }
738
+ case "block": {
739
+ const { previous, current, operation } = change.block;
740
+ if (operation) {
741
+ const count = _nullishCoalesce(blockCounts.get(change.id), () => ( 1));
742
+ const verb = operation === "insert" ? "Inserted" : "Deleted";
743
+ change.description = count > 1 ? `${verb} ${count} blocks` : `${verb} ${blockLabel(current.type, current.attrs)}`;
744
+ } else {
745
+ change.description = describeBlockChange(previous, current);
746
+ }
747
+ break;
748
+ }
685
749
  }
686
750
  });
687
751
  return changes.sort((a, b) => a.from - b.from || a.to - b.to);
@@ -698,15 +762,20 @@ function getTrackedChangeAt(state, pos = state.selection.from, changes = getTrac
698
762
  return _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(inline.find((c) => c.ranges.some((r) => r.from < pos && pos < r.to)), () => ( inline.find((c) => c.ranges.some((r) => r.from <= pos && pos <= r.to)))), () => ( blocks.find((c) => c.ranges.some((r) => r.from < pos && pos < r.to)))), () => ( null));
699
763
  }
700
764
  function selectionRange(change) {
701
- return change.type === "block" ? [change.from + 1, change.to - 1] : [change.from, change.to];
765
+ if (change.type === "block") return [change.from + 1, change.to - 1];
766
+ if (change.type === "move" && change.move) {
767
+ const ranges = change.move.to.length ? change.move.to : change.move.from;
768
+ if (ranges.length) return [ranges[0].from, ranges[ranges.length - 1].to];
769
+ }
770
+ return [change.from, change.to];
702
771
  }
703
772
  function isTrackChangesEnabled(source) {
704
- const state = _nullishCoalesce(_optionalChain([source, 'optionalAccess', _15 => _15.state]), () => ( source));
773
+ const state = _nullishCoalesce(_optionalChain([source, 'optionalAccess', _17 => _17.state]), () => ( source));
705
774
  if (!state || typeof state.plugins === "undefined") return false;
706
- return _nullishCoalesce(_optionalChain([trackChangesPluginKey, 'access', _16 => _16.getState, 'call', _17 => _17(state), 'optionalAccess', _18 => _18.enabled]), () => ( false));
775
+ return _nullishCoalesce(_optionalChain([trackChangesPluginKey, 'access', _18 => _18.getState, 'call', _19 => _19(state), 'optionalAccess', _20 => _20.enabled]), () => ( false));
707
776
  }
708
777
  function getTrackChangesStore(editor) {
709
- return _nullishCoalesce(_optionalChain([editor, 'optionalAccess', _19 => _19.storage, 'optionalAccess', _20 => _20.trackChanges, 'optionalAccess', _21 => _21.store]), () => ( null));
778
+ return _nullishCoalesce(_optionalChain([editor, 'optionalAccess', _21 => _21.storage, 'optionalAccess', _22 => _22.trackChanges, 'optionalAccess', _23 => _23.store]), () => ( null));
710
779
  }
711
780
  function marksFromJSON(schema, marks) {
712
781
  const result = [];
@@ -767,7 +836,7 @@ function sinkItem(tr, contentPos) {
767
836
  const itemType = $pos.node(itemDepth).type;
768
837
  if (index === 0 || list.child(index - 1).type !== itemType) return false;
769
838
  const nodeBefore = list.child(index - 1);
770
- const nestedBefore = _optionalChain([nodeBefore, 'access', _22 => _22.lastChild, 'optionalAccess', _23 => _23.type]) === list.type;
839
+ const nestedBefore = _optionalChain([nodeBefore, 'access', _24 => _24.lastChild, 'optionalAccess', _25 => _25.type]) === list.type;
771
840
  const inner = _model.Fragment.from(nestedBefore ? itemType.create() : null);
772
841
  const slice = new (0, _model.Slice)(
773
842
  _model.Fragment.from(itemType.create(null, _model.Fragment.from(list.type.create(null, inner)))),
@@ -868,21 +937,69 @@ function restoreWrappers(tr, contentPos, wrappers) {
868
937
  const wrapper = tr.doc.nodeAt(start);
869
938
  if (!wrapper) return;
870
939
  const end = start + wrapper.nodeSize;
871
- if (_optionalChain([tr, 'access', _24 => _24.doc, 'access', _25 => _25.resolve, 'call', _26 => _26(end), 'access', _27 => _27.nodeAfter, 'optionalAccess', _28 => _28.type]) === wrapper.type && _transform.canJoin.call(void 0, tr.doc, end)) {
940
+ if (_optionalChain([tr, 'access', _26 => _26.doc, 'access', _27 => _27.resolve, 'call', _28 => _28(end), 'access', _29 => _29.nodeAfter, 'optionalAccess', _30 => _30.type]) === wrapper.type && _transform.canJoin.call(void 0, tr.doc, end)) {
872
941
  step(() => tr.join(end));
873
942
  }
874
- if (_optionalChain([tr, 'access', _29 => _29.doc, 'access', _30 => _30.resolve, 'call', _31 => _31(start), 'access', _32 => _32.nodeBefore, 'optionalAccess', _33 => _33.type]) === wrapper.type && _transform.canJoin.call(void 0, tr.doc, start)) {
943
+ if (_optionalChain([tr, 'access', _31 => _31.doc, 'access', _32 => _32.resolve, 'call', _33 => _33(start), 'access', _34 => _34.nodeBefore, 'optionalAccess', _35 => _35.type]) === wrapper.type && _transform.canJoin.call(void 0, tr.doc, start)) {
875
944
  step(() => tr.join(start));
876
945
  }
877
946
  return;
878
947
  }
879
948
  }
949
+ function removeBlocks(tr, ids, decision) {
950
+ const removed = decision === "accept" ? "delete" : "insert";
951
+ const memo = /* @__PURE__ */ new Map();
952
+ const removable = (node) => {
953
+ const cached = memo.get(node);
954
+ if (cached !== void 0) return cached;
955
+ let result;
956
+ if (node.isTextblock) {
957
+ const record = _optionalChain([node, 'access', _36 => _36.attrs, 'optionalAccess', _37 => _37[BLOCK_CHANGE_ATTRIBUTE]]);
958
+ result = !!_optionalChain([record, 'optionalAccess', _38 => _38.changeId]) && record.operation === removed && ids.has(record.changeId);
959
+ } else if (node.isLeaf || node.childCount === 0) {
960
+ result = false;
961
+ } else {
962
+ result = true;
963
+ for (let i = 0; i < node.childCount && result; i++) result = removable(node.child(i));
964
+ }
965
+ memo.set(node, result);
966
+ return result;
967
+ };
968
+ const doc = tr.doc;
969
+ if (removable(doc)) {
970
+ const filler = _optionalChain([doc, 'access', _39 => _39.type, 'access', _40 => _40.contentMatch, 'access', _41 => _41.defaultType, 'optionalAccess', _42 => _42.createAndFill, 'call', _43 => _43()]);
971
+ if (filler) tr.replaceWith(0, doc.content.size, filler);
972
+ return;
973
+ }
974
+ const ranges = [];
975
+ const visit = (node, contentStart) => {
976
+ node.forEach((child, offset) => {
977
+ const from = contentStart + offset;
978
+ if (removable(child)) {
979
+ ranges.push({ from, to: from + child.nodeSize });
980
+ } else if (!child.isTextblock && !child.isLeaf) {
981
+ visit(child, from + 1);
982
+ }
983
+ });
984
+ };
985
+ visit(doc, 0);
986
+ if (ranges.length === 0) return;
987
+ const startIndex = tr.steps.length;
988
+ ranges.reverse().forEach(({ from, to }) => {
989
+ const mapping = tr.mapping.slice(startIndex);
990
+ try {
991
+ tr.delete(mapping.map(from, 1), mapping.map(to, -1));
992
+ } catch (e4) {
993
+ }
994
+ });
995
+ }
880
996
  function decideBlocks(tr, changes, decision) {
881
997
  const ids = new Set(changes.map((c) => c.id));
998
+ removeBlocks(tr, ids, decision);
882
999
  const items = [];
883
1000
  tr.doc.descendants((node, pos) => {
884
- const record = _optionalChain([node, 'access', _34 => _34.attrs, 'optionalAccess', _35 => _35[BLOCK_CHANGE_ATTRIBUTE]]);
885
- if (node.isTextblock && _optionalChain([record, 'optionalAccess', _36 => _36.changeId]) && ids.has(record.changeId)) {
1001
+ const record = _optionalChain([node, 'access', _44 => _44.attrs, 'optionalAccess', _45 => _45[BLOCK_CHANGE_ATTRIBUTE]]);
1002
+ if (node.isTextblock && _optionalChain([record, 'optionalAccess', _46 => _46.changeId]) && ids.has(record.changeId)) {
886
1003
  items.push({ contentPos: pos + 1, record });
887
1004
  }
888
1005
  return !node.isTextblock;
@@ -894,7 +1011,7 @@ function decideBlocks(tr, changes, decision) {
894
1011
  const $pos = tr.doc.resolve(contentPos);
895
1012
  if (!$pos.parent.isTextblock || $pos.parentOffset !== 0) return;
896
1013
  const pos = $pos.before();
897
- if (decision === "accept") {
1014
+ if (decision === "accept" || record.operation) {
898
1015
  tr.setNodeAttribute(pos, BLOCK_CHANGE_ATTRIBUTE, null);
899
1016
  return;
900
1017
  }
@@ -907,25 +1024,49 @@ function decideBlocks(tr, changes, decision) {
907
1024
  const attrs = { ...previous.attrs, [BLOCK_CHANGE_ATTRIBUTE]: null };
908
1025
  try {
909
1026
  tr.setNodeMarkup(pos, type, attrs);
910
- } catch (e4) {
1027
+ } catch (e5) {
911
1028
  try {
912
1029
  tr.setBlockType(pos + 1, pos + 1, type, attrs);
913
- } catch (e5) {
1030
+ } catch (e6) {
914
1031
  tr.setNodeAttribute(pos, BLOCK_CHANGE_ATTRIBUTE, null);
915
1032
  }
916
1033
  }
917
1034
  try {
918
1035
  restoreWrappers(tr, tr.mapping.slice(startIndex).map(original), _nullishCoalesce(previous.wrappers, () => ( [])));
919
- } catch (e6) {
1036
+ } catch (e7) {
920
1037
  }
921
1038
  });
922
1039
  }
1040
+ function deleteWholeBlock(tr, from, to) {
1041
+ const $from = tr.doc.resolve(from);
1042
+ const block = $from.parent;
1043
+ if ($from.depth !== 1 || !block.isTextblock || from !== $from.start() || to !== $from.end() || tr.doc.childCount < 2) {
1044
+ return false;
1045
+ }
1046
+ try {
1047
+ tr.delete($from.before(), $from.after());
1048
+ return true;
1049
+ } catch (e8) {
1050
+ return false;
1051
+ }
1052
+ }
923
1053
  function applyDecision(tr, changes, decision) {
924
1054
  const schema = tr.doc.type.schema;
925
1055
  const format = changes.filter((c) => c.type === "format");
926
1056
  if (format.length) decideFormat(tr, format, decision);
927
1057
  const deletions = [];
928
1058
  changes.forEach((change) => {
1059
+ if (change.type === "move" && change.move) {
1060
+ const accept = decision === "accept";
1061
+ const keepType = schema.marks[accept ? INSERTION_MARK_NAME : DELETION_MARK_NAME];
1062
+ (accept ? change.move.to : change.move.from).forEach(({ from, to }) => {
1063
+ if (keepType) tr.removeMark(from, to, keepType);
1064
+ });
1065
+ (accept ? change.move.from : change.move.to).forEach(
1066
+ ({ from, to }) => deletions.push({ from, to, wholeBlocks: true })
1067
+ );
1068
+ return;
1069
+ }
929
1070
  if (change.type !== "insertion" && change.type !== "deletion") return;
930
1071
  const markType = schema.marks[change.type];
931
1072
  if (!markType) return;
@@ -938,8 +1079,11 @@ function applyDecision(tr, changes, decision) {
938
1079
  }
939
1080
  });
940
1081
  });
941
- deletions.sort((a, b) => b.from - a.from).forEach(({ from, to }) => {
942
- tr.delete(tr.mapping.map(from), tr.mapping.map(to));
1082
+ deletions.sort((a, b) => b.from - a.from).forEach(({ from, to, wholeBlocks }) => {
1083
+ const start = tr.mapping.map(from);
1084
+ const end = tr.mapping.map(to);
1085
+ if (wholeBlocks && deleteWholeBlock(tr, start, end)) return;
1086
+ tr.delete(start, end);
943
1087
  });
944
1088
  const blocks = changes.filter((c) => c.type === "block");
945
1089
  if (blocks.length) decideBlocks(tr, blocks, decision);
@@ -974,7 +1118,7 @@ function acceptSlice(slice, schema) {
974
1118
  if (insertion) marks = insertion.removeFromSet(marks);
975
1119
  if (format) marks = format.removeFromSet(marks);
976
1120
  children.push(marks === child.marks ? child : child.mark(marks));
977
- } else if (_optionalChain([child, 'access', _37 => _37.attrs, 'optionalAccess', _38 => _38[BLOCK_CHANGE_ATTRIBUTE]])) {
1121
+ } else if (_optionalChain([child, 'access', _47 => _47.attrs, 'optionalAccess', _48 => _48[BLOCK_CHANGE_ATTRIBUTE]])) {
978
1122
  children.push(
979
1123
  child.type.create(
980
1124
  { ...child.attrs, [BLOCK_CHANGE_ATTRIBUTE]: null },
@@ -997,6 +1141,52 @@ function stripMarks(fragment) {
997
1141
  });
998
1142
  return _model.Fragment.fromArray(children);
999
1143
  }
1144
+ var SENTENCE_END = /[.!?…]$/;
1145
+ var TRAILING_CLOSERS = /["'”’)]+$/;
1146
+ var TRAILING_SPACES = /[  ]+$/;
1147
+ function isMoveSized(text) {
1148
+ const trimmed = text.replace(TRAILING_SPACES, "");
1149
+ if (trimmed.includes("\n")) return true;
1150
+ const sentence = trimmed.replace(TRAILING_CLOSERS, "");
1151
+ return SENTENCE_END.test(sentence) && sentence.trim().split(/\s+/).length >= 2;
1152
+ }
1153
+ var normalizeMoveText = (text) => text.replace(/\s+/g, "");
1154
+ function deletedText(slice, ctx) {
1155
+ let text = "";
1156
+ let blocks = 0;
1157
+ slice.content.descendants((node) => {
1158
+ if (node.isTextblock) {
1159
+ if (blocks++ > 0) text += "\n";
1160
+ return true;
1161
+ }
1162
+ if (!node.isText) return true;
1163
+ const insertion = ctx.insertion.isInSet(node.marks);
1164
+ if (insertion && insertion.attrs.authorId === ctx.author.id) return false;
1165
+ if (ctx.deletion.isInSet(node.marks)) return false;
1166
+ text += _nullishCoalesce(node.text, () => ( ""));
1167
+ return false;
1168
+ });
1169
+ return text;
1170
+ }
1171
+ var rangeText = (doc, from, to) => doc.textBetween(from, to, "\n", "");
1172
+ function linkMoveSource(tr, pending, ctx) {
1173
+ const segments = [];
1174
+ tr.doc.descendants((node, pos) => {
1175
+ if (!node.isInline) return true;
1176
+ const mark = ctx.deletion.isInSet(node.marks);
1177
+ if (mark && mark.attrs.changeId === pending.id && !mark.attrs[MOVE_ID_ATTRIBUTE]) {
1178
+ segments.push({ from: pos, to: pos + node.nodeSize, mark });
1179
+ }
1180
+ return false;
1181
+ });
1182
+ if (segments.length === 0) return false;
1183
+ const text = segments.map((s) => rangeText(tr.doc, s.from, s.to)).join("");
1184
+ if (normalizeMoveText(text) !== pending.text) return false;
1185
+ segments.forEach(
1186
+ ({ from, to, mark }) => tr.addMark(from, to, ctx.deletion.create({ ...mark.attrs, [MOVE_ID_ATTRIBUTE]: pending.id }))
1187
+ );
1188
+ return true;
1189
+ }
1000
1190
  function newAttributes(ctx) {
1001
1191
  return {
1002
1192
  changeId: ctx.generateId(),
@@ -1019,7 +1209,7 @@ function adjacentAttributes(doc, from, to, type, ctx) {
1019
1209
  const candidates = [doc.resolve(from).nodeBefore, doc.resolve(to).nodeAfter];
1020
1210
  for (const node of candidates) {
1021
1211
  const mark = node && type.isInSet(node.marks);
1022
- if (mark && mark.attrs.authorId === ctx.author.id && mark.attrs.changeId) {
1212
+ if (mark && mark.attrs.authorId === ctx.author.id && mark.attrs.changeId && !mark.attrs[MOVE_ID_ATTRIBUTE]) {
1023
1213
  return changeAttributes(mark);
1024
1214
  }
1025
1215
  }
@@ -1148,7 +1338,8 @@ function trackBlocks(tr, pending, ctx) {
1148
1338
  if (!node.isTextblock || $pos.parentOffset !== 0 || $pos.depth === 0) return;
1149
1339
  if (!node.type.spec.attrs || !(BLOCK_CHANGE_ATTRIBUTE in node.type.spec.attrs)) return;
1150
1340
  const pos = $pos.before();
1151
- const original = _nullishCoalesce(_optionalChain([existing, 'optionalAccess', _39 => _39.previous]), () => ( previous));
1341
+ if (_optionalChain([existing, 'optionalAccess', _49 => _49.operation]) || _optionalChain([node, 'access', _50 => _50.attrs, 'access', _51 => _51[BLOCK_CHANGE_ATTRIBUTE], 'optionalAccess', _52 => _52.operation])) return;
1342
+ const original = _nullishCoalesce(_optionalChain([existing, 'optionalAccess', _53 => _53.previous]), () => ( previous));
1152
1343
  const current = blockSnapshot(tr.doc, pos);
1153
1344
  if (sameBlock(original, current, ctx.ignoredAttributes)) {
1154
1345
  if (node.attrs[BLOCK_CHANGE_ATTRIBUTE]) {
@@ -1180,7 +1371,7 @@ function collectBlockChanges(step, docBefore, docAfter, rest, pending, ctx) {
1180
1371
  };
1181
1372
  if (step instanceof _transform.AttrStep) {
1182
1373
  const node = docBefore.nodeAt(step.pos);
1183
- if (_optionalChain([node, 'optionalAccess', _40 => _40.isTextblock]) && step.attr !== BLOCK_CHANGE_ATTRIBUTE && !ctx.ignoredAttributes.has(step.attr)) {
1374
+ if (_optionalChain([node, 'optionalAccess', _54 => _54.isTextblock]) && step.attr !== BLOCK_CHANGE_ATTRIBUTE && !ctx.ignoredAttributes.has(step.attr)) {
1184
1375
  record(step.pos, step.pos);
1185
1376
  }
1186
1377
  return;
@@ -1275,24 +1466,57 @@ function trackTransactions(transactions, oldState, newState, ctx) {
1275
1466
  if (blocks.size) {
1276
1467
  changed = trackBlocks(tr, blocks, ctx) || changed;
1277
1468
  }
1469
+ const moves = ctx.moves;
1470
+ let insertAttrs = null;
1471
+ let deleteAttrs = null;
1472
+ const moveAttrs = (id) => ({
1473
+ changeId: id,
1474
+ authorId: ctx.author.id,
1475
+ authorName: ctx.author.name,
1476
+ authorColor: _nullishCoalesce(ctx.author.color, () => ( null)),
1477
+ createdAt: ctx.now(),
1478
+ [MOVE_ID_ATTRIBUTE]: id
1479
+ });
1480
+ if (moves && inserted.length) {
1481
+ const insertedText = normalizeMoveText(
1482
+ inserted.map((r) => rangeText(tr.doc, r.from, r.to)).join("")
1483
+ );
1484
+ const pending = moves.pending;
1485
+ if (moves.event === "paste" && pending && pending.authorId === ctx.author.id && insertedText === pending.text && linkMoveSource(tr, pending, ctx)) {
1486
+ insertAttrs = moveAttrs(pending.id);
1487
+ } else if (moves.event === "drop" && restores.length) {
1488
+ const raw = restores.map((r) => deletedText(r.slice, ctx)).join("\n");
1489
+ if (insertedText && normalizeMoveText(raw) === insertedText && moves.isMove(raw)) {
1490
+ insertAttrs = deleteAttrs = moveAttrs(ctx.generateId());
1491
+ }
1492
+ }
1493
+ }
1494
+ if (_optionalChain([moves, 'optionalAccess', _55 => _55.event]) === "cut" && restores.length) {
1495
+ deleteAttrs = newAttributes(ctx);
1496
+ const raw = restores.map((r) => deletedText(r.slice, ctx)).join("\n");
1497
+ if (normalizeMoveText(raw) && moves.isMove(raw)) {
1498
+ moves.cut = { id: deleteAttrs.changeId, text: normalizeMoveText(raw), authorId: ctx.author.id };
1499
+ }
1500
+ }
1278
1501
  inserted.forEach(({ from, to }) => {
1279
1502
  tr.removeMark(from, to, ctx.deletion);
1280
1503
  tr.removeMark(from, to, ctx.insertion);
1281
1504
  if (ctx.format) tr.removeMark(from, to, ctx.format);
1282
- const attrs = _nullishCoalesce(adjacentAttributes(tr.doc, from, to, ctx.insertion, ctx), () => ( newAttributes(ctx)));
1505
+ const attrs = _nullishCoalesce(_nullishCoalesce(insertAttrs, () => ( adjacentAttributes(tr.doc, from, to, ctx.insertion, ctx))), () => ( newAttributes(ctx)));
1283
1506
  tr.addMark(from, to, ctx.insertion.create(attrs));
1284
1507
  changed = true;
1285
1508
  });
1509
+ if (insertAttrs) changed = true;
1286
1510
  let cursor = null;
1287
1511
  restores.sort((a, b) => b.pos - a.pos).forEach((restore) => {
1288
1512
  const pos = tr.mapping.map(restore.pos, -1);
1289
- const attrs = _nullishCoalesce(adjacentAttributes(tr.doc, pos, pos, ctx.deletion, ctx), () => ( newAttributes(ctx)));
1513
+ const attrs = _nullishCoalesce(_nullishCoalesce(deleteAttrs, () => ( adjacentAttributes(tr.doc, pos, pos, ctx.deletion, ctx))), () => ( newAttributes(ctx)));
1290
1514
  const marked = markDeletedSlice(restore.slice, restore.parentType, attrs, ctx);
1291
1515
  if (!marked || !marked.hasContent) return;
1292
1516
  const sizeBefore = tr.doc.content.size;
1293
1517
  try {
1294
1518
  tr.replace(pos, pos, marked.slice);
1295
- } catch (e7) {
1519
+ } catch (e9) {
1296
1520
  return;
1297
1521
  }
1298
1522
  changed = true;
@@ -1304,7 +1528,7 @@ function trackTransactions(transactions, oldState, newState, ctx) {
1304
1528
  if (cursor !== null) {
1305
1529
  try {
1306
1530
  tr.setSelection(_state.TextSelection.create(tr.doc, cursor));
1307
- } catch (e8) {
1531
+ } catch (e10) {
1308
1532
  }
1309
1533
  }
1310
1534
  tr.setMeta(TRACK_CHANGES_SKIP_META, true);
@@ -1314,10 +1538,10 @@ function buildSnapshot(state, author) {
1314
1538
  const plugin = trackChangesPluginKey.getState(state);
1315
1539
  const changes = getTrackedChanges(state.doc);
1316
1540
  return {
1317
- enabled: _nullishCoalesce(_optionalChain([plugin, 'optionalAccess', _41 => _41.enabled]), () => ( false)),
1318
- author: _nullishCoalesce(_optionalChain([plugin, 'optionalAccess', _42 => _42.author]), () => ( author)),
1541
+ enabled: _nullishCoalesce(_optionalChain([plugin, 'optionalAccess', _56 => _56.enabled]), () => ( false)),
1542
+ author: _nullishCoalesce(_optionalChain([plugin, 'optionalAccess', _57 => _57.author]), () => ( author)),
1319
1543
  changes,
1320
- currentChangeId: _nullishCoalesce(_optionalChain([getTrackedChangeAt, 'call', _43 => _43(state, state.selection.from, changes), 'optionalAccess', _44 => _44.id]), () => ( null))
1544
+ currentChangeId: _nullishCoalesce(_optionalChain([getTrackedChangeAt, 'call', _58 => _58(state, state.selection.from, changes), 'optionalAccess', _59 => _59.id]), () => ( null))
1321
1545
  };
1322
1546
  }
1323
1547
  function allowTrackingInCodeBlocks(schema) {
@@ -1345,12 +1569,17 @@ var TrackChanges = _core.Extension.create({
1345
1569
  deletionHTMLAttributes: {},
1346
1570
  formatChangeHTMLAttributes: {},
1347
1571
  blockChangeClass: "pixerate-block-change border-l-2 border-amber-400 pl-2 dark:border-amber-500",
1572
+ blockInsertedClass: "pixerate-block-inserted underline decoration-emerald-500 text-emerald-700 dark:text-emerald-400",
1573
+ blockDeletedClass: "pixerate-block-deleted line-through decoration-red-500 text-red-600 dark:text-red-400",
1348
1574
  trackFormatting: true,
1349
1575
  trackBlocks: true,
1350
1576
  trackCodeBlocks: true,
1351
1577
  blockTypes: ["paragraph", "heading", "codeBlock"],
1352
1578
  ignoredMarks: [],
1353
- ignoredBlockAttributes: ["id"]
1579
+ ignoredBlockAttributes: ["id"],
1580
+ trackMoves: true,
1581
+ isMove: isMoveSized,
1582
+ moveHTMLAttributes: {}
1354
1583
  };
1355
1584
  },
1356
1585
  addStorage() {
@@ -1364,11 +1593,13 @@ var TrackChanges = _core.Extension.create({
1364
1593
  };
1365
1594
  },
1366
1595
  addGlobalAttributes() {
1367
- if (_optionalChain([this, 'access', _45 => _45.options, 'optionalAccess', _46 => _46.trackBlocks]) === false) return [];
1368
- const blockClass = _nullishCoalesce(_optionalChain([this, 'access', _47 => _47.options, 'optionalAccess', _48 => _48.blockChangeClass]), () => ( ""));
1596
+ if (_optionalChain([this, 'access', _60 => _60.options, 'optionalAccess', _61 => _61.trackBlocks]) === false) return [];
1597
+ const blockClass = _nullishCoalesce(_optionalChain([this, 'access', _62 => _62.options, 'optionalAccess', _63 => _63.blockChangeClass]), () => ( ""));
1598
+ const insertedClass = _nullishCoalesce(_optionalChain([this, 'access', _64 => _64.options, 'optionalAccess', _65 => _65.blockInsertedClass]), () => ( ""));
1599
+ const deletedClass = _nullishCoalesce(_optionalChain([this, 'access', _66 => _66.options, 'optionalAccess', _67 => _67.blockDeletedClass]), () => ( ""));
1369
1600
  return [
1370
1601
  {
1371
- types: _nullishCoalesce(_optionalChain([this, 'access', _49 => _49.options, 'optionalAccess', _50 => _50.blockTypes]), () => ( ["paragraph", "heading", "codeBlock"])),
1602
+ types: _nullishCoalesce(_optionalChain([this, 'access', _68 => _68.options, 'optionalAccess', _69 => _69.blockTypes]), () => ( ["paragraph", "heading", "codeBlock"])),
1372
1603
  attributes: {
1373
1604
  [BLOCK_CHANGE_ATTRIBUTE]: {
1374
1605
  default: null,
@@ -1377,9 +1608,13 @@ var TrackChanges = _core.Extension.create({
1377
1608
  renderHTML: (attrs) => {
1378
1609
  const value = attrs[BLOCK_CHANGE_ATTRIBUTE];
1379
1610
  if (!value) return {};
1611
+ const operation = value.operation;
1612
+ const extra = operation === "insert" ? insertedClass : operation === "delete" ? deletedClass : "";
1613
+ const className = [blockClass, extra].filter(Boolean).join(" ");
1380
1614
  return {
1381
1615
  "data-block-change": JSON.stringify(value),
1382
- ...blockClass ? { class: blockClass } : {}
1616
+ ...operation ? { "data-block-operation": operation } : {},
1617
+ ...className ? { class: className } : {}
1383
1618
  };
1384
1619
  }
1385
1620
  }
@@ -1388,12 +1623,21 @@ var TrackChanges = _core.Extension.create({
1388
1623
  ];
1389
1624
  },
1390
1625
  addExtensions() {
1391
- const insertionAttrs = _nullishCoalesce(_optionalChain([this, 'access', _51 => _51.options, 'optionalAccess', _52 => _52.insertionHTMLAttributes]), () => ( {}));
1392
- const deletionAttrs = _nullishCoalesce(_optionalChain([this, 'access', _53 => _53.options, 'optionalAccess', _54 => _54.deletionHTMLAttributes]), () => ( {}));
1393
- const formatAttrs = _nullishCoalesce(_optionalChain([this, 'access', _55 => _55.options, 'optionalAccess', _56 => _56.formatChangeHTMLAttributes]), () => ( {}));
1626
+ const insertionAttrs = _nullishCoalesce(_optionalChain([this, 'access', _70 => _70.options, 'optionalAccess', _71 => _71.insertionHTMLAttributes]), () => ( {}));
1627
+ const deletionAttrs = _nullishCoalesce(_optionalChain([this, 'access', _72 => _72.options, 'optionalAccess', _73 => _73.deletionHTMLAttributes]), () => ( {}));
1628
+ const formatAttrs = _nullishCoalesce(_optionalChain([this, 'access', _74 => _74.options, 'optionalAccess', _75 => _75.formatChangeHTMLAttributes]), () => ( {}));
1629
+ const moveAttrs = _nullishCoalesce(_optionalChain([this, 'access', _76 => _76.options, 'optionalAccess', _77 => _77.moveHTMLAttributes]), () => ( {}));
1630
+ const markOptions = (attrs) => ({
1631
+ ...Object.keys(attrs).length ? { HTMLAttributes: attrs } : {},
1632
+ ...Object.keys(moveAttrs).length ? { moveHTMLAttributes: moveAttrs } : {}
1633
+ });
1634
+ const configured = (mark, attrs) => {
1635
+ const options = markOptions(attrs);
1636
+ return Object.keys(options).length ? mark.configure(options) : mark;
1637
+ };
1394
1638
  return [
1395
- Object.keys(insertionAttrs).length ? TrackedInsertion.configure({ HTMLAttributes: insertionAttrs }) : TrackedInsertion,
1396
- Object.keys(deletionAttrs).length ? TrackedDeletion.configure({ HTMLAttributes: deletionAttrs }) : TrackedDeletion,
1639
+ configured(TrackedInsertion, insertionAttrs),
1640
+ configured(TrackedDeletion, deletionAttrs),
1397
1641
  Object.keys(formatAttrs).length ? TrackedFormatChange.configure({ HTMLAttributes: formatAttrs }) : TrackedFormatChange
1398
1642
  ];
1399
1643
  },
@@ -1401,9 +1645,9 @@ var TrackChanges = _core.Extension.create({
1401
1645
  if (this.options.trackCodeBlocks) allowTrackingInCodeBlocks(this.editor.schema);
1402
1646
  },
1403
1647
  addCommands() {
1404
- const decide = (decision, id) => ({ state, tr, dispatch }) => {
1648
+ const decide = (decision, id, onlyMoves = false) => ({ state, tr, dispatch }) => {
1405
1649
  const all = getTrackedChanges(state.doc);
1406
- const changes = id === null ? all : all.filter((c) => c.id === id);
1650
+ const changes = id === null ? all : all.filter((c) => c.id === id && (!onlyMoves || c.type === "move"));
1407
1651
  if (changes.length === 0) return false;
1408
1652
  if (dispatch) {
1409
1653
  applyDecision(tr, changes, decision);
@@ -1440,11 +1684,22 @@ var TrackChanges = _core.Extension.create({
1440
1684
  return true;
1441
1685
  },
1442
1686
  acceptChange: (id) => decide("accept", id),
1687
+ acceptMove: (id) => decide("accept", id, true),
1688
+ rejectMove: (id) => decide("reject", id, true),
1443
1689
  rejectChange: (id) => decide("reject", id),
1444
1690
  acceptAllChanges: () => decide("accept", null),
1445
1691
  rejectAllChanges: () => decide("reject", null),
1446
1692
  selectNextChange: () => select(1),
1447
- selectPreviousChange: () => select(-1)
1693
+ selectPreviousChange: () => select(-1),
1694
+ selectChange: (id) => ({ state, tr, dispatch }) => {
1695
+ const change = getTrackedChanges(state.doc).find((c) => c.id === id);
1696
+ if (!change) return false;
1697
+ if (dispatch) {
1698
+ const [anchor, head] = selectionRange(change);
1699
+ tr.setSelection(_state.TextSelection.create(tr.doc, anchor, head)).scrollIntoView();
1700
+ }
1701
+ return true;
1702
+ }
1448
1703
  };
1449
1704
  },
1450
1705
  addProseMirrorPlugins() {
@@ -1455,6 +1710,8 @@ var TrackChanges = _core.Extension.create({
1455
1710
  let editorView = null;
1456
1711
  let pending = null;
1457
1712
  let flushTimer = null;
1713
+ let pendingMove = null;
1714
+ const isMove = _nullishCoalesce(options.isMove, () => ( isMoveSized));
1458
1715
  const scheduleFlush = () => {
1459
1716
  if (flushTimer) clearTimeout(flushTimer);
1460
1717
  flushTimer = setTimeout(() => {
@@ -1484,9 +1741,12 @@ var TrackChanges = _core.Extension.create({
1484
1741
  },
1485
1742
  appendTransaction: (transactions, oldState, newState) => {
1486
1743
  const plugin = trackChangesPluginKey.getState(oldState);
1487
- const tracking = !!_optionalChain([plugin, 'optionalAccess', _57 => _57.enabled]);
1488
- if (!tracking && !pending) return null;
1489
- if (_optionalChain([editorView, 'optionalAccess', _58 => _58.composing]) && transactions.some((t) => t.docChanged)) {
1744
+ const tracking = !!_optionalChain([plugin, 'optionalAccess', _78 => _78.enabled]);
1745
+ if (!tracking && !pending) {
1746
+ if (transactions.some((t) => t.docChanged)) pendingMove = null;
1747
+ return null;
1748
+ }
1749
+ if (_optionalChain([editorView, 'optionalAccess', _79 => _79.composing]) && transactions.some((t) => t.docChanged)) {
1490
1750
  if (tracking) {
1491
1751
  if (!pending) pending = { oldState, transactions: [] };
1492
1752
  pending.transactions.push(...transactions);
@@ -1501,8 +1761,18 @@ var TrackChanges = _core.Extension.create({
1501
1761
  pending = null;
1502
1762
  }
1503
1763
  if (!tracking && trs === transactions) return null;
1504
- const author = _nullishCoalesce(_optionalChain([plugin, 'optionalAccess', _59 => _59.author]), () => ( options.author));
1505
- return trackTransactions(trs, fromState, newState, {
1764
+ const author = _nullishCoalesce(_optionalChain([plugin, 'optionalAccess', _80 => _80.author]), () => ( options.author));
1765
+ const userTransactions = trs.filter((t) => !shouldSkip(t));
1766
+ let moves;
1767
+ if (userTransactions.length) {
1768
+ const uiEvent = userTransactions.length === 1 ? userTransactions[0].getMeta("uiEvent") : null;
1769
+ const event = uiEvent === "cut" || uiEvent === "paste" || uiEvent === "drop" ? uiEvent : null;
1770
+ if (options.trackMoves !== false) {
1771
+ moves = { event, pending: event === "paste" ? pendingMove : null, isMove };
1772
+ }
1773
+ pendingMove = null;
1774
+ }
1775
+ const result = trackTransactions(trs, fromState, newState, {
1506
1776
  author,
1507
1777
  now: options.now,
1508
1778
  generateId: options.generateId,
@@ -1511,8 +1781,11 @@ var TrackChanges = _core.Extension.create({
1511
1781
  format: options.trackFormatting !== false ? newState.schema.marks[FORMAT_CHANGE_MARK_NAME] : void 0,
1512
1782
  trackBlocks: options.trackBlocks !== false,
1513
1783
  ignoredMarks,
1514
- ignoredAttributes
1784
+ ignoredAttributes,
1785
+ moves
1515
1786
  });
1787
+ if (_optionalChain([moves, 'optionalAccess', _81 => _81.cut])) pendingMove = moves.cut;
1788
+ return result;
1516
1789
  },
1517
1790
  props: {
1518
1791
  transformPasted: (slice, view) => acceptSlice(slice, view.state.schema),
@@ -1545,551 +1818,6 @@ var TrackChanges = _core.Extension.create({
1545
1818
  }
1546
1819
  });
1547
1820
 
1548
- // src/serializers/plain-text.ts
1549
-
1550
- var TRACKED_DELETION_REGEX = /<del\b(?=[^>]*\bdata-change-type=["']deletion["'])[^>]*>[\s\S]*?<\/del>/gi;
1551
- var TRACKED_INSERTION_REGEX = /<ins\b(?=[^>]*\bdata-change-type=["']insertion["'])[^>]*>[\s\S]*?<\/ins>/gi;
1552
- function stripTrackedChanges(html, view) {
1553
- if (view === "all" || !html.includes("data-change-type")) return html;
1554
- return html.replace(
1555
- view === "accepted" ? TRACKED_DELETION_REGEX : TRACKED_INSERTION_REGEX,
1556
- ""
1557
- );
1558
- }
1559
- function escapeHtml(text) {
1560
- if (!text) return "";
1561
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1562
- }
1563
- var PARAGRAPH_HTML_REGEX = /^\s*<p[\s>][\s\S]*<\/p>\s*$/i;
1564
- function plainTextToTipTapHtml(text) {
1565
- if (!text) return "<p></p>";
1566
- if (PARAGRAPH_HTML_REGEX.test(text)) {
1567
- return text;
1568
- }
1569
- return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => `<p>${escapeHtml(line)}</p>`).join("");
1570
- }
1571
- function plainTextToSlice(text, schema) {
1572
- const nodes = [];
1573
- text.replace(/\r\n?/g, "\n").split("\n").forEach((line) => {
1574
- const nodeJson = { type: "paragraph" };
1575
- if (line.length > 0) {
1576
- nodeJson.content = [{ type: "text", text: line }];
1577
- }
1578
- try {
1579
- nodes.push(_model.Node.fromJSON(schema, nodeJson));
1580
- } catch (e9) {
1581
- }
1582
- });
1583
- return _model.Slice.maxOpen(_model.Fragment.fromArray(nodes));
1584
- }
1585
- var BLOCK_TAGS = /* @__PURE__ */ new Set([
1586
- "P",
1587
- "DIV",
1588
- "LI",
1589
- "UL",
1590
- "OL",
1591
- "PRE",
1592
- "BLOCKQUOTE",
1593
- "TABLE",
1594
- "TR",
1595
- "H1",
1596
- "H2",
1597
- "H3",
1598
- "H4",
1599
- "H5",
1600
- "H6",
1601
- "HR"
1602
- ]);
1603
- var MENTION_SPAN_REGEX = /<span\b(?=[^>]*\bdata-type=["']mention["'])([^>]*)>[\s\S]*?<\/span>/gi;
1604
- function getHtmlAttribute(attrs, name) {
1605
- const match = new RegExp(`\\b${name}=(?:"([^"]*)"|'([^']*)')`, "i").exec(
1606
- attrs
1607
- );
1608
- return match ? _nullishCoalesce(match[1], () => ( match[2])) : void 0;
1609
- }
1610
- function parseHtmlFragment(html) {
1611
- const template = document.createElement("template");
1612
- template.innerHTML = html;
1613
- return template.content;
1614
- }
1615
- function decodeHtmlEntities(text) {
1616
- return text.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#0*39;/g, "'").replace(/&nbsp;/g, "\xA0").replace(/&amp;/g, "&");
1617
- }
1618
- function htmlToPlainText(html, options = {}) {
1619
- if (!html) return "";
1620
- const mentionNormalized = stripTrackedChanges(
1621
- html,
1622
- _nullishCoalesce(options.trackedChanges, () => ( "accepted"))
1623
- ).replace(MENTION_SPAN_REGEX, (match, attrs) => {
1624
- const label = getHtmlAttribute(attrs, "data-label") || getHtmlAttribute(attrs, "data-id");
1625
- return label ? `@${label}` : match;
1626
- });
1627
- if (typeof document !== "undefined") {
1628
- const fragment = parseHtmlFragment(mentionNormalized);
1629
- fragment.querySelectorAll("br.ProseMirror-trailingBreak").forEach((br) => br.remove());
1630
- const lines = [];
1631
- let current = null;
1632
- const flush = () => {
1633
- if (current !== null) {
1634
- lines.push(current);
1635
- current = null;
1636
- }
1637
- };
1638
- const visit = (node) => {
1639
- if (node.nodeType === 3) {
1640
- const value = _nullishCoalesce(node.nodeValue, () => ( ""));
1641
- if (current === null && value.trim() === "") return;
1642
- current = (_nullishCoalesce(current, () => ( ""))) + value;
1643
- return;
1644
- }
1645
- if (node.nodeType !== 1) return;
1646
- const tag = node.tagName.toUpperCase();
1647
- if (tag === "BR") {
1648
- current = (_nullishCoalesce(current, () => ( ""))) + "\n";
1649
- return;
1650
- }
1651
- if (!BLOCK_TAGS.has(tag)) {
1652
- node.childNodes.forEach(visit);
1653
- return;
1654
- }
1655
- flush();
1656
- const linesBefore = lines.length;
1657
- node.childNodes.forEach(visit);
1658
- flush();
1659
- if (lines.length === linesBefore && tag !== "HR") {
1660
- lines.push("");
1661
- }
1662
- };
1663
- fragment.childNodes.forEach(visit);
1664
- flush();
1665
- return lines.join("\n");
1666
- }
1667
- const text = mentionNormalized.replace(/<br\s*\/?>/gi, "\n").replace(
1668
- /<\/(?:p|div|li|pre|blockquote|h[1-6])>(?:\s*<\/(?:li|ul|ol|blockquote|div)>)*/gi,
1669
- "\n"
1670
- ).replace(/<[^>]+>/g, "");
1671
- return decodeHtmlEntities(text).replace(/\n$/, "");
1672
- }
1673
- function getEditorText(editor, options = {}) {
1674
- if (!editor) return "";
1675
- const html = typeof editor.getHTML === "function" ? editor.getHTML() : "";
1676
- if (html) {
1677
- return htmlToPlainText(html, options);
1678
- }
1679
- if (typeof editor.getText === "function") {
1680
- try {
1681
- return editor.getText({ blockSeparator: "\n" });
1682
- } catch (e10) {
1683
- return editor.getText();
1684
- }
1685
- }
1686
- return "";
1687
- }
1688
- function extractMentionsFromDoc(docOrEditor) {
1689
- if (!docOrEditor) return [];
1690
- const mentions = [];
1691
- const doc = _optionalChain([docOrEditor, 'optionalAccess', _60 => _60.state, 'optionalAccess', _61 => _61.doc]) || (typeof _optionalChain([docOrEditor, 'optionalAccess', _62 => _62.descendants]) === "function" ? docOrEditor : null);
1692
- if (doc && typeof doc.descendants === "function") {
1693
- doc.descendants((node) => {
1694
- if (_optionalChain([node, 'access', _63 => _63.type, 'optionalAccess', _64 => _64.name]) === "mention" && node.attrs) {
1695
- mentions.push({
1696
- id: node.attrs.id || "",
1697
- label: node.attrs.label || "",
1698
- type: node.attrs.type,
1699
- avatarUrl: node.attrs.avatarUrl,
1700
- color: node.attrs.color,
1701
- ...node.attrs
1702
- });
1703
- }
1704
- });
1705
- return mentions;
1706
- }
1707
- if (typeof docOrEditor === "object" && docOrEditor.content) {
1708
- const walk = (nodes) => {
1709
- for (const node of nodes) {
1710
- if (node.type === "mention" && node.attrs) {
1711
- mentions.push({
1712
- id: node.attrs.id || "",
1713
- label: node.attrs.label || "",
1714
- type: node.attrs.type,
1715
- avatarUrl: node.attrs.avatarUrl,
1716
- color: node.attrs.color,
1717
- ...node.attrs
1718
- });
1719
- }
1720
- if (Array.isArray(node.content)) {
1721
- walk(node.content);
1722
- }
1723
- }
1724
- };
1725
- walk(docOrEditor.content);
1726
- return mentions;
1727
- }
1728
- if (typeof docOrEditor === "string") {
1729
- if (typeof document !== "undefined") {
1730
- parseHtmlFragment(docOrEditor).querySelectorAll('span[data-type="mention"]').forEach((el) => {
1731
- mentions.push({
1732
- id: el.getAttribute("data-id") || "",
1733
- label: el.getAttribute("data-label") || "",
1734
- type: el.getAttribute("data-type-name") || void 0,
1735
- avatarUrl: el.getAttribute("data-avatar-url") || void 0,
1736
- color: el.getAttribute("data-color") || void 0
1737
- });
1738
- });
1739
- } else {
1740
- const spanRegex = /<span([^>]*data-type=["']mention["'][^>]*)>/gi;
1741
- let match;
1742
- while ((match = spanRegex.exec(docOrEditor)) !== null) {
1743
- const attrStr = match[1];
1744
- const getAttr = (name) => {
1745
- const m = new RegExp(`${name}=["']([^"']*)["']`, "i").exec(attrStr);
1746
- return m ? m[1] : void 0;
1747
- };
1748
- mentions.push({
1749
- id: getAttr("data-id") || "",
1750
- label: getAttr("data-label") || "",
1751
- type: getAttr("data-type-name") || getAttr("data-entity-type"),
1752
- avatarUrl: getAttr("data-avatar-url"),
1753
- color: getAttr("data-color")
1754
- });
1755
- }
1756
- }
1757
- if (mentions.length === 0) {
1758
- const rawHandles = extractMentions(docOrEditor);
1759
- for (const handle of rawHandles) {
1760
- mentions.push({
1761
- id: handle,
1762
- label: handle,
1763
- type: "user"
1764
- });
1765
- }
1766
- }
1767
- }
1768
- return mentions;
1769
- }
1770
-
1771
- // src/serializers/mentions.ts
1772
- var MENTION_REGEX = /(?:^|[\s>(*_"';\\/[\]{}~`:]|&quot;|&gt;|&lt;|&amp;)@(?:"([^"]+)"|&quot;([^&]+)&quot;|([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*))/g;
1773
- var MARKDOWN_MENTION_SPLIT_REGEX = /(```[\s\S]*?```|~~~[\s\S]*?~~~|<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>|`[^`\n]+`|<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])[^>]*>[\s\S]*?<\/span>|<[^>]+>|\]\([^)]+\)|(?:https?|file|vscode|cursor|mailto):\/\/[^\s<)]+)/gi;
1774
- function stripMarkdownCode(content) {
1775
- if (!content || typeof content !== "string") return "";
1776
- return content.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "").replace(/<pre[\s\S]*?<\/pre>/gi, "").replace(/<code[\s\S]*?<\/code>/gi, "").replace(/`[^`\n]*`/g, "");
1777
- }
1778
- function extractMentions(content) {
1779
- if (!content || typeof content !== "string") return [];
1780
- const normalizedMentionNodes = content.replace(
1781
- /<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["'])[^>]*>([\s\S]*?)<\/span>/gi,
1782
- (match2, inner) => {
1783
- const labelMatch = match2.match(/\bdata-label=["']([^"']+)["']/i);
1784
- if (labelMatch) return ` @${labelMatch[1]} `;
1785
- const idMatch = match2.match(/\bdata-id=["']([^"']+)["']/i);
1786
- if (idMatch) return ` @${idMatch[1]} `;
1787
- return ` ${inner} `;
1788
- }
1789
- );
1790
- const cleanContent = stripMarkdownCode(normalizedMentionNodes);
1791
- const withoutUrls = cleanContent.replace(/(?:https?|ftp|file|vscode|cursor|mailto):\/\/[^\s<>()]+/gi, "").replace(/\]\([^)]*\)/g, "]");
1792
- const textOnly = withoutUrls.replace(/<[^>]+>/g, " ");
1793
- const mentions = [];
1794
- const seen = /* @__PURE__ */ new Set();
1795
- const regex = new RegExp(MENTION_REGEX.source, "g");
1796
- let match;
1797
- while ((match = regex.exec(textOnly)) !== null) {
1798
- const handle = (_nullishCoalesce(_nullishCoalesce(_nullishCoalesce(match[1], () => ( match[2])), () => ( match[3])), () => ( ""))).trim();
1799
- if (handle && !seen.has(handle)) {
1800
- seen.add(handle);
1801
- mentions.push(handle);
1802
- }
1803
- }
1804
- return mentions;
1805
- }
1806
- function parseMentionSegments(content) {
1807
- if (!content) return [];
1808
- const segments = [];
1809
- const regex = new RegExp(MENTION_REGEX.source, "g");
1810
- let lastIndex = 0;
1811
- let match;
1812
- while ((match = regex.exec(content)) !== null) {
1813
- const fullMatch = match[0];
1814
- const atIndex = fullMatch.indexOf("@");
1815
- const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : "";
1816
- const mentionToken = fullMatch.slice(atIndex);
1817
- const handle = _nullishCoalesce(_nullishCoalesce(match[1], () => ( match[2])), () => ( match[3]));
1818
- const matchStart = match.index + prefix.length;
1819
- if (matchStart > lastIndex) {
1820
- segments.push({
1821
- type: "text",
1822
- value: content.slice(lastIndex, matchStart)
1823
- });
1824
- }
1825
- segments.push({
1826
- type: "mention",
1827
- value: mentionToken,
1828
- handle
1829
- });
1830
- lastIndex = matchStart + mentionToken.length;
1831
- }
1832
- if (lastIndex < content.length) {
1833
- segments.push({
1834
- type: "text",
1835
- value: content.slice(lastIndex)
1836
- });
1837
- }
1838
- return segments;
1839
- }
1840
- function preprocessMarkdownMentions(content, optionsOrMentionables = []) {
1841
- if (!content || typeof content !== "string") return "";
1842
- const options = Array.isArray(optionsOrMentionables) ? { mentionables: optionsOrMentionables } : optionsOrMentionables;
1843
- const allMentionables = options.mentionables || [];
1844
- const defaultType = options.defaultType || "user";
1845
- const resolveMention = options.resolveMention;
1846
- const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);
1847
- return parts.map((part) => {
1848
- if (!part) return "";
1849
- if (part.startsWith("```") || part.startsWith("~~~") || part.startsWith("`") || part.startsWith("](") || /^(?:https?|file|vscode|cursor|mailto):\/\//i.test(part) || /^<pre[\s>]/i.test(part) || /^<code[\s>]/i.test(part) || /^<[^>]+>$/i.test(part) || /^<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])/i.test(
1850
- part
1851
- )) {
1852
- return part;
1853
- }
1854
- const regex = new RegExp(MENTION_REGEX.source, "g");
1855
- return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {
1856
- const atIndex = match.indexOf("@");
1857
- const prefix = atIndex > 0 ? match.slice(0, atIndex) : "";
1858
- const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || "").trim();
1859
- if (!rawHandle) return match;
1860
- const lowerHandle = rawHandle.toLowerCase();
1861
- const entity = allMentionables.find((e) => {
1862
- if (_optionalChain([e, 'access', _65 => _65.label, 'optionalAccess', _66 => _66.toLowerCase, 'call', _67 => _67()]) === lowerHandle) return true;
1863
- if (_optionalChain([e, 'access', _68 => _68.handle, 'optionalAccess', _69 => _69.toLowerCase, 'call', _70 => _70()]) === lowerHandle) return true;
1864
- if (_optionalChain([e, 'access', _71 => _71.name, 'optionalAccess', _72 => _72.toLowerCase, 'call', _73 => _73()]) === lowerHandle) return true;
1865
- if (_optionalChain([e, 'access', _74 => _74.id, 'optionalAccess', _75 => _75.toLowerCase, 'call', _76 => _76()]) === lowerHandle) return true;
1866
- if (e.type === "agent" && `agent${(e.handle || e.label || "").toLowerCase()}` === lowerHandle) return true;
1867
- if (_optionalChain([e, 'access', _77 => _77.aliases, 'optionalAccess', _78 => _78.some, 'call', _79 => _79(
1868
- (a) => a.toLowerCase() === lowerHandle || e.type === "agent" && `agent${a.toLowerCase()}` === lowerHandle
1869
- )])) {
1870
- return true;
1871
- }
1872
- return false;
1873
- });
1874
- let id = _optionalChain([entity, 'optionalAccess', _80 => _80.id]);
1875
- let label = _optionalChain([entity, 'optionalAccess', _81 => _81.label]) || _optionalChain([entity, 'optionalAccess', _82 => _82.handle]) || rawHandle;
1876
- let type = _optionalChain([entity, 'optionalAccess', _83 => _83.type]);
1877
- let avatarUrl = _optionalChain([entity, 'optionalAccess', _84 => _84.avatarUrl]);
1878
- let color = _optionalChain([entity, 'optionalAccess', _85 => _85.color]) || _optionalChain([entity, 'optionalAccess', _86 => _86.hexColor]);
1879
- if (!entity) {
1880
- const customResolved = _optionalChain([resolveMention, 'optionalCall', _87 => _87(rawHandle)]);
1881
- if (customResolved) {
1882
- id = _nullishCoalesce(customResolved.id, () => ( id));
1883
- label = _nullishCoalesce(_nullishCoalesce(customResolved.label, () => ( customResolved.handle)), () => ( label));
1884
- type = _nullishCoalesce(customResolved.type, () => ( type));
1885
- avatarUrl = _nullishCoalesce(customResolved.avatarUrl, () => ( avatarUrl));
1886
- color = _nullishCoalesce(_nullishCoalesce(customResolved.color, () => ( customResolved.hexColor)), () => ( color));
1887
- } else {
1888
- const stripped = lowerHandle.replace(/^agent[\s\-_]*/i, "");
1889
- if (["supervisor", "coordinator", "planner", "validator", "executor"].includes(stripped)) {
1890
- type = "agent";
1891
- id = stripped;
1892
- label = stripped;
1893
- } else if (lowerHandle === "agents") {
1894
- type = "team";
1895
- id = "agents";
1896
- label = "agents";
1897
- } else {
1898
- type = defaultType;
1899
- id = rawHandle;
1900
- label = rawHandle;
1901
- }
1902
- }
1903
- }
1904
- const avatarAttr = avatarUrl ? ` data-avatar-url="${escapeHtml(avatarUrl)}"` : "";
1905
- const colorAttr = color ? ` data-color="${escapeHtml(color)}"` : "";
1906
- return `${prefix}<span class="pixerate-mention-node" data-type="mention" data-id="${escapeHtml(
1907
- id || label
1908
- )}" data-label="${escapeHtml(label)}" data-mention-suggestion-char="@" data-type-name="${escapeHtml(
1909
- type || defaultType
1910
- )}"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;
1911
- });
1912
- }).join("");
1913
- }
1914
-
1915
- // src/serializers/markdown.ts
1916
- var _markdownit = require('markdown-it'); var _markdownit2 = _interopRequireDefault(_markdownit);
1917
- var _markdownittasklists = require('markdown-it-task-lists'); var _markdownittasklists2 = _interopRequireDefault(_markdownittasklists);
1918
- var md = new (0, _markdownit2.default)({
1919
- html: true,
1920
- linkify: true,
1921
- breaks: true
1922
- }).use(_markdownittasklists2.default);
1923
- var defaultValidateLink = md.validateLink;
1924
- md.validateLink = (url) => {
1925
- if (url.startsWith("file://") || url.startsWith("vscode://") || url.startsWith("cursor://")) {
1926
- return true;
1927
- }
1928
- return defaultValidateLink.call(md, url);
1929
- };
1930
- var ALLOWED_HTML_TAGS = /* @__PURE__ */ new Set([
1931
- "a",
1932
- "abbr",
1933
- "b",
1934
- "blockquote",
1935
- "br",
1936
- "code",
1937
- "del",
1938
- "details",
1939
- "div",
1940
- "em",
1941
- "h1",
1942
- "h2",
1943
- "h3",
1944
- "h4",
1945
- "h5",
1946
- "h6",
1947
- "hr",
1948
- "i",
1949
- "img",
1950
- "input",
1951
- "kbd",
1952
- "li",
1953
- "mark",
1954
- "ol",
1955
- "p",
1956
- "pre",
1957
- "s",
1958
- "span",
1959
- "strong",
1960
- "sub",
1961
- "summary",
1962
- "sup",
1963
- "table",
1964
- "tbody",
1965
- "td",
1966
- "tfoot",
1967
- "th",
1968
- "thead",
1969
- "tr",
1970
- "u",
1971
- "ul"
1972
- ]);
1973
- var ALLOWED_HTML_ATTRS = /* @__PURE__ */ new Set([
1974
- "alt",
1975
- "align",
1976
- "checked",
1977
- "class",
1978
- "colspan",
1979
- "disabled",
1980
- "height",
1981
- "href",
1982
- "rel",
1983
- "rowspan",
1984
- "src",
1985
- "start",
1986
- "target",
1987
- "title",
1988
- "type",
1989
- "width"
1990
- ]);
1991
- var HTML_TAG_REGEX = /<(\/?)([a-zA-Z][a-zA-Z0-9-]*)((?:\s+[^\s"'>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'=<>`]+))?)*)\s*\/?>/g;
1992
- var HTML_ATTR_REGEX = /([^\s"'>\/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
1993
- function sanitizeTag(tagText, isClosing, rawTagName, rawAttrs, stripDisallowed) {
1994
- const tagName = rawTagName.toLowerCase();
1995
- const reject = () => stripDisallowed ? "" : escapeHtml(tagText);
1996
- if (!ALLOWED_HTML_TAGS.has(tagName)) return reject();
1997
- if (isClosing) return `</${tagName}>`;
1998
- if (tagName === "input" && !/\stype\s*=\s*["']?checkbox["']?[\s>/]/i.test(tagText)) {
1999
- return reject();
2000
- }
2001
- let attrs = "";
2002
- let attrMatch;
2003
- HTML_ATTR_REGEX.lastIndex = 0;
2004
- while ((attrMatch = HTML_ATTR_REGEX.exec(rawAttrs)) !== null) {
2005
- const name = attrMatch[1].toLowerCase();
2006
- if (!ALLOWED_HTML_ATTRS.has(name) && !/^data-[a-z0-9_.-]+$/.test(name)) {
2007
- continue;
2008
- }
2009
- const rawValue = _nullishCoalesce(_nullishCoalesce(attrMatch[2], () => ( attrMatch[3])), () => ( attrMatch[4]));
2010
- if (rawValue === void 0) {
2011
- attrs += ` ${name}`;
2012
- continue;
2013
- }
2014
- const value = md.utils.unescapeAll(rawValue);
2015
- if ((name === "href" || name === "src") && // Browsers ignore control characters and whitespace inside schemes.
2016
- !md.validateLink(value.replace(/[\u0000-\u0020\u007f]/g, ""))) {
2017
- continue;
2018
- }
2019
- attrs += ` ${name}="${escapeHtml(value)}"`;
2020
- }
2021
- return `<${tagName}${attrs}>`;
2022
- }
2023
- function sanitizeHtml(html, options = {}) {
2024
- return sanitizeEmbeddedHtml(html, options.disallowedTags === "strip");
2025
- }
2026
- function sanitizeEmbeddedHtml(html, stripDisallowed = false) {
2027
- let result = "";
2028
- let lastIndex = 0;
2029
- let match;
2030
- HTML_TAG_REGEX.lastIndex = 0;
2031
- while ((match = HTML_TAG_REGEX.exec(html)) !== null) {
2032
- result += html.slice(lastIndex, match.index).replace(/</g, "&lt;");
2033
- result += sanitizeTag(match[0], match[1], match[2], match[3], stripDisallowed);
2034
- lastIndex = match.index + match[0].length;
2035
- }
2036
- return result + html.slice(lastIndex).replace(/</g, "&lt;");
2037
- }
2038
- var defaultHtmlInline = md.renderer.rules.html_inline;
2039
- var defaultHtmlBlock = md.renderer.rules.html_block;
2040
- md.renderer.rules.html_inline = (tokens, idx, options, env, self) => _optionalChain([env, 'optionalAccess', _88 => _88.allowUnsafeHtml]) ? defaultHtmlInline(tokens, idx, options, env, self) : sanitizeEmbeddedHtml(tokens[idx].content);
2041
- md.renderer.rules.html_block = (tokens, idx, options, env, self) => _optionalChain([env, 'optionalAccess', _89 => _89.allowUnsafeHtml]) ? defaultHtmlBlock(tokens, idx, options, env, self) : sanitizeEmbeddedHtml(tokens[idx].content);
2042
- function preprocessMarkdownFileLinks(content) {
2043
- if (!content) return "";
2044
- return content.replace(
2045
- /\[([^\]]+)\]\(((?:file|vscode|cursor):\/\/[^)]+)\)/g,
2046
- (_match, rawLabel, href) => {
2047
- const trimmed = rawLabel.trim();
2048
- const codeMatch = trimmed.match(/^`([^`]+)`$/);
2049
- const labelContent = codeMatch ? `<code>${escapeHtml(codeMatch[1])}</code>` : escapeHtml(trimmed);
2050
- return `<a href="${escapeHtml(href)}" data-file-link="true" title="Click to copy file path">${labelContent}</a>`;
2051
- }
2052
- );
2053
- }
2054
- function markdownToTipTapHtml(markdown, options) {
2055
- if (!markdown) return "<p></p>";
2056
- let content = markdown;
2057
- if (_optionalChain([options, 'optionalAccess', _90 => _90.preprocessFileLinks])) {
2058
- content = preprocessMarkdownFileLinks(content);
2059
- }
2060
- if (_optionalChain([options, 'optionalAccess', _91 => _91.preprocessMentions]) || _optionalChain([options, 'optionalAccess', _92 => _92.mentionables]) || _optionalChain([options, 'optionalAccess', _93 => _93.preprocessOptions])) {
2061
- const mentionOpts = options.preprocessOptions || {
2062
- mentionables: options.mentionables
2063
- };
2064
- content = preprocessMarkdownMentions(content, mentionOpts);
2065
- }
2066
- return md.render(content, { allowUnsafeHtml: _optionalChain([options, 'optionalAccess', _94 => _94.allowUnsafeHtml]) });
2067
- }
2068
- function getEditorMarkdown(editor, options = {}) {
2069
- if (!editor) return "";
2070
- const markdown = _optionalChain([editor, 'access', _95 => _95.storage, 'optionalAccess', _96 => _96.markdown]);
2071
- if (typeof _optionalChain([markdown, 'optionalAccess', _97 => _97.getMarkdown]) === "function") {
2072
- const doc = _optionalChain([editor, 'access', _98 => _98.state, 'optionalAccess', _99 => _99.doc]);
2073
- if (doc && typeof _optionalChain([markdown, 'access', _100 => _100.serializer, 'optionalAccess', _101 => _101.serialize]) === "function") {
2074
- const resolved = resolveTrackedChanges(doc, _nullishCoalesce(options.trackedChanges, () => ( "accepted")));
2075
- if (resolved !== doc) return markdown.serializer.serialize(resolved);
2076
- }
2077
- return markdown.getMarkdown();
2078
- }
2079
- return getEditorText(editor, options);
2080
- }
2081
-
2082
-
2083
-
2084
-
2085
-
2086
-
2087
-
2088
-
2089
-
2090
-
2091
-
2092
-
2093
1821
 
2094
1822
 
2095
1823
 
@@ -2118,5 +1846,5 @@ function getEditorMarkdown(editor, options = {}) {
2118
1846
 
2119
1847
 
2120
1848
 
2121
- exports.createReviewId = createReviewId; exports.CommentStore = CommentStore; exports.createCommentStore = createCommentStore; exports.formatReviewTime = formatReviewTime; exports.INSERTION_MARK_NAME = INSERTION_MARK_NAME; exports.DELETION_MARK_NAME = DELETION_MARK_NAME; exports.FORMAT_CHANGE_MARK_NAME = FORMAT_CHANGE_MARK_NAME; exports.BLOCK_CHANGE_ATTRIBUTE = BLOCK_CHANGE_ATTRIBUTE; exports.TRACK_CHANGES_SKIP_META = TRACK_CHANGES_SKIP_META; exports.TrackChangesStore = TrackChangesStore; exports.trackChangesPluginKey = trackChangesPluginKey; exports.TrackedInsertion = TrackedInsertion; exports.TrackedDeletion = TrackedDeletion; exports.TrackedFormatChange = TrackedFormatChange; exports.describeFormatChange = describeFormatChange; exports.describeBlockChange = describeBlockChange; exports.getTrackedChanges = getTrackedChanges; exports.getTrackedChangeAt = getTrackedChangeAt; exports.isTrackChangesEnabled = isTrackChangesEnabled; exports.getTrackChangesStore = getTrackChangesStore; exports.resolveTrackedChanges = resolveTrackedChanges; exports.TrackChanges = TrackChanges; exports.MENTION_REGEX = MENTION_REGEX; exports.MARKDOWN_MENTION_SPLIT_REGEX = MARKDOWN_MENTION_SPLIT_REGEX; exports.stripMarkdownCode = stripMarkdownCode; exports.extractMentions = extractMentions; exports.parseMentionSegments = parseMentionSegments; exports.preprocessMarkdownMentions = preprocessMarkdownMentions; exports.escapeHtml = escapeHtml; exports.plainTextToTipTapHtml = plainTextToTipTapHtml; exports.plainTextToSlice = plainTextToSlice; exports.htmlToPlainText = htmlToPlainText; exports.getEditorText = getEditorText; exports.extractMentionsFromDoc = extractMentionsFromDoc; exports.sanitizeHtml = sanitizeHtml; exports.preprocessMarkdownFileLinks = preprocessMarkdownFileLinks; exports.markdownToTipTapHtml = markdownToTipTapHtml; exports.getEditorMarkdown = getEditorMarkdown;
2122
- //# sourceMappingURL=chunk-AA4ZEVCC.cjs.map
1849
+ exports.createReviewId = createReviewId; exports.CommentStore = CommentStore; exports.createCommentStore = createCommentStore; exports.formatReviewTime = formatReviewTime; exports.INSERTION_MARK_NAME = INSERTION_MARK_NAME; exports.DELETION_MARK_NAME = DELETION_MARK_NAME; exports.FORMAT_CHANGE_MARK_NAME = FORMAT_CHANGE_MARK_NAME; exports.BLOCK_CHANGE_ATTRIBUTE = BLOCK_CHANGE_ATTRIBUTE; exports.MOVE_ID_ATTRIBUTE = MOVE_ID_ATTRIBUTE; exports.TRACK_CHANGES_SKIP_META = TRACK_CHANGES_SKIP_META; exports.TrackChangesStore = TrackChangesStore; exports.trackChangesPluginKey = trackChangesPluginKey; exports.MOVE_TO_CLASS = MOVE_TO_CLASS; exports.MOVE_FROM_CLASS = MOVE_FROM_CLASS; exports.TrackedInsertion = TrackedInsertion; exports.TrackedDeletion = TrackedDeletion; exports.TrackedFormatChange = TrackedFormatChange; exports.describeFormatChange = describeFormatChange; exports.describeBlockChange = describeBlockChange; exports.trackedChangeLabel = trackedChangeLabel; exports.getTrackedChanges = getTrackedChanges; exports.getTrackedChangeAt = getTrackedChangeAt; exports.isTrackChangesEnabled = isTrackChangesEnabled; exports.getTrackChangesStore = getTrackChangesStore; exports.resolveTrackedChanges = resolveTrackedChanges; exports.isMoveSized = isMoveSized; exports.TrackChanges = TrackChanges;
1850
+ //# sourceMappingURL=chunk-X4N4WUKB.cjs.map