@lexical/selection 0.1.15

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Dominic Gannaway
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,579 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ 'use strict';
8
+
9
+ var lexical = require('lexical');
10
+
11
+ /**
12
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
13
+ *
14
+ * This source code is licensed under the MIT license found in the
15
+ * LICENSE file in the root directory of this source tree.
16
+ *
17
+ *
18
+ */
19
+ const cssToStyles = new Map();
20
+
21
+ function $cloneWithProperties(node) {
22
+ const latest = node.getLatest();
23
+ const constructor = latest.constructor;
24
+ const clone = constructor.clone(latest);
25
+ clone.__parent = latest.__parent;
26
+
27
+ if (lexical.$isElementNode(latest) && lexical.$isElementNode(clone)) {
28
+ clone.__children = Array.from(latest.__children);
29
+ clone.__format = latest.__format;
30
+ clone.__indent = latest.__indent;
31
+ clone.__dir = latest.__dir;
32
+ } else if (lexical.$isTextNode(latest) && lexical.$isTextNode(clone)) {
33
+ clone.__format = latest.__format;
34
+ clone.__style = latest.__style;
35
+ clone.__mode = latest.__mode;
36
+ clone.__detail = latest.__detail;
37
+ } else if (lexical.$isDecoratorNode(latest) && lexical.$isDecoratorNode(clone)) {
38
+ clone.__state = latest.__state;
39
+ } // $FlowFixMe
40
+
41
+
42
+ return clone;
43
+ }
44
+
45
+ function $getIndexFromPossibleClone(node, parent, nodeMap) {
46
+ const parentClone = nodeMap.get(parent.getKey());
47
+
48
+ if (lexical.$isElementNode(parentClone)) {
49
+ return parentClone.__children.indexOf(node.getKey());
50
+ }
51
+
52
+ return node.getIndexWithinParent();
53
+ }
54
+
55
+ function $getParentAvoidingExcludedElements(node) {
56
+ let parent = node.getParent();
57
+
58
+ while (parent !== null && parent.excludeFromCopy()) {
59
+ parent = parent.getParent();
60
+ }
61
+
62
+ return parent;
63
+ }
64
+
65
+ function $copyLeafNodeBranchToRoot(leaf, startingOffset, isLeftSide, range, nodeMap) {
66
+ let node = leaf;
67
+ let offset = startingOffset;
68
+
69
+ while (node !== null) {
70
+ const parent = $getParentAvoidingExcludedElements(node);
71
+
72
+ if (parent === null) {
73
+ break;
74
+ }
75
+
76
+ if (!lexical.$isElementNode(node) || !node.excludeFromCopy()) {
77
+ const key = node.getKey();
78
+ let clone = nodeMap.get(key);
79
+ const needsClone = clone === undefined;
80
+
81
+ if (needsClone) {
82
+ clone = $cloneWithProperties(node);
83
+ nodeMap.set(key, clone);
84
+ }
85
+
86
+ if (lexical.$isTextNode(clone) && !clone.isSegmented() && !clone.isToken()) {
87
+ clone.__text = clone.__text.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset);
88
+ } else if (lexical.$isElementNode(clone)) {
89
+ clone.__children = clone.__children.slice(isLeftSide ? offset : 0, isLeftSide ? undefined : offset + 1);
90
+ }
91
+
92
+ if (lexical.$isRootNode(parent)) {
93
+ if (needsClone) {
94
+ // We only want to collect a range of top level nodes.
95
+ // So if the parent is the root, we know this is a top level.
96
+ range.push(key);
97
+ }
98
+
99
+ break;
100
+ }
101
+ }
102
+
103
+ offset = $getIndexFromPossibleClone(node, parent, nodeMap);
104
+ node = parent;
105
+ }
106
+ }
107
+
108
+ function $cloneContents(selection) {
109
+ if (!lexical.$isRangeSelection(selection)) {
110
+ {
111
+ throw Error(`TODO`);
112
+ }
113
+ }
114
+
115
+ const anchor = selection.anchor;
116
+ const focus = selection.focus;
117
+ const anchorOffset = anchor.getCharacterOffset();
118
+ const focusOffset = focus.getCharacterOffset();
119
+ const anchorNode = anchor.getNode();
120
+ const focusNode = focus.getNode();
121
+ const anchorNodeParent = anchorNode.getParentOrThrow(); // Handle a single text node extraction
122
+
123
+ if (anchorNode === focusNode && lexical.$isTextNode(anchorNode) && (anchorNodeParent.canBeEmpty() || anchorNodeParent.getChildrenSize() > 1)) {
124
+ const clonedFirstNode = $cloneWithProperties(anchorNode);
125
+ const isBefore = focusOffset > anchorOffset;
126
+ const startOffset = isBefore ? anchorOffset : focusOffset;
127
+ const endOffset = isBefore ? focusOffset : anchorOffset;
128
+ clonedFirstNode.__text = clonedFirstNode.__text.slice(startOffset, endOffset);
129
+ const key = clonedFirstNode.getKey();
130
+ return {
131
+ nodeMap: [[key, clonedFirstNode]],
132
+ range: [key]
133
+ };
134
+ }
135
+
136
+ const nodes = selection.getNodes();
137
+
138
+ if (nodes.length === 0) {
139
+ return {
140
+ nodeMap: [],
141
+ range: []
142
+ };
143
+ } // Check if we can use the parent of the nodes, if the
144
+ // parent can't be empty, then it's important that we
145
+ // also copy that element node along with its children.
146
+
147
+
148
+ let nodesLength = nodes.length;
149
+ const firstNode = nodes[0];
150
+ const firstNodeParent = firstNode.getParent();
151
+
152
+ if (firstNodeParent !== null && (!firstNodeParent.canBeEmpty() || lexical.$isRootNode(firstNodeParent))) {
153
+ const parentChildren = firstNodeParent.__children;
154
+ const parentChildrenLength = parentChildren.length;
155
+
156
+ if (parentChildrenLength === nodesLength) {
157
+ let areTheSame = true;
158
+
159
+ for (let i = 0; i < parentChildren.length; i++) {
160
+ if (parentChildren[i] !== nodes[i].__key) {
161
+ areTheSame = false;
162
+ break;
163
+ }
164
+ }
165
+
166
+ if (areTheSame) {
167
+ nodesLength++;
168
+ nodes.push(firstNodeParent);
169
+ }
170
+ }
171
+ }
172
+
173
+ const lastNode = nodes[nodesLength - 1];
174
+ const isBefore = anchor.isBefore(focus);
175
+ const nodeMap = new Map();
176
+ const range = []; // Do first node to root
177
+
178
+ $copyLeafNodeBranchToRoot(firstNode, isBefore ? anchorOffset : focusOffset, true, range, nodeMap); // Copy all nodes between
179
+
180
+ for (let i = 0; i < nodesLength; i++) {
181
+ const node = nodes[i];
182
+ const key = node.getKey();
183
+
184
+ if (!nodeMap.has(key) && (!lexical.$isElementNode(node) || !node.excludeFromCopy())) {
185
+ const clone = $cloneWithProperties(node);
186
+
187
+ if (lexical.$isRootNode(node.getParent())) {
188
+ range.push(node.getKey());
189
+ }
190
+
191
+ nodeMap.set(key, clone);
192
+ }
193
+ } // Do last node to root
194
+
195
+
196
+ $copyLeafNodeBranchToRoot(lastNode, isBefore ? focusOffset : anchorOffset, false, range, nodeMap);
197
+ return {
198
+ nodeMap: Array.from(nodeMap.entries()),
199
+ range
200
+ };
201
+ }
202
+ function getStyleObjectFromCSS(css) {
203
+ return cssToStyles.get(css) || null;
204
+ }
205
+
206
+ function getCSSFromStyleObject(styles) {
207
+ let css = '';
208
+
209
+ for (const style in styles) {
210
+ if (style) {
211
+ css += `${style}: ${styles[style]};`;
212
+ }
213
+ }
214
+
215
+ return css;
216
+ }
217
+
218
+ function $patchNodeStyle(node, patch) {
219
+ const prevStyles = getStyleObjectFromCSS(node.getStyle());
220
+ const newStyles = prevStyles ? { ...prevStyles,
221
+ ...patch
222
+ } : patch;
223
+ const newCSSText = getCSSFromStyleObject(newStyles);
224
+ node.setStyle(newCSSText);
225
+ cssToStyles.set(newCSSText, newStyles);
226
+ }
227
+
228
+ function $patchStyleText(selection, patch) {
229
+ const selectedNodes = selection.getNodes();
230
+ const selectedNodesLength = selectedNodes.length;
231
+ const lastIndex = selectedNodesLength - 1;
232
+ let firstNode = selectedNodes[0];
233
+ let lastNode = selectedNodes[lastIndex];
234
+
235
+ if (selection.isCollapsed()) {
236
+ return;
237
+ }
238
+
239
+ const anchor = selection.anchor;
240
+ const focus = selection.focus;
241
+ const firstNodeText = firstNode.getTextContent();
242
+ const firstNodeTextLength = firstNodeText.length;
243
+ const focusOffset = focus.offset;
244
+ let anchorOffset = anchor.offset;
245
+ let startOffset;
246
+ let endOffset;
247
+ const isBefore = anchor.isBefore(focus);
248
+ startOffset = isBefore ? anchorOffset : focusOffset;
249
+ endOffset = isBefore ? focusOffset : anchorOffset; // This is the case where the user only selected the very end of the
250
+ // first node so we don't want to include it in the formatting change.
251
+
252
+ if (startOffset === firstNode.getTextContentSize()) {
253
+ const nextSibling = firstNode.getNextSibling();
254
+
255
+ if (lexical.$isTextNode(nextSibling)) {
256
+ // we basically make the second node the firstNode, changing offsets accordingly
257
+ anchorOffset = 0;
258
+ startOffset = 0;
259
+ firstNode = nextSibling;
260
+ }
261
+ } // This is the case where we only selected a single node
262
+
263
+
264
+ if (firstNode.is(lastNode)) {
265
+ if (lexical.$isTextNode(firstNode)) {
266
+ startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset;
267
+ endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset; // No actual text is selected, so do nothing.
268
+
269
+ if (startOffset === endOffset) {
270
+ return;
271
+ } // The entire node is selected, so just format it
272
+
273
+
274
+ if (startOffset === 0 && endOffset === firstNodeTextLength) {
275
+ $patchNodeStyle(firstNode, patch);
276
+ firstNode.select(startOffset, endOffset);
277
+ } else {
278
+ // The node is partially selected, so split it into two nodes
279
+ // and style the selected one.
280
+ const splitNodes = firstNode.splitText(startOffset, endOffset);
281
+ const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1];
282
+ $patchNodeStyle(replacement, patch);
283
+ replacement.select(0, endOffset - startOffset);
284
+ }
285
+ } // multiple nodes selected.
286
+
287
+ } else {
288
+ if (lexical.$isTextNode(firstNode)) {
289
+ if (startOffset !== 0) {
290
+ // the entire first node isn't selected, so split it
291
+ [, firstNode] = firstNode.splitText(startOffset);
292
+ startOffset = 0;
293
+ }
294
+
295
+ $patchNodeStyle(firstNode, patch);
296
+ }
297
+
298
+ if (lexical.$isTextNode(lastNode)) {
299
+ const lastNodeText = lastNode.getTextContent();
300
+ const lastNodeTextLength = lastNodeText.length; // if the entire last node isn't selected, split it
301
+
302
+ if (endOffset !== lastNodeTextLength) {
303
+ [lastNode] = lastNode.splitText(endOffset);
304
+ }
305
+
306
+ if (endOffset !== 0) {
307
+ $patchNodeStyle(lastNode, patch);
308
+ }
309
+ } // style all the text nodes in between
310
+
311
+
312
+ for (let i = 1; i < lastIndex; i++) {
313
+ const selectedNode = selectedNodes[i];
314
+ const selectedNodeKey = selectedNode.getKey();
315
+
316
+ if (lexical.$isTextNode(selectedNode) && selectedNodeKey !== firstNode.getKey() && selectedNodeKey !== lastNode.getKey() && !selectedNode.isToken()) {
317
+ $patchNodeStyle(selectedNode, patch);
318
+ }
319
+ }
320
+ }
321
+ }
322
+ function $getSelectionStyleValueForProperty(selection, styleProperty, defaultValue = '') {
323
+ let styleValue = null;
324
+ const nodes = selection.getNodes();
325
+ const anchor = selection.anchor;
326
+ const focus = selection.focus;
327
+ const isBackward = selection.isBackward();
328
+ const endOffset = isBackward ? focus.offset : anchor.offset;
329
+ const endNode = isBackward ? focus.getNode() : anchor.getNode();
330
+
331
+ for (let i = 0; i < nodes.length; i++) {
332
+ const node = nodes[i]; // if no actual characters in the end node are selected, we don't
333
+ // include it in the selection for purposes of determining style
334
+ // value
335
+
336
+ if (i !== 0 && endOffset === 0 && node.is(endNode)) {
337
+ continue;
338
+ }
339
+
340
+ if (lexical.$isTextNode(node)) {
341
+ const nodeStyleValue = $getNodeStyleValueForProperty(node, styleProperty, defaultValue);
342
+
343
+ if (styleValue === null) {
344
+ styleValue = nodeStyleValue;
345
+ } else if (styleValue !== nodeStyleValue) {
346
+ // multiple text nodes are in the selection and they don't all
347
+ // have the same font size.
348
+ styleValue = '';
349
+ break;
350
+ }
351
+ }
352
+ }
353
+
354
+ return styleValue === null ? defaultValue : styleValue;
355
+ }
356
+
357
+ function $getNodeStyleValueForProperty(node, styleProperty, defaultValue) {
358
+ const css = node.getStyle();
359
+ const styleObject = getStyleObjectFromCSS(css);
360
+
361
+ if (styleObject !== null) {
362
+ return styleObject[styleProperty] || defaultValue;
363
+ }
364
+
365
+ return defaultValue;
366
+ }
367
+
368
+ function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) {
369
+ selection.modify(isHoldingShift ? 'extend' : 'move', isBackward, granularity);
370
+ }
371
+ function $isParentElementRTL(selection) {
372
+ const anchorNode = selection.anchor.getNode();
373
+ const parent = lexical.$isRootNode(anchorNode) ? anchorNode : anchorNode.getParentOrThrow();
374
+ return parent.getDirection() === 'rtl';
375
+ }
376
+ function $moveCharacter(selection, isHoldingShift, isBackward) {
377
+ const isRTL = $isParentElementRTL(selection);
378
+ $moveCaretSelection(selection, isHoldingShift, isBackward ? !isRTL : isRTL, 'character');
379
+ }
380
+ function $selectAll(selection) {
381
+ const anchor = selection.anchor;
382
+ const focus = selection.focus;
383
+ const anchorNode = anchor.getNode();
384
+ const topParent = anchorNode.getTopLevelElementOrThrow();
385
+ const root = topParent.getParentOrThrow();
386
+ let firstNode = root.getFirstDescendant();
387
+ let lastNode = root.getLastDescendant();
388
+ let firstType = 'element';
389
+ let lastType = 'element';
390
+ let lastOffset = 0;
391
+
392
+ if (lexical.$isTextNode(firstNode)) {
393
+ firstType = 'text';
394
+ } else if (!lexical.$isElementNode(firstNode) && firstNode !== null) {
395
+ firstNode = firstNode.getParentOrThrow();
396
+ }
397
+
398
+ if (lexical.$isTextNode(lastNode)) {
399
+ lastType = 'text';
400
+ lastOffset = lastNode.getTextContentSize();
401
+ } else if (!lexical.$isElementNode(lastNode) && lastNode !== null) {
402
+ lastNode = lastNode.getParentOrThrow();
403
+ lastOffset = lastNode.getChildrenSize();
404
+ }
405
+
406
+ if (firstNode && lastNode) {
407
+ anchor.set(firstNode.getKey(), 0, firstType);
408
+ focus.set(lastNode.getKey(), lastOffset, lastType);
409
+ }
410
+ }
411
+
412
+ function $removeParentEmptyElements(startingNode) {
413
+ let node = startingNode;
414
+
415
+ while (node !== null && !lexical.$isRootNode(node)) {
416
+ const latest = node.getLatest();
417
+ const parentNode = node.getParent();
418
+
419
+ if (latest.__children.length === 0) {
420
+ node.remove();
421
+ }
422
+
423
+ node = parentNode;
424
+ }
425
+ }
426
+
427
+ function $wrapLeafNodesInElements(selection, createElement, wrappingElement) {
428
+ const nodes = selection.getNodes();
429
+ const nodesLength = nodes.length;
430
+
431
+ if (nodesLength === 0) {
432
+ const anchor = selection.anchor;
433
+ const target = anchor.type === 'text' ? anchor.getNode().getParentOrThrow() : anchor.getNode();
434
+ const children = target.getChildren();
435
+ let element = createElement();
436
+ children.forEach(child => element.append(child));
437
+
438
+ if (wrappingElement) {
439
+ element = wrappingElement.append(element);
440
+ }
441
+
442
+ target.replace(element);
443
+ return;
444
+ }
445
+
446
+ const firstNode = nodes[0];
447
+ const elementMapping = new Map();
448
+ const elements = []; // The below logic is to find the right target for us to
449
+ // either insertAfter/insertBefore/append the corresponding
450
+ // elements to. This is made more complicated due to nested
451
+ // structures.
452
+
453
+ let target = lexical.$isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
454
+
455
+ while (target !== null) {
456
+ const prevSibling = target.getPreviousSibling();
457
+
458
+ if (prevSibling !== null) {
459
+ target = prevSibling;
460
+ break;
461
+ }
462
+
463
+ target = target.getParentOrThrow();
464
+
465
+ if (lexical.$isRootNode(target)) {
466
+ break;
467
+ }
468
+ }
469
+
470
+ const emptyElements = new Set(); // Find any top level empty elements
471
+
472
+ for (let i = 0; i < nodesLength; i++) {
473
+ const node = nodes[i];
474
+
475
+ if (lexical.$isElementNode(node) && node.getChildrenSize() === 0) {
476
+ emptyElements.add(node.getKey());
477
+ }
478
+ }
479
+
480
+ const movedLeafNodes = new Set(); // Move out all leaf nodes into our elements array.
481
+ // If we find a top level empty element, also move make
482
+ // an element for that.
483
+
484
+ for (let i = 0; i < nodesLength; i++) {
485
+ const node = nodes[i];
486
+ const parent = node.getParent();
487
+
488
+ if (parent !== null && lexical.$isLeafNode(node) && !movedLeafNodes.has(node.getKey())) {
489
+ const parentKey = parent.getKey();
490
+
491
+ if (elementMapping.get(parentKey) === undefined) {
492
+ const targetElement = createElement();
493
+ elements.push(targetElement);
494
+ elementMapping.set(parentKey, targetElement); // Move node and its siblings to the new
495
+ // element.
496
+
497
+ parent.getChildren().forEach(child => {
498
+ targetElement.append(child);
499
+ movedLeafNodes.add(child.getKey());
500
+ });
501
+ $removeParentEmptyElements(parent);
502
+ }
503
+ } else if (emptyElements.has(node.getKey())) {
504
+ elements.push(createElement());
505
+ node.remove();
506
+ }
507
+ }
508
+
509
+ if (wrappingElement) {
510
+ for (let i = 0; i < elements.length; i++) {
511
+ const element = elements[i];
512
+ wrappingElement.append(element);
513
+ }
514
+ } // If our target is the root, let's see if we can re-adjust
515
+ // so that the target is the first child instead.
516
+
517
+
518
+ if (lexical.$isRootNode(target)) {
519
+ const firstChild = target.getFirstChild();
520
+
521
+ if (lexical.$isElementNode(firstChild)) {
522
+ target = firstChild;
523
+ }
524
+
525
+ if (firstChild === null) {
526
+ if (wrappingElement) {
527
+ target.append(wrappingElement);
528
+ } else {
529
+ for (let i = 0; i < elements.length; i++) {
530
+ const element = elements[i];
531
+ target.append(element);
532
+ }
533
+ }
534
+ } else {
535
+ if (wrappingElement) {
536
+ firstChild.insertBefore(wrappingElement);
537
+ } else {
538
+ for (let i = 0; i < elements.length; i++) {
539
+ const element = elements[i];
540
+ firstChild.insertBefore(element);
541
+ }
542
+ }
543
+ }
544
+ } else {
545
+ if (wrappingElement) {
546
+ target.insertAfter(wrappingElement);
547
+ } else {
548
+ for (let i = elements.length - 1; i >= 0; i--) {
549
+ const element = elements[i];
550
+ target.insertAfter(element);
551
+ }
552
+ }
553
+ }
554
+
555
+ selection.dirty = true;
556
+ }
557
+ function $isAtNodeEnd(point) {
558
+ if (point.type === 'text') {
559
+ return point.offset === point.getNode().getTextContentSize();
560
+ }
561
+
562
+ return point.offset === point.getNode().getChildrenSize();
563
+ }
564
+ function $shouldOverrideDefaultCharacterSelection(selection, isBackward) {
565
+ const possibleNode = lexical.$getDecoratorNode(selection.focus, isBackward);
566
+ return lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated();
567
+ }
568
+
569
+ exports.$cloneContents = $cloneContents;
570
+ exports.$getSelectionStyleValueForProperty = $getSelectionStyleValueForProperty;
571
+ exports.$isAtNodeEnd = $isAtNodeEnd;
572
+ exports.$isParentElementRTL = $isParentElementRTL;
573
+ exports.$moveCaretSelection = $moveCaretSelection;
574
+ exports.$moveCharacter = $moveCharacter;
575
+ exports.$patchStyleText = $patchStyleText;
576
+ exports.$selectAll = $selectAll;
577
+ exports.$shouldOverrideDefaultCharacterSelection = $shouldOverrideDefaultCharacterSelection;
578
+ exports.$wrapLeafNodesInElements = $wrapLeafNodesInElements;
579
+ exports.getStyleObjectFromCSS = getStyleObjectFromCSS;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ 'use strict'
8
+ const LexicalSelection = process.env.NODE_ENV === 'development' ? require('./LexicalSelection.dev.js') : require('./LexicalSelection.prod.js')
9
+ module.exports = LexicalSelection;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ var k=require("lexical");const r=new Map;function v(a){a=a.getLatest();const c=a.constructor.clone(a);c.__parent=a.__parent;k.$isElementNode(a)&&k.$isElementNode(c)?(c.__children=Array.from(a.__children),c.__format=a.__format,c.__indent=a.__indent,c.__dir=a.__dir):k.$isTextNode(a)&&k.$isTextNode(c)?(c.__format=a.__format,c.__style=a.__style,c.__mode=a.__mode,c.__detail=a.__detail):k.$isDecoratorNode(a)&&k.$isDecoratorNode(c)&&(c.__state=a.__state);return c}
8
+ function w(a,c,b,g,l){for(var e=c;null!==a;){for(c=a.getParent();null!==c&&c.excludeFromCopy();)c=c.getParent();if(null===c)break;if(!k.$isElementNode(a)||!a.excludeFromCopy()){const d=a.getKey();let f=l.get(d);const h=void 0===f;h&&(f=v(a),l.set(d,f));!k.$isTextNode(f)||f.isSegmented()||f.isToken()?k.$isElementNode(f)&&(f.__children=f.__children.slice(b?e:0,b?void 0:e+1)):f.__text=f.__text.slice(b?e:0,b?void 0:e);if(k.$isRootNode(c)){h&&g.push(d);break}}e=l.get(c.getKey());e=k.$isElementNode(e)?
9
+ e.__children.indexOf(a.getKey()):a.getIndexWithinParent();a=c}}function x(a){return r.get(a)||null}function y(a,c){var b=x(a.getStyle());c=b?{...b,...c}:c;b="";for(g in c)g&&(b+=`${g}: ${c[g]};`);var g=b;a.setStyle(g);r.set(g,c)}function z(a,c,b,g){a.modify(c?"extend":"move",b,g)}function A(a){a=a.anchor.getNode();return"rtl"===(k.$isRootNode(a)?a:a.getParentOrThrow()).getDirection()}
10
+ function B(a){for(;null!==a&&!k.$isRootNode(a);){const c=a.getLatest(),b=a.getParent();0===c.__children.length&&a.remove();a=b}}
11
+ exports.$cloneContents=function(a){if(!k.$isRangeSelection(a))throw Error("Minified Lexical error #68; see codes.json for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");var c=a.anchor,b=a.focus,g=c.getCharacterOffset();const l=b.getCharacterOffset();var e=c.getNode(),d=b.getNode(),f=e.getParentOrThrow();if(e===d&&k.$isTextNode(e)&&(f.canBeEmpty()||1<f.getChildrenSize()))return a=v(e),e=l>g,a.__text=a.__text.slice(e?g:l,e?l:g),g=a.getKey(),
12
+ {nodeMap:[[g,a]],range:[g]};a=a.getNodes();if(0===a.length)return{nodeMap:[],range:[]};e=a.length;d=a[0];f=d.getParent();if(null!==f&&(!f.canBeEmpty()||k.$isRootNode(f))){var h=f.__children;if(h.length===e){var m=!0;for(var n=0;n<h.length;n++)if(h[n]!==a[n].__key){m=!1;break}m&&(e++,a.push(f))}}f=a[e-1];c=c.isBefore(b);b=new Map;h=[];w(d,c?g:l,!0,h,b);for(d=0;d<e;d++)if(m=a[d],n=m.getKey(),!(b.has(n)||k.$isElementNode(m)&&m.excludeFromCopy())){const t=v(m);k.$isRootNode(m.getParent())&&h.push(m.getKey());
13
+ b.set(n,t)}w(f,c?l:g,!1,h,b);return{nodeMap:Array.from(b.entries()),range:h}};exports.$getSelectionStyleValueForProperty=function(a,c,b=""){let g=null;const l=a.getNodes();var e=a.anchor,d=a.focus,f=a.isBackward();a=f?d.offset:e.offset;e=f?d.getNode():e.getNode();for(d=0;d<l.length;d++){var h=l[d];if((0===d||0!==a||!h.is(e))&&k.$isTextNode(h)){f=c;var m=b;h=h.getStyle();h=x(h);f=null!==h?h[f]||m:m;if(null===g)g=f;else if(g!==f){g="";break}}}return null===g?b:g};
14
+ exports.$isAtNodeEnd=function(a){return"text"===a.type?a.offset===a.getNode().getTextContentSize():a.offset===a.getNode().getChildrenSize()};exports.$isParentElementRTL=A;exports.$moveCaretSelection=z;exports.$moveCharacter=function(a,c,b){const g=A(a);z(a,c,b?!g:g,"character")};
15
+ exports.$patchStyleText=function(a,c){var b=a.getNodes();const g=b.length-1;let l=b[0],e=b[g];if(!a.isCollapsed()){var d=a.anchor,f=a.focus;a=l.getTextContent().length;var h=f.offset,m=d.offset;d=(f=d.isBefore(f))?m:h;f=f?h:m;if(d===l.getTextContentSize()){const n=l.getNextSibling();k.$isTextNode(n)&&(d=m=0,l=n)}if(l.is(e))k.$isTextNode(l)&&(d=m>h?h:m,f=m>h?m:h,d!==f&&(0===d&&f===a?(y(l,c),l.select(d,f)):(b=l.splitText(d,f),b=0===d?b[0]:b[1],y(b,c),b.select(0,f-d))));else for(k.$isTextNode(l)&&(0!==
16
+ d&&([,l]=l.splitText(d)),y(l,c)),k.$isTextNode(e)&&(a=e.getTextContent().length,f!==a&&([e]=e.splitText(f)),0!==f&&y(e,c)),a=1;a<g;a++)h=b[a],m=h.getKey(),k.$isTextNode(h)&&m!==l.getKey()&&m!==e.getKey()&&!h.isToken()&&y(h,c)}};
17
+ exports.$selectAll=function(a){const c=a.anchor;a=a.focus;var b=c.getNode().getTopLevelElementOrThrow().getParentOrThrow();let g=b.getFirstDescendant();b=b.getLastDescendant();let l="element",e="element",d=0;k.$isTextNode(g)?l="text":k.$isElementNode(g)||null===g||(g=g.getParentOrThrow());k.$isTextNode(b)?(e="text",d=b.getTextContentSize()):k.$isElementNode(b)||null===b||(b=b.getParentOrThrow(),d=b.getChildrenSize());g&&b&&(c.set(g.getKey(),0,l),a.set(b.getKey(),d,e))};
18
+ exports.$shouldOverrideDefaultCharacterSelection=function(a,c){a=k.$getDecoratorNode(a.focus,c);return k.$isDecoratorNode(a)&&!a.isIsolated()};
19
+ exports.$wrapLeafNodesInElements=function(a,c,b){const g=a.getNodes(),l=g.length;if(0===l){a=a.anchor;a="text"===a.type?a.getNode().getParentOrThrow():a.getNode();var e=a.getChildren();let p=c();e.forEach(u=>p.append(u));b&&(p=b.append(p));a.replace(p)}else{var d=g[0],f=new Map;e=[];for(d=k.$isElementNode(d)?d:d.getParentOrThrow();null!==d;){var h=d.getPreviousSibling();if(null!==h){d=h;break}d=d.getParentOrThrow();if(k.$isRootNode(d))break}h=new Set;for(var m=0;m<l;m++){var n=g[m];k.$isElementNode(n)&&
20
+ 0===n.getChildrenSize()&&h.add(n.getKey())}var t=new Set;for(m=0;m<l;m++){var q=g[m];n=q.getParent();if(null!==n&&k.$isLeafNode(q)&&!t.has(q.getKey())){if(q=n.getKey(),void 0===f.get(q)){const p=c();e.push(p);f.set(q,p);n.getChildren().forEach(u=>{p.append(u);t.add(u.getKey())});B(n)}}else h.has(q.getKey())&&(e.push(c()),q.remove())}if(b)for(c=0;c<e.length;c++)b.append(e[c]);if(k.$isRootNode(d))if(c=d.getFirstChild(),k.$isElementNode(c)&&(d=c),null===c)if(b)d.append(b);else for(b=0;b<e.length;b++)d.append(e[b]);
21
+ else if(b)c.insertBefore(b);else for(b=0;b<e.length;b++)c.insertBefore(e[b]);else if(b)d.insertAfter(b);else for(b=e.length-1;0<=b;b--)d.insertAfter(e[b]);a.dirty=!0}};exports.getStyleObjectFromCSS=x;
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # `@lexical/selection`
2
+
3
+ This package contains utilities and helpers for handling Lexical selection.
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@lexical/selection",
3
+ "author": {
4
+ "name": "Dominic Gannaway",
5
+ "email": "dg@domgan.com"
6
+ },
7
+ "description": "This package contains utilities and helpers for handling Lexical selection.",
8
+ "keywords": [
9
+ "lexical",
10
+ "editor",
11
+ "rich-text",
12
+ "list",
13
+ "selection"
14
+ ],
15
+ "license": "MIT",
16
+ "version": "0.1.15",
17
+ "main": "LexicalSelection.js",
18
+ "peerDependencies": {
19
+ "lexical": "0.1.15"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/facebook/lexical",
24
+ "directory": "packages/lexical-selection"
25
+ }
26
+ }