@haklex/rich-editor 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AlertQuoteEditNode-C55sxsR3.js +267 -0
- package/dist/KaTeXRenderer-CQQT3BMw.js +215 -0
- package/dist/LinkCardRenderer-CigqFwCv.js +45 -0
- package/dist/MermaidPlugin-BrOr-wQi.js +67 -0
- package/dist/PresentDialogContext-DKNicgia.js +74 -0
- package/dist/RubyRenderer-jOkydJHg.js +15 -0
- package/dist/SubmitShortcutPlugin-D-7XrQfm.js +2186 -0
- package/dist/commands-entry.mjs +54 -74
- package/dist/config-CNiK9v2M.js +1246 -0
- package/dist/grid.css-CJCkLTZc.js +44 -0
- package/dist/index.mjs +121 -180
- package/dist/katex.css-CIOEOXyd.js +145 -0
- package/dist/node-registry-DOYK_WIp.js +669 -0
- package/dist/nodes-entry.mjs +5 -50
- package/dist/normalizeSerializedEditorState-B-1wmGzd.js +78 -0
- package/dist/plugins-entry.mjs +3 -28
- package/dist/renderers-entry.mjs +41 -61
- package/dist/rich-editor.css +2 -1
- package/dist/static-entry.mjs +16 -66
- package/dist/styles-entry.mjs +3 -21
- package/dist/theme-B5B2EOWM.js +1099 -0
- package/package.json +30 -30
- package/dist/AlertQuoteEditNode-sPNf3_7P.js +0 -293
- package/dist/KaTeXRenderer-CQyQzNTJ.js +0 -218
- package/dist/LinkCardRenderer-QmkOlyXb.js +0 -36
- package/dist/MermaidPlugin-DKuGUcCG.js +0 -101
- package/dist/PresentDialogContext-DRroMIoK.js +0 -71
- package/dist/RubyRenderer-CJQmODir.js +0 -14
- package/dist/SubmitShortcutPlugin-D9uKYHda.js +0 -2427
- package/dist/config-Dl3ZkytB.js +0 -1362
- package/dist/grid.css-Md5-Cfx_.js +0 -11
- package/dist/katex.css-Csc-7N7u.js +0 -28
- package/dist/node-registry-CovhHUB6.js +0 -824
- package/dist/normalizeSerializedEditorState-k5G4xSi9.js +0 -85
- package/dist/theme-lEwScxEX.js +0 -1113
|
@@ -1,824 +0,0 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { o as $isBannerNode, p as BannerRenderer, q as BannerNode, r as normalizeBannerType, s as $isCodeBlockNode, t as CodeBlockRenderer, v as CodeBlockNode, F as FootnoteSectionNode, g as $isGridContainerNode, G as GridContainerNode, l as builtinNodes, V as VideoNode, L as LinkCardNode, C as CommentNode, D as DetailsNode, R as RubyNode } from "./config-Dl3ZkytB.js";
|
|
5
|
-
import { N as NESTED_EDITOR_NODES, A as AlertQuoteEditNode } from "./AlertQuoteEditNode-sPNf3_7P.js";
|
|
6
|
-
import { $getNodeByKey, $insertNodes, createEditor, $getSelection, $isNodeSelection, $isElementNode, $isDecoratorNode, $createNodeSelection, $setSelection, $createParagraphNode, $nodesOfType, $getRoot } from "lexical";
|
|
7
|
-
import { Flag, LayoutGrid, Plus, Minus } from "lucide-react";
|
|
8
|
-
import { useCallback, createElement, useState, useEffect } from "react";
|
|
9
|
-
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
10
|
-
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
11
|
-
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
12
|
-
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
13
|
-
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
14
|
-
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
15
|
-
import { LexicalNestedComposer } from "@lexical/react/LexicalNestedComposer";
|
|
16
|
-
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
17
|
-
import { a as RendererWrapper, b as useFootnoteDefinitions } from "./KaTeXRenderer-CQyQzNTJ.js";
|
|
18
|
-
import { n as editorTheme, S as SpoilerNode, M as MentionNode, k as KaTeXInlineNode, K as KaTeXBlockNode, I as ImageNode, F as FootnoteNode, l as MermaidNode, T as TagNode } from "./theme-lEwScxEX.js";
|
|
19
|
-
import { useLexicalNodeSelection } from "@lexical/react/useLexicalNodeSelection";
|
|
20
|
-
import { e as clsx, d as sharedStyles, s as semanticClassNames } from "./katex.css-Csc-7N7u.js";
|
|
21
|
-
import { b as gridStyles, g as gridClassNames } from "./grid.css-Md5-Cfx_.js";
|
|
22
|
-
const codeBlockCursorIntentMap = /* @__PURE__ */ new Map();
|
|
23
|
-
function setCodeBlockCursorIntent(nodeKey, placement) {
|
|
24
|
-
codeBlockCursorIntentMap.set(nodeKey, placement);
|
|
25
|
-
}
|
|
26
|
-
function consumeCodeBlockCursorIntent(nodeKey) {
|
|
27
|
-
const placement = codeBlockCursorIntentMap.get(nodeKey);
|
|
28
|
-
if (!placement) return null;
|
|
29
|
-
codeBlockCursorIntentMap.delete(nodeKey);
|
|
30
|
-
return placement;
|
|
31
|
-
}
|
|
32
|
-
function BannerEditDecorator({
|
|
33
|
-
nodeKey,
|
|
34
|
-
bannerType,
|
|
35
|
-
contentEditor
|
|
36
|
-
}) {
|
|
37
|
-
const [editor] = useLexicalComposerContext();
|
|
38
|
-
const editable = editor.isEditable();
|
|
39
|
-
const handleTypeChange = useCallback(
|
|
40
|
-
(newType) => {
|
|
41
|
-
editor.update(() => {
|
|
42
|
-
const node = $getNodeByKey(nodeKey);
|
|
43
|
-
if ($isBannerNode(node)) {
|
|
44
|
-
node.setBannerType(newType);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
},
|
|
48
|
-
[editor, nodeKey]
|
|
49
|
-
);
|
|
50
|
-
return /* @__PURE__ */ jsxs("div", { className: "rich-banner-inner", children: [
|
|
51
|
-
/* @__PURE__ */ jsx(
|
|
52
|
-
RendererWrapper,
|
|
53
|
-
{
|
|
54
|
-
defaultRenderer: BannerRenderer,
|
|
55
|
-
rendererKey: "Banner",
|
|
56
|
-
props: {
|
|
57
|
-
type: bannerType,
|
|
58
|
-
editable,
|
|
59
|
-
onTypeChange: editable ? handleTypeChange : void 0
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
),
|
|
63
|
-
/* @__PURE__ */ jsx("div", { className: "rich-banner-content", children: /* @__PURE__ */ jsxs(LexicalNestedComposer, { initialEditor: contentEditor, children: [
|
|
64
|
-
/* @__PURE__ */ jsx(
|
|
65
|
-
RichTextPlugin,
|
|
66
|
-
{
|
|
67
|
-
ErrorBoundary: LexicalErrorBoundary,
|
|
68
|
-
contentEditable: /* @__PURE__ */ jsx(
|
|
69
|
-
ContentEditable,
|
|
70
|
-
{
|
|
71
|
-
"aria-placeholder": "",
|
|
72
|
-
className: "rich-banner-content-editable",
|
|
73
|
-
placeholder: /* @__PURE__ */ jsx("span", { style: { display: "none" } }),
|
|
74
|
-
style: { outline: "none" }
|
|
75
|
-
}
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
),
|
|
79
|
-
/* @__PURE__ */ jsx(ListPlugin, {}),
|
|
80
|
-
/* @__PURE__ */ jsx(LinkPlugin, {})
|
|
81
|
-
] }) })
|
|
82
|
-
] });
|
|
83
|
-
}
|
|
84
|
-
function createContentEditor() {
|
|
85
|
-
return createEditor({
|
|
86
|
-
namespace: "BannerContent",
|
|
87
|
-
nodes: NESTED_EDITOR_NODES,
|
|
88
|
-
theme: editorTheme,
|
|
89
|
-
onError: (error) => {
|
|
90
|
-
console.error("[BannerContent]", error);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
const _BannerEditNode = class _BannerEditNode extends BannerNode {
|
|
95
|
-
constructor(bannerType, contentState, key) {
|
|
96
|
-
super(bannerType, contentState, key);
|
|
97
|
-
__publicField(this, "__contentEditor");
|
|
98
|
-
this.__contentEditor = createContentEditor();
|
|
99
|
-
if (contentState) {
|
|
100
|
-
const editorState = this.__contentEditor.parseEditorState(contentState);
|
|
101
|
-
this.__contentEditor.setEditorState(editorState);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
static clone(node) {
|
|
105
|
-
const cloned = new _BannerEditNode(
|
|
106
|
-
node.__bannerType,
|
|
107
|
-
node.__contentState,
|
|
108
|
-
node.__key
|
|
109
|
-
);
|
|
110
|
-
cloned.__contentEditor = node.__contentEditor;
|
|
111
|
-
return cloned;
|
|
112
|
-
}
|
|
113
|
-
getContentEditor() {
|
|
114
|
-
return this.__contentEditor;
|
|
115
|
-
}
|
|
116
|
-
static importJSON(serializedNode) {
|
|
117
|
-
const legacy = serializedNode;
|
|
118
|
-
const bannerType = normalizeBannerType(serializedNode.bannerType);
|
|
119
|
-
if (serializedNode.content) {
|
|
120
|
-
return new _BannerEditNode(bannerType, serializedNode.content);
|
|
121
|
-
}
|
|
122
|
-
if (legacy.children) {
|
|
123
|
-
const content = {
|
|
124
|
-
root: {
|
|
125
|
-
children: legacy.children,
|
|
126
|
-
direction: null,
|
|
127
|
-
format: "",
|
|
128
|
-
indent: 0,
|
|
129
|
-
type: "root",
|
|
130
|
-
version: 1
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
return new _BannerEditNode(bannerType, content);
|
|
134
|
-
}
|
|
135
|
-
return new _BannerEditNode(bannerType);
|
|
136
|
-
}
|
|
137
|
-
exportJSON() {
|
|
138
|
-
return {
|
|
139
|
-
...super.exportJSON(),
|
|
140
|
-
type: "banner",
|
|
141
|
-
bannerType: this.__bannerType,
|
|
142
|
-
content: this.__contentEditor.getEditorState().toJSON(),
|
|
143
|
-
version: 1
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
decorate(_editor, _config) {
|
|
147
|
-
return createElement(BannerEditDecorator, {
|
|
148
|
-
nodeKey: this.__key,
|
|
149
|
-
bannerType: this.__bannerType,
|
|
150
|
-
contentEditor: this.__contentEditor
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
__publicField(_BannerEditNode, "commandItems", [
|
|
155
|
-
{
|
|
156
|
-
title: "Banner",
|
|
157
|
-
icon: createElement(Flag, { size: 20 }),
|
|
158
|
-
description: "Highlighted banner block",
|
|
159
|
-
keywords: ["banner", "notice", "announcement"],
|
|
160
|
-
section: "ADVANCED",
|
|
161
|
-
placement: ["slash", "toolbar"],
|
|
162
|
-
group: "insert",
|
|
163
|
-
onSelect: (editor) => {
|
|
164
|
-
editor.update(() => {
|
|
165
|
-
$insertNodes([$createBannerEditNode("note")]);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
]);
|
|
170
|
-
let BannerEditNode = _BannerEditNode;
|
|
171
|
-
function $createBannerEditNode(bannerType, contentState) {
|
|
172
|
-
return new BannerEditNode(bannerType, contentState);
|
|
173
|
-
}
|
|
174
|
-
function CodeBlockEditDecorator({ nodeKey, code, language }) {
|
|
175
|
-
const [editor] = useLexicalComposerContext();
|
|
176
|
-
const [isSelected] = useLexicalNodeSelection(nodeKey);
|
|
177
|
-
const [shouldFocusEditor, setShouldFocusEditor] = useState(false);
|
|
178
|
-
const [cursorPlacement, setCursorPlacement] = useState("start");
|
|
179
|
-
const editable = editor.isEditable();
|
|
180
|
-
useEffect(() => {
|
|
181
|
-
if (!editable || !isSelected) {
|
|
182
|
-
setShouldFocusEditor(false);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
let nextShouldFocus = false;
|
|
186
|
-
let nextCursorPlacement = "start";
|
|
187
|
-
editor.getEditorState().read(() => {
|
|
188
|
-
const selection = $getSelection();
|
|
189
|
-
const selectedNodes = $isNodeSelection(selection) ? selection.getNodes() : null;
|
|
190
|
-
nextShouldFocus = selectedNodes !== null && selectedNodes.length === 1 && selectedNodes[0]?.getKey() === nodeKey;
|
|
191
|
-
if (nextShouldFocus) {
|
|
192
|
-
nextCursorPlacement = consumeCodeBlockCursorIntent(nodeKey) ?? "start";
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
setShouldFocusEditor(nextShouldFocus);
|
|
196
|
-
if (nextShouldFocus) {
|
|
197
|
-
setCursorPlacement(nextCursorPlacement);
|
|
198
|
-
}
|
|
199
|
-
}, [editable, editor, isSelected, nodeKey]);
|
|
200
|
-
const handleCodeChange = useCallback(
|
|
201
|
-
(newCode) => {
|
|
202
|
-
editor.update(() => {
|
|
203
|
-
const node = $getNodeByKey(nodeKey);
|
|
204
|
-
if ($isCodeBlockNode(node)) {
|
|
205
|
-
node.setCode(newCode);
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
},
|
|
209
|
-
[editor, nodeKey]
|
|
210
|
-
);
|
|
211
|
-
const handleLanguageChange = useCallback(
|
|
212
|
-
(newLanguage) => {
|
|
213
|
-
editor.update(() => {
|
|
214
|
-
const node = $getNodeByKey(nodeKey);
|
|
215
|
-
if ($isCodeBlockNode(node)) {
|
|
216
|
-
node.setLanguage(newLanguage);
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
},
|
|
220
|
-
[editor, nodeKey]
|
|
221
|
-
);
|
|
222
|
-
const handleDelete = useCallback(() => {
|
|
223
|
-
editor.getRootElement()?.focus({ preventScroll: true });
|
|
224
|
-
editor.update(() => {
|
|
225
|
-
const node = $getNodeByKey(nodeKey);
|
|
226
|
-
if (!node) return;
|
|
227
|
-
const prev = node.getPreviousSibling();
|
|
228
|
-
const next = node.getNextSibling();
|
|
229
|
-
const parent = node.getParent();
|
|
230
|
-
node.remove();
|
|
231
|
-
if (prev) {
|
|
232
|
-
if ($isElementNode(prev)) {
|
|
233
|
-
prev.selectEnd();
|
|
234
|
-
} else {
|
|
235
|
-
if ($isDecoratorNode(prev) && prev.getType() === "code-block") {
|
|
236
|
-
setCodeBlockCursorIntent(prev.getKey(), "end");
|
|
237
|
-
}
|
|
238
|
-
const selection = $createNodeSelection();
|
|
239
|
-
selection.add(prev.getKey());
|
|
240
|
-
$setSelection(selection);
|
|
241
|
-
}
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (next) {
|
|
245
|
-
if ($isElementNode(next)) {
|
|
246
|
-
next.selectStart();
|
|
247
|
-
} else {
|
|
248
|
-
if ($isDecoratorNode(next) && next.getType() === "code-block") {
|
|
249
|
-
setCodeBlockCursorIntent(next.getKey(), "start");
|
|
250
|
-
}
|
|
251
|
-
const selection = $createNodeSelection();
|
|
252
|
-
selection.add(next.getKey());
|
|
253
|
-
$setSelection(selection);
|
|
254
|
-
}
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
if (parent) {
|
|
258
|
-
const p = $createParagraphNode();
|
|
259
|
-
parent.append(p);
|
|
260
|
-
p.selectStart();
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
}, [editor, nodeKey]);
|
|
264
|
-
const handleExitBlock = useCallback(
|
|
265
|
-
(direction) => {
|
|
266
|
-
editor.getRootElement()?.focus({ preventScroll: true });
|
|
267
|
-
editor.update(() => {
|
|
268
|
-
const node = $getNodeByKey(nodeKey);
|
|
269
|
-
if (!node) return;
|
|
270
|
-
if (direction === "before") {
|
|
271
|
-
const prev = node.getPreviousSibling();
|
|
272
|
-
if (!prev) return;
|
|
273
|
-
if ($isElementNode(prev)) {
|
|
274
|
-
prev.selectEnd();
|
|
275
|
-
} else {
|
|
276
|
-
if ($isDecoratorNode(prev) && prev.getType() === "code-block") {
|
|
277
|
-
setCodeBlockCursorIntent(prev.getKey(), "end");
|
|
278
|
-
}
|
|
279
|
-
const selection = $createNodeSelection();
|
|
280
|
-
selection.add(prev.getKey());
|
|
281
|
-
$setSelection(selection);
|
|
282
|
-
}
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
let next = node.getNextSibling();
|
|
286
|
-
if (!next) {
|
|
287
|
-
const p = $createParagraphNode();
|
|
288
|
-
node.insertAfter(p);
|
|
289
|
-
next = p;
|
|
290
|
-
}
|
|
291
|
-
if ($isElementNode(next)) {
|
|
292
|
-
next.selectStart();
|
|
293
|
-
} else {
|
|
294
|
-
if ($isDecoratorNode(next) && next.getType() === "code-block") {
|
|
295
|
-
setCodeBlockCursorIntent(next.getKey(), "start");
|
|
296
|
-
}
|
|
297
|
-
const selection = $createNodeSelection();
|
|
298
|
-
selection.add(next.getKey());
|
|
299
|
-
$setSelection(selection);
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
},
|
|
303
|
-
[editor, nodeKey]
|
|
304
|
-
);
|
|
305
|
-
return /* @__PURE__ */ jsx(
|
|
306
|
-
RendererWrapper,
|
|
307
|
-
{
|
|
308
|
-
defaultRenderer: CodeBlockRenderer,
|
|
309
|
-
rendererKey: "CodeBlock",
|
|
310
|
-
props: {
|
|
311
|
-
code,
|
|
312
|
-
language,
|
|
313
|
-
editable,
|
|
314
|
-
onCodeChange: editable ? handleCodeChange : void 0,
|
|
315
|
-
onLanguageChange: editable ? handleLanguageChange : void 0,
|
|
316
|
-
onDelete: editable ? handleDelete : void 0,
|
|
317
|
-
onExitBlock: editable ? handleExitBlock : void 0,
|
|
318
|
-
selected: editable ? shouldFocusEditor : false,
|
|
319
|
-
cursorPlacement: editable ? cursorPlacement : "start"
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
const _CodeBlockEditNode = class _CodeBlockEditNode extends CodeBlockNode {
|
|
325
|
-
static clone(node) {
|
|
326
|
-
return new _CodeBlockEditNode(node.__code, node.__language, node.__key);
|
|
327
|
-
}
|
|
328
|
-
static importJSON(serializedNode) {
|
|
329
|
-
return new _CodeBlockEditNode(serializedNode.code, serializedNode.language);
|
|
330
|
-
}
|
|
331
|
-
decorate(_editor, _config) {
|
|
332
|
-
return createElement(CodeBlockEditDecorator, {
|
|
333
|
-
nodeKey: this.__key,
|
|
334
|
-
code: this.__code,
|
|
335
|
-
language: this.__language
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
__publicField(_CodeBlockEditNode, "commandItems", CodeBlockNode.commandItems.map((item) => ({
|
|
340
|
-
...item,
|
|
341
|
-
onSelect: (editor) => {
|
|
342
|
-
editor.update(() => {
|
|
343
|
-
$insertNodes([new _CodeBlockEditNode("", "text")]);
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
})));
|
|
347
|
-
let CodeBlockEditNode = _CodeBlockEditNode;
|
|
348
|
-
function $createCodeBlockEditNode(code, language) {
|
|
349
|
-
return new CodeBlockEditNode(code, language);
|
|
350
|
-
}
|
|
351
|
-
function FootnoteSectionEditRenderer({ definitions }) {
|
|
352
|
-
const [editor] = useLexicalComposerContext();
|
|
353
|
-
const { displayNumberMap } = useFootnoteDefinitions();
|
|
354
|
-
const sortedEntries = Object.entries(definitions).sort(
|
|
355
|
-
([a], [b]) => (displayNumberMap[a] ?? 0) - (displayNumberMap[b] ?? 0)
|
|
356
|
-
);
|
|
357
|
-
const handleContentChange = useCallback(
|
|
358
|
-
(identifier, newContent) => {
|
|
359
|
-
editor.update(() => {
|
|
360
|
-
const sectionNodes = $nodesOfType(FootnoteSectionNode);
|
|
361
|
-
if (sectionNodes.length > 0) {
|
|
362
|
-
sectionNodes[0].setDefinition(identifier, newContent);
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
},
|
|
366
|
-
[editor]
|
|
367
|
-
);
|
|
368
|
-
const handleRemove = useCallback(
|
|
369
|
-
(identifier) => {
|
|
370
|
-
editor.update(() => {
|
|
371
|
-
const sectionNodes = $nodesOfType(FootnoteSectionNode);
|
|
372
|
-
if (sectionNodes.length > 0) {
|
|
373
|
-
sectionNodes[0].removeDefinition(identifier);
|
|
374
|
-
}
|
|
375
|
-
});
|
|
376
|
-
},
|
|
377
|
-
[editor]
|
|
378
|
-
);
|
|
379
|
-
if (sortedEntries.length === 0) return null;
|
|
380
|
-
return /* @__PURE__ */ jsxs(
|
|
381
|
-
"div",
|
|
382
|
-
{
|
|
383
|
-
role: "doc-endnotes",
|
|
384
|
-
className: clsx(
|
|
385
|
-
"rich-footnote-section-content",
|
|
386
|
-
"rich-footnote-section-edit",
|
|
387
|
-
semanticClassNames.footnoteSection,
|
|
388
|
-
sharedStyles.footnoteSection
|
|
389
|
-
),
|
|
390
|
-
children: [
|
|
391
|
-
/* @__PURE__ */ jsx(
|
|
392
|
-
"hr",
|
|
393
|
-
{
|
|
394
|
-
className: clsx(
|
|
395
|
-
semanticClassNames.footnoteSectionDivider,
|
|
396
|
-
sharedStyles.footnoteSectionDivider
|
|
397
|
-
)
|
|
398
|
-
}
|
|
399
|
-
),
|
|
400
|
-
/* @__PURE__ */ jsx(
|
|
401
|
-
"ol",
|
|
402
|
-
{
|
|
403
|
-
className: clsx(semanticClassNames.footnoteSectionList, sharedStyles.footnoteSectionList),
|
|
404
|
-
children: sortedEntries.map(([identifier, content]) => {
|
|
405
|
-
const displayNum = displayNumberMap[identifier] ?? identifier;
|
|
406
|
-
return /* @__PURE__ */ jsxs(
|
|
407
|
-
"li",
|
|
408
|
-
{
|
|
409
|
-
id: `footnote-${identifier}`,
|
|
410
|
-
className: clsx(
|
|
411
|
-
semanticClassNames.footnoteSectionItem,
|
|
412
|
-
sharedStyles.footnoteSectionItem,
|
|
413
|
-
semanticClassNames.footnoteSectionItemEdit,
|
|
414
|
-
sharedStyles.footnoteSectionItemEdit
|
|
415
|
-
),
|
|
416
|
-
children: [
|
|
417
|
-
/* @__PURE__ */ jsxs(
|
|
418
|
-
"span",
|
|
419
|
-
{
|
|
420
|
-
className: clsx(
|
|
421
|
-
semanticClassNames.footnoteSectionItemNum,
|
|
422
|
-
sharedStyles.footnoteSectionItemNum
|
|
423
|
-
),
|
|
424
|
-
children: [
|
|
425
|
-
displayNum,
|
|
426
|
-
"."
|
|
427
|
-
]
|
|
428
|
-
}
|
|
429
|
-
),
|
|
430
|
-
/* @__PURE__ */ jsx(
|
|
431
|
-
"input",
|
|
432
|
-
{
|
|
433
|
-
placeholder: `Footnote content for [^${identifier}]`,
|
|
434
|
-
type: "text",
|
|
435
|
-
value: content,
|
|
436
|
-
className: clsx(
|
|
437
|
-
semanticClassNames.footnoteSectionItemInput,
|
|
438
|
-
sharedStyles.footnoteSectionItemInput
|
|
439
|
-
),
|
|
440
|
-
onChange: (e) => handleContentChange(identifier, e.target.value)
|
|
441
|
-
}
|
|
442
|
-
),
|
|
443
|
-
/* @__PURE__ */ jsx(
|
|
444
|
-
"button",
|
|
445
|
-
{
|
|
446
|
-
"aria-label": `Remove footnote ${identifier}`,
|
|
447
|
-
type: "button",
|
|
448
|
-
className: clsx(
|
|
449
|
-
semanticClassNames.footnoteSectionItemRemove,
|
|
450
|
-
sharedStyles.footnoteSectionItemRemove
|
|
451
|
-
),
|
|
452
|
-
onClick: () => handleRemove(identifier),
|
|
453
|
-
children: "×"
|
|
454
|
-
}
|
|
455
|
-
)
|
|
456
|
-
]
|
|
457
|
-
},
|
|
458
|
-
identifier
|
|
459
|
-
);
|
|
460
|
-
})
|
|
461
|
-
}
|
|
462
|
-
)
|
|
463
|
-
]
|
|
464
|
-
}
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
class FootnoteSectionEditNode extends FootnoteSectionNode {
|
|
468
|
-
static getType() {
|
|
469
|
-
return "footnote-section";
|
|
470
|
-
}
|
|
471
|
-
static clone(node) {
|
|
472
|
-
return new FootnoteSectionEditNode({ ...node.__definitions }, node.__key);
|
|
473
|
-
}
|
|
474
|
-
static importJSON(serializedNode) {
|
|
475
|
-
return new FootnoteSectionEditNode(serializedNode.definitions);
|
|
476
|
-
}
|
|
477
|
-
decorate(_editor, _config) {
|
|
478
|
-
return createElement(FootnoteSectionEditRenderer, {
|
|
479
|
-
definitions: this.__definitions,
|
|
480
|
-
nodeKey: this.__key
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
const COL_OPTIONS = [1, 2, 3, 4];
|
|
485
|
-
function GridEditDecorator({
|
|
486
|
-
nodeKey,
|
|
487
|
-
cols: initialCols,
|
|
488
|
-
gap,
|
|
489
|
-
cellEditors
|
|
490
|
-
}) {
|
|
491
|
-
const [editor] = useLexicalComposerContext();
|
|
492
|
-
const [currentCols, setCurrentCols] = useState(initialCols);
|
|
493
|
-
useEffect(() => {
|
|
494
|
-
return editor.registerUpdateListener(({ editorState }) => {
|
|
495
|
-
editorState.read(() => {
|
|
496
|
-
const node = $getNodeByKey(nodeKey);
|
|
497
|
-
if ($isGridContainerNode(node)) {
|
|
498
|
-
setCurrentCols(node.getCols());
|
|
499
|
-
}
|
|
500
|
-
});
|
|
501
|
-
});
|
|
502
|
-
}, [editor, nodeKey]);
|
|
503
|
-
const handleSetCols = useCallback(
|
|
504
|
-
(cols) => {
|
|
505
|
-
editor.update(() => {
|
|
506
|
-
const node = $getNodeByKey(nodeKey);
|
|
507
|
-
if ($isGridContainerNode(node)) {
|
|
508
|
-
node.setCols(cols);
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
},
|
|
512
|
-
[editor, nodeKey]
|
|
513
|
-
);
|
|
514
|
-
const handleAddRow = useCallback(() => {
|
|
515
|
-
editor.update(() => {
|
|
516
|
-
const node = $getNodeByKey(nodeKey);
|
|
517
|
-
if ($isGridContainerNode(node)) {
|
|
518
|
-
node.addCells(node.getCols());
|
|
519
|
-
}
|
|
520
|
-
});
|
|
521
|
-
}, [editor, nodeKey]);
|
|
522
|
-
const handleRemoveRow = useCallback(() => {
|
|
523
|
-
editor.update(() => {
|
|
524
|
-
const node = $getNodeByKey(nodeKey);
|
|
525
|
-
if (!$isGridEditNode(node)) return;
|
|
526
|
-
const cols = node.getCols();
|
|
527
|
-
const editors = node.getCellEditors();
|
|
528
|
-
if (editors.length <= cols) return;
|
|
529
|
-
const lastRow = editors.slice(-cols);
|
|
530
|
-
const allEmpty = lastRow.every(
|
|
531
|
-
(cellEditor) => cellEditor.getEditorState().read(() => $getRoot().getTextContentSize() === 0)
|
|
532
|
-
);
|
|
533
|
-
if (!allEmpty) return;
|
|
534
|
-
node.removeCells(cols);
|
|
535
|
-
});
|
|
536
|
-
}, [editor, nodeKey]);
|
|
537
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
538
|
-
/* @__PURE__ */ jsxs(
|
|
539
|
-
"div",
|
|
540
|
-
{
|
|
541
|
-
className: clsx(gridClassNames.toolbar, gridStyles.toolbar),
|
|
542
|
-
onMouseDown: (e) => e.preventDefault(),
|
|
543
|
-
children: [
|
|
544
|
-
/* @__PURE__ */ jsx("span", { className: clsx(gridClassNames.toolbarIcon, gridStyles.toolbarIcon), children: /* @__PURE__ */ jsx(LayoutGrid, { size: 14 }) }),
|
|
545
|
-
COL_OPTIONS.map((n) => /* @__PURE__ */ jsx(
|
|
546
|
-
"button",
|
|
547
|
-
{
|
|
548
|
-
"aria-label": `${n} columns`,
|
|
549
|
-
type: "button",
|
|
550
|
-
className: clsx(
|
|
551
|
-
gridClassNames.colButton,
|
|
552
|
-
gridStyles.colButton,
|
|
553
|
-
n === currentCols && gridClassNames.colButtonActive,
|
|
554
|
-
n === currentCols && gridStyles.colButtonActive
|
|
555
|
-
),
|
|
556
|
-
onClick: () => handleSetCols(n),
|
|
557
|
-
children: n
|
|
558
|
-
},
|
|
559
|
-
n
|
|
560
|
-
)),
|
|
561
|
-
/* @__PURE__ */ jsx("div", { className: clsx(gridClassNames.toolbarDivider, gridStyles.toolbarDivider) }),
|
|
562
|
-
/* @__PURE__ */ jsx(
|
|
563
|
-
"button",
|
|
564
|
-
{
|
|
565
|
-
"aria-label": "Add row",
|
|
566
|
-
className: clsx(gridClassNames.actionButton, gridStyles.actionButton),
|
|
567
|
-
type: "button",
|
|
568
|
-
onClick: handleAddRow,
|
|
569
|
-
children: /* @__PURE__ */ jsx(Plus, { size: 14 })
|
|
570
|
-
}
|
|
571
|
-
),
|
|
572
|
-
/* @__PURE__ */ jsx(
|
|
573
|
-
"button",
|
|
574
|
-
{
|
|
575
|
-
"aria-label": "Remove row",
|
|
576
|
-
className: clsx(gridClassNames.actionButton, gridStyles.actionButton),
|
|
577
|
-
type: "button",
|
|
578
|
-
onClick: handleRemoveRow,
|
|
579
|
-
children: /* @__PURE__ */ jsx(Minus, { size: 14 })
|
|
580
|
-
}
|
|
581
|
-
)
|
|
582
|
-
]
|
|
583
|
-
}
|
|
584
|
-
),
|
|
585
|
-
/* @__PURE__ */ jsx(
|
|
586
|
-
"div",
|
|
587
|
-
{
|
|
588
|
-
className: clsx(gridClassNames.inner, gridStyles.inner),
|
|
589
|
-
style: {
|
|
590
|
-
gridTemplateColumns: `repeat(${currentCols}, 1fr)`,
|
|
591
|
-
gap
|
|
592
|
-
},
|
|
593
|
-
children: cellEditors.map((cellEditor, i) => /* @__PURE__ */ jsx("div", { className: clsx(gridClassNames.cell, gridStyles.cell), children: /* @__PURE__ */ jsxs(LexicalNestedComposer, { initialEditor: cellEditor, children: [
|
|
594
|
-
/* @__PURE__ */ jsx(
|
|
595
|
-
RichTextPlugin,
|
|
596
|
-
{
|
|
597
|
-
ErrorBoundary: LexicalErrorBoundary,
|
|
598
|
-
contentEditable: /* @__PURE__ */ jsx(
|
|
599
|
-
ContentEditable,
|
|
600
|
-
{
|
|
601
|
-
"aria-placeholder": "",
|
|
602
|
-
className: clsx(gridClassNames.cellEditable, gridStyles.cellEditable),
|
|
603
|
-
placeholder: /* @__PURE__ */ jsx("span", { style: { display: "none" } })
|
|
604
|
-
}
|
|
605
|
-
)
|
|
606
|
-
}
|
|
607
|
-
),
|
|
608
|
-
/* @__PURE__ */ jsx(ListPlugin, {}),
|
|
609
|
-
/* @__PURE__ */ jsx(LinkPlugin, {})
|
|
610
|
-
] }) }, i))
|
|
611
|
-
}
|
|
612
|
-
)
|
|
613
|
-
] });
|
|
614
|
-
}
|
|
615
|
-
function createCellEditor() {
|
|
616
|
-
return createEditor({
|
|
617
|
-
namespace: "GridCell",
|
|
618
|
-
nodes: NESTED_EDITOR_NODES,
|
|
619
|
-
theme: editorTheme,
|
|
620
|
-
onError: (error) => {
|
|
621
|
-
console.error("[GridCell]", error);
|
|
622
|
-
}
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
const _GridEditNode = class _GridEditNode extends GridContainerNode {
|
|
626
|
-
constructor(cols = 2, gap, cellStates, key) {
|
|
627
|
-
super(cols, gap, cellStates, key);
|
|
628
|
-
__publicField(this, "__cellEditors");
|
|
629
|
-
this.__cellEditors = this.__cellStates.map((state) => {
|
|
630
|
-
const editor = createCellEditor();
|
|
631
|
-
const editorState = editor.parseEditorState(state);
|
|
632
|
-
editor.setEditorState(editorState);
|
|
633
|
-
return editor;
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
static clone(node) {
|
|
637
|
-
const cloned = new _GridEditNode(node.__cols, node.__gap, node.__cellStates, node.__key);
|
|
638
|
-
cloned.__cellEditors = [...node.__cellEditors];
|
|
639
|
-
return cloned;
|
|
640
|
-
}
|
|
641
|
-
getCellEditors() {
|
|
642
|
-
return this.getLatest().__cellEditors;
|
|
643
|
-
}
|
|
644
|
-
setCols(cols) {
|
|
645
|
-
const writable = this.getWritable();
|
|
646
|
-
const prev = writable.__cellEditors.length;
|
|
647
|
-
writable.__cols = cols;
|
|
648
|
-
if (cols > prev) {
|
|
649
|
-
for (let i = prev; i < cols; i++) {
|
|
650
|
-
const editor = createCellEditor();
|
|
651
|
-
writable.__cellEditors.push(editor);
|
|
652
|
-
const emptyState = {
|
|
653
|
-
root: {
|
|
654
|
-
children: [
|
|
655
|
-
{
|
|
656
|
-
type: "paragraph",
|
|
657
|
-
children: [],
|
|
658
|
-
direction: null,
|
|
659
|
-
format: "",
|
|
660
|
-
indent: 0,
|
|
661
|
-
textFormat: 0,
|
|
662
|
-
textStyle: "",
|
|
663
|
-
version: 1
|
|
664
|
-
}
|
|
665
|
-
],
|
|
666
|
-
direction: null,
|
|
667
|
-
format: "",
|
|
668
|
-
indent: 0,
|
|
669
|
-
type: "root",
|
|
670
|
-
version: 1
|
|
671
|
-
}
|
|
672
|
-
};
|
|
673
|
-
writable.__cellStates.push(emptyState);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
addCells(count) {
|
|
678
|
-
const writable = this.getWritable();
|
|
679
|
-
for (let i = 0; i < count; i++) {
|
|
680
|
-
const editor = createCellEditor();
|
|
681
|
-
writable.__cellEditors.push(editor);
|
|
682
|
-
const emptyState = {
|
|
683
|
-
root: {
|
|
684
|
-
children: [
|
|
685
|
-
{
|
|
686
|
-
type: "paragraph",
|
|
687
|
-
children: [],
|
|
688
|
-
direction: null,
|
|
689
|
-
format: "",
|
|
690
|
-
indent: 0,
|
|
691
|
-
textFormat: 0,
|
|
692
|
-
textStyle: "",
|
|
693
|
-
version: 1
|
|
694
|
-
}
|
|
695
|
-
],
|
|
696
|
-
direction: null,
|
|
697
|
-
format: "",
|
|
698
|
-
indent: 0,
|
|
699
|
-
type: "root",
|
|
700
|
-
version: 1
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
writable.__cellStates.push(emptyState);
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
removeCells(count) {
|
|
707
|
-
const writable = this.getWritable();
|
|
708
|
-
const editors = writable.__cellEditors;
|
|
709
|
-
const states = writable.__cellStates;
|
|
710
|
-
const toRemove = Math.min(count, editors.length);
|
|
711
|
-
for (let i = 0; i < toRemove; i++) {
|
|
712
|
-
const editor = editors.at(-1);
|
|
713
|
-
if (!editor) break;
|
|
714
|
-
const isEmpty = editor.getEditorState().read(() => {
|
|
715
|
-
return $getRoot().getTextContentSize() === 0;
|
|
716
|
-
});
|
|
717
|
-
if (!isEmpty) break;
|
|
718
|
-
editors.pop();
|
|
719
|
-
states.pop();
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
static importJSON(serializedNode) {
|
|
723
|
-
const legacy = serializedNode;
|
|
724
|
-
const cols = legacy.cols || 2;
|
|
725
|
-
const rawGap = legacy.gap;
|
|
726
|
-
const gap = typeof rawGap === "number" ? `${rawGap}px` : rawGap;
|
|
727
|
-
if (legacy.cells && legacy.cells.length > 0) {
|
|
728
|
-
return new _GridEditNode(cols, gap, legacy.cells);
|
|
729
|
-
}
|
|
730
|
-
if (legacy.children) {
|
|
731
|
-
const cellStates = legacy.children.map((child) => {
|
|
732
|
-
return {
|
|
733
|
-
root: {
|
|
734
|
-
children: [child],
|
|
735
|
-
direction: null,
|
|
736
|
-
format: "",
|
|
737
|
-
indent: 0,
|
|
738
|
-
type: "root",
|
|
739
|
-
version: 1
|
|
740
|
-
}
|
|
741
|
-
};
|
|
742
|
-
});
|
|
743
|
-
return new _GridEditNode(cols, gap, cellStates);
|
|
744
|
-
}
|
|
745
|
-
return new _GridEditNode(cols, gap);
|
|
746
|
-
}
|
|
747
|
-
exportJSON() {
|
|
748
|
-
return {
|
|
749
|
-
...super.exportJSON(),
|
|
750
|
-
type: "grid-container",
|
|
751
|
-
cols: this.__cols,
|
|
752
|
-
gap: this.__gap,
|
|
753
|
-
cells: this.__cellEditors.map((editor) => editor.getEditorState().toJSON()),
|
|
754
|
-
version: 1
|
|
755
|
-
};
|
|
756
|
-
}
|
|
757
|
-
decorate(_editor, _config) {
|
|
758
|
-
return createElement(GridEditDecorator, {
|
|
759
|
-
nodeKey: this.__key,
|
|
760
|
-
cols: this.__cols,
|
|
761
|
-
gap: this.__gap,
|
|
762
|
-
cellEditors: this.__cellEditors
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
};
|
|
766
|
-
__publicField(_GridEditNode, "slashMenuItems", [
|
|
767
|
-
{
|
|
768
|
-
title: "Grid",
|
|
769
|
-
icon: createElement(LayoutGrid, { size: 20 }),
|
|
770
|
-
description: "Grid layout container",
|
|
771
|
-
keywords: ["grid", "columns", "layout"],
|
|
772
|
-
section: "LAYOUT",
|
|
773
|
-
onSelect: (editor) => {
|
|
774
|
-
editor.update(() => {
|
|
775
|
-
$insertNodes([$createGridEditNode(2)]);
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
]);
|
|
780
|
-
let GridEditNode = _GridEditNode;
|
|
781
|
-
function $createGridEditNode(cols = 2, gap) {
|
|
782
|
-
return new GridEditNode(cols, gap);
|
|
783
|
-
}
|
|
784
|
-
function $isGridEditNode(node) {
|
|
785
|
-
return node instanceof GridEditNode;
|
|
786
|
-
}
|
|
787
|
-
const customEditNodes = [
|
|
788
|
-
SpoilerNode,
|
|
789
|
-
MentionNode,
|
|
790
|
-
KaTeXInlineNode,
|
|
791
|
-
KaTeXBlockNode,
|
|
792
|
-
ImageNode,
|
|
793
|
-
AlertQuoteEditNode,
|
|
794
|
-
CodeBlockEditNode,
|
|
795
|
-
FootnoteNode,
|
|
796
|
-
FootnoteSectionEditNode,
|
|
797
|
-
VideoNode,
|
|
798
|
-
LinkCardNode,
|
|
799
|
-
CommentNode,
|
|
800
|
-
DetailsNode,
|
|
801
|
-
GridEditNode,
|
|
802
|
-
BannerEditNode,
|
|
803
|
-
MermaidNode,
|
|
804
|
-
RubyNode,
|
|
805
|
-
TagNode
|
|
806
|
-
];
|
|
807
|
-
const allEditNodes = [...builtinNodes, ...customEditNodes];
|
|
808
|
-
let _resolvedEditNodes = null;
|
|
809
|
-
function setResolvedEditNodes(nodes) {
|
|
810
|
-
_resolvedEditNodes = nodes;
|
|
811
|
-
}
|
|
812
|
-
function getResolvedEditNodes() {
|
|
813
|
-
return _resolvedEditNodes ?? allEditNodes;
|
|
814
|
-
}
|
|
815
|
-
export {
|
|
816
|
-
$createBannerEditNode as $,
|
|
817
|
-
FootnoteSectionEditNode as F,
|
|
818
|
-
allEditNodes as a,
|
|
819
|
-
setCodeBlockCursorIntent as b,
|
|
820
|
-
customEditNodes as c,
|
|
821
|
-
$createCodeBlockEditNode as d,
|
|
822
|
-
getResolvedEditNodes as g,
|
|
823
|
-
setResolvedEditNodes as s
|
|
824
|
-
};
|