@lexical/selection 0.12.2 → 0.12.4
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 +106 -223
- package/LexicalSelection.prod.js +23 -23
- package/package.json +2 -2
- package/range-selection.d.ts +7 -1
package/LexicalSelection.dev.js
CHANGED
|
@@ -24,30 +24,24 @@ const CSS_TO_STYLES = new Map();
|
|
|
24
24
|
* LICENSE file in the root directory of this source tree.
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
|
-
|
|
28
27
|
function getDOMTextNode(element) {
|
|
29
28
|
let node = element;
|
|
30
|
-
|
|
31
29
|
while (node != null) {
|
|
32
30
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
33
31
|
return node;
|
|
34
32
|
}
|
|
35
|
-
|
|
36
33
|
node = node.firstChild;
|
|
37
34
|
}
|
|
38
|
-
|
|
39
35
|
return null;
|
|
40
36
|
}
|
|
41
|
-
|
|
42
37
|
function getDOMIndexWithinParent(node) {
|
|
43
38
|
const parent = node.parentNode;
|
|
44
|
-
|
|
45
39
|
if (parent == null) {
|
|
46
40
|
throw new Error('Should never happen');
|
|
47
41
|
}
|
|
48
|
-
|
|
49
42
|
return [parent, Array.from(parent.childNodes).indexOf(node)];
|
|
50
43
|
}
|
|
44
|
+
|
|
51
45
|
/**
|
|
52
46
|
* Creates a selection range for the DOM.
|
|
53
47
|
* @param editor - The lexical editor.
|
|
@@ -57,8 +51,6 @@ function getDOMIndexWithinParent(node) {
|
|
|
57
51
|
* @param _focusOffset - The amount of space offset from the focus to the anchor.
|
|
58
52
|
* @returns The range of selection for the DOM that was created.
|
|
59
53
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
54
|
function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffset) {
|
|
63
55
|
const anchorKey = anchorNode.getKey();
|
|
64
56
|
const focusKey = focusNode.getKey();
|
|
@@ -67,154 +59,129 @@ function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffs
|
|
|
67
59
|
let focusDOM = editor.getElementByKey(focusKey);
|
|
68
60
|
let anchorOffset = _anchorOffset;
|
|
69
61
|
let focusOffset = _focusOffset;
|
|
70
|
-
|
|
71
62
|
if (lexical.$isTextNode(anchorNode)) {
|
|
72
63
|
anchorDOM = getDOMTextNode(anchorDOM);
|
|
73
64
|
}
|
|
74
|
-
|
|
75
65
|
if (lexical.$isTextNode(focusNode)) {
|
|
76
66
|
focusDOM = getDOMTextNode(focusDOM);
|
|
77
67
|
}
|
|
78
|
-
|
|
79
68
|
if (anchorNode === undefined || focusNode === undefined || anchorDOM === null || focusDOM === null) {
|
|
80
69
|
return null;
|
|
81
70
|
}
|
|
82
|
-
|
|
83
71
|
if (anchorDOM.nodeName === 'BR') {
|
|
84
72
|
[anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM);
|
|
85
73
|
}
|
|
86
|
-
|
|
87
74
|
if (focusDOM.nodeName === 'BR') {
|
|
88
75
|
[focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM);
|
|
89
76
|
}
|
|
90
|
-
|
|
91
77
|
const firstChild = anchorDOM.firstChild;
|
|
92
|
-
|
|
93
78
|
if (anchorDOM === focusDOM && firstChild != null && firstChild.nodeName === 'BR' && anchorOffset === 0 && focusOffset === 0) {
|
|
94
79
|
focusOffset = 1;
|
|
95
80
|
}
|
|
96
|
-
|
|
97
81
|
try {
|
|
98
82
|
range.setStart(anchorDOM, anchorOffset);
|
|
99
83
|
range.setEnd(focusDOM, focusOffset);
|
|
100
84
|
} catch (e) {
|
|
101
85
|
return null;
|
|
102
86
|
}
|
|
103
|
-
|
|
104
87
|
if (range.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) {
|
|
105
88
|
// Range is backwards, we need to reverse it
|
|
106
89
|
range.setStart(focusDOM, focusOffset);
|
|
107
90
|
range.setEnd(anchorDOM, anchorOffset);
|
|
108
91
|
}
|
|
109
|
-
|
|
110
92
|
return range;
|
|
111
93
|
}
|
|
94
|
+
|
|
112
95
|
/**
|
|
113
96
|
* Creates DOMRects, generally used to help the editor find a specific location on the screen.
|
|
114
97
|
* @param editor - The lexical editor
|
|
115
98
|
* @param range - A fragment of a document that can contain nodes and parts of text nodes.
|
|
116
99
|
* @returns The selectionRects as an array.
|
|
117
100
|
*/
|
|
118
|
-
|
|
119
101
|
function createRectsFromDOMRange(editor, range) {
|
|
120
102
|
const rootElement = editor.getRootElement();
|
|
121
|
-
|
|
122
103
|
if (rootElement === null) {
|
|
123
104
|
return [];
|
|
124
105
|
}
|
|
125
|
-
|
|
126
106
|
const rootRect = rootElement.getBoundingClientRect();
|
|
127
107
|
const computedStyle = getComputedStyle(rootElement);
|
|
128
108
|
const rootPadding = parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);
|
|
129
109
|
const selectionRects = Array.from(range.getClientRects());
|
|
130
|
-
let selectionRectsLength = selectionRects.length;
|
|
131
|
-
|
|
110
|
+
let selectionRectsLength = selectionRects.length;
|
|
111
|
+
//sort rects from top left to bottom right.
|
|
132
112
|
selectionRects.sort((a, b) => {
|
|
133
|
-
const top = a.top - b.top;
|
|
113
|
+
const top = a.top - b.top;
|
|
114
|
+
// Some rects match position closely, but not perfectly,
|
|
134
115
|
// so we give a 3px tolerance.
|
|
135
|
-
|
|
136
116
|
if (Math.abs(top) <= 3) {
|
|
137
117
|
return a.left - b.left;
|
|
138
118
|
}
|
|
139
|
-
|
|
140
119
|
return top;
|
|
141
120
|
});
|
|
142
121
|
let prevRect;
|
|
143
|
-
|
|
144
122
|
for (let i = 0; i < selectionRectsLength; i++) {
|
|
145
|
-
const selectionRect = selectionRects[i];
|
|
146
|
-
|
|
147
|
-
const isOverlappingRect = prevRect && prevRect.top <= selectionRect.top && prevRect.top + prevRect.height > selectionRect.top && prevRect.left + prevRect.width > selectionRect.left;
|
|
148
|
-
|
|
123
|
+
const selectionRect = selectionRects[i];
|
|
124
|
+
// Exclude rects that overlap preceding Rects in the sorted list.
|
|
125
|
+
const isOverlappingRect = prevRect && prevRect.top <= selectionRect.top && prevRect.top + prevRect.height > selectionRect.top && prevRect.left + prevRect.width > selectionRect.left;
|
|
126
|
+
// Exclude selections that span the entire element
|
|
149
127
|
const selectionSpansElement = selectionRect.width + rootPadding === rootRect.width;
|
|
150
|
-
|
|
151
128
|
if (isOverlappingRect || selectionSpansElement) {
|
|
152
129
|
selectionRects.splice(i--, 1);
|
|
153
130
|
selectionRectsLength--;
|
|
154
131
|
continue;
|
|
155
132
|
}
|
|
156
|
-
|
|
157
133
|
prevRect = selectionRect;
|
|
158
134
|
}
|
|
159
|
-
|
|
160
135
|
return selectionRects;
|
|
161
136
|
}
|
|
137
|
+
|
|
162
138
|
/**
|
|
163
139
|
* Creates an object containing all the styles and their values provided in the CSS string.
|
|
164
140
|
* @param css - The CSS string of styles and their values.
|
|
165
141
|
* @returns The styleObject containing all the styles and their values.
|
|
166
142
|
*/
|
|
167
|
-
|
|
168
143
|
function getStyleObjectFromRawCSS(css) {
|
|
169
144
|
const styleObject = {};
|
|
170
145
|
const styles = css.split(';');
|
|
171
|
-
|
|
172
146
|
for (const style of styles) {
|
|
173
147
|
if (style !== '') {
|
|
174
148
|
const [key, value] = style.split(/:([^]+)/); // split on first colon
|
|
175
|
-
|
|
176
149
|
styleObject[key.trim()] = value.trim();
|
|
177
150
|
}
|
|
178
151
|
}
|
|
179
|
-
|
|
180
152
|
return styleObject;
|
|
181
153
|
}
|
|
154
|
+
|
|
182
155
|
/**
|
|
183
156
|
* Given a CSS string, returns an object from the style cache.
|
|
184
157
|
* @param css - The CSS property as a string.
|
|
185
158
|
* @returns The value of the given CSS property.
|
|
186
159
|
*/
|
|
187
|
-
|
|
188
160
|
function getStyleObjectFromCSS(css) {
|
|
189
161
|
let value = CSS_TO_STYLES.get(css);
|
|
190
|
-
|
|
191
162
|
if (value === undefined) {
|
|
192
163
|
value = getStyleObjectFromRawCSS(css);
|
|
193
164
|
CSS_TO_STYLES.set(css, value);
|
|
194
165
|
}
|
|
195
|
-
|
|
196
166
|
{
|
|
197
167
|
// Freeze the value in DEV to prevent accidental mutations
|
|
198
168
|
Object.freeze(value);
|
|
199
169
|
}
|
|
200
|
-
|
|
201
170
|
return value;
|
|
202
171
|
}
|
|
172
|
+
|
|
203
173
|
/**
|
|
204
174
|
* Gets the CSS styles from the style object.
|
|
205
175
|
* @param styles - The style object containing the styles to get.
|
|
206
176
|
* @returns A string containing the CSS styles and their values.
|
|
207
177
|
*/
|
|
208
|
-
|
|
209
178
|
function getCSSFromStyleObject(styles) {
|
|
210
179
|
let css = '';
|
|
211
|
-
|
|
212
180
|
for (const style in styles) {
|
|
213
181
|
if (style) {
|
|
214
182
|
css += `${style}: ${styles[style]};`;
|
|
215
183
|
}
|
|
216
184
|
}
|
|
217
|
-
|
|
218
185
|
return css;
|
|
219
186
|
}
|
|
220
187
|
|
|
@@ -225,7 +192,6 @@ function getCSSFromStyleObject(styles) {
|
|
|
225
192
|
* LICENSE file in the root directory of this source tree.
|
|
226
193
|
*
|
|
227
194
|
*/
|
|
228
|
-
|
|
229
195
|
function $updateElementNodeProperties(target, source) {
|
|
230
196
|
target.__first = source.__first;
|
|
231
197
|
target.__last = source.__last;
|
|
@@ -235,7 +201,6 @@ function $updateElementNodeProperties(target, source) {
|
|
|
235
201
|
target.__dir = source.__dir;
|
|
236
202
|
return target;
|
|
237
203
|
}
|
|
238
|
-
|
|
239
204
|
function $updateTextNodeProperties(target, source) {
|
|
240
205
|
target.__format = source.__format;
|
|
241
206
|
target.__style = source.__style;
|
|
@@ -243,31 +208,28 @@ function $updateTextNodeProperties(target, source) {
|
|
|
243
208
|
target.__detail = source.__detail;
|
|
244
209
|
return target;
|
|
245
210
|
}
|
|
211
|
+
|
|
246
212
|
/**
|
|
247
213
|
* Returns a copy of a node, but generates a new key for the copy.
|
|
248
214
|
* @param node - The node to be cloned.
|
|
249
215
|
* @returns The clone of the node.
|
|
250
216
|
*/
|
|
251
|
-
|
|
252
|
-
|
|
253
217
|
function $cloneWithProperties(node) {
|
|
254
|
-
const constructor = node.constructor;
|
|
255
|
-
|
|
218
|
+
const constructor = node.constructor;
|
|
219
|
+
// @ts-expect-error
|
|
256
220
|
const clone = constructor.clone(node);
|
|
257
221
|
clone.__parent = node.__parent;
|
|
258
222
|
clone.__next = node.__next;
|
|
259
223
|
clone.__prev = node.__prev;
|
|
260
|
-
|
|
261
224
|
if (lexical.$isElementNode(node) && lexical.$isElementNode(clone)) {
|
|
262
225
|
return $updateElementNodeProperties(clone, node);
|
|
263
226
|
}
|
|
264
|
-
|
|
265
227
|
if (lexical.$isTextNode(node) && lexical.$isTextNode(clone)) {
|
|
266
228
|
return $updateTextNodeProperties(clone, node);
|
|
267
229
|
}
|
|
268
|
-
|
|
269
230
|
return clone;
|
|
270
231
|
}
|
|
232
|
+
|
|
271
233
|
/**
|
|
272
234
|
* Generally used to append text content to HTML and JSON. Grabs the text content and "slices"
|
|
273
235
|
* it to be generated into the new TextNode.
|
|
@@ -275,14 +237,12 @@ function $cloneWithProperties(node) {
|
|
|
275
237
|
* @param textNode - The TextNode to be edited.
|
|
276
238
|
* @returns The updated TextNode.
|
|
277
239
|
*/
|
|
278
|
-
|
|
279
240
|
function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
280
241
|
if (textNode.isSelected() && !textNode.isSegmented() && !textNode.isToken() && (lexical.$isRangeSelection(selection) || lexical.DEPRECATED_$isGridSelection(selection))) {
|
|
281
242
|
const anchorNode = selection.anchor.getNode();
|
|
282
243
|
const focusNode = selection.focus.getNode();
|
|
283
244
|
const isAnchor = textNode.is(anchorNode);
|
|
284
245
|
const isFocus = textNode.is(focusNode);
|
|
285
|
-
|
|
286
246
|
if (isAnchor || isFocus) {
|
|
287
247
|
const isBackward = selection.isBackward();
|
|
288
248
|
const [anchorOffset, focusOffset] = selection.getCharacterOffsets();
|
|
@@ -291,7 +251,6 @@ function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
|
291
251
|
const isLast = textNode.is(isBackward ? anchorNode : focusNode);
|
|
292
252
|
let startOffset = 0;
|
|
293
253
|
let endOffset = undefined;
|
|
294
|
-
|
|
295
254
|
if (isSame) {
|
|
296
255
|
startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
297
256
|
endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
@@ -304,27 +263,25 @@ function $sliceSelectedTextNodeContent(selection, textNode) {
|
|
|
304
263
|
startOffset = 0;
|
|
305
264
|
endOffset = offset;
|
|
306
265
|
}
|
|
307
|
-
|
|
308
266
|
textNode.__text = textNode.__text.slice(startOffset, endOffset);
|
|
309
267
|
return textNode;
|
|
310
268
|
}
|
|
311
269
|
}
|
|
312
|
-
|
|
313
270
|
return textNode;
|
|
314
271
|
}
|
|
272
|
+
|
|
315
273
|
/**
|
|
316
274
|
* Determines if the current selection is at the end of the node.
|
|
317
275
|
* @param point - The point of the selection to test.
|
|
318
276
|
* @returns true if the provided point offset is in the last possible position, false otherwise.
|
|
319
277
|
*/
|
|
320
|
-
|
|
321
278
|
function $isAtNodeEnd(point) {
|
|
322
279
|
if (point.type === 'text') {
|
|
323
280
|
return point.offset === point.getNode().getTextContentSize();
|
|
324
281
|
}
|
|
325
|
-
|
|
326
282
|
return point.offset === point.getNode().getChildrenSize();
|
|
327
283
|
}
|
|
284
|
+
|
|
328
285
|
/**
|
|
329
286
|
* Trims text from a node in order to shorten it, eg. to enforce a text's max length. If it deletes text
|
|
330
287
|
* that is an ancestor of the anchor then it will leave 2 indents, otherwise, if no text content exists, it deletes
|
|
@@ -333,89 +290,72 @@ function $isAtNodeEnd(point) {
|
|
|
333
290
|
* @param anchor - The anchor of the current selection, where the selection should be pointing.
|
|
334
291
|
* @param delCount - The amount of characters to delete. Useful as a dynamic variable eg. textContentSize - maxLength;
|
|
335
292
|
*/
|
|
336
|
-
|
|
337
293
|
function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
338
294
|
// Work from the current selection anchor point
|
|
339
295
|
let currentNode = anchor.getNode();
|
|
340
296
|
let remaining = delCount;
|
|
341
|
-
|
|
342
297
|
if (lexical.$isElementNode(currentNode)) {
|
|
343
298
|
const descendantNode = currentNode.getDescendantByIndex(anchor.offset);
|
|
344
|
-
|
|
345
299
|
if (descendantNode !== null) {
|
|
346
300
|
currentNode = descendantNode;
|
|
347
301
|
}
|
|
348
302
|
}
|
|
349
|
-
|
|
350
303
|
while (remaining > 0 && currentNode !== null) {
|
|
304
|
+
if (lexical.$isElementNode(currentNode)) {
|
|
305
|
+
const lastDescendant = currentNode.getLastDescendant();
|
|
306
|
+
if (lastDescendant !== null) {
|
|
307
|
+
currentNode = lastDescendant;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
351
310
|
let nextNode = currentNode.getPreviousSibling();
|
|
352
311
|
let additionalElementWhitespace = 0;
|
|
353
|
-
|
|
354
312
|
if (nextNode === null) {
|
|
355
313
|
let parent = currentNode.getParentOrThrow();
|
|
356
314
|
let parentSibling = parent.getPreviousSibling();
|
|
357
|
-
|
|
358
315
|
while (parentSibling === null) {
|
|
359
316
|
parent = parent.getParent();
|
|
360
|
-
|
|
361
317
|
if (parent === null) {
|
|
362
318
|
nextNode = null;
|
|
363
319
|
break;
|
|
364
320
|
}
|
|
365
|
-
|
|
366
321
|
parentSibling = parent.getPreviousSibling();
|
|
367
322
|
}
|
|
368
|
-
|
|
369
323
|
if (parent !== null) {
|
|
370
324
|
additionalElementWhitespace = parent.isInline() ? 0 : 2;
|
|
371
|
-
|
|
372
|
-
if (lexical.$isElementNode(parentSibling)) {
|
|
373
|
-
nextNode = parentSibling.getLastDescendant();
|
|
374
|
-
} else {
|
|
375
|
-
nextNode = parentSibling;
|
|
376
|
-
}
|
|
325
|
+
nextNode = parentSibling;
|
|
377
326
|
}
|
|
378
327
|
}
|
|
379
|
-
|
|
380
|
-
|
|
328
|
+
let text = currentNode.getTextContent();
|
|
329
|
+
// If the text is empty, we need to consider adding in two line breaks to match
|
|
381
330
|
// the content if we were to get it from its parent.
|
|
382
|
-
|
|
383
331
|
if (text === '' && lexical.$isElementNode(currentNode) && !currentNode.isInline()) {
|
|
384
332
|
// TODO: should this be handled in core?
|
|
385
333
|
text = '\n\n';
|
|
386
334
|
}
|
|
387
|
-
|
|
388
335
|
const currentNodeSize = text.length;
|
|
389
|
-
|
|
390
336
|
if (!lexical.$isTextNode(currentNode) || remaining >= currentNodeSize) {
|
|
391
337
|
const parent = currentNode.getParent();
|
|
392
338
|
currentNode.remove();
|
|
393
|
-
|
|
394
339
|
if (parent != null && parent.getChildrenSize() === 0 && !lexical.$isRootNode(parent)) {
|
|
395
340
|
parent.remove();
|
|
396
341
|
}
|
|
397
|
-
|
|
398
342
|
remaining -= currentNodeSize + additionalElementWhitespace;
|
|
399
343
|
currentNode = nextNode;
|
|
400
344
|
} else {
|
|
401
|
-
const key = currentNode.getKey();
|
|
402
|
-
|
|
345
|
+
const key = currentNode.getKey();
|
|
346
|
+
// See if we can just revert it to what was in the last editor state
|
|
403
347
|
const prevTextContent = editor.getEditorState().read(() => {
|
|
404
348
|
const prevNode = lexical.$getNodeByKey(key);
|
|
405
|
-
|
|
406
349
|
if (lexical.$isTextNode(prevNode) && prevNode.isSimpleText()) {
|
|
407
350
|
return prevNode.getTextContent();
|
|
408
351
|
}
|
|
409
|
-
|
|
410
352
|
return null;
|
|
411
353
|
});
|
|
412
354
|
const offset = currentNodeSize - remaining;
|
|
413
355
|
const slicedText = text.slice(0, offset);
|
|
414
|
-
|
|
415
356
|
if (prevTextContent !== null && prevTextContent !== text) {
|
|
416
357
|
const prevSelection = lexical.$getPreviousSelection();
|
|
417
358
|
let target = currentNode;
|
|
418
|
-
|
|
419
359
|
if (!currentNode.isSimpleText()) {
|
|
420
360
|
const textNode = lexical.$createTextNode(prevTextContent);
|
|
421
361
|
currentNode.replace(textNode);
|
|
@@ -423,7 +363,6 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
423
363
|
} else {
|
|
424
364
|
currentNode.setTextContent(prevTextContent);
|
|
425
365
|
}
|
|
426
|
-
|
|
427
366
|
if (lexical.$isRangeSelection(prevSelection) && prevSelection.isCollapsed()) {
|
|
428
367
|
const prevOffset = prevSelection.anchor.offset;
|
|
429
368
|
target.select(prevOffset, prevOffset);
|
|
@@ -431,16 +370,14 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
431
370
|
} else if (currentNode.isSimpleText()) {
|
|
432
371
|
// Split text
|
|
433
372
|
const isSelected = anchor.key === key;
|
|
434
|
-
let anchorOffset = anchor.offset;
|
|
373
|
+
let anchorOffset = anchor.offset;
|
|
374
|
+
// Move offset to end if it's less than the remaining number, otherwise
|
|
435
375
|
// we'll have a negative splitStart.
|
|
436
|
-
|
|
437
376
|
if (anchorOffset < remaining) {
|
|
438
377
|
anchorOffset = currentNodeSize;
|
|
439
378
|
}
|
|
440
|
-
|
|
441
379
|
const splitStart = isSelected ? anchorOffset - remaining : 0;
|
|
442
380
|
const splitEnd = isSelected ? anchorOffset : offset;
|
|
443
|
-
|
|
444
381
|
if (isSelected && splitStart === 0) {
|
|
445
382
|
const [excessNode] = currentNode.splitText(splitStart, splitEnd);
|
|
446
383
|
excessNode.remove();
|
|
@@ -452,22 +389,20 @@ function trimTextContentFromAnchor(editor, anchor, delCount) {
|
|
|
452
389
|
const textNode = lexical.$createTextNode(slicedText);
|
|
453
390
|
currentNode.replace(textNode);
|
|
454
391
|
}
|
|
455
|
-
|
|
456
392
|
remaining = 0;
|
|
457
393
|
}
|
|
458
394
|
}
|
|
459
395
|
}
|
|
396
|
+
|
|
460
397
|
/**
|
|
461
398
|
* Gets the TextNode's style object and adds the styles to the CSS.
|
|
462
399
|
* @param node - The TextNode to add styles to.
|
|
463
400
|
*/
|
|
464
|
-
|
|
465
401
|
function $addNodeStyle(node) {
|
|
466
402
|
const CSSText = node.getStyle();
|
|
467
403
|
const styles = getStyleObjectFromRawCSS(CSSText);
|
|
468
404
|
CSS_TO_STYLES.set(CSSText, styles);
|
|
469
405
|
}
|
|
470
|
-
|
|
471
406
|
function $patchStyle(target, patch) {
|
|
472
407
|
const prevStyles = getStyleObjectFromCSS('getStyle' in target ? target.getStyle() : target.style);
|
|
473
408
|
const newStyles = Object.entries(patch).reduce((styles, [key, value]) => {
|
|
@@ -476,14 +411,15 @@ function $patchStyle(target, patch) {
|
|
|
476
411
|
} else {
|
|
477
412
|
styles[key] = value;
|
|
478
413
|
}
|
|
479
|
-
|
|
480
414
|
return styles;
|
|
481
|
-
}, {
|
|
415
|
+
}, {
|
|
416
|
+
...prevStyles
|
|
482
417
|
} || {});
|
|
483
418
|
const newCSSText = getCSSFromStyleObject(newStyles);
|
|
484
419
|
target.setStyle(newCSSText);
|
|
485
420
|
CSS_TO_STYLES.set(newCSSText, newStyles);
|
|
486
421
|
}
|
|
422
|
+
|
|
487
423
|
/**
|
|
488
424
|
* Applies the provided styles to the TextNodes in the provided Selection.
|
|
489
425
|
* Will update partially selected TextNodes by splitting the TextNode and applying
|
|
@@ -491,40 +427,31 @@ function $patchStyle(target, patch) {
|
|
|
491
427
|
* @param selection - The selected node(s) to update.
|
|
492
428
|
* @param patch - The patch to apply, which can include multiple styles. { CSSProperty: value }
|
|
493
429
|
*/
|
|
494
|
-
|
|
495
|
-
|
|
496
430
|
function $patchStyleText(selection, patch) {
|
|
497
431
|
const selectedNodes = selection.getNodes();
|
|
498
432
|
const selectedNodesLength = selectedNodes.length;
|
|
499
|
-
|
|
500
433
|
if (lexical.DEPRECATED_$isGridSelection(selection)) {
|
|
501
434
|
const cellSelection = lexical.$createRangeSelection();
|
|
502
435
|
const cellSelectionAnchor = cellSelection.anchor;
|
|
503
436
|
const cellSelectionFocus = cellSelection.focus;
|
|
504
|
-
|
|
505
437
|
for (let i = 0; i < selectedNodesLength; i++) {
|
|
506
438
|
const node = selectedNodes[i];
|
|
507
|
-
|
|
508
439
|
if (lexical.DEPRECATED_$isGridCellNode(node)) {
|
|
509
440
|
cellSelectionAnchor.set(node.getKey(), 0, 'element');
|
|
510
441
|
cellSelectionFocus.set(node.getKey(), node.getChildrenSize(), 'element');
|
|
511
442
|
$patchStyleText(lexical.$normalizeSelection__EXPERIMENTAL(cellSelection), patch);
|
|
512
443
|
}
|
|
513
444
|
}
|
|
514
|
-
|
|
515
445
|
lexical.$setSelection(selection);
|
|
516
446
|
return;
|
|
517
447
|
}
|
|
518
|
-
|
|
519
448
|
const lastIndex = selectedNodesLength - 1;
|
|
520
449
|
let firstNode = selectedNodes[0];
|
|
521
450
|
let lastNode = selectedNodes[lastIndex];
|
|
522
|
-
|
|
523
451
|
if (selection.isCollapsed()) {
|
|
524
452
|
$patchStyle(selection, patch);
|
|
525
453
|
return;
|
|
526
454
|
}
|
|
527
|
-
|
|
528
455
|
const anchor = selection.anchor;
|
|
529
456
|
const focus = selection.focus;
|
|
530
457
|
const firstNodeText = firstNode.getTextContent();
|
|
@@ -536,31 +463,32 @@ function $patchStyleText(selection, patch) {
|
|
|
536
463
|
let endOffset = isBefore ? focusOffset : anchorOffset;
|
|
537
464
|
const startType = isBefore ? anchor.type : focus.type;
|
|
538
465
|
const endType = isBefore ? focus.type : anchor.type;
|
|
539
|
-
const endKey = isBefore ? focus.key : anchor.key;
|
|
540
|
-
// first node so we don't want to include it in the formatting change.
|
|
466
|
+
const endKey = isBefore ? focus.key : anchor.key;
|
|
541
467
|
|
|
468
|
+
// This is the case where the user only selected the very end of the
|
|
469
|
+
// first node so we don't want to include it in the formatting change.
|
|
542
470
|
if (lexical.$isTextNode(firstNode) && startOffset === firstNodeTextLength) {
|
|
543
471
|
const nextSibling = firstNode.getNextSibling();
|
|
544
|
-
|
|
545
472
|
if (lexical.$isTextNode(nextSibling)) {
|
|
546
473
|
// we basically make the second node the firstNode, changing offsets accordingly
|
|
547
474
|
anchorOffset = 0;
|
|
548
475
|
startOffset = 0;
|
|
549
476
|
firstNode = nextSibling;
|
|
550
477
|
}
|
|
551
|
-
}
|
|
552
|
-
|
|
478
|
+
}
|
|
553
479
|
|
|
480
|
+
// This is the case where we only selected a single node
|
|
554
481
|
if (selectedNodes.length === 1) {
|
|
555
482
|
if (lexical.$isTextNode(firstNode)) {
|
|
556
483
|
startOffset = startType === 'element' ? 0 : anchorOffset > focusOffset ? focusOffset : anchorOffset;
|
|
557
|
-
endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
484
|
+
endOffset = endType === 'element' ? firstNodeTextLength : anchorOffset > focusOffset ? anchorOffset : focusOffset;
|
|
558
485
|
|
|
486
|
+
// No actual text is selected, so do nothing.
|
|
559
487
|
if (startOffset === endOffset) {
|
|
560
488
|
return;
|
|
561
|
-
}
|
|
562
|
-
|
|
489
|
+
}
|
|
563
490
|
|
|
491
|
+
// The entire node is selected, so just format it
|
|
564
492
|
if (startOffset === 0 && endOffset === firstNodeTextLength) {
|
|
565
493
|
$patchStyle(firstNode, patch);
|
|
566
494
|
firstNode.select(startOffset, endOffset);
|
|
@@ -573,44 +501,41 @@ function $patchStyleText(selection, patch) {
|
|
|
573
501
|
replacement.select(0, endOffset - startOffset);
|
|
574
502
|
}
|
|
575
503
|
} // multiple nodes selected.
|
|
576
|
-
|
|
577
504
|
} else {
|
|
578
505
|
if (lexical.$isTextNode(firstNode) && startOffset < firstNode.getTextContentSize()) {
|
|
579
506
|
if (startOffset !== 0) {
|
|
580
507
|
// the entire first node isn't selected, so split it
|
|
581
508
|
firstNode = firstNode.splitText(startOffset)[1];
|
|
582
509
|
startOffset = 0;
|
|
510
|
+
anchor.set(firstNode.getKey(), startOffset, 'text');
|
|
583
511
|
}
|
|
584
|
-
|
|
585
512
|
$patchStyle(firstNode, patch);
|
|
586
513
|
}
|
|
587
|
-
|
|
588
514
|
if (lexical.$isTextNode(lastNode)) {
|
|
589
515
|
const lastNodeText = lastNode.getTextContent();
|
|
590
|
-
const lastNodeTextLength = lastNodeText.length;
|
|
516
|
+
const lastNodeTextLength = lastNodeText.length;
|
|
517
|
+
|
|
518
|
+
// The last node might not actually be the end node
|
|
591
519
|
//
|
|
592
520
|
// If not, assume the last node is fully-selected unless the end offset is
|
|
593
521
|
// zero.
|
|
594
|
-
|
|
595
522
|
if (lastNode.__key !== endKey && endOffset !== 0) {
|
|
596
523
|
endOffset = lastNodeTextLength;
|
|
597
|
-
}
|
|
598
|
-
|
|
524
|
+
}
|
|
599
525
|
|
|
526
|
+
// if the entire last node isn't selected, split it
|
|
600
527
|
if (endOffset !== lastNodeTextLength) {
|
|
601
528
|
[lastNode] = lastNode.splitText(endOffset);
|
|
602
529
|
}
|
|
603
|
-
|
|
604
530
|
if (endOffset !== 0) {
|
|
605
531
|
$patchStyle(lastNode, patch);
|
|
606
532
|
}
|
|
607
|
-
}
|
|
608
|
-
|
|
533
|
+
}
|
|
609
534
|
|
|
535
|
+
// style all the text nodes in between
|
|
610
536
|
for (let i = 1; i < lastIndex; i++) {
|
|
611
537
|
const selectedNode = selectedNodes[i];
|
|
612
538
|
const selectedNodeKey = selectedNode.getKey();
|
|
613
|
-
|
|
614
539
|
if (lexical.$isTextNode(selectedNode) && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {
|
|
615
540
|
$patchStyle(selectedNode, patch);
|
|
616
541
|
}
|
|
@@ -625,84 +550,55 @@ function $patchStyleText(selection, patch) {
|
|
|
625
550
|
* LICENSE file in the root directory of this source tree.
|
|
626
551
|
*
|
|
627
552
|
*/
|
|
553
|
+
|
|
628
554
|
/**
|
|
629
555
|
* Converts all nodes in the selection that are of one block type to another.
|
|
630
556
|
* @param selection - The selected blocks to be converted.
|
|
631
557
|
* @param createElement - The function that creates the node. eg. $createParagraphNode.
|
|
632
558
|
*/
|
|
633
|
-
|
|
634
559
|
function $setBlocksType(selection, createElement) {
|
|
635
560
|
if (selection.anchor.key === 'root') {
|
|
636
561
|
const element = createElement();
|
|
637
562
|
const root = lexical.$getRoot();
|
|
638
563
|
const firstChild = root.getFirstChild();
|
|
639
|
-
|
|
640
564
|
if (firstChild) {
|
|
641
565
|
firstChild.replace(element, true);
|
|
642
566
|
} else {
|
|
643
567
|
root.append(element);
|
|
644
568
|
}
|
|
645
|
-
|
|
646
569
|
return;
|
|
647
570
|
}
|
|
648
|
-
|
|
649
571
|
const nodes = selection.getNodes();
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
nodes.push(maybeBlock);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (maybeBlock.isInline()) {
|
|
657
|
-
maybeBlock = maybeBlock.getParentOrThrow();
|
|
658
|
-
|
|
659
|
-
if (nodes.indexOf(maybeBlock) === -1) {
|
|
660
|
-
nodes.push(maybeBlock);
|
|
661
|
-
}
|
|
572
|
+
const firstSelectedBlock = $getAncestor(selection.anchor.getNode(), INTERNAL_$isBlock);
|
|
573
|
+
if (firstSelectedBlock && nodes.indexOf(firstSelectedBlock) === -1) {
|
|
574
|
+
nodes.push(firstSelectedBlock);
|
|
662
575
|
}
|
|
663
|
-
|
|
664
576
|
for (let i = 0; i < nodes.length; i++) {
|
|
665
577
|
const node = nodes[i];
|
|
666
|
-
|
|
667
|
-
if (!isBlock(node)) {
|
|
578
|
+
if (!INTERNAL_$isBlock(node)) {
|
|
668
579
|
continue;
|
|
669
580
|
}
|
|
670
|
-
|
|
671
581
|
const targetElement = createElement();
|
|
672
582
|
targetElement.setFormat(node.getFormatType());
|
|
673
583
|
targetElement.setIndent(node.getIndent());
|
|
674
584
|
node.replace(targetElement, true);
|
|
675
585
|
}
|
|
676
586
|
}
|
|
677
|
-
|
|
678
|
-
function isBlock(node) {
|
|
679
|
-
if (!lexical.$isElementNode(node) || lexical.$isRootOrShadowRoot(node)) {
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const firstChild = node.getFirstChild();
|
|
684
|
-
const isLeafElement = firstChild === null || lexical.$isLineBreakNode(firstChild) || lexical.$isTextNode(firstChild) || firstChild.isInline();
|
|
685
|
-
return !node.isInline() && node.canBeEmpty() !== false && isLeafElement;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
587
|
function isPointAttached(point) {
|
|
689
588
|
return point.getNode().isAttached();
|
|
690
589
|
}
|
|
691
|
-
|
|
692
590
|
function $removeParentEmptyElements(startingNode) {
|
|
693
591
|
let node = startingNode;
|
|
694
|
-
|
|
695
592
|
while (node !== null && !lexical.$isRootOrShadowRoot(node)) {
|
|
696
593
|
const latest = node.getLatest();
|
|
697
594
|
const parentNode = node.getParent();
|
|
698
|
-
|
|
699
595
|
if (latest.getChildrenSize() === 0) {
|
|
700
596
|
node.remove(true);
|
|
701
597
|
}
|
|
702
|
-
|
|
703
598
|
node = parentNode;
|
|
704
599
|
}
|
|
705
600
|
}
|
|
601
|
+
|
|
706
602
|
/**
|
|
707
603
|
* @deprecated
|
|
708
604
|
* Wraps all nodes in the selection into another node of the type returned by createElement.
|
|
@@ -710,13 +606,10 @@ function $removeParentEmptyElements(startingNode) {
|
|
|
710
606
|
* @param createElement - A function that creates the wrapping ElementNode. eg. $createParagraphNode.
|
|
711
607
|
* @param wrappingElement - An element to append the wrapped selection and its children to.
|
|
712
608
|
*/
|
|
713
|
-
|
|
714
|
-
|
|
715
609
|
function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
716
610
|
const nodes = selection.getNodes();
|
|
717
611
|
const nodesLength = nodes.length;
|
|
718
612
|
const anchor = selection.anchor;
|
|
719
|
-
|
|
720
613
|
if (nodesLength === 0 || nodesLength === 1 && anchor.type === 'element' && anchor.getNode().getChildrenSize() === 0) {
|
|
721
614
|
const target = anchor.type === 'text' ? anchor.getNode().getParentOrThrow() : anchor.getNode();
|
|
722
615
|
const children = target.getChildren();
|
|
@@ -724,24 +617,20 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
724
617
|
element.setFormat(target.getFormatType());
|
|
725
618
|
element.setIndent(target.getIndent());
|
|
726
619
|
children.forEach(child => element.append(child));
|
|
727
|
-
|
|
728
620
|
if (wrappingElement) {
|
|
729
621
|
element = wrappingElement.append(element);
|
|
730
622
|
}
|
|
731
|
-
|
|
732
623
|
target.replace(element);
|
|
733
624
|
return;
|
|
734
625
|
}
|
|
735
|
-
|
|
736
626
|
let topLevelNode = null;
|
|
737
627
|
let descendants = [];
|
|
738
|
-
|
|
739
628
|
for (let i = 0; i < nodesLength; i++) {
|
|
740
|
-
const node = nodes[i];
|
|
629
|
+
const node = nodes[i];
|
|
630
|
+
// Determine whether wrapping has to be broken down into multiple chunks. This can happen if the
|
|
741
631
|
// user selected multiple Root-like nodes that have to be treated separately as if they are
|
|
742
632
|
// their own branch. I.e. you don't want to wrap a whole table, but rather the contents of each
|
|
743
633
|
// of each of the cell nodes.
|
|
744
|
-
|
|
745
634
|
if (lexical.$isRootOrShadowRoot(node)) {
|
|
746
635
|
$wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);
|
|
747
636
|
descendants = [];
|
|
@@ -753,9 +642,9 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
753
642
|
descendants = [node];
|
|
754
643
|
}
|
|
755
644
|
}
|
|
756
|
-
|
|
757
645
|
$wrapNodesImpl(selection, descendants, descendants.length, createElement, wrappingElement);
|
|
758
646
|
}
|
|
647
|
+
|
|
759
648
|
/**
|
|
760
649
|
* Wraps each node into a new ElementNode.
|
|
761
650
|
* @param selection - The selection of nodes to wrap.
|
|
@@ -765,80 +654,67 @@ function $wrapNodes(selection, createElement, wrappingElement = null) {
|
|
|
765
654
|
* @param wrappingElement - An element to wrap all the nodes into.
|
|
766
655
|
* @returns
|
|
767
656
|
*/
|
|
768
|
-
|
|
769
657
|
function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingElement = null) {
|
|
770
658
|
if (nodes.length === 0) {
|
|
771
659
|
return;
|
|
772
660
|
}
|
|
773
|
-
|
|
774
661
|
const firstNode = nodes[0];
|
|
775
662
|
const elementMapping = new Map();
|
|
776
|
-
const elements = [];
|
|
663
|
+
const elements = [];
|
|
664
|
+
// The below logic is to find the right target for us to
|
|
777
665
|
// either insertAfter/insertBefore/append the corresponding
|
|
778
666
|
// elements to. This is made more complicated due to nested
|
|
779
667
|
// structures.
|
|
780
|
-
|
|
781
668
|
let target = lexical.$isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
|
|
782
|
-
|
|
783
669
|
if (target.isInline()) {
|
|
784
670
|
target = target.getParentOrThrow();
|
|
785
671
|
}
|
|
786
|
-
|
|
787
672
|
let targetIsPrevSibling = false;
|
|
788
|
-
|
|
789
673
|
while (target !== null) {
|
|
790
674
|
const prevSibling = target.getPreviousSibling();
|
|
791
|
-
|
|
792
675
|
if (prevSibling !== null) {
|
|
793
676
|
target = prevSibling;
|
|
794
677
|
targetIsPrevSibling = true;
|
|
795
678
|
break;
|
|
796
679
|
}
|
|
797
|
-
|
|
798
680
|
target = target.getParentOrThrow();
|
|
799
|
-
|
|
800
681
|
if (lexical.$isRootOrShadowRoot(target)) {
|
|
801
682
|
break;
|
|
802
683
|
}
|
|
803
684
|
}
|
|
685
|
+
const emptyElements = new Set();
|
|
804
686
|
|
|
805
|
-
|
|
806
|
-
|
|
687
|
+
// Find any top level empty elements
|
|
807
688
|
for (let i = 0; i < nodesLength; i++) {
|
|
808
689
|
const node = nodes[i];
|
|
809
|
-
|
|
810
690
|
if (lexical.$isElementNode(node) && node.getChildrenSize() === 0) {
|
|
811
691
|
emptyElements.add(node.getKey());
|
|
812
692
|
}
|
|
813
693
|
}
|
|
694
|
+
const movedNodes = new Set();
|
|
814
695
|
|
|
815
|
-
|
|
696
|
+
// Move out all leaf nodes into our elements array.
|
|
816
697
|
// If we find a top level empty element, also move make
|
|
817
698
|
// an element for that.
|
|
818
|
-
|
|
819
699
|
for (let i = 0; i < nodesLength; i++) {
|
|
820
700
|
const node = nodes[i];
|
|
821
701
|
let parent = node.getParent();
|
|
822
|
-
|
|
823
702
|
if (parent !== null && parent.isInline()) {
|
|
824
703
|
parent = parent.getParent();
|
|
825
704
|
}
|
|
826
|
-
|
|
827
705
|
if (parent !== null && lexical.$isLeafNode(node) && !movedNodes.has(node.getKey())) {
|
|
828
706
|
const parentKey = parent.getKey();
|
|
829
|
-
|
|
830
707
|
if (elementMapping.get(parentKey) === undefined) {
|
|
831
708
|
const targetElement = createElement();
|
|
832
709
|
targetElement.setFormat(parent.getFormatType());
|
|
833
710
|
targetElement.setIndent(parent.getIndent());
|
|
834
711
|
elements.push(targetElement);
|
|
835
|
-
elementMapping.set(parentKey, targetElement);
|
|
712
|
+
elementMapping.set(parentKey, targetElement);
|
|
713
|
+
// Move node and its siblings to the new
|
|
836
714
|
// element.
|
|
837
|
-
|
|
838
715
|
parent.getChildren().forEach(child => {
|
|
839
716
|
targetElement.append(child);
|
|
840
717
|
movedNodes.add(child.getKey());
|
|
841
|
-
|
|
842
718
|
if (lexical.$isElementNode(child)) {
|
|
843
719
|
// Skip nested leaf nodes if the parent has already been moved
|
|
844
720
|
child.getChildrenKeys().forEach(key => movedNodes.add(key));
|
|
@@ -854,17 +730,16 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
854
730
|
node.remove(true);
|
|
855
731
|
}
|
|
856
732
|
}
|
|
857
|
-
|
|
858
733
|
if (wrappingElement !== null) {
|
|
859
734
|
for (let i = 0; i < elements.length; i++) {
|
|
860
735
|
const element = elements[i];
|
|
861
736
|
wrappingElement.append(element);
|
|
862
737
|
}
|
|
863
738
|
}
|
|
739
|
+
let lastElement = null;
|
|
864
740
|
|
|
865
|
-
|
|
741
|
+
// If our target is Root-like, let's see if we can re-adjust
|
|
866
742
|
// so that the target is the first child instead.
|
|
867
|
-
|
|
868
743
|
if (lexical.$isRootOrShadowRoot(target)) {
|
|
869
744
|
if (targetIsPrevSibling) {
|
|
870
745
|
if (wrappingElement !== null) {
|
|
@@ -877,11 +752,9 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
877
752
|
}
|
|
878
753
|
} else {
|
|
879
754
|
const firstChild = target.getFirstChild();
|
|
880
|
-
|
|
881
755
|
if (lexical.$isElementNode(firstChild)) {
|
|
882
756
|
target = firstChild;
|
|
883
757
|
}
|
|
884
|
-
|
|
885
758
|
if (firstChild === null) {
|
|
886
759
|
if (wrappingElement) {
|
|
887
760
|
target.append(wrappingElement);
|
|
@@ -915,9 +788,7 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
915
788
|
}
|
|
916
789
|
}
|
|
917
790
|
}
|
|
918
|
-
|
|
919
791
|
const prevSelection = lexical.$getPreviousSelection();
|
|
920
|
-
|
|
921
792
|
if (lexical.$isRangeSelection(prevSelection) && isPointAttached(prevSelection.anchor) && isPointAttached(prevSelection.focus)) {
|
|
922
793
|
lexical.$setSelection(prevSelection.clone());
|
|
923
794
|
} else if (lastElement !== null) {
|
|
@@ -926,17 +797,18 @@ function $wrapNodesImpl(selection, nodes, nodesLength, createElement, wrappingEl
|
|
|
926
797
|
selection.dirty = true;
|
|
927
798
|
}
|
|
928
799
|
}
|
|
800
|
+
|
|
929
801
|
/**
|
|
930
802
|
* Determines if the default character selection should be overridden. Used with DecoratorNodes
|
|
931
803
|
* @param selection - The selection whose default character selection may need to be overridden.
|
|
932
804
|
* @param isBackward - Is the selection backwards (the focus comes before the anchor)?
|
|
933
805
|
* @returns true if it should be overridden, false if not.
|
|
934
806
|
*/
|
|
935
|
-
|
|
936
807
|
function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
937
808
|
const possibleNode = lexical.$getAdjacentNode(selection.focus, isBackward);
|
|
938
809
|
return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated() || lexical.$isElementNode(possibleNode) && !possibleNode.isInline() && !possibleNode.canBeEmpty();
|
|
939
810
|
}
|
|
811
|
+
|
|
940
812
|
/**
|
|
941
813
|
* Moves the selection according to the arguments.
|
|
942
814
|
* @param selection - The selected text or nodes.
|
|
@@ -944,37 +816,36 @@ function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
|
|
|
944
816
|
* @param isBackward - Is the selection selected backwards (the focus comes before the anchor)?
|
|
945
817
|
* @param granularity - The distance to adjust the current selection.
|
|
946
818
|
*/
|
|
947
|
-
|
|
948
819
|
function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {
|
|
949
820
|
selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);
|
|
950
821
|
}
|
|
822
|
+
|
|
951
823
|
/**
|
|
952
824
|
* Tests a parent element for right to left direction.
|
|
953
825
|
* @param selection - The selection whose parent is to be tested.
|
|
954
826
|
* @returns true if the selections' parent element has a direction of 'rtl' (right to left), false otherwise.
|
|
955
827
|
*/
|
|
956
|
-
|
|
957
828
|
function $isParentElementRTL(selection) {
|
|
958
829
|
const anchorNode = selection.anchor.getNode();
|
|
959
830
|
const parent = lexical.$isRootNode(anchorNode) ? anchorNode : anchorNode.getParentOrThrow();
|
|
960
831
|
return parent.getDirection() === 'rtl';
|
|
961
832
|
}
|
|
833
|
+
|
|
962
834
|
/**
|
|
963
835
|
* Moves selection by character according to arguments.
|
|
964
836
|
* @param selection - The selection of the characters to move.
|
|
965
837
|
* @param isHoldingShift - Is the shift key being held down during the operation.
|
|
966
838
|
* @param isBackward - Is the selection backward (the focus comes before the anchor)?
|
|
967
839
|
*/
|
|
968
|
-
|
|
969
840
|
function $moveCharacter(selection, isHoldingShift, isBackward) {
|
|
970
841
|
const isRTL = $isParentElementRTL(selection);
|
|
971
842
|
$moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
|
|
972
843
|
}
|
|
844
|
+
|
|
973
845
|
/**
|
|
974
846
|
* Expands the current Selection to cover all of the content in the editor.
|
|
975
847
|
* @param selection - The current selection.
|
|
976
848
|
*/
|
|
977
|
-
|
|
978
849
|
function $selectAll(selection) {
|
|
979
850
|
const anchor = selection.anchor;
|
|
980
851
|
const focus = selection.focus;
|
|
@@ -986,25 +857,23 @@ function $selectAll(selection) {
|
|
|
986
857
|
let firstType = 'element';
|
|
987
858
|
let lastType = 'element';
|
|
988
859
|
let lastOffset = 0;
|
|
989
|
-
|
|
990
860
|
if (lexical.$isTextNode(firstNode)) {
|
|
991
861
|
firstType = 'text';
|
|
992
862
|
} else if (!lexical.$isElementNode(firstNode) && firstNode !== null) {
|
|
993
863
|
firstNode = firstNode.getParentOrThrow();
|
|
994
864
|
}
|
|
995
|
-
|
|
996
865
|
if (lexical.$isTextNode(lastNode)) {
|
|
997
866
|
lastType = 'text';
|
|
998
867
|
lastOffset = lastNode.getTextContentSize();
|
|
999
868
|
} else if (!lexical.$isElementNode(lastNode) && lastNode !== null) {
|
|
1000
869
|
lastNode = lastNode.getParentOrThrow();
|
|
1001
870
|
}
|
|
1002
|
-
|
|
1003
871
|
if (firstNode && lastNode) {
|
|
1004
872
|
anchor.set(firstNode.getKey(), 0, firstType);
|
|
1005
873
|
focus.set(lastNode.getKey(), lastOffset, lastType);
|
|
1006
874
|
}
|
|
1007
875
|
}
|
|
876
|
+
|
|
1008
877
|
/**
|
|
1009
878
|
* Returns the current value of a CSS property for Nodes, if set. If not set, it returns the defaultValue.
|
|
1010
879
|
* @param node - The node whose style value to get.
|
|
@@ -1012,17 +881,15 @@ function $selectAll(selection) {
|
|
|
1012
881
|
* @param defaultValue - The default value for the property.
|
|
1013
882
|
* @returns The value of the property for node.
|
|
1014
883
|
*/
|
|
1015
|
-
|
|
1016
884
|
function $getNodeStyleValueForProperty(node, styleProperty, defaultValue) {
|
|
1017
885
|
const css = node.getStyle();
|
|
1018
886
|
const styleObject = getStyleObjectFromCSS(css);
|
|
1019
|
-
|
|
1020
887
|
if (styleObject !== null) {
|
|
1021
888
|
return styleObject[styleProperty] || defaultValue;
|
|
1022
889
|
}
|
|
1023
|
-
|
|
1024
890
|
return defaultValue;
|
|
1025
891
|
}
|
|
892
|
+
|
|
1026
893
|
/**
|
|
1027
894
|
* Returns the current value of a CSS property for TextNodes in the Selection, if set. If not set, it returns the defaultValue.
|
|
1028
895
|
* If all TextNodes do not have the same value, it returns an empty string.
|
|
@@ -1031,8 +898,6 @@ function $getNodeStyleValueForProperty(node, styleProperty, defaultValue) {
|
|
|
1031
898
|
* @param defaultValue - The default value for the property, defaults to an empty string.
|
|
1032
899
|
* @returns The value of the property for the selected TextNodes.
|
|
1033
900
|
*/
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
901
|
function $getSelectionStyleValueForProperty(selection, styleProperty, defaultValue = '') {
|
|
1037
902
|
let styleValue = null;
|
|
1038
903
|
const nodes = selection.getNodes();
|
|
@@ -1041,28 +906,24 @@ function $getSelectionStyleValueForProperty(selection, styleProperty, defaultVal
|
|
|
1041
906
|
const isBackward = selection.isBackward();
|
|
1042
907
|
const endOffset = isBackward ? focus.offset : anchor.offset;
|
|
1043
908
|
const endNode = isBackward ? focus.getNode() : anchor.getNode();
|
|
1044
|
-
|
|
1045
|
-
if (selection.style !== '') {
|
|
909
|
+
if (selection.isCollapsed() && selection.style !== '') {
|
|
1046
910
|
const css = selection.style;
|
|
1047
911
|
const styleObject = getStyleObjectFromCSS(css);
|
|
1048
|
-
|
|
1049
912
|
if (styleObject !== null && styleProperty in styleObject) {
|
|
1050
913
|
return styleObject[styleProperty];
|
|
1051
914
|
}
|
|
1052
915
|
}
|
|
1053
|
-
|
|
1054
916
|
for (let i = 0; i < nodes.length; i++) {
|
|
1055
|
-
const node = nodes[i];
|
|
917
|
+
const node = nodes[i];
|
|
918
|
+
|
|
919
|
+
// if no actual characters in the end node are selected, we don't
|
|
1056
920
|
// include it in the selection for purposes of determining style
|
|
1057
921
|
// value
|
|
1058
|
-
|
|
1059
922
|
if (i !== 0 && endOffset === 0 && node.is(endNode)) {
|
|
1060
923
|
continue;
|
|
1061
924
|
}
|
|
1062
|
-
|
|
1063
925
|
if (lexical.$isTextNode(node)) {
|
|
1064
926
|
const nodeStyleValue = $getNodeStyleValueForProperty(node, styleProperty, defaultValue);
|
|
1065
|
-
|
|
1066
927
|
if (styleValue === null) {
|
|
1067
928
|
styleValue = nodeStyleValue;
|
|
1068
929
|
} else if (styleValue !== nodeStyleValue) {
|
|
@@ -1073,10 +934,32 @@ function $getSelectionStyleValueForProperty(selection, styleProperty, defaultVal
|
|
|
1073
934
|
}
|
|
1074
935
|
}
|
|
1075
936
|
}
|
|
1076
|
-
|
|
1077
937
|
return styleValue === null ? defaultValue : styleValue;
|
|
1078
938
|
}
|
|
1079
939
|
|
|
940
|
+
/**
|
|
941
|
+
* This function is for internal use of the library.
|
|
942
|
+
* Please do not use it as it may change in the future.
|
|
943
|
+
*/
|
|
944
|
+
function INTERNAL_$isBlock(node) {
|
|
945
|
+
if (lexical.$isDecoratorNode(node) && !node.isInline()) {
|
|
946
|
+
return true;
|
|
947
|
+
}
|
|
948
|
+
if (!lexical.$isElementNode(node) || lexical.$isRootOrShadowRoot(node)) {
|
|
949
|
+
return false;
|
|
950
|
+
}
|
|
951
|
+
const firstChild = node.getFirstChild();
|
|
952
|
+
const isLeafElement = firstChild === null || lexical.$isLineBreakNode(firstChild) || lexical.$isTextNode(firstChild) || firstChild.isInline();
|
|
953
|
+
return !node.isInline() && node.canBeEmpty() !== false && isLeafElement;
|
|
954
|
+
}
|
|
955
|
+
function $getAncestor(node, predicate) {
|
|
956
|
+
let parent = node;
|
|
957
|
+
while (parent !== null && parent.getParent() !== null && !predicate(parent)) {
|
|
958
|
+
parent = parent.getParentOrThrow();
|
|
959
|
+
}
|
|
960
|
+
return predicate(parent) ? parent : null;
|
|
961
|
+
}
|
|
962
|
+
|
|
1080
963
|
exports.$addNodeStyle = $addNodeStyle;
|
|
1081
964
|
exports.$cloneWithProperties = $cloneWithProperties;
|
|
1082
965
|
exports.$getSelectionStyleValueForProperty = $getSelectionStyleValueForProperty;
|
package/LexicalSelection.prod.js
CHANGED
|
@@ -4,27 +4,27 @@
|
|
|
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 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
|
|
8
|
-
function A(a){let b="";for(let
|
|
9
|
-
function C(a,b){var
|
|
10
|
-
a=r?
|
|
11
|
-
a!==h&&([
|
|
12
|
-
function E(a,b,
|
|
13
|
-
q&&k.$isLeafNode(n)&&!r.has(n.getKey())){if(n=q.getKey(),void 0===h.get(n)){let t=
|
|
14
|
-
|
|
15
|
-
null!==b?b.selectEnd():a.dirty=!0}}function F(a,b,
|
|
16
|
-
exports.$cloneWithProperties=function(a){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};
|
|
17
|
-
exports.$getSelectionStyleValueForProperty=function(a,b,
|
|
18
|
-
exports.$isAtNodeEnd=function(a){return"text"===a.type?a.offset===a.getNode().getTextContentSize():a.offset===a.getNode().getChildrenSize()};exports.$isParentElementRTL=G;exports.$moveCaretSelection=F;exports.$moveCharacter=function(a,b,
|
|
19
|
-
exports.$selectAll=function(a){let b=a.anchor;a=a.focus;var
|
|
20
|
-
exports.$setBlocksType=function(a,b){if("root"===a.anchor.key){b=b();var
|
|
21
|
-
|
|
22
|
-
exports.$sliceSelectedTextNodeContent=function(a,b){if(b.isSelected()&&!b.isSegmented()&&!b.isToken()&&(k.$isRangeSelection(a)||k.DEPRECATED_$isGridSelection(a))){var
|
|
23
|
-
exports.$wrapNodes=function(a,b,
|
|
24
|
-
|
|
25
|
-
exports.createDOMRange=function(a,b,
|
|
26
|
-
|
|
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 d of a)if(""!==d){let [f,c]=d.split(/:([^]+)/);b[f.trim()]=c.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 d in a)d&&(b+=`${d}: ${a[d]};`);return b}function B(a,b){var d=z("getStyle"in a?a.getStyle():a.style);b=Object.entries(b).reduce((f,[c,g])=>{null===g?delete f[c]:f[c]=g;return f},{...d});d=A(b);a.setStyle(d);u.set(d,b)}
|
|
9
|
+
function C(a,b){var d=a.getNodes(),f=d.length;if(k.DEPRECATED_$isGridSelection(a)){var c=k.$createRangeSelection(),g=c.anchor,h=c.focus;for(var e=0;e<f;e++){var l=d[e];k.DEPRECATED_$isGridCellNode(l)&&(g.set(l.getKey(),0,"element"),h.set(l.getKey(),l.getChildrenSize(),"element"),C(k.$normalizeSelection__EXPERIMENTAL(c),b))}k.$setSelection(a)}else if(--f,c=d[0],g=d[f],a.isCollapsed())B(a,b);else{e=a.anchor;var m=a.focus;l=c.getTextContent().length;var p=m.offset,n=e.offset,r=e.isBefore(m);h=r?n:p;
|
|
10
|
+
a=r?p:n;var q=r?e.type:m.type,t=r?m.type:e.type;m=r?m.key:e.key;k.$isTextNode(c)&&h===l&&(r=c.getNextSibling(),k.$isTextNode(r)&&(h=n=0,c=r));if(1===d.length)k.$isTextNode(c)&&(h="element"===q?0:n>p?p:n,a="element"===t?l:n>p?n:p,h!==a&&(0===h&&a===l?(B(c,b),c.select(h,a)):(d=c.splitText(h,a),d=0===h?d[0]:d[1],B(d,b),d.select(0,a-h))));else for(k.$isTextNode(c)&&h<c.getTextContentSize()&&(0!==h&&(c=c.splitText(h)[1],h=0,e.set(c.getKey(),h,"text")),B(c,b)),k.$isTextNode(g)&&(h=g.getTextContent().length,
|
|
11
|
+
g.__key!==m&&0!==a&&(a=h),a!==h&&([g]=g.splitText(a)),0!==a&&B(g,b)),a=1;a<f;a++)h=d[a],e=h.getKey(),k.$isTextNode(h)&&e!==c.getKey()&&e!==g.getKey()&&!h.isToken()&&B(h,b)}}function D(a){for(;null!==a&&!k.$isRootOrShadowRoot(a);){let b=a.getLatest(),d=a.getParent();0===b.getChildrenSize()&&a.remove(!0);a=d}}
|
|
12
|
+
function E(a,b,d,f,c=null){if(0!==b.length){var g=b[0],h=new Map,e=[];g=k.$isElementNode(g)?g:g.getParentOrThrow();g.isInline()&&(g=g.getParentOrThrow());for(var l=!1;null!==g;){var m=g.getPreviousSibling();if(null!==m){g=m;l=!0;break}g=g.getParentOrThrow();if(k.$isRootOrShadowRoot(g))break}m=new Set;for(var p=0;p<d;p++){var n=b[p];k.$isElementNode(n)&&0===n.getChildrenSize()&&m.add(n.getKey())}var r=new Set;for(p=0;p<d;p++){n=b[p];var q=n.getParent();null!==q&&q.isInline()&&(q=q.getParent());if(null!==
|
|
13
|
+
q&&k.$isLeafNode(n)&&!r.has(n.getKey())){if(n=q.getKey(),void 0===h.get(n)){let t=f();t.setFormat(q.getFormatType());t.setIndent(q.getIndent());e.push(t);h.set(n,t);q.getChildren().forEach(x=>{t.append(x);r.add(x.getKey());k.$isElementNode(x)&&x.getChildrenKeys().forEach(I=>r.add(I))});D(q)}}else m.has(n.getKey())&&(q=f(),q.setFormat(n.getFormatType()),q.setIndent(n.getIndent()),e.push(q),n.remove(!0))}if(null!==c)for(b=0;b<e.length;b++)c.append(e[b]);b=null;if(k.$isRootOrShadowRoot(g))if(l)if(null!==
|
|
14
|
+
c)g.insertAfter(c);else for(c=e.length-1;0<=c;c--)g.insertAfter(e[c]);else if(l=g.getFirstChild(),k.$isElementNode(l)&&(g=l),null===l)if(c)g.append(c);else for(c=0;c<e.length;c++)l=e[c],g.append(l),b=l;else if(null!==c)l.insertBefore(c);else for(g=0;g<e.length;g++)c=e[g],l.insertBefore(c),b=c;else if(c)g.insertAfter(c);else for(c=e.length-1;0<=c;c--)l=e[c],g.insertAfter(l),b=l;e=k.$getPreviousSelection();k.$isRangeSelection(e)&&e.anchor.getNode().isAttached()&&e.focus.getNode().isAttached()?k.$setSelection(e.clone()):
|
|
15
|
+
null!==b?b.selectEnd():a.dirty=!0}}function F(a,b,d,f){a.modify(b?"extend":"move",d,f)}function G(a){a=a.anchor.getNode();return"rtl"===(k.$isRootNode(a)?a:a.getParentOrThrow()).getDirection()}function H(a){if(k.$isDecoratorNode(a)&&!a.isInline())return!0;if(!k.$isElementNode(a)||k.$isRootOrShadowRoot(a))return!1;var b=a.getFirstChild();b=null===b||k.$isLineBreakNode(b)||k.$isTextNode(b)||b.isInline();return!a.isInline()&&!1!==a.canBeEmpty()&&b}
|
|
16
|
+
exports.$addNodeStyle=function(a){a=a.getStyle();let b=y(a);u.set(a,b)};exports.$cloneWithProperties=function(a){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};
|
|
17
|
+
exports.$getSelectionStyleValueForProperty=function(a,b,d=""){let f=null,c=a.getNodes();var g=a.anchor,h=a.focus,e=a.isBackward();let l=e?h.offset:g.offset;g=e?h.getNode():g.getNode();if(a.isCollapsed()&&""!==a.style&&(a=z(a.style),null!==a&&b in a))return a[b];for(a=0;a<c.length;a++){var m=c[a];if((0===a||0!==l||!m.is(g))&&k.$isTextNode(m))if(h=b,e=d,m=m.getStyle(),m=z(m),h=null!==m?m[h]||e:e,null===f)f=h;else if(f!==h){f="";break}}return null===f?d:f};
|
|
18
|
+
exports.$isAtNodeEnd=function(a){return"text"===a.type?a.offset===a.getNode().getTextContentSize():a.offset===a.getNode().getChildrenSize()};exports.$isParentElementRTL=G;exports.$moveCaretSelection=F;exports.$moveCharacter=function(a,b,d){let f=G(a);F(a,b,d?!f:f,"character")};exports.$patchStyleText=C;
|
|
19
|
+
exports.$selectAll=function(a){let b=a.anchor;a=a.focus;var d=b.getNode().getTopLevelElementOrThrow().getParentOrThrow();let f=d.getFirstDescendant();d=d.getLastDescendant();let c="element",g="element",h=0;k.$isTextNode(f)?c="text":k.$isElementNode(f)||null===f||(f=f.getParentOrThrow());k.$isTextNode(d)?(g="text",h=d.getTextContentSize()):k.$isElementNode(d)||null===d||(d=d.getParentOrThrow());f&&d&&(b.set(f.getKey(),0,c),a.set(d.getKey(),h,g))};
|
|
20
|
+
exports.$setBlocksType=function(a,b){if("root"===a.anchor.key){b=b();var d=k.$getRoot();(a=d.getFirstChild())?a.replace(b,!0):d.append(b)}else{d=a.getNodes();for(a=a.anchor.getNode();null!==a&&null!==a.getParent()&&!H(a);)a=a.getParentOrThrow();(a=H(a)?a:null)&&-1===d.indexOf(a)&&d.push(a);for(a=0;a<d.length;a++){let f=d[a];if(!H(f))continue;let c=b();c.setFormat(f.getFormatType());c.setIndent(f.getIndent());f.replace(c,!0)}}};
|
|
21
|
+
exports.$shouldOverrideDefaultCharacterSelection=function(a,b){a=k.$getAdjacentNode(a.focus,b);return k.$isDecoratorNode(a)&&!a.isIsolated()||k.$isElementNode(a)&&!a.isInline()&&!a.canBeEmpty()};
|
|
22
|
+
exports.$sliceSelectedTextNodeContent=function(a,b){if(b.isSelected()&&!b.isSegmented()&&!b.isToken()&&(k.$isRangeSelection(a)||k.DEPRECATED_$isGridSelection(a))){var d=a.anchor.getNode(),f=a.focus.getNode(),c=b.is(d),g=b.is(f);if(c||g){c=a.isBackward();let [h,e]=a.getCharacterOffsets();a=d.is(f);g=b.is(c?f:d);f=b.is(c?d:f);d=0;let l=void 0;a?(d=h>e?e:h,l=h>e?h:e):g?(d=c?e:h,l=void 0):f&&(c=c?h:e,d=0,l=c);b.__text=b.__text.slice(d,l)}}return b};
|
|
23
|
+
exports.$wrapNodes=function(a,b,d=null){var f=a.getNodes();let c=f.length;var g=a.anchor;if(0===c||1===c&&"element"===g.type&&0===g.getNode().getChildrenSize()){a="text"===g.type?g.getNode().getParentOrThrow():g.getNode();f=a.getChildren();let e=b();e.setFormat(a.getFormatType());e.setIndent(a.getIndent());f.forEach(l=>e.append(l));d&&(e=d.append(e));a.replace(e)}else{g=null;var h=[];for(let e=0;e<c;e++){let l=f[e];k.$isRootOrShadowRoot(l)?(E(a,h,h.length,b,d),h=[],g=l):null===g||null!==g&&k.$hasAncestor(l,
|
|
24
|
+
g)?h.push(l):(E(a,h,h.length,b,d),h=[l])}E(a,h,h.length,b,d)}};
|
|
25
|
+
exports.createDOMRange=function(a,b,d,f,c){let g=b.getKey(),h=f.getKey(),e=document.createRange(),l=a.getElementByKey(g);a=a.getElementByKey(h);k.$isTextNode(b)&&(l=v(l));k.$isTextNode(f)&&(a=v(a));if(void 0===b||void 0===f||null===l||null===a)return null;"BR"===l.nodeName&&([l,d]=w(l));"BR"===a.nodeName&&([a,c]=w(a));b=l.firstChild;l===a&&null!=b&&"BR"===b.nodeName&&0===d&&0===c&&(c=1);try{e.setStart(l,d),e.setEnd(a,c)}catch(m){return null}!e.collapsed||d===c&&g===h||(e.setStart(a,c),e.setEnd(l,
|
|
26
|
+
d));return e};exports.createRectsFromDOMRange=function(a,b){var d=a.getRootElement();if(null===d)return[];a=d.getBoundingClientRect();d=getComputedStyle(d);d=parseFloat(d.paddingLeft)+parseFloat(d.paddingRight);b=Array.from(b.getClientRects());let f=b.length;b.sort((g,h)=>{let e=g.top-h.top;return 3>=Math.abs(e)?g.left-h.left:e});let c;for(let g=0;g<f;g++){let h=b[g],e=h.width+d===a.width;c&&c.top<=h.top&&c.top+c.height>h.top&&c.left+c.width>h.left||e?(b.splice(g--,1),f--):c=h}return b};
|
|
27
27
|
exports.getStyleObjectFromCSS=z;
|
|
28
|
-
exports.trimTextContentFromAnchor=function(a,b,
|
|
29
|
-
|
|
30
|
-
c))):
|
|
28
|
+
exports.trimTextContentFromAnchor=function(a,b,d){let f=b.getNode();if(k.$isElementNode(f)){var c=f.getDescendantByIndex(b.offset);null!==c&&(f=c)}for(;0<d&&null!==f;){k.$isElementNode(f)&&(c=f.getLastDescendant(),null!==c&&(f=c));var g=f.getPreviousSibling(),h=0;if(null===g){c=f.getParentOrThrow();for(var e=c.getPreviousSibling();null===e;){c=c.getParent();if(null===c){g=null;break}e=c.getPreviousSibling()}null!==c&&(h=c.isInline()?0:2,g=e)}e=f.getTextContent();""===e&&k.$isElementNode(f)&&!f.isInline()&&
|
|
29
|
+
(e="\n\n");c=e.length;if(!k.$isTextNode(f)||d>=c)e=f.getParent(),f.remove(),null==e||0!==e.getChildrenSize()||k.$isRootNode(e)||e.remove(),d-=c+h,f=g;else{let l=f.getKey();h=a.getEditorState().read(()=>{const p=k.$getNodeByKey(l);return k.$isTextNode(p)&&p.isSimpleText()?p.getTextContent():null});g=c-d;let m=e.slice(0,g);null!==h&&h!==e?(d=k.$getPreviousSelection(),c=f,f.isSimpleText()?f.setTextContent(h):(c=k.$createTextNode(h),f.replace(c)),k.$isRangeSelection(d)&&d.isCollapsed()&&(d=d.anchor.offset,
|
|
30
|
+
c.select(d,d))):f.isSimpleText()?(h=b.key===l,e=b.offset,e<d&&(e=c),d=h?e-d:0,c=h?e:g,h&&0===d?([d]=f.splitText(d,c),d.remove()):([,d]=f.splitText(d,c),d.remove())):(d=k.$createTextNode(m),f.replace(d));d=0}}}
|
package/package.json
CHANGED
package/range-selection.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
import type { ElementNode, GridSelection, LexicalNode, RangeSelection } from 'lexical';
|
|
8
|
+
import type { DecoratorNode, ElementNode, GridSelection, LexicalNode, RangeSelection } from 'lexical';
|
|
9
9
|
/**
|
|
10
10
|
* Converts all nodes in the selection that are of one block type to another.
|
|
11
11
|
* @param selection - The selected blocks to be converted.
|
|
@@ -72,3 +72,9 @@ export declare function $selectAll(selection: RangeSelection): void;
|
|
|
72
72
|
* @returns The value of the property for the selected TextNodes.
|
|
73
73
|
*/
|
|
74
74
|
export declare function $getSelectionStyleValueForProperty(selection: RangeSelection, styleProperty: string, defaultValue?: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* This function is for internal use of the library.
|
|
77
|
+
* Please do not use it as it may change in the future.
|
|
78
|
+
*/
|
|
79
|
+
export declare function INTERNAL_$isBlock(node: LexicalNode): node is ElementNode | DecoratorNode<unknown>;
|
|
80
|
+
export declare function $getAncestor<NodeType extends LexicalNode = LexicalNode>(node: LexicalNode, predicate: (ancestor: LexicalNode) => ancestor is NodeType): NodeType | null;
|