@lexical/selection 0.8.0 → 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 +215 -93
- 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,40 +386,36 @@ function $addNodeStyle(node) {
|
|
|
323
386
|
const styles = getStyleObjectFromRawCSS(CSSText);
|
|
324
387
|
CSS_TO_STYLES.set(CSSText, styles);
|
|
325
388
|
}
|
|
326
|
-
|
|
327
|
-
|
|
389
|
+
|
|
390
|
+
function $patchStyle(target, patch) {
|
|
391
|
+
const prevStyles = getStyleObjectFromCSS('getStyle' in target ? target.getStyle() : target.style);
|
|
328
392
|
const newStyles = Object.entries(patch).reduce((styles, [key, value]) => {
|
|
329
393
|
if (value === null) {
|
|
330
394
|
delete styles[key];
|
|
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
|
-
|
|
350
|
-
Object.entries(patch).forEach(([key, value]) => {
|
|
351
|
-
if (value !== null) {
|
|
352
|
-
styles[key] = value;
|
|
353
|
-
}
|
|
354
|
-
return styles;
|
|
355
|
-
});
|
|
356
|
-
const style = getCSSFromStyleObject(styles);
|
|
357
|
-
selection.setStyle(style);
|
|
415
|
+
$patchStyle(selection, patch);
|
|
358
416
|
return;
|
|
359
417
|
}
|
|
418
|
+
|
|
360
419
|
const anchor = selection.anchor;
|
|
361
420
|
const focus = selection.focus;
|
|
362
421
|
const firstNodeText = firstNode.getTextContent();
|
|
@@ -368,44 +427,44 @@ function $patchStyleText(selection, patch) {
|
|
|
368
427
|
let endOffset = isBefore ? focusOffset : anchorOffset;
|
|
369
428
|
const startType = isBefore ? anchor.type : focus.type;
|
|
370
429
|
const endType = isBefore ? focus.type : anchor.type;
|
|
371
|
-
const endKey = isBefore ? focus.key : anchor.key;
|
|
372
|
-
|
|
373
|
-
// 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
|
|
374
431
|
// first node so we don't want to include it in the formatting change.
|
|
432
|
+
|
|
375
433
|
if (lexical.$isTextNode(firstNode) && startOffset === firstNodeTextLength) {
|
|
376
434
|
const nextSibling = firstNode.getNextSibling();
|
|
435
|
+
|
|
377
436
|
if (lexical.$isTextNode(nextSibling)) {
|
|
378
437
|
// we basically make the second node the firstNode, changing offsets accordingly
|
|
379
438
|
anchorOffset = 0;
|
|
380
439
|
startOffset = 0;
|
|
381
440
|
firstNode = nextSibling;
|
|
382
441
|
}
|
|
383
|
-
}
|
|
442
|
+
} // This is the case where we only selected a single node
|
|
384
443
|
|
|
385
|
-
|
|
386
|
-
if (
|
|
444
|
+
|
|
445
|
+
if (selectedNodes.length === 1) {
|
|
387
446
|
if (lexical.$isTextNode(firstNode)) {
|
|
388
447
|
startOffset = startType === 'element' ? 0 : anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
389
|
-
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.
|
|
390
449
|
|
|
391
|
-
// No actual text is selected, so do nothing.
|
|
392
450
|
if (startOffset === endOffset) {
|
|
393
451
|
return;
|
|
394
|
-
}
|
|
452
|
+
} // The entire node is selected, so just format it
|
|
453
|
+
|
|
395
454
|
|
|
396
|
-
// The entire node is selected, so just format it
|
|
397
455
|
if (startOffset === 0 && endOffset === firstNodeTextLength) {
|
|
398
|
-
$
|
|
456
|
+
$patchStyle(firstNode, patch);
|
|
399
457
|
firstNode.select(startOffset, endOffset);
|
|
400
458
|
} else {
|
|
401
459
|
// The node is partially selected, so split it into two nodes
|
|
402
460
|
// and style the selected one.
|
|
403
461
|
const splitNodes = firstNode.splitText(startOffset, endOffset);
|
|
404
462
|
const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];
|
|
405
|
-
$
|
|
463
|
+
$patchStyle(replacement, patch);
|
|
406
464
|
replacement.select(0, endOffset - startOffset);
|
|
407
465
|
}
|
|
408
466
|
} // multiple nodes selected.
|
|
467
|
+
|
|
409
468
|
} else {
|
|
410
469
|
if (lexical.$isTextNode(firstNode) && startOffset < firstNode.getTextContentSize()) {
|
|
411
470
|
if (startOffset !== 0) {
|
|
@@ -413,35 +472,38 @@ function $patchStyleText(selection, patch) {
|
|
|
413
472
|
firstNode = firstNode.splitText(startOffset)[1];
|
|
414
473
|
startOffset = 0;
|
|
415
474
|
}
|
|
416
|
-
|
|
475
|
+
|
|
476
|
+
$patchStyle(firstNode, patch);
|
|
417
477
|
}
|
|
478
|
+
|
|
418
479
|
if (lexical.$isTextNode(lastNode)) {
|
|
419
480
|
const lastNodeText = lastNode.getTextContent();
|
|
420
|
-
const lastNodeTextLength = lastNodeText.length;
|
|
421
|
-
|
|
422
|
-
// 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
|
|
423
482
|
//
|
|
424
483
|
// If not, assume the last node is fully-selected unless the end offset is
|
|
425
484
|
// zero.
|
|
485
|
+
|
|
426
486
|
if (lastNode.__key !== endKey && endOffset !== 0) {
|
|
427
487
|
endOffset = lastNodeTextLength;
|
|
428
|
-
}
|
|
488
|
+
} // if the entire last node isn't selected, split it
|
|
489
|
+
|
|
429
490
|
|
|
430
|
-
// if the entire last node isn't selected, split it
|
|
431
491
|
if (endOffset !== lastNodeTextLength) {
|
|
432
492
|
[lastNode] = lastNode.splitText(endOffset);
|
|
433
493
|
}
|
|
494
|
+
|
|
434
495
|
if (endOffset !== 0) {
|
|
435
|
-
$
|
|
496
|
+
$patchStyle(lastNode, patch);
|
|
436
497
|
}
|
|
437
|
-
}
|
|
498
|
+
} // style all the text nodes in between
|
|
499
|
+
|
|
438
500
|
|
|
439
|
-
// style all the text nodes in between
|
|
440
501
|
for (let i = 1; i < lastIndex; i++) {
|
|
441
502
|
const selectedNode = selectedNodes[i];
|
|
442
503
|
const selectedNodeKey = selectedNode.getKey();
|
|
504
|
+
|
|
443
505
|
if (lexical.$isTextNode(selectedNode) && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {
|
|
444
|
-
$
|
|
506
|
+
$patchStyle(selectedNode, patch);
|
|
445
507
|
}
|
|
446
508
|
}
|
|
447
509
|
}
|
|
@@ -454,7 +516,6 @@ function $patchStyleText(selection, patch) {
|
|
|
454
516
|
* LICENSE file in the root directory of this source tree.
|
|
455
517
|
*
|
|
456
518
|
*/
|
|
457
|
-
|
|
458
519
|
/**
|
|
459
520
|
* Converts all nodes in the selection that are of one block type to another specified by parameter
|
|
460
521
|
*
|
|
@@ -462,50 +523,87 @@ function $patchStyleText(selection, patch) {
|
|
|
462
523
|
* @param createElement
|
|
463
524
|
* @returns
|
|
464
525
|
*/
|
|
465
|
-
|
|
526
|
+
|
|
527
|
+
function $setBlocksType(selection, createElement) {
|
|
466
528
|
if (selection.anchor.key === 'root') {
|
|
467
529
|
const element = createElement();
|
|
468
530
|
const root = lexical.$getRoot();
|
|
469
531
|
const firstChild = root.getFirstChild();
|
|
470
|
-
|
|
532
|
+
|
|
533
|
+
if (firstChild) {
|
|
534
|
+
firstChild.replace(element, true);
|
|
535
|
+
} else {
|
|
536
|
+
root.append(element);
|
|
537
|
+
}
|
|
538
|
+
|
|
471
539
|
return;
|
|
472
540
|
}
|
|
541
|
+
|
|
473
542
|
const nodes = selection.getNodes();
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
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
|
+
}
|
|
478
555
|
}
|
|
556
|
+
|
|
479
557
|
for (let i = 0; i < nodes.length; i++) {
|
|
480
558
|
const node = nodes[i];
|
|
481
|
-
|
|
559
|
+
|
|
560
|
+
if (!isBlock(node)) {
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
|
|
482
564
|
const targetElement = createElement();
|
|
483
565
|
targetElement.setFormat(node.getFormatType());
|
|
484
566
|
targetElement.setIndent(node.getIndent());
|
|
485
567
|
node.replace(targetElement, true);
|
|
486
568
|
}
|
|
487
569
|
}
|
|
570
|
+
|
|
488
571
|
function isBlock(node) {
|
|
489
|
-
|
|
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;
|
|
490
579
|
}
|
|
580
|
+
|
|
491
581
|
function isPointAttached(point) {
|
|
492
582
|
return point.getNode().isAttached();
|
|
493
583
|
}
|
|
584
|
+
|
|
494
585
|
function $removeParentEmptyElements(startingNode) {
|
|
495
586
|
let node = startingNode;
|
|
587
|
+
|
|
496
588
|
while (node !== null && !lexical.$isRootOrShadowRoot(node)) {
|
|
497
589
|
const latest = node.getLatest();
|
|
498
590
|
const parentNode = node.getParent();
|
|
591
|
+
|
|
499
592
|
if (latest.getChildrenSize() === 0) {
|
|
500
593
|
node.remove(true);
|
|
501
594
|
}
|
|
595
|
+
|
|
502
596
|
node = parentNode;
|
|
503
597
|
}
|
|
504
598
|
}
|
|
599
|
+
/** @deprecated */
|
|
600
|
+
|
|
601
|
+
|
|
505
602
|
function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
506
603
|
const nodes = selection.getNodes();
|
|
507
604
|
const nodesLength = nodes.length;
|
|
508
605
|
const anchor = selection.anchor;
|
|
606
|
+
|
|
509
607
|
if (nodesLength === 0 || nodesLength === 1 && anchor.type === 'element' && anchor.getNode().getChildrenSize() === 0) {
|
|
510
608
|
const target = anchor.type === 'text' ? anchor.getNode().getParentOrThrow() : anchor.getNode();
|
|
511
609
|
const children = target.getChildren();
|
|
@@ -513,20 +611,24 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
513
611
|
element.setFormat(target.getFormatType());
|
|
514
612
|
element.setIndent(target.getIndent());
|
|
515
613
|
children.forEach(child => element.append(child));
|
|
614
|
+
|
|
516
615
|
if (wrappingElement) {
|
|
517
616
|
element = wrappingElement.append(element);
|
|
518
617
|
}
|
|
618
|
+
|
|
519
619
|
target.replace(element);
|
|
520
620
|
return;
|
|
521
621
|
}
|
|
622
|
+
|
|
522
623
|
let topLevelNode = null;
|
|
523
624
|
let descendants = [];
|
|
625
|
+
|
|
524
626
|
for (let i = 0; i < nodesLength; i++) {
|
|
525
|
-
const node = nodes[i];
|
|
526
|
-
// 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
|
|
527
628
|
// user selected multiple Root-like nodes that have to be treated separately as if they are
|
|
528
629
|
// their own branch. I.e. you don't want to wrap a whole table, but rather the contents of each
|
|
529
630
|
// of each of the cell nodes.
|
|
631
|
+
|
|
530
632
|
if (lexical.$isRootOrShadowRoot(node)) {
|
|
531
633
|
$wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);
|
|
532
634
|
descendants = [];
|
|
@@ -538,69 +640,82 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
538
640
|
descendants = [node];
|
|
539
641
|
}
|
|
540
642
|
}
|
|
643
|
+
|
|
541
644
|
$wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);
|
|
542
645
|
}
|
|
543
646
|
function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingElement = null) {
|
|
544
647
|
if (nodes.length === 0) {
|
|
545
648
|
return;
|
|
546
649
|
}
|
|
650
|
+
|
|
547
651
|
const firstNode = nodes[0];
|
|
548
652
|
const elementMapping = new Map();
|
|
549
|
-
const elements = [];
|
|
550
|
-
// 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
|
|
551
654
|
// either insertAfter/insertBefore/append the corresponding
|
|
552
655
|
// elements to. This is made more complicated due to nested
|
|
553
656
|
// structures.
|
|
657
|
+
|
|
554
658
|
let target = lexical.$isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
|
|
659
|
+
|
|
555
660
|
if (target.isInline()) {
|
|
556
661
|
target = target.getParentOrThrow();
|
|
557
662
|
}
|
|
663
|
+
|
|
558
664
|
let targetIsPrevSibling = false;
|
|
665
|
+
|
|
559
666
|
while (target !== null) {
|
|
560
667
|
const prevSibling = target.getPreviousSibling();
|
|
668
|
+
|
|
561
669
|
if (prevSibling !== null) {
|
|
562
670
|
target = prevSibling;
|
|
563
671
|
targetIsPrevSibling = true;
|
|
564
672
|
break;
|
|
565
673
|
}
|
|
674
|
+
|
|
566
675
|
target = target.getParentOrThrow();
|
|
676
|
+
|
|
567
677
|
if (lexical.$isRootOrShadowRoot(target)) {
|
|
568
678
|
break;
|
|
569
679
|
}
|
|
570
680
|
}
|
|
571
|
-
const emptyElements = new Set();
|
|
572
681
|
|
|
573
|
-
// Find any top level empty elements
|
|
682
|
+
const emptyElements = new Set(); // Find any top level empty elements
|
|
683
|
+
|
|
574
684
|
for (let i = 0; i < nodesLength; i++) {
|
|
575
685
|
const node = nodes[i];
|
|
686
|
+
|
|
576
687
|
if (lexical.$isElementNode(node) && node.getChildrenSize() === 0) {
|
|
577
688
|
emptyElements.add(node.getKey());
|
|
578
689
|
}
|
|
579
690
|
}
|
|
580
|
-
const movedNodes = new Set();
|
|
581
691
|
|
|
582
|
-
// Move out all leaf nodes into our elements array.
|
|
692
|
+
const movedNodes = new Set(); // Move out all leaf nodes into our elements array.
|
|
583
693
|
// If we find a top level empty element, also move make
|
|
584
694
|
// an element for that.
|
|
695
|
+
|
|
585
696
|
for (let i = 0; i < nodesLength; i++) {
|
|
586
697
|
const node = nodes[i];
|
|
587
698
|
let parent = node.getParent();
|
|
699
|
+
|
|
588
700
|
if (parent !== null && parent.isInline()) {
|
|
589
701
|
parent = parent.getParent();
|
|
590
702
|
}
|
|
703
|
+
|
|
591
704
|
if (parent !== null && lexical.$isLeafNode(node) && !movedNodes.has(node.getKey())) {
|
|
592
705
|
const parentKey = parent.getKey();
|
|
706
|
+
|
|
593
707
|
if (elementMapping.get(parentKey) === undefined) {
|
|
594
708
|
const targetElement = createElement();
|
|
595
709
|
targetElement.setFormat(parent.getFormatType());
|
|
596
710
|
targetElement.setIndent(parent.getIndent());
|
|
597
711
|
elements.push(targetElement);
|
|
598
|
-
elementMapping.set(parentKey, targetElement);
|
|
599
|
-
// Move node and its siblings to the new
|
|
712
|
+
elementMapping.set(parentKey, targetElement); // Move node and its siblings to the new
|
|
600
713
|
// element.
|
|
714
|
+
|
|
601
715
|
parent.getChildren().forEach(child => {
|
|
602
716
|
targetElement.append(child);
|
|
603
717
|
movedNodes.add(child.getKey());
|
|
718
|
+
|
|
604
719
|
if (lexical.$isElementNode(child)) {
|
|
605
720
|
// Skip nested leaf nodes if the parent has already been moved
|
|
606
721
|
child.getChildrenKeys().forEach(key => movedNodes.add(key));
|
|
@@ -616,16 +731,17 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
616
731
|
node.remove(true);
|
|
617
732
|
}
|
|
618
733
|
}
|
|
734
|
+
|
|
619
735
|
if (wrappingElement !== null) {
|
|
620
736
|
for (let i = 0; i < elements.length; i++) {
|
|
621
737
|
const element = elements[i];
|
|
622
738
|
wrappingElement.append(element);
|
|
623
739
|
}
|
|
624
740
|
}
|
|
625
|
-
let lastElement = null;
|
|
626
741
|
|
|
627
|
-
// 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
|
|
628
743
|
// so that the target is the first child instead.
|
|
744
|
+
|
|
629
745
|
if (lexical.$isRootOrShadowRoot(target)) {
|
|
630
746
|
if (targetIsPrevSibling) {
|
|
631
747
|
if (wrappingElement !== null) {
|
|
@@ -638,9 +754,11 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
638
754
|
}
|
|
639
755
|
} else {
|
|
640
756
|
const firstChild = target.getFirstChild();
|
|
757
|
+
|
|
641
758
|
if (lexical.$isElementNode(firstChild)) {
|
|
642
759
|
target = firstChild;
|
|
643
760
|
}
|
|
761
|
+
|
|
644
762
|
if (firstChild === null) {
|
|
645
763
|
if (wrappingElement) {
|
|
646
764
|
target.append(wrappingElement);
|
|
@@ -674,7 +792,9 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
674
792
|
}
|
|
675
793
|
}
|
|
676
794
|
}
|
|
795
|
+
|
|
677
796
|
const prevSelection = lexical.$getPreviousSelection();
|
|
797
|
+
|
|
678
798
|
if (lexical.$isRangeSelection(prevSelection) && isPointAttached(prevSelection.anchor) && isPointAttached(prevSelection.focus)) {
|
|
679
799
|
lexical.$setSelection(prevSelection.clone());
|
|
680
800
|
} else if (lastElement !== null) {
|
|
@@ -710,30 +830,37 @@ function $selectAll(selection) {
|
|
|
710
830
|
let firstType = 'element';
|
|
711
831
|
let lastType = 'element';
|
|
712
832
|
let lastOffset = 0;
|
|
833
|
+
|
|
713
834
|
if (lexical.$isTextNode(firstNode)) {
|
|
714
835
|
firstType = 'text';
|
|
715
836
|
} else if (!lexical.$isElementNode(firstNode) && firstNode !== null) {
|
|
716
837
|
firstNode = firstNode.getParentOrThrow();
|
|
717
838
|
}
|
|
839
|
+
|
|
718
840
|
if (lexical.$isTextNode(lastNode)) {
|
|
719
841
|
lastType = 'text';
|
|
720
842
|
lastOffset = lastNode.getTextContentSize();
|
|
721
843
|
} else if (!lexical.$isElementNode(lastNode) && lastNode !== null) {
|
|
722
844
|
lastNode = lastNode.getParentOrThrow();
|
|
723
845
|
}
|
|
846
|
+
|
|
724
847
|
if (firstNode && lastNode) {
|
|
725
848
|
anchor.set(firstNode.getKey(), 0, firstType);
|
|
726
849
|
focus.set(lastNode.getKey(), lastOffset, lastType);
|
|
727
850
|
}
|
|
728
851
|
}
|
|
852
|
+
|
|
729
853
|
function $getNodeStyleValueForProperty(node, styleProperty, defaultValue) {
|
|
730
854
|
const css = node.getStyle();
|
|
731
855
|
const styleObject = getStyleObjectFromCSS(css);
|
|
856
|
+
|
|
732
857
|
if (styleObject !== null) {
|
|
733
858
|
return styleObject[styleProperty] || defaultValue;
|
|
734
859
|
}
|
|
860
|
+
|
|
735
861
|
return defaultValue;
|
|
736
862
|
}
|
|
863
|
+
|
|
737
864
|
function $getSelectionStyleValueForProperty(selection, styleProperty, defaultValue = '') {
|
|
738
865
|
let styleValue = null;
|
|
739
866
|
const nodes = selection.getNodes();
|
|
@@ -742,44 +869,39 @@ function $getSelectionStyleValueForProperty(selection, styleProperty, defaultVal
|
|
|
742
869
|
const isBackward = selection.isBackward();
|
|
743
870
|
const endOffset = isBackward ? focus.offset : anchor.offset;
|
|
744
871
|
const endNode = isBackward ? focus.getNode() : anchor.getNode();
|
|
872
|
+
|
|
745
873
|
if (selection.style !== '') {
|
|
746
874
|
const css = selection.style;
|
|
747
875
|
const styleObject = getStyleObjectFromCSS(css);
|
|
748
|
-
|
|
749
|
-
if (styleObject !== null) {
|
|
750
|
-
|
|
751
|
-
} else {
|
|
752
|
-
nodeStyleValue = defaultValue;
|
|
753
|
-
}
|
|
754
|
-
if (styleValue === null) {
|
|
755
|
-
styleValue = nodeStyleValue;
|
|
756
|
-
} else if (styleValue !== nodeStyleValue) {
|
|
757
|
-
// multiple text nodes are in the selection and they don't all
|
|
758
|
-
// have the same font size.
|
|
759
|
-
styleValue = '';
|
|
876
|
+
|
|
877
|
+
if (styleObject !== null && styleProperty in styleObject) {
|
|
878
|
+
return styleObject[styleProperty];
|
|
760
879
|
}
|
|
761
880
|
}
|
|
762
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
763
|
-
const node = nodes[i];
|
|
764
881
|
|
|
765
|
-
|
|
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
|
|
766
884
|
// include it in the selection for purposes of determining style
|
|
767
885
|
// value
|
|
886
|
+
|
|
768
887
|
if (i !== 0 && endOffset === 0 && node.is(endNode)) {
|
|
769
888
|
continue;
|
|
770
889
|
}
|
|
890
|
+
|
|
771
891
|
if (lexical.$isTextNode(node)) {
|
|
772
892
|
const nodeStyleValue = $getNodeStyleValueForProperty(node, styleProperty, defaultValue);
|
|
893
|
+
|
|
773
894
|
if (styleValue === null) {
|
|
774
895
|
styleValue = nodeStyleValue;
|
|
775
896
|
} else if (styleValue !== nodeStyleValue) {
|
|
776
897
|
// multiple text nodes are in the selection and they don't all
|
|
777
|
-
// have the same
|
|
898
|
+
// have the same style.
|
|
778
899
|
styleValue = '';
|
|
779
900
|
break;
|
|
780
901
|
}
|
|
781
902
|
}
|
|
782
903
|
}
|
|
904
|
+
|
|
783
905
|
return styleValue === null ? defaultValue : styleValue;
|
|
784
906
|
}
|
|
785
907
|
|
|
@@ -792,7 +914,7 @@ exports.$moveCaretSelection = $moveCaretSelection;
|
|
|
792
914
|
exports.$moveCharacter = $moveCharacter;
|
|
793
915
|
exports.$patchStyleText = $patchStyleText;
|
|
794
916
|
exports.$selectAll = $selectAll;
|
|
795
|
-
exports.$
|
|
917
|
+
exports.$setBlocksType = $setBlocksType;
|
|
796
918
|
exports.$shouldOverrideDefaultCharacterSelection = $shouldOverrideDefaultCharacterSelection;
|
|
797
919
|
exports.$sliceSelectedTextNodeContent = $sliceSelectedTextNodeContent;
|
|
798
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
|
|
9
|
-
function
|
|
10
|
-
r&&
|
|
11
|
-
d)f.insertAfter(d);else for(d=g.length-1;0<=d;d--)f.insertAfter(g[d]);else if(
|
|
12
|
-
null!==b?b.selectEnd():a.dirty=!0}}function
|
|
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 e=null,d=a.getNodes();var f=a.anchor,h=a.focus,g=a.isBackward();let
|
|
15
|
-
exports.$isAtNodeEnd=function(a){return"text"===a.type?a.offset===a.getNode().getTextContentSize():a.offset===a.getNode().getChildrenSize()};exports.$isParentElementRTL=
|
|
16
|
-
exports.$patchStyleText=function(a,b){var c=a.getNodes();let e=c.length-1,d=c[0],f=c[e];if(a.isCollapsed())
|
|
17
|
-
|
|
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;
|
|
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 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(
|
|
23
|
-
f)?h.push(
|
|
24
|
-
exports.createDOMRange=function(a,b,c,e,d){let f=b.getKey(),h=e.getKey(),g=document.createRange(),
|
|
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=
|
|
26
|
-
exports.trimTextContentFromAnchor=function(a,b,c){let e=b.getNode();if(
|
|
27
|
-
d=
|
|
28
|
-
(
|
|
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;
|