@atlaskit/editor-plugin-list 10.0.12 → 10.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @atlaskit/editor-plugin-list
2
2
 
3
+ ## 10.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`65cb641586cc0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/65cb641586cc0) -
8
+ Refactor list indentation to use shared utilities from editor-common
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies
13
+
3
14
  ## 10.0.12
4
15
 
5
16
  ### Patch Changes
@@ -4,13 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.moveSelectedListItems = moveSelectedListItems;
7
+ var _lists = require("@atlaskit/editor-common/lists");
7
8
  var _types = require("../../types");
8
9
  var _find = require("../utils/find");
9
10
  var _listIndentation = require("../utils/list-indentation");
10
11
  /**
11
12
  * Moves the selected list items n levels up (negative delta) or down (positive delta).
12
13
  */
13
- function moveSelectedListItems(tr, delta) {
14
+ function moveSelectedListItems(tr, indentDelta) {
14
15
  var originalSelection = tr.selection;
15
16
 
16
17
  // Find the root list so depth adjustments are absolute
@@ -30,36 +31,40 @@ function moveSelectedListItems(tr, delta) {
30
31
  rootListEnd: rootListEnd,
31
32
  selectionFrom: originalSelection.from,
32
33
  selectionTo: originalSelection.to,
33
- delta: delta
34
+ indentDelta: indentDelta,
35
+ maxDepth: _types.MAX_NESTED_LIST_INDENTATION
34
36
  });
35
- if (!result || result.maxDepth >= _types.MAX_NESTED_LIST_INDENTATION) {
37
+ if (!result) {
36
38
  return;
37
39
  }
38
- var elements = result.elements,
40
+ var items = result.items,
39
41
  startIndex = result.startIndex,
40
42
  endIndex = result.endIndex;
41
43
 
42
44
  // Build replacement — handles both indent (all depths >= 0)
43
45
  // and outdent (some depths may be < 0, producing extracted paragraphs).
44
- var _buildReplacementFrag = (0, _listIndentation.buildReplacementFragment)(elements, tr.doc.type.schema),
46
+ var _buildReplacementFrag = (0, _listIndentation.buildReplacementFragment)(items, tr.doc.type.schema),
45
47
  fragment = _buildReplacementFrag.fragment,
46
48
  contentStartOffsets = _buildReplacementFrag.contentStartOffsets;
47
49
  if (fragment.size === 0) {
48
50
  return;
49
51
  }
50
52
  tr.replaceWith(rootListStart, rootListEnd, fragment);
51
- var fromContentStart = elements[startIndex].pos + 1;
52
- var toContentStart = elements[endIndex].pos + 1;
53
- var fromOffset = originalSelection.from - fromContentStart;
54
- var toOffset = originalSelection.to - toContentStart;
55
- var clamp = function clamp(pos) {
56
- return Math.min(Math.max(0, pos), tr.doc.content.size);
57
- };
58
- var from = clamp(rootListStart + contentStartOffsets[startIndex] + fromOffset);
59
- var to = clamp(rootListStart + contentStartOffsets[endIndex] + toOffset);
53
+ var _computeSelectionOffs = (0, _lists.computeSelectionOffsets)({
54
+ items: items,
55
+ startIndex: startIndex,
56
+ endIndex: endIndex,
57
+ originalFrom: originalSelection.from,
58
+ originalTo: originalSelection.to,
59
+ contentStartOffsets: contentStartOffsets,
60
+ rootListStart: rootListStart,
61
+ docSize: tr.doc.content.size
62
+ }),
63
+ from = _computeSelectionOffs.from,
64
+ to = _computeSelectionOffs.to;
60
65
 
61
66
  // Restore selection using the positional offsets from the rebuild.
62
- (0, _listIndentation.restoreSelection)({
67
+ (0, _lists.restoreSelection)({
63
68
  tr: tr,
64
69
  originalSelection: originalSelection,
65
70
  from: from,
@@ -5,20 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.buildReplacementFragment = buildReplacementFragment;
7
7
  exports.flattenList = flattenList;
8
- exports.restoreSelection = restoreSelection;
9
- var _selection = require("@atlaskit/editor-common/selection");
8
+ var _lists = require("@atlaskit/editor-common/lists");
10
9
  var _utils = require("@atlaskit/editor-common/utils");
11
- var _model = require("@atlaskit/editor-prosemirror/model");
12
- var _state = require("@atlaskit/editor-prosemirror/state");
13
10
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
14
11
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
15
12
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
16
- /**
17
- * A single content-bearing list element extracted from the PM tree.
18
- * Wrapper `listItem` nodes (those with no non-list children) are discarded;
19
- * only items the user can actually see and select are represented.
20
- */
21
-
22
13
  /**
23
14
  * Returns true if a listItem has at least one non-list child (paragraph, etc.).
24
15
  */
@@ -37,62 +28,31 @@ function contentSize(listItem) {
37
28
  return size + ((0, _utils.isListNode)(child) ? 0 : child.nodeSize);
38
29
  }, 0);
39
30
  }
31
+
40
32
  /**
41
- * Flatten a root list into a flat array of content-bearing `ListElement`
42
- * objects and simultaneously determine which elements intersect the user's
43
- * selection.
33
+ * Flatten a root list into a flat array of content-bearing items
34
+ * and simultaneously determine which elements intersect the user's selection.
35
+ *
36
+ * Delegates to the shared `flattenListLike` with list-specific callbacks.
44
37
  * Selection intersection is checked against each item's content-only
45
38
  * span (excluding nested lists).
46
39
  */
47
- function flattenList(_ref) {
48
- var doc = _ref.doc,
49
- rootListStart = _ref.rootListStart,
50
- rootListEnd = _ref.rootListEnd,
51
- selectionFrom = _ref.selectionFrom,
52
- selectionTo = _ref.selectionTo,
53
- delta = _ref.delta;
54
- var elements = [];
55
- var startIndex = -1;
56
- var endIndex = -1;
57
- var maxDepth = 0;
58
- var rootDepth = doc.resolve(rootListStart).depth;
59
- doc.nodesBetween(rootListStart, rootListEnd, function (node, pos, parent) {
60
- if (!(0, _utils.isListItemNode)(node) || !hasContentChildren(node) || !(0, _utils.isListNode)(parent)) {
61
- return true;
62
- }
63
-
64
- // Check selection intersection using content-only bounds
65
- var cStart = pos + 1;
66
- var cEnd = cStart + contentSize(node);
67
- var isSelected = cStart < selectionTo && cEnd > selectionFrom;
68
- var depth = (doc.resolve(pos).depth - rootDepth - 1) / 2 + (isSelected ? delta : 0);
69
- elements.push({
70
- node: node,
71
- pos: pos,
72
- depth: depth,
73
- listType: parent.type.name,
74
- parentListAttrs: parent.attrs,
75
- isSelected: isSelected
76
- });
77
- if (isSelected) {
78
- var index = elements.length - 1;
79
- if (startIndex === -1) {
80
- startIndex = index;
81
- }
82
- endIndex = index;
83
- maxDepth = Math.max(maxDepth, depth);
40
+ function flattenList(options) {
41
+ return (0, _lists.flattenList)(options, {
42
+ isContentNode: function isContentNode(node, parent) {
43
+ return (0, _utils.isListItemNode)(node) && hasContentChildren(node) && (0, _utils.isListNode)(parent);
44
+ },
45
+ // +1 shifts from the listItem node boundary to the start of its content children
46
+ getSelectionBounds: function getSelectionBounds(node, pos) {
47
+ return {
48
+ start: pos + 1,
49
+ end: pos + 1 + contentSize(node)
50
+ };
51
+ },
52
+ getDepth: function getDepth(resolvedDepth, rootDepth) {
53
+ return (resolvedDepth - rootDepth - 1) / 2;
84
54
  }
85
- return true;
86
55
  });
87
- if (elements.length === 0 || startIndex === -1) {
88
- return null;
89
- }
90
- return {
91
- elements: elements,
92
- startIndex: startIndex,
93
- endIndex: endIndex,
94
- maxDepth: maxDepth
95
- };
96
56
  }
97
57
 
98
58
  /**
@@ -110,7 +70,7 @@ function extractContentChildren(listItem) {
110
70
  }
111
71
 
112
72
  /**
113
- * Rebuild a ProseMirror list tree from a flat array of `ListElement` objects
73
+ * Rebuild a ProseMirror list tree from a flat array of `FlattenedItem` objects
114
74
  * using a bottom-up stack approach.
115
75
  *
116
76
  * The algorithm tracks open list/listItem wrappers on a stack. As depth
@@ -207,106 +167,43 @@ function rebuildPMList(elements, schema) {
207
167
  }
208
168
  closeToDepth(0);
209
169
  var root = stack[0];
210
- return schema.nodes[root.listType].create(root.listAttrs, root.items);
211
- }
212
- /**
213
- * Build a replacement Fragment from a flat array of `ListElement` objects.
214
- *
215
- * Elements with depth >= 0 are grouped into consecutive list segments
216
- * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
217
- * past the root) are converted to their content children (paragraphs).
218
- * The result interleaves list nodes and extracted content in document order.
219
- */
220
- function buildReplacementFragment(elements, schema) {
221
- var fragment = _model.Fragment.empty;
222
- var pendingListSegment = [];
223
- var pendingStartIdx = 0;
170
+ var rebuilt = schema.nodes[root.listType].create(root.listAttrs, root.items);
171
+
172
+ // Compute content start offsets by walking the rebuilt tree.
224
173
  var contentStartOffsets = new Array(elements.length);
225
- var flushListSegment = function flushListSegment() {
226
- if (pendingListSegment.length > 0) {
227
- var fragmentOffset = fragment.size;
228
- var rebuilt = rebuildPMList(pendingListSegment, schema);
229
- if (rebuilt) {
230
- // Walk the rebuilt tree to find content-bearing listItem positions.
231
- // descendants() visits in document order matching the element order.
232
- var segIdx = 0;
233
- rebuilt.descendants(function (node, pos) {
234
- if ((0, _utils.isListItemNode)(node) && hasContentChildren(node)) {
235
- // pos is relative to rebuilt's content start;
236
- // +1 for rebuilt's opening tag, +1 for listItem's opening tag
237
- contentStartOffsets[pendingStartIdx + segIdx] = fragmentOffset + 1 + pos + 1;
238
- segIdx++;
239
- }
240
- return true;
241
- });
242
- fragment = fragment.addToEnd(rebuilt);
243
- }
244
- pendingListSegment = [];
174
+ var segIdx = 0;
175
+ rebuilt.descendants(function (node, pos) {
176
+ if ((0, _utils.isListItemNode)(node) && hasContentChildren(node)) {
177
+ // +1 for rebuilt's opening tag, +1 for listItem's opening tag
178
+ contentStartOffsets[segIdx] = 1 + pos + 1;
179
+ segIdx++;
245
180
  }
246
- };
247
- var elIdx = 0;
248
- var _iterator2 = _createForOfIteratorHelper(elements),
249
- _step2;
250
- try {
251
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
252
- var el = _step2.value;
253
- if (el.depth < 0) {
254
- flushListSegment();
255
- // Extracted element — content children become top-level nodes.
256
- // Record offset of first content child.
257
- contentStartOffsets[elIdx] = fragment.size;
258
- var _iterator3 = _createForOfIteratorHelper(extractContentChildren(el.node)),
259
- _step3;
260
- try {
261
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
262
- var node = _step3.value;
263
- fragment = fragment.addToEnd(node);
264
- }
265
- } catch (err) {
266
- _iterator3.e(err);
267
- } finally {
268
- _iterator3.f();
269
- }
270
- } else {
271
- if (pendingListSegment.length === 0) {
272
- pendingStartIdx = elIdx;
273
- }
274
- pendingListSegment.push(el);
275
- }
276
- elIdx++;
277
- }
278
- } catch (err) {
279
- _iterator2.e(err);
280
- } finally {
281
- _iterator2.f();
282
- }
283
- flushListSegment();
181
+ return true;
182
+ });
284
183
  return {
285
- fragment: fragment,
184
+ node: rebuilt,
286
185
  contentStartOffsets: contentStartOffsets
287
186
  };
288
187
  }
188
+
289
189
  /**
290
- * Restore the transaction's selection after a list structural change.
190
+ * Build a replacement Fragment from a flat array of `FlattenedItem` objects.
291
191
  *
292
- * Uses the content start offsets computed during fragment rebuild to
293
- * map each selection endpoint to its new absolute position.
192
+ * Elements with depth >= 0 are grouped into consecutive list segments
193
+ * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
194
+ * past the root) are converted to their content children (paragraphs).
195
+ * The result interleaves list nodes and extracted content in document order.
196
+ *
197
+ * Delegates to the shared `buildReplacementFragment` with list-specific
198
+ * rebuild and extraction functions.
294
199
  */
295
- function restoreSelection(_ref2) {
296
- var tr = _ref2.tr,
297
- originalSelection = _ref2.originalSelection,
298
- from = _ref2.from,
299
- to = _ref2.to;
300
- var maxPos = tr.doc.content.size;
301
- if (originalSelection instanceof _state.NodeSelection) {
302
- try {
303
- tr.setSelection(_state.NodeSelection.create(tr.doc, Math.min(from, maxPos - 1)));
304
- } catch (_unused) {
305
- tr.setSelection(_state.Selection.near(tr.doc.resolve(from)));
200
+ function buildReplacementFragment(elements, schema) {
201
+ return (0, _lists.buildReplacementFragment)({
202
+ items: elements,
203
+ schema: schema,
204
+ rebuildFn: rebuildPMList,
205
+ extractContentFn: function extractContentFn(item) {
206
+ return extractContentChildren(item.node);
306
207
  }
307
- } else if (originalSelection instanceof _selection.GapCursorSelection) {
308
- tr.setSelection(new _selection.GapCursorSelection(tr.doc.resolve(from), originalSelection.side));
309
- } else {
310
- tr.setSelection(_state.TextSelection.create(tr.doc, from, to));
311
- }
208
+ });
312
209
  }
@@ -1,11 +1,12 @@
1
+ import { restoreSelection, computeSelectionOffsets } from '@atlaskit/editor-common/lists';
1
2
  import { MAX_NESTED_LIST_INDENTATION } from '../../types';
2
3
  import { findFirstParentListNode, findRootParentListNode } from '../utils/find';
3
- import { buildReplacementFragment, flattenList, restoreSelection } from '../utils/list-indentation';
4
+ import { buildReplacementFragment, flattenList } from '../utils/list-indentation';
4
5
 
5
6
  /**
6
7
  * Moves the selected list items n levels up (negative delta) or down (positive delta).
7
8
  */
8
- export function moveSelectedListItems(tr, delta) {
9
+ export function moveSelectedListItems(tr, indentDelta) {
9
10
  const originalSelection = tr.selection;
10
11
 
11
12
  // Find the root list so depth adjustments are absolute
@@ -25,13 +26,14 @@ export function moveSelectedListItems(tr, delta) {
25
26
  rootListEnd,
26
27
  selectionFrom: originalSelection.from,
27
28
  selectionTo: originalSelection.to,
28
- delta
29
+ indentDelta,
30
+ maxDepth: MAX_NESTED_LIST_INDENTATION
29
31
  });
30
- if (!result || result.maxDepth >= MAX_NESTED_LIST_INDENTATION) {
32
+ if (!result) {
31
33
  return;
32
34
  }
33
35
  const {
34
- elements,
36
+ items,
35
37
  startIndex,
36
38
  endIndex
37
39
  } = result;
@@ -41,18 +43,24 @@ export function moveSelectedListItems(tr, delta) {
41
43
  const {
42
44
  fragment,
43
45
  contentStartOffsets
44
- } = buildReplacementFragment(elements, tr.doc.type.schema);
46
+ } = buildReplacementFragment(items, tr.doc.type.schema);
45
47
  if (fragment.size === 0) {
46
48
  return;
47
49
  }
48
50
  tr.replaceWith(rootListStart, rootListEnd, fragment);
49
- const fromContentStart = elements[startIndex].pos + 1;
50
- const toContentStart = elements[endIndex].pos + 1;
51
- const fromOffset = originalSelection.from - fromContentStart;
52
- const toOffset = originalSelection.to - toContentStart;
53
- const clamp = pos => Math.min(Math.max(0, pos), tr.doc.content.size);
54
- const from = clamp(rootListStart + contentStartOffsets[startIndex] + fromOffset);
55
- const to = clamp(rootListStart + contentStartOffsets[endIndex] + toOffset);
51
+ const {
52
+ from,
53
+ to
54
+ } = computeSelectionOffsets({
55
+ items,
56
+ startIndex,
57
+ endIndex,
58
+ originalFrom: originalSelection.from,
59
+ originalTo: originalSelection.to,
60
+ contentStartOffsets,
61
+ rootListStart,
62
+ docSize: tr.doc.content.size
63
+ });
56
64
 
57
65
  // Restore selection using the positional offsets from the rebuild.
58
66
  restoreSelection({
@@ -1,14 +1,5 @@
1
- import { GapCursorSelection } from '@atlaskit/editor-common/selection';
1
+ import { buildReplacementFragment as buildReplacementFragmentBase, flattenList as flattenListBase } from '@atlaskit/editor-common/lists';
2
2
  import { isListItemNode, isListNode } from '@atlaskit/editor-common/utils';
3
- import { Fragment } from '@atlaskit/editor-prosemirror/model';
4
- import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
5
-
6
- /**
7
- * A single content-bearing list element extracted from the PM tree.
8
- * Wrapper `listItem` nodes (those with no non-list children) are discarded;
9
- * only items the user can actually see and select are represented.
10
- */
11
-
12
3
  /**
13
4
  * Returns true if a listItem has at least one non-list child (paragraph, etc.).
14
5
  */
@@ -25,63 +16,25 @@ function contentSize(listItem) {
25
16
  return size + (isListNode(child) ? 0 : child.nodeSize);
26
17
  }, 0);
27
18
  }
19
+
28
20
  /**
29
- * Flatten a root list into a flat array of content-bearing `ListElement`
30
- * objects and simultaneously determine which elements intersect the user's
31
- * selection.
21
+ * Flatten a root list into a flat array of content-bearing items
22
+ * and simultaneously determine which elements intersect the user's selection.
23
+ *
24
+ * Delegates to the shared `flattenListLike` with list-specific callbacks.
32
25
  * Selection intersection is checked against each item's content-only
33
26
  * span (excluding nested lists).
34
27
  */
35
- export function flattenList({
36
- doc,
37
- rootListStart,
38
- rootListEnd,
39
- selectionFrom,
40
- selectionTo,
41
- delta
42
- }) {
43
- const elements = [];
44
- let startIndex = -1;
45
- let endIndex = -1;
46
- let maxDepth = 0;
47
- const rootDepth = doc.resolve(rootListStart).depth;
48
- doc.nodesBetween(rootListStart, rootListEnd, (node, pos, parent) => {
49
- if (!isListItemNode(node) || !hasContentChildren(node) || !isListNode(parent)) {
50
- return true;
51
- }
52
-
53
- // Check selection intersection using content-only bounds
54
- const cStart = pos + 1;
55
- const cEnd = cStart + contentSize(node);
56
- const isSelected = cStart < selectionTo && cEnd > selectionFrom;
57
- const depth = (doc.resolve(pos).depth - rootDepth - 1) / 2 + (isSelected ? delta : 0);
58
- elements.push({
59
- node,
60
- pos,
61
- depth,
62
- listType: parent.type.name,
63
- parentListAttrs: parent.attrs,
64
- isSelected
65
- });
66
- if (isSelected) {
67
- const index = elements.length - 1;
68
- if (startIndex === -1) {
69
- startIndex = index;
70
- }
71
- endIndex = index;
72
- maxDepth = Math.max(maxDepth, depth);
73
- }
74
- return true;
28
+ export function flattenList(options) {
29
+ return flattenListBase(options, {
30
+ isContentNode: (node, parent) => isListItemNode(node) && hasContentChildren(node) && isListNode(parent),
31
+ // +1 shifts from the listItem node boundary to the start of its content children
32
+ getSelectionBounds: (node, pos) => ({
33
+ start: pos + 1,
34
+ end: pos + 1 + contentSize(node)
35
+ }),
36
+ getDepth: (resolvedDepth, rootDepth) => (resolvedDepth - rootDepth - 1) / 2
75
37
  });
76
- if (elements.length === 0 || startIndex === -1) {
77
- return null;
78
- }
79
- return {
80
- elements,
81
- startIndex,
82
- endIndex,
83
- maxDepth
84
- };
85
38
  }
86
39
 
87
40
  /**
@@ -99,7 +52,7 @@ function extractContentChildren(listItem) {
99
52
  }
100
53
 
101
54
  /**
102
- * Rebuild a ProseMirror list tree from a flat array of `ListElement` objects
55
+ * Rebuild a ProseMirror list tree from a flat array of `FlattenedItem` objects
103
56
  * using a bottom-up stack approach.
104
57
  *
105
58
  * The algorithm tracks open list/listItem wrappers on a stack. As depth
@@ -182,89 +135,41 @@ function rebuildPMList(elements, schema) {
182
135
  // Close all remaining open lists
183
136
  closeToDepth(0);
184
137
  const root = stack[0];
185
- return schema.nodes[root.listType].create(root.listAttrs, root.items);
186
- }
187
- /**
188
- * Build a replacement Fragment from a flat array of `ListElement` objects.
189
- *
190
- * Elements with depth >= 0 are grouped into consecutive list segments
191
- * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
192
- * past the root) are converted to their content children (paragraphs).
193
- * The result interleaves list nodes and extracted content in document order.
194
- */
195
- export function buildReplacementFragment(elements, schema) {
196
- let fragment = Fragment.empty;
197
- let pendingListSegment = [];
198
- let pendingStartIdx = 0;
138
+ const rebuilt = schema.nodes[root.listType].create(root.listAttrs, root.items);
139
+
140
+ // Compute content start offsets by walking the rebuilt tree.
199
141
  const contentStartOffsets = new Array(elements.length);
200
- const flushListSegment = () => {
201
- if (pendingListSegment.length > 0) {
202
- const fragmentOffset = fragment.size;
203
- const rebuilt = rebuildPMList(pendingListSegment, schema);
204
- if (rebuilt) {
205
- // Walk the rebuilt tree to find content-bearing listItem positions.
206
- // descendants() visits in document order matching the element order.
207
- let segIdx = 0;
208
- rebuilt.descendants((node, pos) => {
209
- if (isListItemNode(node) && hasContentChildren(node)) {
210
- // pos is relative to rebuilt's content start;
211
- // +1 for rebuilt's opening tag, +1 for listItem's opening tag
212
- contentStartOffsets[pendingStartIdx + segIdx] = fragmentOffset + 1 + pos + 1;
213
- segIdx++;
214
- }
215
- return true;
216
- });
217
- fragment = fragment.addToEnd(rebuilt);
218
- }
219
- pendingListSegment = [];
142
+ let segIdx = 0;
143
+ rebuilt.descendants((node, pos) => {
144
+ if (isListItemNode(node) && hasContentChildren(node)) {
145
+ // +1 for rebuilt's opening tag, +1 for listItem's opening tag
146
+ contentStartOffsets[segIdx] = 1 + pos + 1;
147
+ segIdx++;
220
148
  }
221
- };
222
- let elIdx = 0;
223
- for (const el of elements) {
224
- if (el.depth < 0) {
225
- flushListSegment();
226
- // Extracted element — content children become top-level nodes.
227
- // Record offset of first content child.
228
- contentStartOffsets[elIdx] = fragment.size;
229
- for (const node of extractContentChildren(el.node)) {
230
- fragment = fragment.addToEnd(node);
231
- }
232
- } else {
233
- if (pendingListSegment.length === 0) {
234
- pendingStartIdx = elIdx;
235
- }
236
- pendingListSegment.push(el);
237
- }
238
- elIdx++;
239
- }
240
- flushListSegment();
149
+ return true;
150
+ });
241
151
  return {
242
- fragment,
152
+ node: rebuilt,
243
153
  contentStartOffsets
244
154
  };
245
155
  }
156
+
246
157
  /**
247
- * Restore the transaction's selection after a list structural change.
158
+ * Build a replacement Fragment from a flat array of `FlattenedItem` objects.
248
159
  *
249
- * Uses the content start offsets computed during fragment rebuild to
250
- * map each selection endpoint to its new absolute position.
160
+ * Elements with depth >= 0 are grouped into consecutive list segments
161
+ * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
162
+ * past the root) are converted to their content children (paragraphs).
163
+ * The result interleaves list nodes and extracted content in document order.
164
+ *
165
+ * Delegates to the shared `buildReplacementFragment` with list-specific
166
+ * rebuild and extraction functions.
251
167
  */
252
- export function restoreSelection({
253
- tr,
254
- originalSelection,
255
- from,
256
- to
257
- }) {
258
- const maxPos = tr.doc.content.size;
259
- if (originalSelection instanceof NodeSelection) {
260
- try {
261
- tr.setSelection(NodeSelection.create(tr.doc, Math.min(from, maxPos - 1)));
262
- } catch {
263
- tr.setSelection(Selection.near(tr.doc.resolve(from)));
264
- }
265
- } else if (originalSelection instanceof GapCursorSelection) {
266
- tr.setSelection(new GapCursorSelection(tr.doc.resolve(from), originalSelection.side));
267
- } else {
268
- tr.setSelection(TextSelection.create(tr.doc, from, to));
269
- }
168
+ export function buildReplacementFragment(elements, schema) {
169
+ return buildReplacementFragmentBase({
170
+ items: elements,
171
+ schema,
172
+ rebuildFn: rebuildPMList,
173
+ extractContentFn: item => extractContentChildren(item.node)
174
+ });
270
175
  }
@@ -1,11 +1,12 @@
1
+ import { restoreSelection, computeSelectionOffsets } from '@atlaskit/editor-common/lists';
1
2
  import { MAX_NESTED_LIST_INDENTATION } from '../../types';
2
3
  import { findFirstParentListNode, findRootParentListNode } from '../utils/find';
3
- import { buildReplacementFragment, flattenList, restoreSelection } from '../utils/list-indentation';
4
+ import { buildReplacementFragment, flattenList } from '../utils/list-indentation';
4
5
 
5
6
  /**
6
7
  * Moves the selected list items n levels up (negative delta) or down (positive delta).
7
8
  */
8
- export function moveSelectedListItems(tr, delta) {
9
+ export function moveSelectedListItems(tr, indentDelta) {
9
10
  var originalSelection = tr.selection;
10
11
 
11
12
  // Find the root list so depth adjustments are absolute
@@ -25,33 +26,37 @@ export function moveSelectedListItems(tr, delta) {
25
26
  rootListEnd: rootListEnd,
26
27
  selectionFrom: originalSelection.from,
27
28
  selectionTo: originalSelection.to,
28
- delta: delta
29
+ indentDelta: indentDelta,
30
+ maxDepth: MAX_NESTED_LIST_INDENTATION
29
31
  });
30
- if (!result || result.maxDepth >= MAX_NESTED_LIST_INDENTATION) {
32
+ if (!result) {
31
33
  return;
32
34
  }
33
- var elements = result.elements,
35
+ var items = result.items,
34
36
  startIndex = result.startIndex,
35
37
  endIndex = result.endIndex;
36
38
 
37
39
  // Build replacement — handles both indent (all depths >= 0)
38
40
  // and outdent (some depths may be < 0, producing extracted paragraphs).
39
- var _buildReplacementFrag = buildReplacementFragment(elements, tr.doc.type.schema),
41
+ var _buildReplacementFrag = buildReplacementFragment(items, tr.doc.type.schema),
40
42
  fragment = _buildReplacementFrag.fragment,
41
43
  contentStartOffsets = _buildReplacementFrag.contentStartOffsets;
42
44
  if (fragment.size === 0) {
43
45
  return;
44
46
  }
45
47
  tr.replaceWith(rootListStart, rootListEnd, fragment);
46
- var fromContentStart = elements[startIndex].pos + 1;
47
- var toContentStart = elements[endIndex].pos + 1;
48
- var fromOffset = originalSelection.from - fromContentStart;
49
- var toOffset = originalSelection.to - toContentStart;
50
- var clamp = function clamp(pos) {
51
- return Math.min(Math.max(0, pos), tr.doc.content.size);
52
- };
53
- var from = clamp(rootListStart + contentStartOffsets[startIndex] + fromOffset);
54
- var to = clamp(rootListStart + contentStartOffsets[endIndex] + toOffset);
48
+ var _computeSelectionOffs = computeSelectionOffsets({
49
+ items: items,
50
+ startIndex: startIndex,
51
+ endIndex: endIndex,
52
+ originalFrom: originalSelection.from,
53
+ originalTo: originalSelection.to,
54
+ contentStartOffsets: contentStartOffsets,
55
+ rootListStart: rootListStart,
56
+ docSize: tr.doc.content.size
57
+ }),
58
+ from = _computeSelectionOffs.from,
59
+ to = _computeSelectionOffs.to;
55
60
 
56
61
  // Restore selection using the positional offsets from the rebuild.
57
62
  restoreSelection({
@@ -1,17 +1,8 @@
1
1
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
2
2
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
3
3
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
- import { GapCursorSelection } from '@atlaskit/editor-common/selection';
4
+ import { buildReplacementFragment as buildReplacementFragmentBase, flattenList as flattenListBase } from '@atlaskit/editor-common/lists';
5
5
  import { isListItemNode, isListNode } from '@atlaskit/editor-common/utils';
6
- import { Fragment } from '@atlaskit/editor-prosemirror/model';
7
- import { NodeSelection, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
8
-
9
- /**
10
- * A single content-bearing list element extracted from the PM tree.
11
- * Wrapper `listItem` nodes (those with no non-list children) are discarded;
12
- * only items the user can actually see and select are represented.
13
- */
14
-
15
6
  /**
16
7
  * Returns true if a listItem has at least one non-list child (paragraph, etc.).
17
8
  */
@@ -30,62 +21,31 @@ function contentSize(listItem) {
30
21
  return size + (isListNode(child) ? 0 : child.nodeSize);
31
22
  }, 0);
32
23
  }
24
+
33
25
  /**
34
- * Flatten a root list into a flat array of content-bearing `ListElement`
35
- * objects and simultaneously determine which elements intersect the user's
36
- * selection.
26
+ * Flatten a root list into a flat array of content-bearing items
27
+ * and simultaneously determine which elements intersect the user's selection.
28
+ *
29
+ * Delegates to the shared `flattenListLike` with list-specific callbacks.
37
30
  * Selection intersection is checked against each item's content-only
38
31
  * span (excluding nested lists).
39
32
  */
40
- export function flattenList(_ref) {
41
- var doc = _ref.doc,
42
- rootListStart = _ref.rootListStart,
43
- rootListEnd = _ref.rootListEnd,
44
- selectionFrom = _ref.selectionFrom,
45
- selectionTo = _ref.selectionTo,
46
- delta = _ref.delta;
47
- var elements = [];
48
- var startIndex = -1;
49
- var endIndex = -1;
50
- var maxDepth = 0;
51
- var rootDepth = doc.resolve(rootListStart).depth;
52
- doc.nodesBetween(rootListStart, rootListEnd, function (node, pos, parent) {
53
- if (!isListItemNode(node) || !hasContentChildren(node) || !isListNode(parent)) {
54
- return true;
33
+ export function flattenList(options) {
34
+ return flattenListBase(options, {
35
+ isContentNode: function isContentNode(node, parent) {
36
+ return isListItemNode(node) && hasContentChildren(node) && isListNode(parent);
37
+ },
38
+ // +1 shifts from the listItem node boundary to the start of its content children
39
+ getSelectionBounds: function getSelectionBounds(node, pos) {
40
+ return {
41
+ start: pos + 1,
42
+ end: pos + 1 + contentSize(node)
43
+ };
44
+ },
45
+ getDepth: function getDepth(resolvedDepth, rootDepth) {
46
+ return (resolvedDepth - rootDepth - 1) / 2;
55
47
  }
56
-
57
- // Check selection intersection using content-only bounds
58
- var cStart = pos + 1;
59
- var cEnd = cStart + contentSize(node);
60
- var isSelected = cStart < selectionTo && cEnd > selectionFrom;
61
- var depth = (doc.resolve(pos).depth - rootDepth - 1) / 2 + (isSelected ? delta : 0);
62
- elements.push({
63
- node: node,
64
- pos: pos,
65
- depth: depth,
66
- listType: parent.type.name,
67
- parentListAttrs: parent.attrs,
68
- isSelected: isSelected
69
- });
70
- if (isSelected) {
71
- var index = elements.length - 1;
72
- if (startIndex === -1) {
73
- startIndex = index;
74
- }
75
- endIndex = index;
76
- maxDepth = Math.max(maxDepth, depth);
77
- }
78
- return true;
79
48
  });
80
- if (elements.length === 0 || startIndex === -1) {
81
- return null;
82
- }
83
- return {
84
- elements: elements,
85
- startIndex: startIndex,
86
- endIndex: endIndex,
87
- maxDepth: maxDepth
88
- };
89
49
  }
90
50
 
91
51
  /**
@@ -103,7 +63,7 @@ function extractContentChildren(listItem) {
103
63
  }
104
64
 
105
65
  /**
106
- * Rebuild a ProseMirror list tree from a flat array of `ListElement` objects
66
+ * Rebuild a ProseMirror list tree from a flat array of `FlattenedItem` objects
107
67
  * using a bottom-up stack approach.
108
68
  *
109
69
  * The algorithm tracks open list/listItem wrappers on a stack. As depth
@@ -200,106 +160,43 @@ function rebuildPMList(elements, schema) {
200
160
  }
201
161
  closeToDepth(0);
202
162
  var root = stack[0];
203
- return schema.nodes[root.listType].create(root.listAttrs, root.items);
204
- }
205
- /**
206
- * Build a replacement Fragment from a flat array of `ListElement` objects.
207
- *
208
- * Elements with depth >= 0 are grouped into consecutive list segments
209
- * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
210
- * past the root) are converted to their content children (paragraphs).
211
- * The result interleaves list nodes and extracted content in document order.
212
- */
213
- export function buildReplacementFragment(elements, schema) {
214
- var fragment = Fragment.empty;
215
- var pendingListSegment = [];
216
- var pendingStartIdx = 0;
163
+ var rebuilt = schema.nodes[root.listType].create(root.listAttrs, root.items);
164
+
165
+ // Compute content start offsets by walking the rebuilt tree.
217
166
  var contentStartOffsets = new Array(elements.length);
218
- var flushListSegment = function flushListSegment() {
219
- if (pendingListSegment.length > 0) {
220
- var fragmentOffset = fragment.size;
221
- var rebuilt = rebuildPMList(pendingListSegment, schema);
222
- if (rebuilt) {
223
- // Walk the rebuilt tree to find content-bearing listItem positions.
224
- // descendants() visits in document order matching the element order.
225
- var segIdx = 0;
226
- rebuilt.descendants(function (node, pos) {
227
- if (isListItemNode(node) && hasContentChildren(node)) {
228
- // pos is relative to rebuilt's content start;
229
- // +1 for rebuilt's opening tag, +1 for listItem's opening tag
230
- contentStartOffsets[pendingStartIdx + segIdx] = fragmentOffset + 1 + pos + 1;
231
- segIdx++;
232
- }
233
- return true;
234
- });
235
- fragment = fragment.addToEnd(rebuilt);
236
- }
237
- pendingListSegment = [];
238
- }
239
- };
240
- var elIdx = 0;
241
- var _iterator2 = _createForOfIteratorHelper(elements),
242
- _step2;
243
- try {
244
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
245
- var el = _step2.value;
246
- if (el.depth < 0) {
247
- flushListSegment();
248
- // Extracted element — content children become top-level nodes.
249
- // Record offset of first content child.
250
- contentStartOffsets[elIdx] = fragment.size;
251
- var _iterator3 = _createForOfIteratorHelper(extractContentChildren(el.node)),
252
- _step3;
253
- try {
254
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
255
- var node = _step3.value;
256
- fragment = fragment.addToEnd(node);
257
- }
258
- } catch (err) {
259
- _iterator3.e(err);
260
- } finally {
261
- _iterator3.f();
262
- }
263
- } else {
264
- if (pendingListSegment.length === 0) {
265
- pendingStartIdx = elIdx;
266
- }
267
- pendingListSegment.push(el);
268
- }
269
- elIdx++;
167
+ var segIdx = 0;
168
+ rebuilt.descendants(function (node, pos) {
169
+ if (isListItemNode(node) && hasContentChildren(node)) {
170
+ // +1 for rebuilt's opening tag, +1 for listItem's opening tag
171
+ contentStartOffsets[segIdx] = 1 + pos + 1;
172
+ segIdx++;
270
173
  }
271
- } catch (err) {
272
- _iterator2.e(err);
273
- } finally {
274
- _iterator2.f();
275
- }
276
- flushListSegment();
174
+ return true;
175
+ });
277
176
  return {
278
- fragment: fragment,
177
+ node: rebuilt,
279
178
  contentStartOffsets: contentStartOffsets
280
179
  };
281
180
  }
181
+
282
182
  /**
283
- * Restore the transaction's selection after a list structural change.
183
+ * Build a replacement Fragment from a flat array of `FlattenedItem` objects.
284
184
  *
285
- * Uses the content start offsets computed during fragment rebuild to
286
- * map each selection endpoint to its new absolute position.
185
+ * Elements with depth >= 0 are grouped into consecutive list segments
186
+ * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
187
+ * past the root) are converted to their content children (paragraphs).
188
+ * The result interleaves list nodes and extracted content in document order.
189
+ *
190
+ * Delegates to the shared `buildReplacementFragment` with list-specific
191
+ * rebuild and extraction functions.
287
192
  */
288
- export function restoreSelection(_ref2) {
289
- var tr = _ref2.tr,
290
- originalSelection = _ref2.originalSelection,
291
- from = _ref2.from,
292
- to = _ref2.to;
293
- var maxPos = tr.doc.content.size;
294
- if (originalSelection instanceof NodeSelection) {
295
- try {
296
- tr.setSelection(NodeSelection.create(tr.doc, Math.min(from, maxPos - 1)));
297
- } catch (_unused) {
298
- tr.setSelection(Selection.near(tr.doc.resolve(from)));
193
+ export function buildReplacementFragment(elements, schema) {
194
+ return buildReplacementFragmentBase({
195
+ items: elements,
196
+ schema: schema,
197
+ rebuildFn: rebuildPMList,
198
+ extractContentFn: function extractContentFn(item) {
199
+ return extractContentChildren(item.node);
299
200
  }
300
- } else if (originalSelection instanceof GapCursorSelection) {
301
- tr.setSelection(new GapCursorSelection(tr.doc.resolve(from), originalSelection.side));
302
- } else {
303
- tr.setSelection(TextSelection.create(tr.doc, from, to));
304
- }
201
+ });
305
202
  }
@@ -2,4 +2,4 @@ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
2
2
  /**
3
3
  * Moves the selected list items n levels up (negative delta) or down (positive delta).
4
4
  */
5
- export declare function moveSelectedListItems(tr: Transaction, delta: number): void;
5
+ export declare function moveSelectedListItems(tr: Transaction, indentDelta: number): void;
@@ -1,76 +1,23 @@
1
- import type { Attrs, Node as PMNode, Schema } from '@atlaskit/editor-prosemirror/model';
2
- import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
- import type { Transaction } from '@atlaskit/editor-prosemirror/state';
4
- import { Selection } from '@atlaskit/editor-prosemirror/state';
1
+ import { type BuildResult, type FlattenedItem, type FlattenListOptions, type FlattenListResult } from '@atlaskit/editor-common/lists';
2
+ import type { Schema } from '@atlaskit/editor-prosemirror/model';
5
3
  /**
6
- * A single content-bearing list element extracted from the PM tree.
7
- * Wrapper `listItem` nodes (those with no non-list children) are discarded;
8
- * only items the user can actually see and select are represented.
9
- */
10
- export interface ListElement {
11
- depth: number;
12
- /** Whether this element was within the user's selection (and had its depth adjusted). */
13
- isSelected: boolean;
14
- listType: 'bulletList' | 'orderedList';
15
- node: PMNode;
16
- /** Attributes of the immediate parent list node (bulletList/orderedList). */
17
- parentListAttrs: Attrs | null;
18
- pos: number;
19
- }
20
- export interface FlattenListResult {
21
- elements: ListElement[];
22
- endIndex: number;
23
- maxDepth: number;
24
- startIndex: number;
25
- }
26
- export interface FlattenListOptions {
27
- delta: number;
28
- doc: PMNode;
29
- rootListEnd: number;
30
- rootListStart: number;
31
- selectionFrom: number;
32
- selectionTo: number;
33
- }
34
- /**
35
- * Flatten a root list into a flat array of content-bearing `ListElement`
36
- * objects and simultaneously determine which elements intersect the user's
37
- * selection.
4
+ * Flatten a root list into a flat array of content-bearing items
5
+ * and simultaneously determine which elements intersect the user's selection.
6
+ *
7
+ * Delegates to the shared `flattenListLike` with list-specific callbacks.
38
8
  * Selection intersection is checked against each item's content-only
39
9
  * span (excluding nested lists).
40
10
  */
41
- export declare function flattenList({ doc, rootListStart, rootListEnd, selectionFrom, selectionTo, delta, }: FlattenListOptions): FlattenListResult | null;
42
- export interface BuildResult {
43
- /**
44
- * For each element (by index), the offset within the fragment where the
45
- * element's content begins. For list elements this is the position just
46
- * inside the listItem (pos + 1); for extracted elements it is the position
47
- * of the first extracted content child.
48
- *
49
- * To get the absolute document position after `tr.replaceWith(rangeStart, …)`,
50
- * add `rangeStart` to the offset.
51
- */
52
- contentStartOffsets: number[];
53
- fragment: Fragment;
54
- }
11
+ export declare function flattenList(options: FlattenListOptions): FlattenListResult | null;
55
12
  /**
56
- * Build a replacement Fragment from a flat array of `ListElement` objects.
13
+ * Build a replacement Fragment from a flat array of `FlattenedItem` objects.
57
14
  *
58
15
  * Elements with depth >= 0 are grouped into consecutive list segments
59
16
  * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
60
17
  * past the root) are converted to their content children (paragraphs).
61
18
  * The result interleaves list nodes and extracted content in document order.
62
- */
63
- export declare function buildReplacementFragment(elements: ListElement[], schema: Schema): BuildResult;
64
- export interface RestoreSelectionOptions {
65
- from: number;
66
- originalSelection: Selection;
67
- to: number;
68
- tr: Transaction;
69
- }
70
- /**
71
- * Restore the transaction's selection after a list structural change.
72
19
  *
73
- * Uses the content start offsets computed during fragment rebuild to
74
- * map each selection endpoint to its new absolute position.
20
+ * Delegates to the shared `buildReplacementFragment` with list-specific
21
+ * rebuild and extraction functions.
75
22
  */
76
- export declare function restoreSelection({ tr, originalSelection, from, to, }: RestoreSelectionOptions): void;
23
+ export declare function buildReplacementFragment(elements: FlattenedItem[], schema: Schema): BuildResult;
@@ -2,4 +2,4 @@ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
2
2
  /**
3
3
  * Moves the selected list items n levels up (negative delta) or down (positive delta).
4
4
  */
5
- export declare function moveSelectedListItems(tr: Transaction, delta: number): void;
5
+ export declare function moveSelectedListItems(tr: Transaction, indentDelta: number): void;
@@ -1,76 +1,23 @@
1
- import type { Attrs, Node as PMNode, Schema } from '@atlaskit/editor-prosemirror/model';
2
- import { Fragment } from '@atlaskit/editor-prosemirror/model';
3
- import type { Transaction } from '@atlaskit/editor-prosemirror/state';
4
- import { Selection } from '@atlaskit/editor-prosemirror/state';
1
+ import { type BuildResult, type FlattenedItem, type FlattenListOptions, type FlattenListResult } from '@atlaskit/editor-common/lists';
2
+ import type { Schema } from '@atlaskit/editor-prosemirror/model';
5
3
  /**
6
- * A single content-bearing list element extracted from the PM tree.
7
- * Wrapper `listItem` nodes (those with no non-list children) are discarded;
8
- * only items the user can actually see and select are represented.
9
- */
10
- export interface ListElement {
11
- depth: number;
12
- /** Whether this element was within the user's selection (and had its depth adjusted). */
13
- isSelected: boolean;
14
- listType: 'bulletList' | 'orderedList';
15
- node: PMNode;
16
- /** Attributes of the immediate parent list node (bulletList/orderedList). */
17
- parentListAttrs: Attrs | null;
18
- pos: number;
19
- }
20
- export interface FlattenListResult {
21
- elements: ListElement[];
22
- endIndex: number;
23
- maxDepth: number;
24
- startIndex: number;
25
- }
26
- export interface FlattenListOptions {
27
- delta: number;
28
- doc: PMNode;
29
- rootListEnd: number;
30
- rootListStart: number;
31
- selectionFrom: number;
32
- selectionTo: number;
33
- }
34
- /**
35
- * Flatten a root list into a flat array of content-bearing `ListElement`
36
- * objects and simultaneously determine which elements intersect the user's
37
- * selection.
4
+ * Flatten a root list into a flat array of content-bearing items
5
+ * and simultaneously determine which elements intersect the user's selection.
6
+ *
7
+ * Delegates to the shared `flattenListLike` with list-specific callbacks.
38
8
  * Selection intersection is checked against each item's content-only
39
9
  * span (excluding nested lists).
40
10
  */
41
- export declare function flattenList({ doc, rootListStart, rootListEnd, selectionFrom, selectionTo, delta, }: FlattenListOptions): FlattenListResult | null;
42
- export interface BuildResult {
43
- /**
44
- * For each element (by index), the offset within the fragment where the
45
- * element's content begins. For list elements this is the position just
46
- * inside the listItem (pos + 1); for extracted elements it is the position
47
- * of the first extracted content child.
48
- *
49
- * To get the absolute document position after `tr.replaceWith(rangeStart, …)`,
50
- * add `rangeStart` to the offset.
51
- */
52
- contentStartOffsets: number[];
53
- fragment: Fragment;
54
- }
11
+ export declare function flattenList(options: FlattenListOptions): FlattenListResult | null;
55
12
  /**
56
- * Build a replacement Fragment from a flat array of `ListElement` objects.
13
+ * Build a replacement Fragment from a flat array of `FlattenedItem` objects.
57
14
  *
58
15
  * Elements with depth >= 0 are grouped into consecutive list segments
59
16
  * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
60
17
  * past the root) are converted to their content children (paragraphs).
61
18
  * The result interleaves list nodes and extracted content in document order.
62
- */
63
- export declare function buildReplacementFragment(elements: ListElement[], schema: Schema): BuildResult;
64
- export interface RestoreSelectionOptions {
65
- from: number;
66
- originalSelection: Selection;
67
- to: number;
68
- tr: Transaction;
69
- }
70
- /**
71
- * Restore the transaction's selection after a list structural change.
72
19
  *
73
- * Uses the content start offsets computed during fragment rebuild to
74
- * map each selection endpoint to its new absolute position.
20
+ * Delegates to the shared `buildReplacementFragment` with list-specific
21
+ * rebuild and extraction functions.
75
22
  */
76
- export declare function restoreSelection({ tr, originalSelection, from, to, }: RestoreSelectionOptions): void;
23
+ export declare function buildReplacementFragment(elements: FlattenedItem[], schema: Schema): BuildResult;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-list",
3
- "version": "10.0.12",
3
+ "version": "10.1.0",
4
4
  "description": "List plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -38,11 +38,11 @@
38
38
  "@atlaskit/platform-feature-flags": "^1.1.0",
39
39
  "@atlaskit/prosemirror-history": "^0.2.0",
40
40
  "@atlaskit/prosemirror-input-rules": "^3.6.0",
41
- "@atlaskit/tmp-editor-statsig": "^44.0.0",
41
+ "@atlaskit/tmp-editor-statsig": "^44.1.0",
42
42
  "@babel/runtime": "^7.0.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@atlaskit/editor-common": "^112.7.0",
45
+ "@atlaskit/editor-common": "^112.8.0",
46
46
  "react": "^18.2.0",
47
47
  "react-intl-next": "npm:react-intl@^5.18.1"
48
48
  },