@servicetitan/anvil2 3.15.1 → 3.16.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 (79) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/{Announcement-Cnz80WGx.js → Announcement-PfnsVVz1.js} +5 -2
  3. package/dist/Announcement-PfnsVVz1.js.map +1 -0
  4. package/dist/Announcement.js +1 -1
  5. package/dist/{DataTable-DkEpJ_Op.js → DataTable-DIXP9-Bx.js} +4 -4
  6. package/dist/{DataTable-DkEpJ_Op.js.map → DataTable-DIXP9-Bx.js.map} +1 -1
  7. package/dist/{Dialog-B9llUKJz.js → Dialog-_tHqOsbr.js} +2 -2
  8. package/dist/{Dialog-B9llUKJz.js.map → Dialog-_tHqOsbr.js.map} +1 -1
  9. package/dist/Dialog.js +1 -1
  10. package/dist/{Drawer-Bjd2XLUX.js → Drawer-D-ThWNp0.js} +2 -2
  11. package/dist/{Drawer-Bjd2XLUX.js.map → Drawer-D-ThWNp0.js.map} +1 -1
  12. package/dist/Drawer.js +1 -1
  13. package/dist/{FilterBar-ecqJDraA.js → FilterBar-jFn8O7v7.js} +17 -15
  14. package/dist/FilterBar-jFn8O7v7.js.map +1 -0
  15. package/dist/FilterBar.js +1 -1
  16. package/dist/MultiSelectField.js +1 -1
  17. package/dist/{MultiSelectFieldSync-DpPO0cya.js → MultiSelectFieldSync-DuImKXuj.js} +3 -3
  18. package/dist/{MultiSelectFieldSync-DpPO0cya.js.map → MultiSelectFieldSync-DuImKXuj.js.map} +1 -1
  19. package/dist/MultiSelectMenu.js +1 -1
  20. package/dist/{MultiSelectMenuSync-BN_3moW_.js → MultiSelectMenuSync-BhNXsgAN.js} +3 -3
  21. package/dist/{MultiSelectMenuSync-BN_3moW_.js.map → MultiSelectMenuSync-BhNXsgAN.js.map} +1 -1
  22. package/dist/{Page-IZ4p51iJ.js → Page-ZSHNJs7z.js} +2 -2
  23. package/dist/{Page-IZ4p51iJ.js.map → Page-ZSHNJs7z.js.map} +1 -1
  24. package/dist/Page.js +1 -1
  25. package/dist/{Pagination-Su4VBAhT.js → Pagination-Bsl99RRI.js} +4 -2
  26. package/dist/{Pagination-Su4VBAhT.js.map → Pagination-Bsl99RRI.js.map} +1 -1
  27. package/dist/Pagination.js +1 -1
  28. package/dist/{ProgressBar-TQ0fPmn9.js → ProgressBar-zPKYv4Il.js} +10 -13
  29. package/dist/ProgressBar-zPKYv4Il.js.map +1 -0
  30. package/dist/ProgressBar.css +10 -14
  31. package/dist/ProgressBar.js +1 -1
  32. package/dist/{RichTextEditor-BpzUo8dB.js → RichTextEditor-DcAVqd2d.js} +18821 -20223
  33. package/dist/RichTextEditor-DcAVqd2d.js.map +1 -0
  34. package/dist/RichTextEditor.js +1 -1
  35. package/dist/{SavedFiltersButton-D9GJbJQu.js → SavedFiltersButton-Bl8mr-LB.js} +4 -4
  36. package/dist/{SavedFiltersButton-D9GJbJQu.js.map → SavedFiltersButton-Bl8mr-LB.js.map} +1 -1
  37. package/dist/SavedFiltersButton.js +1 -1
  38. package/dist/SelectField.js +1 -1
  39. package/dist/{SelectFieldSync-BN2ebLWT.js → SelectFieldSync-SS7FELT3.js} +3 -3
  40. package/dist/{SelectFieldSync-BN2ebLWT.js.map → SelectFieldSync-SS7FELT3.js.map} +1 -1
  41. package/dist/SelectMenu.js +1 -1
  42. package/dist/{SelectMenuSync-DuPf8KCc.js → SelectMenuSync-CPpE6vUG.js} +3 -3
  43. package/dist/{SelectMenuSync-DuPf8KCc.js.map → SelectMenuSync-CPpE6vUG.js.map} +1 -1
  44. package/dist/{SelectOptions-BK7kNjYM.js → SelectOptions-BDAu_9dv.js} +2 -2
  45. package/dist/{SelectOptions-BK7kNjYM.js.map → SelectOptions-BDAu_9dv.js.map} +1 -1
  46. package/dist/Table.js +1 -1
  47. package/dist/Toast.js +2 -2
  48. package/dist/{Toaster-BryQmKe1.js → Toaster-SqkX0Kes.js} +2 -2
  49. package/dist/{Toaster-BryQmKe1.js.map → Toaster-SqkX0Kes.js.map} +1 -1
  50. package/dist/{Toaster-BtP_HezK.js → Toaster-dVGVVcat.js} +2 -2
  51. package/dist/{Toaster-BtP_HezK.js.map → Toaster-dVGVVcat.js.map} +1 -1
  52. package/dist/assets/icons/material.ts +184 -184
  53. package/dist/assets/icons/st.ts +9 -9
  54. package/dist/beta.js +9 -9
  55. package/dist/{bulkActionTypes-D5y3Acn1.js → bulkActionTypes-SukoplGV.js} +2 -2
  56. package/dist/{bulkActionTypes-D5y3Acn1.js.map → bulkActionTypes-SukoplGV.js.map} +1 -1
  57. package/dist/downshift.esm-U4VMqrF-.js.map +1 -1
  58. package/dist/extends-Bg2s_OKl.js.map +1 -1
  59. package/dist/{filter-state-Do862BNr.js → filter-state-hDtCUggM.js} +6 -6
  60. package/dist/{filter-state-Do862BNr.js.map → filter-state-hDtCUggM.js.map} +1 -1
  61. package/dist/{index-Dt0zG4YB.js → index-C2dOrf4N.js} +1549 -1582
  62. package/dist/index-C2dOrf4N.js.map +1 -0
  63. package/dist/index.js +11 -11
  64. package/dist/src/components/Pagination/Pagination.d.ts +28 -0
  65. package/dist/src/internal/components/LoadMoreSlot.d.ts +13 -0
  66. package/dist/src/internal/hooks/useAutoLoadMore.d.ts +40 -0
  67. package/dist/src/internal/hooks/useFocusReturnOnUnmount.d.ts +10 -0
  68. package/dist/{syncFilterUtils-ClEj4Oeg.js → syncFilterUtils-SMop8ckR.js} +177 -62
  69. package/dist/syncFilterUtils-SMop8ckR.js.map +1 -0
  70. package/package.json +21 -21
  71. package/dist/Announcement-Cnz80WGx.js.map +0 -1
  72. package/dist/FilterBar-ecqJDraA.js.map +0 -1
  73. package/dist/ProgressBar-TQ0fPmn9.js.map +0 -1
  74. package/dist/RichTextEditor-BpzUo8dB.js.map +0 -1
  75. package/dist/check_circle-C3DDoVXp.js +0 -8
  76. package/dist/check_circle-C3DDoVXp.js.map +0 -1
  77. package/dist/index-Dt0zG4YB.js.map +0 -1
  78. package/dist/src/internal/components/InView.d.ts +0 -14
  79. package/dist/syncFilterUtils-ClEj4Oeg.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { P as PluginKey, a as Plugin, S as Slice, F as Fragment, T as TextSelection, A as AllSelection, N as NodeSelection, E as Extension, g as getUpdatedPosition$1, M as MappablePosition, b as NodeRange, c as SelectionRange, d as Selection, D as DecorationSet, e as Decoration, f as computePosition, i as isFirefox } from './RichTextEditor-BpzUo8dB.js';
1
+ import { P as PluginKey, a as Plugin, S as Slice, F as Fragment, T as TextSelection, A as AllSelection, N as NodeSelection, E as Extension, g as getUpdatedPosition$1, M as MappablePosition, b as NodeRange, c as SelectionRange, d as Selection, D as DecorationSet, e as Decoration, f as computePosition, i as isFirefox } from './RichTextEditor-DcAVqd2d.js';
2
2
  import { useRef, useMemo, useEffect } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
 
@@ -1153,6 +1153,10 @@ const unexpectedCase = () => {
1153
1153
  * decoding.hasContent(decoder) // => false - all data is read
1154
1154
  * ```
1155
1155
  *
1156
+ * Security: Decoders process untrusted input, and `decoder.arr` may be a view on a larger (possibly pooled) ArrayBuffer.
1157
+ * Never create views via `new Uint8Array(arr.buffer, ..)` / `new DataView(arr.buffer, ..)`; use the private `subarray` /
1158
+ * `subdataview` helpers, which throw on out-of-bounds access instead of exposing foreign memory.
1159
+ *
1156
1160
  * @module decoding
1157
1161
  */
1158
1162
 
@@ -1160,6 +1164,42 @@ const unexpectedCase = () => {
1160
1164
  const errorUnexpectedEndOfArray = create$3('Unexpected end of array');
1161
1165
  const errorIntegerOutOfRange = create$3('Integer out of Range');
1162
1166
 
1167
+ /**
1168
+ * Create a view of `len` bytes of `arr`, starting at `begin`. Throws if the range exceeds `arr`.
1169
+ *
1170
+ * Security: Always use this (or `subdataview`) instead of `new Uint8Array(arr.buffer, ..)`. `arr` may be a view on a
1171
+ * larger (possibly shared/pooled) ArrayBuffer. An unchecked view could expose memory outside of `arr`.
1172
+ *
1173
+ * @template {ArrayBufferLike} Buf
1174
+ * @param {Uint8Array<Buf>} arr
1175
+ * @param {number} begin
1176
+ * @param {number} len
1177
+ * @return {Uint8Array<Buf>}
1178
+ */
1179
+ const subarray = (arr, begin, len) => {
1180
+ if (begin < 0 || len < 0 || begin + len > arr.length) {
1181
+ throw errorUnexpectedEndOfArray
1182
+ }
1183
+ return new Uint8Array(arr.buffer, arr.byteOffset + begin, len)
1184
+ };
1185
+
1186
+ /**
1187
+ * Create a DataView of `len` bytes of `arr`, starting at `begin`. Throws if the range exceeds `arr`.
1188
+ *
1189
+ * Security: See `subarray`.
1190
+ *
1191
+ * @param {Uint8Array} arr
1192
+ * @param {number} begin
1193
+ * @param {number} len
1194
+ * @return {DataView}
1195
+ */
1196
+ const subdataview = (arr, begin, len) => {
1197
+ if (begin < 0 || len < 0 || begin + len > arr.length) {
1198
+ throw errorUnexpectedEndOfArray
1199
+ }
1200
+ return new DataView(arr.buffer, arr.byteOffset + begin, len)
1201
+ };
1202
+
1163
1203
  /**
1164
1204
  * A Decoder handles the decoding of an Uint8Array.
1165
1205
  * @template {ArrayBufferLike} [Buf=ArrayBufferLike]
@@ -1212,7 +1252,7 @@ const hasContent = decoder => decoder.pos !== decoder.arr.length;
1212
1252
  * @return {Uint8Array<Buf>}
1213
1253
  */
1214
1254
  const readUint8Array = (decoder, len) => {
1215
- const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len);
1255
+ const view = subarray(decoder.arr, decoder.pos, len);
1216
1256
  decoder.pos += len;
1217
1257
  return view
1218
1258
  };
@@ -1373,7 +1413,7 @@ const readVarString = utf8TextDecoder ? _readVarStringNative : _readVarStringPol
1373
1413
  * @return {DataView}
1374
1414
  */
1375
1415
  const readFromDataView = (decoder, len) => {
1376
- const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len);
1416
+ const dv = subdataview(decoder.arr, decoder.pos, len);
1377
1417
  decoder.pos += len;
1378
1418
  return dv
1379
1419
  };
@@ -14563,1667 +14603,1594 @@ const yUndoPlugin = ({ protectedNodes = defaultProtectedNodes, trackedOrigins =
14563
14603
  }
14564
14604
  });
14565
14605
 
14566
- // src/collaboration.ts
14606
+ //#region src/helpers/isChangeOrigin.ts
14607
+ /**
14608
+ * Checks if a transaction was originated from a Yjs change.
14609
+ * @param {Transaction} transaction - The transaction to check.
14610
+ * @returns {boolean} - True if the transaction was originated from a Yjs change, false otherwise.
14611
+ * @example
14612
+ * const transaction = new Transaction(doc)
14613
+ * const isOrigin = isChangeOrigin(transaction) // returns false
14614
+ */
14567
14615
  function isChangeOrigin(transaction) {
14568
- return !!transaction.getMeta(ySyncPluginKey);
14616
+ return !!transaction.getMeta(ySyncPluginKey);
14569
14617
  }
14618
+ //#endregion
14619
+ //#region src/helpers/yRelativePosition.ts
14620
+ /**
14621
+ * Converts a Y.js relative position to a position in the Tiptap document.
14622
+ */
14570
14623
  function getYAbsolutePosition(state, relativePos) {
14571
- const ystate = ySyncPluginKey.getState(state);
14572
- return relativePositionToAbsolutePosition(
14573
- ystate.doc,
14574
- ystate.type,
14575
- relativePos,
14576
- ystate.binding.mapping
14577
- ) || 0;
14624
+ const ystate = ySyncPluginKey.getState(state);
14625
+ return relativePositionToAbsolutePosition(ystate.doc, ystate.type, relativePos, ystate.binding.mapping) || 0;
14578
14626
  }
14627
+ /**
14628
+ * Converts a position in the Tiptap document to a Y.js relative position.
14629
+ */
14579
14630
  function getYRelativePosition(state, absolutePos) {
14580
- const ystate = ySyncPluginKey.getState(state);
14581
- return absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping);
14631
+ const ystate = ySyncPluginKey.getState(state);
14632
+ return absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping);
14582
14633
  }
14583
-
14584
- // src/helpers/CollaborationMappablePosition.ts
14585
- var CollaborationMappablePosition = class _CollaborationMappablePosition extends MappablePosition {
14586
- constructor(position, yRelativePosition) {
14587
- super(position);
14588
- this.yRelativePosition = yRelativePosition;
14589
- }
14590
- /**
14591
- * Creates a CollaborationMappablePosition from a JSON object.
14592
- */
14593
- static fromJSON(json) {
14594
- return new _CollaborationMappablePosition(json.position, json.yRelativePosition);
14595
- }
14596
- /**
14597
- * Converts the CollaborationMappablePosition to a JSON object.
14598
- */
14599
- toJSON() {
14600
- return {
14601
- position: this.position,
14602
- yRelativePosition: this.yRelativePosition
14603
- };
14604
- }
14605
- };
14634
+ //#endregion
14635
+ //#region src/helpers/CollaborationMappablePosition.ts
14636
+ /**
14637
+ * A MappablePosition subclass that includes Y.js relative position information
14638
+ * to track positions in collaborative transactions.
14639
+ */
14640
+ var CollaborationMappablePosition = class CollaborationMappablePosition extends MappablePosition {
14641
+ constructor(position, yRelativePosition) {
14642
+ super(position);
14643
+ this.yRelativePosition = yRelativePosition;
14644
+ }
14645
+ /**
14646
+ * Creates a CollaborationMappablePosition from a JSON object.
14647
+ */
14648
+ static fromJSON(json) {
14649
+ return new CollaborationMappablePosition(json.position, json.yRelativePosition);
14650
+ }
14651
+ /**
14652
+ * Converts the CollaborationMappablePosition to a JSON object.
14653
+ */
14654
+ toJSON() {
14655
+ return {
14656
+ position: this.position,
14657
+ yRelativePosition: this.yRelativePosition
14658
+ };
14659
+ }
14660
+ };
14661
+ /**
14662
+ * Creates a MappablePosition from a position number.
14663
+ * This is the collaboration implementation that returns a CollaborationMappablePosition.
14664
+ */
14606
14665
  function createMappablePosition(position, state) {
14607
- const yRelativePosition = getYRelativePosition(state, position);
14608
- return new CollaborationMappablePosition(position, yRelativePosition);
14666
+ return new CollaborationMappablePosition(position, getYRelativePosition(state, position));
14609
14667
  }
14668
+ /**
14669
+ * Returns the new position after applying a transaction. Handles both Y.js
14670
+ * transactions and regular transactions.
14671
+ */
14610
14672
  function getUpdatedPosition(position, transaction, state) {
14611
- const yRelativePosition = position instanceof CollaborationMappablePosition ? position.yRelativePosition : null;
14612
- if (isChangeOrigin(transaction) && yRelativePosition) {
14613
- const absolutePosition2 = getYAbsolutePosition(state, yRelativePosition);
14614
- return {
14615
- position: new CollaborationMappablePosition(absolutePosition2, yRelativePosition),
14616
- mapResult: null
14617
- };
14618
- }
14619
- const result = getUpdatedPosition$1(position, transaction);
14620
- const absolutePosition = result.position.position;
14621
- return {
14622
- position: new CollaborationMappablePosition(
14623
- absolutePosition,
14624
- yRelativePosition != null ? yRelativePosition : getYRelativePosition(state, absolutePosition)
14625
- ),
14626
- mapResult: result.mapResult
14627
- };
14673
+ const yRelativePosition = position instanceof CollaborationMappablePosition ? position.yRelativePosition : null;
14674
+ if (isChangeOrigin(transaction) && yRelativePosition) return {
14675
+ position: new CollaborationMappablePosition(getYAbsolutePosition(state, yRelativePosition), yRelativePosition),
14676
+ mapResult: null
14677
+ };
14678
+ const result = getUpdatedPosition$1(position, transaction);
14679
+ const absolutePosition = result.position.position;
14680
+ return {
14681
+ position: new CollaborationMappablePosition(absolutePosition, yRelativePosition !== null && yRelativePosition !== void 0 ? yRelativePosition : getYRelativePosition(state, absolutePosition)),
14682
+ mapResult: result.mapResult
14683
+ };
14628
14684
  }
14629
-
14630
- // src/collaboration.ts
14685
+ //#endregion
14686
+ //#region src/collaboration.ts
14687
+ /**
14688
+ * This extension allows you to collaborate with others in real-time.
14689
+ * @see https://tiptap.dev/api/extensions/collaboration
14690
+ */
14631
14691
  Extension.create({
14632
- name: "collaboration",
14633
- priority: 1e3,
14634
- addOptions() {
14635
- return {
14636
- document: null,
14637
- field: "default",
14638
- fragment: null,
14639
- provider: null
14640
- };
14641
- },
14642
- addStorage() {
14643
- return {
14644
- isDisabled: false
14645
- };
14646
- },
14647
- onCreate() {
14648
- if (this.editor.extensionManager.extensions.find((extension) => extension.name === "undoRedo")) {
14649
- console.warn(
14650
- '[tiptap warn]: "@tiptap/extension-collaboration" comes with its own history support and is not compatible with "@tiptap/extension-undo-redo".'
14651
- );
14652
- }
14653
- },
14654
- onBeforeCreate() {
14655
- this.editor.utils.getUpdatedPosition = (position, transaction) => getUpdatedPosition(position, transaction, this.editor.state);
14656
- this.editor.utils.createMappablePosition = (position) => createMappablePosition(position, this.editor.state);
14657
- },
14658
- addCommands() {
14659
- return {
14660
- undo: () => ({ tr, state, dispatch }) => {
14661
- tr.setMeta("preventDispatch", true);
14662
- const undoManager = yUndoPluginKey.getState(state).undoManager;
14663
- if (undoManager.undoStack.length === 0) {
14664
- return false;
14665
- }
14666
- if (!dispatch) {
14667
- return true;
14668
- }
14669
- return undo(state);
14670
- },
14671
- redo: () => ({ tr, state, dispatch }) => {
14672
- tr.setMeta("preventDispatch", true);
14673
- const undoManager = yUndoPluginKey.getState(state).undoManager;
14674
- if (undoManager.redoStack.length === 0) {
14675
- return false;
14676
- }
14677
- if (!dispatch) {
14678
- return true;
14679
- }
14680
- return redo(state);
14681
- }
14682
- };
14683
- },
14684
- addKeyboardShortcuts() {
14685
- return {
14686
- "Mod-z": () => this.editor.commands.undo(),
14687
- "Mod-y": () => this.editor.commands.redo(),
14688
- "Shift-Mod-z": () => this.editor.commands.redo()
14689
- };
14690
- },
14691
- addProseMirrorPlugins() {
14692
- const fragment = this.options.fragment ? this.options.fragment : this.options.document.getXmlFragment(this.options.field);
14693
- const yUndoPluginInstance = yUndoPlugin(this.options.yUndoOptions);
14694
- const originalUndoPluginView = yUndoPluginInstance.spec.view;
14695
- yUndoPluginInstance.spec.view = (view) => {
14696
- const { undoManager } = yUndoPluginKey.getState(view.state);
14697
- if (undoManager.restore) {
14698
- undoManager.restore();
14699
- undoManager.restore = () => {
14700
- };
14701
- }
14702
- const viewRet = originalUndoPluginView ? originalUndoPluginView(view) : void 0;
14703
- return {
14704
- destroy: () => {
14705
- const hasUndoManSelf = undoManager.trackedOrigins.has(undoManager);
14706
- const observers = undoManager._observers;
14707
- undoManager.restore = () => {
14708
- if (hasUndoManSelf) {
14709
- undoManager.trackedOrigins.add(undoManager);
14710
- }
14711
- undoManager.doc.on("afterTransaction", undoManager.afterTransactionHandler);
14712
- undoManager._observers = observers;
14713
- };
14714
- if (viewRet == null ? void 0 : viewRet.destroy) {
14715
- viewRet.destroy();
14716
- }
14717
- }
14718
- };
14719
- };
14720
- const ySyncPluginOptions = {
14721
- ...this.options.ySyncOptions,
14722
- onFirstRender: this.options.onFirstRender
14723
- };
14724
- const ySyncPluginInstance = ySyncPlugin(fragment, ySyncPluginOptions);
14725
- return [
14726
- ySyncPluginInstance,
14727
- yUndoPluginInstance,
14728
- // Only add the filterInvalidContent plugin if content checking is enabled
14729
- this.editor.options.enableContentCheck && new Plugin({
14730
- key: new PluginKey("filterInvalidContent"),
14731
- filterTransaction: (transaction) => {
14732
- if (!isChangeOrigin(transaction)) {
14733
- return true;
14734
- }
14735
- if (this.storage.isDisabled) {
14736
- return false;
14737
- }
14738
- if (!transaction.docChanged) {
14739
- return true;
14740
- }
14741
- try {
14742
- transaction.doc.check();
14743
- return true;
14744
- } catch (error) {
14745
- this.storage.isDisabled = true;
14746
- this.editor.emit("contentError", {
14747
- error,
14748
- editor: this.editor,
14749
- disableCollaboration: () => {
14750
- var _a;
14751
- (_a = fragment.doc) == null ? void 0 : _a.destroy();
14752
- }
14753
- });
14754
- return true;
14755
- }
14756
- }
14757
- })
14758
- ].filter(Boolean);
14759
- }
14692
+ name: "collaboration",
14693
+ priority: 1e3,
14694
+ addOptions() {
14695
+ return {
14696
+ document: null,
14697
+ field: "default",
14698
+ fragment: null,
14699
+ provider: null
14700
+ };
14701
+ },
14702
+ addStorage() {
14703
+ return { isDisabled: false };
14704
+ },
14705
+ onCreate() {
14706
+ if (this.editor.extensionManager.extensions.find((extension) => extension.name === "undoRedo")) console.warn("[tiptap warn]: \"@tiptap/extension-collaboration\" comes with its own history support and is not compatible with \"@tiptap/extension-undo-redo\".");
14707
+ },
14708
+ onBeforeCreate() {
14709
+ this.editor.utils.getUpdatedPosition = (position, transaction) => getUpdatedPosition(position, transaction, this.editor.state);
14710
+ this.editor.utils.createMappablePosition = (position) => createMappablePosition(position, this.editor.state);
14711
+ },
14712
+ addCommands() {
14713
+ return {
14714
+ undo: () => ({ tr, state, dispatch }) => {
14715
+ tr.setMeta("preventDispatch", true);
14716
+ if (yUndoPluginKey.getState(state).undoManager.undoStack.length === 0) return false;
14717
+ if (!dispatch) return true;
14718
+ return undo(state);
14719
+ },
14720
+ redo: () => ({ tr, state, dispatch }) => {
14721
+ tr.setMeta("preventDispatch", true);
14722
+ if (yUndoPluginKey.getState(state).undoManager.redoStack.length === 0) return false;
14723
+ if (!dispatch) return true;
14724
+ return redo(state);
14725
+ }
14726
+ };
14727
+ },
14728
+ addKeyboardShortcuts() {
14729
+ return {
14730
+ "Mod-z": () => this.editor.commands.undo(),
14731
+ "Mod-y": () => this.editor.commands.redo(),
14732
+ "Shift-Mod-z": () => this.editor.commands.redo()
14733
+ };
14734
+ },
14735
+ addProseMirrorPlugins() {
14736
+ const fragment = this.options.fragment ? this.options.fragment : this.options.document.getXmlFragment(this.options.field);
14737
+ const yUndoPluginInstance = yUndoPlugin(this.options.yUndoOptions);
14738
+ const originalUndoPluginView = yUndoPluginInstance.spec.view;
14739
+ yUndoPluginInstance.spec.view = (view) => {
14740
+ const { undoManager } = yUndoPluginKey.getState(view.state);
14741
+ if (undoManager.restore) {
14742
+ undoManager.restore();
14743
+ undoManager.restore = () => {};
14744
+ }
14745
+ const viewRet = originalUndoPluginView ? originalUndoPluginView(view) : void 0;
14746
+ return { destroy: () => {
14747
+ const hasUndoManSelf = undoManager.trackedOrigins.has(undoManager);
14748
+ const observers = undoManager._observers;
14749
+ undoManager.restore = () => {
14750
+ if (hasUndoManSelf) undoManager.trackedOrigins.add(undoManager);
14751
+ undoManager.doc.on("afterTransaction", undoManager.afterTransactionHandler);
14752
+ undoManager._observers = observers;
14753
+ };
14754
+ if (viewRet === null || viewRet === void 0 ? void 0 : viewRet.destroy) viewRet.destroy();
14755
+ } };
14756
+ };
14757
+ const ySyncPluginOptions = {
14758
+ ...this.options.ySyncOptions,
14759
+ onFirstRender: this.options.onFirstRender
14760
+ };
14761
+ return [
14762
+ ySyncPlugin(fragment, ySyncPluginOptions),
14763
+ yUndoPluginInstance,
14764
+ new Plugin({ filterTransaction: (transaction, state) => {
14765
+ if (transaction.getMeta("inputRule")) yUndoPluginKey.getState(state).undoManager.stopCapturing();
14766
+ return true;
14767
+ } }),
14768
+ this.editor.options.enableContentCheck && new Plugin({
14769
+ key: new PluginKey("filterInvalidContent"),
14770
+ filterTransaction: (transaction) => {
14771
+ if (!isChangeOrigin(transaction)) return true;
14772
+ if (this.storage.isDisabled) return false;
14773
+ if (!transaction.docChanged) return true;
14774
+ try {
14775
+ transaction.doc.check();
14776
+ return true;
14777
+ } catch (error) {
14778
+ this.storage.isDisabled = true;
14779
+ this.editor.emit("contentError", {
14780
+ error,
14781
+ editor: this.editor,
14782
+ disableCollaboration: () => {
14783
+ var _fragment$doc;
14784
+ (_fragment$doc = fragment.doc) === null || _fragment$doc === void 0 || _fragment$doc.destroy();
14785
+ }
14786
+ });
14787
+ return true;
14788
+ }
14789
+ }
14790
+ })
14791
+ ].filter(Boolean);
14792
+ }
14760
14793
  });
14761
14794
 
14762
- // src/node-range.ts
14795
+ //#region src/helpers/getNodeRangeDecorations.ts
14763
14796
  function getNodeRangeDecorations(ranges) {
14764
- if (!ranges.length) {
14765
- return DecorationSet.empty;
14766
- }
14767
- const decorations = [];
14768
- const doc = ranges[0].$from.node(0);
14769
- ranges.forEach((range) => {
14770
- const pos = range.$from.pos;
14771
- const node = range.$from.nodeAfter;
14772
- if (!node) {
14773
- return;
14774
- }
14775
- decorations.push(
14776
- Decoration.node(pos, pos + node.nodeSize, {
14777
- class: "ProseMirror-selectednoderange"
14778
- })
14779
- );
14780
- });
14781
- return DecorationSet.create(doc, decorations);
14797
+ if (!ranges.length) return DecorationSet.empty;
14798
+ const decorations = [];
14799
+ const doc = ranges[0].$from.node(0);
14800
+ ranges.forEach((range) => {
14801
+ const pos = range.$from.pos;
14802
+ const node = range.$from.nodeAfter;
14803
+ if (!node) return;
14804
+ decorations.push(Decoration.node(pos, pos + node.nodeSize, { class: "ProseMirror-selectednoderange" }));
14805
+ });
14806
+ return DecorationSet.create(doc, decorations);
14782
14807
  }
14808
+ //#endregion
14809
+ //#region src/helpers/getSelectionRanges.ts
14783
14810
  function getNodeContentBounds(nodeStart, nodeSize, node) {
14784
- const contentOffset = node.isText || node.isAtom ? 0 : 1;
14785
- return {
14786
- start: nodeStart + contentOffset,
14787
- end: nodeStart + nodeSize - contentOffset
14788
- };
14811
+ const contentOffset = node.isText || node.isAtom ? 0 : 1;
14812
+ return {
14813
+ start: nodeStart + contentOffset,
14814
+ end: nodeStart + nodeSize - contentOffset
14815
+ };
14789
14816
  }
14817
+ /**
14818
+ * Calculates node-aligned selection ranges between two resolved positions.
14819
+ *
14820
+ * The helper derives a suitable depth when none is provided and returns a
14821
+ * `SelectionRange` for each matching child node in the computed `NodeRange`.
14822
+ * Each returned range exposes `$from` as the resolved start position of the
14823
+ * node selection and `$to` as the resolved end position.
14824
+ *
14825
+ * @param $from The resolved anchor position where the selection starts.
14826
+ * @param $to The resolved head position where the selection ends.
14827
+ * @param depth An optional depth to force when creating the ProseMirror `NodeRange`.
14828
+ * When omitted, the depth is inferred from the shared depth of `$from` and `$to`.
14829
+ * @param options Optional behavior flags for how boundary nodes are handled.
14830
+ * @param options.extendOnBoundaryOverlap Whether touching only a node's start
14831
+ * or end content boundary should still include that node in the returned ranges.
14832
+ * @returns An array of `SelectionRange` objects for the nodes covered at the
14833
+ * computed depth.
14834
+ * @example
14835
+ * ```ts
14836
+ * const { $from, $to } = editor.state.selection
14837
+ * const ranges = getSelectionRanges($from, $to, undefined, {
14838
+ * extendOnBoundaryOverlap: false,
14839
+ * })
14840
+ *
14841
+ * ranges.forEach(range => {
14842
+ * console.log(range.$from.pos, range.$to.pos)
14843
+ * })
14844
+ * ```
14845
+ */
14790
14846
  function getSelectionRanges($from, $to, depth, options = {}) {
14791
- const ranges = [];
14792
- const doc = $from.node(0);
14793
- const { extendOnBoundaryOverlap = true } = options;
14794
- if (typeof depth === "number" && depth >= 0) ; else if ($from.sameParent($to)) {
14795
- depth = Math.max(0, $from.sharedDepth($to.pos) - 1);
14796
- } else {
14797
- depth = $from.sharedDepth($to.pos);
14798
- }
14799
- const nodeRange = new NodeRange($from, $to, depth);
14800
- const offset = nodeRange.depth === 0 ? 0 : doc.resolve(nodeRange.start).posAtIndex(0);
14801
- nodeRange.parent.forEach((node, pos) => {
14802
- const from = offset + pos;
14803
- const to = from + node.nodeSize;
14804
- const contentBounds = getNodeContentBounds(from, node.nodeSize, node);
14805
- const overlapsNodeContent = extendOnBoundaryOverlap ? $to.pos >= contentBounds.start && $from.pos <= contentBounds.end : $to.pos > contentBounds.start && $from.pos < contentBounds.end;
14806
- if (from < nodeRange.start || from >= nodeRange.end) {
14807
- return;
14808
- }
14809
- if (!overlapsNodeContent) {
14810
- return;
14811
- }
14812
- const selectionRange = new SelectionRange(doc.resolve(from), doc.resolve(to));
14813
- ranges.push(selectionRange);
14814
- });
14815
- return ranges;
14847
+ const ranges = [];
14848
+ const doc = $from.node(0);
14849
+ const { extendOnBoundaryOverlap = true } = options;
14850
+ if (typeof depth === "number" && depth >= 0) ; else if ($from.sameParent($to)) depth = Math.max(0, $from.sharedDepth($to.pos) - 1);
14851
+ else depth = $from.sharedDepth($to.pos);
14852
+ const nodeRange = new NodeRange($from, $to, depth);
14853
+ const offset = nodeRange.depth === 0 ? 0 : doc.resolve(nodeRange.start).posAtIndex(0);
14854
+ nodeRange.parent.forEach((node, pos) => {
14855
+ const from = offset + pos;
14856
+ const to = from + node.nodeSize;
14857
+ const contentBounds = getNodeContentBounds(from, node.nodeSize, node);
14858
+ const overlapsNodeContent = extendOnBoundaryOverlap ? $to.pos >= contentBounds.start && $from.pos <= contentBounds.end : $to.pos > contentBounds.start && $from.pos < contentBounds.end;
14859
+ if (from < nodeRange.start || from >= nodeRange.end) return;
14860
+ if (!overlapsNodeContent) return;
14861
+ const selectionRange = new SelectionRange(doc.resolve(from), doc.resolve(to));
14862
+ ranges.push(selectionRange);
14863
+ });
14864
+ return ranges;
14816
14865
  }
14817
-
14818
- // src/helpers/NodeRangeBookmark.ts
14819
- var NodeRangeBookmark = class _NodeRangeBookmark {
14820
- constructor(anchor, head, depth) {
14821
- this.anchor = anchor;
14822
- this.head = head;
14823
- this.depth = depth != null ? depth : 0;
14824
- }
14825
- map(mapping) {
14826
- return new _NodeRangeBookmark(mapping.map(this.anchor), mapping.map(this.head), this.depth);
14827
- }
14828
- resolve(doc) {
14829
- const $anchor = doc.resolve(this.anchor);
14830
- const $head = doc.resolve(this.head);
14831
- return new NodeRangeSelection($anchor, $head, this.depth);
14832
- }
14833
- };
14834
-
14835
- // src/helpers/NodeRangeSelection.ts
14836
- var NodeRangeSelection = class _NodeRangeSelection extends Selection {
14837
- constructor($anchor, $head, depth, bias = 1) {
14838
- const { doc } = $anchor;
14839
- const isCursor = $anchor === $head;
14840
- const isCursorAtEnd = $anchor.pos === doc.content.size && $head.pos === doc.content.size;
14841
- const $correctedHead = isCursor && !isCursorAtEnd ? doc.resolve($head.pos + (bias > 0 ? 1 : -1)) : $head;
14842
- const $correctedAnchor = isCursor && isCursorAtEnd ? doc.resolve($anchor.pos - (bias > 0 ? 1 : -1)) : $anchor;
14843
- const ranges = getSelectionRanges(
14844
- $correctedAnchor.min($correctedHead),
14845
- $correctedAnchor.max($correctedHead),
14846
- depth
14847
- );
14848
- const $rangeFrom = $correctedHead.pos >= $anchor.pos ? ranges[0].$from : ranges[ranges.length - 1].$to;
14849
- const $rangeTo = $correctedHead.pos >= $anchor.pos ? ranges[ranges.length - 1].$to : ranges[0].$from;
14850
- super($rangeFrom, $rangeTo, ranges);
14851
- this.depth = depth;
14852
- }
14853
- // we can safely ignore this TypeScript error: https://github.com/Microsoft/TypeScript/issues/338
14854
- // @ts-ignore
14855
- get $to() {
14856
- return this.ranges[this.ranges.length - 1].$to;
14857
- }
14858
- eq(other) {
14859
- return other instanceof _NodeRangeSelection && other.$from.pos === this.$from.pos && other.$to.pos === this.$to.pos;
14860
- }
14861
- map(doc, mapping) {
14862
- const $anchor = doc.resolve(mapping.map(this.anchor));
14863
- const $head = doc.resolve(mapping.map(this.head));
14864
- return new _NodeRangeSelection($anchor, $head, this.depth);
14865
- }
14866
- toJSON() {
14867
- return {
14868
- type: "nodeRange",
14869
- anchor: this.anchor,
14870
- head: this.head,
14871
- depth: this.depth
14872
- };
14873
- }
14874
- get isForwards() {
14875
- return this.head >= this.anchor;
14876
- }
14877
- get isBackwards() {
14878
- return !this.isForwards;
14879
- }
14880
- extendBackwards() {
14881
- const { doc } = this.$from;
14882
- if (this.isForwards && this.ranges.length > 1) {
14883
- const ranges = this.ranges.slice(0, -1);
14884
- const $from2 = ranges[0].$from;
14885
- const $to = ranges[ranges.length - 1].$to;
14886
- return new _NodeRangeSelection($from2, $to, this.depth);
14887
- }
14888
- const firstRange = this.ranges[0];
14889
- const $from = doc.resolve(Math.max(0, firstRange.$from.pos - 1));
14890
- return new _NodeRangeSelection(this.$anchor, $from, this.depth);
14891
- }
14892
- extendForwards() {
14893
- const { doc } = this.$from;
14894
- if (this.isBackwards && this.ranges.length > 1) {
14895
- const ranges = this.ranges.slice(1);
14896
- const $from = ranges[0].$from;
14897
- const $to2 = ranges[ranges.length - 1].$to;
14898
- return new _NodeRangeSelection($to2, $from, this.depth);
14899
- }
14900
- const lastRange = this.ranges[this.ranges.length - 1];
14901
- const $to = doc.resolve(Math.min(doc.content.size, lastRange.$to.pos + 1));
14902
- return new _NodeRangeSelection(this.$anchor, $to, this.depth);
14903
- }
14904
- static fromJSON(doc, json) {
14905
- return new _NodeRangeSelection(doc.resolve(json.anchor), doc.resolve(json.head), json.depth);
14906
- }
14907
- static create(doc, anchor, head, depth, bias = 1) {
14908
- return new this(doc.resolve(anchor), doc.resolve(head), depth, bias);
14909
- }
14910
- getBookmark() {
14911
- return new NodeRangeBookmark(this.anchor, this.head, this.depth);
14912
- }
14866
+ //#endregion
14867
+ //#region src/helpers/NodeRangeBookmark.ts
14868
+ var NodeRangeBookmark = class NodeRangeBookmark {
14869
+ constructor(anchor, head, depth) {
14870
+ this.anchor = anchor;
14871
+ this.head = head;
14872
+ this.depth = depth !== null && depth !== void 0 ? depth : 0;
14873
+ }
14874
+ map(mapping) {
14875
+ return new NodeRangeBookmark(mapping.map(this.anchor), mapping.map(this.head), this.depth);
14876
+ }
14877
+ resolve(doc) {
14878
+ return new NodeRangeSelection(doc.resolve(this.anchor), doc.resolve(this.head), this.depth);
14879
+ }
14880
+ };
14881
+ //#endregion
14882
+ //#region src/helpers/NodeRangeSelection.ts
14883
+ var NodeRangeSelection = class NodeRangeSelection extends Selection {
14884
+ constructor($anchor, $head, depth, bias = 1) {
14885
+ const { doc } = $anchor;
14886
+ const isCursor = $anchor === $head;
14887
+ const isCursorAtEnd = $anchor.pos === doc.content.size && $head.pos === doc.content.size;
14888
+ const $correctedHead = isCursor && !isCursorAtEnd ? doc.resolve($head.pos + (bias > 0 ? 1 : -1)) : $head;
14889
+ const $correctedAnchor = isCursor && isCursorAtEnd ? doc.resolve($anchor.pos - (bias > 0 ? 1 : -1)) : $anchor;
14890
+ const ranges = getSelectionRanges($correctedAnchor.min($correctedHead), $correctedAnchor.max($correctedHead), depth);
14891
+ const $rangeFrom = $correctedHead.pos >= $anchor.pos ? ranges[0].$from : ranges[ranges.length - 1].$to;
14892
+ const $rangeTo = $correctedHead.pos >= $anchor.pos ? ranges[ranges.length - 1].$to : ranges[0].$from;
14893
+ super($rangeFrom, $rangeTo, ranges);
14894
+ this.depth = depth;
14895
+ }
14896
+ get $to() {
14897
+ return this.ranges[this.ranges.length - 1].$to;
14898
+ }
14899
+ eq(other) {
14900
+ return other instanceof NodeRangeSelection && other.$from.pos === this.$from.pos && other.$to.pos === this.$to.pos;
14901
+ }
14902
+ map(doc, mapping) {
14903
+ const $anchor = doc.resolve(mapping.map(this.anchor));
14904
+ const $head = doc.resolve(mapping.map(this.head));
14905
+ return new NodeRangeSelection($anchor, $head, this.depth);
14906
+ }
14907
+ toJSON() {
14908
+ return {
14909
+ type: "nodeRange",
14910
+ anchor: this.anchor,
14911
+ head: this.head,
14912
+ depth: this.depth
14913
+ };
14914
+ }
14915
+ get isForwards() {
14916
+ return this.head >= this.anchor;
14917
+ }
14918
+ get isBackwards() {
14919
+ return !this.isForwards;
14920
+ }
14921
+ extendBackwards() {
14922
+ const { doc } = this.$from;
14923
+ if (this.isForwards && this.ranges.length > 1) {
14924
+ const ranges = this.ranges.slice(0, -1);
14925
+ const $from = ranges[0].$from;
14926
+ const $to = ranges[ranges.length - 1].$to;
14927
+ return new NodeRangeSelection($from, $to, this.depth);
14928
+ }
14929
+ const firstRange = this.ranges[0];
14930
+ const $from = doc.resolve(Math.max(0, firstRange.$from.pos - 1));
14931
+ return new NodeRangeSelection(this.$anchor, $from, this.depth);
14932
+ }
14933
+ extendForwards() {
14934
+ const { doc } = this.$from;
14935
+ if (this.isBackwards && this.ranges.length > 1) {
14936
+ const ranges = this.ranges.slice(1);
14937
+ const $from = ranges[0].$from;
14938
+ const $to = ranges[ranges.length - 1].$to;
14939
+ return new NodeRangeSelection($to, $from, this.depth);
14940
+ }
14941
+ const lastRange = this.ranges[this.ranges.length - 1];
14942
+ const $to = doc.resolve(Math.min(doc.content.size, lastRange.$to.pos + 1));
14943
+ return new NodeRangeSelection(this.$anchor, $to, this.depth);
14944
+ }
14945
+ static fromJSON(doc, json) {
14946
+ return new NodeRangeSelection(doc.resolve(json.anchor), doc.resolve(json.head), json.depth);
14947
+ }
14948
+ static create(doc, anchor, head, depth, bias = 1) {
14949
+ return new this(doc.resolve(anchor), doc.resolve(head), depth, bias);
14950
+ }
14951
+ getBookmark() {
14952
+ return new NodeRangeBookmark(this.anchor, this.head, this.depth);
14953
+ }
14913
14954
  };
14914
14955
  NodeRangeSelection.prototype.visible = false;
14915
14956
  try {
14916
- Selection.jsonID("nodeRange", NodeRangeSelection);
14917
- } catch {
14918
- }
14919
-
14920
- // src/helpers/isNodeRangeSelection.ts
14957
+ Selection.jsonID("nodeRange", NodeRangeSelection);
14958
+ } catch {}
14959
+ //#endregion
14960
+ //#region src/helpers/isNodeRangeSelection.ts
14921
14961
  function isNodeRangeSelection(value) {
14922
- return value instanceof NodeRangeSelection;
14962
+ return value instanceof NodeRangeSelection;
14923
14963
  }
14924
-
14925
- // src/node-range.ts
14964
+ //#endregion
14965
+ //#region src/node-range.ts
14926
14966
  Extension.create({
14927
- name: "nodeRange",
14928
- addOptions() {
14929
- return {
14930
- depth: void 0,
14931
- key: "Mod"
14932
- };
14933
- },
14934
- addKeyboardShortcuts() {
14935
- return {
14936
- // extend NodeRangeSelection upwards
14937
- "Shift-ArrowUp": ({ editor }) => {
14938
- const { depth } = this.options;
14939
- const { view, state } = editor;
14940
- const { doc, selection, tr } = state;
14941
- const { anchor, head } = selection;
14942
- if (!isNodeRangeSelection(selection)) {
14943
- const nodeRangeSelection2 = NodeRangeSelection.create(doc, anchor, head, depth, -1);
14944
- tr.setSelection(nodeRangeSelection2);
14945
- view.dispatch(tr);
14946
- return true;
14947
- }
14948
- const nodeRangeSelection = selection.extendBackwards();
14949
- tr.setSelection(nodeRangeSelection);
14950
- view.dispatch(tr);
14951
- return true;
14952
- },
14953
- // extend NodeRangeSelection downwards
14954
- "Shift-ArrowDown": ({ editor }) => {
14955
- const { depth } = this.options;
14956
- const { view, state } = editor;
14957
- const { doc, selection, tr } = state;
14958
- const { anchor, head } = selection;
14959
- if (!isNodeRangeSelection(selection)) {
14960
- const nodeRangeSelection2 = NodeRangeSelection.create(doc, anchor, head, depth);
14961
- tr.setSelection(nodeRangeSelection2);
14962
- view.dispatch(tr);
14963
- return true;
14964
- }
14965
- const nodeRangeSelection = selection.extendForwards();
14966
- tr.setSelection(nodeRangeSelection);
14967
- view.dispatch(tr);
14968
- return true;
14969
- },
14970
- // add `NodeRangeSelection` to all nodes
14971
- "Mod-a": ({ editor }) => {
14972
- const { depth } = this.options;
14973
- const { view, state } = editor;
14974
- const { doc, tr } = state;
14975
- const nodeRangeSelection = NodeRangeSelection.create(doc, 0, doc.content.size, depth);
14976
- tr.setSelection(nodeRangeSelection);
14977
- view.dispatch(tr);
14978
- return true;
14979
- }
14980
- };
14981
- },
14982
- onSelectionUpdate() {
14983
- const { selection } = this.editor.state;
14984
- if (isNodeRangeSelection(selection)) {
14985
- this.editor.view.dom.classList.add("ProseMirror-noderangeselection");
14986
- }
14987
- },
14988
- addProseMirrorPlugins() {
14989
- let hideTextSelection = false;
14990
- let activeMouseSelection = false;
14991
- return [
14992
- new Plugin({
14993
- key: new PluginKey("nodeRange"),
14994
- props: {
14995
- attributes: () => {
14996
- if (hideTextSelection) {
14997
- return {
14998
- class: "ProseMirror-noderangeselection"
14999
- };
15000
- }
15001
- return { class: "" };
15002
- },
15003
- handleDOMEvents: {
15004
- mousedown: (view, event) => {
15005
- const { key } = this.options;
15006
- const isMac = /Mac/.test(navigator.platform);
15007
- const isShift = !!event.shiftKey;
15008
- const isControl = !!event.ctrlKey;
15009
- const isAlt = !!event.altKey;
15010
- const isMeta = !!event.metaKey;
15011
- const isMod = isMac ? isMeta : isControl;
15012
- if (key === null || key === void 0 || key === "Shift" && isShift || key === "Control" && isControl || key === "Alt" && isAlt || key === "Meta" && isMeta || key === "Mod" && isMod) {
15013
- activeMouseSelection = true;
15014
- }
15015
- if (!activeMouseSelection) {
15016
- return false;
15017
- }
15018
- document.addEventListener(
15019
- "mouseup",
15020
- () => {
15021
- activeMouseSelection = false;
15022
- const { state } = view;
15023
- const { doc, selection, tr } = state;
15024
- const { $anchor, $head } = selection;
15025
- if ($anchor.sameParent($head)) {
15026
- return;
15027
- }
15028
- const nodeRangeSelection = NodeRangeSelection.create(
15029
- doc,
15030
- $anchor.pos,
15031
- $head.pos,
15032
- this.options.depth
15033
- );
15034
- tr.setSelection(nodeRangeSelection);
15035
- view.dispatch(tr);
15036
- },
15037
- { once: true }
15038
- );
15039
- return false;
15040
- }
15041
- },
15042
- // when selecting some text we want to render some decorations
15043
- // to preview a `NodeRangeSelection`
15044
- decorations: (state) => {
15045
- const { selection } = state;
15046
- const isNodeRange = isNodeRangeSelection(selection);
15047
- hideTextSelection = false;
15048
- if (!activeMouseSelection) {
15049
- if (!isNodeRange) {
15050
- return null;
15051
- }
15052
- hideTextSelection = true;
15053
- return getNodeRangeDecorations(selection.ranges);
15054
- }
15055
- const { $from, $to } = selection;
15056
- if (!isNodeRange && $from.sameParent($to)) {
15057
- return null;
15058
- }
15059
- const nodeRanges = getSelectionRanges($from, $to, this.options.depth);
15060
- if (!nodeRanges.length) {
15061
- return null;
15062
- }
15063
- hideTextSelection = true;
15064
- return getNodeRangeDecorations(nodeRanges);
15065
- }
15066
- }
15067
- })
15068
- ];
15069
- }
14967
+ name: "nodeRange",
14968
+ addOptions() {
14969
+ return {
14970
+ depth: void 0,
14971
+ key: "Mod"
14972
+ };
14973
+ },
14974
+ addKeyboardShortcuts() {
14975
+ return {
14976
+ "Shift-ArrowUp": ({ editor }) => {
14977
+ const { depth } = this.options;
14978
+ const { view, state } = editor;
14979
+ const { doc, selection, tr } = state;
14980
+ const { anchor, head } = selection;
14981
+ if (!isNodeRangeSelection(selection)) {
14982
+ const nodeRangeSelection = NodeRangeSelection.create(doc, anchor, head, depth, -1);
14983
+ tr.setSelection(nodeRangeSelection);
14984
+ view.dispatch(tr);
14985
+ return true;
14986
+ }
14987
+ const nodeRangeSelection = selection.extendBackwards();
14988
+ tr.setSelection(nodeRangeSelection);
14989
+ view.dispatch(tr);
14990
+ return true;
14991
+ },
14992
+ "Shift-ArrowDown": ({ editor }) => {
14993
+ const { depth } = this.options;
14994
+ const { view, state } = editor;
14995
+ const { doc, selection, tr } = state;
14996
+ const { anchor, head } = selection;
14997
+ if (!isNodeRangeSelection(selection)) {
14998
+ const nodeRangeSelection = NodeRangeSelection.create(doc, anchor, head, depth);
14999
+ tr.setSelection(nodeRangeSelection);
15000
+ view.dispatch(tr);
15001
+ return true;
15002
+ }
15003
+ const nodeRangeSelection = selection.extendForwards();
15004
+ tr.setSelection(nodeRangeSelection);
15005
+ view.dispatch(tr);
15006
+ return true;
15007
+ },
15008
+ "Mod-a": ({ editor }) => {
15009
+ const { depth } = this.options;
15010
+ const { view, state } = editor;
15011
+ const { doc, tr } = state;
15012
+ const nodeRangeSelection = NodeRangeSelection.create(doc, 0, doc.content.size, depth);
15013
+ tr.setSelection(nodeRangeSelection);
15014
+ view.dispatch(tr);
15015
+ return true;
15016
+ }
15017
+ };
15018
+ },
15019
+ onSelectionUpdate() {
15020
+ const { selection } = this.editor.state;
15021
+ if (isNodeRangeSelection(selection)) this.editor.view.dom.classList.add("ProseMirror-noderangeselection");
15022
+ },
15023
+ addProseMirrorPlugins() {
15024
+ let hideTextSelection = false;
15025
+ let activeMouseSelection = false;
15026
+ return [new Plugin({
15027
+ key: new PluginKey("nodeRange"),
15028
+ props: {
15029
+ attributes: () => {
15030
+ if (hideTextSelection) return { class: "ProseMirror-noderangeselection" };
15031
+ return { class: "" };
15032
+ },
15033
+ handleDOMEvents: { mousedown: (view, event) => {
15034
+ const { key } = this.options;
15035
+ const isMac = /Mac/.test(navigator.platform);
15036
+ const isShift = !!event.shiftKey;
15037
+ const isControl = !!event.ctrlKey;
15038
+ const isAlt = !!event.altKey;
15039
+ const isMeta = !!event.metaKey;
15040
+ if (key === null || key === void 0 || key === "Shift" && isShift || key === "Control" && isControl || key === "Alt" && isAlt || key === "Meta" && isMeta || key === "Mod" && (isMac ? isMeta : isControl)) activeMouseSelection = true;
15041
+ if (!activeMouseSelection) return false;
15042
+ document.addEventListener("mouseup", () => {
15043
+ activeMouseSelection = false;
15044
+ const { state } = view;
15045
+ const { doc, selection, tr } = state;
15046
+ const { $anchor, $head } = selection;
15047
+ if ($anchor.sameParent($head)) return;
15048
+ const nodeRangeSelection = NodeRangeSelection.create(doc, $anchor.pos, $head.pos, this.options.depth);
15049
+ tr.setSelection(nodeRangeSelection);
15050
+ view.dispatch(tr);
15051
+ }, { once: true });
15052
+ return false;
15053
+ } },
15054
+ decorations: (state) => {
15055
+ const { selection } = state;
15056
+ const isNodeRange = isNodeRangeSelection(selection);
15057
+ hideTextSelection = false;
15058
+ if (!activeMouseSelection) {
15059
+ if (!isNodeRange) return null;
15060
+ hideTextSelection = true;
15061
+ return getNodeRangeDecorations(selection.ranges);
15062
+ }
15063
+ const { $from, $to } = selection;
15064
+ if (!isNodeRange && $from.sameParent($to)) return null;
15065
+ const nodeRanges = getSelectionRanges($from, $to, this.options.depth);
15066
+ if (!nodeRanges.length) return null;
15067
+ hideTextSelection = true;
15068
+ return getNodeRangeDecorations(nodeRanges);
15069
+ }
15070
+ }
15071
+ })];
15072
+ }
15070
15073
  });
15071
15074
 
15072
- // src/drag-handle.ts
15073
-
15074
- // src/helpers/cloneElement.ts
15075
+ //#region src/helpers/cloneElement.ts
15075
15076
  function getCSSText(element, properties) {
15076
- const style = getComputedStyle(element);
15077
- if (properties) {
15078
- return properties.map((property) => property.trim()).filter((property) => property.length > 0).map((property) => `${property}:${style.getPropertyValue(property)};`).join("");
15079
- }
15080
- let value = "";
15081
- for (let i = 0; i < style.length; i += 1) {
15082
- value += `${style[i]}:${style.getPropertyValue(style[i])};`;
15083
- }
15084
- return value;
15077
+ const style = getComputedStyle(element);
15078
+ if (properties) return properties.map((property) => property.trim()).filter((property) => property.length > 0).map((property) => `${property}:${style.getPropertyValue(property)};`).join("");
15079
+ let value = "";
15080
+ for (let i = 0; i < style.length; i += 1) value += `${style[i]}:${style.getPropertyValue(style[i])};`;
15081
+ return value;
15085
15082
  }
15086
15083
  function cloneElement(node, properties) {
15087
- const clonedNode = node.cloneNode(true);
15088
- const sourceElements = [node, ...Array.from(node.getElementsByTagName("*"))];
15089
- const targetElements = [
15090
- clonedNode,
15091
- ...Array.from(clonedNode.getElementsByTagName("*"))
15092
- ];
15093
- sourceElements.forEach((sourceElement, index) => {
15094
- targetElements[index].style.cssText = getCSSText(sourceElement, properties);
15095
- });
15096
- return clonedNode;
15084
+ const clonedNode = node.cloneNode(true);
15085
+ const sourceElements = [node, ...Array.from(node.getElementsByTagName("*"))];
15086
+ const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName("*"))];
15087
+ sourceElements.forEach((sourceElement, index) => {
15088
+ targetElements[index].style.cssText = getCSSText(sourceElement, properties);
15089
+ });
15090
+ return clonedNode;
15097
15091
  }
15098
-
15099
- // src/helpers/defaultRules.ts
15100
- var listItemFirstChild = {
15101
- id: "listItemFirstChild",
15102
- evaluate: ({ parent, isFirst }) => {
15103
- if (!isFirst) {
15104
- return 0;
15105
- }
15106
- const listItemTypes = ["listItem", "taskItem"];
15107
- if (parent && listItemTypes.includes(parent.type.name)) {
15108
- return 1e3;
15109
- }
15110
- return 0;
15111
- }
15112
- };
15113
- var listWrapperDeprioritize = {
15114
- id: "listWrapperDeprioritize",
15115
- evaluate: ({ node }) => {
15116
- const listItemTypes = ["listItem", "taskItem"];
15117
- const firstChild = node.firstChild;
15118
- if (firstChild && listItemTypes.includes(firstChild.type.name)) {
15119
- return 1e3;
15120
- }
15121
- return 0;
15122
- }
15123
- };
15124
- var tableStructure = {
15125
- id: "tableStructure",
15126
- evaluate: ({ node, parent }) => {
15127
- const tableStructureTypes = ["tableRow", "tableCell", "tableHeader"];
15128
- if (tableStructureTypes.includes(node.type.name)) {
15129
- return 1e3;
15130
- }
15131
- if (parent && parent.type.name === "tableHeader") {
15132
- return 1e3;
15133
- }
15134
- return 0;
15135
- }
15136
- };
15137
- var inlineContent = {
15138
- id: "inlineContent",
15139
- evaluate: ({ node }) => {
15140
- if (node.isInline || node.isText) {
15141
- return 1e3;
15142
- }
15143
- return 0;
15144
- }
15145
- };
15146
- var defaultRules = [
15147
- listItemFirstChild,
15148
- listWrapperDeprioritize,
15149
- tableStructure,
15150
- inlineContent
15092
+ /**
15093
+ * All default rules.
15094
+ * Users can extend these or replace them entirely.
15095
+ */
15096
+ const defaultRules = [
15097
+ {
15098
+ id: "listItemFirstChild",
15099
+ evaluate: ({ parent, isFirst }) => {
15100
+ if (!isFirst) return 0;
15101
+ if (parent && ["listItem", "taskItem"].includes(parent.type.name)) return 1e3;
15102
+ return 0;
15103
+ }
15104
+ },
15105
+ {
15106
+ id: "listWrapperDeprioritize",
15107
+ evaluate: ({ node }) => {
15108
+ const listItemTypes = ["listItem", "taskItem"];
15109
+ const firstChild = node.firstChild;
15110
+ if (firstChild && listItemTypes.includes(firstChild.type.name)) return 1e3;
15111
+ return 0;
15112
+ }
15113
+ },
15114
+ {
15115
+ id: "tableStructure",
15116
+ evaluate: ({ node, parent }) => {
15117
+ if ([
15118
+ "tableRow",
15119
+ "tableCell",
15120
+ "tableHeader"
15121
+ ].includes(node.type.name)) return 1e3;
15122
+ if (parent && parent.type.name === "tableHeader") return 1e3;
15123
+ return 0;
15124
+ }
15125
+ },
15126
+ {
15127
+ id: "inlineContent",
15128
+ evaluate: ({ node }) => {
15129
+ if (node.isInline || node.isText) return 1e3;
15130
+ return 0;
15131
+ }
15132
+ }
15151
15133
  ];
15152
-
15153
- // src/helpers/edgeDetection.ts
15154
- var DEFAULT_EDGE_CONFIG = {
15155
- edges: ["left", "top"],
15156
- threshold: 12,
15157
- strength: 500
15158
- };
15134
+ //#endregion
15135
+ //#region src/helpers/edgeDetection.ts
15136
+ /**
15137
+ * Default edge detection configuration.
15138
+ */
15139
+ const DEFAULT_EDGE_CONFIG = {
15140
+ edges: ["left", "top"],
15141
+ threshold: 12,
15142
+ strength: 500
15143
+ };
15144
+ /**
15145
+ * Normalizes edge detection presets or custom config into a full config object.
15146
+ * Partial configs are merged with defaults.
15147
+ *
15148
+ * @param input - The preset string or partial/full config
15149
+ * @returns A complete EdgeDetectionConfig
15150
+ */
15159
15151
  function normalizeEdgeDetection(input) {
15160
- if (input === void 0 || input === "left") {
15161
- return { ...DEFAULT_EDGE_CONFIG };
15162
- }
15163
- if (input === "right") {
15164
- return { edges: ["right", "top"], threshold: 12, strength: 500 };
15165
- }
15166
- if (input === "both") {
15167
- return { edges: ["left", "right", "top"], threshold: 12, strength: 500 };
15168
- }
15169
- if (input === "none") {
15170
- return { edges: [], threshold: 0, strength: 0 };
15171
- }
15172
- return { ...DEFAULT_EDGE_CONFIG, ...input };
15152
+ if (input === void 0 || input === "left") return { ...DEFAULT_EDGE_CONFIG };
15153
+ if (input === "right") return {
15154
+ edges: ["right", "top"],
15155
+ threshold: 12,
15156
+ strength: 500
15157
+ };
15158
+ if (input === "both") return {
15159
+ edges: [
15160
+ "left",
15161
+ "right",
15162
+ "top"
15163
+ ],
15164
+ threshold: 12,
15165
+ strength: 500
15166
+ };
15167
+ if (input === "none") return {
15168
+ edges: [],
15169
+ threshold: 0,
15170
+ strength: 0
15171
+ };
15172
+ return {
15173
+ ...DEFAULT_EDGE_CONFIG,
15174
+ ...input
15175
+ };
15173
15176
  }
15177
+ /**
15178
+ * Determines if cursor is near specified edges of an element.
15179
+ *
15180
+ * @param coords - The cursor coordinates
15181
+ * @param element - The element to check against
15182
+ * @param config - The edge detection configuration
15183
+ * @returns True if the cursor is near any of the configured edges
15184
+ */
15174
15185
  function isNearEdge(coords, element, config) {
15175
- if (config.edges.length === 0) {
15176
- return false;
15177
- }
15178
- const rect = element.getBoundingClientRect();
15179
- const { threshold, edges } = config;
15180
- return edges.some((edge) => {
15181
- if (edge === "left") {
15182
- return coords.x - rect.left < threshold;
15183
- }
15184
- if (edge === "right") {
15185
- return rect.right - coords.x < threshold;
15186
- }
15187
- if (edge === "top") {
15188
- return coords.y - rect.top < threshold;
15189
- }
15190
- if (edge === "bottom") {
15191
- return rect.bottom - coords.y < threshold;
15192
- }
15193
- return false;
15194
- });
15186
+ if (config.edges.length === 0) return false;
15187
+ const rect = element.getBoundingClientRect();
15188
+ const { threshold, edges } = config;
15189
+ return edges.some((edge) => {
15190
+ if (edge === "left") return coords.x - rect.left < threshold;
15191
+ if (edge === "right") return rect.right - coords.x < threshold;
15192
+ if (edge === "top") return coords.y - rect.top < threshold;
15193
+ if (edge === "bottom") return rect.bottom - coords.y < threshold;
15194
+ return false;
15195
+ });
15195
15196
  }
15197
+ /**
15198
+ * Calculates score deduction for edge proximity.
15199
+ * Deeper nodes get larger deductions when near edges,
15200
+ * making shallower (parent) nodes win.
15201
+ *
15202
+ * @param coords - The cursor coordinates
15203
+ * @param element - The element to check against (may be null)
15204
+ * @param config - The edge detection configuration
15205
+ * @param depth - The depth of the node in the document tree
15206
+ * @returns The score deduction to apply
15207
+ */
15196
15208
  function calculateEdgeDeduction(coords, element, config, depth) {
15197
- if (!element || config.edges.length === 0) {
15198
- return 0;
15199
- }
15200
- if (isNearEdge(coords, element, config)) {
15201
- return config.strength * depth;
15202
- }
15203
- return 0;
15209
+ if (!element || config.edges.length === 0) return 0;
15210
+ if (isNearEdge(coords, element, config)) return config.strength * depth;
15211
+ return 0;
15204
15212
  }
15205
-
15206
- // src/helpers/scoring.ts
15207
- var BASE_SCORE = 1e3;
15213
+ //#endregion
15214
+ //#region src/helpers/scoring.ts
15215
+ /**
15216
+ * Base score for all nodes. Rules deduct from this score.
15217
+ * A node with score <= 0 is excluded from being a drag target.
15218
+ */
15219
+ const BASE_SCORE = 1e3;
15220
+ /**
15221
+ * Calculates the drag target score for a node.
15222
+ * Higher score = more likely to be selected.
15223
+ *
15224
+ * @param context - The rule context containing node information
15225
+ * @param rules - The rules to apply
15226
+ * @param edgeConfig - The edge detection configuration
15227
+ * @param coords - The cursor coordinates
15228
+ * @returns The calculated score, or -1 if the node is excluded
15229
+ */
15208
15230
  function calculateScore(context, rules, edgeConfig, coords) {
15209
- let score = BASE_SCORE;
15210
- let excluded = false;
15211
- rules.every((rule) => {
15212
- const deduction = rule.evaluate(context);
15213
- score -= deduction;
15214
- if (score <= 0) {
15215
- excluded = true;
15216
- return false;
15217
- }
15218
- return true;
15219
- });
15220
- if (excluded) {
15221
- return -1;
15222
- }
15223
- const dom = context.view.nodeDOM(context.pos);
15224
- score -= calculateEdgeDeduction(coords, dom, edgeConfig, context.depth);
15225
- if (score <= 0) {
15226
- return -1;
15227
- }
15228
- return score;
15231
+ let score = BASE_SCORE;
15232
+ let excluded = false;
15233
+ rules.every((rule) => {
15234
+ const deduction = rule.evaluate(context);
15235
+ score -= deduction;
15236
+ if (score <= 0) {
15237
+ excluded = true;
15238
+ return false;
15239
+ }
15240
+ return true;
15241
+ });
15242
+ if (excluded) return -1;
15243
+ const dom = context.view.nodeDOM(context.pos);
15244
+ score -= calculateEdgeDeduction(coords, dom, edgeConfig, context.depth);
15245
+ if (score <= 0) return -1;
15246
+ return score;
15229
15247
  }
15230
-
15231
- // src/helpers/findBestDragTarget.ts
15248
+ //#endregion
15249
+ //#region src/helpers/findBestDragTarget.ts
15250
+ /**
15251
+ * Checks if any ancestor at or above the given depth is in the allowed list.
15252
+ *
15253
+ * @param $pos - The resolved position
15254
+ * @param depth - The current depth being checked
15255
+ * @param allowedTypes - The list of allowed node type names
15256
+ * @returns True if any ancestor is in the allowed list
15257
+ */
15232
15258
  function hasAncestorOfType($pos, depth, allowedTypes) {
15233
- const ancestorDepths = Array.from({ length: depth }, (_, i) => depth - 1 - i);
15234
- return ancestorDepths.some((d) => allowedTypes.includes($pos.node(d).type.name));
15259
+ return Array.from({ length: depth }, (_, i) => depth - 1 - i).some((d) => allowedTypes.includes($pos.node(d).type.name));
15235
15260
  }
15261
+ /**
15262
+ * Finds the best drag target at the given coordinates using the scoring system.
15263
+ *
15264
+ * @param view - The editor view
15265
+ * @param coords - The cursor coordinates
15266
+ * @param options - The normalized nested options
15267
+ * @returns The best drag target, or null if none found
15268
+ */
15236
15269
  function findBestDragTarget(view, coords, options) {
15237
- if (!Number.isFinite(coords.x) || !Number.isFinite(coords.y)) {
15238
- return null;
15239
- }
15240
- const posInfo = view.posAtCoords({ left: coords.x, top: coords.y });
15241
- if (!posInfo) {
15242
- return null;
15243
- }
15244
- const { doc } = view.state;
15245
- const $pos = doc.resolve(posInfo.pos);
15246
- const rules = [];
15247
- if (options.defaultRules) {
15248
- rules.push(...defaultRules);
15249
- }
15250
- rules.push(...options.rules);
15251
- const depthLevels = Array.from({ length: $pos.depth }, (_, i) => $pos.depth - i);
15252
- const candidates = depthLevels.map((depth) => {
15253
- const node = $pos.node(depth);
15254
- const nodePos = $pos.before(depth);
15255
- if (options.allowedContainers && depth > 0) {
15256
- const inAllowedContainer = hasAncestorOfType($pos, depth, options.allowedContainers);
15257
- if (!inAllowedContainer) {
15258
- return null;
15259
- }
15260
- }
15261
- const parent = depth > 0 ? $pos.node(depth - 1) : null;
15262
- const index = depth > 0 ? $pos.index(depth - 1) : 0;
15263
- const siblingCount = parent ? parent.childCount : 1;
15264
- const context = {
15265
- node,
15266
- pos: nodePos,
15267
- depth,
15268
- parent,
15269
- index,
15270
- isFirst: index === 0,
15271
- isLast: index === siblingCount - 1,
15272
- $pos,
15273
- view
15274
- };
15275
- const score = calculateScore(context, rules, options.edgeDetection, coords);
15276
- if (score < 0) {
15277
- return null;
15278
- }
15279
- const dom = view.nodeDOM(nodePos);
15280
- return { node, pos: nodePos, depth, score, dom };
15281
- }).filter((candidate) => candidate !== null);
15282
- const nodeAfter = $pos.nodeAfter;
15283
- if (nodeAfter && nodeAfter.isAtom && !nodeAfter.isInline) {
15284
- const nodePos = posInfo.pos;
15285
- const depth = $pos.depth + 1;
15286
- const parent = $pos.parent;
15287
- const index = $pos.index();
15288
- const siblingCount = parent.childCount;
15289
- let inAllowedContainer = true;
15290
- if (options.allowedContainers) {
15291
- inAllowedContainer = hasAncestorOfType($pos, depth, options.allowedContainers);
15292
- }
15293
- if (inAllowedContainer) {
15294
- const context = {
15295
- node: nodeAfter,
15296
- pos: nodePos,
15297
- depth,
15298
- parent,
15299
- index,
15300
- isFirst: index === 0,
15301
- isLast: index === siblingCount - 1,
15302
- $pos,
15303
- view
15304
- };
15305
- const score = calculateScore(context, rules, options.edgeDetection, coords);
15306
- if (score >= 0) {
15307
- const dom = view.nodeDOM(nodePos);
15308
- if (dom) {
15309
- candidates.push({ node: nodeAfter, pos: nodePos, depth, score, dom });
15310
- }
15311
- }
15312
- }
15313
- }
15314
- if (candidates.length === 0) {
15315
- return null;
15316
- }
15317
- candidates.sort((a, b) => {
15318
- if (b.score !== a.score) {
15319
- return b.score - a.score;
15320
- }
15321
- return b.depth - a.depth;
15322
- });
15323
- const winner = candidates[0];
15324
- if (!winner.dom) {
15325
- return null;
15326
- }
15327
- return {
15328
- node: winner.node,
15329
- pos: winner.pos,
15330
- dom: winner.dom
15331
- };
15270
+ if (!Number.isFinite(coords.x) || !Number.isFinite(coords.y)) return null;
15271
+ const posInfo = view.posAtCoords({
15272
+ left: coords.x,
15273
+ top: coords.y
15274
+ });
15275
+ if (!posInfo) return null;
15276
+ const { doc } = view.state;
15277
+ const $pos = doc.resolve(posInfo.pos);
15278
+ const rules = [];
15279
+ if (options.defaultRules) rules.push(...defaultRules);
15280
+ rules.push(...options.rules);
15281
+ const candidates = Array.from({ length: $pos.depth }, (_, i) => $pos.depth - i).map((depth) => {
15282
+ const node = $pos.node(depth);
15283
+ const nodePos = $pos.before(depth);
15284
+ if (options.allowedContainers && depth > 0) {
15285
+ if (!hasAncestorOfType($pos, depth, options.allowedContainers)) return null;
15286
+ }
15287
+ const parent = depth > 0 ? $pos.node(depth - 1) : null;
15288
+ const index = depth > 0 ? $pos.index(depth - 1) : 0;
15289
+ const siblingCount = parent ? parent.childCount : 1;
15290
+ const score = calculateScore({
15291
+ node,
15292
+ pos: nodePos,
15293
+ depth,
15294
+ parent,
15295
+ index,
15296
+ isFirst: index === 0,
15297
+ isLast: index === siblingCount - 1,
15298
+ $pos,
15299
+ view
15300
+ }, rules, options.edgeDetection, coords);
15301
+ if (score < 0) return null;
15302
+ return {
15303
+ node,
15304
+ pos: nodePos,
15305
+ depth,
15306
+ score,
15307
+ dom: view.nodeDOM(nodePos)
15308
+ };
15309
+ }).filter((candidate) => candidate !== null);
15310
+ const nodeAfter = $pos.nodeAfter;
15311
+ if (nodeAfter && nodeAfter.isAtom && !nodeAfter.isInline) {
15312
+ const nodePos = posInfo.pos;
15313
+ const depth = $pos.depth + 1;
15314
+ const parent = $pos.parent;
15315
+ const index = $pos.index();
15316
+ const siblingCount = parent.childCount;
15317
+ let inAllowedContainer = true;
15318
+ if (options.allowedContainers) inAllowedContainer = hasAncestorOfType($pos, depth, options.allowedContainers);
15319
+ if (inAllowedContainer) {
15320
+ const score = calculateScore({
15321
+ node: nodeAfter,
15322
+ pos: nodePos,
15323
+ depth,
15324
+ parent,
15325
+ index,
15326
+ isFirst: index === 0,
15327
+ isLast: index === siblingCount - 1,
15328
+ $pos,
15329
+ view
15330
+ }, rules, options.edgeDetection, coords);
15331
+ if (score >= 0) {
15332
+ const dom = view.nodeDOM(nodePos);
15333
+ if (dom) candidates.push({
15334
+ node: nodeAfter,
15335
+ pos: nodePos,
15336
+ depth,
15337
+ score,
15338
+ dom
15339
+ });
15340
+ }
15341
+ }
15342
+ }
15343
+ if (candidates.length === 0) return null;
15344
+ candidates.sort((a, b) => {
15345
+ if (b.score !== a.score) return b.score - a.score;
15346
+ return b.depth - a.depth;
15347
+ });
15348
+ const winner = candidates[0];
15349
+ if (!winner.dom) return null;
15350
+ return {
15351
+ node: winner.node,
15352
+ pos: winner.pos,
15353
+ dom: winner.dom
15354
+ };
15332
15355
  }
15333
-
15334
- // src/helpers/findNextElementFromCursor.ts
15356
+ //#endregion
15357
+ //#region src/helpers/findNextElementFromCursor.ts
15358
+ /**
15359
+ * Finds the draggable block element that is a direct child of view.dom.
15360
+ *
15361
+ * Direct children that are widget decorations rather than document content are
15362
+ * skipped — they are not draggable blocks, and treating them as such would
15363
+ * align the drag handle to the decoration (e.g. the page header) instead of the
15364
+ * actual first block on the page.
15365
+ */
15335
15366
  function findClosestTopLevelBlock(element, view) {
15336
- var _a;
15337
- let current = element;
15338
- while ((current == null ? void 0 : current.parentElement) && current.parentElement !== view.dom) {
15339
- current = current.parentElement;
15340
- }
15341
- if ((current == null ? void 0 : current.parentElement) !== view.dom) {
15342
- return void 0;
15343
- }
15344
- if (!((_a = current.pmViewDesc) == null ? void 0 : _a.node)) {
15345
- return void 0;
15346
- }
15347
- return current;
15367
+ var _pmViewDesc;
15368
+ let current = element;
15369
+ while ((current === null || current === void 0 ? void 0 : current.parentElement) && current.parentElement !== view.dom) current = current.parentElement;
15370
+ if ((current === null || current === void 0 ? void 0 : current.parentElement) !== view.dom) return;
15371
+ if (!((_pmViewDesc = current.pmViewDesc) === null || _pmViewDesc === void 0 ? void 0 : _pmViewDesc.node)) return;
15372
+ return current;
15348
15373
  }
15374
+ /**
15375
+ * Checks if a DOMRect has valid, finite dimensions.
15376
+ */
15349
15377
  function isValidRect(rect) {
15350
- return Number.isFinite(rect.top) && Number.isFinite(rect.bottom) && Number.isFinite(rect.left) && Number.isFinite(rect.right) && rect.width > 0 && rect.height > 0;
15378
+ return Number.isFinite(rect.top) && Number.isFinite(rect.bottom) && Number.isFinite(rect.left) && Number.isFinite(rect.right) && rect.width > 0 && rect.height > 0;
15351
15379
  }
15380
+ /**
15381
+ * Returns the bounding rect of the first or last child of `container` that has
15382
+ * a valid (non-zero) layout box.
15383
+ *
15384
+ * Some extensions insert zero-size widget decorations as the first/last child
15385
+ * of the editor — for example the Pages extension anchors its page-chrome
15386
+ * overlay in a zero-height `<div>` as the first child. Reading `firstElementChild`
15387
+ * / `lastElementChild` directly would yield an invalid rect and abort clamping,
15388
+ * so we skip over any edge children without a valid box.
15389
+ */
15352
15390
  function edgeBlockRect(container, edge) {
15353
- let current = edge === "first" ? container.firstElementChild : container.lastElementChild;
15354
- while (current) {
15355
- const rect = current.getBoundingClientRect();
15356
- if (isValidRect(rect)) {
15357
- return rect;
15358
- }
15359
- current = edge === "first" ? current.nextElementSibling : current.previousElementSibling;
15360
- }
15361
- return null;
15391
+ let current = edge === "first" ? container.firstElementChild : container.lastElementChild;
15392
+ while (current) {
15393
+ const rect = current.getBoundingClientRect();
15394
+ if (isValidRect(rect)) return rect;
15395
+ current = edge === "first" ? current.nextElementSibling : current.previousElementSibling;
15396
+ }
15397
+ return null;
15362
15398
  }
15399
+ /**
15400
+ * Clamps coordinates to content bounds with O(1) layout reads
15401
+ */
15363
15402
  function clampToContent(view, x, y, inset = 5) {
15364
- if (!Number.isFinite(x) || !Number.isFinite(y)) {
15365
- return null;
15366
- }
15367
- const container = view.dom;
15368
- const topRect = edgeBlockRect(container, "first");
15369
- const botRect = edgeBlockRect(container, "last");
15370
- if (!topRect || !botRect) {
15371
- return null;
15372
- }
15373
- const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset);
15374
- const epsilon = 0.5;
15375
- const sameLeft = Math.abs(topRect.left - botRect.left) < epsilon;
15376
- const sameRight = Math.abs(topRect.right - botRect.right) < epsilon;
15377
- let rowRect = topRect;
15378
- if (sameLeft && sameRight) {
15379
- rowRect = topRect;
15380
- }
15381
- const clampedX = Math.min(Math.max(rowRect.left + inset, x), rowRect.right - inset);
15382
- if (!Number.isFinite(clampedX) || !Number.isFinite(clampedY)) {
15383
- return null;
15384
- }
15385
- return { x: clampedX, y: clampedY };
15403
+ if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
15404
+ const container = view.dom;
15405
+ const topRect = edgeBlockRect(container, "first");
15406
+ const botRect = edgeBlockRect(container, "last");
15407
+ if (!topRect || !botRect) return null;
15408
+ const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset);
15409
+ const epsilon = .5;
15410
+ const sameLeft = Math.abs(topRect.left - botRect.left) < epsilon;
15411
+ const sameRight = Math.abs(topRect.right - botRect.right) < epsilon;
15412
+ let rowRect = topRect;
15413
+ if (sameLeft && sameRight) rowRect = topRect;
15414
+ const clampedX = Math.min(Math.max(rowRect.left + inset, x), rowRect.right - inset);
15415
+ if (!Number.isFinite(clampedX) || !Number.isFinite(clampedY)) return null;
15416
+ return {
15417
+ x: clampedX,
15418
+ y: clampedY
15419
+ };
15386
15420
  }
15387
- var findElementNextToCoords = (options) => {
15388
- const { x, y, editor, nestedOptions } = options;
15389
- const { view, state } = editor;
15390
- const clamped = clampToContent(view, x, y, 5);
15391
- if (!clamped) {
15392
- return { resultElement: null, resultNode: null, pos: null };
15393
- }
15394
- const { x: clampedX, y: clampedY } = clamped;
15395
- if (nestedOptions == null ? void 0 : nestedOptions.enabled) {
15396
- const target = findBestDragTarget(view, { x: clampedX, y: clampedY }, nestedOptions);
15397
- if (!target) {
15398
- return { resultElement: null, resultNode: null, pos: null };
15399
- }
15400
- return {
15401
- resultElement: target.dom,
15402
- resultNode: target.node,
15403
- pos: target.pos
15404
- };
15405
- }
15406
- const elements = view.root.elementsFromPoint(clampedX, clampedY);
15407
- let block;
15408
- Array.prototype.some.call(elements, (el) => {
15409
- if (!view.dom.contains(el)) {
15410
- return false;
15411
- }
15412
- const candidate = findClosestTopLevelBlock(el, view);
15413
- if (candidate) {
15414
- block = candidate;
15415
- return true;
15416
- }
15417
- return false;
15418
- });
15419
- if (!block) {
15420
- const coords = view.posAtCoords({ left: clampedX, top: clampedY });
15421
- if (coords) {
15422
- const $pos = state.doc.resolve(coords.pos);
15423
- const depth = Math.min($pos.depth, 1);
15424
- const blockPos = depth > 0 ? $pos.before(depth) : $pos.pos;
15425
- const blockNode = state.doc.nodeAt(blockPos);
15426
- if (blockNode) {
15427
- const dom = view.nodeDOM(blockPos);
15428
- return {
15429
- resultElement: dom instanceof HTMLElement ? dom : null,
15430
- resultNode: blockNode,
15431
- pos: blockPos
15432
- };
15433
- }
15434
- }
15435
- return { resultElement: null, resultNode: null, pos: null };
15436
- }
15437
- let pos;
15438
- try {
15439
- pos = view.posAtDOM(block, 0);
15440
- } catch {
15441
- return { resultElement: null, resultNode: null, pos: null };
15442
- }
15443
- const node = state.doc.nodeAt(pos);
15444
- if (!node) {
15445
- const resolvedPos = state.doc.resolve(pos);
15446
- const parent = resolvedPos.parent;
15447
- return {
15448
- resultElement: block,
15449
- resultNode: parent,
15450
- pos: resolvedPos.start()
15451
- };
15452
- }
15453
- return {
15454
- resultElement: block,
15455
- resultNode: node,
15456
- pos
15457
- };
15458
- };
15459
-
15460
- // src/helpers/getDraggedBlockDir.ts
15421
+ const findElementNextToCoords = (options) => {
15422
+ const { x, y, editor, nestedOptions } = options;
15423
+ const { view, state } = editor;
15424
+ const clamped = clampToContent(view, x, y, 5);
15425
+ if (!clamped) return {
15426
+ resultElement: null,
15427
+ resultNode: null,
15428
+ pos: null
15429
+ };
15430
+ const { x: clampedX, y: clampedY } = clamped;
15431
+ if (nestedOptions === null || nestedOptions === void 0 ? void 0 : nestedOptions.enabled) {
15432
+ const target = findBestDragTarget(view, {
15433
+ x: clampedX,
15434
+ y: clampedY
15435
+ }, nestedOptions);
15436
+ if (!target) return {
15437
+ resultElement: null,
15438
+ resultNode: null,
15439
+ pos: null
15440
+ };
15441
+ return {
15442
+ resultElement: target.dom,
15443
+ resultNode: target.node,
15444
+ pos: target.pos
15445
+ };
15446
+ }
15447
+ const elements = view.root.elementsFromPoint(clampedX, clampedY);
15448
+ let block;
15449
+ Array.prototype.some.call(elements, (el) => {
15450
+ if (!view.dom.contains(el)) return false;
15451
+ const candidate = findClosestTopLevelBlock(el, view);
15452
+ if (candidate) {
15453
+ block = candidate;
15454
+ return true;
15455
+ }
15456
+ return false;
15457
+ });
15458
+ if (!block) {
15459
+ const coords = view.posAtCoords({
15460
+ left: clampedX,
15461
+ top: clampedY
15462
+ });
15463
+ if (coords) {
15464
+ const $pos = state.doc.resolve(coords.pos);
15465
+ const depth = Math.min($pos.depth, 1);
15466
+ const blockPos = depth > 0 ? $pos.before(depth) : $pos.pos;
15467
+ const blockNode = state.doc.nodeAt(blockPos);
15468
+ if (blockNode) {
15469
+ const dom = view.nodeDOM(blockPos);
15470
+ return {
15471
+ resultElement: dom instanceof HTMLElement ? dom : null,
15472
+ resultNode: blockNode,
15473
+ pos: blockPos
15474
+ };
15475
+ }
15476
+ }
15477
+ return {
15478
+ resultElement: null,
15479
+ resultNode: null,
15480
+ pos: null
15481
+ };
15482
+ }
15483
+ let pos;
15484
+ try {
15485
+ pos = view.posAtDOM(block, 0);
15486
+ } catch {
15487
+ return {
15488
+ resultElement: null,
15489
+ resultNode: null,
15490
+ pos: null
15491
+ };
15492
+ }
15493
+ const node = state.doc.nodeAt(pos);
15494
+ if (!node) {
15495
+ const resolvedPos = state.doc.resolve(pos);
15496
+ const parent = resolvedPos.parent;
15497
+ return {
15498
+ resultElement: block,
15499
+ resultNode: parent,
15500
+ pos: resolvedPos.start()
15501
+ };
15502
+ }
15503
+ return {
15504
+ resultElement: block,
15505
+ resultNode: node,
15506
+ pos
15507
+ };
15508
+ };
15509
+ //#endregion
15510
+ //#region src/helpers/getDraggedBlockDir.ts
15511
+ /**
15512
+ * Resolves the DOM element that visually represents the dragged block.
15513
+ */
15461
15514
  function getDraggedBlockElement(view, pos) {
15462
- const nodeDom = view.nodeDOM(pos);
15463
- if (nodeDom instanceof Element && nodeDom !== view.dom) {
15464
- return nodeDom;
15465
- }
15466
- const { node, offset } = view.domAtPos(pos);
15467
- const child = node.childNodes[offset];
15468
- if (child instanceof Element) {
15469
- return child;
15470
- }
15471
- if (node instanceof Element) {
15472
- return node;
15473
- }
15474
- if (node.nodeType === Node.TEXT_NODE && node.parentElement) {
15475
- return node.parentElement;
15476
- }
15477
- return null;
15515
+ const nodeDom = view.nodeDOM(pos);
15516
+ if (nodeDom instanceof Element && nodeDom !== view.dom) return nodeDom;
15517
+ const { node, offset } = view.domAtPos(pos);
15518
+ const child = node.childNodes[offset];
15519
+ if (child instanceof Element) return child;
15520
+ if (node instanceof Element) return node;
15521
+ if (node.nodeType === Node.TEXT_NODE && node.parentElement) return node.parentElement;
15522
+ return null;
15478
15523
  }
15524
+ /**
15525
+ * Resolves the text direction (`dir` attribute value) for the block being
15526
+ * dragged. Uses `view.nodeDOM` first because it maps a ProseMirror position
15527
+ * directly to the block-level DOM element. Falls back to `view.domAtPos` with
15528
+ * proper child-at-offset resolution when `nodeDOM` doesn't return an element,
15529
+ * and ultimately to the editor root direction.
15530
+ */
15479
15531
  function getDraggedBlockDir(view, pos) {
15480
- const draggedDom = getDraggedBlockElement(view, pos);
15481
- const contentDir = draggedDom ? getComputedStyle(draggedDom).direction : getComputedStyle(view.dom).direction;
15482
- return contentDir || "ltr";
15532
+ const draggedDom = getDraggedBlockElement(view, pos);
15533
+ return (draggedDom ? getComputedStyle(draggedDom).direction : getComputedStyle(view.dom).direction) || "ltr";
15483
15534
  }
15484
-
15485
- // src/helpers/removeNode.ts
15535
+ //#endregion
15536
+ //#region src/helpers/removeNode.ts
15486
15537
  function removeNode(node) {
15487
- var _a;
15488
- (_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
15538
+ var _node$parentNode;
15539
+ (_node$parentNode = node.parentNode) === null || _node$parentNode === void 0 || _node$parentNode.removeChild(node);
15489
15540
  }
15490
-
15491
- // src/helpers/dragHandler.ts
15541
+ //#endregion
15542
+ //#region src/helpers/dragHandler.ts
15492
15543
  function getDragImageOffset(direction, wrapperWidth) {
15493
- return direction === "rtl" ? wrapperWidth : 0;
15544
+ return direction === "rtl" ? wrapperWidth : 0;
15494
15545
  }
15495
15546
  function shouldResetMargin(dragImageProperties) {
15496
- if (!dragImageProperties) {
15497
- return true;
15498
- }
15499
- return !dragImageProperties.some((property) => {
15500
- const p = property.trim().toLowerCase();
15501
- return p === "margin" || p.startsWith("margin-");
15502
- });
15547
+ if (!dragImageProperties) return true;
15548
+ return !dragImageProperties.some((property) => {
15549
+ const p = property.trim().toLowerCase();
15550
+ return p === "margin" || p.startsWith("margin-");
15551
+ });
15503
15552
  }
15504
15553
  function getDragHandleRanges(event, editor, nestedOptions, dragContext) {
15505
- const { doc } = editor.view.state;
15506
- if ((nestedOptions == null ? void 0 : nestedOptions.enabled) && (dragContext == null ? void 0 : dragContext.node) && dragContext.pos >= 0) {
15507
- const nodeStart = dragContext.pos;
15508
- const nodeEnd = dragContext.pos + dragContext.node.nodeSize;
15509
- return [
15510
- {
15511
- $from: doc.resolve(nodeStart),
15512
- $to: doc.resolve(nodeEnd)
15513
- }
15514
- ];
15515
- }
15516
- const result = findElementNextToCoords({
15517
- editor,
15518
- x: event.clientX,
15519
- y: event.clientY,
15520
- nestedOptions
15521
- });
15522
- if (!result.resultNode || result.pos === null) {
15523
- return [];
15524
- }
15525
- const offset = result.resultNode.isText || result.resultNode.isAtom ? 0 : -1;
15526
- const $from = doc.resolve(result.pos);
15527
- const $to = doc.resolve(result.pos + result.resultNode.nodeSize + offset);
15528
- return getSelectionRanges($from, $to, 0, { extendOnBoundaryOverlap: false });
15554
+ const { doc } = editor.view.state;
15555
+ if ((nestedOptions === null || nestedOptions === void 0 ? void 0 : nestedOptions.enabled) && (dragContext === null || dragContext === void 0 ? void 0 : dragContext.node) && dragContext.pos >= 0) {
15556
+ const nodeStart = dragContext.pos;
15557
+ const nodeEnd = dragContext.pos + dragContext.node.nodeSize;
15558
+ return [{
15559
+ $from: doc.resolve(nodeStart),
15560
+ $to: doc.resolve(nodeEnd)
15561
+ }];
15562
+ }
15563
+ const result = findElementNextToCoords({
15564
+ editor,
15565
+ x: event.clientX,
15566
+ y: event.clientY,
15567
+ nestedOptions
15568
+ });
15569
+ if (!result.resultNode || result.pos === null) return [];
15570
+ const offset = result.resultNode.isText || result.resultNode.isAtom ? 0 : -1;
15571
+ const $from = doc.resolve(result.pos);
15572
+ const $to = doc.resolve(result.pos + result.resultNode.nodeSize + offset);
15573
+ return getSelectionRanges($from, $to, 0, { extendOnBoundaryOverlap: false });
15529
15574
  }
15530
15575
  function dragHandler(event, editor, nestedOptions, dragContext, dragImageProperties) {
15531
- const { view } = editor;
15532
- if (!event.dataTransfer) {
15533
- return;
15534
- }
15535
- const { empty, $from, $to } = view.state.selection;
15536
- const dragHandleRanges = getDragHandleRanges(event, editor, nestedOptions, dragContext);
15537
- const selectionRanges = getSelectionRanges($from, $to, 0, { extendOnBoundaryOverlap: false });
15538
- const isDragHandleWithinSelection = selectionRanges.some((range) => {
15539
- return dragHandleRanges.find((dragHandleRange) => {
15540
- return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to;
15541
- });
15542
- });
15543
- const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges;
15544
- if (!ranges.length) {
15545
- return;
15546
- }
15547
- const { tr } = view.state;
15548
- const wrapper = document.createElement("div");
15549
- const from = ranges[0].$from.pos;
15550
- const to = ranges[ranges.length - 1].$to.pos;
15551
- const direction = getDraggedBlockDir(view, from);
15552
- wrapper.setAttribute("dir", direction);
15553
- const isNestedDrag = (nestedOptions == null ? void 0 : nestedOptions.enabled) && (dragContext == null ? void 0 : dragContext.node);
15554
- const isSingleBlock = ranges.length === 1;
15555
- let slice;
15556
- let selection;
15557
- if (isNestedDrag && isSingleBlock) {
15558
- slice = view.state.doc.slice(from, to);
15559
- selection = NodeSelection.create(view.state.doc, from);
15560
- } else {
15561
- selection = NodeRangeSelection.create(view.state.doc, from, to);
15562
- slice = selection.content();
15563
- }
15564
- const resetMargin = shouldResetMargin(dragImageProperties);
15565
- ranges.forEach((range) => {
15566
- const element = getDraggedBlockElement(view, range.$from.pos);
15567
- if (!element) {
15568
- return;
15569
- }
15570
- const clonedElement = cloneElement(element, dragImageProperties);
15571
- if (resetMargin) {
15572
- clonedElement.style.margin = "0";
15573
- }
15574
- wrapper.append(clonedElement);
15575
- });
15576
- wrapper.style.position = "absolute";
15577
- wrapper.style.top = "-10000px";
15578
- document.body.append(wrapper);
15579
- event.dataTransfer.clearData();
15580
- const wrapperRect = wrapper.getBoundingClientRect();
15581
- const dragImageX = getDragImageOffset(direction, wrapperRect.width);
15582
- event.dataTransfer.setDragImage(wrapper, dragImageX, 0);
15583
- let cleanedUp = false;
15584
- const cleanupDragPreview = () => {
15585
- if (cleanedUp) {
15586
- return;
15587
- }
15588
- cleanedUp = true;
15589
- removeNode(wrapper);
15590
- document.removeEventListener("drop", cleanupDragPreview);
15591
- document.removeEventListener("dragend", cleanupDragPreview);
15592
- };
15593
- const nodeSelection = selection instanceof NodeSelection ? selection : void 0;
15594
- view.dragging = { slice, move: true, node: nodeSelection };
15595
- tr.setSelection(selection);
15596
- view.dispatch(tr);
15597
- document.addEventListener("drop", cleanupDragPreview);
15598
- document.addEventListener("dragend", cleanupDragPreview);
15576
+ const { view } = editor;
15577
+ if (!event.dataTransfer) return;
15578
+ const { empty, $from, $to } = view.state.selection;
15579
+ const dragHandleRanges = getDragHandleRanges(event, editor, nestedOptions, dragContext);
15580
+ const selectionRanges = getSelectionRanges($from, $to, 0, { extendOnBoundaryOverlap: false });
15581
+ const isDragHandleWithinSelection = selectionRanges.some((range) => {
15582
+ return dragHandleRanges.find((dragHandleRange) => {
15583
+ return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to;
15584
+ });
15585
+ });
15586
+ const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges;
15587
+ if (!ranges.length) return;
15588
+ const { tr } = view.state;
15589
+ const wrapper = document.createElement("div");
15590
+ const from = ranges[0].$from.pos;
15591
+ const to = ranges[ranges.length - 1].$to.pos;
15592
+ const direction = getDraggedBlockDir(view, from);
15593
+ wrapper.setAttribute("dir", direction);
15594
+ const isNestedDrag = (nestedOptions === null || nestedOptions === void 0 ? void 0 : nestedOptions.enabled) && (dragContext === null || dragContext === void 0 ? void 0 : dragContext.node);
15595
+ const isSingleBlock = ranges.length === 1;
15596
+ let slice;
15597
+ let selection;
15598
+ if (isNestedDrag && isSingleBlock) {
15599
+ slice = view.state.doc.slice(from, to);
15600
+ selection = NodeSelection.create(view.state.doc, from);
15601
+ } else {
15602
+ selection = NodeRangeSelection.create(view.state.doc, from, to);
15603
+ slice = selection.content();
15604
+ }
15605
+ const resetMargin = shouldResetMargin(dragImageProperties);
15606
+ ranges.forEach((range) => {
15607
+ const element = getDraggedBlockElement(view, range.$from.pos);
15608
+ if (!element) return;
15609
+ const clonedElement = cloneElement(element, dragImageProperties);
15610
+ if (resetMargin) clonedElement.style.margin = "0";
15611
+ wrapper.append(clonedElement);
15612
+ });
15613
+ wrapper.style.position = "absolute";
15614
+ wrapper.style.top = "-10000px";
15615
+ document.body.append(wrapper);
15616
+ event.dataTransfer.clearData();
15617
+ const dragImageX = getDragImageOffset(direction, wrapper.getBoundingClientRect().width);
15618
+ event.dataTransfer.setDragImage(wrapper, dragImageX, 0);
15619
+ let cleanedUp = false;
15620
+ const cleanupDragPreview = () => {
15621
+ if (cleanedUp) return;
15622
+ cleanedUp = true;
15623
+ removeNode(wrapper);
15624
+ document.removeEventListener("drop", cleanupDragPreview);
15625
+ document.removeEventListener("dragend", cleanupDragPreview);
15626
+ };
15627
+ const nodeSelection = selection instanceof NodeSelection ? selection : void 0;
15628
+ view.dragging = {
15629
+ slice,
15630
+ move: true,
15631
+ node: nodeSelection
15632
+ };
15633
+ tr.setSelection(selection);
15634
+ view.dispatch(tr);
15635
+ document.addEventListener("drop", cleanupDragPreview);
15636
+ document.addEventListener("dragend", cleanupDragPreview);
15599
15637
  }
15600
-
15601
- // src/helpers/getOuterNode.ts
15602
- var getOuterNodePos = (doc, pos) => {
15603
- const resolvedPos = doc.resolve(pos);
15604
- const { depth } = resolvedPos;
15605
- if (depth === 0) {
15606
- return pos;
15607
- }
15608
- const a = resolvedPos.pos - resolvedPos.parentOffset;
15609
- return a - 1;
15610
- };
15611
- var getOuterNode = (doc, pos) => {
15612
- const node = doc.nodeAt(pos);
15613
- const resolvedPos = doc.resolve(pos);
15614
- let { depth } = resolvedPos;
15615
- let parent = node;
15616
- while (depth > 0) {
15617
- const currentNode = resolvedPos.node(depth);
15618
- depth -= 1;
15619
- if (depth === 0) {
15620
- parent = currentNode;
15621
- }
15622
- }
15623
- return parent;
15624
- };
15638
+ //#endregion
15639
+ //#region src/helpers/getOuterNode.ts
15640
+ const getOuterNodePos = (doc, pos) => {
15641
+ const resolvedPos = doc.resolve(pos);
15642
+ const { depth } = resolvedPos;
15643
+ if (depth === 0) return pos;
15644
+ return resolvedPos.pos - resolvedPos.parentOffset - 1;
15645
+ };
15646
+ const getOuterNode = (doc, pos) => {
15647
+ const node = doc.nodeAt(pos);
15648
+ const resolvedPos = doc.resolve(pos);
15649
+ let { depth } = resolvedPos;
15650
+ let parent = node;
15651
+ while (depth > 0) {
15652
+ const currentNode = resolvedPos.node(depth);
15653
+ depth -= 1;
15654
+ if (depth === 0) parent = currentNode;
15655
+ }
15656
+ return parent;
15657
+ };
15658
+ //#endregion
15659
+ //#region src/helpers/nodeRangeDrop.ts
15625
15660
  function mapPendingRestoreAnchor(pendingRestore, tr, options) {
15626
- if (!tr.docChanged) {
15627
- return pendingRestore;
15628
- }
15629
- if (options.isChangeOrigin && pendingRestore.relativeAnchorPos != null) {
15630
- const newPos = options.getAbsolutePos(pendingRestore.relativeAnchorPos);
15631
- if (!Number.isFinite(newPos) || newPos <= 0) {
15632
- return null;
15633
- }
15634
- return {
15635
- ...pendingRestore,
15636
- anchorPos: newPos
15637
- };
15638
- }
15639
- const mappedResult = tr.mapping.mapResult(pendingRestore.anchorPos, 1);
15640
- if (mappedResult.deleted) {
15641
- return null;
15642
- }
15643
- return {
15644
- ...pendingRestore,
15645
- anchorPos: mappedResult.pos
15646
- };
15661
+ if (!tr.docChanged) return pendingRestore;
15662
+ if (options.isChangeOrigin && pendingRestore.relativeAnchorPos != null) {
15663
+ const newPos = options.getAbsolutePos(pendingRestore.relativeAnchorPos);
15664
+ if (!Number.isFinite(newPos) || newPos <= 0) return null;
15665
+ return {
15666
+ ...pendingRestore,
15667
+ anchorPos: newPos
15668
+ };
15669
+ }
15670
+ const mappedResult = tr.mapping.mapResult(pendingRestore.anchorPos, 1);
15671
+ if (mappedResult.deleted) return null;
15672
+ return {
15673
+ ...pendingRestore,
15674
+ anchorPos: mappedResult.pos
15675
+ };
15647
15676
  }
15648
15677
  function sumNodeSizes(parent, from, to) {
15649
- let size = 0;
15650
- for (let i = from; i < to; i += 1) {
15651
- size += parent.child(i).nodeSize;
15652
- }
15653
- return size;
15678
+ let size = 0;
15679
+ for (let i = from; i < to; i += 1) size += parent.child(i).nodeSize;
15680
+ return size;
15654
15681
  }
15655
15682
  function getActiveDragRange(selection) {
15656
- var _a;
15657
- if (!isNodeRangeSelection(selection)) {
15658
- return null;
15659
- }
15660
- return {
15661
- anchorPos: selection.from,
15662
- nodeCount: selection.ranges.length,
15663
- depth: (_a = selection.depth) != null ? _a : 0
15664
- };
15683
+ var _selection$depth;
15684
+ if (!isNodeRangeSelection(selection)) return null;
15685
+ return {
15686
+ anchorPos: selection.from,
15687
+ nodeCount: selection.ranges.length,
15688
+ depth: (_selection$depth = selection.depth) !== null && _selection$depth !== void 0 ? _selection$depth : 0
15689
+ };
15665
15690
  }
15691
+ /**
15692
+ * Computes the position range of the freshly dropped blocks so a
15693
+ * `NodeRangeSelection` can be restored over them after a drag-and-drop.
15694
+ */
15666
15695
  function getDroppedBlockRange(doc, anchorPos, nodeCount, depth) {
15667
- const $pos = doc.resolve(anchorPos);
15668
- const parent = $pos.node(depth);
15669
- let index = $pos.index(depth);
15670
- if (index >= parent.childCount) {
15671
- index = Math.max(0, parent.childCount - nodeCount);
15672
- }
15673
- const count = Math.min(nodeCount, parent.childCount - index);
15674
- if (count <= 0) {
15675
- return null;
15676
- }
15677
- const blockStart = $pos.start(depth) + sumNodeSizes(parent, 0, index);
15678
- const blockEnd = blockStart + sumNodeSizes(parent, index, index + count);
15679
- return { anchor: blockStart, head: blockEnd, count };
15696
+ const $pos = doc.resolve(anchorPos);
15697
+ const parent = $pos.node(depth);
15698
+ let index = $pos.index(depth);
15699
+ if (index >= parent.childCount) index = Math.max(0, parent.childCount - nodeCount);
15700
+ const count = Math.min(nodeCount, parent.childCount - index);
15701
+ if (count <= 0) return null;
15702
+ const blockStart = $pos.start(depth) + sumNodeSizes(parent, 0, index);
15703
+ return {
15704
+ anchor: blockStart,
15705
+ head: blockStart + sumNodeSizes(parent, index, index + count),
15706
+ count
15707
+ };
15680
15708
  }
15681
15709
  function createDroppedNodeRangeSelection(doc, anchorPos, nodeCount, depth) {
15682
- try {
15683
- const range = getDroppedBlockRange(doc, anchorPos, nodeCount, depth);
15684
- if (!range) {
15685
- return null;
15686
- }
15687
- const selection = NodeRangeSelection.create(doc, range.anchor, range.head, depth);
15688
- return selection.ranges.length === nodeCount ? selection : null;
15689
- } catch {
15690
- return null;
15691
- }
15710
+ try {
15711
+ const range = getDroppedBlockRange(doc, anchorPos, nodeCount, depth);
15712
+ if (!range) return null;
15713
+ const selection = NodeRangeSelection.create(doc, range.anchor, range.head, depth);
15714
+ return selection.ranges.length === nodeCount ? selection : null;
15715
+ } catch {
15716
+ return null;
15717
+ }
15692
15718
  }
15693
-
15694
- // src/drag-handle-plugin.ts
15695
- var getRelativePos = (state, absolutePos) => {
15696
- const ystate = ySyncPluginKey.getState(state);
15697
- if (!ystate) {
15698
- return null;
15699
- }
15700
- return absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping);
15701
- };
15702
- var getAbsolutePos = (state, relativePos) => {
15703
- const ystate = ySyncPluginKey.getState(state);
15704
- if (!ystate) {
15705
- return -1;
15706
- }
15707
- return relativePositionToAbsolutePosition(
15708
- ystate.doc,
15709
- ystate.type,
15710
- relativePos,
15711
- ystate.binding.mapping
15712
- ) || 0;
15713
- };
15714
- var getOuterDomNode = (view, domNode) => {
15715
- let tmpDomNode = domNode;
15716
- while (tmpDomNode == null ? void 0 : tmpDomNode.parentNode) {
15717
- if (tmpDomNode.parentNode === view.dom) {
15718
- break;
15719
- }
15720
- tmpDomNode = tmpDomNode.parentNode;
15721
- }
15722
- return tmpDomNode;
15723
- };
15724
- var dragHandlePluginDefaultKey = new PluginKey("dragHandle");
15725
- var DragHandlePlugin = ({
15726
- pluginKey = dragHandlePluginDefaultKey,
15727
- element,
15728
- editor,
15729
- computePositionConfig,
15730
- getReferencedVirtualElement,
15731
- onNodeChange,
15732
- onElementDragStart,
15733
- onElementDragEnd,
15734
- nestedOptions,
15735
- dragImageProperties
15736
- }) => {
15737
- const wrapper = document.createElement("div");
15738
- let locked = false;
15739
- let currentNode = null;
15740
- let currentNodePos = -1;
15741
- let currentNodeRelPos;
15742
- let rafId = null;
15743
- let pendingMouseCoords = null;
15744
- let activeDragRange = null;
15745
- let pendingRestore = null;
15746
- function clearDragRangeState() {
15747
- activeDragRange = null;
15748
- pendingRestore = null;
15749
- }
15750
- function remapPendingRestore(tr, state) {
15751
- if (!pendingRestore) {
15752
- return;
15753
- }
15754
- pendingRestore = mapPendingRestoreAnchor(pendingRestore, tr, {
15755
- isChangeOrigin: isChangeOrigin(tr),
15756
- getAbsolutePos: (relativePos) => getAbsolutePos(state, relativePos)
15757
- });
15758
- }
15759
- function buildRestoreTransaction(state) {
15760
- if (!pendingRestore) {
15761
- return null;
15762
- }
15763
- const nodeRangeSelection = createDroppedNodeRangeSelection(
15764
- state.doc,
15765
- pendingRestore.anchorPos,
15766
- pendingRestore.nodeCount,
15767
- pendingRestore.depth
15768
- );
15769
- if (!nodeRangeSelection) {
15770
- pendingRestore = null;
15771
- activeDragRange = null;
15772
- return null;
15773
- }
15774
- clearDragRangeState();
15775
- return state.tr.setSelection(nodeRangeSelection);
15776
- }
15777
- function hideHandle() {
15778
- if (!element) {
15779
- return;
15780
- }
15781
- element.style.visibility = "hidden";
15782
- element.style.pointerEvents = "none";
15783
- }
15784
- function showHandle() {
15785
- if (!element) {
15786
- return;
15787
- }
15788
- if (!editor.isEditable) {
15789
- hideHandle();
15790
- return;
15791
- }
15792
- element.style.visibility = "";
15793
- element.style.pointerEvents = "auto";
15794
- }
15795
- function repositionDragHandle(dom) {
15796
- const virtualElement = (getReferencedVirtualElement == null ? void 0 : getReferencedVirtualElement()) || {
15797
- getBoundingClientRect: () => dom.getBoundingClientRect()
15798
- };
15799
- computePosition(virtualElement, element, computePositionConfig).then((val) => {
15800
- Object.assign(element.style, {
15801
- position: val.strategy,
15802
- left: `${val.x}px`,
15803
- top: `${val.y}px`
15804
- });
15805
- });
15806
- }
15807
- function onDragStart(e) {
15808
- onElementDragStart == null ? void 0 : onElementDragStart(e);
15809
- dragHandler(
15810
- e,
15811
- editor,
15812
- nestedOptions,
15813
- { node: currentNode, pos: currentNodePos },
15814
- dragImageProperties
15815
- );
15816
- activeDragRange = getActiveDragRange(editor.state.selection);
15817
- if (element) {
15818
- element.dataset.dragging = "true";
15819
- }
15820
- setTimeout(() => {
15821
- if (element) {
15822
- element.style.pointerEvents = "none";
15823
- }
15824
- }, 0);
15825
- }
15826
- function onDragEnd(e) {
15827
- onElementDragEnd == null ? void 0 : onElementDragEnd(e);
15828
- activeDragRange = null;
15829
- hideHandle();
15830
- if (element) {
15831
- element.style.pointerEvents = "auto";
15832
- element.dataset.dragging = "false";
15833
- }
15834
- }
15835
- function onDrop(e) {
15836
- if (!e.target || !editor.view.dom.contains(e.target)) {
15837
- return;
15838
- }
15839
- if (isFirefox()) {
15840
- const editorElement = editor.view.dom;
15841
- requestAnimationFrame(() => {
15842
- if (editorElement.isContentEditable) {
15843
- editorElement.contentEditable = "false";
15844
- editorElement.contentEditable = "true";
15845
- }
15846
- });
15847
- }
15848
- if (!activeDragRange || editor.view.state.selection.empty) {
15849
- return;
15850
- }
15851
- const anchorPos = editor.state.selection.from;
15852
- const relativeAnchorPos = getRelativePos(editor.state, anchorPos);
15853
- pendingRestore = {
15854
- ...activeDragRange,
15855
- anchorPos,
15856
- relativeAnchorPos: relativeAnchorPos != null ? relativeAnchorPos : void 0
15857
- };
15858
- editor.view.dispatch(editor.state.tr.setMeta("addToHistory", false));
15859
- }
15860
- function cleanup() {
15861
- element.removeEventListener("dragstart", onDragStart);
15862
- element.removeEventListener("dragend", onDragEnd);
15863
- document.removeEventListener("drop", onDrop);
15864
- if (rafId) {
15865
- cancelAnimationFrame(rafId);
15866
- rafId = null;
15867
- pendingMouseCoords = null;
15868
- }
15869
- clearDragRangeState();
15870
- }
15871
- wrapper.appendChild(element);
15872
- return {
15873
- unbind() {
15874
- cleanup();
15875
- },
15876
- plugin: new Plugin({
15877
- key: typeof pluginKey === "string" ? new PluginKey(pluginKey) : pluginKey,
15878
- state: {
15879
- init() {
15880
- return { locked: false };
15881
- },
15882
- apply(tr, value, _oldState, state) {
15883
- remapPendingRestore(tr, state);
15884
- const isLocked = tr.getMeta("lockDragHandle");
15885
- const hideDragHandle = tr.getMeta("hideDragHandle");
15886
- if (isLocked !== void 0) {
15887
- locked = isLocked;
15888
- }
15889
- if (hideDragHandle) {
15890
- hideHandle();
15891
- locked = false;
15892
- currentNode = null;
15893
- currentNodePos = -1;
15894
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
15895
- return value;
15896
- }
15897
- if (tr.docChanged && currentNodePos !== -1 && element) {
15898
- if (isChangeOrigin(tr)) {
15899
- const newPos = getAbsolutePos(state, currentNodeRelPos);
15900
- if (newPos !== currentNodePos) {
15901
- currentNodePos = newPos;
15902
- }
15903
- } else {
15904
- const newPos = tr.mapping.map(currentNodePos);
15905
- if (newPos !== currentNodePos) {
15906
- currentNodePos = newPos;
15907
- currentNodeRelPos = getRelativePos(state, currentNodePos);
15908
- }
15909
- }
15910
- }
15911
- return value;
15912
- }
15913
- },
15914
- appendTransaction(_transactions, _oldState, newState) {
15915
- return buildRestoreTransaction(newState);
15916
- },
15917
- view: (view) => {
15918
- var _a;
15919
- element.draggable = true;
15920
- element.style.pointerEvents = "auto";
15921
- element.dataset.dragging = "false";
15922
- (_a = editor.view.dom.parentElement) == null ? void 0 : _a.appendChild(wrapper);
15923
- wrapper.style.pointerEvents = "none";
15924
- wrapper.style.position = "absolute";
15925
- wrapper.style.top = "0";
15926
- wrapper.style.left = "0";
15927
- wrapper.style.zIndex = "10";
15928
- element.addEventListener("dragstart", onDragStart);
15929
- element.addEventListener("dragend", onDragEnd);
15930
- document.addEventListener("drop", onDrop);
15931
- return {
15932
- update(_, oldState) {
15933
- if (!element) {
15934
- return;
15935
- }
15936
- if (!editor.isEditable) {
15937
- hideHandle();
15938
- return;
15939
- }
15940
- if (locked) {
15941
- element.draggable = false;
15942
- } else {
15943
- element.draggable = true;
15944
- }
15945
- if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {
15946
- return;
15947
- }
15948
- let domNode = view.nodeDOM(currentNodePos);
15949
- domNode = getOuterDomNode(view, domNode);
15950
- if (domNode === view.dom) {
15951
- return;
15952
- }
15953
- if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
15954
- return;
15955
- }
15956
- const domNodePos = view.posAtDOM(domNode, 0);
15957
- const outerNode = getOuterNode(editor.state.doc, domNodePos);
15958
- const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
15959
- currentNode = outerNode;
15960
- currentNodePos = outerNodePos;
15961
- currentNodeRelPos = getRelativePos(view.state, currentNodePos);
15962
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
15963
- repositionDragHandle(domNode);
15964
- },
15965
- // TODO: Kills even on hot reload
15966
- destroy() {
15967
- cleanup();
15968
- if (element) {
15969
- removeNode(wrapper);
15970
- }
15971
- }
15972
- };
15973
- },
15974
- props: {
15975
- handleDOMEvents: {
15976
- keydown(view) {
15977
- if (!element || locked) {
15978
- return false;
15979
- }
15980
- if (view.hasFocus()) {
15981
- hideHandle();
15982
- currentNode = null;
15983
- currentNodePos = -1;
15984
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
15985
- return false;
15986
- }
15987
- return false;
15988
- },
15989
- mouseleave(_view, e) {
15990
- if (locked) {
15991
- return false;
15992
- }
15993
- if (e.target && !wrapper.contains(e.relatedTarget)) {
15994
- hideHandle();
15995
- currentNode = null;
15996
- currentNodePos = -1;
15997
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
15998
- }
15999
- return false;
16000
- },
16001
- mousemove(view, e) {
16002
- if (!element || locked) {
16003
- return false;
16004
- }
16005
- pendingMouseCoords = { x: e.clientX, y: e.clientY };
16006
- if (rafId) {
16007
- return false;
16008
- }
16009
- rafId = requestAnimationFrame(() => {
16010
- rafId = null;
16011
- if (!pendingMouseCoords) {
16012
- return;
16013
- }
16014
- const { x, y } = pendingMouseCoords;
16015
- pendingMouseCoords = null;
16016
- const nodeData = findElementNextToCoords({
16017
- x,
16018
- y,
16019
- editor,
16020
- nestedOptions
16021
- });
16022
- if (!nodeData.resultElement) {
16023
- return;
16024
- }
16025
- let domNode = nodeData.resultElement;
16026
- let targetNode = nodeData.resultNode;
16027
- let targetPos = nodeData.pos;
16028
- if (!(nestedOptions == null ? void 0 : nestedOptions.enabled)) {
16029
- domNode = getOuterDomNode(view, domNode);
16030
- if (domNode === view.dom) {
16031
- return;
16032
- }
16033
- if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
16034
- return;
16035
- }
16036
- const domNodePos = view.posAtDOM(domNode, 0);
16037
- targetNode = getOuterNode(editor.state.doc, domNodePos);
16038
- targetPos = getOuterNodePos(editor.state.doc, domNodePos);
16039
- }
16040
- if (targetNode !== currentNode) {
16041
- currentNode = targetNode;
16042
- currentNodePos = targetPos != null ? targetPos : -1;
16043
- currentNodeRelPos = getRelativePos(view.state, currentNodePos);
16044
- onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
16045
- repositionDragHandle(domNode);
16046
- showHandle();
16047
- }
16048
- });
16049
- return false;
16050
- }
16051
- }
16052
- }
16053
- })
16054
- };
16055
- };
16056
-
16057
- // src/helpers/normalizeOptions.ts
15719
+ //#endregion
15720
+ //#region src/drag-handle-plugin.ts
15721
+ const getRelativePos = (state, absolutePos) => {
15722
+ const ystate = ySyncPluginKey.getState(state);
15723
+ if (!ystate) return null;
15724
+ return absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping);
15725
+ };
15726
+ const getAbsolutePos = (state, relativePos) => {
15727
+ const ystate = ySyncPluginKey.getState(state);
15728
+ if (!ystate) return -1;
15729
+ return relativePositionToAbsolutePosition(ystate.doc, ystate.type, relativePos, ystate.binding.mapping) || 0;
15730
+ };
15731
+ const getOuterDomNode = (view, domNode) => {
15732
+ let tmpDomNode = domNode;
15733
+ while (tmpDomNode === null || tmpDomNode === void 0 ? void 0 : tmpDomNode.parentNode) {
15734
+ if (tmpDomNode.parentNode === view.dom) break;
15735
+ tmpDomNode = tmpDomNode.parentNode;
15736
+ }
15737
+ return tmpDomNode;
15738
+ };
15739
+ const dragHandlePluginDefaultKey = new PluginKey("dragHandle");
15740
+ const DragHandlePlugin = ({ pluginKey = dragHandlePluginDefaultKey, element, editor, computePositionConfig, getReferencedVirtualElement, onNodeChange, onElementDragStart, onElementDragEnd, nestedOptions, dragImageProperties }) => {
15741
+ const wrapper = document.createElement("div");
15742
+ let locked = false;
15743
+ let currentNode = null;
15744
+ let currentNodePos = -1;
15745
+ let currentNodeRelPos;
15746
+ let rafId = null;
15747
+ let pendingMouseCoords = null;
15748
+ let activeDragRange = null;
15749
+ let pendingRestore = null;
15750
+ function clearDragRangeState() {
15751
+ activeDragRange = null;
15752
+ pendingRestore = null;
15753
+ }
15754
+ function remapPendingRestore(tr, state) {
15755
+ if (!pendingRestore) return;
15756
+ pendingRestore = mapPendingRestoreAnchor(pendingRestore, tr, {
15757
+ isChangeOrigin: isChangeOrigin(tr),
15758
+ getAbsolutePos: (relativePos) => getAbsolutePos(state, relativePos)
15759
+ });
15760
+ }
15761
+ function buildRestoreTransaction(state) {
15762
+ if (!pendingRestore) return null;
15763
+ const nodeRangeSelection = createDroppedNodeRangeSelection(state.doc, pendingRestore.anchorPos, pendingRestore.nodeCount, pendingRestore.depth);
15764
+ if (!nodeRangeSelection) {
15765
+ pendingRestore = null;
15766
+ activeDragRange = null;
15767
+ return null;
15768
+ }
15769
+ clearDragRangeState();
15770
+ return state.tr.setSelection(nodeRangeSelection);
15771
+ }
15772
+ function hideHandle() {
15773
+ if (!element) return;
15774
+ element.style.visibility = "hidden";
15775
+ element.style.pointerEvents = "none";
15776
+ }
15777
+ function showHandle() {
15778
+ if (!element) return;
15779
+ if (!editor.isEditable) {
15780
+ hideHandle();
15781
+ return;
15782
+ }
15783
+ element.style.visibility = "";
15784
+ element.style.pointerEvents = "auto";
15785
+ }
15786
+ function repositionDragHandle(dom) {
15787
+ const virtualElement = (getReferencedVirtualElement === null || getReferencedVirtualElement === void 0 ? void 0 : getReferencedVirtualElement()) || { getBoundingClientRect: () => dom.getBoundingClientRect() };
15788
+ computePosition(virtualElement, element, computePositionConfig).then((val) => {
15789
+ Object.assign(element.style, {
15790
+ position: val.strategy,
15791
+ left: `${val.x}px`,
15792
+ top: `${val.y}px`
15793
+ });
15794
+ });
15795
+ }
15796
+ function onDragStart(e) {
15797
+ onElementDragStart === null || onElementDragStart === void 0 || onElementDragStart(e);
15798
+ dragHandler(e, editor, nestedOptions, {
15799
+ node: currentNode,
15800
+ pos: currentNodePos
15801
+ }, dragImageProperties);
15802
+ activeDragRange = getActiveDragRange(editor.state.selection);
15803
+ if (element) element.dataset.dragging = "true";
15804
+ setTimeout(() => {
15805
+ if (element) element.style.pointerEvents = "none";
15806
+ }, 0);
15807
+ }
15808
+ function onDragEnd(e) {
15809
+ onElementDragEnd === null || onElementDragEnd === void 0 || onElementDragEnd(e);
15810
+ activeDragRange = null;
15811
+ hideHandle();
15812
+ if (element) {
15813
+ element.style.pointerEvents = "auto";
15814
+ element.dataset.dragging = "false";
15815
+ }
15816
+ }
15817
+ function onDrop(e) {
15818
+ if (!e.target || !editor.view.dom.contains(e.target)) return;
15819
+ if (isFirefox()) {
15820
+ const editorElement = editor.view.dom;
15821
+ requestAnimationFrame(() => {
15822
+ if (editorElement.isContentEditable) {
15823
+ editorElement.contentEditable = "false";
15824
+ editorElement.contentEditable = "true";
15825
+ }
15826
+ });
15827
+ }
15828
+ if (!activeDragRange || editor.view.state.selection.empty) return;
15829
+ const anchorPos = editor.state.selection.from;
15830
+ const relativeAnchorPos = getRelativePos(editor.state, anchorPos);
15831
+ pendingRestore = {
15832
+ ...activeDragRange,
15833
+ anchorPos,
15834
+ relativeAnchorPos: relativeAnchorPos !== null && relativeAnchorPos !== void 0 ? relativeAnchorPos : void 0
15835
+ };
15836
+ editor.view.dispatch(editor.state.tr.setMeta("addToHistory", false));
15837
+ }
15838
+ function cleanup() {
15839
+ element.removeEventListener("dragstart", onDragStart);
15840
+ element.removeEventListener("dragend", onDragEnd);
15841
+ document.removeEventListener("drop", onDrop);
15842
+ if (rafId) {
15843
+ cancelAnimationFrame(rafId);
15844
+ rafId = null;
15845
+ pendingMouseCoords = null;
15846
+ }
15847
+ clearDragRangeState();
15848
+ }
15849
+ wrapper.appendChild(element);
15850
+ return {
15851
+ unbind() {
15852
+ cleanup();
15853
+ },
15854
+ plugin: new Plugin({
15855
+ key: typeof pluginKey === "string" ? new PluginKey(pluginKey) : pluginKey,
15856
+ state: {
15857
+ init() {
15858
+ return { locked: false };
15859
+ },
15860
+ apply(tr, value, _oldState, state) {
15861
+ remapPendingRestore(tr, state);
15862
+ const isLocked = tr.getMeta("lockDragHandle");
15863
+ const hideDragHandle = tr.getMeta("hideDragHandle");
15864
+ if (isLocked !== void 0) locked = isLocked;
15865
+ if (hideDragHandle) {
15866
+ hideHandle();
15867
+ locked = false;
15868
+ currentNode = null;
15869
+ currentNodePos = -1;
15870
+ onNodeChange === null || onNodeChange === void 0 || onNodeChange({
15871
+ editor,
15872
+ node: null,
15873
+ pos: -1
15874
+ });
15875
+ return value;
15876
+ }
15877
+ if (tr.docChanged && currentNodePos !== -1 && element) {
15878
+ if (isChangeOrigin(tr)) {
15879
+ const newPos = getAbsolutePos(state, currentNodeRelPos);
15880
+ if (newPos !== currentNodePos) currentNodePos = newPos;
15881
+ } else {
15882
+ const newPos = tr.mapping.map(currentNodePos);
15883
+ if (newPos !== currentNodePos) {
15884
+ currentNodePos = newPos;
15885
+ currentNodeRelPos = getRelativePos(state, currentNodePos);
15886
+ }
15887
+ }
15888
+ }
15889
+ return value;
15890
+ }
15891
+ },
15892
+ appendTransaction(_transactions, _oldState, newState) {
15893
+ return buildRestoreTransaction(newState);
15894
+ },
15895
+ view: (view) => {
15896
+ var _editor$view$dom$pare;
15897
+ element.draggable = true;
15898
+ element.style.pointerEvents = "auto";
15899
+ element.dataset.dragging = "false";
15900
+ (_editor$view$dom$pare = editor.view.dom.parentElement) === null || _editor$view$dom$pare === void 0 || _editor$view$dom$pare.appendChild(wrapper);
15901
+ wrapper.style.pointerEvents = "none";
15902
+ wrapper.style.position = "absolute";
15903
+ wrapper.style.top = "0";
15904
+ wrapper.style.left = "0";
15905
+ wrapper.style.zIndex = "10";
15906
+ element.addEventListener("dragstart", onDragStart);
15907
+ element.addEventListener("dragend", onDragEnd);
15908
+ document.addEventListener("drop", onDrop);
15909
+ return {
15910
+ update(_, oldState) {
15911
+ if (!element) return;
15912
+ if (!editor.isEditable) {
15913
+ hideHandle();
15914
+ return;
15915
+ }
15916
+ if (locked) element.draggable = false;
15917
+ else element.draggable = true;
15918
+ if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) return;
15919
+ let domNode = view.nodeDOM(currentNodePos);
15920
+ domNode = getOuterDomNode(view, domNode);
15921
+ if (domNode === view.dom) return;
15922
+ if ((domNode === null || domNode === void 0 ? void 0 : domNode.nodeType) !== 1) return;
15923
+ const domNodePos = view.posAtDOM(domNode, 0);
15924
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
15925
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
15926
+ currentNode = outerNode;
15927
+ currentNodePos = outerNodePos;
15928
+ currentNodeRelPos = getRelativePos(view.state, currentNodePos);
15929
+ onNodeChange === null || onNodeChange === void 0 || onNodeChange({
15930
+ editor,
15931
+ node: currentNode,
15932
+ pos: currentNodePos
15933
+ });
15934
+ repositionDragHandle(domNode);
15935
+ },
15936
+ destroy() {
15937
+ cleanup();
15938
+ if (element) removeNode(wrapper);
15939
+ }
15940
+ };
15941
+ },
15942
+ props: { handleDOMEvents: {
15943
+ keydown(view) {
15944
+ if (!element || locked) return false;
15945
+ if (view.hasFocus()) {
15946
+ hideHandle();
15947
+ currentNode = null;
15948
+ currentNodePos = -1;
15949
+ onNodeChange === null || onNodeChange === void 0 || onNodeChange({
15950
+ editor,
15951
+ node: null,
15952
+ pos: -1
15953
+ });
15954
+ return false;
15955
+ }
15956
+ return false;
15957
+ },
15958
+ mouseleave(_view, e) {
15959
+ if (locked) return false;
15960
+ if (e.target && !wrapper.contains(e.relatedTarget)) {
15961
+ hideHandle();
15962
+ currentNode = null;
15963
+ currentNodePos = -1;
15964
+ onNodeChange === null || onNodeChange === void 0 || onNodeChange({
15965
+ editor,
15966
+ node: null,
15967
+ pos: -1
15968
+ });
15969
+ }
15970
+ return false;
15971
+ },
15972
+ mousemove(view, e) {
15973
+ if (!element || locked) return false;
15974
+ pendingMouseCoords = {
15975
+ x: e.clientX,
15976
+ y: e.clientY
15977
+ };
15978
+ if (rafId) return false;
15979
+ rafId = requestAnimationFrame(() => {
15980
+ rafId = null;
15981
+ if (!pendingMouseCoords) return;
15982
+ const { x, y } = pendingMouseCoords;
15983
+ pendingMouseCoords = null;
15984
+ const nodeData = findElementNextToCoords({
15985
+ x,
15986
+ y,
15987
+ editor,
15988
+ nestedOptions
15989
+ });
15990
+ if (!nodeData.resultElement) return;
15991
+ let domNode = nodeData.resultElement;
15992
+ let targetNode = nodeData.resultNode;
15993
+ let targetPos = nodeData.pos;
15994
+ if (!(nestedOptions === null || nestedOptions === void 0 ? void 0 : nestedOptions.enabled)) {
15995
+ domNode = getOuterDomNode(view, domNode);
15996
+ if (domNode === view.dom) return;
15997
+ if ((domNode === null || domNode === void 0 ? void 0 : domNode.nodeType) !== 1) return;
15998
+ const domNodePos = view.posAtDOM(domNode, 0);
15999
+ targetNode = getOuterNode(editor.state.doc, domNodePos);
16000
+ targetPos = getOuterNodePos(editor.state.doc, domNodePos);
16001
+ }
16002
+ if (targetNode !== currentNode) {
16003
+ var _targetPos;
16004
+ currentNode = targetNode;
16005
+ currentNodePos = (_targetPos = targetPos) !== null && _targetPos !== void 0 ? _targetPos : -1;
16006
+ currentNodeRelPos = getRelativePos(view.state, currentNodePos);
16007
+ onNodeChange === null || onNodeChange === void 0 || onNodeChange({
16008
+ editor,
16009
+ node: currentNode,
16010
+ pos: currentNodePos
16011
+ });
16012
+ repositionDragHandle(domNode);
16013
+ showHandle();
16014
+ }
16015
+ });
16016
+ return false;
16017
+ }
16018
+ } }
16019
+ })
16020
+ };
16021
+ };
16022
+ //#endregion
16023
+ //#region src/helpers/normalizeOptions.ts
16024
+ /**
16025
+ * Normalizes the nested options input into a complete configuration object.
16026
+ *
16027
+ * @param input - The nested option (boolean, object, or undefined)
16028
+ * @returns A fully normalized options object
16029
+ *
16030
+ * @example
16031
+ * // Simple enable
16032
+ * normalizeNestedOptions(true)
16033
+ * // Returns: { enabled: true, rules: [], defaultRules: true, ... }
16034
+ *
16035
+ * @example
16036
+ * // Custom config
16037
+ * normalizeNestedOptions({ rules: [myRule], edgeDetection: 'none' })
16038
+ * // Returns: { enabled: true, rules: [myRule], edgeDetection: { edges: [], ... } }
16039
+ */
16058
16040
  function normalizeNestedOptions(input) {
16059
- var _a, _b;
16060
- if (input === false || input === void 0) {
16061
- return {
16062
- enabled: false,
16063
- rules: [],
16064
- defaultRules: true,
16065
- allowedContainers: void 0,
16066
- edgeDetection: normalizeEdgeDetection("none")
16067
- };
16068
- }
16069
- if (input === true) {
16070
- return {
16071
- enabled: true,
16072
- rules: [],
16073
- defaultRules: true,
16074
- allowedContainers: void 0,
16075
- edgeDetection: normalizeEdgeDetection("left")
16076
- };
16077
- }
16078
- return {
16079
- enabled: true,
16080
- rules: (_a = input.rules) != null ? _a : [],
16081
- defaultRules: (_b = input.defaultRules) != null ? _b : true,
16082
- allowedContainers: input.allowedContainers,
16083
- edgeDetection: normalizeEdgeDetection(input.edgeDetection)
16084
- };
16041
+ var _input$rules, _input$defaultRules;
16042
+ if (input === false || input === void 0) return {
16043
+ enabled: false,
16044
+ rules: [],
16045
+ defaultRules: true,
16046
+ allowedContainers: void 0,
16047
+ edgeDetection: normalizeEdgeDetection("none")
16048
+ };
16049
+ if (input === true) return {
16050
+ enabled: true,
16051
+ rules: [],
16052
+ defaultRules: true,
16053
+ allowedContainers: void 0,
16054
+ edgeDetection: normalizeEdgeDetection("left")
16055
+ };
16056
+ return {
16057
+ enabled: true,
16058
+ rules: (_input$rules = input.rules) !== null && _input$rules !== void 0 ? _input$rules : [],
16059
+ defaultRules: (_input$defaultRules = input.defaultRules) !== null && _input$defaultRules !== void 0 ? _input$defaultRules : true,
16060
+ allowedContainers: input.allowedContainers,
16061
+ edgeDetection: normalizeEdgeDetection(input.edgeDetection)
16062
+ };
16085
16063
  }
16086
-
16087
- // src/drag-handle.ts
16088
- var defaultComputePositionConfig = {
16089
- placement: "left-start",
16090
- strategy: "absolute"
16064
+ //#endregion
16065
+ //#region src/drag-handle.ts
16066
+ const defaultComputePositionConfig = {
16067
+ placement: "left-start",
16068
+ strategy: "absolute"
16091
16069
  };
16092
16070
  Extension.create({
16093
- name: "dragHandle",
16094
- addOptions() {
16095
- return {
16096
- render() {
16097
- const element = document.createElement("div");
16098
- element.classList.add("drag-handle");
16099
- return element;
16100
- },
16101
- computePositionConfig: {},
16102
- locked: false,
16103
- onNodeChange: () => {
16104
- return null;
16105
- },
16106
- onElementDragStart: void 0,
16107
- onElementDragEnd: void 0,
16108
- nested: false,
16109
- dragImageProperties: void 0
16110
- };
16111
- },
16112
- addCommands() {
16113
- return {
16114
- lockDragHandle: () => ({ editor }) => {
16115
- this.options.locked = true;
16116
- return editor.commands.setMeta("lockDragHandle", this.options.locked);
16117
- },
16118
- unlockDragHandle: () => ({ editor }) => {
16119
- this.options.locked = false;
16120
- return editor.commands.setMeta("lockDragHandle", this.options.locked);
16121
- },
16122
- toggleDragHandle: () => ({ editor }) => {
16123
- this.options.locked = !this.options.locked;
16124
- return editor.commands.setMeta("lockDragHandle", this.options.locked);
16125
- }
16126
- };
16127
- },
16128
- addProseMirrorPlugins() {
16129
- const element = this.options.render();
16130
- const nestedOptions = normalizeNestedOptions(this.options.nested);
16131
- return [
16132
- DragHandlePlugin({
16133
- computePositionConfig: {
16134
- ...defaultComputePositionConfig,
16135
- ...this.options.computePositionConfig
16136
- },
16137
- getReferencedVirtualElement: this.options.getReferencedVirtualElement,
16138
- element,
16139
- editor: this.editor,
16140
- onNodeChange: this.options.onNodeChange,
16141
- onElementDragStart: this.options.onElementDragStart,
16142
- onElementDragEnd: this.options.onElementDragEnd,
16143
- nestedOptions,
16144
- dragImageProperties: this.options.dragImageProperties
16145
- }).plugin
16146
- ];
16147
- }
16071
+ name: "dragHandle",
16072
+ addOptions() {
16073
+ return {
16074
+ render() {
16075
+ const element = document.createElement("div");
16076
+ element.classList.add("drag-handle");
16077
+ return element;
16078
+ },
16079
+ computePositionConfig: {},
16080
+ locked: false,
16081
+ onNodeChange: () => {
16082
+ return null;
16083
+ },
16084
+ onElementDragStart: void 0,
16085
+ onElementDragEnd: void 0,
16086
+ nested: false,
16087
+ dragImageProperties: void 0
16088
+ };
16089
+ },
16090
+ addCommands() {
16091
+ return {
16092
+ lockDragHandle: () => ({ editor }) => {
16093
+ this.options.locked = true;
16094
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
16095
+ },
16096
+ unlockDragHandle: () => ({ editor }) => {
16097
+ this.options.locked = false;
16098
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
16099
+ },
16100
+ toggleDragHandle: () => ({ editor }) => {
16101
+ this.options.locked = !this.options.locked;
16102
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
16103
+ }
16104
+ };
16105
+ },
16106
+ addProseMirrorPlugins() {
16107
+ const element = this.options.render();
16108
+ const nestedOptions = normalizeNestedOptions(this.options.nested);
16109
+ return [DragHandlePlugin({
16110
+ computePositionConfig: {
16111
+ ...defaultComputePositionConfig,
16112
+ ...this.options.computePositionConfig
16113
+ },
16114
+ getReferencedVirtualElement: this.options.getReferencedVirtualElement,
16115
+ element,
16116
+ editor: this.editor,
16117
+ onNodeChange: this.options.onNodeChange,
16118
+ onElementDragStart: this.options.onElementDragStart,
16119
+ onElementDragEnd: this.options.onElementDragEnd,
16120
+ nestedOptions,
16121
+ dragImageProperties: this.options.dragImageProperties
16122
+ }).plugin];
16123
+ }
16148
16124
  });
16149
16125
 
16150
- // src/DragHandle.tsx
16151
- var DragHandle = (props) => {
16152
- const {
16153
- className = "drag-handle",
16154
- children,
16155
- editor,
16156
- pluginKey = dragHandlePluginDefaultKey,
16157
- onNodeChange,
16158
- onElementDragStart,
16159
- onElementDragEnd,
16160
- getReferencedVirtualElement,
16161
- computePositionConfig = defaultComputePositionConfig,
16162
- nested = false
16163
- } = props;
16164
- const elementRef = useRef(null);
16165
- if (elementRef.current === null && typeof document !== "undefined") {
16166
- elementRef.current = document.createElement("div");
16167
- }
16168
- const nestedOptions = useMemo(() => normalizeNestedOptions(nested), [JSON.stringify(nested)]);
16169
- useEffect(() => {
16170
- const element2 = elementRef.current;
16171
- if (!element2) {
16172
- return;
16173
- }
16174
- element2.className = className;
16175
- }, [className]);
16176
- useEffect(() => {
16177
- if (typeof document === "undefined") {
16178
- return;
16179
- }
16180
- if (editor.isDestroyed) {
16181
- return;
16182
- }
16183
- const element2 = elementRef.current;
16184
- if (!element2) {
16185
- return;
16186
- }
16187
- element2.style.visibility = "hidden";
16188
- element2.style.position = "absolute";
16189
- element2.dataset.dragging = "false";
16190
- const { plugin, unbind } = DragHandlePlugin({
16191
- editor,
16192
- element: element2,
16193
- pluginKey,
16194
- computePositionConfig: {
16195
- ...defaultComputePositionConfig,
16196
- ...computePositionConfig
16197
- },
16198
- onElementDragStart,
16199
- onElementDragEnd,
16200
- onNodeChange,
16201
- getReferencedVirtualElement,
16202
- nestedOptions
16203
- });
16204
- editor.registerPlugin(plugin);
16205
- return () => {
16206
- if (!editor.isDestroyed) {
16207
- editor.unregisterPlugin(pluginKey);
16208
- }
16209
- unbind();
16210
- };
16211
- }, [
16212
- editor,
16213
- onNodeChange,
16214
- getReferencedVirtualElement,
16215
- pluginKey,
16216
- computePositionConfig,
16217
- onElementDragStart,
16218
- onElementDragEnd,
16219
- nestedOptions
16220
- ]);
16221
- const element = elementRef.current;
16222
- if (!element) {
16223
- return null;
16224
- }
16225
- return createPortal(children, element);
16126
+ //#region src/DragHandle.tsx
16127
+ const DragHandle = (props) => {
16128
+ const { className = "drag-handle", children, editor, pluginKey = dragHandlePluginDefaultKey, onNodeChange, onElementDragStart, onElementDragEnd, getReferencedVirtualElement, computePositionConfig = defaultComputePositionConfig, nested = false } = props;
16129
+ const elementRef = useRef(null);
16130
+ if (elementRef.current === null && typeof document !== "undefined") elementRef.current = document.createElement("div");
16131
+ const callbacks = {
16132
+ onNodeChange,
16133
+ onElementDragStart,
16134
+ onElementDragEnd,
16135
+ getReferencedVirtualElement
16136
+ };
16137
+ const callbacksRef = useRef(callbacks);
16138
+ callbacksRef.current = callbacks;
16139
+ const nestedOptions = useMemo(() => normalizeNestedOptions(nested), [JSON.stringify(nested)]);
16140
+ useEffect(() => {
16141
+ const element = elementRef.current;
16142
+ if (!element) return;
16143
+ element.className = className;
16144
+ }, [className]);
16145
+ useEffect(() => {
16146
+ if (typeof document === "undefined") return;
16147
+ if (editor.isDestroyed) return;
16148
+ const element = elementRef.current;
16149
+ if (!element) return;
16150
+ element.style.visibility = "hidden";
16151
+ element.style.position = "absolute";
16152
+ element.dataset.dragging = "false";
16153
+ const { plugin, unbind } = DragHandlePlugin({
16154
+ editor,
16155
+ element,
16156
+ pluginKey,
16157
+ computePositionConfig: {
16158
+ ...defaultComputePositionConfig,
16159
+ ...computePositionConfig
16160
+ },
16161
+ onElementDragStart: (event) => {
16162
+ var _callbacksRef$current, _callbacksRef$current2;
16163
+ return (_callbacksRef$current = (_callbacksRef$current2 = callbacksRef.current).onElementDragStart) === null || _callbacksRef$current === void 0 ? void 0 : _callbacksRef$current.call(_callbacksRef$current2, event);
16164
+ },
16165
+ onElementDragEnd: (event) => {
16166
+ var _callbacksRef$current3, _callbacksRef$current4;
16167
+ return (_callbacksRef$current3 = (_callbacksRef$current4 = callbacksRef.current).onElementDragEnd) === null || _callbacksRef$current3 === void 0 ? void 0 : _callbacksRef$current3.call(_callbacksRef$current4, event);
16168
+ },
16169
+ onNodeChange: (data) => {
16170
+ var _callbacksRef$current5, _callbacksRef$current6;
16171
+ return (_callbacksRef$current5 = (_callbacksRef$current6 = callbacksRef.current).onNodeChange) === null || _callbacksRef$current5 === void 0 ? void 0 : _callbacksRef$current5.call(_callbacksRef$current6, data);
16172
+ },
16173
+ getReferencedVirtualElement: () => {
16174
+ var _callbacksRef$current7, _callbacksRef$current8, _callbacksRef$current9;
16175
+ return (_callbacksRef$current7 = (_callbacksRef$current8 = (_callbacksRef$current9 = callbacksRef.current).getReferencedVirtualElement) === null || _callbacksRef$current8 === void 0 ? void 0 : _callbacksRef$current8.call(_callbacksRef$current9)) !== null && _callbacksRef$current7 !== void 0 ? _callbacksRef$current7 : null;
16176
+ },
16177
+ nestedOptions
16178
+ });
16179
+ editor.registerPlugin(plugin);
16180
+ return () => {
16181
+ if (!editor.isDestroyed) editor.unregisterPlugin(pluginKey);
16182
+ unbind();
16183
+ };
16184
+ }, [
16185
+ editor,
16186
+ pluginKey,
16187
+ computePositionConfig,
16188
+ nestedOptions
16189
+ ]);
16190
+ const element = elementRef.current;
16191
+ if (!element) return null;
16192
+ return createPortal(children, element);
16226
16193
  };
16227
16194
 
16228
16195
  export { DragHandle };
16229
- //# sourceMappingURL=index-Dt0zG4YB.js.map
16196
+ //# sourceMappingURL=index-C2dOrf4N.js.map