@lexical/utils 0.6.0 → 0.6.2

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.
@@ -24,6 +24,67 @@ function removeClassNamesFromElement(element, ...classNames) {
24
24
  }
25
25
  });
26
26
  }
27
+ function isMimeType(file, acceptableMimeTypes) {
28
+ for (const acceptableType of acceptableMimeTypes) {
29
+ if (file.type.startsWith(acceptableType)) {
30
+ return true;
31
+ }
32
+ }
33
+
34
+ return false;
35
+ }
36
+ /**
37
+ * Lexical File Reader with:
38
+ * 1. MIME type support
39
+ * 2. batched results (HistoryPlugin compatibility)
40
+ * 3. Order aware (respects the order when multiple Files are passed)
41
+ *
42
+ * const filesResult = await mediaFileReader(files, ['image/']);
43
+ * filesResult.forEach(file => editor.dispatchCommand('INSERT_IMAGE', {
44
+ * src: file.result,
45
+ * }));
46
+ */
47
+
48
+ function mediaFileReader(files, acceptableMimeTypes) {
49
+ const filesIterator = files[Symbol.iterator]();
50
+ return new Promise((resolve, reject) => {
51
+ const processed = [];
52
+
53
+ const handleNextFile = () => {
54
+ const {
55
+ done,
56
+ value: file
57
+ } = filesIterator.next();
58
+
59
+ if (done) {
60
+ return resolve(processed);
61
+ }
62
+
63
+ const fileReader = new FileReader();
64
+ fileReader.addEventListener('error', reject);
65
+ fileReader.addEventListener('load', () => {
66
+ const result = fileReader.result;
67
+
68
+ if (typeof result === 'string') {
69
+ processed.push({
70
+ file,
71
+ result
72
+ });
73
+ }
74
+
75
+ handleNextFile();
76
+ });
77
+
78
+ if (isMimeType(file, acceptableMimeTypes)) {
79
+ fileReader.readAsDataURL(file);
80
+ } else {
81
+ handleNextFile();
82
+ }
83
+ };
84
+
85
+ handleNextFile();
86
+ });
87
+ }
27
88
  function $dfs(startingNode, endingNode) {
28
89
  const nodes = [];
29
90
  const start = (startingNode || lexical.$getRoot()).getLatest();
@@ -321,19 +382,44 @@ function $insertNodeToNearestRoot(node) {
321
382
  const selection = lexical.$getSelection();
322
383
 
323
384
  if (lexical.$isRangeSelection(selection)) {
324
- const focusNode = selection.focus.getNode();
325
- focusNode.getTopLevelElementOrThrow().insertAfter(node);
326
- } else if (lexical.$isNodeSelection(selection) || lexical.DEPRECATED_$isGridSelection(selection)) {
327
- const nodes = selection.getNodes();
328
- nodes[nodes.length - 1].getTopLevelElementOrThrow().insertAfter(node);
385
+ const {
386
+ focus
387
+ } = selection;
388
+ const focusNode = focus.getNode();
389
+ const focusOffset = focus.offset;
390
+ let splitNode;
391
+ let splitOffset;
392
+
393
+ if (lexical.$isTextNode(focusNode)) {
394
+ splitNode = focusNode.getParentOrThrow();
395
+ splitOffset = focusNode.getIndexWithinParent();
396
+
397
+ if (focusOffset > 0) {
398
+ splitOffset += 1;
399
+ focusNode.splitText(focusOffset);
400
+ }
401
+ } else {
402
+ splitNode = focusNode;
403
+ splitOffset = focusOffset;
404
+ }
405
+
406
+ const [, rightTree] = $splitNode(splitNode, splitOffset);
407
+ rightTree.insertBefore(node);
408
+ rightTree.selectStart();
329
409
  } else {
330
- const root = lexical.$getRoot();
331
- root.append(node);
410
+ if (lexical.$isNodeSelection(selection) || lexical.DEPRECATED_$isGridSelection(selection)) {
411
+ const nodes = selection.getNodes();
412
+ nodes[nodes.length - 1].getTopLevelElementOrThrow().insertAfter(node);
413
+ } else {
414
+ const root = lexical.$getRoot();
415
+ root.append(node);
416
+ }
417
+
418
+ const paragraphNode = lexical.$createParagraphNode();
419
+ node.insertAfter(paragraphNode);
420
+ paragraphNode.select();
332
421
  }
333
422
 
334
- const paragraphNode = lexical.$createParagraphNode();
335
- node.insertAfter(paragraphNode);
336
- paragraphNode.select();
337
423
  return node.getLatest();
338
424
  }
339
425
  function $wrapNodeInElement(node, createElementNode) {
@@ -342,6 +428,34 @@ function $wrapNodeInElement(node, createElementNode) {
342
428
  elementNode.append(node);
343
429
  return elementNode;
344
430
  }
431
+ function $splitNode(node, offset) {
432
+ let startNode = node.getChildAtIndex(offset);
433
+
434
+ if (startNode == null) {
435
+ startNode = node;
436
+ }
437
+
438
+ const recurse = currentNode => {
439
+ const parent = currentNode.getParentOrThrow();
440
+ const isParentRoot = lexical.$isRootOrShadowRoot(parent); // The node we start split from (leaf) is moved, but its recursive
441
+ // parents are copied to create separate tree
442
+
443
+ const nodeToMove = currentNode === startNode && !isParentRoot ? currentNode : lexical.$copyNode(currentNode);
444
+
445
+ if (isParentRoot) {
446
+ currentNode.insertAfter(nodeToMove);
447
+ return [currentNode, nodeToMove, nodeToMove];
448
+ } else {
449
+ const [leftTree, rightTree, newParent] = recurse(parent);
450
+ const nextSiblings = currentNode.getNextSiblings();
451
+ newParent.append(nodeToMove, ...nextSiblings);
452
+ return [leftTree, rightTree, nodeToMove];
453
+ }
454
+ };
455
+
456
+ const [leftTree, rightTree] = recurse(startNode);
457
+ return [leftTree, rightTree];
458
+ }
345
459
 
346
460
  exports.$dfs = $dfs;
347
461
  exports.$findMatchingParent = $findMatchingParent;
@@ -349,8 +463,11 @@ exports.$getNearestBlockElementAncestorOrThrow = $getNearestBlockElementAncestor
349
463
  exports.$getNearestNodeOfType = $getNearestNodeOfType;
350
464
  exports.$insertNodeToNearestRoot = $insertNodeToNearestRoot;
351
465
  exports.$restoreEditorState = $restoreEditorState;
466
+ exports.$splitNode = $splitNode;
352
467
  exports.$wrapNodeInElement = $wrapNodeInElement;
353
468
  exports.addClassNamesToElement = addClassNamesToElement;
469
+ exports.isMimeType = isMimeType;
470
+ exports.mediaFileReader = mediaFileReader;
354
471
  exports.mergeRegister = mergeRegister;
355
472
  exports.registerNestedElementResolver = registerNestedElementResolver;
356
473
  exports.removeClassNamesFromElement = removeClassNamesFromElement;
@@ -24,6 +24,14 @@ declare export function removeClassNamesFromElement(
24
24
  element: HTMLElement,
25
25
  ...classNames: Array<typeof undefined | boolean | null | string>
26
26
  ): void;
27
+ declare export function isMimeType(
28
+ file: File,
29
+ acceptableMimeTypes: Array<string>,
30
+ ): boolean;
31
+ declare export function mediaFileReader(
32
+ files: Array<File>,
33
+ acceptableMimeTypes: Array<string>,
34
+ ): Promise<Array<$ReadOnly<{file: File, result: string}>>>;
27
35
  declare export function $dfs(
28
36
  startingNode?: LexicalNode,
29
37
  endingNode?: LexicalNode,
@@ -70,3 +78,5 @@ declare export function $wrapNodeInElement(
70
78
  node: LexicalNode,
71
79
  createElementNode: () => ElementNode,
72
80
  ): ElementNode;
81
+
82
+ declare export function $splitNode<T: LexicalNode>(node: T): T;
@@ -4,13 +4,15 @@
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 l=require("lexical");function n(a){throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?code=${a} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function p(a,b){for(;a!==l.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}
8
- function q(a,b,d,f,e){var c=d._nodes.get(a.__type);void 0===c&&n(5);for(var h in a){var k=a[h];if(null!=k&&"object"===typeof k&&(k=k.editorState,null!=k)){var g=l.createEditor({namespace:k.namespace});g._nodes=d._nodes;g._parentEditor=d._parentEditor;g._pendingEditorState=r(g,k);a[h]=g}}c=c.klass;h=a.__key;a.__key=void 0;c=c.clone(a);a.__key=h;h=c.__key;e._nodeMap.set(h,c);c.__parent=f;if(l.$isElementNode(c)){f=a.__children;for(k=0;k<f.length;k++)g=b.get(f[k]),void 0!==g&&(g=q(g,b,d,h,e).__key,c.__children.push(g));
7
+ 'use strict';var l=require("lexical");function p(a){throw Error(`Minified Lexical error #${a}; visit https://lexical.dev/docs/error?code=${a} for the full message or `+"use the non-minified dev environment for full errors and additional helpful warnings.");}function q(a,b){for(let d of b)if(a.type.startsWith(d))return!0;return!1}function r(a,b){for(;a!==l.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}
8
+ function t(a,b,d,g,f){var c=d._nodes.get(a.__type);void 0===c&&p(5);for(var e in a){var k=a[e];if(null!=k&&"object"===typeof k&&(k=k.editorState,null!=k)){var h=l.createEditor({namespace:k.namespace});h._nodes=d._nodes;h._parentEditor=d._parentEditor;h._pendingEditorState=u(h,k);a[e]=h}}c=c.klass;e=a.__key;a.__key=void 0;c=c.clone(a);a.__key=e;e=c.__key;f._nodeMap.set(e,c);c.__parent=g;if(l.$isElementNode(c)){g=a.__children;for(k=0;k<g.length;k++)h=b.get(g[k]),void 0!==h&&(h=t(h,b,d,e,f).__key,c.__children.push(h));
9
9
  c.__indent=a.__indent;c.__format=a.__format;c.__dir=a.__dir}else l.$isTextNode(c)&&(c.__format=a.__format,c.__style=a.__style,c.__mode=a.__mode,c.__detail=a.__detail);return c}
10
- function t(a,b){let d=b._editorState.constructor,f=new Map,e=new d(f),c=new Map(a._nodeMap),h=c.get("root");a=b._updating;try{b._updating=!1,b.update(()=>{let k=b._dirtyElements,g=b._dirtyLeaves,m=b._dirtyType;b._dirtyElements=new Map;b._dirtyLeaves=new Set;b._dirtyType=0;try{q(h,c,b,null,e)}finally{b._dirtyElements=k,b._dirtyLeaves=g,b._dirtyType=m}})}finally{b._updating=a}e._readOnly=!0;return e}function r(a,b){b="string"===typeof b?JSON.parse(b):b;return t(b,a)}
11
- exports.$dfs=function(a,b){let d=[];a=(a||l.$getRoot()).getLatest();b=b||(l.$isElementNode(a)?a.getLastDescendant():a);for(var f=a,e=0;null!==(f=f.getParent());)e++;for(f=e;null!==a&&!a.is(b);)if(d.push({depth:f,node:a}),l.$isElementNode(a)&&0<a.getChildrenSize())a=a.getFirstChild(),f++;else for(e=null;null===e&&null!==a;)e=a.getNextSibling(),null===e?(a=a.getParent(),f--):a=e;null!==a&&a.is(b)&&d.push({depth:f,node:a});return d};exports.$findMatchingParent=p;
12
- exports.$getNearestBlockElementAncestorOrThrow=function(a){a=p(a,b=>l.$isElementNode(b)&&!b.isInline());l.$isElementNode(a)||n(4);return a};exports.$getNearestNodeOfType=function(a,b){for(;null!=a;){if(a instanceof b)return a;a=a.getParent()}return null};
13
- exports.$insertNodeToNearestRoot=function(a){var b=l.$getSelection();l.$isRangeSelection(b)?b.focus.getNode().getTopLevelElementOrThrow().insertAfter(a):l.$isNodeSelection(b)||l.DEPRECATED_$isGridSelection(b)?(b=b.getNodes(),b[b.length-1].getTopLevelElementOrThrow().insertAfter(a)):l.$getRoot().append(a);b=l.$createParagraphNode();a.insertAfter(b);b.select();return a.getLatest()};
14
- exports.$restoreEditorState=function(a,b){let d=new Map(b._nodeMap),f=a._pendingEditorState;f&&(f._nodeMap=d);a._dirtyType=2;a=b._selection;l.$setSelection(null===a?null:a.clone())};exports.$wrapNodeInElement=function(a,b){b=b();a.replace(b);b.append(a);return b};exports.addClassNamesToElement=function(a,...b){b.forEach(d=>{"string"===typeof d&&(d=d.split(" ").filter(f=>""!==f),a.classList.add(...d))})};exports.mergeRegister=function(...a){return()=>{a.forEach(b=>b())}};
15
- exports.registerNestedElementResolver=function(a,b,d,f){return a.registerNodeTransform(b,e=>{a:{var c=e.getChildren();for(var h=0;h<c.length;h++)if(c[h]instanceof b){c=null;break a}for(c=e;null!==c;)if(h=c,c=c.getParent(),c instanceof b){c={child:h,parent:c};break a}c=null}if(null!==c){const {child:k,parent:g}=c;if(k.is(e)){f(g,e);e=k.getNextSiblings();c=e.length;g.insertAfter(k);if(0!==c){h=d(g);k.insertAfter(h);for(let m=0;m<c;m++)h.append(e[m])}g.canBeEmpty()||0!==g.getChildrenSize()||g.remove()}}})};
16
- exports.removeClassNamesFromElement=function(a,...b){b.forEach(d=>{"string"===typeof d&&a.classList.remove(...d.split(" "))})};exports.unstable_convertLegacyJSONEditorState=r
10
+ function v(a,b){let d=b._editorState.constructor,g=new Map,f=new d(g),c=new Map(a._nodeMap),e=c.get("root");a=b._updating;try{b._updating=!1,b.update(()=>{let k=b._dirtyElements,h=b._dirtyLeaves,m=b._dirtyType;b._dirtyElements=new Map;b._dirtyLeaves=new Set;b._dirtyType=0;try{t(e,c,b,null,f)}finally{b._dirtyElements=k,b._dirtyLeaves=h,b._dirtyType=m}})}finally{b._updating=a}f._readOnly=!0;return f}function u(a,b){b="string"===typeof b?JSON.parse(b):b;return v(b,a)}
11
+ function w(a,b){let d=a.getChildAtIndex(b);null==d&&(d=a);let g=e=>{const k=e.getParentOrThrow(),h=l.$isRootOrShadowRoot(k),m=e!==d||h?l.$copyNode(e):e;if(h)return e.insertAfter(m),[e,m,m];const [n,x,y]=g(k);e=e.getNextSiblings();y.append(m,...e);return[n,x,m]},[f,c]=g(d);return[f,c]}
12
+ exports.$dfs=function(a,b){let d=[];a=(a||l.$getRoot()).getLatest();b=b||(l.$isElementNode(a)?a.getLastDescendant():a);for(var g=a,f=0;null!==(g=g.getParent());)f++;for(g=f;null!==a&&!a.is(b);)if(d.push({depth:g,node:a}),l.$isElementNode(a)&&0<a.getChildrenSize())a=a.getFirstChild(),g++;else for(f=null;null===f&&null!==a;)f=a.getNextSibling(),null===f?(a=a.getParent(),g--):a=f;null!==a&&a.is(b)&&d.push({depth:g,node:a});return d};exports.$findMatchingParent=r;
13
+ exports.$getNearestBlockElementAncestorOrThrow=function(a){a=r(a,b=>l.$isElementNode(b)&&!b.isInline());l.$isElementNode(a)||p(4);return a};exports.$getNearestNodeOfType=function(a,b){for(;null!=a;){if(a instanceof b)return a;a=a.getParent()}return null};
14
+ exports.$insertNodeToNearestRoot=function(a){var b=l.$getSelection();if(l.$isRangeSelection(b)){var {focus:d}=b;b=d.getNode();d=d.offset;let g,f;l.$isTextNode(b)?(g=b.getParentOrThrow(),f=b.getIndexWithinParent(),0<d&&(f+=1,b.splitText(d))):(g=b,f=d);[,b]=w(g,f);b.insertBefore(a);b.selectStart()}else l.$isNodeSelection(b)||l.DEPRECATED_$isGridSelection(b)?(b=b.getNodes(),b[b.length-1].getTopLevelElementOrThrow().insertAfter(a)):l.$getRoot().append(a),b=l.$createParagraphNode(),a.insertAfter(b),b.select();
15
+ return a.getLatest()};exports.$restoreEditorState=function(a,b){let d=new Map(b._nodeMap),g=a._pendingEditorState;g&&(g._nodeMap=d);a._dirtyType=2;a=b._selection;l.$setSelection(null===a?null:a.clone())};exports.$splitNode=w;exports.$wrapNodeInElement=function(a,b){b=b();a.replace(b);b.append(a);return b};exports.addClassNamesToElement=function(a,...b){b.forEach(d=>{"string"===typeof d&&(d=d.split(" ").filter(g=>""!==g),a.classList.add(...d))})};exports.isMimeType=q;
16
+ exports.mediaFileReader=function(a,b){let d=a[Symbol.iterator]();return new Promise((g,f)=>{let c=[],e=()=>{const {done:k,value:h}=d.next();if(k)return g(c);const m=new FileReader;m.addEventListener("error",f);m.addEventListener("load",()=>{const n=m.result;"string"===typeof n&&c.push({file:h,result:n});e()});q(h,b)?m.readAsDataURL(h):e()};e()})};exports.mergeRegister=function(...a){return()=>{a.forEach(b=>b())}};
17
+ exports.registerNestedElementResolver=function(a,b,d,g){return a.registerNodeTransform(b,f=>{a:{var c=f.getChildren();for(var e=0;e<c.length;e++)if(c[e]instanceof b){c=null;break a}for(c=f;null!==c;)if(e=c,c=c.getParent(),c instanceof b){c={child:e,parent:c};break a}c=null}if(null!==c){const {child:k,parent:h}=c;if(k.is(f)){g(h,f);f=k.getNextSiblings();c=f.length;h.insertAfter(k);if(0!==c){e=d(h);k.insertAfter(e);for(let m=0;m<c;m++)e.append(f[m])}h.canBeEmpty()||0!==h.getChildrenSize()||h.remove()}}})};
18
+ exports.removeClassNamesFromElement=function(a,...b){b.forEach(d=>{"string"===typeof d&&a.classList.remove(...d.split(" "))})};exports.unstable_convertLegacyJSONEditorState=u
package/index.d.ts CHANGED
@@ -13,6 +13,22 @@ export declare type DFSNode = Readonly<{
13
13
  }>;
14
14
  export declare function addClassNamesToElement(element: HTMLElement, ...classNames: Array<typeof undefined | boolean | null | string>): void;
15
15
  export declare function removeClassNamesFromElement(element: HTMLElement, ...classNames: Array<typeof undefined | boolean | null | string>): void;
16
+ export declare function isMimeType(file: File, acceptableMimeTypes: Array<string>): boolean;
17
+ /**
18
+ * Lexical File Reader with:
19
+ * 1. MIME type support
20
+ * 2. batched results (HistoryPlugin compatibility)
21
+ * 3. Order aware (respects the order when multiple Files are passed)
22
+ *
23
+ * const filesResult = await mediaFileReader(files, ['image/']);
24
+ * filesResult.forEach(file => editor.dispatchCommand('INSERT_IMAGE', {
25
+ * src: file.result,
26
+ * }));
27
+ */
28
+ export declare function mediaFileReader(files: Array<File>, acceptableMimeTypes: Array<string>): Promise<Array<{
29
+ file: File;
30
+ result: string;
31
+ }>>;
16
32
  export declare function $dfs(startingNode?: LexicalNode, endingNode?: LexicalNode): Array<DFSNode>;
17
33
  export declare function $getNearestNodeOfType<T extends ElementNode>(node: LexicalNode, klass: Klass<T>): T | null;
18
34
  export declare function $getNearestBlockElementAncestorOrThrow(startNode: LexicalNode): ElementNode;
@@ -26,4 +42,5 @@ export declare function unstable_convertLegacyJSONEditorState(editor: LexicalEdi
26
42
  export declare function $restoreEditorState(editor: LexicalEditor, editorState: EditorState): void;
27
43
  export declare function $insertNodeToNearestRoot<T extends LexicalNode>(node: T): T;
28
44
  export declare function $wrapNodeInElement(node: LexicalNode, createElementNode: () => ElementNode): ElementNode;
45
+ export declare function $splitNode(node: ElementNode, offset: number): [ElementNode | null, ElementNode];
29
46
  export {};
package/package.json CHANGED
@@ -8,14 +8,14 @@
8
8
  "utils"
9
9
  ],
10
10
  "license": "MIT",
11
- "version": "0.6.0",
11
+ "version": "0.6.2",
12
12
  "main": "LexicalUtils.js",
13
13
  "peerDependencies": {
14
- "lexical": "0.6.0"
14
+ "lexical": "0.6.2"
15
15
  },
16
16
  "dependencies": {
17
- "@lexical/list": "0.6.0",
18
- "@lexical/table": "0.6.0"
17
+ "@lexical/list": "0.6.2",
18
+ "@lexical/table": "0.6.2"
19
19
  },
20
20
  "repository": {
21
21
  "type": "git",