@haklex/rich-editor 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{RichEditor-B9KIgSwn.js → RichEditor-DnJwe663.js} +582 -18
- package/dist/components/RichEditor.d.ts.map +1 -1
- package/dist/components/decorators/AlertEditDecorator.d.ts.map +1 -1
- package/dist/components/decorators/CodeBlockEditDecorator.d.ts.map +1 -1
- package/dist/components/renderers/CodeBlockRenderer.d.ts +5 -0
- package/dist/components/renderers/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/editor.mjs +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +198 -35
- package/dist/nodes/CodeBlockEditNode.d.ts +9 -0
- package/dist/nodes/CodeBlockEditNode.d.ts.map +1 -1
- package/dist/nodes/CodeBlockNode.d.ts +1 -0
- package/dist/nodes/CodeBlockNode.d.ts.map +1 -1
- package/dist/nodes/MentionNode.d.ts +2 -0
- package/dist/nodes/MentionNode.d.ts.map +1 -1
- package/dist/plugins/BlockExitPlugin.d.ts +2 -0
- package/dist/plugins/BlockExitPlugin.d.ts.map +1 -0
- package/dist/plugins/BlockIdPlugin.d.ts +3 -0
- package/dist/plugins/BlockIdPlugin.d.ts.map +1 -0
- package/dist/rich-editor.css +1 -1
- package/dist/static-entry.mjs +1 -1
- package/dist/{theme-D1COY7pa.js → theme-gVNBI_ET.js} +79 -50
- package/dist/transformers/code-block.d.ts +3 -0
- package/dist/transformers/code-block.d.ts.map +1 -0
- package/dist/transformers/index.d.ts +1 -0
- package/dist/transformers/index.d.ts.map +1 -1
- package/dist/transformers/quote.d.ts +3 -0
- package/dist/transformers/quote.d.ts.map +1 -0
- package/dist/utils/codeBlockSelectionIntent.d.ts +4 -0
- package/dist/utils/codeBlockSelectionIntent.d.ts.map +1 -0
- package/dist/utils/comment-anchor.d.ts +32 -0
- package/dist/utils/comment-anchor.d.ts.map +1 -0
- package/package.json +5 -5
|
@@ -12,10 +12,10 @@ import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
|
12
12
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
13
13
|
import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
|
|
14
14
|
import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
|
|
15
|
-
import {
|
|
16
|
-
import { $getNodeByKey, $insertNodes, createEditor, $
|
|
15
|
+
import { Y as $isAlertQuoteNode, d as RendererWrapper, Z as AlertRenderer, _ as SpoilerNode, T as MentionNode, a0 as FootnoteNode, O as KaTeXInlineNode, a1 as AlertQuoteNode, f as editorTheme, a2 as $isBannerNode, a3 as BannerRenderer, a4 as BannerNode, a5 as normalizeBannerType, a6 as $isCodeBlockNode, a7 as CodeBlockRenderer, a8 as CodeBlockNode, i as useFootnoteDefinitions, I as FootnoteSectionNode, v as $isGridContainerNode, K as GridContainerNode, b as builtinNodes, M as KaTeXBlockNode, L as ImageNode, a9 as VideoNode, Q as LinkCardNode, aa as DetailsNode, U as MermaidNode, F as FootnoteDefinitionsProvider, p as $createImageNode, W as computeImageMeta, V as OPEN_IMAGE_UPLOAD_DIALOG_COMMAND, ab as $createKaTeXInlineNode, ac as $createKaTeXBlockNode, ad as $createDetailsNode, ae as $createFootnoteNode, t as $isFootnoteSectionNode, $ as $createFootnoteSectionNode, r as $createMentionNode, g as extractTextContent, af as $createSpoilerNode, s as $createMermaidNode, C as ColorSchemeProvider, R as RendererConfigProvider } from "./theme-gVNBI_ET.js";
|
|
16
|
+
import { $getNodeByKey, KEY_ENTER_COMMAND, COMMAND_PRIORITY_CRITICAL, KEY_ARROW_DOWN_COMMAND, COMMAND_PRIORITY_HIGH, $getRoot, $createParagraphNode, $isParagraphNode, $getSelection, $isRangeSelection, $insertNodes, createEditor, $isElementNode, $isDecoratorNode, $createNodeSelection, $setSelection, $nodesOfType, createCommand, COMMAND_PRIORITY_EDITOR, $isRootNode, $isNodeSelection, KEY_BACKSPACE_COMMAND, KEY_DELETE_COMMAND, KEY_ARROW_UP_COMMAND, $isTextNode, createState, $getState, $addUpdateTag, $setState, $parseSerializedNode, PASTE_COMMAND, $createTextNode, $createLineBreakNode } from "lexical";
|
|
17
17
|
import { Info, Lightbulb, TriangleAlert, Flag, LayoutGrid, Plus, Minus, Check, Upload, Link2 } from "lucide-react";
|
|
18
|
-
import { useCallback, createElement, useState,
|
|
18
|
+
import { useCallback, useEffect, createElement, useState, createContext, use, useRef, useMemo } from "react";
|
|
19
19
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
20
20
|
import { ContentEditable as ContentEditable$1 } from "@lexical/react/LexicalContentEditable";
|
|
21
21
|
import { LexicalNestedComposer } from "@lexical/react/LexicalNestedComposer";
|
|
@@ -23,13 +23,110 @@ import { CodeNode } from "@lexical/code";
|
|
|
23
23
|
import { HorizontalRuleNode, INSERT_HORIZONTAL_RULE_COMMAND, $createHorizontalRuleNode } from "@lexical/extension";
|
|
24
24
|
import { LinkNode, AutoLinkNode, createLinkMatcherWithRegExp, registerAutoLink } from "@lexical/link";
|
|
25
25
|
import { ListNode, ListItemNode } from "@lexical/list";
|
|
26
|
-
import { HeadingNode, QuoteNode, DRAG_DROP_PASTE } from "@lexical/rich-text";
|
|
26
|
+
import { HeadingNode, QuoteNode, $isQuoteNode, DRAG_DROP_PASTE, $createQuoteNode } from "@lexical/rich-text";
|
|
27
27
|
import { TableNode, TableCellNode, TableRowNode } from "@lexical/table";
|
|
28
|
+
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
|
|
28
29
|
import { Dialog, DialogPopup, DialogTitle, SegmentedControl } from "@haklex/rich-editor-ui";
|
|
29
30
|
import { b as clsx, g as getVariantClass } from "./utils-fpeaZV1R.js";
|
|
30
31
|
import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
|
|
31
|
-
import { CHECK_LIST, TRANSFORMERS } from "@lexical/markdown";
|
|
32
|
+
import { CHECK_LIST, TRANSFORMERS, QUOTE, CODE } from "@lexical/markdown";
|
|
32
33
|
import { GIT_ALERT_TRANSFORMER as GIT_ALERT_TRANSFORMER$1, CONTAINER_TRANSFORMER as CONTAINER_TRANSFORMER$1, FOOTNOTE_TRANSFORMER as FOOTNOTE_TRANSFORMER$1, FOOTNOTE_SECTION_TRANSFORMER as FOOTNOTE_SECTION_TRANSFORMER$1, KATEX_INLINE_TRANSFORMER as KATEX_INLINE_TRANSFORMER$1, KATEX_BLOCK_TRANSFORMER as KATEX_BLOCK_TRANSFORMER$1, MENTION_TRANSFORMER as MENTION_TRANSFORMER$1, SPOILER_TRANSFORMER as SPOILER_TRANSFORMER$1, INSERT_TRANSFORMER, SUPERSCRIPT_TRANSFORMER, SUBSCRIPT_TRANSFORMER, IMAGE_BLOCK_TRANSFORMER, VIDEO_BLOCK_TRANSFORMER, CODE_BLOCK_NODE_TRANSFORMER, LINK_CARD_BLOCK_TRANSFORMER, MERMAID_BLOCK_TRANSFORMER, HORIZONTAL_RULE_BLOCK_TRANSFORMER, TABLE_BLOCK_TRANSFORMER } from "@haklex/rich-headless/transformers";
|
|
34
|
+
function ExitBlockPlugin({
|
|
35
|
+
parentEditor,
|
|
36
|
+
nodeKey
|
|
37
|
+
}) {
|
|
38
|
+
const [editor] = useLexicalComposerContext();
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const focusParent = () => {
|
|
41
|
+
parentEditor.focus(() => {
|
|
42
|
+
parentEditor.update(() => {
|
|
43
|
+
const alertNode = $getNodeByKey(nodeKey);
|
|
44
|
+
if (alertNode) {
|
|
45
|
+
const next = alertNode.getNextSibling();
|
|
46
|
+
if (next) {
|
|
47
|
+
next.selectStart();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const exitAlert = (removeEmpty) => {
|
|
54
|
+
const root = $getRoot();
|
|
55
|
+
const lastChild = root.getLastChild();
|
|
56
|
+
const shouldRemoveAlert = removeEmpty && root.getChildrenSize() <= 1;
|
|
57
|
+
if (removeEmpty && lastChild) {
|
|
58
|
+
lastChild.remove();
|
|
59
|
+
}
|
|
60
|
+
if (shouldRemoveAlert) {
|
|
61
|
+
parentEditor.update(
|
|
62
|
+
() => {
|
|
63
|
+
const alertNode = $getNodeByKey(nodeKey);
|
|
64
|
+
if (alertNode) {
|
|
65
|
+
const paragraph = $createParagraphNode();
|
|
66
|
+
alertNode.insertAfter(paragraph);
|
|
67
|
+
alertNode.remove();
|
|
68
|
+
paragraph.selectStart();
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{ onUpdate: focusParent }
|
|
72
|
+
);
|
|
73
|
+
} else {
|
|
74
|
+
parentEditor.update(
|
|
75
|
+
() => {
|
|
76
|
+
const alertNode = $getNodeByKey(nodeKey);
|
|
77
|
+
if (alertNode) {
|
|
78
|
+
let next = alertNode.getNextSibling();
|
|
79
|
+
if (!next || !$isParagraphNode(next)) {
|
|
80
|
+
next = $createParagraphNode();
|
|
81
|
+
alertNode.insertAfter(next);
|
|
82
|
+
}
|
|
83
|
+
next.selectStart();
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{ onUpdate: focusParent }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const isAtLastEmptyParagraph = () => {
|
|
91
|
+
const selection = $getSelection();
|
|
92
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed())
|
|
93
|
+
return false;
|
|
94
|
+
const anchorNode = selection.anchor.getNode();
|
|
95
|
+
const topLevelElement = anchorNode.getTopLevelElement();
|
|
96
|
+
return topLevelElement && $isParagraphNode(topLevelElement) && topLevelElement.getTextContent() === "" && topLevelElement.getNextSibling() === null;
|
|
97
|
+
};
|
|
98
|
+
const unregisterEnter = editor.registerCommand(
|
|
99
|
+
KEY_ENTER_COMMAND,
|
|
100
|
+
(event) => {
|
|
101
|
+
if (event?.metaKey || event?.ctrlKey) {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
exitAlert(false);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (!isAtLastEmptyParagraph()) return false;
|
|
107
|
+
event?.preventDefault();
|
|
108
|
+
exitAlert(true);
|
|
109
|
+
return true;
|
|
110
|
+
},
|
|
111
|
+
COMMAND_PRIORITY_CRITICAL
|
|
112
|
+
);
|
|
113
|
+
const unregisterArrowDown = editor.registerCommand(
|
|
114
|
+
KEY_ARROW_DOWN_COMMAND,
|
|
115
|
+
(event) => {
|
|
116
|
+
if (!isAtLastEmptyParagraph()) return false;
|
|
117
|
+
event?.preventDefault();
|
|
118
|
+
exitAlert(false);
|
|
119
|
+
return true;
|
|
120
|
+
},
|
|
121
|
+
COMMAND_PRIORITY_HIGH
|
|
122
|
+
);
|
|
123
|
+
return () => {
|
|
124
|
+
unregisterEnter();
|
|
125
|
+
unregisterArrowDown();
|
|
126
|
+
};
|
|
127
|
+
}, [editor, parentEditor, nodeKey]);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
33
130
|
function AlertEditDecorator({
|
|
34
131
|
nodeKey,
|
|
35
132
|
alertType,
|
|
@@ -78,7 +175,8 @@ function AlertEditDecorator({
|
|
|
78
175
|
}
|
|
79
176
|
),
|
|
80
177
|
/* @__PURE__ */ jsx(ListPlugin, {}),
|
|
81
|
-
/* @__PURE__ */ jsx(LinkPlugin, {})
|
|
178
|
+
/* @__PURE__ */ jsx(LinkPlugin, {}),
|
|
179
|
+
/* @__PURE__ */ jsx(ExitBlockPlugin, { parentEditor: editor, nodeKey })
|
|
82
180
|
] }) })
|
|
83
181
|
] });
|
|
84
182
|
}
|
|
@@ -337,13 +435,31 @@ let BannerEditNode = _BannerEditNode;
|
|
|
337
435
|
function $createBannerEditNode(bannerType, contentState) {
|
|
338
436
|
return new BannerEditNode(bannerType, contentState);
|
|
339
437
|
}
|
|
438
|
+
const codeBlockCursorIntentMap = /* @__PURE__ */ new Map();
|
|
439
|
+
function setCodeBlockCursorIntent(nodeKey, placement) {
|
|
440
|
+
codeBlockCursorIntentMap.set(nodeKey, placement);
|
|
441
|
+
}
|
|
442
|
+
function consumeCodeBlockCursorIntent(nodeKey) {
|
|
443
|
+
const placement = codeBlockCursorIntentMap.get(nodeKey);
|
|
444
|
+
if (!placement) return null;
|
|
445
|
+
codeBlockCursorIntentMap.delete(nodeKey);
|
|
446
|
+
return placement;
|
|
447
|
+
}
|
|
340
448
|
function CodeBlockEditDecorator({
|
|
341
449
|
nodeKey,
|
|
342
450
|
code,
|
|
343
451
|
language
|
|
344
452
|
}) {
|
|
345
453
|
const [editor] = useLexicalComposerContext();
|
|
454
|
+
const [isSelected] = useLexicalNodeSelection(nodeKey);
|
|
455
|
+
const [cursorPlacement, setCursorPlacement] = useState(
|
|
456
|
+
"start"
|
|
457
|
+
);
|
|
346
458
|
const editable = editor.isEditable();
|
|
459
|
+
useEffect(() => {
|
|
460
|
+
if (!editable || !isSelected) return;
|
|
461
|
+
setCursorPlacement(consumeCodeBlockCursorIntent(nodeKey) ?? "start");
|
|
462
|
+
}, [editable, isSelected, nodeKey]);
|
|
347
463
|
const handleCodeChange = useCallback(
|
|
348
464
|
(newCode) => {
|
|
349
465
|
editor.update(() => {
|
|
@@ -355,6 +471,100 @@ function CodeBlockEditDecorator({
|
|
|
355
471
|
},
|
|
356
472
|
[editor, nodeKey]
|
|
357
473
|
);
|
|
474
|
+
const handleLanguageChange = useCallback(
|
|
475
|
+
(newLanguage) => {
|
|
476
|
+
editor.update(() => {
|
|
477
|
+
const node = $getNodeByKey(nodeKey);
|
|
478
|
+
if ($isCodeBlockNode(node)) {
|
|
479
|
+
node.setLanguage(newLanguage);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
[editor, nodeKey]
|
|
484
|
+
);
|
|
485
|
+
const handleDelete = useCallback(() => {
|
|
486
|
+
editor.getRootElement()?.focus({ preventScroll: true });
|
|
487
|
+
editor.update(() => {
|
|
488
|
+
const node = $getNodeByKey(nodeKey);
|
|
489
|
+
if (!node) return;
|
|
490
|
+
const prev = node.getPreviousSibling();
|
|
491
|
+
const next = node.getNextSibling();
|
|
492
|
+
const parent = node.getParent();
|
|
493
|
+
node.remove();
|
|
494
|
+
if (prev) {
|
|
495
|
+
if ($isElementNode(prev)) {
|
|
496
|
+
prev.selectEnd();
|
|
497
|
+
} else {
|
|
498
|
+
if ($isDecoratorNode(prev) && prev.getType() === "code-block") {
|
|
499
|
+
setCodeBlockCursorIntent(prev.getKey(), "end");
|
|
500
|
+
}
|
|
501
|
+
const selection = $createNodeSelection();
|
|
502
|
+
selection.add(prev.getKey());
|
|
503
|
+
$setSelection(selection);
|
|
504
|
+
}
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
if (next) {
|
|
508
|
+
if ($isElementNode(next)) {
|
|
509
|
+
next.selectStart();
|
|
510
|
+
} else {
|
|
511
|
+
if ($isDecoratorNode(next) && next.getType() === "code-block") {
|
|
512
|
+
setCodeBlockCursorIntent(next.getKey(), "start");
|
|
513
|
+
}
|
|
514
|
+
const selection = $createNodeSelection();
|
|
515
|
+
selection.add(next.getKey());
|
|
516
|
+
$setSelection(selection);
|
|
517
|
+
}
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
if (parent) {
|
|
521
|
+
const p = $createParagraphNode();
|
|
522
|
+
parent.append(p);
|
|
523
|
+
p.selectStart();
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
}, [editor, nodeKey]);
|
|
527
|
+
const handleExitBlock = useCallback(
|
|
528
|
+
(direction) => {
|
|
529
|
+
editor.getRootElement()?.focus({ preventScroll: true });
|
|
530
|
+
editor.update(() => {
|
|
531
|
+
const node = $getNodeByKey(nodeKey);
|
|
532
|
+
if (!node) return;
|
|
533
|
+
if (direction === "before") {
|
|
534
|
+
const prev = node.getPreviousSibling();
|
|
535
|
+
if (!prev) return;
|
|
536
|
+
if ($isElementNode(prev)) {
|
|
537
|
+
prev.selectEnd();
|
|
538
|
+
} else {
|
|
539
|
+
if ($isDecoratorNode(prev) && prev.getType() === "code-block") {
|
|
540
|
+
setCodeBlockCursorIntent(prev.getKey(), "end");
|
|
541
|
+
}
|
|
542
|
+
const selection = $createNodeSelection();
|
|
543
|
+
selection.add(prev.getKey());
|
|
544
|
+
$setSelection(selection);
|
|
545
|
+
}
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
let next = node.getNextSibling();
|
|
549
|
+
if (!next) {
|
|
550
|
+
const p = $createParagraphNode();
|
|
551
|
+
node.insertAfter(p);
|
|
552
|
+
next = p;
|
|
553
|
+
}
|
|
554
|
+
if ($isElementNode(next)) {
|
|
555
|
+
next.selectStart();
|
|
556
|
+
} else {
|
|
557
|
+
if ($isDecoratorNode(next) && next.getType() === "code-block") {
|
|
558
|
+
setCodeBlockCursorIntent(next.getKey(), "start");
|
|
559
|
+
}
|
|
560
|
+
const selection = $createNodeSelection();
|
|
561
|
+
selection.add(next.getKey());
|
|
562
|
+
$setSelection(selection);
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
},
|
|
566
|
+
[editor, nodeKey]
|
|
567
|
+
);
|
|
358
568
|
return /* @__PURE__ */ jsx(
|
|
359
569
|
RendererWrapper,
|
|
360
570
|
{
|
|
@@ -364,17 +574,22 @@ function CodeBlockEditDecorator({
|
|
|
364
574
|
code,
|
|
365
575
|
language,
|
|
366
576
|
editable,
|
|
367
|
-
onCodeChange: editable ? handleCodeChange : void 0
|
|
577
|
+
onCodeChange: editable ? handleCodeChange : void 0,
|
|
578
|
+
onLanguageChange: editable ? handleLanguageChange : void 0,
|
|
579
|
+
onDelete: editable ? handleDelete : void 0,
|
|
580
|
+
onExitBlock: editable ? handleExitBlock : void 0,
|
|
581
|
+
selected: editable ? isSelected : false,
|
|
582
|
+
cursorPlacement: editable ? cursorPlacement : "start"
|
|
368
583
|
}
|
|
369
584
|
}
|
|
370
585
|
);
|
|
371
586
|
}
|
|
372
|
-
class
|
|
587
|
+
const _CodeBlockEditNode = class _CodeBlockEditNode extends CodeBlockNode {
|
|
373
588
|
static clone(node) {
|
|
374
|
-
return new
|
|
589
|
+
return new _CodeBlockEditNode(node.__code, node.__language, node.__key);
|
|
375
590
|
}
|
|
376
591
|
static importJSON(serializedNode) {
|
|
377
|
-
return new
|
|
592
|
+
return new _CodeBlockEditNode(serializedNode.code, serializedNode.language);
|
|
378
593
|
}
|
|
379
594
|
decorate(_editor, _config) {
|
|
380
595
|
return createElement(CodeBlockEditDecorator, {
|
|
@@ -383,7 +598,16 @@ class CodeBlockEditNode extends CodeBlockNode {
|
|
|
383
598
|
language: this.__language
|
|
384
599
|
});
|
|
385
600
|
}
|
|
386
|
-
}
|
|
601
|
+
};
|
|
602
|
+
__publicField(_CodeBlockEditNode, "slashMenuItems", CodeBlockNode.slashMenuItems.map((item) => ({
|
|
603
|
+
...item,
|
|
604
|
+
onSelect: (editor) => {
|
|
605
|
+
editor.update(() => {
|
|
606
|
+
$insertNodes([new _CodeBlockEditNode("", "text")]);
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
})));
|
|
610
|
+
let CodeBlockEditNode = _CodeBlockEditNode;
|
|
387
611
|
function FootnoteSectionEditRenderer({
|
|
388
612
|
definitions
|
|
389
613
|
}) {
|
|
@@ -871,6 +1095,280 @@ function AutoLinkPlugin({ matchers }) {
|
|
|
871
1095
|
}, [editor, matchers]);
|
|
872
1096
|
return null;
|
|
873
1097
|
}
|
|
1098
|
+
function selectDecoratorNode(node, cursorPlacement = "start") {
|
|
1099
|
+
if (node.getType() === "code-block") {
|
|
1100
|
+
setCodeBlockCursorIntent(node.getKey(), cursorPlacement);
|
|
1101
|
+
}
|
|
1102
|
+
const selection = $createNodeSelection();
|
|
1103
|
+
selection.add(node.getKey());
|
|
1104
|
+
$setSelection(selection);
|
|
1105
|
+
}
|
|
1106
|
+
function isAtTopLevelBoundary(selection, direction) {
|
|
1107
|
+
const point = selection.anchor;
|
|
1108
|
+
const topLevel = point.getNode().getTopLevelElementOrThrow();
|
|
1109
|
+
const pointNode = point.getNode();
|
|
1110
|
+
if (point.type === "text") {
|
|
1111
|
+
if (!$isTextNode(pointNode)) return false;
|
|
1112
|
+
const expectedOffset = direction === "start" ? 0 : pointNode.getTextContentSize();
|
|
1113
|
+
if (point.offset !== expectedOffset) return false;
|
|
1114
|
+
} else {
|
|
1115
|
+
if (!$isElementNode(pointNode)) return false;
|
|
1116
|
+
const expectedOffset = direction === "start" ? 0 : pointNode.getChildrenSize();
|
|
1117
|
+
if (point.offset !== expectedOffset) return false;
|
|
1118
|
+
}
|
|
1119
|
+
let current = pointNode;
|
|
1120
|
+
while (current && current !== topLevel) {
|
|
1121
|
+
const sibling = direction === "start" ? current.getPreviousSibling() : current.getNextSibling();
|
|
1122
|
+
if (sibling !== null) return false;
|
|
1123
|
+
current = current.getParent();
|
|
1124
|
+
}
|
|
1125
|
+
return current === topLevel;
|
|
1126
|
+
}
|
|
1127
|
+
function isSingleLineParagraph(node) {
|
|
1128
|
+
return $isParagraphNode(node) && !node.getTextContent().includes("\n");
|
|
1129
|
+
}
|
|
1130
|
+
function BlockExitPlugin() {
|
|
1131
|
+
const [editor] = useLexicalComposerContext();
|
|
1132
|
+
useEffect(() => {
|
|
1133
|
+
const unregisterArrowDown = editor.registerCommand(
|
|
1134
|
+
KEY_ARROW_DOWN_COMMAND,
|
|
1135
|
+
(event) => {
|
|
1136
|
+
const selection = $getSelection();
|
|
1137
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
const anchorNode = selection.anchor.getNode();
|
|
1141
|
+
const topLevelElement = anchorNode.getTopLevelElementOrThrow();
|
|
1142
|
+
const shouldSelectNextDecorator = isAtTopLevelBoundary(selection, "end") || isSingleLineParagraph(topLevelElement);
|
|
1143
|
+
if (!$isQuoteNode(topLevelElement) && shouldSelectNextDecorator) {
|
|
1144
|
+
const next2 = topLevelElement.getNextSibling();
|
|
1145
|
+
if (next2 && $isDecoratorNode(next2) && next2.isKeyboardSelectable()) {
|
|
1146
|
+
event?.preventDefault();
|
|
1147
|
+
selectDecoratorNode(next2, "start");
|
|
1148
|
+
return true;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
const element = $isElementNode(anchorNode) ? anchorNode : anchorNode.getParentOrThrow();
|
|
1152
|
+
let quoteChild = element;
|
|
1153
|
+
let quoteNode = null;
|
|
1154
|
+
let current = element;
|
|
1155
|
+
while (current) {
|
|
1156
|
+
const parent = current.getParent();
|
|
1157
|
+
if (!parent || $isRootNode(parent)) break;
|
|
1158
|
+
if ($isQuoteNode(parent)) {
|
|
1159
|
+
quoteNode = parent;
|
|
1160
|
+
quoteChild = current;
|
|
1161
|
+
break;
|
|
1162
|
+
}
|
|
1163
|
+
current = parent;
|
|
1164
|
+
}
|
|
1165
|
+
if (!quoteNode) return false;
|
|
1166
|
+
if (quoteChild.getNextSibling() !== null) return false;
|
|
1167
|
+
if (!$isParagraphNode(quoteChild) || quoteChild.getTextContent() !== "")
|
|
1168
|
+
return false;
|
|
1169
|
+
event?.preventDefault();
|
|
1170
|
+
let next = quoteNode.getNextSibling();
|
|
1171
|
+
if (!next) {
|
|
1172
|
+
next = $createParagraphNode();
|
|
1173
|
+
quoteNode.insertAfter(next);
|
|
1174
|
+
}
|
|
1175
|
+
next.selectStart();
|
|
1176
|
+
return true;
|
|
1177
|
+
},
|
|
1178
|
+
COMMAND_PRIORITY_CRITICAL
|
|
1179
|
+
);
|
|
1180
|
+
const unregisterCmdEnter = editor.registerCommand(
|
|
1181
|
+
KEY_ENTER_COMMAND,
|
|
1182
|
+
(event) => {
|
|
1183
|
+
if (!event?.metaKey && !event?.ctrlKey) return false;
|
|
1184
|
+
const selection = $getSelection();
|
|
1185
|
+
if ($isNodeSelection(selection)) {
|
|
1186
|
+
const nodes = selection.getNodes();
|
|
1187
|
+
if (nodes.length !== 1) return false;
|
|
1188
|
+
const node = nodes[0];
|
|
1189
|
+
if (!$isDecoratorNode(node)) return false;
|
|
1190
|
+
event.preventDefault();
|
|
1191
|
+
let next2 = node.getNextSibling();
|
|
1192
|
+
if (!next2) {
|
|
1193
|
+
next2 = $createParagraphNode();
|
|
1194
|
+
node.insertAfter(next2);
|
|
1195
|
+
}
|
|
1196
|
+
if ($isElementNode(next2)) {
|
|
1197
|
+
next2.selectStart();
|
|
1198
|
+
} else if ($isDecoratorNode(next2)) {
|
|
1199
|
+
selectDecoratorNode(next2, "start");
|
|
1200
|
+
}
|
|
1201
|
+
return true;
|
|
1202
|
+
}
|
|
1203
|
+
if (!$isRangeSelection(selection)) return false;
|
|
1204
|
+
const anchorNode = selection.anchor.getNode();
|
|
1205
|
+
const topLevelElement = anchorNode.getTopLevelElementOrThrow();
|
|
1206
|
+
if ($isParagraphNode(topLevelElement)) return false;
|
|
1207
|
+
event.preventDefault();
|
|
1208
|
+
let next = topLevelElement.getNextSibling();
|
|
1209
|
+
if (!next || !$isParagraphNode(next)) {
|
|
1210
|
+
next = $createParagraphNode();
|
|
1211
|
+
topLevelElement.insertAfter(next);
|
|
1212
|
+
}
|
|
1213
|
+
next.selectStart();
|
|
1214
|
+
return true;
|
|
1215
|
+
},
|
|
1216
|
+
COMMAND_PRIORITY_CRITICAL
|
|
1217
|
+
);
|
|
1218
|
+
function handleDeleteDecorator(event) {
|
|
1219
|
+
const selection = $getSelection();
|
|
1220
|
+
if (!$isNodeSelection(selection)) return false;
|
|
1221
|
+
const nodes = selection.getNodes();
|
|
1222
|
+
if (nodes.length !== 1) return false;
|
|
1223
|
+
const node = nodes[0];
|
|
1224
|
+
if (!$isDecoratorNode(node)) return false;
|
|
1225
|
+
event?.preventDefault();
|
|
1226
|
+
const prev = node.getPreviousSibling();
|
|
1227
|
+
const next = node.getNextSibling();
|
|
1228
|
+
node.remove();
|
|
1229
|
+
if (prev && $isElementNode(prev)) {
|
|
1230
|
+
prev.selectEnd();
|
|
1231
|
+
} else if (prev && $isDecoratorNode(prev)) {
|
|
1232
|
+
selectDecoratorNode(prev, "end");
|
|
1233
|
+
} else if (next && $isElementNode(next)) {
|
|
1234
|
+
next.selectStart();
|
|
1235
|
+
} else if (next && $isDecoratorNode(next)) {
|
|
1236
|
+
selectDecoratorNode(next, "start");
|
|
1237
|
+
} else {
|
|
1238
|
+
const root = $getRoot();
|
|
1239
|
+
if (root && $isElementNode(root)) {
|
|
1240
|
+
const p = $createParagraphNode();
|
|
1241
|
+
root.append(p);
|
|
1242
|
+
p.selectStart();
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
return true;
|
|
1246
|
+
}
|
|
1247
|
+
const unregisterBackspace = editor.registerCommand(
|
|
1248
|
+
KEY_BACKSPACE_COMMAND,
|
|
1249
|
+
handleDeleteDecorator,
|
|
1250
|
+
COMMAND_PRIORITY_HIGH
|
|
1251
|
+
);
|
|
1252
|
+
const unregisterDelete = editor.registerCommand(
|
|
1253
|
+
KEY_DELETE_COMMAND,
|
|
1254
|
+
handleDeleteDecorator,
|
|
1255
|
+
COMMAND_PRIORITY_HIGH
|
|
1256
|
+
);
|
|
1257
|
+
const unregisterArrowUpDecorator = editor.registerCommand(
|
|
1258
|
+
KEY_ARROW_UP_COMMAND,
|
|
1259
|
+
(event) => {
|
|
1260
|
+
const selection = $getSelection();
|
|
1261
|
+
if ($isRangeSelection(selection) && selection.isCollapsed()) {
|
|
1262
|
+
const anchorNode = selection.anchor.getNode();
|
|
1263
|
+
const topLevelElement = anchorNode.getTopLevelElementOrThrow();
|
|
1264
|
+
const shouldSelectPreviousDecorator = isAtTopLevelBoundary(selection, "start") || isSingleLineParagraph(topLevelElement);
|
|
1265
|
+
if (!$isQuoteNode(topLevelElement) && shouldSelectPreviousDecorator) {
|
|
1266
|
+
const prev2 = topLevelElement.getPreviousSibling();
|
|
1267
|
+
if (prev2 && $isDecoratorNode(prev2) && prev2.isKeyboardSelectable()) {
|
|
1268
|
+
event?.preventDefault();
|
|
1269
|
+
selectDecoratorNode(prev2, "end");
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (!$isNodeSelection(selection)) return false;
|
|
1275
|
+
const nodes = selection.getNodes();
|
|
1276
|
+
if (nodes.length !== 1) return false;
|
|
1277
|
+
const node = nodes[0];
|
|
1278
|
+
if (!$isDecoratorNode(node)) return false;
|
|
1279
|
+
const prev = node.getPreviousSibling();
|
|
1280
|
+
if (prev && $isElementNode(prev)) {
|
|
1281
|
+
event?.preventDefault();
|
|
1282
|
+
prev.selectEnd();
|
|
1283
|
+
return true;
|
|
1284
|
+
}
|
|
1285
|
+
if (prev && $isDecoratorNode(prev)) {
|
|
1286
|
+
event?.preventDefault();
|
|
1287
|
+
selectDecoratorNode(prev, "end");
|
|
1288
|
+
return true;
|
|
1289
|
+
}
|
|
1290
|
+
return false;
|
|
1291
|
+
},
|
|
1292
|
+
COMMAND_PRIORITY_CRITICAL
|
|
1293
|
+
);
|
|
1294
|
+
const unregisterArrowDownDecorator = editor.registerCommand(
|
|
1295
|
+
KEY_ARROW_DOWN_COMMAND,
|
|
1296
|
+
(event) => {
|
|
1297
|
+
const selection = $getSelection();
|
|
1298
|
+
if (!$isNodeSelection(selection)) return false;
|
|
1299
|
+
const nodes = selection.getNodes();
|
|
1300
|
+
if (nodes.length !== 1) return false;
|
|
1301
|
+
const node = nodes[0];
|
|
1302
|
+
if (!$isDecoratorNode(node)) return false;
|
|
1303
|
+
const next = node.getNextSibling();
|
|
1304
|
+
if (next && $isElementNode(next)) {
|
|
1305
|
+
event?.preventDefault();
|
|
1306
|
+
next.selectStart();
|
|
1307
|
+
return true;
|
|
1308
|
+
}
|
|
1309
|
+
if (next && $isDecoratorNode(next)) {
|
|
1310
|
+
event?.preventDefault();
|
|
1311
|
+
selectDecoratorNode(next, "start");
|
|
1312
|
+
return true;
|
|
1313
|
+
}
|
|
1314
|
+
return false;
|
|
1315
|
+
},
|
|
1316
|
+
COMMAND_PRIORITY_CRITICAL
|
|
1317
|
+
);
|
|
1318
|
+
return () => {
|
|
1319
|
+
unregisterArrowDown();
|
|
1320
|
+
unregisterCmdEnter();
|
|
1321
|
+
unregisterBackspace();
|
|
1322
|
+
unregisterDelete();
|
|
1323
|
+
unregisterArrowUpDecorator();
|
|
1324
|
+
unregisterArrowDownDecorator();
|
|
1325
|
+
};
|
|
1326
|
+
}, [editor]);
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
const blockIdState = createState("blockId", {
|
|
1330
|
+
parse: (v) => typeof v === "string" ? v : ""
|
|
1331
|
+
});
|
|
1332
|
+
const NORMALIZATION_TAG = "block-id-normalization";
|
|
1333
|
+
function BlockIdPlugin() {
|
|
1334
|
+
const [editor] = useLexicalComposerContext();
|
|
1335
|
+
useEffect(() => {
|
|
1336
|
+
return editor.registerUpdateListener(({ tags }) => {
|
|
1337
|
+
if (tags.has(NORMALIZATION_TAG)) return;
|
|
1338
|
+
editor.read(() => {
|
|
1339
|
+
const children = $getRoot().getChildren();
|
|
1340
|
+
let needsUpdate = false;
|
|
1341
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1342
|
+
for (const child of children) {
|
|
1343
|
+
const id = $getState(child, blockIdState);
|
|
1344
|
+
if (id === "" || seen.has(id)) {
|
|
1345
|
+
needsUpdate = true;
|
|
1346
|
+
break;
|
|
1347
|
+
}
|
|
1348
|
+
seen.add(id);
|
|
1349
|
+
}
|
|
1350
|
+
if (!needsUpdate) return;
|
|
1351
|
+
editor.update(
|
|
1352
|
+
() => {
|
|
1353
|
+
$addUpdateTag("history-merge");
|
|
1354
|
+
const children2 = $getRoot().getChildren();
|
|
1355
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
1356
|
+
for (const child of children2) {
|
|
1357
|
+
let id = $getState(child, blockIdState);
|
|
1358
|
+
if (id === "" || seen2.has(id)) {
|
|
1359
|
+
id = crypto.randomUUID();
|
|
1360
|
+
$setState(child, blockIdState, id);
|
|
1361
|
+
}
|
|
1362
|
+
seen2.add(id);
|
|
1363
|
+
}
|
|
1364
|
+
},
|
|
1365
|
+
{ tag: NORMALIZATION_TAG }
|
|
1366
|
+
);
|
|
1367
|
+
});
|
|
1368
|
+
});
|
|
1369
|
+
}, [editor]);
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
874
1372
|
function EditorRefPlugin({ onEditorReady }) {
|
|
875
1373
|
const [editor] = useLexicalComposerContext();
|
|
876
1374
|
const callbackRef = useRef(onEditorReady);
|
|
@@ -1561,6 +2059,34 @@ const GIT_ALERT_TRANSFORMER = {
|
|
|
1561
2059
|
parentNode.replace(alertNode);
|
|
1562
2060
|
}
|
|
1563
2061
|
};
|
|
2062
|
+
function findCodeBlockKlass(nodes) {
|
|
2063
|
+
return nodes.find((n) => n.getType?.() === "code-block") || CodeBlockNode;
|
|
2064
|
+
}
|
|
2065
|
+
const CODE_BLOCK_MULTILINE_TRANSFORMER = {
|
|
2066
|
+
dependencies: [],
|
|
2067
|
+
regExpEnd: {
|
|
2068
|
+
optional: true,
|
|
2069
|
+
regExp: /[ \t]*```$/
|
|
2070
|
+
},
|
|
2071
|
+
regExpStart: /^[ \t]*```([\w-]+)?/,
|
|
2072
|
+
replace: (rootNode, _children, startMatch, _endMatch, linesInBetween) => {
|
|
2073
|
+
const lang = startMatch[1] || "";
|
|
2074
|
+
let code = "";
|
|
2075
|
+
if (linesInBetween) {
|
|
2076
|
+
const lines = [...linesInBetween];
|
|
2077
|
+
while (lines.length > 0 && !lines[0].length) lines.shift();
|
|
2078
|
+
while (lines.length > 0 && !lines.at(-1).length) lines.pop();
|
|
2079
|
+
code = lines.join("\n");
|
|
2080
|
+
}
|
|
2081
|
+
const Klass = findCodeBlockKlass(getResolvedEditNodes());
|
|
2082
|
+
const node = new Klass(code, lang);
|
|
2083
|
+
rootNode.replace(node);
|
|
2084
|
+
const selection = $createNodeSelection();
|
|
2085
|
+
selection.add(node.getKey());
|
|
2086
|
+
$setSelection(selection);
|
|
2087
|
+
},
|
|
2088
|
+
type: "multiline-element"
|
|
2089
|
+
};
|
|
1564
2090
|
const BANNER_TYPE_MAP = {
|
|
1565
2091
|
note: "note",
|
|
1566
2092
|
info: "note",
|
|
@@ -1683,6 +2209,39 @@ const MENTION_TRANSFORMER = {
|
|
|
1683
2209
|
textNode.replace(mentionNode);
|
|
1684
2210
|
}
|
|
1685
2211
|
};
|
|
2212
|
+
const QUOTE_TRANSFORMER = {
|
|
2213
|
+
dependencies: [QuoteNode],
|
|
2214
|
+
export: (node, exportChildren) => {
|
|
2215
|
+
if (!$isQuoteNode(node)) {
|
|
2216
|
+
return null;
|
|
2217
|
+
}
|
|
2218
|
+
const lines = exportChildren(node).split("\n");
|
|
2219
|
+
return lines.map((line) => `> ${line}`).join("\n");
|
|
2220
|
+
},
|
|
2221
|
+
regExp: /^>\s/,
|
|
2222
|
+
replace: (parentNode, children, _match, isImport) => {
|
|
2223
|
+
if (isImport) {
|
|
2224
|
+
const previousNode = parentNode.getPreviousSibling();
|
|
2225
|
+
if ($isQuoteNode(previousNode)) {
|
|
2226
|
+
previousNode.splice(previousNode.getChildrenSize(), 0, [
|
|
2227
|
+
$createLineBreakNode(),
|
|
2228
|
+
...children
|
|
2229
|
+
]);
|
|
2230
|
+
parentNode.remove();
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
const node = $createQuoteNode();
|
|
2235
|
+
const paragraph = $createParagraphNode();
|
|
2236
|
+
paragraph.append(...children);
|
|
2237
|
+
node.append(paragraph);
|
|
2238
|
+
parentNode.replace(node);
|
|
2239
|
+
if (!isImport) {
|
|
2240
|
+
paragraph.select(0, 0);
|
|
2241
|
+
}
|
|
2242
|
+
},
|
|
2243
|
+
type: "element"
|
|
2244
|
+
};
|
|
1686
2245
|
function quoteAttr(value) {
|
|
1687
2246
|
return value.replaceAll('"', '\\"');
|
|
1688
2247
|
}
|
|
@@ -1730,12 +2289,14 @@ const ALL_TRANSFORMERS = [
|
|
|
1730
2289
|
IMAGE_BLOCK_TRANSFORMER,
|
|
1731
2290
|
VIDEO_BLOCK_TRANSFORMER,
|
|
1732
2291
|
CODE_BLOCK_NODE_TRANSFORMER,
|
|
2292
|
+
CODE_BLOCK_MULTILINE_TRANSFORMER,
|
|
1733
2293
|
LINK_CARD_BLOCK_TRANSFORMER,
|
|
1734
2294
|
MERMAID_BLOCK_TRANSFORMER,
|
|
1735
2295
|
GRID_CONTAINER_BLOCK_TRANSFORMER,
|
|
1736
2296
|
HORIZONTAL_RULE_BLOCK_TRANSFORMER,
|
|
1737
2297
|
TABLE_BLOCK_TRANSFORMER,
|
|
1738
|
-
|
|
2298
|
+
QUOTE_TRANSFORMER,
|
|
2299
|
+
...TRANSFORMERS.filter((t) => t !== QUOTE && t !== CODE)
|
|
1739
2300
|
];
|
|
1740
2301
|
function MarkdownShortcutsPlugin() {
|
|
1741
2302
|
return /* @__PURE__ */ jsx(MarkdownShortcutPlugin, { transformers: ALL_TRANSFORMERS });
|
|
@@ -1914,7 +2475,9 @@ function RichEditor({
|
|
|
1914
2475
|
/* @__PURE__ */ jsx(MermaidPlugin, {}),
|
|
1915
2476
|
/* @__PURE__ */ jsx(HorizontalRulePlugin, {}),
|
|
1916
2477
|
/* @__PURE__ */ jsx(CheckListPlugin, {}),
|
|
2478
|
+
/* @__PURE__ */ jsx(BlockExitPlugin, {}),
|
|
1917
2479
|
/* @__PURE__ */ jsx(AutoLinkPlugin, {}),
|
|
2480
|
+
/* @__PURE__ */ jsx(BlockIdPlugin, {}),
|
|
1918
2481
|
/* @__PURE__ */ jsx(EditorRefPlugin, { onEditorReady }),
|
|
1919
2482
|
autoFocus && /* @__PURE__ */ jsx(AutoFocusPlugin, {}),
|
|
1920
2483
|
children,
|
|
@@ -1932,14 +2495,15 @@ export {
|
|
|
1932
2495
|
NESTED_EDITOR_NODES as N,
|
|
1933
2496
|
RichEditor as R,
|
|
1934
2497
|
allEditNodes as a,
|
|
1935
|
-
|
|
2498
|
+
blockIdState as b,
|
|
1936
2499
|
customEditNodes as c,
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2500
|
+
FootnoteSectionEditNode as d,
|
|
2501
|
+
INSERT_IMAGE_COMMAND as e,
|
|
2502
|
+
INSERT_KATEX_BLOCK_COMMAND as f,
|
|
1940
2503
|
getResolvedEditNodes as g,
|
|
1941
|
-
|
|
1942
|
-
|
|
2504
|
+
INSERT_KATEX_INLINE_COMMAND as h,
|
|
2505
|
+
INSERT_MERMAID_COMMAND as i,
|
|
2506
|
+
defaultImageUpload as j,
|
|
1943
2507
|
setResolvedEditNodes as s,
|
|
1944
2508
|
useImageUpload as u
|
|
1945
2509
|
};
|