@atlaskit/editor-plugin-list 12.0.1 → 12.0.3
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 +20 -0
- package/dist/cjs/pm-plugins/main.js +17 -14
- package/dist/cjs/pm-plugins/transforms.js +49 -19
- package/dist/es2019/pm-plugins/main.js +16 -13
- package/dist/es2019/pm-plugins/transforms.js +47 -16
- package/dist/esm/pm-plugins/main.js +17 -14
- package/dist/esm/pm-plugins/transforms.js +49 -19
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-list
|
|
2
2
|
|
|
3
|
+
## 12.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 12.0.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`402738b592e0b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/402738b592e0b) -
|
|
14
|
+
Fix invalid flexible list structures caused by delete, paste, and typing operations.
|
|
15
|
+
|
|
16
|
+
Under platform_editor_flexible_list_schema, operations that remove content spanning list or task
|
|
17
|
+
list items could leave nodes with a nested list as their first child instead of a required
|
|
18
|
+
paragraph/item. Normalisation now runs efficiently on all relevant transactions in
|
|
19
|
+
appendTransaction.
|
|
20
|
+
|
|
21
|
+
- Updated dependencies
|
|
22
|
+
|
|
3
23
|
## 12.0.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -13,6 +13,7 @@ var _utils = require("@atlaskit/editor-common/utils");
|
|
|
13
13
|
var _state2 = require("@atlaskit/editor-prosemirror/state");
|
|
14
14
|
var _utils2 = require("@atlaskit/editor-prosemirror/utils");
|
|
15
15
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
16
|
+
var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
|
|
16
17
|
var _transforms = require("./transforms");
|
|
17
18
|
var _selection2 = require("./utils/selection");
|
|
18
19
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
@@ -141,21 +142,23 @@ var createPlugin = exports.createPlugin = function createPlugin(eventDispatch, f
|
|
|
141
142
|
state: createPluginState(eventDispatch, createInitialState(featureFlags, api)),
|
|
142
143
|
key: listPluginKey,
|
|
143
144
|
appendTransaction: function appendTransaction(transactions, _oldState, newState) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (transactions.some(function (t) {
|
|
148
|
-
return t.
|
|
145
|
+
if (!(0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_flexible_list_schema', 'isEnabled', true)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (!transactions.some(function (t) {
|
|
149
|
+
return t.docChanged;
|
|
149
150
|
})) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
// Efficiently scans only affected list nodes — exits early if none are found.
|
|
154
|
+
var tr = (0, _transforms.applyListNormalisationFixes)({
|
|
155
|
+
tr: newState.tr,
|
|
156
|
+
transactions: transactions,
|
|
157
|
+
doc: newState.doc,
|
|
158
|
+
schema: newState.schema
|
|
159
|
+
});
|
|
160
|
+
if (tr.docChanged) {
|
|
161
|
+
return tr;
|
|
159
162
|
}
|
|
160
163
|
return null;
|
|
161
164
|
},
|
|
@@ -14,7 +14,6 @@ var _utils = require("@atlaskit/editor-common/utils");
|
|
|
14
14
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
15
15
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
16
16
|
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
17
|
-
var _utils2 = require("@atlaskit/editor-prosemirror/utils");
|
|
18
17
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
19
18
|
var _indentation = require("./utils/indentation");
|
|
20
19
|
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; } } }; }
|
|
@@ -136,14 +135,30 @@ function getAffectedListsFromTransactions(transactions, doc, schema) {
|
|
|
136
135
|
if (!(step instanceof _transform.ReplaceStep) && !(step instanceof _transform.ReplaceAroundStep)) {
|
|
137
136
|
continue;
|
|
138
137
|
}
|
|
139
|
-
// Check both the start and end of each changed range, mapped to post-
|
|
138
|
+
// Check both the start and end of each changed range, mapped to post-transaction positions.
|
|
140
139
|
for (var _i = 0, _arr = [step.from, step.to]; _i < _arr.length; _i++) {
|
|
141
140
|
var rawPos = _arr[_i];
|
|
142
141
|
var mappedPos = Math.min(tr.mapping.map(rawPos), doc.content.size - 1);
|
|
143
142
|
var $pos = doc.resolve(mappedPos);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
// Walk ancestors from inner to outer, recording the outermost list node.
|
|
144
|
+
// Once we find a list and then exit list structure (hit a non-list ancestor),
|
|
145
|
+
// break early — prevents container nodes (e.g. panel) from causing us to
|
|
146
|
+
// return an outer list that is in a different structural context.
|
|
147
|
+
// $pos.node(depth) is O(1) array access.
|
|
148
|
+
var rootListPos = null;
|
|
149
|
+
var rootListNode = null;
|
|
150
|
+
for (var depth = $pos.depth; depth >= 0; depth--) {
|
|
151
|
+
var node = $pos.node(depth);
|
|
152
|
+
if (listTypes.includes(node.type)) {
|
|
153
|
+
rootListPos = $pos.before(depth);
|
|
154
|
+
rootListNode = node;
|
|
155
|
+
} else if (rootListNode !== null && node.type !== schema.nodes.listItem) {
|
|
156
|
+
// We've exited the list structure — stop walking.
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (rootListPos !== null && rootListNode !== null) {
|
|
161
|
+
result.set(rootListPos, rootListNode);
|
|
147
162
|
}
|
|
148
163
|
}
|
|
149
164
|
}
|
|
@@ -180,10 +195,14 @@ function applyListNormalisationFixes(_ref) {
|
|
|
180
195
|
}
|
|
181
196
|
var _schema$nodes2 = schema.nodes,
|
|
182
197
|
listItem = _schema$nodes2.listItem,
|
|
183
|
-
paragraph = _schema$nodes2.paragraph
|
|
198
|
+
paragraph = _schema$nodes2.paragraph,
|
|
199
|
+
bulletList = _schema$nodes2.bulletList,
|
|
200
|
+
orderedList = _schema$nodes2.orderedList,
|
|
201
|
+
taskList = _schema$nodes2.taskList;
|
|
184
202
|
if (!listItem) {
|
|
185
203
|
return tr;
|
|
186
204
|
}
|
|
205
|
+
var nestedListTypes = [bulletList, orderedList, taskList].filter(Boolean);
|
|
187
206
|
|
|
188
207
|
// Process lists in reverse position order so fixes at higher positions
|
|
189
208
|
// don't shift the positions of fixes at lower positions.
|
|
@@ -198,16 +217,22 @@ function applyListNormalisationFixes(_ref) {
|
|
|
198
217
|
_step3;
|
|
199
218
|
try {
|
|
200
219
|
var _loop = function _loop() {
|
|
201
|
-
var _step3$value = (0, _slicedToArray2.default)(_step3.value,
|
|
202
|
-
listPos = _step3$value[0]
|
|
203
|
-
|
|
204
|
-
//
|
|
205
|
-
|
|
220
|
+
var _step3$value = (0, _slicedToArray2.default)(_step3.value, 1),
|
|
221
|
+
listPos = _step3$value[0];
|
|
222
|
+
// Re-resolve the list node from the current transaction doc (post-paste state),
|
|
223
|
+
// as the original listNode snapshot may be stale after the paste transaction.
|
|
224
|
+
var mappedListPos = tr.mapping.map(listPos);
|
|
225
|
+
var currentListNode = tr.doc.nodeAt(mappedListPos);
|
|
226
|
+
if (!currentListNode) {
|
|
227
|
+
return 1; // continue
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Collect all listItem positions at all depths in document order, then process in
|
|
231
|
+
// reverse so that fixes at higher positions don't shift positions of lower ones.
|
|
206
232
|
var listItemPositions = [];
|
|
207
|
-
|
|
233
|
+
currentListNode.descendants(function (node, offsetPos) {
|
|
208
234
|
if (node.type === listItem) {
|
|
209
|
-
listItemPositions.push(
|
|
210
|
-
return false; // Don't descend — inner listItems are handled via their own ancestor list
|
|
235
|
+
listItemPositions.push(mappedListPos + 1 + offsetPos);
|
|
211
236
|
}
|
|
212
237
|
return true;
|
|
213
238
|
});
|
|
@@ -237,20 +262,25 @@ function applyListNormalisationFixes(_ref) {
|
|
|
237
262
|
}
|
|
238
263
|
}
|
|
239
264
|
|
|
240
|
-
// Insert empty paragraph before list-first
|
|
265
|
+
// Insert empty paragraph before a list-type first child when _indentation is off.
|
|
266
|
+
// Only list types (bulletList, orderedList, taskList) are invalid as a first child —
|
|
267
|
+
// other non-paragraph types (mediaSingle, codeBlock, extension) are valid per the schema.
|
|
241
268
|
if (paragraph && !(0, _expValEquals.expValEquals)('platform_editor_flexible_list_indentation', 'isEnabled', true)) {
|
|
242
|
-
|
|
243
|
-
|
|
269
|
+
// Re-map position after any join steps that may have been added above.
|
|
270
|
+
var remappedPos = tr.mapping.map(listItemPositions[i]);
|
|
271
|
+
var currentNode = tr.doc.nodeAt(remappedPos);
|
|
272
|
+
var firstChild = currentNode === null || currentNode === void 0 ? void 0 : currentNode.firstChild;
|
|
273
|
+
if (firstChild && nestedListTypes.includes(firstChild.type)) {
|
|
244
274
|
var emptyParagraph = paragraph.createAndFill();
|
|
245
275
|
if (emptyParagraph) {
|
|
246
|
-
tr.insert(
|
|
276
|
+
tr.insert(remappedPos + 1, emptyParagraph);
|
|
247
277
|
}
|
|
248
278
|
}
|
|
249
279
|
}
|
|
250
280
|
}
|
|
251
281
|
};
|
|
252
282
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
253
|
-
_loop();
|
|
283
|
+
if (_loop()) continue;
|
|
254
284
|
}
|
|
255
285
|
} catch (err) {
|
|
256
286
|
_iterator3.e(err);
|
|
@@ -5,6 +5,7 @@ import { getItemCounterDigitsSize, isListNode, pluginFactory } from '@atlaskit/e
|
|
|
5
5
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
6
6
|
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
7
7
|
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
8
|
+
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
8
9
|
import { applyListNormalisationFixes } from './transforms';
|
|
9
10
|
import { isWrappingPossible } from './utils/selection';
|
|
10
11
|
const listPluginKey = new PluginKey('listPlugin');
|
|
@@ -133,19 +134,21 @@ export const createPlugin = (eventDispatch, featureFlags, api) => {
|
|
|
133
134
|
state: createPluginState(eventDispatch, createInitialState(featureFlags, api)),
|
|
134
135
|
key: listPluginKey,
|
|
135
136
|
appendTransaction(transactions, _oldState, newState) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (transactions.some(t => t.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
137
|
+
if (!expValEqualsNoExposure('platform_editor_flexible_list_schema', 'isEnabled', true)) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
if (!transactions.some(t => t.docChanged)) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
// Efficiently scans only affected list nodes — exits early if none are found.
|
|
144
|
+
const tr = applyListNormalisationFixes({
|
|
145
|
+
tr: newState.tr,
|
|
146
|
+
transactions,
|
|
147
|
+
doc: newState.doc,
|
|
148
|
+
schema: newState.schema
|
|
149
|
+
});
|
|
150
|
+
if (tr.docChanged) {
|
|
151
|
+
return tr;
|
|
149
152
|
}
|
|
150
153
|
return null;
|
|
151
154
|
},
|
|
@@ -2,7 +2,6 @@ import { isListNode } from '@atlaskit/editor-common/utils';
|
|
|
2
2
|
import { Fragment, NodeRange, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
3
3
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
4
|
import { liftTarget, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
5
|
-
import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
6
5
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
7
6
|
import { getListLiftTarget } from './utils/indentation';
|
|
8
7
|
function liftListItem(selection, tr) {
|
|
@@ -124,13 +123,29 @@ function getAffectedListsFromTransactions(transactions, doc, schema) {
|
|
|
124
123
|
if (!(step instanceof ReplaceStep) && !(step instanceof ReplaceAroundStep)) {
|
|
125
124
|
continue;
|
|
126
125
|
}
|
|
127
|
-
// Check both the start and end of each changed range, mapped to post-
|
|
126
|
+
// Check both the start and end of each changed range, mapped to post-transaction positions.
|
|
128
127
|
for (const rawPos of [step.from, step.to]) {
|
|
129
128
|
const mappedPos = Math.min(tr.mapping.map(rawPos), doc.content.size - 1);
|
|
130
129
|
const $pos = doc.resolve(mappedPos);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
// Walk ancestors from inner to outer, recording the outermost list node.
|
|
131
|
+
// Once we find a list and then exit list structure (hit a non-list ancestor),
|
|
132
|
+
// break early — prevents container nodes (e.g. panel) from causing us to
|
|
133
|
+
// return an outer list that is in a different structural context.
|
|
134
|
+
// $pos.node(depth) is O(1) array access.
|
|
135
|
+
let rootListPos = null;
|
|
136
|
+
let rootListNode = null;
|
|
137
|
+
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
138
|
+
const node = $pos.node(depth);
|
|
139
|
+
if (listTypes.includes(node.type)) {
|
|
140
|
+
rootListPos = $pos.before(depth);
|
|
141
|
+
rootListNode = node;
|
|
142
|
+
} else if (rootListNode !== null && node.type !== schema.nodes.listItem) {
|
|
143
|
+
// We've exited the list structure — stop walking.
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (rootListPos !== null && rootListNode !== null) {
|
|
148
|
+
result.set(rootListPos, rootListNode);
|
|
134
149
|
}
|
|
135
150
|
}
|
|
136
151
|
}
|
|
@@ -158,23 +173,34 @@ export function applyListNormalisationFixes({
|
|
|
158
173
|
}
|
|
159
174
|
const {
|
|
160
175
|
listItem,
|
|
161
|
-
paragraph
|
|
176
|
+
paragraph,
|
|
177
|
+
bulletList,
|
|
178
|
+
orderedList,
|
|
179
|
+
taskList
|
|
162
180
|
} = schema.nodes;
|
|
163
181
|
if (!listItem) {
|
|
164
182
|
return tr;
|
|
165
183
|
}
|
|
184
|
+
const nestedListTypes = [bulletList, orderedList, taskList].filter(Boolean);
|
|
166
185
|
|
|
167
186
|
// Process lists in reverse position order so fixes at higher positions
|
|
168
187
|
// don't shift the positions of fixes at lower positions.
|
|
169
188
|
const sortedEntries = [...affectedLists.entries()].sort(([posA], [posB]) => posB - posA);
|
|
170
|
-
for (const [listPos
|
|
171
|
-
//
|
|
172
|
-
//
|
|
189
|
+
for (const [listPos] of sortedEntries) {
|
|
190
|
+
// Re-resolve the list node from the current transaction doc (post-paste state),
|
|
191
|
+
// as the original listNode snapshot may be stale after the paste transaction.
|
|
192
|
+
const mappedListPos = tr.mapping.map(listPos);
|
|
193
|
+
const currentListNode = tr.doc.nodeAt(mappedListPos);
|
|
194
|
+
if (!currentListNode) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Collect all listItem positions at all depths in document order, then process in
|
|
199
|
+
// reverse so that fixes at higher positions don't shift positions of lower ones.
|
|
173
200
|
const listItemPositions = [];
|
|
174
|
-
|
|
201
|
+
currentListNode.descendants((node, offsetPos) => {
|
|
175
202
|
if (node.type === listItem) {
|
|
176
|
-
listItemPositions.push(
|
|
177
|
-
return false; // Don't descend — inner listItems are handled via their own ancestor list
|
|
203
|
+
listItemPositions.push(mappedListPos + 1 + offsetPos);
|
|
178
204
|
}
|
|
179
205
|
return true;
|
|
180
206
|
});
|
|
@@ -204,13 +230,18 @@ export function applyListNormalisationFixes({
|
|
|
204
230
|
}
|
|
205
231
|
}
|
|
206
232
|
|
|
207
|
-
// Insert empty paragraph before list-first
|
|
233
|
+
// Insert empty paragraph before a list-type first child when _indentation is off.
|
|
234
|
+
// Only list types (bulletList, orderedList, taskList) are invalid as a first child —
|
|
235
|
+
// other non-paragraph types (mediaSingle, codeBlock, extension) are valid per the schema.
|
|
208
236
|
if (paragraph && !expValEquals('platform_editor_flexible_list_indentation', 'isEnabled', true)) {
|
|
209
|
-
|
|
210
|
-
|
|
237
|
+
// Re-map position after any join steps that may have been added above.
|
|
238
|
+
const remappedPos = tr.mapping.map(listItemPositions[i]);
|
|
239
|
+
const currentNode = tr.doc.nodeAt(remappedPos);
|
|
240
|
+
const firstChild = currentNode === null || currentNode === void 0 ? void 0 : currentNode.firstChild;
|
|
241
|
+
if (firstChild && nestedListTypes.includes(firstChild.type)) {
|
|
211
242
|
const emptyParagraph = paragraph.createAndFill();
|
|
212
243
|
if (emptyParagraph) {
|
|
213
|
-
tr.insert(
|
|
244
|
+
tr.insert(remappedPos + 1, emptyParagraph);
|
|
214
245
|
}
|
|
215
246
|
}
|
|
216
247
|
}
|
|
@@ -8,6 +8,7 @@ import { getItemCounterDigitsSize, isListNode, pluginFactory } from '@atlaskit/e
|
|
|
8
8
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
9
9
|
import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
10
10
|
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
11
|
+
import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
|
|
11
12
|
import { applyListNormalisationFixes } from './transforms';
|
|
12
13
|
import { isWrappingPossible } from './utils/selection';
|
|
13
14
|
var listPluginKey = new PluginKey('listPlugin');
|
|
@@ -134,21 +135,23 @@ export var createPlugin = function createPlugin(eventDispatch, featureFlags, api
|
|
|
134
135
|
state: createPluginState(eventDispatch, createInitialState(featureFlags, api)),
|
|
135
136
|
key: listPluginKey,
|
|
136
137
|
appendTransaction: function appendTransaction(transactions, _oldState, newState) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (transactions.some(function (t) {
|
|
141
|
-
return t.
|
|
138
|
+
if (!expValEqualsNoExposure('platform_editor_flexible_list_schema', 'isEnabled', true)) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
if (!transactions.some(function (t) {
|
|
142
|
+
return t.docChanged;
|
|
142
143
|
})) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
// Efficiently scans only affected list nodes — exits early if none are found.
|
|
147
|
+
var tr = applyListNormalisationFixes({
|
|
148
|
+
tr: newState.tr,
|
|
149
|
+
transactions: transactions,
|
|
150
|
+
doc: newState.doc,
|
|
151
|
+
schema: newState.schema
|
|
152
|
+
});
|
|
153
|
+
if (tr.docChanged) {
|
|
154
|
+
return tr;
|
|
152
155
|
}
|
|
153
156
|
return null;
|
|
154
157
|
},
|
|
@@ -7,7 +7,6 @@ import { isListNode } from '@atlaskit/editor-common/utils';
|
|
|
7
7
|
import { Fragment, NodeRange, Slice } from '@atlaskit/editor-prosemirror/model';
|
|
8
8
|
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
9
9
|
import { liftTarget, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
10
|
-
import { findParentNodeOfTypeClosestToPos } from '@atlaskit/editor-prosemirror/utils';
|
|
11
10
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
12
11
|
import { getListLiftTarget } from './utils/indentation';
|
|
13
12
|
function liftListItem(selection, tr) {
|
|
@@ -126,14 +125,30 @@ function getAffectedListsFromTransactions(transactions, doc, schema) {
|
|
|
126
125
|
if (!(step instanceof ReplaceStep) && !(step instanceof ReplaceAroundStep)) {
|
|
127
126
|
continue;
|
|
128
127
|
}
|
|
129
|
-
// Check both the start and end of each changed range, mapped to post-
|
|
128
|
+
// Check both the start and end of each changed range, mapped to post-transaction positions.
|
|
130
129
|
for (var _i = 0, _arr = [step.from, step.to]; _i < _arr.length; _i++) {
|
|
131
130
|
var rawPos = _arr[_i];
|
|
132
131
|
var mappedPos = Math.min(tr.mapping.map(rawPos), doc.content.size - 1);
|
|
133
132
|
var $pos = doc.resolve(mappedPos);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
// Walk ancestors from inner to outer, recording the outermost list node.
|
|
134
|
+
// Once we find a list and then exit list structure (hit a non-list ancestor),
|
|
135
|
+
// break early — prevents container nodes (e.g. panel) from causing us to
|
|
136
|
+
// return an outer list that is in a different structural context.
|
|
137
|
+
// $pos.node(depth) is O(1) array access.
|
|
138
|
+
var rootListPos = null;
|
|
139
|
+
var rootListNode = null;
|
|
140
|
+
for (var depth = $pos.depth; depth >= 0; depth--) {
|
|
141
|
+
var node = $pos.node(depth);
|
|
142
|
+
if (listTypes.includes(node.type)) {
|
|
143
|
+
rootListPos = $pos.before(depth);
|
|
144
|
+
rootListNode = node;
|
|
145
|
+
} else if (rootListNode !== null && node.type !== schema.nodes.listItem) {
|
|
146
|
+
// We've exited the list structure — stop walking.
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (rootListPos !== null && rootListNode !== null) {
|
|
151
|
+
result.set(rootListPos, rootListNode);
|
|
137
152
|
}
|
|
138
153
|
}
|
|
139
154
|
}
|
|
@@ -170,10 +185,14 @@ export function applyListNormalisationFixes(_ref) {
|
|
|
170
185
|
}
|
|
171
186
|
var _schema$nodes2 = schema.nodes,
|
|
172
187
|
listItem = _schema$nodes2.listItem,
|
|
173
|
-
paragraph = _schema$nodes2.paragraph
|
|
188
|
+
paragraph = _schema$nodes2.paragraph,
|
|
189
|
+
bulletList = _schema$nodes2.bulletList,
|
|
190
|
+
orderedList = _schema$nodes2.orderedList,
|
|
191
|
+
taskList = _schema$nodes2.taskList;
|
|
174
192
|
if (!listItem) {
|
|
175
193
|
return tr;
|
|
176
194
|
}
|
|
195
|
+
var nestedListTypes = [bulletList, orderedList, taskList].filter(Boolean);
|
|
177
196
|
|
|
178
197
|
// Process lists in reverse position order so fixes at higher positions
|
|
179
198
|
// don't shift the positions of fixes at lower positions.
|
|
@@ -188,16 +207,22 @@ export function applyListNormalisationFixes(_ref) {
|
|
|
188
207
|
_step3;
|
|
189
208
|
try {
|
|
190
209
|
var _loop = function _loop() {
|
|
191
|
-
var _step3$value = _slicedToArray(_step3.value,
|
|
192
|
-
listPos = _step3$value[0]
|
|
193
|
-
|
|
194
|
-
//
|
|
195
|
-
|
|
210
|
+
var _step3$value = _slicedToArray(_step3.value, 1),
|
|
211
|
+
listPos = _step3$value[0];
|
|
212
|
+
// Re-resolve the list node from the current transaction doc (post-paste state),
|
|
213
|
+
// as the original listNode snapshot may be stale after the paste transaction.
|
|
214
|
+
var mappedListPos = tr.mapping.map(listPos);
|
|
215
|
+
var currentListNode = tr.doc.nodeAt(mappedListPos);
|
|
216
|
+
if (!currentListNode) {
|
|
217
|
+
return 1; // continue
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Collect all listItem positions at all depths in document order, then process in
|
|
221
|
+
// reverse so that fixes at higher positions don't shift positions of lower ones.
|
|
196
222
|
var listItemPositions = [];
|
|
197
|
-
|
|
223
|
+
currentListNode.descendants(function (node, offsetPos) {
|
|
198
224
|
if (node.type === listItem) {
|
|
199
|
-
listItemPositions.push(
|
|
200
|
-
return false; // Don't descend — inner listItems are handled via their own ancestor list
|
|
225
|
+
listItemPositions.push(mappedListPos + 1 + offsetPos);
|
|
201
226
|
}
|
|
202
227
|
return true;
|
|
203
228
|
});
|
|
@@ -227,20 +252,25 @@ export function applyListNormalisationFixes(_ref) {
|
|
|
227
252
|
}
|
|
228
253
|
}
|
|
229
254
|
|
|
230
|
-
// Insert empty paragraph before list-first
|
|
255
|
+
// Insert empty paragraph before a list-type first child when _indentation is off.
|
|
256
|
+
// Only list types (bulletList, orderedList, taskList) are invalid as a first child —
|
|
257
|
+
// other non-paragraph types (mediaSingle, codeBlock, extension) are valid per the schema.
|
|
231
258
|
if (paragraph && !expValEquals('platform_editor_flexible_list_indentation', 'isEnabled', true)) {
|
|
232
|
-
|
|
233
|
-
|
|
259
|
+
// Re-map position after any join steps that may have been added above.
|
|
260
|
+
var remappedPos = tr.mapping.map(listItemPositions[i]);
|
|
261
|
+
var currentNode = tr.doc.nodeAt(remappedPos);
|
|
262
|
+
var firstChild = currentNode === null || currentNode === void 0 ? void 0 : currentNode.firstChild;
|
|
263
|
+
if (firstChild && nestedListTypes.includes(firstChild.type)) {
|
|
234
264
|
var emptyParagraph = paragraph.createAndFill();
|
|
235
265
|
if (emptyParagraph) {
|
|
236
|
-
tr.insert(
|
|
266
|
+
tr.insert(remappedPos + 1, emptyParagraph);
|
|
237
267
|
}
|
|
238
268
|
}
|
|
239
269
|
}
|
|
240
270
|
}
|
|
241
271
|
};
|
|
242
272
|
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
243
|
-
_loop();
|
|
273
|
+
if (_loop()) continue;
|
|
244
274
|
}
|
|
245
275
|
} catch (err) {
|
|
246
276
|
_iterator3.e(err);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-list",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.3",
|
|
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": "^64.0.0",
|
|
42
42
|
"@babel/runtime": "^7.0.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@atlaskit/editor-common": "^114.
|
|
45
|
+
"@atlaskit/editor-common": "^114.5.0",
|
|
46
46
|
"react": "^18.2.0",
|
|
47
47
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|
|
48
48
|
},
|