@atlaskit/editor-plugin-list 9.0.27 → 10.0.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.
@@ -0,0 +1,298 @@
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
+ 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
+ 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';
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
+ /**
16
+ * Returns true if a listItem has at least one non-list child (paragraph, etc.).
17
+ */
18
+ function hasContentChildren(listItem) {
19
+ return listItem.children.some(function (child) {
20
+ return !isListNode(child);
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Compute the size of non-list (content) children of a listItem, which
26
+ * represents the "visible" bounds of the item for selection purposes.
27
+ */
28
+ function contentSize(listItem) {
29
+ return listItem.children.reduce(function (size, child) {
30
+ return size + (isListNode(child) ? 0 : child.nodeSize);
31
+ }, 0);
32
+ }
33
+ /**
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.
37
+ * Selection intersection is checked against each item's content-only
38
+ * span (excluding nested lists).
39
+ */
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;
55
+ }
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
+ });
68
+ if (isSelected) {
69
+ var index = elements.length - 1;
70
+ if (startIndex === -1) {
71
+ startIndex = index;
72
+ }
73
+ endIndex = index;
74
+ maxDepth = Math.max(maxDepth, depth);
75
+ }
76
+ return true;
77
+ });
78
+ if (elements.length === 0 || startIndex === -1) {
79
+ return null;
80
+ }
81
+ return {
82
+ elements: elements,
83
+ startIndex: startIndex,
84
+ endIndex: endIndex,
85
+ maxDepth: maxDepth
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Extract non-list (content) children from a listItem node.
91
+ */
92
+ function extractContentChildren(listItem) {
93
+ var children = [];
94
+ for (var i = 0; i < listItem.childCount; i++) {
95
+ var child = listItem.child(i);
96
+ if (!isListNode(child)) {
97
+ children.push(child);
98
+ }
99
+ }
100
+ return children;
101
+ }
102
+
103
+ /**
104
+ * Rebuild a ProseMirror list tree from a flat array of `ListElement` objects
105
+ * using a bottom-up stack approach.
106
+ *
107
+ * The algorithm tracks open list/listItem wrappers on a stack. As depth
108
+ * transitions occur between consecutive elements, wrapper nodes are opened
109
+ * (depth increase) or closed (depth decrease).
110
+ */
111
+ function rebuildPMList(elements, schema) {
112
+ if (elements.length === 0) {
113
+ return null;
114
+ }
115
+
116
+ // Each stack frame represents an open list at a given depth.
117
+ // items[] accumulates the PMNode children (listItem nodes) for that list.
118
+
119
+ var stack = [];
120
+ function openList(listType) {
121
+ stack.push({
122
+ listType: listType,
123
+ items: []
124
+ });
125
+ }
126
+
127
+ /**
128
+ * Close lists on the stack down to `targetDepth`, wrapping each closed
129
+ * list into the last listItem of its parent.
130
+ */
131
+ function closeToDepth(targetDepth) {
132
+ var _loop = function _loop() {
133
+ var closed = stack.pop();
134
+ if (!closed) {
135
+ return 1; // break
136
+ }
137
+ var listNode = schema.nodes[closed.listType].create(null, closed.items);
138
+
139
+ // Attach the closed list to the last listItem on the parent frame
140
+ var parentFrame = stack[stack.length - 1];
141
+ var lastItem = parentFrame.items[parentFrame.items.length - 1];
142
+ if (lastItem) {
143
+ // Append the nested list to this listItem's children
144
+ var newContent = [];
145
+ lastItem.forEach(function (child) {
146
+ return newContent.push(child);
147
+ });
148
+ newContent.push(listNode);
149
+ parentFrame.items[parentFrame.items.length - 1] = schema.nodes.listItem.create(lastItem.attrs, newContent);
150
+ } else {
151
+ // Edge case: no listItem to attach to. Create a wrapper.
152
+ var wrapperItem = schema.nodes.listItem.create(null, [listNode]);
153
+ parentFrame.items.push(wrapperItem);
154
+ }
155
+ };
156
+ while (stack.length > targetDepth + 1) {
157
+ if (_loop()) break;
158
+ }
159
+ }
160
+
161
+ // Seed the root list
162
+ openList(elements[0].listType);
163
+ var _iterator = _createForOfIteratorHelper(elements),
164
+ _step;
165
+ try {
166
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
167
+ var el = _step.value;
168
+ var targetDepth = el.depth;
169
+
170
+ // Close lists if we're going shallower
171
+ if (stack.length > targetDepth + 1) {
172
+ closeToDepth(targetDepth);
173
+ }
174
+
175
+ // Open lists if we need to go deeper.
176
+ // We do NOT create wrapper listItems here — closeToDepth handles
177
+ // creating wrappers that contain only the nested list (no empty paragraph).
178
+ while (stack.length < targetDepth + 1) {
179
+ openList(el.listType);
180
+ }
181
+
182
+ // Build the listItem for this element using its content children
183
+ var contentChildren = extractContentChildren(el.node);
184
+ var listItem = schema.nodes.listItem.create(el.node.attrs, contentChildren);
185
+ stack[stack.length - 1].items.push(listItem);
186
+ }
187
+
188
+ // Close all remaining open lists
189
+ } catch (err) {
190
+ _iterator.e(err);
191
+ } finally {
192
+ _iterator.f();
193
+ }
194
+ closeToDepth(0);
195
+ var root = stack[0];
196
+ return schema.nodes[root.listType].create(null, root.items);
197
+ }
198
+ /**
199
+ * Build a replacement Fragment from a flat array of `ListElement` objects.
200
+ *
201
+ * Elements with depth >= 0 are grouped into consecutive list segments
202
+ * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
203
+ * past the root) are converted to their content children (paragraphs).
204
+ * The result interleaves list nodes and extracted content in document order.
205
+ */
206
+ export function buildReplacementFragment(elements, schema) {
207
+ var fragment = Fragment.empty;
208
+ var pendingListSegment = [];
209
+ var pendingStartIdx = 0;
210
+ var contentStartOffsets = new Array(elements.length);
211
+ var flushListSegment = function flushListSegment() {
212
+ if (pendingListSegment.length > 0) {
213
+ var fragmentOffset = fragment.size;
214
+ var rebuilt = rebuildPMList(pendingListSegment, schema);
215
+ if (rebuilt) {
216
+ // Walk the rebuilt tree to find content-bearing listItem positions.
217
+ // descendants() visits in document order matching the element order.
218
+ var segIdx = 0;
219
+ rebuilt.descendants(function (node, pos) {
220
+ if (isListItemNode(node) && hasContentChildren(node)) {
221
+ // pos is relative to rebuilt's content start;
222
+ // +1 for rebuilt's opening tag, +1 for listItem's opening tag
223
+ contentStartOffsets[pendingStartIdx + segIdx] = fragmentOffset + 1 + pos + 1;
224
+ segIdx++;
225
+ }
226
+ return true;
227
+ });
228
+ fragment = fragment.addToEnd(rebuilt);
229
+ }
230
+ pendingListSegment = [];
231
+ }
232
+ };
233
+ var elIdx = 0;
234
+ var _iterator2 = _createForOfIteratorHelper(elements),
235
+ _step2;
236
+ try {
237
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
238
+ var el = _step2.value;
239
+ if (el.depth < 0) {
240
+ flushListSegment();
241
+ // Extracted element — content children become top-level nodes.
242
+ // Record offset of first content child.
243
+ contentStartOffsets[elIdx] = fragment.size;
244
+ var _iterator3 = _createForOfIteratorHelper(extractContentChildren(el.node)),
245
+ _step3;
246
+ try {
247
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
248
+ var node = _step3.value;
249
+ fragment = fragment.addToEnd(node);
250
+ }
251
+ } catch (err) {
252
+ _iterator3.e(err);
253
+ } finally {
254
+ _iterator3.f();
255
+ }
256
+ } else {
257
+ if (pendingListSegment.length === 0) {
258
+ pendingStartIdx = elIdx;
259
+ }
260
+ pendingListSegment.push(el);
261
+ }
262
+ elIdx++;
263
+ }
264
+ } catch (err) {
265
+ _iterator2.e(err);
266
+ } finally {
267
+ _iterator2.f();
268
+ }
269
+ flushListSegment();
270
+ return {
271
+ fragment: fragment,
272
+ contentStartOffsets: contentStartOffsets
273
+ };
274
+ }
275
+ /**
276
+ * Restore the transaction's selection after a list structural change.
277
+ *
278
+ * Uses the content start offsets computed during fragment rebuild to
279
+ * map each selection endpoint to its new absolute position.
280
+ */
281
+ export function restoreSelection(_ref2) {
282
+ var tr = _ref2.tr,
283
+ originalSelection = _ref2.originalSelection,
284
+ from = _ref2.from,
285
+ to = _ref2.to;
286
+ var maxPos = tr.doc.content.size;
287
+ if (originalSelection instanceof NodeSelection) {
288
+ try {
289
+ tr.setSelection(NodeSelection.create(tr.doc, Math.min(from, maxPos - 1)));
290
+ } catch (_unused) {
291
+ tr.setSelection(Selection.near(tr.doc.resolve(from)));
292
+ }
293
+ } else if (originalSelection instanceof GapCursorSelection) {
294
+ tr.setSelection(new GapCursorSelection(tr.doc.resolve(from), originalSelection.side));
295
+ } else {
296
+ tr.setSelection(TextSelection.create(tr.doc, from, to));
297
+ }
298
+ }
@@ -0,0 +1,5 @@
1
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
2
+ /**
3
+ * Moves the selected list items n levels up (negative delta) or down (positive delta).
4
+ */
5
+ export declare function moveSelectedListItems(tr: Transaction, delta: number): void;
@@ -0,0 +1,72 @@
1
+ import type { 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';
5
+ /**
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
+ node: PMNode;
12
+ pos: number;
13
+ depth: number;
14
+ listType: 'bulletList' | 'orderedList';
15
+ }
16
+ export interface FlattenListResult {
17
+ elements: ListElement[];
18
+ startIndex: number;
19
+ endIndex: number;
20
+ maxDepth: number;
21
+ }
22
+ export interface FlattenListOptions {
23
+ doc: PMNode;
24
+ rootListStart: number;
25
+ rootListEnd: number;
26
+ selectionFrom: number;
27
+ selectionTo: number;
28
+ delta: number;
29
+ }
30
+ /**
31
+ * Flatten a root list into a flat array of content-bearing `ListElement`
32
+ * objects and simultaneously determine which elements intersect the user's
33
+ * selection.
34
+ * Selection intersection is checked against each item's content-only
35
+ * span (excluding nested lists).
36
+ */
37
+ export declare function flattenList({ doc, rootListStart, rootListEnd, selectionFrom, selectionTo, delta, }: FlattenListOptions): FlattenListResult | null;
38
+ export interface BuildResult {
39
+ fragment: Fragment;
40
+ /**
41
+ * For each element (by index), the offset within the fragment where the
42
+ * element's content begins. For list elements this is the position just
43
+ * inside the listItem (pos + 1); for extracted elements it is the position
44
+ * of the first extracted content child.
45
+ *
46
+ * To get the absolute document position after `tr.replaceWith(rangeStart, …)`,
47
+ * add `rangeStart` to the offset.
48
+ */
49
+ contentStartOffsets: number[];
50
+ }
51
+ /**
52
+ * Build a replacement Fragment from a flat array of `ListElement` objects.
53
+ *
54
+ * Elements with depth >= 0 are grouped into consecutive list segments
55
+ * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
56
+ * past the root) are converted to their content children (paragraphs).
57
+ * The result interleaves list nodes and extracted content in document order.
58
+ */
59
+ export declare function buildReplacementFragment(elements: ListElement[], schema: Schema): BuildResult;
60
+ export interface RestoreSelectionOptions {
61
+ tr: Transaction;
62
+ originalSelection: Selection;
63
+ from: number;
64
+ to: number;
65
+ }
66
+ /**
67
+ * Restore the transaction's selection after a list structural change.
68
+ *
69
+ * Uses the content start offsets computed during fragment rebuild to
70
+ * map each selection endpoint to its new absolute position.
71
+ */
72
+ export declare function restoreSelection({ tr, originalSelection, from, to, }: RestoreSelectionOptions): void;
@@ -0,0 +1,5 @@
1
+ import type { Transaction } from '@atlaskit/editor-prosemirror/state';
2
+ /**
3
+ * Moves the selected list items n levels up (negative delta) or down (positive delta).
4
+ */
5
+ export declare function moveSelectedListItems(tr: Transaction, delta: number): void;
@@ -0,0 +1,72 @@
1
+ import type { 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';
5
+ /**
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
+ node: PMNode;
12
+ pos: number;
13
+ depth: number;
14
+ listType: 'bulletList' | 'orderedList';
15
+ }
16
+ export interface FlattenListResult {
17
+ elements: ListElement[];
18
+ startIndex: number;
19
+ endIndex: number;
20
+ maxDepth: number;
21
+ }
22
+ export interface FlattenListOptions {
23
+ doc: PMNode;
24
+ rootListStart: number;
25
+ rootListEnd: number;
26
+ selectionFrom: number;
27
+ selectionTo: number;
28
+ delta: number;
29
+ }
30
+ /**
31
+ * Flatten a root list into a flat array of content-bearing `ListElement`
32
+ * objects and simultaneously determine which elements intersect the user's
33
+ * selection.
34
+ * Selection intersection is checked against each item's content-only
35
+ * span (excluding nested lists).
36
+ */
37
+ export declare function flattenList({ doc, rootListStart, rootListEnd, selectionFrom, selectionTo, delta, }: FlattenListOptions): FlattenListResult | null;
38
+ export interface BuildResult {
39
+ fragment: Fragment;
40
+ /**
41
+ * For each element (by index), the offset within the fragment where the
42
+ * element's content begins. For list elements this is the position just
43
+ * inside the listItem (pos + 1); for extracted elements it is the position
44
+ * of the first extracted content child.
45
+ *
46
+ * To get the absolute document position after `tr.replaceWith(rangeStart, …)`,
47
+ * add `rangeStart` to the offset.
48
+ */
49
+ contentStartOffsets: number[];
50
+ }
51
+ /**
52
+ * Build a replacement Fragment from a flat array of `ListElement` objects.
53
+ *
54
+ * Elements with depth >= 0 are grouped into consecutive list segments
55
+ * and rebuilt via `rebuildPMList`. Elements with depth < 0 (extracted
56
+ * past the root) are converted to their content children (paragraphs).
57
+ * The result interleaves list nodes and extracted content in document order.
58
+ */
59
+ export declare function buildReplacementFragment(elements: ListElement[], schema: Schema): BuildResult;
60
+ export interface RestoreSelectionOptions {
61
+ tr: Transaction;
62
+ originalSelection: Selection;
63
+ from: number;
64
+ to: number;
65
+ }
66
+ /**
67
+ * Restore the transaction's selection after a list structural change.
68
+ *
69
+ * Uses the content start offsets computed during fragment rebuild to
70
+ * map each selection endpoint to its new absolute position.
71
+ */
72
+ export declare function restoreSelection({ tr, originalSelection, from, to, }: RestoreSelectionOptions): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-list",
3
- "version": "9.0.27",
3
+ "version": "10.0.0",
4
4
  "description": "List plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -28,21 +28,21 @@
28
28
  "atlaskit:src": "src/index.ts",
29
29
  "dependencies": {
30
30
  "@atlaskit/adf-schema": "^52.2.0",
31
- "@atlaskit/editor-plugin-analytics": "^7.0.0",
32
- "@atlaskit/editor-plugin-block-menu": "^6.1.0",
33
- "@atlaskit/editor-plugin-feature-flags": "^6.0.0",
34
- "@atlaskit/editor-plugin-toolbar": "^4.1.0",
31
+ "@atlaskit/editor-plugin-analytics": "^8.0.0",
32
+ "@atlaskit/editor-plugin-block-menu": "^7.0.0",
33
+ "@atlaskit/editor-plugin-feature-flags": "^7.0.0",
34
+ "@atlaskit/editor-plugin-toolbar": "^5.0.0",
35
35
  "@atlaskit/editor-prosemirror": "^7.3.0",
36
36
  "@atlaskit/editor-toolbar": "^0.19.0",
37
37
  "@atlaskit/icon": "^32.0.0",
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": "^35.0.0",
41
+ "@atlaskit/tmp-editor-statsig": "^35.10.0",
42
42
  "@babel/runtime": "^7.0.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@atlaskit/editor-common": "^111.30.0",
45
+ "@atlaskit/editor-common": "^112.0.0",
46
46
  "react": "^18.2.0",
47
47
  "react-intl-next": "npm:react-intl@^5.18.1"
48
48
  },