@lexical/text 0.1.15 → 0.1.18

Sign up to get free protection for your applications and to get access to all the features.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 Dominic Gannaway
3
+ Copyright (c) Meta Platforms, Inc. and affiliates.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,53 @@
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
+ */
8
+ import type {ElementNode, LexicalEditor, RootNode, TextNode} from 'lexical';
9
+ export type TextNodeWithOffset = {
10
+ node: TextNode;
11
+ offset: number;
12
+ };
13
+ export function $findTextIntersectionFromCharacters(
14
+ root: RootNode,
15
+ targetCharacters: number,
16
+ ): null | {
17
+ node: TextNode;
18
+ offset: number;
19
+ };
20
+ export function $joinTextNodesInElementNode(
21
+ elementNode: ElementNode,
22
+ separator: string,
23
+ stopAt: TextNodeWithOffset,
24
+ ): string;
25
+ export function $findNodeWithOffsetFromJoinedText(
26
+ offsetInJoinedText: number,
27
+ joinedTextLength: number,
28
+ separatorLength: number,
29
+ elementNode: ElementNode,
30
+ ): ?TextNodeWithOffset;
31
+ export function $isRootTextContentEmpty(
32
+ isEditorComposing: boolean,
33
+ trim?: boolean,
34
+ ): boolean;
35
+ export function $isRootTextContentEmptyCurry(
36
+ isEditorComposing: boolean,
37
+ trim?: boolean,
38
+ ): () => boolean;
39
+ export function $rootTextContentCurry(): string;
40
+ export function $canShowPlaceholder(isComposing: boolean): boolean;
41
+ export function $canShowPlaceholderCurry(
42
+ isEditorComposing: boolean,
43
+ ): () => boolean;
44
+ export type EntityMatch = {
45
+ end: number;
46
+ start: number;
47
+ };
48
+ export function registerLexicalTextEntity<N extends TextNode>(
49
+ editor: LexicalEditor,
50
+ getMatch: (text: string) => null | EntityMatch,
51
+ targetNode: Class<N>,
52
+ createNode: (textNode: TextNode) => N,
53
+ ): Array<() => void>;
@@ -212,6 +212,158 @@ function $canShowPlaceholder(isComposing) {
212
212
  function $canShowPlaceholderCurry(isEditorComposing) {
213
213
  return () => $canShowPlaceholder(isEditorComposing);
214
214
  }
215
+ function registerLexicalTextEntity(editor, getMatch, targetNode, createNode) {
216
+ const isTargetNode = node => {
217
+ return node instanceof targetNode;
218
+ };
219
+
220
+ const replaceWithSimpleText = node => {
221
+ const textNode = lexical.$createTextNode(node.getTextContent());
222
+ textNode.setFormat(node.getFormat());
223
+ node.replace(textNode);
224
+ };
225
+
226
+ const getMode = node => {
227
+ return node.getLatest().__mode;
228
+ };
229
+
230
+ const textNodeTransform = node => {
231
+ if (!node.isSimpleText()) {
232
+ return;
233
+ }
234
+
235
+ const prevSibling = node.getPreviousSibling();
236
+ let text = node.getTextContent();
237
+ let currentNode = node;
238
+ let match;
239
+
240
+ if (lexical.$isTextNode(prevSibling)) {
241
+ const previousText = prevSibling.getTextContent();
242
+ const combinedText = previousText + text;
243
+ const prevMatch = getMatch(combinedText);
244
+
245
+ if (isTargetNode(prevSibling)) {
246
+ if (prevMatch === null || getMode(prevSibling) !== 0) {
247
+ replaceWithSimpleText(prevSibling);
248
+ return;
249
+ } else {
250
+ const diff = prevMatch.end - previousText.length;
251
+
252
+ if (diff > 0) {
253
+ const concatText = text.slice(0, diff);
254
+ const newTextContent = previousText + concatText;
255
+ prevSibling.select();
256
+ prevSibling.setTextContent(newTextContent);
257
+
258
+ if (diff === text.length) {
259
+ node.remove();
260
+ } else {
261
+ const remainingText = text.slice(diff);
262
+ node.setTextContent(remainingText);
263
+ }
264
+
265
+ return;
266
+ }
267
+ }
268
+ } else if (prevMatch === null || prevMatch.start < previousText.length) {
269
+ return;
270
+ }
271
+ }
272
+
273
+ while (true) {
274
+ match = getMatch(text);
275
+ let nextText = match === null ? '' : text.slice(match.end);
276
+ text = nextText;
277
+
278
+ if (nextText === '') {
279
+ const nextSibling = currentNode.getNextSibling();
280
+
281
+ if (lexical.$isTextNode(nextSibling)) {
282
+ nextText = currentNode.getTextContent() + nextSibling.getTextContent();
283
+ const nextMatch = getMatch(nextText);
284
+
285
+ if (nextMatch === null) {
286
+ if (isTargetNode(nextSibling)) {
287
+ replaceWithSimpleText(nextSibling);
288
+ } else {
289
+ nextSibling.markDirty();
290
+ }
291
+
292
+ return;
293
+ } else if (nextMatch.start !== 0) {
294
+ return;
295
+ }
296
+ }
297
+ } else {
298
+ const nextMatch = getMatch(nextText);
299
+
300
+ if (nextMatch !== null && nextMatch.start === 0) {
301
+ return;
302
+ }
303
+ }
304
+
305
+ if (match === null) {
306
+ return;
307
+ }
308
+
309
+ if (match.start === 0 && lexical.$isTextNode(prevSibling) && prevSibling.isTextEntity()) {
310
+ continue;
311
+ }
312
+
313
+ let nodeToReplace;
314
+
315
+ if (match.start === 0) {
316
+ [nodeToReplace, currentNode] = currentNode.splitText(match.end);
317
+ } else {
318
+ [, nodeToReplace, currentNode] = currentNode.splitText(match.start, match.end);
319
+ }
320
+
321
+ const replacementNode = createNode(nodeToReplace);
322
+ nodeToReplace.replace(replacementNode);
323
+
324
+ if (currentNode == null) {
325
+ return;
326
+ }
327
+ }
328
+ };
329
+
330
+ const reverseNodeTransform = node => {
331
+ const text = node.getTextContent();
332
+ const match = getMatch(text);
333
+
334
+ if (match === null || match.start !== 0) {
335
+ replaceWithSimpleText(node);
336
+ return;
337
+ }
338
+
339
+ if (text.length > match.end) {
340
+ // This will split out the rest of the text as simple text
341
+ node.splitText(match.end);
342
+ return;
343
+ }
344
+
345
+ const prevSibling = node.getPreviousSibling();
346
+
347
+ if (lexical.$isTextNode(prevSibling) && prevSibling.isTextEntity()) {
348
+ replaceWithSimpleText(prevSibling);
349
+ replaceWithSimpleText(node);
350
+ }
351
+
352
+ const nextSibling = node.getNextSibling();
353
+
354
+ if (lexical.$isTextNode(nextSibling) && nextSibling.isTextEntity()) {
355
+ replaceWithSimpleText(nextSibling); // This may have already been converted in the previous block
356
+
357
+ if (isTargetNode(node)) {
358
+ replaceWithSimpleText(node);
359
+ }
360
+ }
361
+ };
362
+
363
+ const removePlainTextTransform = editor.registerNodeTransform(lexical.TextNode, textNodeTransform);
364
+ const removeReverseNodeTransform = editor.registerNodeTransform(targetNode, reverseNodeTransform);
365
+ return [removePlainTextTransform, removeReverseNodeTransform];
366
+ }
215
367
 
216
368
  exports.$canShowPlaceholder = $canShowPlaceholder;
217
369
  exports.$canShowPlaceholderCurry = $canShowPlaceholderCurry;
@@ -221,3 +373,4 @@ exports.$isRootTextContentEmpty = $isRootTextContentEmpty;
221
373
  exports.$isRootTextContentEmptyCurry = $isRootTextContentEmptyCurry;
222
374
  exports.$joinTextNodesInElementNode = $joinTextNodesInElementNode;
223
375
  exports.$rootTextContentCurry = $rootTextContentCurry;
376
+ exports.registerLexicalTextEntity = registerLexicalTextEntity;
@@ -0,0 +1,54 @@
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
+ * @flow strict
8
+ */
9
+ import type {ElementNode, LexicalEditor, RootNode, TextNode} from 'lexical';
10
+ export type TextNodeWithOffset = {
11
+ node: TextNode,
12
+ offset: number,
13
+ };
14
+ declare export function $findTextIntersectionFromCharacters(
15
+ root: RootNode,
16
+ targetCharacters: number,
17
+ ): null | {
18
+ node: TextNode,
19
+ offset: number,
20
+ };
21
+ declare export function $joinTextNodesInElementNode(
22
+ elementNode: ElementNode,
23
+ separator: string,
24
+ stopAt: TextNodeWithOffset,
25
+ ): string;
26
+ declare export function $findNodeWithOffsetFromJoinedText(
27
+ offsetInJoinedText: number,
28
+ joinedTextLength: number,
29
+ separatorLength: number,
30
+ elementNode: ElementNode,
31
+ ): ?TextNodeWithOffset;
32
+ declare export function $isRootTextContentEmpty(
33
+ isEditorComposing: boolean,
34
+ trim?: boolean,
35
+ ): boolean;
36
+ declare export function $isRootTextContentEmptyCurry(
37
+ isEditorComposing: boolean,
38
+ trim?: boolean,
39
+ ): () => boolean;
40
+ declare export function $rootTextContentCurry(): string;
41
+ declare export function $canShowPlaceholder(isComposing: boolean): boolean;
42
+ declare export function $canShowPlaceholderCurry(
43
+ isEditorComposing: boolean,
44
+ ): () => boolean;
45
+ export type EntityMatch = {
46
+ end: number,
47
+ start: number,
48
+ };
49
+ declare export function registerLexicalTextEntity<N: TextNode>(
50
+ editor: LexicalEditor,
51
+ getMatch: (text: string) => null | EntityMatch,
52
+ targetNode: Class<N>,
53
+ createNode: (textNode: TextNode) => N,
54
+ ): Array<() => void>;
@@ -4,8 +4,11 @@
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
- var f=require("lexical");function m(a,e=!0){if(a)return!1;a=p();e&&(a=a.trim());return""===a}function p(){return f.$getRoot().getTextContent()}function q(a){if(!m(a,!1))return!1;a=f.$getRoot().getChildren();const e=a.length;if(1<e)return!1;for(let c=0;c<e;c++){var b=a[c];if(f.$isElementNode(b)){if("paragraph"!==b.__type||0!==b.__indent)return!1;b=b.getChildren();const k=b.length;for(let d=0;d<k;d++)if(!f.$isTextNode(b[c]))return!1}}return!0}exports.$canShowPlaceholder=q;
8
- exports.$canShowPlaceholderCurry=function(a){return()=>q(a)};exports.$findNodeWithOffsetFromJoinedText=function(a,e,b,c){c=c.getChildren();const k=c.length;let d=0,g=!1;for(let n=0;n<k&&!(d>e);++n){const l=c[n],r=f.$isTextNode(l);var h=r?l.getTextContent().length:b;h=d+h;if((!1===g&&d===a||0===d&&d===a||d<a&&a<=h)&&f.$isTextNode(l))return{node:l,offset:a-d};d=h;g=r}return null};
9
- exports.$findTextIntersectionFromCharacters=function(a,e){var b=a.getFirstChild();a=0;a:for(;null!==b;){if(f.$isElementNode(b)){var c=b.getFirstChild();if(null!==c){b=c;continue}}else if(f.$isTextNode(b)){c=b.getTextContentSize();if(a+c>e)return{node:b,offset:e-a};a+=c}c=b.getNextSibling();if(null!==c)b=c;else{for(b=b.getParent();null!==b;){c=b.getNextSibling();if(null!==c){b=c;continue a}b=b.getParent()}break}}return null};exports.$isRootTextContentEmpty=m;
10
- exports.$isRootTextContentEmptyCurry=function(a,e){return()=>m(a,e)};
11
- exports.$joinTextNodesInElementNode=function(a,e,b){let c="";a=a.getChildren();const k=a.length;for(let d=0;d<k;++d){const g=a[d];if(f.$isTextNode(g)){const h=g.getTextContent();if(g.is(b.node)){if(b.offset>h.length)throw Error("Minified Lexical error #50; see codes.json for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");c+=g.getTextContent().substr(0,b.offset);break}else c+=h}else c+=e}return c};exports.$rootTextContentCurry=p;
7
+ var k=require("lexical");function r(b,f=!0){if(b)return!1;b=t();f&&(b=b.trim());return""===b}function t(){return k.$getRoot().getTextContent()}function u(b){if(!r(b,!1))return!1;b=k.$getRoot().getChildren();const f=b.length;if(1<f)return!1;for(let e=0;e<f;e++){var c=b[e];if(k.$isElementNode(c)){if("paragraph"!==c.__type||0!==c.__indent)return!1;c=c.getChildren();const p=c.length;for(let g=0;g<p;g++)if(!k.$isTextNode(c[e]))return!1}}return!0}exports.$canShowPlaceholder=u;
8
+ exports.$canShowPlaceholderCurry=function(b){return()=>u(b)};exports.$findNodeWithOffsetFromJoinedText=function(b,f,c,e){e=e.getChildren();const p=e.length;let g=0,a=!1;for(let l=0;l<p&&!(g>f);++l){const m=e[l],n=k.$isTextNode(m);var d=n?m.getTextContent().length:c;d=g+d;if((!1===a&&g===b||0===g&&g===b||g<b&&b<=d)&&k.$isTextNode(m))return{node:m,offset:b-g};g=d;a=n}return null};
9
+ exports.$findTextIntersectionFromCharacters=function(b,f){var c=b.getFirstChild();b=0;a:for(;null!==c;){if(k.$isElementNode(c)){var e=c.getFirstChild();if(null!==e){c=e;continue}}else if(k.$isTextNode(c)){e=c.getTextContentSize();if(b+e>f)return{node:c,offset:f-b};b+=e}e=c.getNextSibling();if(null!==e)c=e;else{for(c=c.getParent();null!==c;){e=c.getNextSibling();if(null!==e){c=e;continue a}c=c.getParent()}break}}return null};exports.$isRootTextContentEmpty=r;
10
+ exports.$isRootTextContentEmptyCurry=function(b,f){return()=>r(b,f)};
11
+ exports.$joinTextNodesInElementNode=function(b,f,c){let e="";b=b.getChildren();const p=b.length;for(let g=0;g<p;++g){const a=b[g];if(k.$isTextNode(a)){const d=a.getTextContent();if(a.is(c.node)){if(c.offset>d.length)throw Error("Minified Lexical error #50; see codes.json for the full message or use the non-minified dev environment for full errors and additional helpful warnings.");e+=a.getTextContent().substr(0,c.offset);break}else e+=d}else e+=f}return e};exports.$rootTextContentCurry=t;
12
+ exports.registerLexicalTextEntity=function(b,f,c,e){const p=a=>{const d=k.$createTextNode(a.getTextContent());d.setFormat(a.getFormat());a.replace(d)},g=b.registerNodeTransform(k.TextNode,a=>{if(a.isSimpleText()){var d=a.getPreviousSibling(),l=a.getTextContent(),m=a;if(k.$isTextNode(d)){var n=d.getTextContent(),h=f(n+l);if(d instanceof c){if(null===h||0!==d.getLatest().__mode){p(d);return}h=h.end-n.length;if(0<h){m=l.slice(0,h);m=n+m;d.select();d.setTextContent(m);h===l.length?a.remove():(d=l.slice(h),
13
+ a.setTextContent(d));return}}else if(null===h||h.start<n.length)return}for(;;){a=f(l);l=h=null===a?"":l.slice(a.end);if(""===h){if(n=m.getNextSibling(),k.$isTextNode(n))if(h=m.getTextContent()+n.getTextContent(),h=f(h),null===h){n instanceof c?p(n):n.markDirty();break}else if(0!==h.start)break}else if(n=f(h),null!==n&&0===n.start)break;if(null===a)break;if(0===a.start&&k.$isTextNode(d)&&d.isTextEntity())continue;let q;0===a.start?[q,m]=m.splitText(a.end):[,q,m]=m.splitText(a.start,a.end);a=e(q);q.replace(a);
14
+ if(null==m)break}}});b=b.registerNodeTransform(c,a=>{var d=a.getTextContent();const l=f(d);null===l||0!==l.start?p(a):d.length>l.end?a.splitText(l.end):(d=a.getPreviousSibling(),k.$isTextNode(d)&&d.isTextEntity()&&(p(d),p(a)),d=a.getNextSibling(),k.$isTextNode(d)&&d.isTextEntity()&&(p(d),a instanceof c&&p(a)))});return[g,b]};
package/package.json CHANGED
@@ -1,9 +1,5 @@
1
1
  {
2
2
  "name": "@lexical/text",
3
- "author": {
4
- "name": "Dominic Gannaway",
5
- "email": "dg@domgan.com"
6
- },
7
3
  "description": "This package contains utilities and helpers for handling Lexical text.",
8
4
  "keywords": [
9
5
  "lexical",
@@ -13,10 +9,10 @@
13
9
  "text"
14
10
  ],
15
11
  "license": "MIT",
16
- "version": "0.1.15",
12
+ "version": "0.1.18",
17
13
  "main": "LexicalText.js",
18
14
  "peerDependencies": {
19
- "lexical": "0.1.15"
15
+ "lexical": "0.1.18"
20
16
  },
21
17
  "repository": {
22
18
  "type": "git",