@lexical/utils 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,9 +31,9 @@ function isMimeType(file, acceptableMimeTypes) {
31
31
  return true;
32
32
  }
33
33
  }
34
+
34
35
  return false;
35
36
  }
36
-
37
37
  /**
38
38
  * Lexical File Reader with:
39
39
  * 1. MIME type support
@@ -45,36 +45,44 @@ function isMimeType(file, acceptableMimeTypes) {
45
45
  * src: file.result,
46
46
  * }));
47
47
  */
48
+
48
49
  function mediaFileReader(files, acceptableMimeTypes) {
49
50
  const filesIterator = files[Symbol.iterator]();
50
51
  return new Promise((resolve, reject) => {
51
52
  const processed = [];
53
+
52
54
  const handleNextFile = () => {
53
55
  const {
54
56
  done,
55
57
  value: file
56
58
  } = filesIterator.next();
59
+
57
60
  if (done) {
58
61
  return resolve(processed);
59
62
  }
63
+
60
64
  const fileReader = new FileReader();
61
65
  fileReader.addEventListener('error', reject);
62
66
  fileReader.addEventListener('load', () => {
63
67
  const result = fileReader.result;
68
+
64
69
  if (typeof result === 'string') {
65
70
  processed.push({
66
71
  file,
67
72
  result
68
73
  });
69
74
  }
75
+
70
76
  handleNextFile();
71
77
  });
78
+
72
79
  if (isMimeType(file, acceptableMimeTypes)) {
73
80
  fileReader.readAsDataURL(file);
74
81
  } else {
75
82
  handleNextFile();
76
83
  }
77
84
  };
85
+
78
86
  handleNextFile();
79
87
  });
80
88
  }
@@ -84,19 +92,23 @@ function $dfs(startingNode, endingNode) {
84
92
  const end = endingNode || (lexical.$isElementNode(start) ? start.getLastDescendant() : start);
85
93
  let node = start;
86
94
  let depth = $getDepth(node);
95
+
87
96
  while (node !== null && !node.is(end)) {
88
97
  nodes.push({
89
98
  depth,
90
99
  node
91
100
  });
101
+
92
102
  if (lexical.$isElementNode(node) && node.getChildrenSize() > 0) {
93
103
  node = node.getFirstChild();
94
104
  depth++;
95
105
  } else {
96
106
  // Find immediate sibling or nearest parent sibling
97
107
  let sibling = null;
108
+
98
109
  while (sibling === null && node !== null) {
99
110
  sibling = node.getNextSibling();
111
+
100
112
  if (sibling === null) {
101
113
  node = node.getParent();
102
114
  depth--;
@@ -106,49 +118,63 @@ function $dfs(startingNode, endingNode) {
106
118
  }
107
119
  }
108
120
  }
121
+
109
122
  if (node !== null && node.is(end)) {
110
123
  nodes.push({
111
124
  depth,
112
125
  node
113
126
  });
114
127
  }
128
+
115
129
  return nodes;
116
130
  }
131
+
117
132
  function $getDepth(node) {
118
133
  let innerNode = node;
119
134
  let depth = 0;
135
+
120
136
  while ((innerNode = innerNode.getParent()) !== null) {
121
137
  depth++;
122
138
  }
139
+
123
140
  return depth;
124
141
  }
142
+
125
143
  function $getNearestNodeOfType(node, klass) {
126
144
  let parent = node;
145
+
127
146
  while (parent != null) {
128
147
  if (parent instanceof klass) {
129
148
  return parent;
130
149
  }
150
+
131
151
  parent = parent.getParent();
132
152
  }
153
+
133
154
  return null;
134
155
  }
135
156
  function $getNearestBlockElementAncestorOrThrow(startNode) {
136
157
  const blockNode = $findMatchingParent(startNode, node => lexical.$isElementNode(node) && !node.isInline());
158
+
137
159
  if (!lexical.$isElementNode(blockNode)) {
138
160
  {
139
161
  throw Error(`Expected node ${startNode.__key} to have closest block element node.`);
140
162
  }
141
163
  }
164
+
142
165
  return blockNode;
143
166
  }
144
167
  function $findMatchingParent(startingNode, findFn) {
145
168
  let curr = startingNode;
169
+
146
170
  while (curr !== lexical.$getRoot() && curr != null) {
147
171
  if (findFn(curr)) {
148
172
  return curr;
149
173
  }
174
+
150
175
  curr = curr.getParent();
151
176
  }
177
+
152
178
  return null;
153
179
  }
154
180
  function mergeRegister(...func) {
@@ -160,21 +186,27 @@ function registerNestedElementResolver(editor, targetNode, cloneNode, handleOver
160
186
  const $isTargetNode = node => {
161
187
  return node instanceof targetNode;
162
188
  };
189
+
163
190
  const $findMatch = node => {
164
191
  // First validate we don't have any children that are of the target,
165
192
  // as we need to handle them first.
166
193
  const children = node.getChildren();
194
+
167
195
  for (let i = 0; i < children.length; i++) {
168
196
  const child = children[i];
197
+
169
198
  if ($isTargetNode(child)) {
170
199
  return null;
171
200
  }
172
201
  }
202
+
173
203
  let parentNode = node;
174
204
  let childNode = node;
205
+
175
206
  while (parentNode !== null) {
176
207
  childNode = parentNode;
177
208
  parentNode = parentNode.getParent();
209
+
178
210
  if ($isTargetNode(parentNode)) {
179
211
  return {
180
212
  child: childNode,
@@ -182,78 +214,94 @@ function registerNestedElementResolver(editor, targetNode, cloneNode, handleOver
182
214
  };
183
215
  }
184
216
  }
217
+
185
218
  return null;
186
219
  };
220
+
187
221
  const elementNodeTransform = node => {
188
222
  const match = $findMatch(node);
223
+
189
224
  if (match !== null) {
190
225
  const {
191
226
  child,
192
227
  parent
193
- } = match;
194
-
195
- // Simple path, we can move child out and siblings into a new parent.
228
+ } = match; // Simple path, we can move child out and siblings into a new parent.
196
229
 
197
230
  if (child.is(node)) {
198
231
  handleOverlap(parent, node);
199
232
  const nextSiblings = child.getNextSiblings();
200
233
  const nextSiblingsLength = nextSiblings.length;
201
234
  parent.insertAfter(child);
235
+
202
236
  if (nextSiblingsLength !== 0) {
203
237
  const newParent = cloneNode(parent);
204
238
  child.insertAfter(newParent);
239
+
205
240
  for (let i = 0; i < nextSiblingsLength; i++) {
206
241
  newParent.append(nextSiblings[i]);
207
242
  }
208
243
  }
244
+
209
245
  if (!parent.canBeEmpty() && parent.getChildrenSize() === 0) {
210
246
  parent.remove();
211
247
  }
212
248
  }
213
249
  }
214
250
  };
251
+
215
252
  return editor.registerNodeTransform(targetNode, elementNodeTransform);
216
253
  }
217
254
  function $restoreEditorState(editor, editorState) {
218
255
  const FULL_RECONCILE = 2;
219
256
  const nodeMap = new Map();
220
257
  const activeEditorState = editor._pendingEditorState;
258
+
221
259
  for (const [key, node] of editorState._nodeMap) {
222
260
  const clone = selection.$cloneWithProperties(node);
261
+
223
262
  if (lexical.$isTextNode(clone)) {
224
263
  clone.__text = node.__text;
225
264
  }
265
+
226
266
  nodeMap.set(key, clone);
227
267
  }
268
+
228
269
  if (activeEditorState) {
229
270
  activeEditorState._nodeMap = nodeMap;
230
271
  }
272
+
231
273
  editor._dirtyType = FULL_RECONCILE;
232
274
  const selection$1 = editorState._selection;
233
275
  lexical.$setSelection(selection$1 === null ? null : selection$1.clone());
234
276
  }
235
277
  function $insertNodeToNearestRoot(node) {
236
278
  const selection = lexical.$getSelection();
279
+
237
280
  if (lexical.$isRangeSelection(selection)) {
238
281
  const {
239
282
  focus
240
283
  } = selection;
241
284
  const focusNode = focus.getNode();
242
285
  const focusOffset = focus.offset;
286
+
243
287
  if (lexical.$isRootOrShadowRoot(focusNode)) {
244
288
  const focusChild = focusNode.getChildAtIndex(focusOffset);
289
+
245
290
  if (focusChild == null) {
246
291
  focusNode.append(node);
247
292
  } else {
248
293
  focusChild.insertBefore(node);
249
294
  }
295
+
250
296
  node.selectNext();
251
297
  } else {
252
298
  let splitNode;
253
299
  let splitOffset;
300
+
254
301
  if (lexical.$isTextNode(focusNode)) {
255
302
  splitNode = focusNode.getParentOrThrow();
256
303
  splitOffset = focusNode.getIndexWithinParent();
304
+
257
305
  if (focusOffset > 0) {
258
306
  splitOffset += 1;
259
307
  focusNode.splitText(focusOffset);
@@ -262,6 +310,7 @@ function $insertNodeToNearestRoot(node) {
262
310
  splitNode = focusNode;
263
311
  splitOffset = focusOffset;
264
312
  }
313
+
265
314
  const [, rightTree] = lexical.$splitNode(splitNode, splitOffset);
266
315
  rightTree.insertBefore(node);
267
316
  rightTree.selectStart();
@@ -274,10 +323,12 @@ function $insertNodeToNearestRoot(node) {
274
323
  const root = lexical.$getRoot();
275
324
  root.append(node);
276
325
  }
326
+
277
327
  const paragraphNode = lexical.$createParagraphNode();
278
328
  node.insertAfter(paragraphNode);
279
329
  paragraphNode.select();
280
330
  }
331
+
281
332
  return node.getLatest();
282
333
  }
283
334
  function $wrapNodeInElement(node, createElementNode) {
@@ -286,6 +337,13 @@ function $wrapNodeInElement(node, createElementNode) {
286
337
  elementNode.append(node);
287
338
  return elementNode;
288
339
  }
340
+ function isHTMLAnchorElement(x) {
341
+ return isHTMLElement(x) && x.tagName === 'A';
342
+ }
343
+ function isHTMLElement(x) {
344
+ // @ts-ignore-next-line - strict check on nodeType here should filter out non-Element EventTarget implementors
345
+ return x.nodeType === 1;
346
+ }
289
347
 
290
348
  exports.$splitNode = lexical.$splitNode;
291
349
  exports.$dfs = $dfs;
@@ -296,6 +354,8 @@ exports.$insertNodeToNearestRoot = $insertNodeToNearestRoot;
296
354
  exports.$restoreEditorState = $restoreEditorState;
297
355
  exports.$wrapNodeInElement = $wrapNodeInElement;
298
356
  exports.addClassNamesToElement = addClassNamesToElement;
357
+ exports.isHTMLAnchorElement = isHTMLAnchorElement;
358
+ exports.isHTMLElement = isHTMLElement;
299
359
  exports.isMimeType = isMimeType;
300
360
  exports.mediaFileReader = mediaFileReader;
301
361
  exports.mergeRegister = mergeRegister;
@@ -4,12 +4,12 @@
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 g=require("@lexical/selection"),n=require("lexical");function p(a,b){for(let c of b)if(a.type.startsWith(c))return!0;return!1}function r(a,b){for(;a!==n.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}exports.$splitNode=n.$splitNode;
8
- exports.$dfs=function(a,b){let c=[];a=(a||n.$getRoot()).getLatest();b=b||(n.$isElementNode(a)?a.getLastDescendant():a);for(var f=a,d=0;null!==(f=f.getParent());)d++;for(f=d;null!==a&&!a.is(b);)if(c.push({depth:f,node:a}),n.$isElementNode(a)&&0<a.getChildrenSize())a=a.getFirstChild(),f++;else for(d=null;null===d&&null!==a;)d=a.getNextSibling(),null===d?(a=a.getParent(),f--):a=d;null!==a&&a.is(b)&&c.push({depth:f,node:a});return c};exports.$findMatchingParent=r;
9
- exports.$getNearestBlockElementAncestorOrThrow=function(a){a=r(a,b=>n.$isElementNode(b)&&!b.isInline());if(!n.$isElementNode(a))throw Error("Minified Lexical error #4; visit https://lexical.dev/docs/error?code=4 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");return a};exports.$getNearestNodeOfType=function(a,b){for(;null!=a;){if(a instanceof b)return a;a=a.getParent()}return null};
7
+ 'use strict';var g=require("@lexical/selection"),n=require("lexical");function p(a,b){for(let c of b)if(a.type.startsWith(c))return!0;return!1}function q(a,b){for(;a!==n.$getRoot()&&null!=a;){if(b(a))return a;a=a.getParent()}return null}function t(a){return 1===a.nodeType}exports.$splitNode=n.$splitNode;
8
+ exports.$dfs=function(a,b){let c=[];a=(a||n.$getRoot()).getLatest();b=b||(n.$isElementNode(a)?a.getLastDescendant():a);for(var f=a,d=0;null!==(f=f.getParent());)d++;for(f=d;null!==a&&!a.is(b);)if(c.push({depth:f,node:a}),n.$isElementNode(a)&&0<a.getChildrenSize())a=a.getFirstChild(),f++;else for(d=null;null===d&&null!==a;)d=a.getNextSibling(),null===d?(a=a.getParent(),f--):a=d;null!==a&&a.is(b)&&c.push({depth:f,node:a});return c};exports.$findMatchingParent=q;
9
+ exports.$getNearestBlockElementAncestorOrThrow=function(a){a=q(a,b=>n.$isElementNode(b)&&!b.isInline());if(!n.$isElementNode(a))throw Error("Minified Lexical error #4; visit https://lexical.dev/docs/error?code=4 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");return a};exports.$getNearestNodeOfType=function(a,b){for(;null!=a;){if(a instanceof b)return a;a=a.getParent()}return null};
10
10
  exports.$insertNodeToNearestRoot=function(a){var b=n.$getSelection();if(n.$isRangeSelection(b)){var {focus:c}=b;b=c.getNode();c=c.offset;if(n.$isRootOrShadowRoot(b))c=b.getChildAtIndex(c),null==c?b.append(a):c.insertBefore(a),a.selectNext();else{let f,d;n.$isTextNode(b)?(f=b.getParentOrThrow(),d=b.getIndexWithinParent(),0<c&&(d+=1,b.splitText(c))):(f=b,d=c);[,b]=n.$splitNode(f,d);b.insertBefore(a);b.selectStart()}}else n.$isNodeSelection(b)||n.DEPRECATED_$isGridSelection(b)?(b=b.getNodes(),b[b.length-
11
11
  1].getTopLevelElementOrThrow().insertAfter(a)):n.$getRoot().append(a),b=n.$createParagraphNode(),a.insertAfter(b),b.select();return a.getLatest()};exports.$restoreEditorState=function(a,b){let c=new Map,f=a._pendingEditorState;for(let [d,e]of b._nodeMap){let h=g.$cloneWithProperties(e);n.$isTextNode(h)&&(h.__text=e.__text);c.set(d,h)}f&&(f._nodeMap=c);a._dirtyType=2;a=b._selection;n.$setSelection(null===a?null:a.clone())};exports.$wrapNodeInElement=function(a,b){b=b();a.replace(b);b.append(a);return b};
12
- exports.addClassNamesToElement=function(a,...b){b.forEach(c=>{"string"===typeof c&&(c=c.split(" ").filter(f=>""!==f),a.classList.add(...c))})};exports.isMimeType=p;
13
- exports.mediaFileReader=function(a,b){let c=a[Symbol.iterator]();return new Promise((f,d)=>{let e=[],h=()=>{const {done:m,value:k}=c.next();if(m)return f(e);const l=new FileReader;l.addEventListener("error",d);l.addEventListener("load",()=>{const q=l.result;"string"===typeof q&&e.push({file:k,result:q});h()});p(k,b)?l.readAsDataURL(k):h()};h()})};exports.mergeRegister=function(...a){return()=>{a.forEach(b=>b())}};
12
+ exports.addClassNamesToElement=function(a,...b){b.forEach(c=>{"string"===typeof c&&(c=c.split(" ").filter(f=>""!==f),a.classList.add(...c))})};exports.isHTMLAnchorElement=function(a){return t(a)&&"A"===a.tagName};exports.isHTMLElement=t;exports.isMimeType=p;
13
+ exports.mediaFileReader=function(a,b){let c=a[Symbol.iterator]();return new Promise((f,d)=>{let e=[],h=()=>{const {done:m,value:k}=c.next();if(m)return f(e);const l=new FileReader;l.addEventListener("error",d);l.addEventListener("load",()=>{const r=l.result;"string"===typeof r&&e.push({file:k,result:r});h()});p(k,b)?l.readAsDataURL(k):h()};h()})};exports.mergeRegister=function(...a){return()=>{a.forEach(b=>b())}};
14
14
  exports.registerNestedElementResolver=function(a,b,c,f){return a.registerNodeTransform(b,d=>{a:{var e=d.getChildren();for(var h=0;h<e.length;h++)if(e[h]instanceof b){e=null;break a}for(e=d;null!==e;)if(h=e,e=e.getParent(),e instanceof b){e={child:h,parent:e};break a}e=null}if(null!==e){const {child:m,parent:k}=e;if(m.is(d)){f(k,d);d=m.getNextSiblings();e=d.length;k.insertAfter(m);if(0!==e){h=c(k);m.insertAfter(h);for(let l=0;l<e;l++)h.append(d[l])}k.canBeEmpty()||0!==k.getChildrenSize()||k.remove()}}})};
15
15
  exports.removeClassNamesFromElement=function(a,...b){b.forEach(c=>{"string"===typeof c&&a.classList.remove(...c.split(" "))})}
package/index.d.ts CHANGED
@@ -42,3 +42,5 @@ export declare function registerNestedElementResolver<N extends ElementNode>(edi
42
42
  export declare function $restoreEditorState(editor: LexicalEditor, editorState: EditorState): void;
43
43
  export declare function $insertNodeToNearestRoot<T extends LexicalNode>(node: T): T;
44
44
  export declare function $wrapNodeInElement(node: LexicalNode, createElementNode: () => ElementNode): ElementNode;
45
+ export declare function isHTMLAnchorElement(x: Node): x is HTMLAnchorElement;
46
+ export declare function isHTMLElement(x: Node | EventTarget): x is HTMLElement;
package/package.json CHANGED
@@ -8,15 +8,15 @@
8
8
  "utils"
9
9
  ],
10
10
  "license": "MIT",
11
- "version": "0.8.0",
11
+ "version": "0.9.0",
12
12
  "main": "LexicalUtils.js",
13
13
  "peerDependencies": {
14
- "lexical": "0.8.0"
14
+ "lexical": "0.9.0"
15
15
  },
16
16
  "dependencies": {
17
- "@lexical/list": "0.8.0",
18
- "@lexical/table": "0.8.0",
19
- "@lexical/selection": "0.8.0"
17
+ "@lexical/list": "0.9.0",
18
+ "@lexical/table": "0.9.0",
19
+ "@lexical/selection": "0.9.0"
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",