@lexical/markdown 0.12.2 → 0.12.3

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.
@@ -20,20 +20,16 @@ var link = require('@lexical/link');
20
20
  * LICENSE file in the root directory of this source tree.
21
21
  *
22
22
  */
23
-
24
23
  function indexBy(list, callback) {
25
24
  const index = {};
26
-
27
25
  for (const item of list) {
28
26
  const key = callback(item);
29
-
30
27
  if (index[key]) {
31
28
  index[key].push(item);
32
29
  } else {
33
30
  index[key] = [item];
34
31
  }
35
32
  }
36
-
37
33
  return index;
38
34
  }
39
35
  function transformersByType(transformers) {
@@ -54,35 +50,30 @@ const PUNCTUATION_OR_SPACE = /[!-/:-@[-`{-~\s]/;
54
50
  *
55
51
  */
56
52
  function createMarkdownExport(transformers) {
57
- const byType = transformersByType(transformers); // Export only uses text formats that are responsible for single format
58
- // e.g. it will filter out *** (bold, italic) and instead use separate ** and *
53
+ const byType = transformersByType(transformers);
59
54
 
55
+ // Export only uses text formats that are responsible for single format
56
+ // e.g. it will filter out *** (bold, italic) and instead use separate ** and *
60
57
  const textFormatTransformers = byType.textFormat.filter(transformer => transformer.format.length === 1);
61
58
  return node => {
62
59
  const output = [];
63
60
  const children = (node || lexical.$getRoot()).getChildren();
64
-
65
61
  for (const child of children) {
66
62
  const result = exportTopLevelElements(child, byType.element, textFormatTransformers, byType.textMatch);
67
-
68
63
  if (result != null) {
69
64
  output.push(result);
70
65
  }
71
66
  }
72
-
73
67
  return output.join('\n\n');
74
68
  };
75
69
  }
76
-
77
70
  function exportTopLevelElements(node, elementTransformers, textTransformersIndex, textMatchTransformers) {
78
71
  for (const transformer of elementTransformers) {
79
72
  const result = transformer.export(node, _node => exportChildren(_node, textTransformersIndex, textMatchTransformers));
80
-
81
73
  if (result != null) {
82
74
  return result;
83
75
  }
84
76
  }
85
-
86
77
  if (lexical.$isElementNode(node)) {
87
78
  return exportChildren(node, textTransformersIndex, textMatchTransformers);
88
79
  } else if (lexical.$isDecoratorNode(node)) {
@@ -91,21 +82,17 @@ function exportTopLevelElements(node, elementTransformers, textTransformersIndex
91
82
  return null;
92
83
  }
93
84
  }
94
-
95
85
  function exportChildren(node, textTransformersIndex, textMatchTransformers) {
96
86
  const output = [];
97
87
  const children = node.getChildren();
98
-
99
88
  mainLoop: for (const child of children) {
100
89
  for (const transformer of textMatchTransformers) {
101
90
  const result = transformer.export(child, parentNode => exportChildren(parentNode, textTransformersIndex, textMatchTransformers), (textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex));
102
-
103
91
  if (result != null) {
104
92
  output.push(result);
105
93
  continue mainLoop;
106
94
  }
107
95
  }
108
-
109
96
  if (lexical.$isLineBreakNode(child)) {
110
97
  output.push('\n');
111
98
  } else if (lexical.$isTextNode(child)) {
@@ -116,10 +103,8 @@ function exportChildren(node, textTransformersIndex, textMatchTransformers) {
116
103
  output.push(child.getTextContent());
117
104
  }
118
105
  }
119
-
120
106
  return output.join('');
121
107
  }
122
-
123
108
  function exportTextFormat(node, textContent, textTransformers) {
124
109
  // This function handles the case of a string looking like this: " foo "
125
110
  // Where it would be invalid markdown to generate: "** foo **"
@@ -128,74 +113,61 @@ function exportTextFormat(node, textContent, textTransformers) {
128
113
  const frozenString = textContent.trim();
129
114
  let output = frozenString;
130
115
  const applied = new Set();
131
-
132
116
  for (const transformer of textTransformers) {
133
117
  const format = transformer.format[0];
134
118
  const tag = transformer.tag;
135
-
136
119
  if (hasFormat(node, format) && !applied.has(format)) {
137
120
  // Multiple tags might be used for the same format (*, _)
138
- applied.add(format); // Prevent adding opening tag is already opened by the previous sibling
139
-
121
+ applied.add(format);
122
+ // Prevent adding opening tag is already opened by the previous sibling
140
123
  const previousNode = getTextSibling(node, true);
141
-
142
124
  if (!hasFormat(previousNode, format)) {
143
125
  output = tag + output;
144
- } // Prevent adding closing tag if next sibling will do it
145
-
126
+ }
146
127
 
128
+ // Prevent adding closing tag if next sibling will do it
147
129
  const nextNode = getTextSibling(node, false);
148
-
149
130
  if (!hasFormat(nextNode, format)) {
150
131
  output += tag;
151
132
  }
152
133
  }
153
- } // Replace trimmed version of textContent ensuring surrounding whitespace is not modified
154
-
134
+ }
155
135
 
136
+ // Replace trimmed version of textContent ensuring surrounding whitespace is not modified
156
137
  return textContent.replace(frozenString, output);
157
- } // Get next or previous text sibling a text node, including cases
158
- // when it's a child of inline element (e.g. link)
159
-
138
+ }
160
139
 
140
+ // Get next or previous text sibling a text node, including cases
141
+ // when it's a child of inline element (e.g. link)
161
142
  function getTextSibling(node, backward) {
162
143
  let sibling = backward ? node.getPreviousSibling() : node.getNextSibling();
163
-
164
144
  if (!sibling) {
165
145
  const parent = node.getParentOrThrow();
166
-
167
146
  if (parent.isInline()) {
168
147
  sibling = backward ? parent.getPreviousSibling() : parent.getNextSibling();
169
148
  }
170
149
  }
171
-
172
150
  while (sibling) {
173
151
  if (lexical.$isElementNode(sibling)) {
174
152
  if (!sibling.isInline()) {
175
153
  break;
176
154
  }
177
-
178
155
  const descendant = backward ? sibling.getLastDescendant() : sibling.getFirstDescendant();
179
-
180
156
  if (lexical.$isTextNode(descendant)) {
181
157
  return descendant;
182
158
  } else {
183
159
  sibling = backward ? sibling.getPreviousSibling() : sibling.getNextSibling();
184
160
  }
185
161
  }
186
-
187
162
  if (lexical.$isTextNode(sibling)) {
188
163
  return sibling;
189
164
  }
190
-
191
165
  if (!lexical.$isElementNode(sibling)) {
192
166
  return null;
193
167
  }
194
168
  }
195
-
196
169
  return null;
197
170
  }
198
-
199
171
  function hasFormat(node, format) {
200
172
  return lexical.$isTextNode(node) && node.hasFormat(format);
201
173
  }
@@ -207,6 +179,7 @@ function hasFormat(node, format) {
207
179
  * LICENSE file in the root directory of this source tree.
208
180
  *
209
181
  */
182
+
210
183
  const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
211
184
 
212
185
  /**
@@ -221,10 +194,13 @@ CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
221
194
  CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);
222
195
  CAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;
223
196
  const IS_SAFARI = CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
224
- const IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; // Keep these in case we need to use them in the future.
225
- // export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
197
+ const IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
198
+ CAN_USE_DOM && /Android/.test(navigator.userAgent);
226
199
 
227
- const IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent); // export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
200
+ // Keep these in case we need to use them in the future.
201
+ // export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
202
+ const IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent);
203
+ // export const canUseTextInputEvent: boolean = CAN_USE_DOM && 'TextEvent' in window && !documentMode;
228
204
 
229
205
  const IS_APPLE_WEBKIT = CAN_USE_DOM && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && !IS_CHROME;
230
206
 
@@ -245,88 +221,74 @@ function createMarkdownImport(transformers) {
245
221
  const linesLength = lines.length;
246
222
  const root = node || lexical.$getRoot();
247
223
  root.clear();
248
-
249
224
  for (let i = 0; i < linesLength; i++) {
250
- const lineText = lines[i]; // Codeblocks are processed first as anything inside such block
225
+ const lineText = lines[i];
226
+ // Codeblocks are processed first as anything inside such block
251
227
  // is ignored for further processing
252
228
  // TODO:
253
229
  // Abstract it to be dynamic as other transformers (add multiline match option)
254
-
255
230
  const [codeBlockNode, shiftedIndex] = importCodeBlock(lines, i, root);
256
-
257
231
  if (codeBlockNode != null) {
258
232
  i = shiftedIndex;
259
233
  continue;
260
234
  }
261
-
262
235
  importBlocks(lineText, root, byType.element, textFormatTransformersIndex, byType.textMatch);
263
- } // Removing empty paragraphs as md does not really
264
- // allow empty lines and uses them as dilimiter
265
-
236
+ }
266
237
 
238
+ // Removing empty paragraphs as md does not really
239
+ // allow empty lines and uses them as dilimiter
267
240
  const children = root.getChildren();
268
-
269
241
  for (const child of children) {
270
242
  if (isEmptyParagraph(child)) {
271
243
  child.remove();
272
244
  }
273
245
  }
274
-
275
246
  if (lexical.$getSelection() !== null) {
276
247
  root.selectEnd();
277
248
  }
278
249
  };
279
250
  }
280
-
281
251
  function isEmptyParagraph(node) {
282
252
  if (!lexical.$isParagraphNode(node)) {
283
253
  return false;
284
254
  }
285
-
286
255
  const firstChild = node.getFirstChild();
287
256
  return firstChild == null || node.getChildrenSize() === 1 && lexical.$isTextNode(firstChild) && MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent());
288
257
  }
289
-
290
258
  function importBlocks(lineText, rootNode, elementTransformers, textFormatTransformersIndex, textMatchTransformers) {
291
259
  const lineTextTrimmed = lineText.trim();
292
260
  const textNode = lexical.$createTextNode(lineTextTrimmed);
293
261
  const elementNode = lexical.$createParagraphNode();
294
262
  elementNode.append(textNode);
295
263
  rootNode.append(elementNode);
296
-
297
264
  for (const {
298
265
  regExp,
299
266
  replace
300
267
  } of elementTransformers) {
301
268
  const match = lineText.match(regExp);
302
-
303
269
  if (match) {
304
270
  textNode.setTextContent(lineText.slice(match[0].length));
305
271
  replace(elementNode, [textNode], match, true);
306
272
  break;
307
273
  }
308
274
  }
275
+ importTextFormatTransformers(textNode, textFormatTransformersIndex, textMatchTransformers);
309
276
 
310
- importTextFormatTransformers(textNode, textFormatTransformersIndex, textMatchTransformers); // If no transformer found and we left with original paragraph node
277
+ // If no transformer found and we left with original paragraph node
311
278
  // can check if its content can be appended to the previous node
312
279
  // if it's a paragraph, quote or list
313
-
314
280
  if (elementNode.isAttached() && lineTextTrimmed.length > 0) {
315
281
  const previousNode = elementNode.getPreviousSibling();
316
-
317
282
  if (lexical.$isParagraphNode(previousNode) || richText.$isQuoteNode(previousNode) || list.$isListNode(previousNode)) {
318
283
  let targetNode = previousNode;
319
-
320
284
  if (list.$isListNode(previousNode)) {
321
285
  const lastDescendant = previousNode.getLastDescendant();
322
-
323
286
  if (lastDescendant == null) {
324
287
  targetNode = null;
325
288
  } else {
326
289
  targetNode = utils.$findMatchingParent(lastDescendant, list.$isListItemNode);
327
290
  }
328
291
  }
329
-
330
292
  if (targetNode != null && targetNode.getTextContentSize() > 0) {
331
293
  targetNode.splice(targetNode.getChildrenSize(), 0, [lexical.$createLineBreakNode(), ...elementNode.getChildren()]);
332
294
  elementNode.remove();
@@ -334,17 +296,13 @@ function importBlocks(lineText, rootNode, elementTransformers, textFormatTransfo
334
296
  }
335
297
  }
336
298
  }
337
-
338
299
  function importCodeBlock(lines, startLineIndex, rootNode) {
339
300
  const openMatch = lines[startLineIndex].match(CODE_BLOCK_REG_EXP);
340
-
341
301
  if (openMatch) {
342
302
  let endLineIndex = startLineIndex;
343
303
  const linesLength = lines.length;
344
-
345
304
  while (++endLineIndex < linesLength) {
346
305
  const closeMatch = lines[endLineIndex].match(CODE_BLOCK_REG_EXP);
347
-
348
306
  if (closeMatch) {
349
307
  const codeBlockNode = code.$createCodeNode(openMatch[1]);
350
308
  const textNode = lexical.$createTextNode(lines.slice(startLineIndex + 1, endLineIndex).join('\n'));
@@ -354,157 +312,133 @@ function importCodeBlock(lines, startLineIndex, rootNode) {
354
312
  }
355
313
  }
356
314
  }
357
-
358
315
  return [null, startLineIndex];
359
- } // Processing text content and replaces text format tags.
316
+ }
317
+
318
+ // Processing text content and replaces text format tags.
360
319
  // It takes outermost tag match and its content, creates text node with
361
320
  // format based on tag and then recursively executed over node's content
362
321
  //
363
322
  // E.g. for "*Hello **world**!*" string it will create text node with
364
323
  // "Hello **world**!" content and italic format and run recursively over
365
324
  // its content to transform "**world**" part
366
-
367
-
368
325
  function importTextFormatTransformers(textNode, textFormatTransformersIndex, textMatchTransformers) {
369
326
  const textContent = textNode.getTextContent();
370
327
  const match = findOutermostMatch(textContent, textFormatTransformersIndex);
371
-
372
328
  if (!match) {
373
329
  // Once text format processing is done run text match transformers, as it
374
330
  // only can span within single text node (unline formats that can cover multiple nodes)
375
331
  importTextMatchTransformers(textNode, textMatchTransformers);
376
332
  return;
377
333
  }
334
+ let currentNode, remainderNode, leadingNode;
378
335
 
379
- let currentNode, remainderNode, leadingNode; // If matching full content there's no need to run splitText and can reuse existing textNode
336
+ // If matching full content there's no need to run splitText and can reuse existing textNode
380
337
  // to update its content and apply format. E.g. for **_Hello_** string after applying bold
381
338
  // format (**) it will reuse the same text node to apply italic (_)
382
-
383
339
  if (match[0] === textContent) {
384
340
  currentNode = textNode;
385
341
  } else {
386
342
  const startIndex = match.index || 0;
387
343
  const endIndex = startIndex + match[0].length;
388
-
389
344
  if (startIndex === 0) {
390
345
  [currentNode, remainderNode] = textNode.splitText(endIndex);
391
346
  } else {
392
347
  [leadingNode, currentNode, remainderNode] = textNode.splitText(startIndex, endIndex);
393
348
  }
394
349
  }
395
-
396
350
  currentNode.setTextContent(match[2]);
397
351
  const transformer = textFormatTransformersIndex.transformersByTag[match[1]];
398
-
399
352
  if (transformer) {
400
353
  for (const format of transformer.format) {
401
354
  if (!currentNode.hasFormat(format)) {
402
355
  currentNode.toggleFormat(format);
403
356
  }
404
357
  }
405
- } // Recursively run over inner text if it's not inline code
406
-
358
+ }
407
359
 
360
+ // Recursively run over inner text if it's not inline code
408
361
  if (!currentNode.hasFormat('code')) {
409
362
  importTextFormatTransformers(currentNode, textFormatTransformersIndex, textMatchTransformers);
410
- } // Run over leading/remaining text if any
411
-
363
+ }
412
364
 
365
+ // Run over leading/remaining text if any
413
366
  if (leadingNode) {
414
367
  importTextFormatTransformers(leadingNode, textFormatTransformersIndex, textMatchTransformers);
415
368
  }
416
-
417
369
  if (remainderNode) {
418
370
  importTextFormatTransformers(remainderNode, textFormatTransformersIndex, textMatchTransformers);
419
371
  }
420
372
  }
421
-
422
373
  function importTextMatchTransformers(textNode_, textMatchTransformers) {
423
374
  let textNode = textNode_;
424
-
425
375
  mainLoop: while (textNode) {
426
376
  for (const transformer of textMatchTransformers) {
427
377
  const match = textNode.getTextContent().match(transformer.importRegExp);
428
-
429
378
  if (!match) {
430
379
  continue;
431
380
  }
432
-
433
381
  const startIndex = match.index || 0;
434
382
  const endIndex = startIndex + match[0].length;
435
383
  let replaceNode, leftTextNode, rightTextNode;
436
-
437
384
  if (startIndex === 0) {
438
385
  [replaceNode, textNode] = textNode.splitText(endIndex);
439
386
  } else {
440
387
  [leftTextNode, replaceNode, rightTextNode] = textNode.splitText(startIndex, endIndex);
441
388
  }
442
-
443
389
  if (leftTextNode) {
444
390
  importTextMatchTransformers(leftTextNode, textMatchTransformers);
445
391
  }
446
-
447
392
  if (rightTextNode) {
448
393
  textNode = rightTextNode;
449
394
  }
450
-
451
395
  transformer.replace(replaceNode, match);
452
396
  continue mainLoop;
453
397
  }
454
-
455
398
  break;
456
399
  }
457
- } // Finds first "<tag>content<tag>" match that is not nested into another tag
458
-
400
+ }
459
401
 
402
+ // Finds first "<tag>content<tag>" match that is not nested into another tag
460
403
  function findOutermostMatch(textContent, textTransformersIndex) {
461
404
  const openTagsMatch = textContent.match(textTransformersIndex.openTagsRegExp);
462
-
463
405
  if (openTagsMatch == null) {
464
406
  return null;
465
407
  }
466
-
467
408
  for (const match of openTagsMatch) {
468
409
  // Open tags reg exp might capture leading space so removing it
469
410
  // before using match to find transformer
470
411
  const tag = match.replace(/^\s/, '');
471
412
  const fullMatchRegExp = textTransformersIndex.fullMatchRegExpByTag[tag];
472
-
473
413
  if (fullMatchRegExp == null) {
474
414
  continue;
475
415
  }
476
-
477
416
  const fullMatch = textContent.match(fullMatchRegExp);
478
417
  const transformer = textTransformersIndex.transformersByTag[tag];
479
-
480
418
  if (fullMatch != null && transformer != null) {
481
419
  if (transformer.intraword !== false) {
482
420
  return fullMatch;
483
- } // For non-intraword transformers checking if it's within a word
484
- // or surrounded with space/punctuation/newline
485
-
421
+ }
486
422
 
423
+ // For non-intraword transformers checking if it's within a word
424
+ // or surrounded with space/punctuation/newline
487
425
  const {
488
426
  index = 0
489
427
  } = fullMatch;
490
428
  const beforeChar = textContent[index - 1];
491
429
  const afterChar = textContent[index + fullMatch[0].length];
492
-
493
430
  if ((!beforeChar || PUNCTUATION_OR_SPACE.test(beforeChar)) && (!afterChar || PUNCTUATION_OR_SPACE.test(afterChar))) {
494
431
  return fullMatch;
495
432
  }
496
433
  }
497
434
  }
498
-
499
435
  return null;
500
436
  }
501
-
502
437
  function createTextFormatTransformersIndex(textTransformers) {
503
438
  const transformersByTag = {};
504
439
  const fullMatchRegExpByTag = {};
505
440
  const openTagsRegExp = [];
506
441
  const escapeRegExp = `(?<![\\\\])`;
507
-
508
442
  for (const transformer of textTransformers) {
509
443
  const {
510
444
  tag
@@ -512,14 +446,12 @@ function createTextFormatTransformersIndex(textTransformers) {
512
446
  transformersByTag[tag] = transformer;
513
447
  const tagRegExp = tag.replace(/(\*|\^|\+)/g, '\\$1');
514
448
  openTagsRegExp.push(tagRegExp);
515
-
516
449
  if (IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT) {
517
450
  fullMatchRegExpByTag[tag] = new RegExp(`(${tagRegExp})(?![${tagRegExp}\\s])(.*?[^${tagRegExp}\\s])${tagRegExp}(?!${tagRegExp})`);
518
451
  } else {
519
452
  fullMatchRegExpByTag[tag] = new RegExp(`(?<![\\\\${tagRegExp}])(${tagRegExp})((\\\\${tagRegExp})?.*?[^${tagRegExp}\\s](\\\\${tagRegExp})?)((?<!\\\\)|(?<=\\\\\\\\))(${tagRegExp})(?![\\\\${tagRegExp}])`);
520
453
  }
521
454
  }
522
-
523
455
  return {
524
456
  // Reg exp to find open tag + content + close tag
525
457
  fullMatchRegExpByTag,
@@ -536,31 +468,27 @@ function createTextFormatTransformersIndex(textTransformers) {
536
468
  * LICENSE file in the root directory of this source tree.
537
469
  *
538
470
  */
539
-
540
471
  function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers) {
541
472
  const grandParentNode = parentNode.getParent();
542
-
543
473
  if (!lexical.$isRootOrShadowRoot(grandParentNode) || parentNode.getFirstChild() !== anchorNode) {
544
474
  return false;
545
475
  }
476
+ const textContent = anchorNode.getTextContent();
546
477
 
547
- const textContent = anchorNode.getTextContent(); // Checking for anchorOffset position to prevent any checks for cases when caret is too far
478
+ // Checking for anchorOffset position to prevent any checks for cases when caret is too far
548
479
  // from a line start to be a part of block-level markdown trigger.
549
480
  //
550
481
  // TODO:
551
482
  // Can have a quick check if caret is close enough to the beginning of the string (e.g. offset less than 10-20)
552
483
  // since otherwise it won't be a markdown shortcut, but tables are exception
553
-
554
484
  if (textContent[anchorOffset - 1] !== ' ') {
555
485
  return false;
556
486
  }
557
-
558
487
  for (const {
559
488
  regExp,
560
489
  replace
561
490
  } of elementTransformers) {
562
491
  const match = textContent.match(regExp);
563
-
564
492
  if (match && match[0].length === anchorOffset) {
565
493
  const nextSiblings = anchorNode.getNextSiblings();
566
494
  const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset);
@@ -570,131 +498,115 @@ function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTra
570
498
  return true;
571
499
  }
572
500
  }
573
-
574
501
  return false;
575
502
  }
576
-
577
503
  function runTextMatchTransformers(anchorNode, anchorOffset, transformersByTrigger) {
578
504
  let textContent = anchorNode.getTextContent();
579
505
  const lastChar = textContent[anchorOffset - 1];
580
506
  const transformers = transformersByTrigger[lastChar];
581
-
582
507
  if (transformers == null) {
583
508
  return false;
584
- } // If typing in the middle of content, remove the tail to do
585
- // reg exp match up to a string end (caret position)
586
-
509
+ }
587
510
 
511
+ // If typing in the middle of content, remove the tail to do
512
+ // reg exp match up to a string end (caret position)
588
513
  if (anchorOffset < textContent.length) {
589
514
  textContent = textContent.slice(0, anchorOffset);
590
515
  }
591
-
592
516
  for (const transformer of transformers) {
593
517
  const match = textContent.match(transformer.regExp);
594
-
595
518
  if (match === null) {
596
519
  continue;
597
520
  }
598
-
599
521
  const startIndex = match.index || 0;
600
522
  const endIndex = startIndex + match[0].length;
601
523
  let replaceNode;
602
-
603
524
  if (startIndex === 0) {
604
525
  [replaceNode] = anchorNode.splitText(endIndex);
605
526
  } else {
606
527
  [, replaceNode] = anchorNode.splitText(startIndex, endIndex);
607
528
  }
608
-
609
529
  replaceNode.selectNext(0, 0);
610
530
  transformer.replace(replaceNode, match);
611
531
  return true;
612
532
  }
613
-
614
533
  return false;
615
534
  }
616
-
617
535
  function runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformers) {
618
536
  const textContent = anchorNode.getTextContent();
619
537
  const closeTagEndIndex = anchorOffset - 1;
620
- const closeChar = textContent[closeTagEndIndex]; // Quick check if we're possibly at the end of inline markdown style
621
-
538
+ const closeChar = textContent[closeTagEndIndex];
539
+ // Quick check if we're possibly at the end of inline markdown style
622
540
  const matchers = textFormatTransformers[closeChar];
623
-
624
541
  if (!matchers) {
625
542
  return false;
626
543
  }
627
-
628
544
  for (const matcher of matchers) {
629
545
  const {
630
546
  tag
631
547
  } = matcher;
632
548
  const tagLength = tag.length;
633
- const closeTagStartIndex = closeTagEndIndex - tagLength + 1; // If tag is not single char check if rest of it matches with text content
549
+ const closeTagStartIndex = closeTagEndIndex - tagLength + 1;
634
550
 
551
+ // If tag is not single char check if rest of it matches with text content
635
552
  if (tagLength > 1) {
636
553
  if (!isEqualSubString(textContent, closeTagStartIndex, tag, 0, tagLength)) {
637
554
  continue;
638
555
  }
639
- } // Space before closing tag cancels inline markdown
640
-
556
+ }
641
557
 
558
+ // Space before closing tag cancels inline markdown
642
559
  if (textContent[closeTagStartIndex - 1] === ' ') {
643
560
  continue;
644
- } // Some tags can not be used within words, hence should have newline/space/punctuation after it
645
-
561
+ }
646
562
 
563
+ // Some tags can not be used within words, hence should have newline/space/punctuation after it
647
564
  const afterCloseTagChar = textContent[closeTagEndIndex + 1];
648
-
649
565
  if (matcher.intraword === false && afterCloseTagChar && !PUNCTUATION_OR_SPACE.test(afterCloseTagChar)) {
650
566
  continue;
651
567
  }
652
-
653
568
  const closeNode = anchorNode;
654
569
  let openNode = closeNode;
655
- let openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag); // Go through text node siblings and search for opening tag
656
- // if haven't found it within the same text node as closing tag
570
+ let openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag);
657
571
 
572
+ // Go through text node siblings and search for opening tag
573
+ // if haven't found it within the same text node as closing tag
658
574
  let sibling = openNode;
659
-
660
575
  while (openTagStartIndex < 0 && (sibling = sibling.getPreviousSibling())) {
661
576
  if (lexical.$isLineBreakNode(sibling)) {
662
577
  break;
663
578
  }
664
-
665
579
  if (lexical.$isTextNode(sibling)) {
666
580
  const siblingTextContent = sibling.getTextContent();
667
581
  openNode = sibling;
668
582
  openTagStartIndex = getOpenTagStartIndex(siblingTextContent, siblingTextContent.length, tag);
669
583
  }
670
- } // Opening tag is not found
671
-
584
+ }
672
585
 
586
+ // Opening tag is not found
673
587
  if (openTagStartIndex < 0) {
674
588
  continue;
675
- } // No content between opening and closing tag
676
-
589
+ }
677
590
 
591
+ // No content between opening and closing tag
678
592
  if (openNode === closeNode && openTagStartIndex + tagLength === closeTagStartIndex) {
679
593
  continue;
680
- } // Checking longer tags for repeating chars (e.g. *** vs **)
681
-
594
+ }
682
595
 
596
+ // Checking longer tags for repeating chars (e.g. *** vs **)
683
597
  const prevOpenNodeText = openNode.getTextContent();
684
-
685
598
  if (openTagStartIndex > 0 && prevOpenNodeText[openTagStartIndex - 1] === closeChar) {
686
599
  continue;
687
- } // Some tags can not be used within words, hence should have newline/space/punctuation before it
688
-
600
+ }
689
601
 
602
+ // Some tags can not be used within words, hence should have newline/space/punctuation before it
690
603
  const beforeOpenTagChar = prevOpenNodeText[openTagStartIndex - 1];
691
-
692
604
  if (matcher.intraword === false && beforeOpenTagChar && !PUNCTUATION_OR_SPACE.test(beforeOpenTagChar)) {
693
605
  continue;
694
- } // Clean text from opening and closing tags (starting from closing tag
695
- // to prevent any offset shifts if we start from opening one)
696
-
606
+ }
697
607
 
608
+ // Clean text from opening and closing tags (starting from closing tag
609
+ // to prevent any offset shifts if we start from opening one)
698
610
  const prevCloseNodeText = closeNode.getTextContent();
699
611
  const closeNodeText = prevCloseNodeText.slice(0, closeTagStartIndex) + prevCloseNodeText.slice(closeTagEndIndex + 1);
700
612
  closeNode.setTextContent(closeNodeText);
@@ -702,62 +614,55 @@ function runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransform
702
614
  openNode.setTextContent(openNodeText.slice(0, openTagStartIndex) + openNodeText.slice(openTagStartIndex + tagLength));
703
615
  const selection = lexical.$getSelection();
704
616
  const nextSelection = lexical.$createRangeSelection();
705
- lexical.$setSelection(nextSelection); // Adjust offset based on deleted chars
706
-
617
+ lexical.$setSelection(nextSelection);
618
+ // Adjust offset based on deleted chars
707
619
  const newOffset = closeTagEndIndex - tagLength * (openNode === closeNode ? 2 : 1) + 1;
708
620
  nextSelection.anchor.set(openNode.__key, openTagStartIndex, 'text');
709
- nextSelection.focus.set(closeNode.__key, newOffset, 'text'); // Apply formatting to selected text
621
+ nextSelection.focus.set(closeNode.__key, newOffset, 'text');
710
622
 
623
+ // Apply formatting to selected text
711
624
  for (const format of matcher.format) {
712
625
  if (!nextSelection.hasFormat(format)) {
713
626
  nextSelection.formatText(format);
714
627
  }
715
- } // Collapse selection up to the focus point
716
-
628
+ }
717
629
 
718
- nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type); // Remove formatting from collapsed selection
630
+ // Collapse selection up to the focus point
631
+ nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type);
719
632
 
633
+ // Remove formatting from collapsed selection
720
634
  for (const format of matcher.format) {
721
635
  if (nextSelection.hasFormat(format)) {
722
636
  nextSelection.toggleFormat(format);
723
637
  }
724
638
  }
725
-
726
639
  if (lexical.$isRangeSelection(selection)) {
727
640
  nextSelection.format = selection.format;
728
641
  }
729
-
730
642
  return true;
731
643
  }
732
-
733
644
  return false;
734
645
  }
735
-
736
646
  function getOpenTagStartIndex(string, maxIndex, tag) {
737
647
  const tagLength = tag.length;
738
-
739
648
  for (let i = maxIndex; i >= tagLength; i--) {
740
649
  const startIndex = i - tagLength;
741
-
742
- if (isEqualSubString(string, startIndex, tag, 0, tagLength) && // Space after opening tag cancels transformation
650
+ if (isEqualSubString(string, startIndex, tag, 0, tagLength) &&
651
+ // Space after opening tag cancels transformation
743
652
  string[startIndex + tagLength] !== ' ') {
744
653
  return startIndex;
745
654
  }
746
655
  }
747
-
748
656
  return -1;
749
657
  }
750
-
751
658
  function isEqualSubString(stringA, aStart, stringB, bStart, length) {
752
659
  for (let i = 0; i < length; i++) {
753
660
  if (stringA[aStart + i] !== stringB[bStart + i]) {
754
661
  return false;
755
662
  }
756
663
  }
757
-
758
664
  return true;
759
665
  }
760
-
761
666
  function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
762
667
  const byType = transformersByType(transformers);
763
668
  const textFormatTransformersIndex = indexBy(byType.textFormat, ({
@@ -766,13 +671,10 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
766
671
  const textMatchTransformersIndex = indexBy(byType.textMatch, ({
767
672
  trigger
768
673
  }) => trigger);
769
-
770
674
  for (const transformer of transformers) {
771
675
  const type = transformer.type;
772
-
773
676
  if (type === 'element' || type === 'text-match') {
774
677
  const dependencies = transformer.dependencies;
775
-
776
678
  for (const node of dependencies) {
777
679
  if (!editor.hasNode(node)) {
778
680
  {
@@ -782,19 +684,15 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
782
684
  }
783
685
  }
784
686
  }
785
-
786
687
  const transform = (parentNode, anchorNode, anchorOffset) => {
787
688
  if (runElementTransformers(parentNode, anchorNode, anchorOffset, byType.element)) {
788
689
  return;
789
690
  }
790
-
791
691
  if (runTextMatchTransformers(anchorNode, anchorOffset, textMatchTransformersIndex)) {
792
692
  return;
793
693
  }
794
-
795
694
  runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformersIndex);
796
695
  };
797
-
798
696
  return editor.registerUpdateListener(({
799
697
  tags,
800
698
  dirtyLeaves,
@@ -804,41 +702,32 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
804
702
  // Ignore updates from undo/redo (as changes already calculated)
805
703
  if (tags.has('historic')) {
806
704
  return;
807
- } // If editor is still composing (i.e. backticks) we must wait before the user confirms the key
808
-
705
+ }
809
706
 
707
+ // If editor is still composing (i.e. backticks) we must wait before the user confirms the key
810
708
  if (editor.isComposing()) {
811
709
  return;
812
710
  }
813
-
814
711
  const selection = editorState.read(lexical.$getSelection);
815
712
  const prevSelection = prevEditorState.read(lexical.$getSelection);
816
-
817
713
  if (!lexical.$isRangeSelection(prevSelection) || !lexical.$isRangeSelection(selection) || !selection.isCollapsed()) {
818
714
  return;
819
715
  }
820
-
821
716
  const anchorKey = selection.anchor.key;
822
717
  const anchorOffset = selection.anchor.offset;
823
-
824
718
  const anchorNode = editorState._nodeMap.get(anchorKey);
825
-
826
719
  if (!lexical.$isTextNode(anchorNode) || !dirtyLeaves.has(anchorKey) || anchorOffset !== 1 && anchorOffset > prevSelection.anchor.offset + 1) {
827
720
  return;
828
721
  }
829
-
830
722
  editor.update(() => {
831
723
  // Markdown is not available inside code
832
724
  if (anchorNode.hasFormat('code')) {
833
725
  return;
834
726
  }
835
-
836
727
  const parentNode = anchorNode.getParent();
837
-
838
728
  if (parentNode === null || code.$isCodeNode(parentNode)) {
839
729
  return;
840
730
  }
841
-
842
731
  transform(parentNode, anchorNode, selection.anchor.offset);
843
732
  });
844
733
  });
@@ -851,7 +740,6 @@ function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) {
851
740
  * LICENSE file in the root directory of this source tree.
852
741
  *
853
742
  */
854
-
855
743
  const createBlockNode = createNode => {
856
744
  return (parentNode, children, match) => {
857
745
  const node = createNode(match);
@@ -859,28 +747,24 @@ const createBlockNode = createNode => {
859
747
  parentNode.replace(node);
860
748
  node.select(0, 0);
861
749
  };
862
- }; // Amount of spaces that define indentation level
863
- // TODO: should be an option
864
-
750
+ };
865
751
 
752
+ // Amount of spaces that define indentation level
753
+ // TODO: should be an option
866
754
  const LIST_INDENT_SIZE = 4;
867
-
868
755
  const listReplace = listType => {
869
756
  return (parentNode, children, match) => {
870
757
  const previousNode = parentNode.getPreviousSibling();
871
758
  const nextNode = parentNode.getNextSibling();
872
759
  const listItem = list.$createListItemNode(listType === 'check' ? match[3] === 'x' : undefined);
873
-
874
760
  if (list.$isListNode(nextNode) && nextNode.getListType() === listType) {
875
761
  const firstChild = nextNode.getFirstChild();
876
-
877
762
  if (firstChild !== null) {
878
763
  firstChild.insertBefore(listItem);
879
764
  } else {
880
765
  // should never happen, but let's handle gracefully, just in case.
881
766
  nextNode.append(listItem);
882
767
  }
883
-
884
768
  parentNode.remove();
885
769
  } else if (list.$isListNode(previousNode) && previousNode.getListType() === listType) {
886
770
  previousNode.append(listItem);
@@ -890,33 +774,27 @@ const listReplace = listType => {
890
774
  list$1.append(listItem);
891
775
  parentNode.replace(list$1);
892
776
  }
893
-
894
777
  listItem.append(...children);
895
778
  listItem.select(0, 0);
896
779
  const indent = Math.floor(match[1].length / LIST_INDENT_SIZE);
897
-
898
780
  if (indent) {
899
781
  listItem.setIndent(indent);
900
782
  }
901
783
  };
902
784
  };
903
-
904
785
  const listExport = (listNode, exportChildren, depth) => {
905
786
  const output = [];
906
787
  const children = listNode.getChildren();
907
788
  let index = 0;
908
-
909
789
  for (const listItemNode of children) {
910
790
  if (list.$isListItemNode(listItemNode)) {
911
791
  if (listItemNode.getChildrenSize() === 1) {
912
792
  const firstChild = listItemNode.getFirstChild();
913
-
914
793
  if (list.$isListNode(firstChild)) {
915
794
  output.push(listExport(firstChild, exportChildren, depth + 1));
916
795
  continue;
917
796
  }
918
797
  }
919
-
920
798
  const indent = ' '.repeat(depth * LIST_INDENT_SIZE);
921
799
  const listType = listNode.getListType();
922
800
  const prefix = listType === 'number' ? `${listNode.getStart() + index}. ` : listType === 'check' ? `- [${listItemNode.getChecked() ? 'x' : ' '}] ` : '- ';
@@ -924,17 +802,14 @@ const listExport = (listNode, exportChildren, depth) => {
924
802
  index++;
925
803
  }
926
804
  }
927
-
928
805
  return output.join('\n');
929
806
  };
930
-
931
807
  const HEADING = {
932
808
  dependencies: [richText.HeadingNode],
933
809
  export: (node, exportChildren) => {
934
810
  if (!richText.$isHeadingNode(node)) {
935
811
  return null;
936
812
  }
937
-
938
813
  const level = Number(node.getTag().slice(1));
939
814
  return '#'.repeat(level) + ' ' + exportChildren(node);
940
815
  },
@@ -951,21 +826,17 @@ const QUOTE = {
951
826
  if (!richText.$isQuoteNode(node)) {
952
827
  return null;
953
828
  }
954
-
955
829
  const lines = exportChildren(node).split('\n');
956
830
  const output = [];
957
-
958
831
  for (const line of lines) {
959
832
  output.push('> ' + line);
960
833
  }
961
-
962
834
  return output.join('\n');
963
835
  },
964
836
  regExp: /^>\s/,
965
837
  replace: (parentNode, children, _match, isImport) => {
966
838
  if (isImport) {
967
839
  const previousNode = parentNode.getPreviousSibling();
968
-
969
840
  if (richText.$isQuoteNode(previousNode)) {
970
841
  previousNode.splice(previousNode.getChildrenSize(), 0, [lexical.$createLineBreakNode(), ...children]);
971
842
  previousNode.select(0, 0);
@@ -973,7 +844,6 @@ const QUOTE = {
973
844
  return;
974
845
  }
975
846
  }
976
-
977
847
  const node = richText.$createQuoteNode();
978
848
  node.append(...children);
979
849
  parentNode.replace(node);
@@ -987,7 +857,6 @@ const CODE = {
987
857
  if (!code.$isCodeNode(node)) {
988
858
  return null;
989
859
  }
990
-
991
860
  const textContent = node.getTextContent();
992
861
  return '```' + (node.getLanguage() || '') + (textContent ? '\n' + textContent : '') + '\n' + '```';
993
862
  },
@@ -1071,23 +940,23 @@ const ITALIC_UNDERSCORE = {
1071
940
  intraword: false,
1072
941
  tag: '_',
1073
942
  type: 'text-format'
1074
- }; // Order of text transformers matters:
943
+ };
944
+
945
+ // Order of text transformers matters:
1075
946
  //
1076
947
  // - code should go first as it prevents any transformations inside
1077
948
  // - then longer tags match (e.g. ** or __ should go before * or _)
1078
-
1079
949
  const LINK = {
1080
950
  dependencies: [link.LinkNode],
1081
951
  export: (node, exportChildren, exportFormat) => {
1082
952
  if (!link.$isLinkNode(node)) {
1083
953
  return null;
1084
954
  }
1085
-
1086
955
  const title = node.getTitle();
1087
956
  const linkContent = title ? `[${node.getTextContent()}](${node.getURL()} "${title}")` : `[${node.getTextContent()}](${node.getURL()})`;
1088
- const firstChild = node.getFirstChild(); // Add text styles only if link has single text node inside. If it's more
957
+ const firstChild = node.getFirstChild();
958
+ // Add text styles only if link has single text node inside. If it's more
1089
959
  // then one we ignore it as markdown does not support nested styles for links
1090
-
1091
960
  if (node.getChildrenSize() === 1 && lexical.$isTextNode(firstChild)) {
1092
961
  return exportFormat(firstChild, linkContent);
1093
962
  } else {
@@ -1111,20 +980,19 @@ const LINK = {
1111
980
  };
1112
981
 
1113
982
  /** @module @lexical/markdown */
1114
- const ELEMENT_TRANSFORMERS = [HEADING, QUOTE, CODE, UNORDERED_LIST, ORDERED_LIST]; // Order of text format transformers matters:
983
+ const ELEMENT_TRANSFORMERS = [HEADING, QUOTE, CODE, UNORDERED_LIST, ORDERED_LIST];
984
+
985
+ // Order of text format transformers matters:
1115
986
  //
1116
987
  // - code should go first as it prevents any transformations inside
1117
988
  // - then longer tags match (e.g. ** or __ should go before * or _)
1118
-
1119
989
  const TEXT_FORMAT_TRANSFORMERS = [INLINE_CODE, BOLD_ITALIC_STAR, BOLD_ITALIC_UNDERSCORE, BOLD_STAR, BOLD_UNDERSCORE, HIGHLIGHT, ITALIC_STAR, ITALIC_UNDERSCORE, STRIKETHROUGH];
1120
990
  const TEXT_MATCH_TRANSFORMERS = [LINK];
1121
991
  const TRANSFORMERS = [...ELEMENT_TRANSFORMERS, ...TEXT_FORMAT_TRANSFORMERS, ...TEXT_MATCH_TRANSFORMERS];
1122
-
1123
992
  function $convertFromMarkdownString(markdown, transformers = TRANSFORMERS, node) {
1124
993
  const importMarkdown = createMarkdownImport(transformers);
1125
994
  return importMarkdown(markdown, node);
1126
995
  }
1127
-
1128
996
  function $convertToMarkdownString(transformers = TRANSFORMERS, node) {
1129
997
  const exportMarkdown = createMarkdownExport(transformers);
1130
998
  return exportMarkdown(node);
@@ -4,26 +4,26 @@
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"),t=require("@lexical/code"),A=require("@lexical/list"),B=require("@lexical/rich-text"),aa=require("@lexical/utils"),G=require("@lexical/link");function H(a,b){let c={};for(let d of a)a=b(d),c[a]?c[a].push(d):c[a]=[d];return c}function I(a){a=H(a,b=>b.type);return{element:a.element||[],textFormat:a["text-format"]||[],textMatch:a["text-match"]||[]}}let J=/[!-/:-@[-`{-~\s]/;
7
+ 'use strict';var k=require("lexical"),t=require("@lexical/code"),z=require("@lexical/list"),B=require("@lexical/rich-text"),aa=require("@lexical/utils"),G=require("@lexical/link");function H(a,b){let c={};for(let d of a)a=b(d),c[a]?c[a].push(d):c[a]=[d];return c}function I(a){a=H(a,b=>b.type);return{element:a.element||[],textFormat:a["text-format"]||[],textMatch:a["text-match"]||[]}}let J=/[!-/:-@[-`{-~\s]/;
8
8
  function ba(a){let b=I(a),c=b.textFormat.filter(d=>1===d.format.length);return d=>{let e=[];d=(d||k.$getRoot()).getChildren();for(let f of d)d=ca(f,b.element,c,b.textMatch),null!=d&&e.push(d);return e.join("\n\n")}}function ca(a,b,c,d){for(let e of b)if(b=e.export(a,f=>K(f,c,d)),null!=b)return b;return k.$isElementNode(a)?K(a,c,d):k.$isDecoratorNode(a)?a.getTextContent():null}
9
9
  function K(a,b,c){let d=[];a=a.getChildren();a:for(let e of a){for(let f of c)if(a=f.export(e,g=>K(g,b,c),(g,l)=>L(g,l,b)),null!=a){d.push(a);continue a}k.$isLineBreakNode(e)?d.push("\n"):k.$isTextNode(e)?d.push(L(e,e.getTextContent(),b)):k.$isElementNode(e)?d.push(K(e,b,c)):k.$isDecoratorNode(e)&&d.push(e.getTextContent())}return d.join("")}
10
10
  function L(a,b,c){let d=b.trim(),e=d,f=new Set;for(let l of c){c=l.format[0];let p=l.tag;if(M(a,c)&&!f.has(c)){f.add(c);var g=N(a,!0);M(g,c)||(e=p+e);g=N(a,!1);M(g,c)||(e+=p)}}return b.replace(d,e)}
11
11
  function N(a,b){let c=b?a.getPreviousSibling():a.getNextSibling();c||(a=a.getParentOrThrow(),a.isInline()&&(c=b?a.getPreviousSibling():a.getNextSibling()));for(;c;){if(k.$isElementNode(c)){if(!c.isInline())break;a=b?c.getLastDescendant():c.getFirstDescendant();if(k.$isTextNode(a))return a;c=b?c.getPreviousSibling():c.getNextSibling()}if(k.$isTextNode(c))return c;if(!k.$isElementNode(c))break}return null}function M(a,b){return k.$isTextNode(a)&&a.hasFormat(b)}
12
- let O="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement,da=O&&"documentMode"in document?document.documentMode:null;O&&/Mac|iPod|iPhone|iPad/.test(navigator.platform);O&&/^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);O&&"InputEvent"in window&&!da?"getTargetRanges"in new window.InputEvent("input"):!1;
13
- let P=O&&/Version\/[\d.]+.*Safari/.test(navigator.userAgent),Q=O&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream,ea=O&&/^(?=.*Chrome).*/i.test(navigator.userAgent),R=O&&/AppleWebKit\/[\d.]+/.test(navigator.userAgent)&&!ea,fa=/^\s{0,3}$/,S=/^```(\w{1,10})?\s?$/;
12
+ let O="undefined"!==typeof window&&"undefined"!==typeof window.document&&"undefined"!==typeof window.document.createElement,da=O&&"documentMode"in document?document.documentMode:null;O&&/Mac|iPod|iPhone|iPad/.test(navigator.platform);O&&/^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent);O&&"InputEvent"in window&&!da?"getTargetRanges"in new window.InputEvent("input"):!1;let P=O&&/Version\/[\d.]+.*Safari/.test(navigator.userAgent),Q=O&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream;
13
+ O&&/Android/.test(navigator.userAgent);let ea=O&&/^(?=.*Chrome).*/i.test(navigator.userAgent),R=O&&/AppleWebKit\/[\d.]+/.test(navigator.userAgent)&&!ea,fa=/^\s{0,3}$/,S=/^```(\w{1,10})?\s?$/;
14
14
  function ha(a){let b=I(a),c=ia(b.textFormat);return(d,e)=>{d=d.split("\n");var f=d.length;e=e||k.$getRoot();e.clear();for(let h=0;h<f;h++){var g=d[h];a:{var l=d,p=h;var r=e;var y=l[p].match(S);if(y)for(var q=p,m=l.length;++q<m;)if(l[q].match(S)){y=t.$createCodeNode(y[1]);l=k.$createTextNode(l.slice(p+1,q).join("\n"));y.append(l);r.append(y);r=[y,q];break a}r=[null,p]}let [n,v]=r;if(null!=n)h=v;else{r=g;m=e;var w=b.element;q=c;l=b.textMatch;p=r.trim();y=k.$createTextNode(p);g=k.$createParagraphNode();
15
- g.append(y);m.append(g);for(let {regExp:x,replace:u}of w)if(m=r.match(x)){y.setTextContent(r.slice(m[0].length));u(g,[y],m,!0);break}T(y,q,l);g.isAttached()&&0<p.length&&(r=g.getPreviousSibling(),k.$isParagraphNode(r)||B.$isQuoteNode(r)||A.$isListNode(r))&&(q=r,A.$isListNode(r)&&(r=r.getLastDescendant(),q=null==r?null:aa.$findMatchingParent(r,A.$isListItemNode)),null!=q&&0<q.getTextContentSize()&&(q.splice(q.getChildrenSize(),0,[k.$createLineBreakNode(),...g.getChildren()]),g.remove()))}}d=e.getChildren();
15
+ g.append(y);m.append(g);for(let {regExp:x,replace:u}of w)if(m=r.match(x)){y.setTextContent(r.slice(m[0].length));u(g,[y],m,!0);break}T(y,q,l);g.isAttached()&&0<p.length&&(r=g.getPreviousSibling(),k.$isParagraphNode(r)||B.$isQuoteNode(r)||z.$isListNode(r))&&(q=r,z.$isListNode(r)&&(r=r.getLastDescendant(),q=null==r?null:aa.$findMatchingParent(r,z.$isListItemNode)),null!=q&&0<q.getTextContentSize()&&(q.splice(q.getChildrenSize(),0,[k.$createLineBreakNode(),...g.getChildren()]),g.remove()))}}d=e.getChildren();
16
16
  for(let h of d)d=h,k.$isParagraphNode(d)?(f=d.getFirstChild(),d=null==f||1===d.getChildrenSize()&&k.$isTextNode(f)&&fa.test(f.getTextContent())):d=!1,d&&h.remove();null!==k.$getSelection()&&e.selectEnd()}}
17
17
  function T(a,b,c){var d=a.getTextContent();let e=ja(d,b);if(e){var f,g;if(e[0]===d)var l=a;else{d=e.index||0;let p=d+e[0].length;0===d?[l,f]=a.splitText(p):[g,l,f]=a.splitText(d,p)}l.setTextContent(e[2]);if(a=b.transformersByTag[e[1]])for(let p of a.format)l.hasFormat(p)||l.toggleFormat(p);l.hasFormat("code")||T(l,b,c);g&&T(g,b,c);f&&T(f,b,c)}else U(a,c)}
18
18
  function U(a,b){a:for(;a;){for(let c of b){let d=a.getTextContent().match(c.importRegExp);if(!d)continue;let e=d.index||0,f=e+d[0].length,g,l,p;0===e?[g,a]=a.splitText(f):[l,g,p]=a.splitText(e,f);l&&U(l,b);p&&(a=p);c.replace(g,d);continue a}break}}
19
19
  function ja(a,b){var c=a.match(b.openTagsRegExp);if(null==c)return null;for(let f of c){var d=f.replace(/^\s/,"");c=b.fullMatchRegExpByTag[d];if(null!=c&&(c=a.match(c),d=b.transformersByTag[d],null!=c&&null!=d)){if(!1!==d.intraword)return c;var {index:e=0}=c;d=a[e-1];e=a[e+c[0].length];if(!(d&&!J.test(d)||e&&!J.test(e)))return c}}return null}
20
20
  function ia(a){let b={},c={},d=[];for(let e of a){({tag:a}=e);b[a]=e;let f=a.replace(/(\*|\^|\+)/g,"\\$1");d.push(f);c[a]=P||Q||R?new RegExp(`(${f})(?![${f}\\s])(.*?[^${f}\\s])${f}(?!${f})`):new RegExp(`(?<![\\\\${f}])(${f})((\\\\${f})?.*?[^${f}\\s](\\\\${f})?)((?<!\\\\)|(?<=\\\\\\\\))(${f})(?![\\\\${f}])`)}return{fullMatchRegExpByTag:c,openTagsRegExp:new RegExp((P||Q||R?"":"(?<![\\\\])")+"("+d.join("|")+")","g"),transformersByTag:b}}
21
21
  function V(a,b,c){let d=c.length;for(;b>=d;b--){let e=b-d;if(W(a,e,c,0,d)&&" "!==a[e+d])return e}return-1}function W(a,b,c,d,e){for(let f=0;f<e;f++)if(a[b+f]!==c[d+f])return!1;return!0}
22
- let ka=a=>(b,c,d)=>{d=a(d);d.append(...c);b.replace(d);d.select(0,0)},X=a=>(b,c,d)=>{var e=b.getPreviousSibling(),f=b.getNextSibling();const g=A.$createListItemNode("check"===a?"x"===d[3]:void 0);A.$isListNode(f)&&f.getListType()===a?(e=f.getFirstChild(),null!==e?e.insertBefore(g):f.append(g),b.remove()):A.$isListNode(e)&&e.getListType()===a?(e.append(g),b.remove()):(f=A.$createListNode(a,"number"===a?Number(d[2]):void 0),f.append(g),b.replace(f));g.append(...c);g.select(0,0);(b=Math.floor(d[1].length/
23
- 4))&&g.setIndent(b)},Y=(a,b,c)=>{const d=[];var e=a.getChildren();let f=0;for(const l of e)if(A.$isListItemNode(l)){if(1===l.getChildrenSize()&&(e=l.getFirstChild(),A.$isListNode(e))){d.push(Y(e,b,c+1));continue}e=" ".repeat(4*c);var g=a.getListType();g="number"===g?`${a.getStart()+f}. `:"check"===g?`- [${l.getChecked()?"x":" "}] `:"- ";d.push(e+g+b(l));f++}return d.join("\n")},la={dependencies:[B.HeadingNode],export:(a,b)=>{if(!B.$isHeadingNode(a))return null;const c=Number(a.getTag().slice(1));
22
+ let ka=a=>(b,c,d)=>{d=a(d);d.append(...c);b.replace(d);d.select(0,0)},X=a=>(b,c,d)=>{var e=b.getPreviousSibling(),f=b.getNextSibling();const g=z.$createListItemNode("check"===a?"x"===d[3]:void 0);z.$isListNode(f)&&f.getListType()===a?(e=f.getFirstChild(),null!==e?e.insertBefore(g):f.append(g),b.remove()):z.$isListNode(e)&&e.getListType()===a?(e.append(g),b.remove()):(f=z.$createListNode(a,"number"===a?Number(d[2]):void 0),f.append(g),b.replace(f));g.append(...c);g.select(0,0);(b=Math.floor(d[1].length/
23
+ 4))&&g.setIndent(b)},Y=(a,b,c)=>{const d=[];var e=a.getChildren();let f=0;for(const l of e)if(z.$isListItemNode(l)){if(1===l.getChildrenSize()&&(e=l.getFirstChild(),z.$isListNode(e))){d.push(Y(e,b,c+1));continue}e=" ".repeat(4*c);var g=a.getListType();g="number"===g?`${a.getStart()+f}. `:"check"===g?`- [${l.getChecked()?"x":" "}] `:"- ";d.push(e+g+b(l));f++}return d.join("\n")},la={dependencies:[B.HeadingNode],export:(a,b)=>{if(!B.$isHeadingNode(a))return null;const c=Number(a.getTag().slice(1));
24
24
  return"#".repeat(c)+" "+b(a)},regExp:/^(#{1,6})\s/,replace:ka(a=>B.$createHeadingNode("h"+a[1].length)),type:"element"},ma={dependencies:[B.QuoteNode],export:(a,b)=>{if(!B.$isQuoteNode(a))return null;a=b(a).split("\n");b=[];for(const c of a)b.push("> "+c);return b.join("\n")},regExp:/^>\s/,replace:(a,b,c,d)=>{if(d&&(c=a.getPreviousSibling(),B.$isQuoteNode(c))){c.splice(c.getChildrenSize(),0,[k.$createLineBreakNode(),...b]);c.select(0,0);a.remove();return}c=B.$createQuoteNode();c.append(...b);a.replace(c);
25
- c.select(0,0)},type:"element"},na={dependencies:[t.CodeNode],export:a=>{if(!t.$isCodeNode(a))return null;const b=a.getTextContent();return"```"+(a.getLanguage()||"")+(b?"\n"+b:"")+"\n```"},regExp:/^```(\w{1,10})?\s/,replace:ka(a=>t.$createCodeNode(a?a[1]:void 0)),type:"element"},oa={dependencies:[A.ListNode,A.ListItemNode],export:(a,b)=>A.$isListNode(a)?Y(a,b,0):null,regExp:/^(\s*)[-*+]\s/,replace:X("bullet"),type:"element"},pa={dependencies:[A.ListNode,A.ListItemNode],export:(a,b)=>A.$isListNode(a)?
26
- Y(a,b,0):null,regExp:/^(\s*)(?:-\s)?\s?(\[(\s|x)?\])\s/i,replace:X("check"),type:"element"},qa={dependencies:[A.ListNode,A.ListItemNode],export:(a,b)=>A.$isListNode(a)?Y(a,b,0):null,regExp:/^(\s*)(\d{1,})\.\s/,replace:X("number"),type:"element"},ra={format:["code"],tag:"`",type:"text-format"},sa={format:["highlight"],tag:"==",type:"text-format"},ta={format:["bold","italic"],tag:"***",type:"text-format"},va={format:["bold","italic"],intraword:!1,tag:"___",type:"text-format"},wa={format:["bold"],tag:"**",
25
+ c.select(0,0)},type:"element"},na={dependencies:[t.CodeNode],export:a=>{if(!t.$isCodeNode(a))return null;const b=a.getTextContent();return"```"+(a.getLanguage()||"")+(b?"\n"+b:"")+"\n```"},regExp:/^```(\w{1,10})?\s/,replace:ka(a=>t.$createCodeNode(a?a[1]:void 0)),type:"element"},oa={dependencies:[z.ListNode,z.ListItemNode],export:(a,b)=>z.$isListNode(a)?Y(a,b,0):null,regExp:/^(\s*)[-*+]\s/,replace:X("bullet"),type:"element"},pa={dependencies:[z.ListNode,z.ListItemNode],export:(a,b)=>z.$isListNode(a)?
26
+ Y(a,b,0):null,regExp:/^(\s*)(?:-\s)?\s?(\[(\s|x)?\])\s/i,replace:X("check"),type:"element"},qa={dependencies:[z.ListNode,z.ListItemNode],export:(a,b)=>z.$isListNode(a)?Y(a,b,0):null,regExp:/^(\s*)(\d{1,})\.\s/,replace:X("number"),type:"element"},ra={format:["code"],tag:"`",type:"text-format"},sa={format:["highlight"],tag:"==",type:"text-format"},ta={format:["bold","italic"],tag:"***",type:"text-format"},va={format:["bold","italic"],intraword:!1,tag:"___",type:"text-format"},wa={format:["bold"],tag:"**",
27
27
  type:"text-format"},xa={format:["bold"],intraword:!1,tag:"__",type:"text-format"},ya={format:["strikethrough"],tag:"~~",type:"text-format"},za={format:["italic"],tag:"*",type:"text-format"},Aa={format:["italic"],intraword:!1,tag:"_",type:"text-format"},Ba={dependencies:[G.LinkNode],export:(a,b,c)=>{if(!G.$isLinkNode(a))return null;b=(b=a.getTitle())?`[${a.getTextContent()}](${a.getURL()} "${b}")`:`[${a.getTextContent()}](${a.getURL()})`;const d=a.getFirstChild();return 1===a.getChildrenSize()&&k.$isTextNode(d)?
28
28
  c(d,b):b},importRegExp:/(?:\[([^[]+)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/,regExp:/(?:\[([^[]+)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/,replace:(a,b)=>{const [,c,d,e]=b;b=G.$createLinkNode(d,{title:e});const f=k.$createTextNode(c);f.setFormat(a.getFormat());b.append(f);a.replace(b)},trigger:")",type:"text-match"},Ca=[la,ma,na,oa,qa],Da=[ra,ta,va,wa,xa,sa,za,Aa,ya],Ea=[Ba],Z=[...Ca,...Da,...Ea];
29
29
  exports.$convertFromMarkdownString=function(a,b=Z,c){return ha(b)(a,c)};exports.$convertToMarkdownString=function(a=Z,b){return ba(a)(b)};exports.BOLD_ITALIC_STAR=ta;exports.BOLD_ITALIC_UNDERSCORE=va;exports.BOLD_STAR=wa;exports.BOLD_UNDERSCORE=xa;exports.CHECK_LIST=pa;exports.CODE=na;exports.ELEMENT_TRANSFORMERS=Ca;exports.HEADING=la;exports.HIGHLIGHT=sa;exports.INLINE_CODE=ra;exports.ITALIC_STAR=za;exports.ITALIC_UNDERSCORE=Aa;exports.LINK=Ba;exports.ORDERED_LIST=qa;exports.QUOTE=ma;
@@ -31,5 +31,5 @@ exports.STRIKETHROUGH=ya;exports.TEXT_FORMAT_TRANSFORMERS=Da;exports.TEXT_MATCH_
31
31
  exports.registerMarkdownShortcuts=function(a,b=Z){let c=I(b),d=H(c.textFormat,({tag:f})=>f[f.length-1]),e=H(c.textMatch,({trigger:f})=>f);for(let f of b)if(b=f.type,"element"===b||"text-match"===b){b=f.dependencies;for(let g of b)if(!a.hasNode(g))throw Error(`MarkdownShortcuts: missing dependency ${g.getType()} for transformer. Ensure node dependency is included in editor initial config.`);}return a.registerUpdateListener(({tags:f,dirtyLeaves:g,editorState:l,prevEditorState:p})=>{if(!f.has("historic")&&
32
32
  !a.isComposing()){var r=l.read(k.$getSelection);f=p.read(k.$getSelection);if(k.$isRangeSelection(f)&&k.$isRangeSelection(r)&&r.isCollapsed()){p=r.anchor.key;var y=r.anchor.offset,q=l._nodeMap.get(p);!k.$isTextNode(q)||!g.has(p)||1!==y&&y>f.anchor.offset+1||a.update(()=>{if(!q.hasFormat("code")){var m=q.getParent();if(null!==m&&!t.$isCodeNode(m)){var w=r.anchor.offset;b:{var h=c.element,n=m.getParent();if(k.$isRootOrShadowRoot(n)&&m.getFirstChild()===q&&(n=q.getTextContent()," "===n[w-1]))for(let {regExp:D,
33
33
  replace:E}of h)if((h=n.match(D))&&h[0].length===w){n=q.getNextSiblings();let [F,ua]=q.splitText(w);F.remove();n=ua?[ua,...n]:n;E(m,n,h,!1);m=!0;break b}m=!1}if(!m){b:{h=q.getTextContent();m=e[h[w-1]];if(null!=m){w<h.length&&(h=h.slice(0,w));for(x of m)if(m=h.match(x.regExp),null!==m){h=m.index||0;n=h+m[0].length;var v=void 0;0===h?[v]=q.splitText(n):[,v]=q.splitText(h,n);v.selectNext(0,0);x.replace(v,m);var x=!0;break b}}x=!1}if(!x)b:{n=q.getTextContent();--w;var u=n[w];if(x=d[u])for(let D of x){var {tag:C}=
34
- D;x=C.length;let E=w-x+1;if(!(1<x&&!W(n,E,C,0,x)||" "===n[E-1])&&(v=n[w+1],!1!==D.intraword||!v||J.test(v))){m=v=q;h=V(n,E,C);for(var z=m;0>h&&(z=z.getPreviousSibling())&&!k.$isLineBreakNode(z);)k.$isTextNode(z)&&(h=z.getTextContent(),m=z,h=V(h,h.length,C));if(!(0>h||m===v&&h+x===E||(C=m.getTextContent(),0<h&&C[h-1]===u||(z=C[h-1],!1===D.intraword&&z&&!J.test(z))))){n=v.getTextContent();n=n.slice(0,E)+n.slice(w+1);v.setTextContent(n);n=m===v?n:C;m.setTextContent(n.slice(0,h)+n.slice(h+x));n=k.$getSelection();
34
+ D;x=C.length;let E=w-x+1;if(!(1<x&&!W(n,E,C,0,x)||" "===n[E-1])&&(v=n[w+1],!1!==D.intraword||!v||J.test(v))){m=v=q;h=V(n,E,C);for(var A=m;0>h&&(A=A.getPreviousSibling())&&!k.$isLineBreakNode(A);)k.$isTextNode(A)&&(h=A.getTextContent(),m=A,h=V(h,h.length,C));if(!(0>h||m===v&&h+x===E||(C=m.getTextContent(),0<h&&C[h-1]===u||(A=C[h-1],!1===D.intraword&&A&&!J.test(A))))){n=v.getTextContent();n=n.slice(0,E)+n.slice(w+1);v.setTextContent(n);n=m===v?n:C;m.setTextContent(n.slice(0,h)+n.slice(h+x));n=k.$getSelection();
35
35
  u=k.$createRangeSelection();k.$setSelection(u);w=w-x*(m===v?2:1)+1;u.anchor.set(m.__key,h,"text");u.focus.set(v.__key,w,"text");for(let F of D.format)u.hasFormat(F)||u.formatText(F);u.anchor.set(u.focus.key,u.focus.offset,u.focus.type);for(let F of D.format)u.hasFormat(F)&&u.toggleFormat(F);k.$isRangeSelection(n)&&(u.format=n.format);break b}}}}}}}})}}})}
package/package.json CHANGED
@@ -8,18 +8,18 @@
8
8
  "markdown"
9
9
  ],
10
10
  "license": "MIT",
11
- "version": "0.12.2",
11
+ "version": "0.12.3",
12
12
  "main": "LexicalMarkdown.js",
13
13
  "peerDependencies": {
14
- "lexical": "0.12.2"
14
+ "lexical": "0.12.3"
15
15
  },
16
16
  "dependencies": {
17
- "@lexical/utils": "0.12.2",
18
- "@lexical/code": "0.12.2",
19
- "@lexical/text": "0.12.2",
20
- "@lexical/rich-text": "0.12.2",
21
- "@lexical/list": "0.12.2",
22
- "@lexical/link": "0.12.2"
17
+ "@lexical/utils": "0.12.3",
18
+ "@lexical/code": "0.12.3",
19
+ "@lexical/text": "0.12.3",
20
+ "@lexical/rich-text": "0.12.3",
21
+ "@lexical/list": "0.12.3",
22
+ "@lexical/link": "0.12.3"
23
23
  },
24
24
  "repository": {
25
25
  "type": "git",