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