@atlaskit/editor-plugin-list 10.0.11 → 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 +17 -0
- package/dist/cjs/pm-plugins/actions/move-selected-list-items.js +20 -15
- package/dist/cjs/pm-plugins/actions/wrap-and-join-lists.js +1 -0
- package/dist/cjs/pm-plugins/utils/list-indentation.js +50 -153
- package/dist/es2019/pm-plugins/actions/move-selected-list-items.js +21 -13
- package/dist/es2019/pm-plugins/actions/wrap-and-join-lists.js +1 -0
- package/dist/es2019/pm-plugins/utils/list-indentation.js +44 -139
- package/dist/esm/pm-plugins/actions/move-selected-list-items.js +20 -15
- package/dist/esm/pm-plugins/actions/wrap-and-join-lists.js +1 -0
- package/dist/esm/pm-plugins/utils/list-indentation.js +50 -153
- package/dist/types/pm-plugins/actions/move-selected-list-items.d.ts +1 -1
- package/dist/types/pm-plugins/utils/list-indentation.d.ts +11 -64
- package/dist/types-ts4.5/pm-plugins/actions/move-selected-list-items.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/utils/list-indentation.d.ts +11 -64
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
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
|
+
|
|
14
|
+
## 10.0.12
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
|
|
3
20
|
## 10.0.11
|
|
4
21
|
|
|
5
22
|
### 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,
|
|
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
|
-
|
|
34
|
+
indentDelta: indentDelta,
|
|
35
|
+
maxDepth: _types.MAX_NESTED_LIST_INDENTATION
|
|
34
36
|
});
|
|
35
|
-
if (!result
|
|
37
|
+
if (!result) {
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
|
-
var
|
|
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)(
|
|
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
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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,
|
|
67
|
+
(0, _lists.restoreSelection)({
|
|
63
68
|
tr: tr,
|
|
64
69
|
originalSelection: originalSelection,
|
|
65
70
|
from: from,
|
|
@@ -93,6 +93,7 @@ function doWrapInList(tr, range, wrappers, joinBefore, listType) {
|
|
|
93
93
|
var parent = range.parent;
|
|
94
94
|
for (var _i2 = range.startIndex, e = range.endIndex, first = true; _i2 < e; _i2++, first = false) {
|
|
95
95
|
if (!first && (0, _transform.canSplit)(tr.doc, splitPos, splitDepth)) {
|
|
96
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
|
|
96
97
|
tr.split(splitPos, splitDepth);
|
|
97
98
|
splitPos += 2 * splitDepth;
|
|
98
99
|
}
|
|
@@ -5,20 +5,11 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.buildReplacementFragment = buildReplacementFragment;
|
|
7
7
|
exports.flattenList = flattenList;
|
|
8
|
-
|
|
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
|
|
42
|
-
*
|
|
43
|
-
*
|
|
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(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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 `
|
|
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
|
-
|
|
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
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
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
|
-
|
|
184
|
+
node: rebuilt,
|
|
286
185
|
contentStartOffsets: contentStartOffsets
|
|
287
186
|
};
|
|
288
187
|
}
|
|
188
|
+
|
|
289
189
|
/**
|
|
290
|
-
*
|
|
190
|
+
* Build a replacement Fragment from a flat array of `FlattenedItem` objects.
|
|
291
191
|
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
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
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
-
}
|
|
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
|
|
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,
|
|
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
|
-
|
|
29
|
+
indentDelta,
|
|
30
|
+
maxDepth: MAX_NESTED_LIST_INDENTATION
|
|
29
31
|
});
|
|
30
|
-
if (!result
|
|
32
|
+
if (!result) {
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
35
|
const {
|
|
34
|
-
|
|
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(
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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({
|
|
@@ -86,6 +86,7 @@ function doWrapInList(tr, range, wrappers, joinBefore, listType) {
|
|
|
86
86
|
const parent = range.parent;
|
|
87
87
|
for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
|
|
88
88
|
if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
|
|
89
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
|
|
89
90
|
tr.split(splitPos, splitDepth);
|
|
90
91
|
splitPos += 2 * splitDepth;
|
|
91
92
|
}
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
})
|
|
43
|
-
|
|
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 `
|
|
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
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
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
|
-
|
|
152
|
+
node: rebuilt,
|
|
243
153
|
contentStartOffsets
|
|
244
154
|
};
|
|
245
155
|
}
|
|
156
|
+
|
|
246
157
|
/**
|
|
247
|
-
*
|
|
158
|
+
* Build a replacement Fragment from a flat array of `FlattenedItem` objects.
|
|
248
159
|
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
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
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
|
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,
|
|
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
|
-
|
|
29
|
+
indentDelta: indentDelta,
|
|
30
|
+
maxDepth: MAX_NESTED_LIST_INDENTATION
|
|
29
31
|
});
|
|
30
|
-
if (!result
|
|
32
|
+
if (!result) {
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
|
-
var
|
|
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(
|
|
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
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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({
|
|
@@ -87,6 +87,7 @@ function doWrapInList(tr, range, wrappers, joinBefore, listType) {
|
|
|
87
87
|
var parent = range.parent;
|
|
88
88
|
for (var _i2 = range.startIndex, e = range.endIndex, first = true; _i2 < e; _i2++, first = false) {
|
|
89
89
|
if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
|
|
90
|
+
// eslint-disable-next-line @atlassian/perf-linting/no-expensive-split-replace -- Ignored via go/ees017 (to be fixed)
|
|
90
91
|
tr.split(splitPos, splitDepth);
|
|
91
92
|
splitPos += 2 * splitDepth;
|
|
92
93
|
}
|
|
@@ -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 {
|
|
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
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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 `
|
|
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
|
-
|
|
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
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
} finally {
|
|
274
|
-
_iterator2.f();
|
|
275
|
-
}
|
|
276
|
-
flushListSegment();
|
|
174
|
+
return true;
|
|
175
|
+
});
|
|
277
176
|
return {
|
|
278
|
-
|
|
177
|
+
node: rebuilt,
|
|
279
178
|
contentStartOffsets: contentStartOffsets
|
|
280
179
|
};
|
|
281
180
|
}
|
|
181
|
+
|
|
282
182
|
/**
|
|
283
|
-
*
|
|
183
|
+
* Build a replacement Fragment from a flat array of `FlattenedItem` objects.
|
|
284
184
|
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
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
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
}
|
|
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,
|
|
5
|
+
export declare function moveSelectedListItems(tr: Transaction, indentDelta: number): void;
|
|
@@ -1,76 +1,23 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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(
|
|
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 `
|
|
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
|
-
*
|
|
74
|
-
*
|
|
20
|
+
* Delegates to the shared `buildReplacementFragment` with list-specific
|
|
21
|
+
* rebuild and extraction functions.
|
|
75
22
|
*/
|
|
76
|
-
export declare function
|
|
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,
|
|
5
|
+
export declare function moveSelectedListItems(tr: Transaction, indentDelta: number): void;
|
|
@@ -1,76 +1,23 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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(
|
|
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 `
|
|
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
|
-
*
|
|
74
|
-
*
|
|
20
|
+
* Delegates to the shared `buildReplacementFragment` with list-specific
|
|
21
|
+
* rebuild and extraction functions.
|
|
75
22
|
*/
|
|
76
|
-
export declare function
|
|
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
|
|
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": "^
|
|
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.
|
|
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
|
},
|