@lexical/list 0.1.7 → 0.1.8
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/LexicalList.dev.js +991 -0
- package/LexicalList.js +9 -23
- package/LexicalList.prod.js +29 -0
- package/package.json +23 -23
|
@@ -0,0 +1,991 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
var list = require('@lexical/list');
|
|
10
|
+
var lexical = require('lexical');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
14
|
+
*
|
|
15
|
+
* This source code is licensed under the MIT license found in the
|
|
16
|
+
* LICENSE file in the root directory of this source tree.
|
|
17
|
+
*
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
function $getNearestNodeOfType(node, klass) {
|
|
21
|
+
let parent = node;
|
|
22
|
+
|
|
23
|
+
while (parent != null) {
|
|
24
|
+
if (parent instanceof klass) {
|
|
25
|
+
return parent;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
parent = parent.getParent();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return parent;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
36
|
+
*
|
|
37
|
+
* This source code is licensed under the MIT license found in the
|
|
38
|
+
* LICENSE file in the root directory of this source tree.
|
|
39
|
+
*
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
function $getListDepth(listNode) {
|
|
43
|
+
let depth = 1;
|
|
44
|
+
let parent = listNode.getParent();
|
|
45
|
+
|
|
46
|
+
while (parent != null) {
|
|
47
|
+
if (list.$isListItemNode(parent)) {
|
|
48
|
+
const parentList = parent.getParent();
|
|
49
|
+
|
|
50
|
+
if (list.$isListNode(parentList)) {
|
|
51
|
+
depth++;
|
|
52
|
+
parent = parentList.getParent();
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
throw Error(`A ListItemNode must have a ListNode for a parent.`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return depth;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return depth;
|
|
65
|
+
}
|
|
66
|
+
function $getTopListNode(listItem) {
|
|
67
|
+
let list$1 = listItem.getParent();
|
|
68
|
+
|
|
69
|
+
if (!list.$isListNode(list$1)) {
|
|
70
|
+
{
|
|
71
|
+
throw Error(`A ListItemNode must have a ListNode for a parent.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let parent = list$1;
|
|
76
|
+
|
|
77
|
+
while (parent !== null) {
|
|
78
|
+
parent = parent.getParent();
|
|
79
|
+
|
|
80
|
+
if (list.$isListNode(parent)) {
|
|
81
|
+
list$1 = parent;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return list$1;
|
|
86
|
+
}
|
|
87
|
+
function $isLastItemInList(listItem) {
|
|
88
|
+
let isLast = true;
|
|
89
|
+
const firstChild = listItem.getFirstChild();
|
|
90
|
+
|
|
91
|
+
if (list.$isListNode(firstChild)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let parent = listItem;
|
|
96
|
+
|
|
97
|
+
while (parent !== null) {
|
|
98
|
+
if (list.$isListItemNode(parent)) {
|
|
99
|
+
if (parent.getNextSiblings().length > 0) {
|
|
100
|
+
isLast = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
parent = parent.getParent();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return isLast;
|
|
108
|
+
} // This should probably be $getAllChildrenOfType
|
|
109
|
+
|
|
110
|
+
function $getAllListItems(node) {
|
|
111
|
+
let listItemNodes = []; //$FlowFixMe - the result of this will always be an array of ListItemNodes.
|
|
112
|
+
|
|
113
|
+
const listChildren = node.getChildren().filter(list.$isListItemNode);
|
|
114
|
+
|
|
115
|
+
for (let i = 0; i < listChildren.length; i++) {
|
|
116
|
+
const listItemNode = listChildren[i];
|
|
117
|
+
const firstChild = listItemNode.getFirstChild();
|
|
118
|
+
|
|
119
|
+
if (list.$isListNode(firstChild)) {
|
|
120
|
+
listItemNodes = listItemNodes.concat($getAllListItems(firstChild));
|
|
121
|
+
} else {
|
|
122
|
+
listItemNodes.push(listItemNode);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return listItemNodes;
|
|
127
|
+
}
|
|
128
|
+
function isNestedListNode(node) {
|
|
129
|
+
return list.$isListItemNode(node) && list.$isListNode(node.getFirstChild());
|
|
130
|
+
}
|
|
131
|
+
function findNearestListItemNode(node) {
|
|
132
|
+
let currentNode = node;
|
|
133
|
+
|
|
134
|
+
while (currentNode !== null) {
|
|
135
|
+
if (list.$isListItemNode(currentNode)) {
|
|
136
|
+
return currentNode;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
currentNode = currentNode.getParent();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
function getUniqueListItemNodes(nodeList) {
|
|
145
|
+
const keys = new Set();
|
|
146
|
+
|
|
147
|
+
for (let i = 0; i < nodeList.length; i++) {
|
|
148
|
+
const node = nodeList[i];
|
|
149
|
+
|
|
150
|
+
if (list.$isListItemNode(node)) {
|
|
151
|
+
keys.add(node);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return Array.from(keys);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
160
|
+
*
|
|
161
|
+
* This source code is licensed under the MIT license found in the
|
|
162
|
+
* LICENSE file in the root directory of this source tree.
|
|
163
|
+
*
|
|
164
|
+
*
|
|
165
|
+
*/
|
|
166
|
+
function insertList(editor, listType) {
|
|
167
|
+
editor.update(() => {
|
|
168
|
+
lexical.$log('formatList');
|
|
169
|
+
const selection = lexical.$getSelection();
|
|
170
|
+
|
|
171
|
+
if (selection !== null) {
|
|
172
|
+
const nodes = selection.getNodes();
|
|
173
|
+
const anchor = selection.anchor;
|
|
174
|
+
const anchorNode = anchor.getNode();
|
|
175
|
+
const anchorNodeParent = anchorNode.getParent(); // This is a special case for when there's nothing selected
|
|
176
|
+
|
|
177
|
+
if (nodes.length === 0) {
|
|
178
|
+
const list$1 = list.$createListNode(listType);
|
|
179
|
+
|
|
180
|
+
if (lexical.$isRootNode(anchorNodeParent)) {
|
|
181
|
+
anchorNode.replace(list$1);
|
|
182
|
+
const listItem = list.$createListItemNode();
|
|
183
|
+
list$1.append(listItem);
|
|
184
|
+
} else if (list.$isListItemNode(anchorNode)) {
|
|
185
|
+
const parent = anchorNode.getParentOrThrow();
|
|
186
|
+
list$1.append(...parent.getChildren());
|
|
187
|
+
parent.replace(list$1);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return;
|
|
191
|
+
} else {
|
|
192
|
+
const handled = new Set();
|
|
193
|
+
|
|
194
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
195
|
+
const node = nodes[i];
|
|
196
|
+
|
|
197
|
+
if (lexical.$isElementNode(node) && node.isEmpty() && !handled.has(node.getKey())) {
|
|
198
|
+
createListOrMerge(node, listType);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (lexical.$isLeafNode(node)) {
|
|
203
|
+
let parent = node.getParent();
|
|
204
|
+
|
|
205
|
+
while (parent != null) {
|
|
206
|
+
const parentKey = parent.getKey();
|
|
207
|
+
|
|
208
|
+
if (list.$isListNode(parent)) {
|
|
209
|
+
if (!handled.has(parentKey)) {
|
|
210
|
+
const newListNode = list.$createListNode(listType);
|
|
211
|
+
newListNode.append(...parent.getChildren());
|
|
212
|
+
parent.replace(newListNode);
|
|
213
|
+
handled.add(parentKey);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
break;
|
|
217
|
+
} else {
|
|
218
|
+
const nextParent = parent.getParent();
|
|
219
|
+
|
|
220
|
+
if (lexical.$isRootNode(nextParent) && !handled.has(parentKey)) {
|
|
221
|
+
handled.add(parentKey);
|
|
222
|
+
createListOrMerge(parent, listType);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
parent = nextParent;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function createListOrMerge(node, listType) {
|
|
237
|
+
if (list.$isListNode(node)) {
|
|
238
|
+
return node;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const previousSibling = node.getPreviousSibling();
|
|
242
|
+
const nextSibling = node.getNextSibling();
|
|
243
|
+
const listItem = list.$createListItemNode();
|
|
244
|
+
|
|
245
|
+
if (list.$isListNode(previousSibling) && listType === previousSibling.getTag()) {
|
|
246
|
+
listItem.append(node);
|
|
247
|
+
previousSibling.append(listItem); // if the same type of list is on both sides, merge them.
|
|
248
|
+
|
|
249
|
+
if (list.$isListNode(nextSibling) && listType === nextSibling.getTag()) {
|
|
250
|
+
previousSibling.append(...nextSibling.getChildren());
|
|
251
|
+
nextSibling.remove();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return previousSibling;
|
|
255
|
+
} else if (list.$isListNode(nextSibling) && listType === nextSibling.getTag()) {
|
|
256
|
+
listItem.append(node);
|
|
257
|
+
nextSibling.getFirstChildOrThrow().insertBefore(listItem);
|
|
258
|
+
return nextSibling;
|
|
259
|
+
} else {
|
|
260
|
+
const list$1 = list.$createListNode(listType);
|
|
261
|
+
list$1.append(listItem);
|
|
262
|
+
node.replace(list$1);
|
|
263
|
+
listItem.append(node);
|
|
264
|
+
return list$1;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function removeList(editor) {
|
|
269
|
+
editor.update(() => {
|
|
270
|
+
lexical.$log('removeList');
|
|
271
|
+
const selection = lexical.$getSelection();
|
|
272
|
+
|
|
273
|
+
if (selection !== null) {
|
|
274
|
+
const listNodes = new Set();
|
|
275
|
+
const nodes = selection.getNodes();
|
|
276
|
+
const anchorNode = selection.anchor.getNode();
|
|
277
|
+
|
|
278
|
+
if (nodes.length === 0 && list.$isListItemNode(anchorNode)) {
|
|
279
|
+
listNodes.add($getTopListNode(anchorNode));
|
|
280
|
+
} else {
|
|
281
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
282
|
+
const node = nodes[i];
|
|
283
|
+
|
|
284
|
+
if (lexical.$isLeafNode(node)) {
|
|
285
|
+
const listItemNode = $getNearestNodeOfType(node, list.ListItemNode);
|
|
286
|
+
|
|
287
|
+
if (listItemNode != null) {
|
|
288
|
+
listNodes.add($getTopListNode(listItemNode));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
listNodes.forEach(listNode => {
|
|
295
|
+
let insertionPoint = listNode;
|
|
296
|
+
const listItems = $getAllListItems(listNode);
|
|
297
|
+
listItems.forEach(listItemNode => {
|
|
298
|
+
if (listItemNode != null) {
|
|
299
|
+
const paragraph = lexical.$createParagraphNode();
|
|
300
|
+
paragraph.append(...listItemNode.getChildren());
|
|
301
|
+
insertionPoint.insertAfter(paragraph);
|
|
302
|
+
insertionPoint = paragraph;
|
|
303
|
+
listItemNode.remove();
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
listNode.remove();
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
function $handleIndent(listItemNodes) {
|
|
312
|
+
// go through each node and decide where to move it.
|
|
313
|
+
listItemNodes.forEach(listItemNode => {
|
|
314
|
+
if (isNestedListNode(listItemNode)) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const parent = listItemNode.getParent();
|
|
319
|
+
const nextSibling = listItemNode.getNextSibling();
|
|
320
|
+
const previousSibling = listItemNode.getPreviousSibling(); // if there are nested lists on either side, merge them all together.
|
|
321
|
+
|
|
322
|
+
if (isNestedListNode(nextSibling) && isNestedListNode(previousSibling)) {
|
|
323
|
+
const innerList = previousSibling.getFirstChild();
|
|
324
|
+
|
|
325
|
+
if (list.$isListNode(innerList)) {
|
|
326
|
+
innerList.append(listItemNode);
|
|
327
|
+
const nextInnerList = nextSibling.getFirstChild();
|
|
328
|
+
|
|
329
|
+
if (list.$isListNode(nextInnerList)) {
|
|
330
|
+
const children = nextInnerList.getChildren();
|
|
331
|
+
innerList.append(...children);
|
|
332
|
+
nextInnerList.remove();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
innerList.getChildren().forEach(child => child.markDirty());
|
|
336
|
+
}
|
|
337
|
+
} else if (isNestedListNode(nextSibling)) {
|
|
338
|
+
// if the ListItemNode is next to a nested ListNode, merge them
|
|
339
|
+
const innerList = nextSibling.getFirstChild();
|
|
340
|
+
|
|
341
|
+
if (list.$isListNode(innerList)) {
|
|
342
|
+
const firstChild = innerList.getFirstChild();
|
|
343
|
+
|
|
344
|
+
if (firstChild !== null) {
|
|
345
|
+
firstChild.insertBefore(listItemNode);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
innerList.getChildren().forEach(child => child.markDirty());
|
|
349
|
+
}
|
|
350
|
+
} else if (isNestedListNode(previousSibling)) {
|
|
351
|
+
const innerList = previousSibling.getFirstChild();
|
|
352
|
+
|
|
353
|
+
if (list.$isListNode(innerList)) {
|
|
354
|
+
innerList.append(listItemNode);
|
|
355
|
+
innerList.getChildren().forEach(child => child.markDirty());
|
|
356
|
+
}
|
|
357
|
+
} else {
|
|
358
|
+
// otherwise, we need to create a new nested ListNode
|
|
359
|
+
if (list.$isListNode(parent)) {
|
|
360
|
+
const newListItem = list.$createListItemNode();
|
|
361
|
+
const newList = list.$createListNode(parent.getTag());
|
|
362
|
+
newListItem.append(newList);
|
|
363
|
+
newList.append(listItemNode);
|
|
364
|
+
|
|
365
|
+
if (previousSibling) {
|
|
366
|
+
previousSibling.insertAfter(newListItem);
|
|
367
|
+
} else if (nextSibling) {
|
|
368
|
+
nextSibling.insertBefore(newListItem);
|
|
369
|
+
} else {
|
|
370
|
+
parent.append(newListItem);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (list.$isListNode(parent)) {
|
|
376
|
+
parent.getChildren().forEach(child => child.markDirty());
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
function $handleOutdent(listItemNodes) {
|
|
381
|
+
// go through each node and decide where to move it.
|
|
382
|
+
listItemNodes.forEach(listItemNode => {
|
|
383
|
+
if (isNestedListNode(listItemNode)) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const parentList = listItemNode.getParent();
|
|
388
|
+
const grandparentListItem = parentList ? parentList.getParent() : undefined;
|
|
389
|
+
const greatGrandparentList = grandparentListItem ? grandparentListItem.getParent() : undefined; // If it doesn't have these ancestors, it's not indented.
|
|
390
|
+
|
|
391
|
+
if (list.$isListNode(greatGrandparentList) && list.$isListItemNode(grandparentListItem) && list.$isListNode(parentList)) {
|
|
392
|
+
// if it's the first child in it's parent list, insert it into the
|
|
393
|
+
// great grandparent list before the grandparent
|
|
394
|
+
const firstChild = parentList ? parentList.getFirstChild() : undefined;
|
|
395
|
+
const lastChild = parentList ? parentList.getLastChild() : undefined;
|
|
396
|
+
|
|
397
|
+
if (listItemNode.is(firstChild)) {
|
|
398
|
+
grandparentListItem.insertBefore(listItemNode);
|
|
399
|
+
|
|
400
|
+
if (parentList.isEmpty()) {
|
|
401
|
+
grandparentListItem.remove();
|
|
402
|
+
} // if it's the last child in it's parent list, insert it into the
|
|
403
|
+
// great grandparent list after the grandparent.
|
|
404
|
+
|
|
405
|
+
} else if (listItemNode.is(lastChild)) {
|
|
406
|
+
grandparentListItem.insertAfter(listItemNode);
|
|
407
|
+
|
|
408
|
+
if (parentList.isEmpty()) {
|
|
409
|
+
grandparentListItem.remove();
|
|
410
|
+
}
|
|
411
|
+
} else {
|
|
412
|
+
// otherwise, we need to split the siblings into two new nested lists
|
|
413
|
+
const tag = parentList.getTag();
|
|
414
|
+
const previousSiblingsListItem = list.$createListItemNode();
|
|
415
|
+
const previousSiblingsList = list.$createListNode(tag);
|
|
416
|
+
previousSiblingsListItem.append(previousSiblingsList);
|
|
417
|
+
listItemNode.getPreviousSiblings().forEach(sibling => previousSiblingsList.append(sibling));
|
|
418
|
+
const nextSiblingsListItem = list.$createListItemNode();
|
|
419
|
+
const nextSiblingsList = list.$createListNode(tag);
|
|
420
|
+
nextSiblingsListItem.append(nextSiblingsList);
|
|
421
|
+
nextSiblingsList.append(...listItemNode.getNextSiblings()); // put the sibling nested lists on either side of the grandparent list item in the great grandparent.
|
|
422
|
+
|
|
423
|
+
grandparentListItem.insertBefore(previousSiblingsListItem);
|
|
424
|
+
grandparentListItem.insertAfter(nextSiblingsListItem); // replace the grandparent list item (now between the siblings) with the outdented list item.
|
|
425
|
+
|
|
426
|
+
grandparentListItem.replace(listItemNode);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
parentList.getChildren().forEach(child => child.markDirty());
|
|
430
|
+
greatGrandparentList.getChildren().forEach(child => child.markDirty());
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function maybeIndentOrOutdent(direction) {
|
|
436
|
+
const selection = lexical.$getSelection();
|
|
437
|
+
|
|
438
|
+
if (selection === null) {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const selectedNodes = selection.getNodes();
|
|
443
|
+
let listItemNodes = [];
|
|
444
|
+
|
|
445
|
+
if (selectedNodes.length === 0) {
|
|
446
|
+
selectedNodes.push(selection.anchor.getNode());
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (selectedNodes.length === 1) {
|
|
450
|
+
// Only 1 node selected. Selection may not contain the ListNodeItem so we traverse the tree to
|
|
451
|
+
// find whether this is part of a ListItemNode
|
|
452
|
+
const nearestListItemNode = findNearestListItemNode(selectedNodes[0]);
|
|
453
|
+
|
|
454
|
+
if (nearestListItemNode !== null) {
|
|
455
|
+
listItemNodes = [nearestListItemNode];
|
|
456
|
+
}
|
|
457
|
+
} else {
|
|
458
|
+
listItemNodes = getUniqueListItemNodes(selectedNodes);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (listItemNodes.length > 0) {
|
|
462
|
+
if (direction === 'indent') {
|
|
463
|
+
$handleIndent(listItemNodes);
|
|
464
|
+
} else {
|
|
465
|
+
$handleOutdent(listItemNodes);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function indentList() {
|
|
475
|
+
return maybeIndentOrOutdent('indent');
|
|
476
|
+
}
|
|
477
|
+
function outdentList() {
|
|
478
|
+
return maybeIndentOrOutdent('outdent');
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
483
|
+
*
|
|
484
|
+
* This source code is licensed under the MIT license found in the
|
|
485
|
+
* LICENSE file in the root directory of this source tree.
|
|
486
|
+
*
|
|
487
|
+
*
|
|
488
|
+
*/
|
|
489
|
+
function addClassNamesToElement(element, ...classNames) {
|
|
490
|
+
classNames.forEach(className => {
|
|
491
|
+
if (className != null && typeof className === 'string') {
|
|
492
|
+
element.classList.add(...className.split(' '));
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
function removeClassNamesFromElement(element, ...classNames) {
|
|
497
|
+
classNames.forEach(className => {
|
|
498
|
+
element.classList.remove(...className.split(' '));
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
504
|
+
*
|
|
505
|
+
* This source code is licensed under the MIT license found in the
|
|
506
|
+
* LICENSE file in the root directory of this source tree.
|
|
507
|
+
*
|
|
508
|
+
*
|
|
509
|
+
*/
|
|
510
|
+
class ListItemNode extends lexical.ElementNode {
|
|
511
|
+
static getType() {
|
|
512
|
+
return 'listitem';
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
static clone(node) {
|
|
516
|
+
return new ListItemNode(node.__key);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
constructor(key) {
|
|
520
|
+
super(key);
|
|
521
|
+
} // View
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
createDOM(config) {
|
|
525
|
+
const element = document.createElement('li');
|
|
526
|
+
element.value = getListItemValue(this);
|
|
527
|
+
$setListItemThemeClassNames(element, config.theme, this);
|
|
528
|
+
return element;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
updateDOM(prevNode, dom, config) {
|
|
532
|
+
//$FlowFixMe - this is always HTMLListItemElement
|
|
533
|
+
dom.value = getListItemValue(this);
|
|
534
|
+
$setListItemThemeClassNames(dom, config.theme, this);
|
|
535
|
+
return false;
|
|
536
|
+
} // Mutation
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
append(...nodes) {
|
|
540
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
541
|
+
const node = nodes[i];
|
|
542
|
+
|
|
543
|
+
if (lexical.$isElementNode(node) && this.canMergeWith(node)) {
|
|
544
|
+
const children = node.getChildren();
|
|
545
|
+
this.append(...children);
|
|
546
|
+
node.remove();
|
|
547
|
+
} else {
|
|
548
|
+
super.append(node);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return this;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
replace(replaceWithNode) {
|
|
556
|
+
if ($isListItemNode(replaceWithNode)) {
|
|
557
|
+
return super.replace(replaceWithNode);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const list$1 = this.getParentOrThrow();
|
|
561
|
+
|
|
562
|
+
if (list.$isListNode(list$1)) {
|
|
563
|
+
const childrenKeys = list$1.__children;
|
|
564
|
+
const childrenLength = childrenKeys.length;
|
|
565
|
+
const index = childrenKeys.indexOf(this.__key);
|
|
566
|
+
|
|
567
|
+
if (index === 0) {
|
|
568
|
+
list$1.insertBefore(replaceWithNode);
|
|
569
|
+
} else if (index === childrenLength - 1) {
|
|
570
|
+
list$1.insertAfter(replaceWithNode);
|
|
571
|
+
} else {
|
|
572
|
+
// Split the list
|
|
573
|
+
const newList = list.$createListNode(list$1.__tag);
|
|
574
|
+
const children = list$1.getChildren();
|
|
575
|
+
|
|
576
|
+
for (let i = index + 1; i < childrenLength; i++) {
|
|
577
|
+
const child = children[i];
|
|
578
|
+
newList.append(child);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
list$1.insertAfter(replaceWithNode);
|
|
582
|
+
replaceWithNode.insertAfter(newList);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
this.remove();
|
|
586
|
+
|
|
587
|
+
if (childrenLength === 1) {
|
|
588
|
+
list$1.remove();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return replaceWithNode;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
insertAfter(node) {
|
|
596
|
+
const siblings = this.getNextSiblings();
|
|
597
|
+
|
|
598
|
+
if ($isListItemNode(node)) {
|
|
599
|
+
// mark subsequent list items dirty so we update their value attribute.
|
|
600
|
+
siblings.forEach(sibling => sibling.markDirty());
|
|
601
|
+
return super.insertAfter(node);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const listNode = this.getParentOrThrow();
|
|
605
|
+
|
|
606
|
+
if (!list.$isListNode(listNode)) {
|
|
607
|
+
{
|
|
608
|
+
throw Error(`insertAfter: list node is not parent of list item node`);
|
|
609
|
+
}
|
|
610
|
+
} // Attempt to merge tables if the list is of the same type.
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
if (list.$isListNode(node) && node.getTag() === listNode.getTag()) {
|
|
614
|
+
let child = node;
|
|
615
|
+
const children = node.getChildren();
|
|
616
|
+
|
|
617
|
+
for (let i = children.length - 1; i >= 0; i--) {
|
|
618
|
+
child = children[i];
|
|
619
|
+
this.insertAfter(child);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return child;
|
|
623
|
+
} // Otherwise, split the list
|
|
624
|
+
// Split the lists and insert the node in between them
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
listNode.insertAfter(node);
|
|
628
|
+
|
|
629
|
+
if (siblings.length !== 0) {
|
|
630
|
+
const newListNode = list.$createListNode(listNode.getTag());
|
|
631
|
+
siblings.forEach(sibling => newListNode.append(sibling));
|
|
632
|
+
node.insertAfter(newListNode);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return node;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
insertNewAfter() {
|
|
639
|
+
const nextSibling = this.getNextSibling();
|
|
640
|
+
const prevSibling = this.getPreviousSibling();
|
|
641
|
+
const list$1 = $getTopListNode(this);
|
|
642
|
+
const isLast = $isLastItemInList(this);
|
|
643
|
+
let newElement;
|
|
644
|
+
|
|
645
|
+
if (lexical.$isElementNode(list$1) && this.getTextContent() === '' && (prevSibling === null || nextSibling === null) && isLast) {
|
|
646
|
+
if (nextSibling === null) {
|
|
647
|
+
newElement = lexical.$createParagraphNode();
|
|
648
|
+
list$1.insertAfter(newElement);
|
|
649
|
+
} else {
|
|
650
|
+
newElement = lexical.$createParagraphNode();
|
|
651
|
+
list$1.insertBefore(newElement);
|
|
652
|
+
} // The naive approach would be to remove this list item and then the list, if it's empty.
|
|
653
|
+
// However, nodes may be repeatedly indented, to create deeply nested lists that each
|
|
654
|
+
// contain just one bullet.
|
|
655
|
+
// Our goal is to remove these (now-empty) deeply nested lists. The easiest way to do that
|
|
656
|
+
// is crawl back up the tree until we find a node that has siblings (e.g. is actually part
|
|
657
|
+
// of the list contents) and delete that, or delete the root of the list (if no list nodes
|
|
658
|
+
// have siblings.)
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
let emptyListPtr = this;
|
|
662
|
+
|
|
663
|
+
while (emptyListPtr.getNextSibling() == null && emptyListPtr.getPreviousSibling() == null) {
|
|
664
|
+
const parent = emptyListPtr.getParent();
|
|
665
|
+
|
|
666
|
+
if (parent == null || !($isListItemNode(emptyListPtr) || list.$isListNode(emptyListPtr))) {
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
emptyListPtr = parent;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
emptyListPtr.remove();
|
|
674
|
+
} else {
|
|
675
|
+
newElement = $createListItemNode();
|
|
676
|
+
this.insertAfter(newElement);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return newElement;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
collapseAtStart(selection) {
|
|
683
|
+
const paragraph = lexical.$createParagraphNode();
|
|
684
|
+
const children = this.getChildren();
|
|
685
|
+
children.forEach(child => paragraph.append(child));
|
|
686
|
+
const listNode = this.getParentOrThrow();
|
|
687
|
+
const listNodeParent = listNode.getParentOrThrow();
|
|
688
|
+
const isIndented = $isListItemNode(listNodeParent);
|
|
689
|
+
|
|
690
|
+
if (listNode.getChildrenSize() === 1) {
|
|
691
|
+
if (isIndented) {
|
|
692
|
+
// if the list node is nested, we just want to remove it,
|
|
693
|
+
// effectively unindenting it.
|
|
694
|
+
listNode.remove();
|
|
695
|
+
listNodeParent.select();
|
|
696
|
+
} else {
|
|
697
|
+
listNode.replace(paragraph); // If we have selection on the list item, we'll need to move it
|
|
698
|
+
// to the paragraph
|
|
699
|
+
|
|
700
|
+
const anchor = selection.anchor;
|
|
701
|
+
const focus = selection.focus;
|
|
702
|
+
const key = paragraph.getKey();
|
|
703
|
+
|
|
704
|
+
if (anchor.type === 'element' && anchor.getNode().is(this)) {
|
|
705
|
+
anchor.set(key, anchor.offset, 'element');
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if (focus.type === 'element' && focus.getNode().is(this)) {
|
|
709
|
+
focus.set(key, focus.offset, 'element');
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
} else {
|
|
713
|
+
listNode.insertBefore(paragraph);
|
|
714
|
+
this.remove();
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
getIndent() {
|
|
721
|
+
// ListItemNode should always have a ListNode for a parent.
|
|
722
|
+
let listNodeParent = this.getParentOrThrow().getParentOrThrow();
|
|
723
|
+
let indentLevel = 0;
|
|
724
|
+
|
|
725
|
+
while ($isListItemNode(listNodeParent)) {
|
|
726
|
+
listNodeParent = listNodeParent.getParentOrThrow().getParentOrThrow();
|
|
727
|
+
indentLevel++;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
return indentLevel;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
setIndent(indent) {
|
|
734
|
+
let currentIndent = this.getIndent();
|
|
735
|
+
|
|
736
|
+
while (currentIndent !== indent) {
|
|
737
|
+
if (currentIndent < indent) {
|
|
738
|
+
$handleIndent([this]);
|
|
739
|
+
currentIndent++;
|
|
740
|
+
} else {
|
|
741
|
+
$handleOutdent([this]);
|
|
742
|
+
currentIndent--;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return this;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
insertBefore(nodeToInsert) {
|
|
750
|
+
const siblings = this.getNextSiblings();
|
|
751
|
+
|
|
752
|
+
if ($isListItemNode(nodeToInsert)) {
|
|
753
|
+
// mark subsequent list items dirty so we update their value attribute.
|
|
754
|
+
siblings.forEach(sibling => sibling.markDirty());
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
return super.insertBefore(nodeToInsert);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
canInsertAfter(node) {
|
|
761
|
+
return $isListItemNode(node);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
canReplaceWith(replacement) {
|
|
765
|
+
return $isListItemNode(replacement);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
canMergeWith(node) {
|
|
769
|
+
return lexical.$isParagraphNode(node) || $isListItemNode(node);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
function getListItemValue(listItem) {
|
|
775
|
+
const list$1 = listItem.getParent();
|
|
776
|
+
let value = 1;
|
|
777
|
+
|
|
778
|
+
if (list$1 != null) {
|
|
779
|
+
if (!list.$isListNode(list$1)) {
|
|
780
|
+
{
|
|
781
|
+
throw Error(`getListItemValue: list node is not parent of list item node`);
|
|
782
|
+
}
|
|
783
|
+
} else {
|
|
784
|
+
value = list$1.__start;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const siblings = listItem.getPreviousSiblings();
|
|
789
|
+
|
|
790
|
+
for (let i = 0; i < siblings.length; i++) {
|
|
791
|
+
const sibling = siblings[i];
|
|
792
|
+
|
|
793
|
+
if ($isListItemNode(sibling) && !list.$isListNode(sibling.getFirstChild())) {
|
|
794
|
+
value++;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return value;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function $setListItemThemeClassNames(dom, editorThemeClasses, node) {
|
|
802
|
+
const classesToAdd = [];
|
|
803
|
+
const classesToRemove = [];
|
|
804
|
+
const listTheme = editorThemeClasses.list;
|
|
805
|
+
const listItemClassName = listTheme ? listTheme.listitem : undefined;
|
|
806
|
+
let nestedListItemClassName;
|
|
807
|
+
|
|
808
|
+
if (listTheme && listTheme.nested) {
|
|
809
|
+
nestedListItemClassName = listTheme.nested.listitem;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (listItemClassName !== undefined) {
|
|
813
|
+
const listItemClasses = listItemClassName.split(' ');
|
|
814
|
+
classesToAdd.push(...listItemClasses);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (nestedListItemClassName !== undefined) {
|
|
818
|
+
const nestedListItemClasses = nestedListItemClassName.split(' ');
|
|
819
|
+
|
|
820
|
+
if (node.getChildren().some(child => list.$isListNode(child))) {
|
|
821
|
+
classesToAdd.push(...nestedListItemClasses);
|
|
822
|
+
} else {
|
|
823
|
+
classesToRemove.push(...nestedListItemClasses);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (classesToAdd.length > 0) {
|
|
828
|
+
addClassNamesToElement(dom, ...classesToAdd);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (classesToRemove.length > 0) {
|
|
832
|
+
removeClassNamesFromElement(dom, ...classesToRemove);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
function $createListItemNode() {
|
|
837
|
+
return new ListItemNode();
|
|
838
|
+
}
|
|
839
|
+
function $isListItemNode(node) {
|
|
840
|
+
return node instanceof ListItemNode;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
845
|
+
*
|
|
846
|
+
* This source code is licensed under the MIT license found in the
|
|
847
|
+
* LICENSE file in the root directory of this source tree.
|
|
848
|
+
*
|
|
849
|
+
*
|
|
850
|
+
*/
|
|
851
|
+
class ListNode extends lexical.ElementNode {
|
|
852
|
+
static getType() {
|
|
853
|
+
return 'list';
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
static clone(node) {
|
|
857
|
+
return new ListNode(node.__tag, node.__start, node.__key);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
constructor(tag, start, key) {
|
|
861
|
+
super(key);
|
|
862
|
+
this.__tag = tag;
|
|
863
|
+
this.__start = start;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
getTag() {
|
|
867
|
+
return this.__tag;
|
|
868
|
+
} // View
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
createDOM(config) {
|
|
872
|
+
const tag = this.__tag;
|
|
873
|
+
const dom = document.createElement(tag);
|
|
874
|
+
|
|
875
|
+
if (this.__start !== 1) {
|
|
876
|
+
dom.setAttribute('start', String(this.__start));
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
setListThemeClassNames(dom, config.theme, this);
|
|
880
|
+
return dom;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
updateDOM(prevNode, dom, config) {
|
|
884
|
+
if (prevNode.__tag !== this.__tag) {
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
setListThemeClassNames(dom, config.theme, this);
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
canBeEmpty() {
|
|
893
|
+
return false;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
append(...nodesToAppend) {
|
|
897
|
+
for (let i = 0; i < nodesToAppend.length; i++) {
|
|
898
|
+
const currentNode = nodesToAppend[i];
|
|
899
|
+
|
|
900
|
+
if (list.$isListItemNode(currentNode)) {
|
|
901
|
+
super.append(currentNode);
|
|
902
|
+
} else {
|
|
903
|
+
const listItemNode = list.$createListItemNode();
|
|
904
|
+
|
|
905
|
+
if ($isListNode(currentNode)) {
|
|
906
|
+
listItemNode.append(currentNode);
|
|
907
|
+
} else {
|
|
908
|
+
const textNode = lexical.$createTextNode(currentNode.getTextContent());
|
|
909
|
+
listItemNode.append(textNode);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
super.append(listItemNode);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
return this;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function setListThemeClassNames(dom, editorThemeClasses, node) {
|
|
922
|
+
const classesToAdd = [];
|
|
923
|
+
const classesToRemove = [];
|
|
924
|
+
const listTheme = editorThemeClasses.list;
|
|
925
|
+
|
|
926
|
+
if (listTheme !== undefined) {
|
|
927
|
+
const listDepth = $getListDepth(node);
|
|
928
|
+
const normalizedListDepth = listDepth % 5;
|
|
929
|
+
const listThemeLevel = normalizedListDepth === 0 ? 5 : normalizedListDepth;
|
|
930
|
+
const listThemeLevelClassName = node.__tag + listThemeLevel;
|
|
931
|
+
const listLevelClassName = listTheme[listThemeLevelClassName];
|
|
932
|
+
const listClassName = listTheme[node.__tag];
|
|
933
|
+
let nestedListClassName;
|
|
934
|
+
const nestedListTheme = listTheme.nested;
|
|
935
|
+
|
|
936
|
+
if (nestedListTheme !== undefined && nestedListTheme.list) {
|
|
937
|
+
nestedListClassName = nestedListTheme.list;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
if (listClassName !== undefined) {
|
|
941
|
+
classesToAdd.push(listClassName);
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
if (listLevelClassName !== undefined) {
|
|
945
|
+
const listItemClasses = listLevelClassName.split(' ');
|
|
946
|
+
classesToAdd.push(...listItemClasses);
|
|
947
|
+
|
|
948
|
+
for (let i = 1; i < 6; i++) {
|
|
949
|
+
if (i !== normalizedListDepth) {
|
|
950
|
+
classesToRemove.push(node.__tag + i);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (nestedListClassName !== undefined) {
|
|
956
|
+
const nestedListItemClasses = nestedListClassName.split(' ');
|
|
957
|
+
|
|
958
|
+
if (listDepth > 1) {
|
|
959
|
+
classesToAdd.push(...nestedListItemClasses);
|
|
960
|
+
} else {
|
|
961
|
+
classesToRemove.push(...nestedListItemClasses);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (classesToAdd.length > 0) {
|
|
967
|
+
addClassNamesToElement(dom, ...classesToAdd);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
if (classesToRemove.length > 0) {
|
|
971
|
+
removeClassNamesFromElement(dom, ...classesToRemove);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
function $createListNode(tag, start = 1) {
|
|
976
|
+
return new ListNode(tag, start);
|
|
977
|
+
}
|
|
978
|
+
function $isListNode(node) {
|
|
979
|
+
return node instanceof ListNode;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
exports.$createListItemNode = $createListItemNode;
|
|
983
|
+
exports.$createListNode = $createListNode;
|
|
984
|
+
exports.$isListItemNode = $isListItemNode;
|
|
985
|
+
exports.$isListNode = $isListNode;
|
|
986
|
+
exports.ListItemNode = ListItemNode;
|
|
987
|
+
exports.ListNode = ListNode;
|
|
988
|
+
exports.indentList = indentList;
|
|
989
|
+
exports.insertList = insertList;
|
|
990
|
+
exports.outdentList = outdentList;
|
|
991
|
+
exports.removeList = removeList;
|
package/LexicalList.js
CHANGED
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
""===this.getTextContent()&&(null===a||null===c)&&d){null===c?(c=f.$createParagraphNode(),b.insertAfter(c)):(c=f.$createParagraphNode(),b.insertBefore(c));for(b=this;null==b.getNextSibling()&&null==b.getPreviousSibling();){a=b.getParent();if(null==a||!C(b)&&!k.$isListNode(b))break;b=a}b.remove()}else c=D(),this.insertAfter(c);return c}collapseAtStart(c){const a=f.$createParagraphNode();this.getChildren().forEach(g=>a.append(g));var b=this.getParentOrThrow(),d=b.getParentOrThrow();const e=C(d);1===
|
|
11
|
-
b.getChildrenSize()?e?(b.remove(),d.select()):(b.replace(a),b=c.anchor,c=c.focus,d=a.getKey(),"element"===b.type&&b.getNode().is(this)&&b.set(d,b.offset,"element"),"element"===c.type&&c.getNode().is(this)&&c.set(d,c.offset,"element")):(b.insertBefore(a),this.remove());return!0}getIndent(){let c=this.getParentOrThrow().getParentOrThrow(),a=0;for(;C(c);)c=c.getParentOrThrow().getParentOrThrow(),a++;return a}setIndent(){return this}insertBefore(c){const a=this.getNextSiblings();C(c)&&a.forEach(b=>b.markDirty());
|
|
12
|
-
return super.insertBefore(c)}canInsertAfter(c){return C(c)}canReplaceWith(c){return C(c)}canMergeWith(c){return f.$isParagraphNode(c)||C(c)}}function A(c){var a=c.getParent();let b=1;null!=a&&(k.$isListNode(a)?b=a.__start:r(47));c=c.getPreviousSiblings();for(a=0;a<c.length;a++){const d=c[a];C(d)&&!k.$isListNode(d.getFirstChild())&&b++}return b}
|
|
13
|
-
function B(c,a,b){const d=[],e=[],g=(a=a.list)?a.listitem:void 0;if(a&&a.nested)var h=a.nested.listitem;void 0!==g&&(a=g.split(" "),d.push(...a));void 0!==h&&(h=h.split(" "),b.getChildren().some(l=>k.$isListNode(l))?d.push(...h):e.push(...h));0<d.length&&n(c,...d);0<e.length&&p(c,...e)}function D(){return new z}function C(c){return c instanceof z}function E(c,a){for(;null!=c&&!(c instanceof a);)c=c.getParent();return c}
|
|
14
|
-
function F(c,a){if(k.$isListNode(c))return c;const b=c.getPreviousSibling(),d=c.getNextSibling(),e=k.$createListItemNode();if(k.$isListNode(b)&&a===b.getTag())return e.append(c),b.append(e),k.$isListNode(d)&&a===d.getTag()&&(b.append(...d.getChildren()),d.remove()),b;if(k.$isListNode(d)&&a===d.getTag())return e.append(c),d.getFirstChildOrThrow().insertBefore(e),d;a=k.$createListNode(a);a.append(e);c.replace(a);e.append(c);return a}
|
|
15
|
-
function G(c){c.forEach(a=>{if(!v(a)){var b=a.getParent(),d=a.getNextSibling(),e=a.getPreviousSibling();if(v(d)&&v(e))e=e.getFirstChild(),k.$isListNode(e)&&(e.append(a),a=d.getFirstChild(),k.$isListNode(a)&&(d=a.getChildren(),e.append(...d),a.remove()),e.getChildren().forEach(g=>g.markDirty()));else if(v(d))d=d.getFirstChild(),k.$isListNode(d)&&(e=d.getFirstChild(),null!==e&&e.insertBefore(a),d.getChildren().forEach(g=>g.markDirty()));else if(v(e))d=e.getFirstChild(),k.$isListNode(d)&&(d.append(a),
|
|
16
|
-
d.getChildren().forEach(g=>g.markDirty()));else if(k.$isListNode(b)){const g=k.$createListItemNode(),h=k.$createListNode(b.getTag());g.append(h);h.append(a);e?e.insertAfter(g):d?d.insertBefore(g):b.append(g)}k.$isListNode(b)&&b.getChildren().forEach(g=>g.markDirty())}})}
|
|
17
|
-
function H(c){c.forEach(a=>{if(!v(a)){var b=a.getParent(),d=b?b.getParent():void 0,e=d?d.getParent():void 0;if(k.$isListNode(e)&&k.$isListItemNode(d)&&k.$isListNode(b)){var g=b?b.getFirstChild():void 0,h=b?b.getLastChild():void 0;if(a.is(g))d.insertBefore(a),b.isEmpty()&&d.remove();else if(a.is(h))d.insertAfter(a),b.isEmpty()&&d.remove();else{var l=b.getTag();g=k.$createListItemNode();const m=k.$createListNode(l);g.append(m);a.getPreviousSiblings().forEach(q=>m.append(q));h=k.$createListItemNode();
|
|
18
|
-
l=k.$createListNode(l);h.append(l);l.append(...a.getNextSiblings());d.insertBefore(g);d.insertAfter(h);d.replace(a)}b.getChildren().forEach(m=>m.markDirty());e.getChildren().forEach(m=>m.markDirty())}}})}
|
|
19
|
-
function I(c){var a=f.$getSelection();if(null===a)return!1;var b=a.getNodes(),d=[];0===b.length&&b.push(a.anchor.getNode());if(1===b.length){a:{for(b=b[0];null!==b;){if(k.$isListItemNode(b))break a;b=b.getParent()}b=null}null!==b&&(d=[b])}else{d=new Set;for(a=0;a<b.length;a++){const e=b[a];k.$isListItemNode(e)&&d.add(e)}d=Array.from(d)}return 0<d.length?("indent"===c?G(d):H(d),!0):!1}exports.$createListItemNode=D;exports.$createListNode=function(c,a=1){return new w(c,a)};exports.$isListItemNode=C;
|
|
20
|
-
exports.$isListNode=y;exports.ListItemNode=z;exports.ListNode=w;exports.indentList=function(){return I("indent")};
|
|
21
|
-
exports.insertList=function(c,a){c.update(()=>{f.$log("formatList");var b=f.$getSelection();if(null!==b){var d=b.getNodes();b=b.anchor.getNode();var e=b.getParent();if(0===d.length)d=k.$createListNode(a),f.$isRootNode(e)?(b.replace(d),b=k.$createListItemNode(),d.append(b)):k.$isListItemNode(b)&&(b=b.getParentOrThrow(),d.append(...b.getChildren()),b.replace(d));else for(b=new Set,e=0;e<d.length;e++){var g=d[e];if(f.$isElementNode(g)&&g.isEmpty()&&!b.has(g.getKey()))F(g,a);else if(f.$isLeafNode(g))for(g=
|
|
22
|
-
g.getParent();null!=g;){const l=g.getKey();if(k.$isListNode(g)){if(!b.has(l)){var h=k.$createListNode(a);h.append(...g.getChildren());g.replace(h);b.add(l)}break}else{h=g.getParent();if(f.$isRootNode(h)&&!b.has(l)){b.add(l);F(g,a);break}g=h}}}}})};exports.outdentList=function(){return I("outdent")};
|
|
23
|
-
exports.removeList=function(c){c.update(()=>{f.$log("removeList");var a=f.$getSelection();if(null!==a){const d=new Set,e=a.getNodes();a=a.anchor.getNode();if(0===e.length&&k.$isListItemNode(a))d.add(t(a));else for(a=0;a<e.length;a++){var b=e[a];f.$isLeafNode(b)&&(b=E(b,k.ListItemNode),null!=b&&d.add(t(b)))}d.forEach(g=>{let h=g;u(g).forEach(l=>{if(null!=l){const m=f.$createParagraphNode();m.append(...l.getChildren());h.insertAfter(m);h=m;l.remove()}});g.remove()})}})};
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict'
|
|
8
|
+
const LexicalList = process.env.NODE_ENV === 'development' ? require('./LexicalList.dev.js') : require('./LexicalList.prod.js')
|
|
9
|
+
module.exports = LexicalList;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
'use strict';var f=require("@lexical/list"),k=require("lexical");function n(c,a){for(;null!=c&&!(c instanceof a);)c=c.getParent();return c}function p(c){throw Error(`Minified Lexical error #${c}; see codes.json for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function r(c){c=c.getParent();f.$isListNode(c)||p(2);let a=c;for(;null!==a;)a=a.getParent(),f.$isListNode(a)&&(c=a);return c}
|
|
8
|
+
function t(c){let a=[];c=c.getChildren().filter(f.$isListItemNode);for(let b=0;b<c.length;b++){const d=c[b],e=d.getFirstChild();f.$isListNode(e)?a=a.concat(t(e)):a.push(d)}return a}function u(c){return f.$isListItemNode(c)&&f.$isListNode(c.getFirstChild())}
|
|
9
|
+
function v(c,a){if(f.$isListNode(c))return c;const b=c.getPreviousSibling(),d=c.getNextSibling(),e=f.$createListItemNode();if(f.$isListNode(b)&&a===b.getTag())return e.append(c),b.append(e),f.$isListNode(d)&&a===d.getTag()&&(b.append(...d.getChildren()),d.remove()),b;if(f.$isListNode(d)&&a===d.getTag())return e.append(c),d.getFirstChildOrThrow().insertBefore(e),d;a=f.$createListNode(a);a.append(e);c.replace(a);e.append(c);return a}
|
|
10
|
+
function w(c){c.forEach(a=>{if(!u(a)){var b=a.getParent(),d=a.getNextSibling(),e=a.getPreviousSibling();if(u(d)&&u(e))e=e.getFirstChild(),f.$isListNode(e)&&(e.append(a),a=d.getFirstChild(),f.$isListNode(a)&&(d=a.getChildren(),e.append(...d),a.remove()),e.getChildren().forEach(g=>g.markDirty()));else if(u(d))d=d.getFirstChild(),f.$isListNode(d)&&(e=d.getFirstChild(),null!==e&&e.insertBefore(a),d.getChildren().forEach(g=>g.markDirty()));else if(u(e))d=e.getFirstChild(),f.$isListNode(d)&&(d.append(a),
|
|
11
|
+
d.getChildren().forEach(g=>g.markDirty()));else if(f.$isListNode(b)){const g=f.$createListItemNode(),h=f.$createListNode(b.getTag());g.append(h);h.append(a);e?e.insertAfter(g):d?d.insertBefore(g):b.append(g)}f.$isListNode(b)&&b.getChildren().forEach(g=>g.markDirty())}})}
|
|
12
|
+
function x(c){c.forEach(a=>{if(!u(a)){var b=a.getParent(),d=b?b.getParent():void 0,e=d?d.getParent():void 0;if(f.$isListNode(e)&&f.$isListItemNode(d)&&f.$isListNode(b)){var g=b?b.getFirstChild():void 0,h=b?b.getLastChild():void 0;if(a.is(g))d.insertBefore(a),b.isEmpty()&&d.remove();else if(a.is(h))d.insertAfter(a),b.isEmpty()&&d.remove();else{var l=b.getTag();g=f.$createListItemNode();const m=f.$createListNode(l);g.append(m);a.getPreviousSiblings().forEach(q=>m.append(q));h=f.$createListItemNode();
|
|
13
|
+
l=f.$createListNode(l);h.append(l);l.append(...a.getNextSiblings());d.insertBefore(g);d.insertAfter(h);d.replace(a)}b.getChildren().forEach(m=>m.markDirty());e.getChildren().forEach(m=>m.markDirty())}}})}
|
|
14
|
+
function y(c){var a=k.$getSelection();if(null===a)return!1;var b=a.getNodes(),d=[];0===b.length&&b.push(a.anchor.getNode());if(1===b.length){a:{for(b=b[0];null!==b;){if(f.$isListItemNode(b))break a;b=b.getParent()}b=null}null!==b&&(d=[b])}else{d=new Set;for(a=0;a<b.length;a++){const e=b[a];f.$isListItemNode(e)&&d.add(e)}d=Array.from(d)}return 0<d.length?("indent"===c?w(d):x(d),!0):!1}function z(c,...a){a.forEach(b=>{null!=b&&"string"===typeof b&&c.classList.add(...b.split(" "))})}
|
|
15
|
+
function A(c,...a){a.forEach(b=>{c.classList.remove(...b.split(" "))})}
|
|
16
|
+
class B extends k.ElementNode{static getType(){return"listitem"}static clone(c){return new B(c.__key)}constructor(c){super(c)}createDOM(c){const a=document.createElement("li");a.value=C(this);D(a,c.theme,this);return a}updateDOM(c,a,b){a.value=C(this);D(a,b.theme,this);return!1}append(...c){for(let a=0;a<c.length;a++){const b=c[a];if(k.$isElementNode(b)&&this.canMergeWith(b)){const d=b.getChildren();this.append(...d);b.remove()}else super.append(b)}return this}replace(c){if(E(c))return super.replace(c);const a=
|
|
17
|
+
this.getParentOrThrow();if(f.$isListNode(a)){var b=a.__children;const e=b.length;var d=b.indexOf(this.__key);if(0===d)a.insertBefore(c);else if(d===e-1)a.insertAfter(c);else{b=f.$createListNode(a.__tag);const g=a.getChildren();for(d+=1;d<e;d++)b.append(g[d]);a.insertAfter(c);c.insertAfter(b)}this.remove();1===e&&a.remove()}return c}insertAfter(c){var a=this.getNextSiblings();if(E(c))return a.forEach(d=>d.markDirty()),super.insertAfter(c);var b=this.getParentOrThrow();f.$isListNode(b)||p(1);if(f.$isListNode(c)&&
|
|
18
|
+
c.getTag()===b.getTag()){a=c;c=c.getChildren();for(b=c.length-1;0<=b;b--)a=c[b],this.insertAfter(a);return a}b.insertAfter(c);if(0!==a.length){const d=f.$createListNode(b.getTag());a.forEach(e=>d.append(e));c.insertAfter(d)}return c}insertNewAfter(){var c=this.getNextSibling(),a=this.getPreviousSibling(),b=r(this);var d=!0;var e=this.getFirstChild();if(f.$isListNode(e))d=!1;else for(e=this;null!==e;)f.$isListItemNode(e)&&0<e.getNextSiblings().length&&(d=!1),e=e.getParent();if(k.$isElementNode(b)&&
|
|
19
|
+
""===this.getTextContent()&&(null===a||null===c)&&d){null===c?(c=k.$createParagraphNode(),b.insertAfter(c)):(c=k.$createParagraphNode(),b.insertBefore(c));for(b=this;null==b.getNextSibling()&&null==b.getPreviousSibling();){a=b.getParent();if(null==a||!E(b)&&!f.$isListNode(b))break;b=a}b.remove()}else c=F(),this.insertAfter(c);return c}collapseAtStart(c){const a=k.$createParagraphNode();this.getChildren().forEach(g=>a.append(g));var b=this.getParentOrThrow(),d=b.getParentOrThrow();const e=E(d);1===
|
|
20
|
+
b.getChildrenSize()?e?(b.remove(),d.select()):(b.replace(a),b=c.anchor,c=c.focus,d=a.getKey(),"element"===b.type&&b.getNode().is(this)&&b.set(d,b.offset,"element"),"element"===c.type&&c.getNode().is(this)&&c.set(d,c.offset,"element")):(b.insertBefore(a),this.remove());return!0}getIndent(){let c=this.getParentOrThrow().getParentOrThrow(),a=0;for(;E(c);)c=c.getParentOrThrow().getParentOrThrow(),a++;return a}setIndent(c){let a=this.getIndent();for(;a!==c;)a<c?(w([this]),a++):(x([this]),a--);return this}insertBefore(c){const a=
|
|
21
|
+
this.getNextSiblings();E(c)&&a.forEach(b=>b.markDirty());return super.insertBefore(c)}canInsertAfter(c){return E(c)}canReplaceWith(c){return E(c)}canMergeWith(c){return k.$isParagraphNode(c)||E(c)}}function C(c){var a=c.getParent();let b=1;null!=a&&(f.$isListNode(a)?b=a.__start:p(47));c=c.getPreviousSiblings();for(a=0;a<c.length;a++){const d=c[a];E(d)&&!f.$isListNode(d.getFirstChild())&&b++}return b}
|
|
22
|
+
function D(c,a,b){const d=[],e=[],g=(a=a.list)?a.listitem:void 0;if(a&&a.nested)var h=a.nested.listitem;void 0!==g&&(a=g.split(" "),d.push(...a));void 0!==h&&(h=h.split(" "),b.getChildren().some(l=>f.$isListNode(l))?d.push(...h):e.push(...h));0<d.length&&z(c,...d);0<e.length&&A(c,...e)}function F(){return new B}function E(c){return c instanceof B}
|
|
23
|
+
class G extends k.ElementNode{static getType(){return"list"}static clone(c){return new G(c.__tag,c.__start,c.__key)}constructor(c,a,b){super(b);this.__tag=c;this.__start=a}getTag(){return this.__tag}createDOM(c){const a=document.createElement(this.__tag);1!==this.__start&&a.setAttribute("start",String(this.__start));H(a,c.theme,this);return a}updateDOM(c,a,b){if(c.__tag!==this.__tag)return!0;H(a,b.theme,this);return!1}canBeEmpty(){return!1}append(...c){for(let b=0;b<c.length;b++){var a=c[b];if(f.$isListItemNode(a))super.append(a);
|
|
24
|
+
else{const d=f.$createListItemNode();I(a)?d.append(a):(a=k.$createTextNode(a.getTextContent()),d.append(a));super.append(d)}}return this}}
|
|
25
|
+
function H(c,a,b){const d=[],e=[];a=a.list;if(void 0!==a){a:{var g=1;for(var h=b.getParent();null!=h;){if(f.$isListItemNode(h)){h=h.getParent();if(f.$isListNode(h)){g++;h=h.getParent();continue}p(2)}break a}}h=g%5;const l=a[b.__tag+(0===h?5:h)],m=a[b.__tag];let q;a=a.nested;void 0!==a&&a.list&&(q=a.list);void 0!==m&&d.push(m);if(void 0!==l)for(a=l.split(" "),d.push(...a),a=1;6>a;a++)a!==h&&e.push(b.__tag+a);void 0!==q&&(b=q.split(" "),1<g?d.push(...b):e.push(...b))}0<d.length&&z(c,...d);0<e.length&&
|
|
26
|
+
A(c,...e)}function I(c){return c instanceof G}exports.$createListItemNode=F;exports.$createListNode=function(c,a=1){return new G(c,a)};exports.$isListItemNode=E;exports.$isListNode=I;exports.ListItemNode=B;exports.ListNode=G;exports.indentList=function(){return y("indent")};
|
|
27
|
+
exports.insertList=function(c,a){c.update(()=>{k.$log("formatList");var b=k.$getSelection();if(null!==b){var d=b.getNodes();b=b.anchor.getNode();var e=b.getParent();if(0===d.length)d=f.$createListNode(a),k.$isRootNode(e)?(b.replace(d),b=f.$createListItemNode(),d.append(b)):f.$isListItemNode(b)&&(b=b.getParentOrThrow(),d.append(...b.getChildren()),b.replace(d));else for(b=new Set,e=0;e<d.length;e++){var g=d[e];if(k.$isElementNode(g)&&g.isEmpty()&&!b.has(g.getKey()))v(g,a);else if(k.$isLeafNode(g))for(g=
|
|
28
|
+
g.getParent();null!=g;){const l=g.getKey();if(f.$isListNode(g)){if(!b.has(l)){var h=f.$createListNode(a);h.append(...g.getChildren());g.replace(h);b.add(l)}break}else{h=g.getParent();if(k.$isRootNode(h)&&!b.has(l)){b.add(l);v(g,a);break}g=h}}}}})};exports.outdentList=function(){return y("outdent")};
|
|
29
|
+
exports.removeList=function(c){c.update(()=>{k.$log("removeList");var a=k.$getSelection();if(null!==a){const d=new Set,e=a.getNodes();a=a.anchor.getNode();if(0===e.length&&f.$isListItemNode(a))d.add(r(a));else for(a=0;a<e.length;a++){var b=e[a];k.$isLeafNode(b)&&(b=n(b,f.ListItemNode),null!=b&&d.add(r(b)))}d.forEach(g=>{let h=g;t(g).forEach(l=>{if(null!=l){const m=k.$createParagraphNode();m.append(...l.getChildren());h.insertAfter(m);h=m;l.remove()}});g.remove()})}})};
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
2
|
+
"name": "@lexical/list",
|
|
3
|
+
"author": {
|
|
4
|
+
"name": "Dominic Gannaway",
|
|
5
|
+
"email": "dg@domgan.com"
|
|
6
|
+
},
|
|
7
|
+
"description": "This package provides the list feature for Lexical.",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"lexical",
|
|
10
|
+
"editor",
|
|
11
|
+
"rich-text",
|
|
12
|
+
"list"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"version": "0.1.8",
|
|
16
|
+
"main": "LexicalList.js",
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"lexical": "0.1.8"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/facebook/lexical",
|
|
23
|
+
"directory": "packages/lexical-list"
|
|
25
24
|
}
|
|
25
|
+
}
|