@lexical/selection 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LexicalSelection.dev.js +203 -63
- package/LexicalSelection.js.flow +1 -1
- package/LexicalSelection.prod.js +22 -22
- package/README.md +2 -2
- package/index.d.ts +2 -2
- package/package.json +2 -2
- package/range-selection.d.ts +2 -1
package/LexicalSelection.dev.js
CHANGED
|
@@ -24,23 +24,31 @@ const CSS_TO_STYLES = new Map();
|
|
|
24
24
|
* LICENSE file in the root directory of this source tree.
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
|
+
|
|
27
28
|
function getDOMTextNode(element) {
|
|
28
29
|
let node = element;
|
|
30
|
+
|
|
29
31
|
while (node != null) {
|
|
30
32
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
31
33
|
return node;
|
|
32
34
|
}
|
|
35
|
+
|
|
33
36
|
node = node.firstChild;
|
|
34
37
|
}
|
|
38
|
+
|
|
35
39
|
return null;
|
|
36
40
|
}
|
|
41
|
+
|
|
37
42
|
function getDOMIndexWithinParent(node) {
|
|
38
43
|
const parent = node.parentNode;
|
|
44
|
+
|
|
39
45
|
if (parent == null) {
|
|
40
46
|
throw new Error('Should never happen');
|
|
41
47
|
}
|
|
48
|
+
|
|
42
49
|
return [parent, Array.from(parent.childNodes).indexOf(node)];
|
|
43
50
|
}
|
|
51
|
+
|
|
44
52
|
function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffset) {
|
|
45
53
|
const anchorKey = anchorNode.getKey();
|
|
46
54
|
const focusKey = focusNode.getKey();
|
|
@@ -49,94 +57,116 @@ function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffs
|
|
|
49
57
|
let focusDOM = editor.getElementByKey(focusKey);
|
|
50
58
|
let anchorOffset = _anchorOffset;
|
|
51
59
|
let focusOffset = _focusOffset;
|
|
60
|
+
|
|
52
61
|
if (lexical.$isTextNode(anchorNode)) {
|
|
53
62
|
anchorDOM = getDOMTextNode(anchorDOM);
|
|
54
63
|
}
|
|
64
|
+
|
|
55
65
|
if (lexical.$isTextNode(focusNode)) {
|
|
56
66
|
focusDOM = getDOMTextNode(focusDOM);
|
|
57
67
|
}
|
|
68
|
+
|
|
58
69
|
if (anchorNode === undefined || focusNode === undefined || anchorDOM === null || focusDOM === null) {
|
|
59
70
|
return null;
|
|
60
71
|
}
|
|
72
|
+
|
|
61
73
|
if (anchorDOM.nodeName === 'BR') {
|
|
62
74
|
[anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM);
|
|
63
75
|
}
|
|
76
|
+
|
|
64
77
|
if (focusDOM.nodeName === 'BR') {
|
|
65
78
|
[focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM);
|
|
66
79
|
}
|
|
80
|
+
|
|
67
81
|
const firstChild = anchorDOM.firstChild;
|
|
82
|
+
|
|
68
83
|
if (anchorDOM === focusDOM && firstChild != null && firstChild.nodeName === 'BR' && anchorOffset === 0 && focusOffset === 0) {
|
|
69
84
|
focusOffset = 1;
|
|
70
85
|
}
|
|
86
|
+
|
|
71
87
|
try {
|
|
72
88
|
range.setStart(anchorDOM, anchorOffset);
|
|
73
89
|
range.setEnd(focusDOM, focusOffset);
|
|
74
90
|
} catch (e) {
|
|
75
91
|
return null;
|
|
76
92
|
}
|
|
93
|
+
|
|
77
94
|
if (range.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) {
|
|
78
95
|
// Range is backwards, we need to reverse it
|
|
79
96
|
range.setStart(focusDOM, focusOffset);
|
|
80
97
|
range.setEnd(anchorDOM, anchorOffset);
|
|
81
98
|
}
|
|
99
|
+
|
|
82
100
|
return range;
|
|
83
101
|
}
|
|
84
102
|
function createRectsFromDOMRange(editor, range) {
|
|
85
103
|
const rootElement = editor.getRootElement();
|
|
104
|
+
|
|
86
105
|
if (rootElement === null) {
|
|
87
106
|
return [];
|
|
88
107
|
}
|
|
108
|
+
|
|
89
109
|
const rootRect = rootElement.getBoundingClientRect();
|
|
90
110
|
const computedStyle = getComputedStyle(rootElement);
|
|
91
111
|
const rootPadding = parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);
|
|
92
112
|
const selectionRects = Array.from(range.getClientRects());
|
|
93
113
|
let selectionRectsLength = selectionRects.length;
|
|
94
114
|
let prevRect;
|
|
115
|
+
|
|
95
116
|
for (let i = 0; i < selectionRectsLength; i++) {
|
|
96
|
-
const selectionRect = selectionRects[i];
|
|
97
|
-
// Exclude a rect that is the exact same as the last rect. getClientRects() can return
|
|
117
|
+
const selectionRect = selectionRects[i]; // Exclude a rect that is the exact same as the last rect. getClientRects() can return
|
|
98
118
|
// the same rect twice for some elements. A more sophisticated thing to do here is to
|
|
99
119
|
// merge all the rects together into a set of rects that don't overlap, so we don't
|
|
100
120
|
// generate backgrounds that are too dark.
|
|
101
|
-
const isDuplicateRect = prevRect && prevRect.top === selectionRect.top && prevRect.left === selectionRect.left && prevRect.width === selectionRect.width && prevRect.height === selectionRect.height;
|
|
102
121
|
|
|
103
|
-
// Exclude selections that span the entire element
|
|
122
|
+
const isDuplicateRect = prevRect && prevRect.top === selectionRect.top && prevRect.left === selectionRect.left && prevRect.width === selectionRect.width && prevRect.height === selectionRect.height; // Exclude selections that span the entire element
|
|
123
|
+
|
|
104
124
|
const selectionSpansElement = selectionRect.width + rootPadding === rootRect.width;
|
|
125
|
+
|
|
105
126
|
if (isDuplicateRect || selectionSpansElement) {
|
|
106
127
|
selectionRects.splice(i--, 1);
|
|
107
128
|
selectionRectsLength--;
|
|
108
129
|
continue;
|
|
109
130
|
}
|
|
131
|
+
|
|
110
132
|
prevRect = selectionRect;
|
|
111
133
|
}
|
|
134
|
+
|
|
112
135
|
return selectionRects;
|
|
113
136
|
}
|
|
114
137
|
function getStyleObjectFromRawCSS(css) {
|
|
115
138
|
const styleObject = {};
|
|
116
139
|
const styles = css.split(';');
|
|
140
|
+
|
|
117
141
|
for (const style of styles) {
|
|
118
142
|
if (style !== '') {
|
|
119
143
|
const [key, value] = style.split(/:([^]+)/); // split on first colon
|
|
144
|
+
|
|
120
145
|
styleObject[key.trim()] = value.trim();
|
|
121
146
|
}
|
|
122
147
|
}
|
|
148
|
+
|
|
123
149
|
return styleObject;
|
|
124
150
|
}
|
|
125
151
|
function getStyleObjectFromCSS(css) {
|
|
126
152
|
let value = CSS_TO_STYLES.get(css);
|
|
153
|
+
|
|
127
154
|
if (value === undefined) {
|
|
128
155
|
value = getStyleObjectFromRawCSS(css);
|
|
129
156
|
CSS_TO_STYLES.set(css, value);
|
|
130
157
|
}
|
|
158
|
+
|
|
131
159
|
return value;
|
|
132
160
|
}
|
|
133
161
|
function getCSSFromStyleObject(styles) {
|
|
134
162
|
let css = '';
|
|
163
|
+
|
|
135
164
|
for (const style in styles) {
|
|
136
165
|
if (style) {
|
|
137
166
|
css += `${style}: ${styles[style]};`;
|
|
138
167
|
}
|
|
139
168
|
}
|
|
169
|
+
|
|
140
170
|
return css;
|
|
141
171
|
}
|
|
142
172
|
|
|
@@ -147,6 +177,7 @@ function getCSSFromStyleObject(styles) {
|
|
|
147
177
|
* LICENSE file in the root directory of this source tree.
|
|
148
178
|
*
|
|
149
179
|
*/
|
|
180
|
+
|
|
150
181
|
function $updateElementNodeProperties(target, source) {
|
|
151
182
|
target.__first = source.__first;
|
|
152
183
|
target.__last = source.__last;
|
|
@@ -156,6 +187,7 @@ function $updateElementNodeProperties(target, source) {
|
|
|
156
187
|
target.__dir = source.__dir;
|
|
157
188
|
return target;
|
|
158
189
|
}
|
|
190
|
+
|
|
159
191
|
function $updateTextNodeProperties(target, source) {
|
|
160
192
|
target.__format = source.__format;
|
|
161
193
|
target.__style = source.__style;
|
|
@@ -163,20 +195,24 @@ function $updateTextNodeProperties(target, source) {
|
|
|
163
195
|
target.__detail = source.__detail;
|
|
164
196
|
return target;
|
|
165
197
|
}
|
|
198
|
+
|
|
166
199
|
function $cloneWithProperties(node) {
|
|
167
200
|
const latest = node.getLatest();
|
|
168
|
-
const constructor = latest.constructor;
|
|
169
|
-
|
|
201
|
+
const constructor = latest.constructor; // @ts-expect-error
|
|
202
|
+
|
|
170
203
|
const clone = constructor.clone(latest);
|
|
171
204
|
clone.__parent = latest.__parent;
|
|
172
205
|
clone.__next = latest.__next;
|
|
173
206
|
clone.__prev = latest.__prev;
|
|
207
|
+
|
|
174
208
|
if (lexical.$isElementNode(latest) && lexical.$isElementNode(clone)) {
|
|
175
209
|
return $updateElementNodeProperties(clone, latest);
|
|
176
210
|
}
|
|
211
|
+
|
|
177
212
|
if (lexical.$isTextNode(latest) && lexical.$isTextNode(clone)) {
|
|
178
213
|
return $updateTextNodeProperties(clone, latest);
|
|
179
214
|
}
|
|
215
|
+
|
|
180
216
|
return clone;
|
|
181
217
|
}
|
|
182
218
|
function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
@@ -185,6 +221,7 @@ function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
|
185
221
|
const focusNode = selection.focus.getNode();
|
|
186
222
|
const isAnchor = textNode.is(anchorNode);
|
|
187
223
|
const isFocus = textNode.is(focusNode);
|
|
224
|
+
|
|
188
225
|
if (isAnchor || isFocus) {
|
|
189
226
|
const isBackward = selection.isBackward();
|
|
190
227
|
const [anchorOffset, focusOffset] = selection.getCharacterOffsets();
|
|
@@ -193,6 +230,7 @@ function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
|
193
230
|
const isLast = textNode.is(isBackward ? anchorNode : focusNode);
|
|
194
231
|
let startOffset = 0;
|
|
195
232
|
let endOffset = undefined;
|
|
233
|
+
|
|
196
234
|
if (isSame) {
|
|
197
235
|
startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
198
236
|
endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
@@ -205,44 +243,56 @@ function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
|
205
243
|
startOffset = 0;
|
|
206
244
|
endOffset = offset;
|
|
207
245
|
}
|
|
246
|
+
|
|
208
247
|
textNode.__text = textNode.__text.slice(startOffset, endOffset);
|
|
209
248
|
return textNode;
|
|
210
249
|
}
|
|
211
250
|
}
|
|
251
|
+
|
|
212
252
|
return textNode;
|
|
213
253
|
}
|
|
214
254
|
function $isAtNodeEnd(point) {
|
|
215
255
|
if (point.type === 'text') {
|
|
216
256
|
return point.offset === point.getNode().getTextContentSize();
|
|
217
257
|
}
|
|
258
|
+
|
|
218
259
|
return point.offset === point.getNode().getChildrenSize();
|
|
219
260
|
}
|
|
220
261
|
function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
221
262
|
// Work from the current selection anchor point
|
|
222
263
|
let currentNode = anchor.getNode();
|
|
223
264
|
let remaining = delCount;
|
|
265
|
+
|
|
224
266
|
if (lexical.$isElementNode(currentNode)) {
|
|
225
267
|
const descendantNode = currentNode.getDescendantByIndex(anchor.offset);
|
|
268
|
+
|
|
226
269
|
if (descendantNode !== null) {
|
|
227
270
|
currentNode = descendantNode;
|
|
228
271
|
}
|
|
229
272
|
}
|
|
273
|
+
|
|
230
274
|
while (remaining > 0 && currentNode !== null) {
|
|
231
275
|
let nextNode = currentNode.getPreviousSibling();
|
|
232
276
|
let additionalElementWhitespace = 0;
|
|
277
|
+
|
|
233
278
|
if (nextNode === null) {
|
|
234
279
|
let parent = currentNode.getParentOrThrow();
|
|
235
280
|
let parentSibling = parent.getPreviousSibling();
|
|
281
|
+
|
|
236
282
|
while (parentSibling === null) {
|
|
237
283
|
parent = parent.getParent();
|
|
284
|
+
|
|
238
285
|
if (parent === null) {
|
|
239
286
|
nextNode = null;
|
|
240
287
|
break;
|
|
241
288
|
}
|
|
289
|
+
|
|
242
290
|
parentSibling = parent.getPreviousSibling();
|
|
243
291
|
}
|
|
292
|
+
|
|
244
293
|
if (parent !== null) {
|
|
245
294
|
additionalElementWhitespace = parent.isInline() ? 0 : 2;
|
|
295
|
+
|
|
246
296
|
if (lexical.$isElementNode(parentSibling)) {
|
|
247
297
|
nextNode = parentSibling.getLastDescendant();
|
|
248
298
|
} else {
|
|
@@ -250,37 +300,46 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
250
300
|
}
|
|
251
301
|
}
|
|
252
302
|
}
|
|
253
|
-
|
|
254
|
-
// If the text is empty, we need to consider adding in two line breaks to match
|
|
303
|
+
|
|
304
|
+
let text = currentNode.getTextContent(); // If the text is empty, we need to consider adding in two line breaks to match
|
|
255
305
|
// the content if we were to get it from its parent.
|
|
306
|
+
|
|
256
307
|
if (text === '' && lexical.$isElementNode(currentNode) && !currentNode.isInline()) {
|
|
257
308
|
// TODO: should this be handled in core?
|
|
258
309
|
text = '\n\n';
|
|
259
310
|
}
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
if (!lexical.$isTextNode(currentNode) || remaining >=
|
|
311
|
+
|
|
312
|
+
const currentNodeSize = currentNode.getTextContentSize();
|
|
313
|
+
|
|
314
|
+
if (!lexical.$isTextNode(currentNode) || remaining >= currentNodeSize) {
|
|
264
315
|
const parent = currentNode.getParent();
|
|
265
316
|
currentNode.remove();
|
|
266
|
-
|
|
317
|
+
|
|
318
|
+
if (parent != null && parent.getChildrenSize() === 0 && !lexical.$isRootNode(parent)) {
|
|
267
319
|
parent.remove();
|
|
268
320
|
}
|
|
269
|
-
|
|
321
|
+
|
|
322
|
+
remaining -= currentNodeSize + additionalElementWhitespace;
|
|
270
323
|
currentNode = nextNode;
|
|
271
324
|
} else {
|
|
272
|
-
const key = currentNode.getKey();
|
|
273
|
-
|
|
325
|
+
const key = currentNode.getKey(); // See if we can just revert it to what was in the last editor state
|
|
326
|
+
|
|
274
327
|
const prevTextContent = editor.getEditorState().read(() => {
|
|
275
328
|
const prevNode = lexical.$getNodeByKey(key);
|
|
329
|
+
|
|
276
330
|
if (lexical.$isTextNode(prevNode) && prevNode.isSimpleText()) {
|
|
277
331
|
return prevNode.getTextContent();
|
|
278
332
|
}
|
|
333
|
+
|
|
279
334
|
return null;
|
|
280
335
|
});
|
|
336
|
+
const offset = currentNodeSize - remaining;
|
|
337
|
+
const slicedText = text.slice(0, offset);
|
|
338
|
+
|
|
281
339
|
if (prevTextContent !== null && prevTextContent !== text) {
|
|
282
340
|
const prevSelection = lexical.$getPreviousSelection();
|
|
283
341
|
let target = currentNode;
|
|
342
|
+
|
|
284
343
|
if (!currentNode.isSimpleText()) {
|
|
285
344
|
const textNode = lexical.$createTextNode(prevTextContent);
|
|
286
345
|
currentNode.replace(textNode);
|
|
@@ -288,6 +347,7 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
288
347
|
} else {
|
|
289
348
|
currentNode.setTextContent(prevTextContent);
|
|
290
349
|
}
|
|
350
|
+
|
|
291
351
|
if (lexical.$isRangeSelection(prevSelection) && prevSelection.isCollapsed()) {
|
|
292
352
|
const prevOffset = prevSelection.anchor.offset;
|
|
293
353
|
target.select(prevOffset, prevOffset);
|
|
@@ -295,14 +355,16 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
295
355
|
} else if (currentNode.isSimpleText()) {
|
|
296
356
|
// Split text
|
|
297
357
|
const isSelected = anchor.key === key;
|
|
298
|
-
let anchorOffset = anchor.offset;
|
|
299
|
-
// Move offset to end if it's less than the remaniing number, otherwise
|
|
358
|
+
let anchorOffset = anchor.offset; // Move offset to end if it's less than the remaining number, otherwise
|
|
300
359
|
// we'll have a negative splitStart.
|
|
360
|
+
|
|
301
361
|
if (anchorOffset < remaining) {
|
|
302
|
-
anchorOffset =
|
|
362
|
+
anchorOffset = currentNodeSize;
|
|
303
363
|
}
|
|
364
|
+
|
|
304
365
|
const splitStart = isSelected ? anchorOffset - remaining : 0;
|
|
305
366
|
const splitEnd = isSelected ? anchorOffset : offset;
|
|
367
|
+
|
|
306
368
|
if (isSelected && splitStart === 0) {
|
|
307
369
|
const [excessNode] = currentNode.splitText(splitStart, splitEnd);
|
|
308
370
|
excessNode.remove();
|
|
@@ -314,6 +376,7 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
314
376
|
const textNode = lexical.$createTextNode(slicedText);
|
|
315
377
|
currentNode.replace(textNode);
|
|
316
378
|
}
|
|
379
|
+
|
|
317
380
|
remaining = 0;
|
|
318
381
|
}
|
|
319
382
|
}
|
|
@@ -323,6 +386,7 @@ function $addNodeStyle(node) {
|
|
|
323
386
|
const styles = getStyleObjectFromRawCSS(CSSText);
|
|
324
387
|
CSS_TO_STYLES.set(CSSText, styles);
|
|
325
388
|
}
|
|
389
|
+
|
|
326
390
|
function $patchStyle(target, patch) {
|
|
327
391
|
const prevStyles = getStyleObjectFromCSS('getStyle' in target ? target.getStyle() : target.style);
|
|
328
392
|
const newStyles = Object.entries(patch).reduce((styles, [key, value]) => {
|
|
@@ -331,24 +395,27 @@ function $patchStyle(target, patch) {
|
|
|
331
395
|
} else {
|
|
332
396
|
styles[key] = value;
|
|
333
397
|
}
|
|
398
|
+
|
|
334
399
|
return styles;
|
|
335
|
-
}, {
|
|
336
|
-
...prevStyles
|
|
400
|
+
}, { ...prevStyles
|
|
337
401
|
} || {});
|
|
338
402
|
const newCSSText = getCSSFromStyleObject(newStyles);
|
|
339
403
|
target.setStyle(newCSSText);
|
|
340
404
|
CSS_TO_STYLES.set(newCSSText, newStyles);
|
|
341
405
|
}
|
|
406
|
+
|
|
342
407
|
function $patchStyleText(selection, patch) {
|
|
343
408
|
const selectedNodes = selection.getNodes();
|
|
344
409
|
const selectedNodesLength = selectedNodes.length;
|
|
345
410
|
const lastIndex = selectedNodesLength - 1;
|
|
346
411
|
let firstNode = selectedNodes[0];
|
|
347
412
|
let lastNode = selectedNodes[lastIndex];
|
|
413
|
+
|
|
348
414
|
if (selection.isCollapsed()) {
|
|
349
415
|
$patchStyle(selection, patch);
|
|
350
416
|
return;
|
|
351
417
|
}
|
|
418
|
+
|
|
352
419
|
const anchor = selection.anchor;
|
|
353
420
|
const focus = selection.focus;
|
|
354
421
|
const firstNodeText = firstNode.getTextContent();
|
|
@@ -360,32 +427,31 @@ function $patchStyleText(selection, patch) {
|
|
|
360
427
|
let endOffset = isBefore ? focusOffset : anchorOffset;
|
|
361
428
|
const startType = isBefore ? anchor.type : focus.type;
|
|
362
429
|
const endType = isBefore ? focus.type : anchor.type;
|
|
363
|
-
const endKey = isBefore ? focus.key : anchor.key;
|
|
364
|
-
|
|
365
|
-
// This is the case where the user only selected the very end of the
|
|
430
|
+
const endKey = isBefore ? focus.key : anchor.key; // This is the case where the user only selected the very end of the
|
|
366
431
|
// first node so we don't want to include it in the formatting change.
|
|
432
|
+
|
|
367
433
|
if (lexical.$isTextNode(firstNode) && startOffset === firstNodeTextLength) {
|
|
368
434
|
const nextSibling = firstNode.getNextSibling();
|
|
435
|
+
|
|
369
436
|
if (lexical.$isTextNode(nextSibling)) {
|
|
370
437
|
// we basically make the second node the firstNode, changing offsets accordingly
|
|
371
438
|
anchorOffset = 0;
|
|
372
439
|
startOffset = 0;
|
|
373
440
|
firstNode = nextSibling;
|
|
374
441
|
}
|
|
375
|
-
}
|
|
442
|
+
} // This is the case where we only selected a single node
|
|
376
443
|
|
|
377
|
-
|
|
378
|
-
if (
|
|
444
|
+
|
|
445
|
+
if (selectedNodes.length === 1) {
|
|
379
446
|
if (lexical.$isTextNode(firstNode)) {
|
|
380
447
|
startOffset = startType === 'element' ? 0 : anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
381
|
-
endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
448
|
+
endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset; // No actual text is selected, so do nothing.
|
|
382
449
|
|
|
383
|
-
// No actual text is selected, so do nothing.
|
|
384
450
|
if (startOffset === endOffset) {
|
|
385
451
|
return;
|
|
386
|
-
}
|
|
452
|
+
} // The entire node is selected, so just format it
|
|
453
|
+
|
|
387
454
|
|
|
388
|
-
// The entire node is selected, so just format it
|
|
389
455
|
if (startOffset === 0 && endOffset === firstNodeTextLength) {
|
|
390
456
|
$patchStyle(firstNode, patch);
|
|
391
457
|
firstNode.select(startOffset, endOffset);
|
|
@@ -398,6 +464,7 @@ function $patchStyleText(selection, patch) {
|
|
|
398
464
|
replacement.select(0, endOffset - startOffset);
|
|
399
465
|
}
|
|
400
466
|
} // multiple nodes selected.
|
|
467
|
+
|
|
401
468
|
} else {
|
|
402
469
|
if (lexical.$isTextNode(firstNode) && startOffset < firstNode.getTextContentSize()) {
|
|
403
470
|
if (startOffset !== 0) {
|
|
@@ -405,33 +472,36 @@ function $patchStyleText(selection, patch) {
|
|
|
405
472
|
firstNode = firstNode.splitText(startOffset)[1];
|
|
406
473
|
startOffset = 0;
|
|
407
474
|
}
|
|
475
|
+
|
|
408
476
|
$patchStyle(firstNode, patch);
|
|
409
477
|
}
|
|
478
|
+
|
|
410
479
|
if (lexical.$isTextNode(lastNode)) {
|
|
411
480
|
const lastNodeText = lastNode.getTextContent();
|
|
412
|
-
const lastNodeTextLength = lastNodeText.length;
|
|
413
|
-
|
|
414
|
-
// The last node might not actually be the end node
|
|
481
|
+
const lastNodeTextLength = lastNodeText.length; // The last node might not actually be the end node
|
|
415
482
|
//
|
|
416
483
|
// If not, assume the last node is fully-selected unless the end offset is
|
|
417
484
|
// zero.
|
|
485
|
+
|
|
418
486
|
if (lastNode.__key !== endKey && endOffset !== 0) {
|
|
419
487
|
endOffset = lastNodeTextLength;
|
|
420
|
-
}
|
|
488
|
+
} // if the entire last node isn't selected, split it
|
|
489
|
+
|
|
421
490
|
|
|
422
|
-
// if the entire last node isn't selected, split it
|
|
423
491
|
if (endOffset !== lastNodeTextLength) {
|
|
424
492
|
[lastNode] = lastNode.splitText(endOffset);
|
|
425
493
|
}
|
|
494
|
+
|
|
426
495
|
if (endOffset !== 0) {
|
|
427
496
|
$patchStyle(lastNode, patch);
|
|
428
497
|
}
|
|
429
|
-
}
|
|
498
|
+
} // style all the text nodes in between
|
|
499
|
+
|
|
430
500
|
|
|
431
|
-
// style all the text nodes in between
|
|
432
501
|
for (let i = 1; i < lastIndex; i++) {
|
|
433
502
|
const selectedNode = selectedNodes[i];
|
|
434
503
|
const selectedNodeKey = selectedNode.getKey();
|
|
504
|
+
|
|
435
505
|
if (lexical.$isTextNode(selectedNode) && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {
|
|
436
506
|
$patchStyle(selectedNode, patch);
|
|
437
507
|
}
|
|
@@ -446,7 +516,6 @@ function $patchStyleText(selection, patch) {
|
|
|
446
516
|
* LICENSE file in the root directory of this source tree.
|
|
447
517
|
*
|
|
448
518
|
*/
|
|
449
|
-
|
|
450
519
|
/**
|
|
451
520
|
* Converts all nodes in the selection that are of one block type to another specified by parameter
|
|
452
521
|
*
|
|
@@ -454,50 +523,87 @@ function $patchStyleText(selection, patch) {
|
|
|
454
523
|
* @param createElement
|
|
455
524
|
* @returns
|
|
456
525
|
*/
|
|
457
|
-
|
|
526
|
+
|
|
527
|
+
function $setBlocksType(selection, createElement) {
|
|
458
528
|
if (selection.anchor.key === 'root') {
|
|
459
529
|
const element = createElement();
|
|
460
530
|
const root = lexical.$getRoot();
|
|
461
531
|
const firstChild = root.getFirstChild();
|
|
462
|
-
|
|
532
|
+
|
|
533
|
+
if (firstChild) {
|
|
534
|
+
firstChild.replace(element, true);
|
|
535
|
+
} else {
|
|
536
|
+
root.append(element);
|
|
537
|
+
}
|
|
538
|
+
|
|
463
539
|
return;
|
|
464
540
|
}
|
|
541
|
+
|
|
465
542
|
const nodes = selection.getNodes();
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
543
|
+
let maybeBlock = selection.anchor.getNode().getParentOrThrow();
|
|
544
|
+
|
|
545
|
+
if (nodes.indexOf(maybeBlock) === -1) {
|
|
546
|
+
nodes.push(maybeBlock);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (maybeBlock.isInline()) {
|
|
550
|
+
maybeBlock = maybeBlock.getParentOrThrow();
|
|
551
|
+
|
|
552
|
+
if (nodes.indexOf(maybeBlock) === -1) {
|
|
553
|
+
nodes.push(maybeBlock);
|
|
554
|
+
}
|
|
470
555
|
}
|
|
556
|
+
|
|
471
557
|
for (let i = 0; i < nodes.length; i++) {
|
|
472
558
|
const node = nodes[i];
|
|
473
|
-
|
|
559
|
+
|
|
560
|
+
if (!isBlock(node)) {
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
|
|
474
564
|
const targetElement = createElement();
|
|
475
565
|
targetElement.setFormat(node.getFormatType());
|
|
476
566
|
targetElement.setIndent(node.getIndent());
|
|
477
567
|
node.replace(targetElement, true);
|
|
478
568
|
}
|
|
479
569
|
}
|
|
570
|
+
|
|
480
571
|
function isBlock(node) {
|
|
481
|
-
|
|
572
|
+
if (!lexical.$isElementNode(node) || lexical.$isRootOrShadowRoot(node)) {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const firstChild = node.getFirstChild();
|
|
577
|
+
const isLeafElement = firstChild === null || lexical.$isTextNode(firstChild) || firstChild.isInline();
|
|
578
|
+
return !node.isInline() && node.canBeEmpty() !== false && isLeafElement;
|
|
482
579
|
}
|
|
580
|
+
|
|
483
581
|
function isPointAttached(point) {
|
|
484
582
|
return point.getNode().isAttached();
|
|
485
583
|
}
|
|
584
|
+
|
|
486
585
|
function $removeParentEmptyElements(startingNode) {
|
|
487
586
|
let node = startingNode;
|
|
587
|
+
|
|
488
588
|
while (node !== null && !lexical.$isRootOrShadowRoot(node)) {
|
|
489
589
|
const latest = node.getLatest();
|
|
490
590
|
const parentNode = node.getParent();
|
|
591
|
+
|
|
491
592
|
if (latest.getChildrenSize() === 0) {
|
|
492
593
|
node.remove(true);
|
|
493
594
|
}
|
|
595
|
+
|
|
494
596
|
node = parentNode;
|
|
495
597
|
}
|
|
496
598
|
}
|
|
599
|
+
/** @deprecated */
|
|
600
|
+
|
|
601
|
+
|
|
497
602
|
function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
498
603
|
const nodes = selection.getNodes();
|
|
499
604
|
const nodesLength = nodes.length;
|
|
500
605
|
const anchor = selection.anchor;
|
|
606
|
+
|
|
501
607
|
if (nodesLength === 0 || nodesLength === 1 && anchor.type === 'element' && anchor.getNode().getChildrenSize() === 0) {
|
|
502
608
|
const target = anchor.type === 'text' ? anchor.getNode().getParentOrThrow() : anchor.getNode();
|
|
503
609
|
const children = target.getChildren();
|
|
@@ -505,20 +611,24 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
505
611
|
element.setFormat(target.getFormatType());
|
|
506
612
|
element.setIndent(target.getIndent());
|
|
507
613
|
children.forEach(child => element.append(child));
|
|
614
|
+
|
|
508
615
|
if (wrappingElement) {
|
|
509
616
|
element = wrappingElement.append(element);
|
|
510
617
|
}
|
|
618
|
+
|
|
511
619
|
target.replace(element);
|
|
512
620
|
return;
|
|
513
621
|
}
|
|
622
|
+
|
|
514
623
|
let topLevelNode = null;
|
|
515
624
|
let descendants = [];
|
|
625
|
+
|
|
516
626
|
for (let i = 0; i < nodesLength; i++) {
|
|
517
|
-
const node = nodes[i];
|
|
518
|
-
// Determine whether wrapping has to be broken down into multiple chunks. This can happen if the
|
|
627
|
+
const node = nodes[i]; // Determine whether wrapping has to be broken down into multiple chunks. This can happen if the
|
|
519
628
|
// user selected multiple Root-like nodes that have to be treated separately as if they are
|
|
520
629
|
// their own branch. I.e. you don't want to wrap a whole table, but rather the contents of each
|
|
521
630
|
// of each of the cell nodes.
|
|
631
|
+
|
|
522
632
|
if (lexical.$isRootOrShadowRoot(node)) {
|
|
523
633
|
$wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);
|
|
524
634
|
descendants = [];
|
|
@@ -530,69 +640,82 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
530
640
|
descendants = [node];
|
|
531
641
|
}
|
|
532
642
|
}
|
|
643
|
+
|
|
533
644
|
$wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);
|
|
534
645
|
}
|
|
535
646
|
function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingElement = null) {
|
|
536
647
|
if (nodes.length === 0) {
|
|
537
648
|
return;
|
|
538
649
|
}
|
|
650
|
+
|
|
539
651
|
const firstNode = nodes[0];
|
|
540
652
|
const elementMapping = new Map();
|
|
541
|
-
const elements = [];
|
|
542
|
-
// The below logic is to find the right target for us to
|
|
653
|
+
const elements = []; // The below logic is to find the right target for us to
|
|
543
654
|
// either insertAfter/insertBefore/append the corresponding
|
|
544
655
|
// elements to. This is made more complicated due to nested
|
|
545
656
|
// structures.
|
|
657
|
+
|
|
546
658
|
let target = lexical.$isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
|
|
659
|
+
|
|
547
660
|
if (target.isInline()) {
|
|
548
661
|
target = target.getParentOrThrow();
|
|
549
662
|
}
|
|
663
|
+
|
|
550
664
|
let targetIsPrevSibling = false;
|
|
665
|
+
|
|
551
666
|
while (target !== null) {
|
|
552
667
|
const prevSibling = target.getPreviousSibling();
|
|
668
|
+
|
|
553
669
|
if (prevSibling !== null) {
|
|
554
670
|
target = prevSibling;
|
|
555
671
|
targetIsPrevSibling = true;
|
|
556
672
|
break;
|
|
557
673
|
}
|
|
674
|
+
|
|
558
675
|
target = target.getParentOrThrow();
|
|
676
|
+
|
|
559
677
|
if (lexical.$isRootOrShadowRoot(target)) {
|
|
560
678
|
break;
|
|
561
679
|
}
|
|
562
680
|
}
|
|
563
|
-
const emptyElements = new Set();
|
|
564
681
|
|
|
565
|
-
// Find any top level empty elements
|
|
682
|
+
const emptyElements = new Set(); // Find any top level empty elements
|
|
683
|
+
|
|
566
684
|
for (let i = 0; i < nodesLength; i++) {
|
|
567
685
|
const node = nodes[i];
|
|
686
|
+
|
|
568
687
|
if (lexical.$isElementNode(node) && node.getChildrenSize() === 0) {
|
|
569
688
|
emptyElements.add(node.getKey());
|
|
570
689
|
}
|
|
571
690
|
}
|
|
572
|
-
const movedNodes = new Set();
|
|
573
691
|
|
|
574
|
-
// Move out all leaf nodes into our elements array.
|
|
692
|
+
const movedNodes = new Set(); // Move out all leaf nodes into our elements array.
|
|
575
693
|
// If we find a top level empty element, also move make
|
|
576
694
|
// an element for that.
|
|
695
|
+
|
|
577
696
|
for (let i = 0; i < nodesLength; i++) {
|
|
578
697
|
const node = nodes[i];
|
|
579
698
|
let parent = node.getParent();
|
|
699
|
+
|
|
580
700
|
if (parent !== null && parent.isInline()) {
|
|
581
701
|
parent = parent.getParent();
|
|
582
702
|
}
|
|
703
|
+
|
|
583
704
|
if (parent !== null && lexical.$isLeafNode(node) && !movedNodes.has(node.getKey())) {
|
|
584
705
|
const parentKey = parent.getKey();
|
|
706
|
+
|
|
585
707
|
if (elementMapping.get(parentKey) === undefined) {
|
|
586
708
|
const targetElement = createElement();
|
|
587
709
|
targetElement.setFormat(parent.getFormatType());
|
|
588
710
|
targetElement.setIndent(parent.getIndent());
|
|
589
711
|
elements.push(targetElement);
|
|
590
|
-
elementMapping.set(parentKey, targetElement);
|
|
591
|
-
// Move node and its siblings to the new
|
|
712
|
+
elementMapping.set(parentKey, targetElement); // Move node and its siblings to the new
|
|
592
713
|
// element.
|
|
714
|
+
|
|
593
715
|
parent.getChildren().forEach(child => {
|
|
594
716
|
targetElement.append(child);
|
|
595
717
|
movedNodes.add(child.getKey());
|
|
718
|
+
|
|
596
719
|
if (lexical.$isElementNode(child)) {
|
|
597
720
|
// Skip nested leaf nodes if the parent has already been moved
|
|
598
721
|
child.getChildrenKeys().forEach(key => movedNodes.add(key));
|
|
@@ -608,16 +731,17 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
608
731
|
node.remove(true);
|
|
609
732
|
}
|
|
610
733
|
}
|
|
734
|
+
|
|
611
735
|
if (wrappingElement !== null) {
|
|
612
736
|
for (let i = 0; i < elements.length; i++) {
|
|
613
737
|
const element = elements[i];
|
|
614
738
|
wrappingElement.append(element);
|
|
615
739
|
}
|
|
616
740
|
}
|
|
617
|
-
let lastElement = null;
|
|
618
741
|
|
|
619
|
-
// If our target is Root-like, let's see if we can re-adjust
|
|
742
|
+
let lastElement = null; // If our target is Root-like, let's see if we can re-adjust
|
|
620
743
|
// so that the target is the first child instead.
|
|
744
|
+
|
|
621
745
|
if (lexical.$isRootOrShadowRoot(target)) {
|
|
622
746
|
if (targetIsPrevSibling) {
|
|
623
747
|
if (wrappingElement !== null) {
|
|
@@ -630,9 +754,11 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
630
754
|
}
|
|
631
755
|
} else {
|
|
632
756
|
const firstChild = target.getFirstChild();
|
|
757
|
+
|
|
633
758
|
if (lexical.$isElementNode(firstChild)) {
|
|
634
759
|
target = firstChild;
|
|
635
760
|
}
|
|
761
|
+
|
|
636
762
|
if (firstChild === null) {
|
|
637
763
|
if (wrappingElement) {
|
|
638
764
|
target.append(wrappingElement);
|
|
@@ -666,7 +792,9 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
666
792
|
}
|
|
667
793
|
}
|
|
668
794
|
}
|
|
795
|
+
|
|
669
796
|
const prevSelection = lexical.$getPreviousSelection();
|
|
797
|
+
|
|
670
798
|
if (lexical.$isRangeSelection(prevSelection) && isPointAttached(prevSelection.anchor) && isPointAttached(prevSelection.focus)) {
|
|
671
799
|
lexical.$setSelection(prevSelection.clone());
|
|
672
800
|
} else if (lastElement !== null) {
|
|
@@ -702,30 +830,37 @@ function $selectAll(selection) {
|
|
|
702
830
|
let firstType = 'element';
|
|
703
831
|
let lastType = 'element';
|
|
704
832
|
let lastOffset = 0;
|
|
833
|
+
|
|
705
834
|
if (lexical.$isTextNode(firstNode)) {
|
|
706
835
|
firstType = 'text';
|
|
707
836
|
} else if (!lexical.$isElementNode(firstNode) && firstNode !== null) {
|
|
708
837
|
firstNode = firstNode.getParentOrThrow();
|
|
709
838
|
}
|
|
839
|
+
|
|
710
840
|
if (lexical.$isTextNode(lastNode)) {
|
|
711
841
|
lastType = 'text';
|
|
712
842
|
lastOffset = lastNode.getTextContentSize();
|
|
713
843
|
} else if (!lexical.$isElementNode(lastNode) && lastNode !== null) {
|
|
714
844
|
lastNode = lastNode.getParentOrThrow();
|
|
715
845
|
}
|
|
846
|
+
|
|
716
847
|
if (firstNode && lastNode) {
|
|
717
848
|
anchor.set(firstNode.getKey(), 0, firstType);
|
|
718
849
|
focus.set(lastNode.getKey(), lastOffset, lastType);
|
|
719
850
|
}
|
|
720
851
|
}
|
|
852
|
+
|
|
721
853
|
function $getNodeStyleValueForProperty(node, styleProperty, defaultValue) {
|
|
722
854
|
const css = node.getStyle();
|
|
723
855
|
const styleObject = getStyleObjectFromCSS(css);
|
|
856
|
+
|
|
724
857
|
if (styleObject !== null) {
|
|
725
858
|
return styleObject[styleProperty] || defaultValue;
|
|
726
859
|
}
|
|
860
|
+
|
|
727
861
|
return defaultValue;
|
|
728
862
|
}
|
|
863
|
+
|
|
729
864
|
function $getSelectionStyleValueForProperty(selection, styleProperty, defaultValue = '') {
|
|
730
865
|
let styleValue = null;
|
|
731
866
|
const nodes = selection.getNodes();
|
|
@@ -734,24 +869,28 @@ function $getSelectionStyleValueForProperty(selection, styleProperty, defaultVal
|
|
|
734
869
|
const isBackward = selection.isBackward();
|
|
735
870
|
const endOffset = isBackward ? focus.offset : anchor.offset;
|
|
736
871
|
const endNode = isBackward ? focus.getNode() : anchor.getNode();
|
|
872
|
+
|
|
737
873
|
if (selection.style !== '') {
|
|
738
874
|
const css = selection.style;
|
|
739
875
|
const styleObject = getStyleObjectFromCSS(css);
|
|
876
|
+
|
|
740
877
|
if (styleObject !== null && styleProperty in styleObject) {
|
|
741
878
|
return styleObject[styleProperty];
|
|
742
879
|
}
|
|
743
880
|
}
|
|
744
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
745
|
-
const node = nodes[i];
|
|
746
881
|
|
|
747
|
-
|
|
882
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
883
|
+
const node = nodes[i]; // if no actual characters in the end node are selected, we don't
|
|
748
884
|
// include it in the selection for purposes of determining style
|
|
749
885
|
// value
|
|
886
|
+
|
|
750
887
|
if (i !== 0 && endOffset === 0 && node.is(endNode)) {
|
|
751
888
|
continue;
|
|
752
889
|
}
|
|
890
|
+
|
|
753
891
|
if (lexical.$isTextNode(node)) {
|
|
754
892
|
const nodeStyleValue = $getNodeStyleValueForProperty(node, styleProperty, defaultValue);
|
|
893
|
+
|
|
755
894
|
if (styleValue === null) {
|
|
756
895
|
styleValue = nodeStyleValue;
|
|
757
896
|
} else if (styleValue !== nodeStyleValue) {
|
|
@@ -762,6 +901,7 @@ function $getSelectionStyleValueForProperty(selection, styleProperty, defaultVal
|
|
|
762
901
|
}
|
|
763
902
|
}
|
|
764
903
|
}
|
|
904
|
+
|
|
765
905
|
return styleValue === null ? defaultValue : styleValue;
|
|
766
906
|
}
|
|
767
907
|
|
|
@@ -774,7 +914,7 @@ exports.$moveCaretSelection = $moveCaretSelection;
|
|
|
774
914
|
exports.$moveCharacter = $moveCharacter;
|
|
775
915
|
exports.$patchStyleText = $patchStyleText;
|
|
776
916
|
exports.$selectAll = $selectAll;
|
|
777
|
-
exports.$
|
|
917
|
+
exports.$setBlocksType = $setBlocksType;
|
|
778
918
|
exports.$shouldOverrideDefaultCharacterSelection = $shouldOverrideDefaultCharacterSelection;
|
|
779
919
|
exports.$sliceSelectedTextNodeContent = $sliceSelectedTextNodeContent;
|
|
780
920
|
exports.$wrapNodes = $wrapNodes;
|
package/LexicalSelection.js.flow
CHANGED
|
@@ -49,7 +49,7 @@ declare export function $wrapNodes(
|
|
|
49
49
|
createElement: () => ElementNode,
|
|
50
50
|
wrappingElement?: ElementNode,
|
|
51
51
|
): void;
|
|
52
|
-
declare export function $
|
|
52
|
+
declare export function $setBlocksType(
|
|
53
53
|
selection: RangeSelection,
|
|
54
54
|
createElement: () => ElementNode,
|
|
55
55
|
): void;
|
package/LexicalSelection.prod.js
CHANGED
|
@@ -4,25 +4,25 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
'use strict';var
|
|
8
|
-
function A(a){let b="";for(let c in a)c&&(b+=`${c}: ${a[c]};`);return b}function B(a,b){var c=z("getStyle"in a?a.getStyle():a.style);b=Object.entries(b).reduce((
|
|
9
|
-
function D(a,b,c,
|
|
10
|
-
r&&
|
|
11
|
-
d)
|
|
12
|
-
null!==b?b.selectEnd():a.dirty=!0}}function E(a,b,c,
|
|
13
|
-
exports.$cloneWithProperties=function(a){a=a.getLatest();let b=a.constructor.clone(a);b.__parent=a.__parent;b.__next=a.__next;b.__prev=a.__prev;if(
|
|
14
|
-
exports.$getSelectionStyleValueForProperty=function(a,b,c=""){let
|
|
15
|
-
exports.$isAtNodeEnd=function(a){return"text"===a.type?a.offset===a.getNode().getTextContentSize():a.offset===a.getNode().getChildrenSize()};exports.$isParentElementRTL=F;exports.$moveCaretSelection=E;exports.$moveCharacter=function(a,b,c){let
|
|
16
|
-
exports.$patchStyleText=function(a,b){var c=a.getNodes();let
|
|
17
|
-
a),c=0===
|
|
18
|
-
exports.$selectAll=function(a){let b=a.anchor;a=a.focus;var c=b.getNode().getTopLevelElementOrThrow().getParentOrThrow();let
|
|
19
|
-
exports.$
|
|
20
|
-
exports.$shouldOverrideDefaultCharacterSelection=function(a,b){a=
|
|
21
|
-
exports.$sliceSelectedTextNodeContent=function(a,b){if(b.isSelected()&&!b.isSegmented()&&!b.isToken()&&(
|
|
22
|
-
exports.$wrapNodes=function(a,b,c=null){var
|
|
23
|
-
|
|
24
|
-
exports.createDOMRange=function(a,b,c,
|
|
25
|
-
c));return g};exports.createRectsFromDOMRange=function(a,b){var c=a.getRootElement();if(null===c)return[];a=c.getBoundingClientRect();c=getComputedStyle(c);c=parseFloat(c.paddingLeft)+parseFloat(c.paddingRight);b=Array.from(b.getClientRects());let
|
|
26
|
-
exports.trimTextContentFromAnchor=function(a,b,c){let
|
|
27
|
-
d=
|
|
28
|
-
(e=b.key===
|
|
7
|
+
'use strict';var k=require("lexical");let u=new Map;function v(a){for(;null!=a;){if(a.nodeType===Node.TEXT_NODE)return a;a=a.firstChild}return null}function w(a){let b=a.parentNode;if(null==b)throw Error("Should never happen");return[b,Array.from(b.childNodes).indexOf(a)]}function y(a){let b={};a=a.split(";");for(let c of a)if(""!==c){let [e,d]=c.split(/:([^]+)/);b[e.trim()]=d.trim()}return b}function z(a){let b=u.get(a);void 0===b&&(b=y(a),u.set(a,b));return b}
|
|
8
|
+
function A(a){let b="";for(let c in a)c&&(b+=`${c}: ${a[c]};`);return b}function B(a,b){var c=z("getStyle"in a?a.getStyle():a.style);b=Object.entries(b).reduce((e,[d,f])=>{null===f?delete e[d]:e[d]=f;return e},{...c});c=A(b);a.setStyle(c);u.set(c,b)}function C(a){for(;null!==a&&!k.$isRootOrShadowRoot(a);){let b=a.getLatest(),c=a.getParent();0===b.getChildrenSize()&&a.remove(!0);a=c}}
|
|
9
|
+
function D(a,b,c,e,d=null){if(0!==b.length){var f=b[0],h=new Map,g=[];f=k.$isElementNode(f)?f:f.getParentOrThrow();f.isInline()&&(f=f.getParentOrThrow());for(var l=!1;null!==f;){var m=f.getPreviousSibling();if(null!==m){f=m;l=!0;break}f=f.getParentOrThrow();if(k.$isRootOrShadowRoot(f))break}m=new Set;for(var q=0;q<c;q++){var p=b[q];k.$isElementNode(p)&&0===p.getChildrenSize()&&m.add(p.getKey())}var n=new Set;for(q=0;q<c;q++){p=b[q];var r=p.getParent();null!==r&&r.isInline()&&(r=r.getParent());if(null!==
|
|
10
|
+
r&&k.$isLeafNode(p)&&!n.has(p.getKey())){if(p=r.getKey(),void 0===h.get(p)){let t=e();t.setFormat(r.getFormatType());t.setIndent(r.getIndent());g.push(t);h.set(p,t);r.getChildren().forEach(x=>{t.append(x);n.add(x.getKey());k.$isElementNode(x)&&x.getChildrenKeys().forEach(G=>n.add(G))});C(r)}}else m.has(p.getKey())&&(r=e(),r.setFormat(p.getFormatType()),r.setIndent(p.getIndent()),g.push(r),p.remove(!0))}if(null!==d)for(b=0;b<g.length;b++)d.append(g[b]);b=null;if(k.$isRootOrShadowRoot(f))if(l)if(null!==
|
|
11
|
+
d)f.insertAfter(d);else for(d=g.length-1;0<=d;d--)f.insertAfter(g[d]);else if(l=f.getFirstChild(),k.$isElementNode(l)&&(f=l),null===l)if(d)f.append(d);else for(d=0;d<g.length;d++)l=g[d],f.append(l),b=l;else if(null!==d)l.insertBefore(d);else for(f=0;f<g.length;f++)d=g[f],l.insertBefore(d),b=d;else if(d)f.insertAfter(d);else for(d=g.length-1;0<=d;d--)l=g[d],f.insertAfter(l),b=l;g=k.$getPreviousSelection();k.$isRangeSelection(g)&&g.anchor.getNode().isAttached()&&g.focus.getNode().isAttached()?k.$setSelection(g.clone()):
|
|
12
|
+
null!==b?b.selectEnd():a.dirty=!0}}function E(a,b,c,e){a.modify(b?"extend":"move",c,e)}function F(a){a=a.anchor.getNode();return"rtl"===(k.$isRootNode(a)?a:a.getParentOrThrow()).getDirection()}exports.$addNodeStyle=function(a){a=a.getStyle();let b=y(a);u.set(a,b)};
|
|
13
|
+
exports.$cloneWithProperties=function(a){a=a.getLatest();let b=a.constructor.clone(a);b.__parent=a.__parent;b.__next=a.__next;b.__prev=a.__prev;if(k.$isElementNode(a)&&k.$isElementNode(b))return b.__first=a.__first,b.__last=a.__last,b.__size=a.__size,b.__format=a.__format,b.__indent=a.__indent,b.__dir=a.__dir,b;k.$isTextNode(a)&&k.$isTextNode(b)&&(b.__format=a.__format,b.__style=a.__style,b.__mode=a.__mode,b.__detail=a.__detail);return b};
|
|
14
|
+
exports.$getSelectionStyleValueForProperty=function(a,b,c=""){let e=null,d=a.getNodes();var f=a.anchor,h=a.focus,g=a.isBackward();let l=g?h.offset:f.offset;f=g?h.getNode():f.getNode();if(""!==a.style&&(a=z(a.style),null!==a&&b in a))return a[b];for(a=0;a<d.length;a++){var m=d[a];if((0===a||0!==l||!m.is(f))&&k.$isTextNode(m))if(h=b,g=c,m=m.getStyle(),m=z(m),h=null!==m?m[h]||g:g,null===e)e=h;else if(e!==h){e="";break}}return null===e?c:e};
|
|
15
|
+
exports.$isAtNodeEnd=function(a){return"text"===a.type?a.offset===a.getNode().getTextContentSize():a.offset===a.getNode().getChildrenSize()};exports.$isParentElementRTL=F;exports.$moveCaretSelection=E;exports.$moveCharacter=function(a,b,c){let e=F(a);E(a,b,c?!e:e,"character")};
|
|
16
|
+
exports.$patchStyleText=function(a,b){var c=a.getNodes();let e=c.length-1,d=c[0],f=c[e];if(a.isCollapsed())B(a,b);else{var h=a.anchor,g=a.focus,l=d.getTextContent().length,m=g.offset,q=h.offset,p=h.isBefore(g),n=p?q:m;a=p?m:q;var r=p?h.type:g.type,t=p?g.type:h.type;h=p?g.key:h.key;k.$isTextNode(d)&&n===l&&(g=d.getNextSibling(),k.$isTextNode(g)&&(n=q=0,d=g));if(1===c.length)k.$isTextNode(d)&&(n="element"===r?0:q>m?m:q,a="element"===t?l:q>m?q:m,n!==a&&(0===n&&a===l?(B(d,b),d.select(n,a)):(c=d.splitText(n,
|
|
17
|
+
a),c=0===n?c[0]:c[1],B(c,b),c.select(0,a-n))));else for(k.$isTextNode(d)&&n<d.getTextContentSize()&&(0!==n&&(d=d.splitText(n)[1]),B(d,b)),k.$isTextNode(f)&&(n=f.getTextContent().length,f.__key!==h&&0!==a&&(a=n),a!==n&&([f]=f.splitText(a)),0!==a&&B(f,b)),a=1;a<e;a++)n=c[a],l=n.getKey(),k.$isTextNode(n)&&l!==d.getKey()&&l!==f.getKey()&&!n.isToken()&&B(n,b)}};
|
|
18
|
+
exports.$selectAll=function(a){let b=a.anchor;a=a.focus;var c=b.getNode().getTopLevelElementOrThrow().getParentOrThrow();let e=c.getFirstDescendant();c=c.getLastDescendant();let d="element",f="element",h=0;k.$isTextNode(e)?d="text":k.$isElementNode(e)||null===e||(e=e.getParentOrThrow());k.$isTextNode(c)?(f="text",h=c.getTextContentSize()):k.$isElementNode(c)||null===c||(c=c.getParentOrThrow());e&&c&&(b.set(e.getKey(),0,d),a.set(c.getKey(),h,f))};
|
|
19
|
+
exports.$setBlocksType=function(a,b){if("root"===a.anchor.key){b=b();var c=k.$getRoot();(a=c.getFirstChild())?a.replace(b,!0):c.append(b)}else for(c=a.getNodes(),a=a.anchor.getNode().getParentOrThrow(),-1===c.indexOf(a)&&c.push(a),a.isInline()&&(a=a.getParentOrThrow(),-1===c.indexOf(a)&&c.push(a)),a=0;a<c.length;a++){let f=c[a];var e=f;if(!k.$isElementNode(e)||k.$isRootOrShadowRoot(e))e=!1;else{var d=e.getFirstChild();d=null===d||k.$isTextNode(d)||d.isInline();e=!e.isInline()&&!1!==e.canBeEmpty()&&
|
|
20
|
+
d}e&&(e=b(),e.setFormat(f.getFormatType()),e.setIndent(f.getIndent()),f.replace(e,!0))}};exports.$shouldOverrideDefaultCharacterSelection=function(a,b){a=k.$getAdjacentNode(a.focus,b);return k.$isDecoratorNode(a)&&!a.isIsolated()||k.$isElementNode(a)&&!a.isInline()&&!a.canBeEmpty()};
|
|
21
|
+
exports.$sliceSelectedTextNodeContent=function(a,b){if(b.isSelected()&&!b.isSegmented()&&!b.isToken()&&(k.$isRangeSelection(a)||k.DEPRECATED_$isGridSelection(a))){var c=a.anchor.getNode(),e=a.focus.getNode(),d=b.is(c),f=b.is(e);if(d||f){d=a.isBackward();let [h,g]=a.getCharacterOffsets();a=c.is(e);f=b.is(d?e:c);e=b.is(d?c:e);c=0;let l=void 0;a?(c=h>g?g:h,l=h>g?h:g):f?(c=d?g:h,l=void 0):e&&(d=d?h:g,c=0,l=d);b.__text=b.__text.slice(c,l)}}return b};
|
|
22
|
+
exports.$wrapNodes=function(a,b,c=null){var e=a.getNodes();let d=e.length;var f=a.anchor;if(0===d||1===d&&"element"===f.type&&0===f.getNode().getChildrenSize()){a="text"===f.type?f.getNode().getParentOrThrow():f.getNode();e=a.getChildren();let g=b();g.setFormat(a.getFormatType());g.setIndent(a.getIndent());e.forEach(l=>g.append(l));c&&(g=c.append(g));a.replace(g)}else{f=null;var h=[];for(let g=0;g<d;g++){let l=e[g];k.$isRootOrShadowRoot(l)?(D(a,h,h.length,b,c),h=[],f=l):null===f||null!==f&&k.$hasAncestor(l,
|
|
23
|
+
f)?h.push(l):(D(a,h,h.length,b,c),h=[l])}D(a,h,h.length,b,c)}};
|
|
24
|
+
exports.createDOMRange=function(a,b,c,e,d){let f=b.getKey(),h=e.getKey(),g=document.createRange(),l=a.getElementByKey(f);a=a.getElementByKey(h);k.$isTextNode(b)&&(l=v(l));k.$isTextNode(e)&&(a=v(a));if(void 0===b||void 0===e||null===l||null===a)return null;"BR"===l.nodeName&&([l,c]=w(l));"BR"===a.nodeName&&([a,d]=w(a));b=l.firstChild;l===a&&null!=b&&"BR"===b.nodeName&&0===c&&0===d&&(d=1);try{g.setStart(l,c),g.setEnd(a,d)}catch(m){return null}!g.collapsed||c===d&&f===h||(g.setStart(a,d),g.setEnd(l,
|
|
25
|
+
c));return g};exports.createRectsFromDOMRange=function(a,b){var c=a.getRootElement();if(null===c)return[];a=c.getBoundingClientRect();c=getComputedStyle(c);c=parseFloat(c.paddingLeft)+parseFloat(c.paddingRight);b=Array.from(b.getClientRects());let e=b.length,d;for(let f=0;f<e;f++){let h=b[f],g=h.width+c===a.width;d&&d.top===h.top&&d.left===h.left&&d.width===h.width&&d.height===h.height||g?(b.splice(f--,1),e--):d=h}return b};exports.getStyleObjectFromCSS=z;
|
|
26
|
+
exports.trimTextContentFromAnchor=function(a,b,c){let e=b.getNode();if(k.$isElementNode(e)){var d=e.getDescendantByIndex(b.offset);null!==d&&(e=d)}for(;0<c&&null!==e;){var f=e.getPreviousSibling(),h=0;if(null===f){d=e.getParentOrThrow();for(var g=d.getPreviousSibling();null===g;){d=d.getParent();if(null===d){f=null;break}g=d.getPreviousSibling()}null!==d&&(h=d.isInline()?0:2,f=k.$isElementNode(g)?g.getLastDescendant():g)}g=e.getTextContent();""===g&&k.$isElementNode(e)&&!e.isInline()&&(g="\n\n");
|
|
27
|
+
d=e.getTextContentSize();if(!k.$isTextNode(e)||c>=d)g=e.getParent(),e.remove(),null==g||0!==g.getChildrenSize()||k.$isRootNode(g)||g.remove(),c-=d+h,e=f;else{let l=e.getKey();h=a.getEditorState().read(()=>{const q=k.$getNodeByKey(l);return k.$isTextNode(q)&&q.isSimpleText()?q.getTextContent():null});f=d-c;let m=g.slice(0,f);null!==h&&h!==g?(c=k.$getPreviousSelection(),d=e,e.isSimpleText()?e.setTextContent(h):(d=k.$createTextNode(h),e.replace(d)),k.$isRangeSelection(c)&&c.isCollapsed()&&(c=c.anchor.offset,
|
|
28
|
+
d.select(c,c))):e.isSimpleText()?(h=b.key===l,g=b.offset,g<c&&(g=d),c=h?g-c:0,d=h?g:f,h&&0===c?([c]=e.splitText(c,d),c.remove()):([,c]=e.splitText(c,d),c.remove())):(c=k.$createTextNode(m),e.replace(c));c=0}}}
|
package/README.md
CHANGED
|
@@ -81,12 +81,12 @@ Expands the current Selection to cover all of the content in the editor.
|
|
|
81
81
|
export function $selectAll(selection: RangeSelection): void;
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
#### `$
|
|
84
|
+
#### `$setBlocksType`
|
|
85
85
|
|
|
86
86
|
Converts all nodes in the selection that are of one block type to another specified by parameter
|
|
87
87
|
|
|
88
88
|
```ts
|
|
89
|
-
export function $
|
|
89
|
+
export function $setBlocksType(
|
|
90
90
|
selection: RangeSelection,
|
|
91
91
|
createElement: () => ElementNode,
|
|
92
92
|
): void;
|
package/index.d.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
import { $addNodeStyle, $cloneWithProperties, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, trimTextContentFromAnchor } from './lexical-node';
|
|
10
|
-
import { $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $selectAll, $
|
|
10
|
+
import { $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $selectAll, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $wrapNodes } from './range-selection';
|
|
11
11
|
import { createDOMRange, createRectsFromDOMRange, getStyleObjectFromCSS } from './utils';
|
|
12
12
|
export { $addNodeStyle, $cloneWithProperties, $isAtNodeEnd, $patchStyleText, $sliceSelectedTextNodeContent, trimTextContentFromAnchor, };
|
|
13
|
-
export { $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $selectAll, $
|
|
13
|
+
export { $getSelectionStyleValueForProperty, $isParentElementRTL, $moveCaretSelection, $moveCharacter, $selectAll, $setBlocksType, $shouldOverrideDefaultCharacterSelection, $wrapNodes, };
|
|
14
14
|
export { createDOMRange, createRectsFromDOMRange, getStyleObjectFromCSS };
|
package/package.json
CHANGED
package/range-selection.d.ts
CHANGED
|
@@ -13,7 +13,8 @@ import type { ElementNode, GridSelection, LexicalNode, RangeSelection } from 'le
|
|
|
13
13
|
* @param createElement
|
|
14
14
|
* @returns
|
|
15
15
|
*/
|
|
16
|
-
export declare function $
|
|
16
|
+
export declare function $setBlocksType(selection: RangeSelection | GridSelection, createElement: () => ElementNode): void;
|
|
17
|
+
/** @deprecated */
|
|
17
18
|
export declare function $wrapNodes(selection: RangeSelection | GridSelection, createElement: () => ElementNode, wrappingElement?: null | ElementNode): void;
|
|
18
19
|
export declare function $wrapNodesImpl(selection: RangeSelection | GridSelection, nodes: LexicalNode[], nodesLength: number, createElement: () => ElementNode, wrappingElement?: null | ElementNode): void;
|
|
19
20
|
export declare function $shouldOverrideDefaultCharacterSelection(selection: RangeSelection, isBackward: boolean): boolean;
|