@haklex/rich-editor 0.1.1 → 0.3.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 (65) 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/RubyRenderer-jOkydJHg.js +15 -0
  6. package/dist/SubmitShortcutPlugin-DhyVFzoj.js +2186 -0
  7. package/dist/commands-entry.mjs +54 -74
  8. package/dist/components/decorators/PollEditDecorator.d.ts +13 -0
  9. package/dist/components/decorators/PollEditDecorator.d.ts.map +1 -0
  10. package/dist/components/renderers/PollRenderer.d.ts +3 -0
  11. package/dist/components/renderers/PollRenderer.d.ts.map +1 -0
  12. package/dist/config-B5BuLljq.js +1633 -0
  13. package/dist/config-edit.d.ts.map +1 -1
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/context/PollDataContext.d.ts +11 -0
  16. package/dist/context/PollDataContext.d.ts.map +1 -0
  17. package/dist/extractPolls-DO31LNrp.js +116 -0
  18. package/dist/grid.css-CJCkLTZc.js +44 -0
  19. package/dist/index.d.ts +5 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.mjs +121 -180
  22. package/dist/katex.css-CIOEOXyd.js +145 -0
  23. package/dist/node-registry-Dz5OTkh4.js +946 -0
  24. package/dist/nodes/PollEditNode.d.ts +14 -0
  25. package/dist/nodes/PollEditNode.d.ts.map +1 -0
  26. package/dist/nodes/PollNode.d.ts +52 -0
  27. package/dist/nodes/PollNode.d.ts.map +1 -0
  28. package/dist/nodes-entry.d.ts +3 -0
  29. package/dist/nodes-entry.d.ts.map +1 -1
  30. package/dist/nodes-entry.mjs +5 -50
  31. package/dist/normalizeSerializedEditorState-B-1wmGzd.js +78 -0
  32. package/dist/plugins-entry.mjs +3 -28
  33. package/dist/renderers-entry.mjs +41 -61
  34. package/dist/rich-editor.css +2 -1
  35. package/dist/static-entry.d.ts +5 -0
  36. package/dist/static-entry.d.ts.map +1 -1
  37. package/dist/static-entry.mjs +16 -66
  38. package/dist/styles/index.d.ts +2 -0
  39. package/dist/styles/index.d.ts.map +1 -1
  40. package/dist/styles/poll-edit.css.d.ts +35 -0
  41. package/dist/styles/poll-edit.css.d.ts.map +1 -0
  42. package/dist/styles/poll.css.d.ts +43 -0
  43. package/dist/styles/poll.css.d.ts.map +1 -0
  44. package/dist/styles-entry.mjs +3 -21
  45. package/dist/theme-B5B2EOWM.js +1099 -0
  46. package/dist/types/poll.d.ts +36 -0
  47. package/dist/types/poll.d.ts.map +1 -0
  48. package/dist/types/renderer-config.d.ts +3 -0
  49. package/dist/types/renderer-config.d.ts.map +1 -1
  50. package/dist/utils/extractPolls.d.ts +4 -0
  51. package/dist/utils/extractPolls.d.ts.map +1 -0
  52. package/package.json +30 -30
  53. package/dist/AlertQuoteEditNode-sPNf3_7P.js +0 -293
  54. package/dist/KaTeXRenderer-CQyQzNTJ.js +0 -218
  55. package/dist/LinkCardRenderer-QmkOlyXb.js +0 -36
  56. package/dist/MermaidPlugin-DKuGUcCG.js +0 -101
  57. package/dist/PresentDialogContext-DRroMIoK.js +0 -71
  58. package/dist/RubyRenderer-CJQmODir.js +0 -14
  59. package/dist/SubmitShortcutPlugin-D9uKYHda.js +0 -2427
  60. package/dist/config-Dl3ZkytB.js +0 -1362
  61. package/dist/grid.css-Md5-Cfx_.js +0 -11
  62. package/dist/katex.css-Csc-7N7u.js +0 -28
  63. package/dist/node-registry-CovhHUB6.js +0 -824
  64. package/dist/normalizeSerializedEditorState-k5G4xSi9.js +0 -85
  65. 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
- };