@haklex/rich-editor 0.1.0 → 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,1246 @@
1
+ import { A as AlertQuoteNode, C as ImageNode, E as FootnoteNode, F as useNestedContentRenderer, M as extractTextContent, _ as KaTeXInlineNode, b as KaTeXBlockNode, c as SpoilerNode, d as MermaidNode, i as TagNode, j as _defineProperty, m as MentionNode } from "./theme-B5B2EOWM.js";
2
+ import { l as RendererWrapper, m as useVariant, s as useFootnoteDefinitions, u as createRendererDecoration } from "./KaTeXRenderer-CQQT3BMw.js";
3
+ import { l as semanticClassNames, r as clsx, u as sharedStyles } from "./katex.css-CIOEOXyd.js";
4
+ import { i as detailsStyles, n as gridStyles, r as detailsClassNames, t as gridClassNames } from "./grid.css-CJCkLTZc.js";
5
+ import { t as LinkCardRenderer } from "./LinkCardRenderer-CigqFwCv.js";
6
+ import { AutoLinkNode, LinkNode } from "@lexical/link";
7
+ import { createContext, createElement, use, useCallback, useEffect, useRef, useState } from "react";
8
+ import { HeadingNode, QuoteNode } from "@lexical/rich-text";
9
+ import { $createTextNode, $insertNodes, DecoratorNode, ElementNode, TextNode } from "lexical";
10
+ import { HorizontalRuleNode } from "@lexical/extension";
11
+ import { CodeNode } from "@lexical/code-core";
12
+ import { ListItemNode, ListNode } from "@lexical/list";
13
+ import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
15
+ import { ChevronRight, Code, Link, MessageSquareQuote, Video } from "lucide-react";
16
+ //#region src/components/renderers/BannerRenderer.tsx
17
+ var BannerRenderer = ({ type }) => {
18
+ return /* @__PURE__ */ jsx("span", { className: `rich-banner-icon rich-banner-icon-${type}` });
19
+ };
20
+ //#endregion
21
+ //#region src/components/renderers/BannerStaticDecorator.tsx
22
+ function BannerStaticDecorator({ bannerType, contentState }) {
23
+ const renderContent = useNestedContentRenderer();
24
+ return /* @__PURE__ */ jsxs("div", {
25
+ className: "rich-banner-inner",
26
+ children: [/* @__PURE__ */ jsx(RendererWrapper, {
27
+ defaultRenderer: BannerRenderer,
28
+ props: { type: bannerType },
29
+ rendererKey: "Banner"
30
+ }), /* @__PURE__ */ jsx("div", {
31
+ className: "rich-banner-content",
32
+ children: renderContent(contentState)
33
+ })]
34
+ });
35
+ }
36
+ //#endregion
37
+ //#region src/nodes/BannerNode.ts
38
+ var LEGACY_TYPE_MAP = {
39
+ info: "note",
40
+ success: "tip",
41
+ error: "caution"
42
+ };
43
+ function normalizeBannerType(type) {
44
+ if (type in LEGACY_TYPE_MAP) return LEGACY_TYPE_MAP[type];
45
+ return type || "note";
46
+ }
47
+ var BANNER_TYPES = [
48
+ "note",
49
+ "tip",
50
+ "important",
51
+ "warning",
52
+ "caution"
53
+ ];
54
+ var BANNER_LABELS = {
55
+ note: "Note",
56
+ tip: "Tip",
57
+ important: "Important",
58
+ warning: "Warning",
59
+ caution: "Caution"
60
+ };
61
+ var BannerNode = class BannerNode extends DecoratorNode {
62
+ static getType() {
63
+ return "banner";
64
+ }
65
+ static clone(node) {
66
+ return new BannerNode(node.__bannerType, node.__contentState, node.__key);
67
+ }
68
+ constructor(bannerType, contentState, key) {
69
+ super(key);
70
+ _defineProperty(this, "__bannerType", void 0);
71
+ _defineProperty(this, "__contentState", void 0);
72
+ this.__bannerType = bannerType;
73
+ this.__contentState = contentState || { root: {
74
+ children: [{
75
+ type: "paragraph",
76
+ children: [],
77
+ direction: null,
78
+ format: "",
79
+ indent: 0,
80
+ textFormat: 0,
81
+ textStyle: "",
82
+ version: 1
83
+ }],
84
+ direction: null,
85
+ format: "",
86
+ indent: 0,
87
+ type: "root",
88
+ version: 1
89
+ } };
90
+ }
91
+ createDOM(_config) {
92
+ const div = document.createElement("div");
93
+ div.className = `rich-banner rich-banner-${this.__bannerType}`;
94
+ return div;
95
+ }
96
+ updateDOM(prevNode, dom) {
97
+ if (prevNode.__bannerType !== this.__bannerType) dom.className = `rich-banner rich-banner-${this.__bannerType}`;
98
+ return false;
99
+ }
100
+ isInline() {
101
+ return false;
102
+ }
103
+ getBannerType() {
104
+ return this.__bannerType;
105
+ }
106
+ setBannerType(bannerType) {
107
+ const writable = this.getWritable();
108
+ writable.__bannerType = bannerType;
109
+ }
110
+ getContentState() {
111
+ return this.getLatest().__contentState;
112
+ }
113
+ setContentState(state) {
114
+ const writable = this.getWritable();
115
+ writable.__contentState = state;
116
+ }
117
+ getTextContent() {
118
+ return extractTextContent(this.__contentState);
119
+ }
120
+ static importJSON(serializedNode) {
121
+ const legacy = serializedNode;
122
+ const bannerType = normalizeBannerType(serializedNode.bannerType);
123
+ if (serializedNode.content) return new BannerNode(bannerType, serializedNode.content);
124
+ if (legacy.children) return new BannerNode(bannerType, { root: {
125
+ children: legacy.children,
126
+ direction: null,
127
+ format: "",
128
+ indent: 0,
129
+ type: "root",
130
+ version: 1
131
+ } });
132
+ return new BannerNode(bannerType);
133
+ }
134
+ exportJSON() {
135
+ return {
136
+ ...super.exportJSON(),
137
+ type: "banner",
138
+ bannerType: this.__bannerType,
139
+ content: this.__contentState,
140
+ version: 1
141
+ };
142
+ }
143
+ decorate(_editor, _config) {
144
+ return createElement(BannerStaticDecorator, {
145
+ bannerType: this.__bannerType,
146
+ contentState: this.__contentState
147
+ });
148
+ }
149
+ };
150
+ function $isBannerNode(node) {
151
+ return node instanceof BannerNode;
152
+ }
153
+ //#endregion
154
+ //#region src/context/ColorSchemeContext.tsx
155
+ var ColorSchemeContext = createContext("light");
156
+ function ColorSchemeProvider({ colorScheme, children }) {
157
+ return /* @__PURE__ */ jsx(ColorSchemeContext.Provider, {
158
+ value: colorScheme,
159
+ children
160
+ });
161
+ }
162
+ function useColorScheme() {
163
+ return use(ColorSchemeContext);
164
+ }
165
+ //#endregion
166
+ //#region src/utils/shiki.ts
167
+ var codeToHtmlFn = null;
168
+ var shikiLoadPromise = null;
169
+ function loadCodeToHtml() {
170
+ if (codeToHtmlFn) return Promise.resolve(codeToHtmlFn);
171
+ if (!shikiLoadPromise) shikiLoadPromise = import("shiki/bundle/web").then((mod) => {
172
+ codeToHtmlFn = mod.codeToHtml;
173
+ return mod.codeToHtml;
174
+ }).catch((err) => {
175
+ shikiLoadPromise = null;
176
+ throw err;
177
+ });
178
+ return shikiLoadPromise;
179
+ }
180
+ //#endregion
181
+ //#region src/components/renderers/CodeBlockRenderer.tsx
182
+ function CodeBlockRenderer({ code, language, showLineNumbers: showLineNumbersProp }) {
183
+ const variant = useVariant();
184
+ const showLineNumbers = showLineNumbersProp ?? variant !== "comment";
185
+ const shikiTheme = useColorScheme() === "dark" ? "github-dark" : "github-light";
186
+ const [highlightedHtml, setHighlightedHtml] = useState(null);
187
+ const [copied, setCopied] = useState(false);
188
+ const copyTimerRef = useRef(void 0);
189
+ useEffect(() => {
190
+ let cancelled = false;
191
+ setHighlightedHtml(null);
192
+ loadCodeToHtml().then((toHtml) => toHtml(code, {
193
+ lang: language,
194
+ theme: shikiTheme
195
+ })).then((html) => {
196
+ if (!cancelled) setHighlightedHtml(html);
197
+ }).catch(() => {
198
+ if (!cancelled) setHighlightedHtml(null);
199
+ });
200
+ return () => {
201
+ cancelled = true;
202
+ };
203
+ }, [
204
+ code,
205
+ language,
206
+ shikiTheme
207
+ ]);
208
+ useEffect(() => {
209
+ return () => clearTimeout(copyTimerRef.current);
210
+ }, []);
211
+ const handleCopy = useCallback(() => {
212
+ navigator.clipboard.writeText(code).then(() => {
213
+ setCopied(true);
214
+ clearTimeout(copyTimerRef.current);
215
+ copyTimerRef.current = setTimeout(() => setCopied(false), 2e3);
216
+ }).catch(() => {});
217
+ }, [code]);
218
+ const header = language ? /* @__PURE__ */ jsxs("div", {
219
+ className: "rich-code-block-header",
220
+ children: [/* @__PURE__ */ jsx("span", {
221
+ className: "rich-code-block-lang",
222
+ children: language
223
+ }), /* @__PURE__ */ jsx("button", {
224
+ "aria-label": copied ? "Copied to clipboard" : "Copy code",
225
+ className: "rich-code-block-copy",
226
+ type: "button",
227
+ onClick: handleCopy,
228
+ children: copied ? "Copied" : "Copy"
229
+ })]
230
+ }) : null;
231
+ const wrapperClass = showLineNumbers ? "rich-code-block rich-code-block-numbered" : "rich-code-block";
232
+ if (highlightedHtml) return /* @__PURE__ */ jsxs("div", {
233
+ className: wrapperClass,
234
+ children: [header, /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: highlightedHtml } })]
235
+ });
236
+ const lines = code.split("\n");
237
+ return /* @__PURE__ */ jsxs("div", {
238
+ className: wrapperClass,
239
+ children: [header, /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => /* @__PURE__ */ jsxs("span", {
240
+ className: "line",
241
+ children: [line, i < lines.length - 1 ? "\n" : ""]
242
+ }, i)) }) })]
243
+ });
244
+ }
245
+ //#endregion
246
+ //#region src/nodes/CodeBlockNode.ts
247
+ var CodeBlockNode = class CodeBlockNode extends DecoratorNode {
248
+ static getType() {
249
+ return "code-block";
250
+ }
251
+ static clone(node) {
252
+ return new CodeBlockNode(node.__code, node.__language, node.__key);
253
+ }
254
+ constructor(code, language, key) {
255
+ super(key);
256
+ _defineProperty(this, "__code", void 0);
257
+ _defineProperty(this, "__language", void 0);
258
+ this.__code = code;
259
+ this.__language = language;
260
+ }
261
+ createDOM(_config) {
262
+ const div = document.createElement("div");
263
+ div.className = "rich-code-block-wrapper";
264
+ return div;
265
+ }
266
+ updateDOM() {
267
+ return false;
268
+ }
269
+ isInline() {
270
+ return false;
271
+ }
272
+ isKeyboardSelectable() {
273
+ return true;
274
+ }
275
+ static importJSON(serializedNode) {
276
+ return $createCodeBlockNode(serializedNode.code, serializedNode.language);
277
+ }
278
+ exportJSON() {
279
+ return {
280
+ ...super.exportJSON(),
281
+ type: "code-block",
282
+ code: this.__code,
283
+ language: this.__language,
284
+ version: 1
285
+ };
286
+ }
287
+ getCode() {
288
+ return this.__code;
289
+ }
290
+ setCode(code) {
291
+ const writable = this.getWritable();
292
+ writable.__code = code;
293
+ }
294
+ getLanguage() {
295
+ return this.__language;
296
+ }
297
+ setLanguage(language) {
298
+ const writable = this.getWritable();
299
+ writable.__language = language;
300
+ }
301
+ decorate(_editor, _config) {
302
+ return createRendererDecoration("CodeBlock", CodeBlockRenderer, {
303
+ code: this.__code,
304
+ language: this.__language
305
+ });
306
+ }
307
+ };
308
+ _defineProperty(CodeBlockNode, "commandItems", [{
309
+ title: "Code Block",
310
+ icon: createElement(Code, { size: 20 }),
311
+ description: "Syntax-highlighted code",
312
+ keywords: [
313
+ "code",
314
+ "snippet",
315
+ "codeblock"
316
+ ],
317
+ section: "MEDIA",
318
+ placement: ["slash", "toolbar"],
319
+ group: "insert",
320
+ onSelect: (editor) => {
321
+ editor.update(() => {
322
+ $insertNodes([$createCodeBlockNode("", "text")]);
323
+ });
324
+ }
325
+ }]);
326
+ function $createCodeBlockNode(code, language) {
327
+ return new CodeBlockNode(code, language);
328
+ }
329
+ function $isCodeBlockNode(node) {
330
+ return node instanceof CodeBlockNode;
331
+ }
332
+ //#endregion
333
+ //#region src/nodes/CommentNode.ts
334
+ var DEFAULT_COMMENT_TEXT = "comment";
335
+ var CommentNode = class CommentNode extends TextNode {
336
+ static getType() {
337
+ return "comment";
338
+ }
339
+ static clone(node) {
340
+ return new CommentNode(node.__text, node.__key);
341
+ }
342
+ static importDOM() {
343
+ return {
344
+ "#comment": () => ({
345
+ conversion: (domNode) => {
346
+ if (!(domNode instanceof Comment)) return null;
347
+ return { node: $createCommentNode(domNode.data) };
348
+ },
349
+ priority: 4
350
+ }),
351
+ "span": () => ({
352
+ conversion: (domNode) => {
353
+ if (!(domNode instanceof HTMLElement)) return null;
354
+ if (!domNode.classList.contains(semanticClassNames.comment)) return null;
355
+ return { node: $createCommentNode(domNode.dataset.comment ?? domNode.textContent ?? "") };
356
+ },
357
+ priority: 2
358
+ })
359
+ };
360
+ }
361
+ constructor(text, key) {
362
+ super(text, key);
363
+ }
364
+ createDOM(config) {
365
+ const element = super.createDOM(config);
366
+ element.classList.add(semanticClassNames.comment, sharedStyles.comment);
367
+ element.dataset.comment = this.__text;
368
+ return element;
369
+ }
370
+ updateDOM(prevNode, dom, config) {
371
+ const updated = super.updateDOM(prevNode, dom, config);
372
+ dom.classList.add(semanticClassNames.comment, sharedStyles.comment);
373
+ if (prevNode.__text !== this.__text) dom.dataset.comment = this.__text;
374
+ return updated;
375
+ }
376
+ exportDOM(_editor) {
377
+ return { element: document.createComment(this.getTextContent()) };
378
+ }
379
+ static importJSON(serializedNode) {
380
+ const node = $createCommentNode(serializedNode.text ?? "");
381
+ node.setFormat(serializedNode.format ?? 0);
382
+ node.setDetail(serializedNode.detail ?? 0);
383
+ node.setMode(serializedNode.mode ?? "normal");
384
+ node.setStyle(serializedNode.style ?? "");
385
+ return node;
386
+ }
387
+ exportJSON() {
388
+ return {
389
+ ...super.exportJSON(),
390
+ type: "comment",
391
+ version: 1
392
+ };
393
+ }
394
+ };
395
+ _defineProperty(CommentNode, "commandItems", [{
396
+ title: "HTML Comment",
397
+ icon: createElement(MessageSquareQuote, { size: 20 }),
398
+ description: "Insert an HTML comment node",
399
+ keywords: [
400
+ "comment",
401
+ "html",
402
+ "annotation",
403
+ "hidden",
404
+ "<!-- -->"
405
+ ],
406
+ section: "INLINE",
407
+ placement: ["slash", "toolbar"],
408
+ group: "insert",
409
+ onSelect: (editor, _queryString) => {
410
+ editor.update(() => {
411
+ const node = $createCommentNode(DEFAULT_COMMENT_TEXT);
412
+ $insertNodes([node]);
413
+ node.select(0, node.getTextContentSize());
414
+ });
415
+ }
416
+ }]);
417
+ function $createCommentNode(text) {
418
+ return new CommentNode(text);
419
+ }
420
+ function $createCommentPlaceholderNode() {
421
+ return $createCommentNode(DEFAULT_COMMENT_TEXT);
422
+ }
423
+ function $isCommentNode(node) {
424
+ return node instanceof CommentNode;
425
+ }
426
+ //#endregion
427
+ //#region src/utils/lucide-dom.ts
428
+ var SVG_NS = "http://www.w3.org/2000/svg";
429
+ var DEFAULT_ATTRS = {
430
+ xmlns: SVG_NS,
431
+ width: "24",
432
+ height: "24",
433
+ viewBox: "0 0 24 24",
434
+ fill: "none",
435
+ stroke: "currentColor",
436
+ "stroke-width": "2",
437
+ "stroke-linecap": "round",
438
+ "stroke-linejoin": "round"
439
+ };
440
+ function createLucideSvg(iconNode, attrs = {}) {
441
+ const svg = document.createElementNS(SVG_NS, "svg");
442
+ const merged = {
443
+ ...DEFAULT_ATTRS,
444
+ ...attrs
445
+ };
446
+ for (const [k, v] of Object.entries(merged)) svg.setAttribute(k, v);
447
+ for (const [tag, elAttrs] of iconNode) {
448
+ const el = document.createElementNS(SVG_NS, tag);
449
+ for (const [k, v] of Object.entries(elAttrs)) {
450
+ if (k === "key") continue;
451
+ el.setAttribute(k, v);
452
+ }
453
+ svg.append(el);
454
+ }
455
+ return svg;
456
+ }
457
+ //#endregion
458
+ //#region src/nodes/DetailsNode.ts
459
+ var ChevronRightIconNode = [["path", { d: "M8 6L12 10L8 14" }]];
460
+ var DetailsNode = class DetailsNode extends ElementNode {
461
+ static getType() {
462
+ return "details";
463
+ }
464
+ static clone(node) {
465
+ return new DetailsNode(node.__summary, node.__open, node.__key);
466
+ }
467
+ constructor(summary, open = false, key) {
468
+ super(key);
469
+ _defineProperty(this, "__summary", void 0);
470
+ _defineProperty(this, "__open", void 0);
471
+ this.__summary = summary;
472
+ this.__open = open;
473
+ }
474
+ createDOM(_config) {
475
+ const details = document.createElement("details");
476
+ details.className = `${detailsClassNames.details} ${detailsStyles.details}`;
477
+ if (this.__open) details.open = true;
478
+ const summary = document.createElement("summary");
479
+ summary.className = `${detailsClassNames.summary} ${detailsStyles.summary}`;
480
+ const chevron = document.createElement("span");
481
+ chevron.className = `${detailsClassNames.chevron} ${detailsStyles.chevron}`;
482
+ chevron.setAttribute("aria-hidden", "true");
483
+ chevron.append(createLucideSvg(ChevronRightIconNode, {
484
+ "width": "20",
485
+ "height": "20",
486
+ "viewBox": "0 0 20 20",
487
+ "stroke-width": "1.5"
488
+ }));
489
+ summary.append(chevron);
490
+ const label = document.createElement("span");
491
+ label.className = `${detailsClassNames.summaryText} ${detailsStyles.summaryText}`;
492
+ label.textContent = this.__summary;
493
+ summary.append(label);
494
+ const content = document.createElement("div");
495
+ content.className = `${detailsClassNames.content} ${detailsStyles.content}`;
496
+ details.append(summary, content);
497
+ return details;
498
+ }
499
+ updateDOM(prevNode, dom) {
500
+ const details = dom;
501
+ if (prevNode.__open !== this.__open) details.open = this.__open;
502
+ if (prevNode.__summary !== this.__summary) {
503
+ const label = dom.querySelector(`.${detailsClassNames.summaryText}`);
504
+ if (label) label.textContent = this.__summary;
505
+ }
506
+ return false;
507
+ }
508
+ static importJSON(serializedNode) {
509
+ return $createDetailsNode(serializedNode.summary, serializedNode.open);
510
+ }
511
+ exportJSON() {
512
+ return {
513
+ ...super.exportJSON(),
514
+ type: "details",
515
+ summary: this.__summary,
516
+ open: this.__open,
517
+ version: 1
518
+ };
519
+ }
520
+ getSummary() {
521
+ return this.getLatest().__summary;
522
+ }
523
+ setSummary(summary) {
524
+ const writable = this.getWritable();
525
+ writable.__summary = summary;
526
+ }
527
+ getOpen() {
528
+ return this.getLatest().__open;
529
+ }
530
+ setOpen(open) {
531
+ const writable = this.getWritable();
532
+ writable.__open = open;
533
+ }
534
+ toggleOpen() {
535
+ this.setOpen(!this.getOpen());
536
+ }
537
+ getDOMSlot(element) {
538
+ const content = element.querySelector(`.${detailsClassNames.content}`);
539
+ return super.getDOMSlot(element).withElement(content);
540
+ }
541
+ isInline() {
542
+ return false;
543
+ }
544
+ };
545
+ _defineProperty(DetailsNode, "slashMenuItems", [{
546
+ title: "Details",
547
+ icon: createElement(ChevronRight, { size: 20 }),
548
+ description: "Collapsible content block",
549
+ keywords: [
550
+ "details",
551
+ "toggle",
552
+ "collapse",
553
+ "accordion"
554
+ ],
555
+ section: "ADVANCED",
556
+ onSelect: (editor) => {
557
+ editor.update(() => {
558
+ $insertNodes([$createDetailsNode("Details")]);
559
+ });
560
+ }
561
+ }]);
562
+ function $createDetailsNode(summary, open = false) {
563
+ return new DetailsNode(summary, open);
564
+ }
565
+ //#endregion
566
+ //#region src/components/renderers/FootnoteSectionRenderer.tsx
567
+ function FootnoteSectionRenderer({ definitions }) {
568
+ const { displayNumberMap } = useFootnoteDefinitions();
569
+ const sortedEntries = Object.entries(definitions).sort(([a], [b]) => (displayNumberMap[a] ?? 0) - (displayNumberMap[b] ?? 0));
570
+ if (sortedEntries.length === 0) return null;
571
+ return /* @__PURE__ */ jsxs("div", {
572
+ role: "doc-endnotes",
573
+ className: clsx("rich-footnote-section-content", semanticClassNames.footnoteSection, sharedStyles.footnoteSection),
574
+ children: [/* @__PURE__ */ jsx("hr", { className: clsx(semanticClassNames.footnoteSectionDivider, sharedStyles.footnoteSectionDivider) }), /* @__PURE__ */ jsx("ol", {
575
+ className: clsx(semanticClassNames.footnoteSectionList, sharedStyles.footnoteSectionList),
576
+ children: sortedEntries.map(([identifier, content]) => {
577
+ return /* @__PURE__ */ jsx(FootnoteSectionItem, {
578
+ content,
579
+ displayNum: displayNumberMap[identifier] ?? identifier,
580
+ identifier
581
+ }, identifier);
582
+ })
583
+ })]
584
+ });
585
+ }
586
+ function FootnoteSectionItem({ identifier, content, displayNum }) {
587
+ const targetId = `footnote-${identifier}`;
588
+ const refId = `footnote-ref-${identifier}`;
589
+ const handleBackClick = useCallback((e) => {
590
+ e.preventDefault();
591
+ const refElement = document.getElementById(refId);
592
+ if (!refElement) return;
593
+ refElement.scrollIntoView({
594
+ behavior: "smooth",
595
+ block: "center"
596
+ });
597
+ refElement.classList.add(semanticClassNames.footnoteHighlight, sharedStyles.footnoteHighlight);
598
+ window.setTimeout(() => {
599
+ refElement.classList.remove(semanticClassNames.footnoteHighlight, sharedStyles.footnoteHighlight);
600
+ }, 1200);
601
+ }, [refId]);
602
+ return /* @__PURE__ */ jsxs("li", {
603
+ className: clsx(semanticClassNames.footnoteSectionItem, sharedStyles.footnoteSectionItem),
604
+ id: targetId,
605
+ value: typeof displayNum === "number" ? displayNum : void 0,
606
+ children: [/* @__PURE__ */ jsx("span", {
607
+ className: "rich-footnote-section-item-content",
608
+ children: content
609
+ }), /* @__PURE__ */ jsx("a", {
610
+ "aria-label": `Back to reference ${displayNum}`,
611
+ className: clsx(semanticClassNames.footnoteBackRef, sharedStyles.footnoteBackRef),
612
+ href: `#${refId}`,
613
+ role: "doc-backlink",
614
+ onClick: handleBackClick,
615
+ children: "↩"
616
+ })]
617
+ });
618
+ }
619
+ //#endregion
620
+ //#region src/nodes/FootnoteSectionNode.ts
621
+ var FootnoteSectionNode = class FootnoteSectionNode extends DecoratorNode {
622
+ static getType() {
623
+ return "footnote-section";
624
+ }
625
+ static clone(node) {
626
+ return new FootnoteSectionNode({ ...node.__definitions }, node.__key);
627
+ }
628
+ constructor(definitions, key) {
629
+ super(key);
630
+ _defineProperty(this, "__definitions", void 0);
631
+ this.__definitions = definitions;
632
+ }
633
+ createDOM(_config) {
634
+ const div = document.createElement("div");
635
+ div.className = `${semanticClassNames.footnoteSection} ${sharedStyles.footnoteSection}`;
636
+ return div;
637
+ }
638
+ updateDOM() {
639
+ return false;
640
+ }
641
+ isInline() {
642
+ return false;
643
+ }
644
+ static importJSON(serializedNode) {
645
+ return $createFootnoteSectionNode(serializedNode.definitions);
646
+ }
647
+ exportJSON() {
648
+ return {
649
+ ...super.exportJSON(),
650
+ type: "footnote-section",
651
+ definitions: this.__definitions,
652
+ version: 1
653
+ };
654
+ }
655
+ getDefinitions() {
656
+ return this.getLatest().__definitions;
657
+ }
658
+ setDefinitions(definitions) {
659
+ const writable = this.getWritable();
660
+ writable.__definitions = definitions;
661
+ }
662
+ getDefinition(identifier) {
663
+ return this.getLatest().__definitions[identifier];
664
+ }
665
+ setDefinition(identifier, content) {
666
+ const writable = this.getWritable();
667
+ writable.__definitions = {
668
+ ...writable.__definitions,
669
+ [identifier]: content
670
+ };
671
+ }
672
+ removeDefinition(identifier) {
673
+ const writable = this.getWritable();
674
+ const { [identifier]: _, ...rest } = writable.__definitions;
675
+ writable.__definitions = rest;
676
+ }
677
+ decorate(_editor, _config) {
678
+ return createRendererDecoration("FootnoteSection", FootnoteSectionRenderer, {
679
+ definitions: this.__definitions,
680
+ nodeKey: this.__key
681
+ });
682
+ }
683
+ };
684
+ function $createFootnoteSectionNode(definitions = {}) {
685
+ return new FootnoteSectionNode(definitions);
686
+ }
687
+ function $isFootnoteSectionNode(node) {
688
+ return node instanceof FootnoteSectionNode;
689
+ }
690
+ //#endregion
691
+ //#region src/components/renderers/GridStaticDecorator.tsx
692
+ function GridStaticDecorator({ cols, gap, cellStates }) {
693
+ const renderContent = useNestedContentRenderer();
694
+ return /* @__PURE__ */ jsx("div", {
695
+ className: clsx(gridClassNames.inner, gridStyles.inner),
696
+ style: {
697
+ display: "grid",
698
+ gridTemplateColumns: `repeat(${cols}, 1fr)`,
699
+ gap
700
+ },
701
+ children: cellStates.map((state, i) => /* @__PURE__ */ jsx("div", {
702
+ className: clsx(gridClassNames.cell, gridStyles.cell),
703
+ children: renderContent(state)
704
+ }, i))
705
+ });
706
+ }
707
+ //#endregion
708
+ //#region src/nodes/GridContainerNode.ts
709
+ var GridContainerNode = class GridContainerNode extends DecoratorNode {
710
+ static getType() {
711
+ return "grid-container";
712
+ }
713
+ static clone(node) {
714
+ return new GridContainerNode(node.__cols, node.__gap, [...node.__cellStates], node.__key);
715
+ }
716
+ constructor(cols = 2, gap, cellStates, key) {
717
+ super(key);
718
+ _defineProperty(this, "__cols", void 0);
719
+ _defineProperty(this, "__gap", void 0);
720
+ _defineProperty(this, "__cellStates", void 0);
721
+ this.__cols = cols;
722
+ this.__gap = gap || "16px";
723
+ if (cellStates) this.__cellStates = cellStates;
724
+ else {
725
+ const emptyState = { root: {
726
+ children: [{
727
+ type: "paragraph",
728
+ children: [],
729
+ direction: null,
730
+ format: "",
731
+ indent: 0,
732
+ textFormat: 0,
733
+ textStyle: "",
734
+ version: 1
735
+ }],
736
+ direction: null,
737
+ format: "",
738
+ indent: 0,
739
+ type: "root",
740
+ version: 1
741
+ } };
742
+ this.__cellStates = Array.from({ length: cols }, () => emptyState);
743
+ }
744
+ }
745
+ createDOM(_config) {
746
+ const div = document.createElement("div");
747
+ div.className = `${gridClassNames.container} ${gridStyles.container}`;
748
+ return div;
749
+ }
750
+ updateDOM() {
751
+ return false;
752
+ }
753
+ isInline() {
754
+ return false;
755
+ }
756
+ getCols() {
757
+ return this.getLatest().__cols;
758
+ }
759
+ setCols(cols) {
760
+ const writable = this.getWritable();
761
+ const prev = writable.__cellStates.length;
762
+ writable.__cols = cols;
763
+ if (cols > prev) {
764
+ const emptyState = { root: {
765
+ children: [{
766
+ type: "paragraph",
767
+ children: [],
768
+ direction: null,
769
+ format: "",
770
+ indent: 0,
771
+ textFormat: 0,
772
+ textStyle: "",
773
+ version: 1
774
+ }],
775
+ direction: null,
776
+ format: "",
777
+ indent: 0,
778
+ type: "root",
779
+ version: 1
780
+ } };
781
+ for (let i = prev; i < cols; i++) writable.__cellStates.push(emptyState);
782
+ }
783
+ }
784
+ getGap() {
785
+ return this.getLatest().__gap;
786
+ }
787
+ setGap(gap) {
788
+ const writable = this.getWritable();
789
+ writable.__gap = gap;
790
+ }
791
+ getCellStates() {
792
+ return this.getLatest().__cellStates;
793
+ }
794
+ addCells(count) {
795
+ const writable = this.getWritable();
796
+ const emptyState = { root: {
797
+ children: [{
798
+ type: "paragraph",
799
+ children: [],
800
+ direction: null,
801
+ format: "",
802
+ indent: 0,
803
+ textFormat: 0,
804
+ textStyle: "",
805
+ version: 1
806
+ }],
807
+ direction: null,
808
+ format: "",
809
+ indent: 0,
810
+ type: "root",
811
+ version: 1
812
+ } };
813
+ for (let i = 0; i < count; i++) writable.__cellStates.push(emptyState);
814
+ }
815
+ removeCells(count) {
816
+ const states = this.getWritable().__cellStates;
817
+ const toRemove = Math.min(count, states.length);
818
+ for (let i = 0; i < toRemove; i++) {
819
+ const state = states.at(-1);
820
+ if (!state) break;
821
+ if (!(extractTextContent(state).trim() === "")) break;
822
+ states.pop();
823
+ }
824
+ }
825
+ getTextContent() {
826
+ return this.__cellStates.map((s) => extractTextContent(s)).join("\n");
827
+ }
828
+ static importJSON(serializedNode) {
829
+ const legacy = serializedNode;
830
+ const cols = legacy.cols || 2;
831
+ const rawGap = legacy.gap;
832
+ const gap = typeof rawGap === "number" ? `${rawGap}px` : rawGap;
833
+ if (legacy.cells && legacy.cells.length > 0) return new GridContainerNode(cols, gap, legacy.cells);
834
+ if (legacy.children) return new GridContainerNode(cols, gap, legacy.children.map((child) => {
835
+ return { root: {
836
+ children: [child],
837
+ direction: null,
838
+ format: "",
839
+ indent: 0,
840
+ type: "root",
841
+ version: 1
842
+ } };
843
+ }));
844
+ return new GridContainerNode(cols, gap);
845
+ }
846
+ exportJSON() {
847
+ return {
848
+ ...super.exportJSON(),
849
+ type: "grid-container",
850
+ cols: this.__cols,
851
+ gap: this.__gap,
852
+ cells: this.__cellStates,
853
+ version: 1
854
+ };
855
+ }
856
+ decorate(_editor, _config) {
857
+ return createElement(GridStaticDecorator, {
858
+ cols: this.__cols,
859
+ gap: this.__gap,
860
+ cellStates: this.__cellStates
861
+ });
862
+ }
863
+ };
864
+ function $createGridContainerNode(cols = 2, gap) {
865
+ return new GridContainerNode(cols, gap);
866
+ }
867
+ function $isGridContainerNode(node) {
868
+ return node instanceof GridContainerNode;
869
+ }
870
+ //#endregion
871
+ //#region src/nodes/LinkCardNode.ts
872
+ var LinkCardNode = class LinkCardNode extends DecoratorNode {
873
+ static getType() {
874
+ return "link-card";
875
+ }
876
+ static clone(node) {
877
+ return new LinkCardNode({
878
+ url: node.__url,
879
+ source: node.__source,
880
+ id: node.__id,
881
+ title: node.__title,
882
+ description: node.__description,
883
+ favicon: node.__favicon,
884
+ image: node.__image
885
+ }, node.__key);
886
+ }
887
+ constructor(payload, key) {
888
+ super(key);
889
+ _defineProperty(this, "__url", void 0);
890
+ _defineProperty(this, "__source", void 0);
891
+ _defineProperty(this, "__id", void 0);
892
+ _defineProperty(this, "__title", void 0);
893
+ _defineProperty(this, "__description", void 0);
894
+ _defineProperty(this, "__favicon", void 0);
895
+ _defineProperty(this, "__image", void 0);
896
+ this.__url = payload.url;
897
+ this.__source = payload.source;
898
+ this.__id = payload.id;
899
+ this.__title = payload.title;
900
+ this.__description = payload.description;
901
+ this.__favicon = payload.favicon;
902
+ this.__image = payload.image;
903
+ }
904
+ createDOM(_config) {
905
+ const div = document.createElement("div");
906
+ div.className = "rich-link-card-wrapper";
907
+ return div;
908
+ }
909
+ updateDOM() {
910
+ return false;
911
+ }
912
+ isInline() {
913
+ return false;
914
+ }
915
+ static importJSON(serializedNode) {
916
+ return $createLinkCardNode({
917
+ url: serializedNode.url,
918
+ source: serializedNode.source,
919
+ id: serializedNode.id,
920
+ title: serializedNode.title,
921
+ description: serializedNode.description,
922
+ favicon: serializedNode.favicon,
923
+ image: serializedNode.image
924
+ });
925
+ }
926
+ exportJSON() {
927
+ return {
928
+ ...super.exportJSON(),
929
+ type: "link-card",
930
+ url: this.__url,
931
+ source: this.__source,
932
+ id: this.__id,
933
+ title: this.__title,
934
+ description: this.__description,
935
+ favicon: this.__favicon,
936
+ image: this.__image,
937
+ version: 1
938
+ };
939
+ }
940
+ getUrl() {
941
+ return this.getLatest().__url;
942
+ }
943
+ setUrl(url) {
944
+ const writable = this.getWritable();
945
+ writable.__url = url;
946
+ }
947
+ getSource() {
948
+ return this.getLatest().__source;
949
+ }
950
+ setSource(source) {
951
+ const writable = this.getWritable();
952
+ writable.__source = source;
953
+ }
954
+ getId() {
955
+ return this.getLatest().__id;
956
+ }
957
+ setId(id) {
958
+ const writable = this.getWritable();
959
+ writable.__id = id;
960
+ }
961
+ decorate(_editor, _config) {
962
+ return createRendererDecoration("LinkCard", LinkCardRenderer, {
963
+ url: this.__url,
964
+ source: this.__source,
965
+ id: this.__id,
966
+ title: this.__title,
967
+ description: this.__description,
968
+ favicon: this.__favicon,
969
+ image: this.__image
970
+ });
971
+ }
972
+ };
973
+ _defineProperty(LinkCardNode, "commandItems", [{
974
+ title: "Link Card",
975
+ icon: createElement(Link, { size: 20 }),
976
+ description: "Link preview card",
977
+ keywords: [
978
+ "link",
979
+ "card",
980
+ "bookmark",
981
+ "embed"
982
+ ],
983
+ section: "MEDIA",
984
+ placement: ["slash", "toolbar"],
985
+ group: "insert",
986
+ onSelect: (editor) => {
987
+ editor.update(() => {
988
+ $insertNodes([$createLinkCardNode({ url: "" })]);
989
+ });
990
+ }
991
+ }]);
992
+ function $createLinkCardNode(payload) {
993
+ return new LinkCardNode(payload);
994
+ }
995
+ function $isLinkCardNode(node) {
996
+ return node instanceof LinkCardNode;
997
+ }
998
+ //#endregion
999
+ //#region src/nodes/RubyNode.ts
1000
+ function readBaseTextFromRuby(element) {
1001
+ let base = "";
1002
+ for (const child of Array.from(element.childNodes)) {
1003
+ if (child.nodeType === Node.TEXT_NODE) {
1004
+ base += child.textContent ?? "";
1005
+ continue;
1006
+ }
1007
+ if (child.nodeType !== Node.ELEMENT_NODE) continue;
1008
+ const childElement = child;
1009
+ const tag = childElement.tagName.toLowerCase();
1010
+ if (tag === "rt" || tag === "rp") continue;
1011
+ base += childElement.textContent ?? "";
1012
+ }
1013
+ return base;
1014
+ }
1015
+ var RubyNode = class RubyNode extends ElementNode {
1016
+ static getType() {
1017
+ return "ruby";
1018
+ }
1019
+ static clone(node) {
1020
+ return new RubyNode(node.__reading, node.__key);
1021
+ }
1022
+ constructor(reading, key) {
1023
+ super(key);
1024
+ _defineProperty(this, "__reading", void 0);
1025
+ this.__reading = reading;
1026
+ }
1027
+ static importJSON(serializedNode) {
1028
+ return $createRubyNode(serializedNode.reading ?? "");
1029
+ }
1030
+ exportJSON() {
1031
+ return {
1032
+ ...super.exportJSON(),
1033
+ type: "ruby",
1034
+ reading: this.__reading,
1035
+ version: 1
1036
+ };
1037
+ }
1038
+ static importDOM() {
1039
+ return { ruby: () => ({
1040
+ conversion: (domNode) => {
1041
+ if (!(domNode instanceof HTMLElement)) return null;
1042
+ const reading = domNode.querySelector("rt")?.textContent ?? "";
1043
+ const baseText = readBaseTextFromRuby(domNode);
1044
+ const node = $createRubyNode(reading);
1045
+ if (baseText) node.append($createTextNode(baseText));
1046
+ return { node };
1047
+ },
1048
+ priority: 2
1049
+ }) };
1050
+ }
1051
+ exportDOM() {
1052
+ const ruby = document.createElement("ruby");
1053
+ ruby.className = `${semanticClassNames.ruby} ${sharedStyles.ruby}`;
1054
+ const baseText = this.getTextContent();
1055
+ if (baseText) ruby.append(baseText);
1056
+ if (this.__reading) {
1057
+ const rt = document.createElement("rt");
1058
+ rt.className = `${semanticClassNames.rubyRt} ${sharedStyles.rubyRt}`;
1059
+ rt.textContent = this.__reading;
1060
+ ruby.append(rt);
1061
+ }
1062
+ return { element: ruby };
1063
+ }
1064
+ createDOM(_config) {
1065
+ const span = document.createElement("span");
1066
+ span.className = `${semanticClassNames.ruby} ${sharedStyles.ruby}`;
1067
+ if (this.__reading) span.dataset.ruby = this.__reading;
1068
+ return span;
1069
+ }
1070
+ updateDOM(prevNode, dom) {
1071
+ if (prevNode.__reading !== this.__reading) if (this.__reading) dom.dataset.ruby = this.__reading;
1072
+ else delete dom.dataset.ruby;
1073
+ return false;
1074
+ }
1075
+ canInsertTextBefore() {
1076
+ return true;
1077
+ }
1078
+ canInsertTextAfter() {
1079
+ return true;
1080
+ }
1081
+ isInline() {
1082
+ return true;
1083
+ }
1084
+ getReading() {
1085
+ return this.getLatest().__reading;
1086
+ }
1087
+ setReading(reading) {
1088
+ const writable = this.getWritable();
1089
+ writable.__reading = reading;
1090
+ }
1091
+ };
1092
+ function $createRubyNode(reading) {
1093
+ return new RubyNode(reading);
1094
+ }
1095
+ function $isRubyNode(node) {
1096
+ return node instanceof RubyNode;
1097
+ }
1098
+ //#endregion
1099
+ //#region src/components/renderers/VideoRenderer.tsx
1100
+ function VideoRenderer({ src, poster, width, height }) {
1101
+ return /* @__PURE__ */ jsx("figure", {
1102
+ className: "rich-video",
1103
+ children: /* @__PURE__ */ jsx("video", {
1104
+ controls: true,
1105
+ height,
1106
+ poster,
1107
+ preload: "metadata",
1108
+ src,
1109
+ style: {
1110
+ maxWidth: "100%",
1111
+ height: "auto"
1112
+ },
1113
+ width
1114
+ })
1115
+ });
1116
+ }
1117
+ //#endregion
1118
+ //#region src/nodes/VideoNode.ts
1119
+ var VideoNode = class VideoNode extends DecoratorNode {
1120
+ static getType() {
1121
+ return "video";
1122
+ }
1123
+ static clone(node) {
1124
+ return new VideoNode({
1125
+ src: node.__src,
1126
+ poster: node.__poster,
1127
+ width: node.__width,
1128
+ height: node.__height
1129
+ }, node.__key);
1130
+ }
1131
+ constructor(payload, key) {
1132
+ super(key);
1133
+ _defineProperty(this, "__src", void 0);
1134
+ _defineProperty(this, "__poster", void 0);
1135
+ _defineProperty(this, "__width", void 0);
1136
+ _defineProperty(this, "__height", void 0);
1137
+ this.__src = payload.src;
1138
+ this.__poster = payload.poster;
1139
+ this.__width = payload.width;
1140
+ this.__height = payload.height;
1141
+ }
1142
+ createDOM(_config) {
1143
+ const div = document.createElement("div");
1144
+ div.className = "rich-video-wrapper";
1145
+ return div;
1146
+ }
1147
+ updateDOM() {
1148
+ return false;
1149
+ }
1150
+ isInline() {
1151
+ return false;
1152
+ }
1153
+ static importJSON(serializedNode) {
1154
+ return $createVideoNode({
1155
+ src: serializedNode.src,
1156
+ poster: serializedNode.poster,
1157
+ width: serializedNode.width,
1158
+ height: serializedNode.height
1159
+ });
1160
+ }
1161
+ exportJSON() {
1162
+ return {
1163
+ ...super.exportJSON(),
1164
+ type: "video",
1165
+ src: this.__src,
1166
+ poster: this.__poster,
1167
+ width: this.__width,
1168
+ height: this.__height,
1169
+ version: 1
1170
+ };
1171
+ }
1172
+ getSrc() {
1173
+ return this.getLatest().__src;
1174
+ }
1175
+ setSrc(src) {
1176
+ const writable = this.getWritable();
1177
+ writable.__src = src;
1178
+ }
1179
+ decorate(_editor, _config) {
1180
+ return createRendererDecoration("Video", VideoRenderer, {
1181
+ src: this.__src,
1182
+ poster: this.__poster,
1183
+ width: this.__width,
1184
+ height: this.__height
1185
+ });
1186
+ }
1187
+ };
1188
+ _defineProperty(VideoNode, "commandItems", [{
1189
+ title: "Video",
1190
+ icon: createElement(Video, { size: 20 }),
1191
+ description: "Embed a video",
1192
+ keywords: [
1193
+ "video",
1194
+ "media",
1195
+ "mp4"
1196
+ ],
1197
+ section: "MEDIA",
1198
+ placement: ["slash", "toolbar"],
1199
+ group: "insert",
1200
+ onSelect: (editor) => {
1201
+ editor.update(() => {
1202
+ $insertNodes([$createVideoNode({ src: "" })]);
1203
+ });
1204
+ }
1205
+ }]);
1206
+ function $createVideoNode(payload) {
1207
+ return new VideoNode(payload);
1208
+ }
1209
+ //#endregion
1210
+ //#region src/config.ts
1211
+ var builtinNodes = [
1212
+ HeadingNode,
1213
+ QuoteNode,
1214
+ ListNode,
1215
+ ListItemNode,
1216
+ LinkNode,
1217
+ AutoLinkNode,
1218
+ HorizontalRuleNode,
1219
+ TableNode,
1220
+ TableCellNode,
1221
+ TableRowNode,
1222
+ CodeNode
1223
+ ];
1224
+ var customNodes = [
1225
+ SpoilerNode,
1226
+ MentionNode,
1227
+ KaTeXInlineNode,
1228
+ KaTeXBlockNode,
1229
+ ImageNode,
1230
+ AlertQuoteNode,
1231
+ CodeBlockNode,
1232
+ FootnoteNode,
1233
+ FootnoteSectionNode,
1234
+ VideoNode,
1235
+ LinkCardNode,
1236
+ CommentNode,
1237
+ DetailsNode,
1238
+ GridContainerNode,
1239
+ BannerNode,
1240
+ MermaidNode,
1241
+ RubyNode,
1242
+ TagNode
1243
+ ];
1244
+ var allNodes = [...builtinNodes, ...customNodes];
1245
+ //#endregion
1246
+ export { BANNER_TYPES as A, $isCodeBlockNode as C, useColorScheme as D, ColorSchemeProvider as E, normalizeBannerType as M, BannerRenderer as N, $isBannerNode as O, CommentNode as S, CodeBlockRenderer as T, $createDetailsNode as _, $createRubyNode as a, $createCommentPlaceholderNode as b, $createLinkCardNode as c, $createGridContainerNode as d, $isGridContainerNode as f, FootnoteSectionNode as g, $isFootnoteSectionNode as h, VideoNode as i, BannerNode as j, BANNER_LABELS as k, $isLinkCardNode as l, $createFootnoteSectionNode as m, builtinNodes as n, $isRubyNode as o, GridContainerNode as p, customNodes as r, RubyNode as s, allNodes as t, LinkCardNode as u, DetailsNode as v, CodeBlockNode as w, $isCommentNode as x, $createCommentNode as y };