@haklex/rich-editor 0.0.80 → 0.0.81

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