@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,1040 +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 { DecoratorNode, createCommand, $insertNodes, $getSelection, $isRangeSelection, $getNodeByKey, ElementNode, TextNode } from "lexical";
5
- import { createContext, use, createElement, useState, useCallback, useEffect, useMemo } from "react";
6
- import { jsxs, jsx, Fragment } from "react/jsx-runtime";
7
- import { a as RendererWrapper, c as createRendererDecoration, h as FootnoteStaticRenderer, j as decodeThumbHash, K as KaTeXRenderer } from "./KaTeXRenderer-C8jv_5xr.js";
8
- import { OctagonAlert, TriangleAlert, MessageSquareWarning, Lightbulb, Info, ImageIcon, Sigma, Workflow, Tag } from "lucide-react";
9
- const NestedContentRendererContext = createContext(
10
- null
11
- );
12
- const NestedContentRendererProvider = NestedContentRendererContext.Provider;
13
- function useOptionalNestedContentRenderer() {
14
- return use(NestedContentRendererContext);
15
- }
16
- function useNestedContentRenderer() {
17
- const fn = use(NestedContentRendererContext);
18
- if (!fn) {
19
- throw new Error(
20
- "useNestedContentRenderer must be used within a NestedContentRendererProvider"
21
- );
22
- }
23
- return fn;
24
- }
25
- const InfoIcon = () => /* @__PURE__ */ jsx(Info, { size: 16 });
26
- const LightbulbIcon = () => /* @__PURE__ */ jsx(Lightbulb, { size: 16 });
27
- const MessageWarningIcon = () => /* @__PURE__ */ jsx(MessageSquareWarning, { size: 16 });
28
- const TriangleAlertIcon = () => /* @__PURE__ */ jsx(TriangleAlert, { size: 16 });
29
- const OctagonAlertIcon = () => /* @__PURE__ */ jsx(OctagonAlert, { size: 16 });
30
- const ALERT_ICONS = {
31
- note: InfoIcon,
32
- tip: LightbulbIcon,
33
- important: MessageWarningIcon,
34
- warning: TriangleAlertIcon,
35
- caution: OctagonAlertIcon
36
- };
37
- const AlertRenderer = ({ type }) => {
38
- const Icon = ALERT_ICONS[type];
39
- return /* @__PURE__ */ jsxs("div", { className: `rich-alert-header rich-alert-header-${type}`, children: [
40
- /* @__PURE__ */ jsx("span", { className: "rich-alert-icon", children: /* @__PURE__ */ jsx(Icon, {}) }),
41
- /* @__PURE__ */ jsx("span", { className: "rich-alert-label", children: ALERT_LABELS[type] })
42
- ] });
43
- };
44
- function AlertStaticDecorator({ alertType, contentState }) {
45
- const renderContent = useNestedContentRenderer();
46
- return /* @__PURE__ */ jsxs(Fragment, { children: [
47
- /* @__PURE__ */ jsx(
48
- RendererWrapper,
49
- {
50
- defaultRenderer: AlertRenderer,
51
- props: { type: alertType },
52
- rendererKey: "Alert"
53
- }
54
- ),
55
- /* @__PURE__ */ jsx("div", { className: "rich-alert-content", children: renderContent(contentState) })
56
- ] });
57
- }
58
- function extractTextContent(state) {
59
- function walk(node) {
60
- if (node.text) return node.text;
61
- if (node.children) return node.children.map(walk).join("");
62
- if (node.root) return walk(node.root);
63
- return "";
64
- }
65
- return walk(state);
66
- }
67
- const ALERT_TYPES = [
68
- "note",
69
- "tip",
70
- "important",
71
- "warning",
72
- "caution"
73
- ];
74
- const ALERT_LABELS = {
75
- note: "Note",
76
- tip: "Tip",
77
- important: "Important",
78
- warning: "Warning",
79
- caution: "Caution"
80
- };
81
- class AlertQuoteNode extends DecoratorNode {
82
- constructor(alertType, contentState, key) {
83
- super(key);
84
- __publicField(this, "__alertType");
85
- __publicField(this, "__contentState");
86
- this.__alertType = alertType;
87
- this.__contentState = contentState || {
88
- root: {
89
- children: [
90
- {
91
- type: "paragraph",
92
- children: [],
93
- direction: null,
94
- format: "",
95
- indent: 0,
96
- textFormat: 0,
97
- textStyle: "",
98
- version: 1
99
- }
100
- ],
101
- direction: null,
102
- format: "",
103
- indent: 0,
104
- type: "root",
105
- version: 1
106
- }
107
- };
108
- }
109
- static getType() {
110
- return "alert-quote";
111
- }
112
- static clone(node) {
113
- return new AlertQuoteNode(node.__alertType, node.__contentState, node.__key);
114
- }
115
- createDOM(_config) {
116
- const div = document.createElement("div");
117
- div.className = `rich-alert rich-alert-${this.__alertType}`;
118
- return div;
119
- }
120
- updateDOM(prevNode, dom) {
121
- if (prevNode.__alertType !== this.__alertType) {
122
- dom.className = `rich-alert rich-alert-${this.__alertType}`;
123
- }
124
- return false;
125
- }
126
- isInline() {
127
- return false;
128
- }
129
- getAlertType() {
130
- return this.__alertType;
131
- }
132
- setAlertType(alertType) {
133
- const writable = this.getWritable();
134
- writable.__alertType = alertType;
135
- }
136
- getContentState() {
137
- return this.getLatest().__contentState;
138
- }
139
- setContentState(state) {
140
- const writable = this.getWritable();
141
- writable.__contentState = state;
142
- }
143
- getTextContent() {
144
- return extractTextContent(this.__contentState);
145
- }
146
- static importJSON(serializedNode) {
147
- return new AlertQuoteNode(serializedNode.alertType, serializedNode.content);
148
- }
149
- exportJSON() {
150
- return {
151
- ...super.exportJSON(),
152
- type: "alert-quote",
153
- alertType: this.__alertType,
154
- content: this.__contentState,
155
- version: 1
156
- };
157
- }
158
- decorate(_editor, _config) {
159
- return createElement(AlertStaticDecorator, {
160
- alertType: this.__alertType,
161
- contentState: this.__contentState
162
- });
163
- }
164
- }
165
- function $isAlertQuoteNode(node) {
166
- return node instanceof AlertQuoteNode;
167
- }
168
- class FootnoteNode extends DecoratorNode {
169
- constructor(identifier, key) {
170
- super(key);
171
- __publicField(this, "__identifier");
172
- this.__identifier = identifier;
173
- }
174
- static getType() {
175
- return "footnote";
176
- }
177
- static clone(node) {
178
- return new FootnoteNode(node.__identifier, node.__key);
179
- }
180
- createDOM(_config) {
181
- const sup = document.createElement("sup");
182
- sup.className = "rich-footnote";
183
- return sup;
184
- }
185
- updateDOM() {
186
- return false;
187
- }
188
- isInline() {
189
- return true;
190
- }
191
- static importJSON(serializedNode) {
192
- return $createFootnoteNode(serializedNode.identifier);
193
- }
194
- exportJSON() {
195
- return {
196
- ...super.exportJSON(),
197
- type: "footnote",
198
- identifier: this.__identifier,
199
- version: 1
200
- };
201
- }
202
- getIdentifier() {
203
- return this.getLatest().__identifier;
204
- }
205
- setIdentifier(identifier) {
206
- const writable = this.getWritable();
207
- writable.__identifier = identifier;
208
- }
209
- decorate(_editor, _config) {
210
- return createRendererDecoration("Footnote", FootnoteStaticRenderer, {
211
- identifier: this.__identifier
212
- });
213
- }
214
- }
215
- function $createFootnoteNode(identifier) {
216
- return new FootnoteNode(identifier);
217
- }
218
- function ImageRenderer({
219
- src,
220
- altText,
221
- width,
222
- height,
223
- caption,
224
- thumbhash,
225
- accent
226
- }) {
227
- const [loaded, setLoaded] = useState(false);
228
- const [zoomed, setZoomed] = useState(false);
229
- const handleLoad = useCallback(() => setLoaded(true), []);
230
- const handleZoomOpen = useCallback(() => {
231
- if (!loaded) return;
232
- setZoomed(true);
233
- }, [loaded]);
234
- const handleZoomClose = useCallback(() => setZoomed(false), []);
235
- useEffect(() => {
236
- if (!zoomed) return;
237
- const onKeyDown = (e) => {
238
- if (e.key === "Escape") setZoomed(false);
239
- };
240
- document.addEventListener("keydown", onKeyDown);
241
- return () => document.removeEventListener("keydown", onKeyDown);
242
- }, [zoomed]);
243
- useEffect(() => {
244
- if (!zoomed) return;
245
- const prev = document.body.style.overflow;
246
- document.body.style.overflow = "hidden";
247
- return () => {
248
- document.body.style.overflow = prev;
249
- };
250
- }, [zoomed]);
251
- const handleContainerKeyDown = useCallback(
252
- (e) => {
253
- if ((e.key === "Enter" || e.key === " ") && loaded) {
254
- e.preventDefault();
255
- setZoomed(true);
256
- }
257
- },
258
- [loaded]
259
- );
260
- const placeholderUrl = useMemo(
261
- () => thumbhash ? decodeThumbHash(thumbhash) : void 0,
262
- [thumbhash]
263
- );
264
- const aspectStyle = width && height ? { aspectRatio: `${width} / ${height}`, maxWidth: "100%", width } : { maxWidth: "100%" };
265
- return /* @__PURE__ */ jsxs("figure", { className: "rich-image", children: [
266
- /* @__PURE__ */ jsx(
267
- "div",
268
- {
269
- "aria-label": loaded ? `Zoom image: ${altText}` : void 0,
270
- className: `rich-image-container${loaded ? " rich-image-loaded" : ""}`,
271
- role: "button",
272
- tabIndex: loaded ? 0 : -1,
273
- style: {
274
- ...aspectStyle,
275
- backgroundColor: !loaded && !placeholderUrl ? accent : void 0,
276
- backgroundImage: !loaded && placeholderUrl ? `url(${placeholderUrl})` : void 0,
277
- backgroundSize: "cover",
278
- cursor: loaded ? "zoom-in" : void 0
279
- },
280
- onClick: handleZoomOpen,
281
- onKeyDown: handleContainerKeyDown,
282
- children: /* @__PURE__ */ jsx(
283
- "img",
284
- {
285
- alt: altText,
286
- className: loaded ? "rich-image-visible" : "rich-image-hidden",
287
- height,
288
- loading: "lazy",
289
- src,
290
- style: { maxWidth: "100%", height: "auto" },
291
- width,
292
- onLoad: handleLoad
293
- }
294
- )
295
- }
296
- ),
297
- caption && /* @__PURE__ */ jsx("figcaption", { children: caption }),
298
- zoomed && /* @__PURE__ */ jsx(
299
- "div",
300
- {
301
- "aria-label": `Zoomed image: ${altText}`,
302
- "aria-modal": "true",
303
- className: "rich-image-zoom-overlay",
304
- role: "dialog",
305
- tabIndex: 0,
306
- onClick: handleZoomClose,
307
- children: /* @__PURE__ */ jsx("img", { alt: altText, className: "rich-image-zoom-img", src })
308
- }
309
- )
310
- ] });
311
- }
312
- const OPEN_IMAGE_UPLOAD_DIALOG_COMMAND = createCommand(
313
- "OPEN_IMAGE_UPLOAD_DIALOG_COMMAND"
314
- );
315
- function sanitizeImageSrc(src) {
316
- const trimmed = src.trim();
317
- if (/^(?:javascript\s*:|vbscript\s*:|data\s*:(?!image\/))/i.test(trimmed)) {
318
- return "";
319
- }
320
- return trimmed;
321
- }
322
- function sanitizeColor(value) {
323
- if (!value) return void 0;
324
- const trimmed = value.trim();
325
- if (/^#[\da-f]{3,8}$/i.test(trimmed)) return trimmed;
326
- if (/^(?:rgb|hsl)a?\([^)]+\)$/i.test(trimmed)) return trimmed;
327
- if (/^[a-z]{3,20}$/i.test(trimmed)) return trimmed;
328
- return void 0;
329
- }
330
- const _ImageNode = class _ImageNode extends DecoratorNode {
331
- constructor(payload, key) {
332
- super(key);
333
- __publicField(this, "__src");
334
- __publicField(this, "__altText");
335
- __publicField(this, "__width");
336
- __publicField(this, "__height");
337
- __publicField(this, "__caption");
338
- __publicField(this, "__thumbhash");
339
- __publicField(this, "__accent");
340
- this.__src = sanitizeImageSrc(payload.src);
341
- this.__altText = payload.altText;
342
- this.__width = payload.width;
343
- this.__height = payload.height;
344
- this.__caption = payload.caption;
345
- this.__thumbhash = payload.thumbhash;
346
- this.__accent = sanitizeColor(payload.accent);
347
- }
348
- static getType() {
349
- return "image";
350
- }
351
- static clone(node) {
352
- return new _ImageNode(
353
- {
354
- src: node.__src,
355
- altText: node.__altText,
356
- width: node.__width,
357
- height: node.__height,
358
- caption: node.__caption,
359
- thumbhash: node.__thumbhash,
360
- accent: node.__accent
361
- },
362
- node.__key
363
- );
364
- }
365
- createDOM(_config) {
366
- const div = document.createElement("div");
367
- div.className = "rich-image-wrapper";
368
- return div;
369
- }
370
- updateDOM() {
371
- return false;
372
- }
373
- isInline() {
374
- return false;
375
- }
376
- static importJSON(serializedNode) {
377
- return $createImageNode({
378
- src: serializedNode.src,
379
- altText: serializedNode.altText,
380
- width: serializedNode.width,
381
- height: serializedNode.height,
382
- caption: serializedNode.caption,
383
- thumbhash: serializedNode.thumbhash,
384
- accent: serializedNode.accent
385
- });
386
- }
387
- exportJSON() {
388
- return {
389
- ...super.exportJSON(),
390
- type: "image",
391
- src: this.__src,
392
- altText: this.__altText,
393
- width: this.__width,
394
- height: this.__height,
395
- caption: this.__caption,
396
- thumbhash: this.__thumbhash,
397
- accent: this.__accent,
398
- version: 1
399
- };
400
- }
401
- setSrc(src) {
402
- const writable = this.getWritable();
403
- writable.__src = sanitizeImageSrc(src);
404
- }
405
- setAltText(altText) {
406
- const writable = this.getWritable();
407
- writable.__altText = altText;
408
- }
409
- setCaption(caption) {
410
- const writable = this.getWritable();
411
- writable.__caption = caption;
412
- }
413
- setDimensions(width, height) {
414
- const writable = this.getWritable();
415
- writable.__width = width;
416
- writable.__height = height;
417
- }
418
- setThumbhash(thumbhash) {
419
- const writable = this.getWritable();
420
- writable.__thumbhash = thumbhash;
421
- }
422
- setAccent(accent) {
423
- const writable = this.getWritable();
424
- writable.__accent = sanitizeColor(accent);
425
- }
426
- getSrc() {
427
- return this.__src;
428
- }
429
- getAltText() {
430
- return this.__altText;
431
- }
432
- getCaption() {
433
- return this.__caption;
434
- }
435
- getWidth() {
436
- return this.__width;
437
- }
438
- getHeight() {
439
- return this.__height;
440
- }
441
- getThumbhash() {
442
- return this.__thumbhash;
443
- }
444
- getAccent() {
445
- return this.__accent;
446
- }
447
- decorate(_editor, _config) {
448
- return createRendererDecoration("Image", ImageRenderer, {
449
- src: this.__src,
450
- altText: this.__altText,
451
- width: this.__width,
452
- height: this.__height,
453
- caption: this.__caption,
454
- thumbhash: this.__thumbhash,
455
- accent: this.__accent
456
- });
457
- }
458
- };
459
- __publicField(_ImageNode, "commandItems", [
460
- {
461
- title: "Image",
462
- icon: createElement(ImageIcon, { size: 20 }),
463
- description: "Upload or embed an image",
464
- keywords: ["image", "picture", "photo"],
465
- section: "MEDIA",
466
- placement: ["slash", "toolbar"],
467
- group: "insert",
468
- onSelect: (editor) => {
469
- const opened = editor.dispatchCommand(OPEN_IMAGE_UPLOAD_DIALOG_COMMAND, void 0);
470
- if (opened) return;
471
- editor.update(() => {
472
- $insertNodes([$createImageNode({ src: "", altText: "" })]);
473
- });
474
- }
475
- }
476
- ]);
477
- let ImageNode = _ImageNode;
478
- function $createImageNode(payload) {
479
- return new ImageNode(payload);
480
- }
481
- function $isImageNode(node) {
482
- return node instanceof ImageNode;
483
- }
484
- const _KaTeXBlockNode = class _KaTeXBlockNode extends DecoratorNode {
485
- constructor(equation, key) {
486
- super(key);
487
- __publicField(this, "__equation");
488
- this.__equation = equation;
489
- }
490
- static getType() {
491
- return "katex-block";
492
- }
493
- static clone(node) {
494
- return new _KaTeXBlockNode(node.__equation, node.__key);
495
- }
496
- createDOM(_config) {
497
- const div = document.createElement("div");
498
- div.className = "rich-katex-block-wrapper";
499
- return div;
500
- }
501
- updateDOM() {
502
- return false;
503
- }
504
- isInline() {
505
- return false;
506
- }
507
- static importJSON(serializedNode) {
508
- return $createKaTeXBlockNode(serializedNode.equation);
509
- }
510
- exportJSON() {
511
- return {
512
- ...super.exportJSON(),
513
- type: "katex-block",
514
- equation: this.__equation,
515
- version: 1
516
- };
517
- }
518
- getEquation() {
519
- return this.__equation;
520
- }
521
- setEquation(equation) {
522
- const writable = this.getWritable();
523
- writable.__equation = equation;
524
- }
525
- decorate(_editor, _config) {
526
- return createRendererDecoration("KaTeX", KaTeXRenderer, {
527
- equation: this.__equation,
528
- displayMode: true
529
- });
530
- }
531
- };
532
- __publicField(_KaTeXBlockNode, "slashMenuItems", [
533
- {
534
- title: "Math Equation",
535
- icon: createElement(Sigma, { size: 20 }),
536
- description: "KaTeX block formula",
537
- keywords: ["math", "equation", "latex", "katex"],
538
- section: "ADVANCED",
539
- onSelect: (editor) => {
540
- editor.update(() => {
541
- $insertNodes([$createKaTeXBlockNode("")]);
542
- });
543
- }
544
- }
545
- ]);
546
- let KaTeXBlockNode = _KaTeXBlockNode;
547
- function $createKaTeXBlockNode(equation) {
548
- return new KaTeXBlockNode(equation);
549
- }
550
- function $isKaTeXBlockNode(node) {
551
- return node instanceof KaTeXBlockNode;
552
- }
553
- class KaTeXInlineNode extends DecoratorNode {
554
- constructor(equation, key) {
555
- super(key);
556
- __publicField(this, "__equation");
557
- this.__equation = equation;
558
- }
559
- static getType() {
560
- return "katex-inline";
561
- }
562
- static clone(node) {
563
- return new KaTeXInlineNode(node.__equation, node.__key);
564
- }
565
- createDOM(_config) {
566
- return document.createElement("span");
567
- }
568
- updateDOM() {
569
- return false;
570
- }
571
- isInline() {
572
- return true;
573
- }
574
- static importJSON(serializedNode) {
575
- return $createKaTeXInlineNode(serializedNode.equation);
576
- }
577
- exportJSON() {
578
- return {
579
- ...super.exportJSON(),
580
- type: "katex-inline",
581
- equation: this.__equation,
582
- version: 1
583
- };
584
- }
585
- getEquation() {
586
- return this.__equation;
587
- }
588
- setEquation(equation) {
589
- const writable = this.getWritable();
590
- writable.__equation = equation;
591
- }
592
- decorate(_editor, _config) {
593
- return createRendererDecoration("KaTeX", KaTeXRenderer, {
594
- equation: this.__equation,
595
- displayMode: false
596
- });
597
- }
598
- }
599
- function $createKaTeXInlineNode(equation) {
600
- return new KaTeXInlineNode(equation);
601
- }
602
- function $isKaTeXInlineNode(node) {
603
- return node instanceof KaTeXInlineNode;
604
- }
605
- function MentionRenderer({ handle, displayName }) {
606
- const normalizedHandle = handle.replace(/^@+/, "");
607
- const label = displayName || normalizedHandle;
608
- return /* @__PURE__ */ jsx("span", { className: "rich-mention rich-mention-plain", children: /* @__PURE__ */ jsxs("span", { className: "rich-mention-handle", children: [
609
- "@",
610
- label
611
- ] }) });
612
- }
613
- const _MentionNode = class _MentionNode extends DecoratorNode {
614
- constructor(platform, handle, displayName, key) {
615
- super(key);
616
- __publicField(this, "__platform");
617
- __publicField(this, "__handle");
618
- __publicField(this, "__displayName");
619
- this.__platform = platform;
620
- this.__handle = handle;
621
- this.__displayName = displayName;
622
- }
623
- static getType() {
624
- return "mention";
625
- }
626
- static clone(node) {
627
- return new _MentionNode(
628
- node.__platform,
629
- node.__handle,
630
- node.__displayName,
631
- node.__key
632
- );
633
- }
634
- createDOM(_config) {
635
- const el = document.createElement("span");
636
- el.style.display = "inline-flex";
637
- el.style.alignItems = "center";
638
- el.style.height = "1lh";
639
- return el;
640
- }
641
- updateDOM() {
642
- return false;
643
- }
644
- isInline() {
645
- return true;
646
- }
647
- getPlatform() {
648
- return this.getLatest().__platform;
649
- }
650
- getHandle() {
651
- return this.getLatest().__handle;
652
- }
653
- getDisplayName() {
654
- return this.getLatest().__displayName;
655
- }
656
- static importJSON(serializedNode) {
657
- return $createMentionNode(
658
- serializedNode.platform,
659
- serializedNode.handle,
660
- serializedNode.displayName
661
- );
662
- }
663
- exportJSON() {
664
- return {
665
- ...super.exportJSON(),
666
- type: "mention",
667
- platform: this.__platform,
668
- handle: this.__handle,
669
- ...this.__displayName ? { displayName: this.__displayName } : {},
670
- version: 1
671
- };
672
- }
673
- decorate(_editor, _config) {
674
- return createRendererDecoration("Mention", MentionRenderer, {
675
- platform: this.__platform,
676
- handle: this.__handle,
677
- displayName: this.__displayName
678
- });
679
- }
680
- };
681
- __publicField(_MentionNode, "slashMenuItems", [
682
- {
683
- title: "Mention",
684
- icon: createElement(
685
- "span",
686
- { style: { fontSize: 16, fontWeight: 700 } },
687
- "@"
688
- ),
689
- description: "Mention a social account",
690
- keywords: ["mention", "at", "@", "github", "twitter"],
691
- section: "INLINE",
692
- onSelect: (editor) => {
693
- editor.update(() => {
694
- const selection = $getSelection();
695
- if ($isRangeSelection(selection)) {
696
- selection.insertText("@");
697
- }
698
- });
699
- }
700
- }
701
- ]);
702
- let MentionNode = _MentionNode;
703
- function $createMentionNode(platform, handle, displayName) {
704
- return new MentionNode(platform, handle, displayName);
705
- }
706
- function $isMentionNode(node) {
707
- return node instanceof MentionNode;
708
- }
709
- function MermaidRenderer({ content }) {
710
- return /* @__PURE__ */ jsx("div", { className: "rich-mermaid-block", children: /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: content }) }) });
711
- }
712
- const _MermaidNode = class _MermaidNode extends DecoratorNode {
713
- constructor(diagram, key) {
714
- super(key);
715
- __publicField(this, "__diagram");
716
- this.__diagram = diagram;
717
- }
718
- static getType() {
719
- return "mermaid";
720
- }
721
- static clone(node) {
722
- return new _MermaidNode(node.__diagram, node.__key);
723
- }
724
- createDOM(_config) {
725
- const div = document.createElement("div");
726
- div.className = "rich-mermaid-wrapper";
727
- return div;
728
- }
729
- updateDOM() {
730
- return false;
731
- }
732
- isInline() {
733
- return false;
734
- }
735
- static importJSON(serializedNode) {
736
- return $createMermaidNode(serializedNode.diagram);
737
- }
738
- exportJSON() {
739
- return {
740
- ...super.exportJSON(),
741
- type: "mermaid",
742
- diagram: this.__diagram,
743
- version: 1
744
- };
745
- }
746
- getDiagram() {
747
- return this.__diagram;
748
- }
749
- setDiagram(diagram) {
750
- const writable = this.getWritable();
751
- writable.__diagram = diagram;
752
- }
753
- decorate(editor, _config) {
754
- const nodeKey = this.__key;
755
- return createRendererDecoration("Mermaid", MermaidRenderer, {
756
- content: this.__diagram,
757
- onContentChange: (newDiagram) => {
758
- editor.update(() => {
759
- const node = $getNodeByKey(nodeKey);
760
- if (node) {
761
- node.setDiagram(newDiagram);
762
- }
763
- });
764
- }
765
- });
766
- }
767
- };
768
- __publicField(_MermaidNode, "commandItems", [
769
- {
770
- title: "Mermaid Diagram",
771
- icon: createElement(Workflow, { size: 20 }),
772
- description: "Flowchart, sequence diagram",
773
- keywords: ["mermaid", "diagram", "chart", "flowchart"],
774
- section: "MEDIA",
775
- placement: ["slash", "toolbar"],
776
- group: "insert",
777
- onSelect: (editor) => {
778
- editor.update(() => {
779
- $insertNodes([
780
- $createMermaidNode("graph TD\n A[Start] --> B[End]")
781
- ]);
782
- });
783
- }
784
- }
785
- ]);
786
- let MermaidNode = _MermaidNode;
787
- function $createMermaidNode(diagram) {
788
- return new MermaidNode(diagram);
789
- }
790
- function $isMermaidNode(node) {
791
- return node instanceof MermaidNode;
792
- }
793
- class SpoilerNode extends ElementNode {
794
- static getType() {
795
- return "spoiler";
796
- }
797
- static clone(node) {
798
- return new SpoilerNode(node.__key);
799
- }
800
- constructor(key) {
801
- super(key);
802
- }
803
- createDOM(_config) {
804
- const span = document.createElement("span");
805
- span.className = "rich-spoiler";
806
- span.setAttribute("role", "button");
807
- span.setAttribute("tabindex", "0");
808
- span.setAttribute("aria-label", "Spoiler (click to reveal)");
809
- const toggle = () => {
810
- if (span.isContentEditable) return;
811
- const revealed = span.classList.toggle("rich-spoiler-revealed");
812
- span.setAttribute(
813
- "aria-label",
814
- revealed ? "Spoiler (revealed)" : "Spoiler (click to reveal)"
815
- );
816
- };
817
- span.addEventListener("click", toggle);
818
- span.addEventListener("keydown", (e) => {
819
- if (e.key === "Enter" || e.key === " ") {
820
- e.preventDefault();
821
- toggle();
822
- }
823
- });
824
- return span;
825
- }
826
- updateDOM() {
827
- return false;
828
- }
829
- static importJSON(_serializedNode) {
830
- return $createSpoilerNode();
831
- }
832
- exportJSON() {
833
- return {
834
- ...super.exportJSON(),
835
- type: "spoiler",
836
- version: 1
837
- };
838
- }
839
- canInsertTextBefore() {
840
- return true;
841
- }
842
- canInsertTextAfter() {
843
- return true;
844
- }
845
- isInline() {
846
- return true;
847
- }
848
- }
849
- function $createSpoilerNode() {
850
- return new SpoilerNode();
851
- }
852
- function stringToHue(str) {
853
- let hash = 0;
854
- for (let i = 0; i < str.length; i++) {
855
- hash = str.charCodeAt(i) + ((hash << 5) - hash);
856
- }
857
- const hue = hash % 360;
858
- return hue < 0 ? hue + 360 : hue;
859
- }
860
- function getTagBgColor(text) {
861
- const hue = stringToHue(text);
862
- const sat = 70 + hue % 21;
863
- const light = 40 + hue % 31;
864
- const bgSat = sat > 30 ? sat - 30 : 0;
865
- const bgLight = light < 80 ? light + 20 : 100;
866
- return `hsla(${hue}, ${bgSat}%, ${bgLight}%, 0.7)`;
867
- }
868
- const _TagNode = class _TagNode extends TextNode {
869
- static getType() {
870
- return "tag";
871
- }
872
- static clone(node) {
873
- return new _TagNode(node.__text, node.__key);
874
- }
875
- static importDOM() {
876
- return {
877
- span: () => ({
878
- conversion: (domNode) => {
879
- if (!(domNode instanceof HTMLElement)) return null;
880
- if (!domNode.classList.contains("rich-tag")) return null;
881
- return {
882
- node: $createTagNode(domNode.textContent ?? "")
883
- };
884
- },
885
- priority: 2
886
- })
887
- };
888
- }
889
- constructor(text, key) {
890
- super(text, key);
891
- }
892
- createDOM(config) {
893
- const element = super.createDOM(config);
894
- element.classList.add("rich-tag");
895
- element.style.backgroundColor = getTagBgColor(this.getTextContent());
896
- return element;
897
- }
898
- updateDOM(prevNode, dom, config) {
899
- const updated = super.updateDOM(prevNode, dom, config);
900
- dom.classList.add("rich-tag");
901
- if (prevNode.__text !== this.__text) {
902
- dom.style.backgroundColor = getTagBgColor(this.__text);
903
- }
904
- return updated;
905
- }
906
- exportDOM(_editor) {
907
- const element = document.createElement("span");
908
- element.className = "rich-tag";
909
- element.style.backgroundColor = getTagBgColor(this.getTextContent());
910
- element.textContent = this.getTextContent();
911
- return { element };
912
- }
913
- getText() {
914
- return this.getTextContent();
915
- }
916
- canInsertTextBefore() {
917
- return false;
918
- }
919
- canInsertTextAfter() {
920
- return false;
921
- }
922
- isTextEntity() {
923
- return true;
924
- }
925
- static importJSON(serializedNode) {
926
- const node = $createTagNode(serializedNode.text ?? "");
927
- node.setFormat(serializedNode.format ?? 0);
928
- node.setDetail(serializedNode.detail ?? 0);
929
- node.setMode(serializedNode.mode ?? "normal");
930
- node.setStyle(serializedNode.style ?? "");
931
- return node;
932
- }
933
- exportJSON() {
934
- return {
935
- ...super.exportJSON(),
936
- type: "tag",
937
- version: 1
938
- };
939
- }
940
- };
941
- __publicField(_TagNode, "commandItems", [
942
- {
943
- title: "Tag",
944
- icon: createElement(Tag, { size: 20 }),
945
- description: "Insert a tag",
946
- keywords: ["tag", "label", "badge"],
947
- section: "INLINE",
948
- placement: ["slash", "toolbar"],
949
- group: "insert",
950
- onSelect: (editor, queryString) => {
951
- editor.update(() => {
952
- $insertNodes([$createTagNode(queryString || "tag")]);
953
- });
954
- }
955
- }
956
- ]);
957
- let TagNode = _TagNode;
958
- function $createTagNode(text) {
959
- return new TagNode(text);
960
- }
961
- function $isTagNode(node) {
962
- return node instanceof TagNode;
963
- }
964
- const editorTheme = {
965
- text: {
966
- bold: "rich-text-bold",
967
- italic: "rich-text-italic",
968
- underline: "rich-text-underline",
969
- strikethrough: "rich-text-strikethrough",
970
- superscript: "rich-text-superscript",
971
- subscript: "rich-text-subscript",
972
- code: "rich-text-code",
973
- highlight: "rich-text-highlight"
974
- },
975
- heading: {
976
- h1: "rich-heading-h1",
977
- h2: "rich-heading-h2",
978
- h3: "rich-heading-h3",
979
- h4: "rich-heading-h4",
980
- h5: "rich-heading-h5",
981
- h6: "rich-heading-h6"
982
- },
983
- list: {
984
- ol: "rich-list-ol",
985
- ul: "rich-list-ul",
986
- listitem: "rich-list-item",
987
- listitemChecked: "rich-list-item-checked",
988
- listitemUnchecked: "rich-list-item-unchecked",
989
- checklist: "rich-checklist",
990
- nested: {
991
- listitem: "rich-list-nested-item"
992
- }
993
- },
994
- quote: "rich-quote",
995
- link: "rich-link",
996
- paragraph: "rich-paragraph",
997
- code: "rich-code-block",
998
- table: "rich-table",
999
- tableCell: "rich-table-cell",
1000
- tableCellHeader: "rich-table-cell-header",
1001
- tableScrollableWrapper: "rich-table-scrollable-wrapper",
1002
- /** Used by @lexical/extension HorizontalRuleNode */
1003
- hr: "rich-hr"
1004
- };
1005
- export {
1006
- $createImageNode as $,
1007
- ALERT_LABELS as A,
1008
- FootnoteNode as F,
1009
- ImageNode as I,
1010
- KaTeXBlockNode as K,
1011
- MentionNode as M,
1012
- NestedContentRendererProvider as N,
1013
- OPEN_IMAGE_UPLOAD_DIALOG_COMMAND as O,
1014
- SpoilerNode as S,
1015
- TagNode as T,
1016
- $createMentionNode as a,
1017
- $createMermaidNode as b,
1018
- $createTagNode as c,
1019
- $isImageNode as d,
1020
- $isKaTeXBlockNode as e,
1021
- $isKaTeXInlineNode as f,
1022
- $isMentionNode as g,
1023
- $isMermaidNode as h,
1024
- $isTagNode as i,
1025
- ALERT_TYPES as j,
1026
- KaTeXInlineNode as k,
1027
- MermaidNode as l,
1028
- getTagBgColor as m,
1029
- editorTheme as n,
1030
- extractTextContent as o,
1031
- useOptionalNestedContentRenderer as p,
1032
- $isAlertQuoteNode as q,
1033
- AlertRenderer as r,
1034
- AlertQuoteNode as s,
1035
- $createKaTeXInlineNode as t,
1036
- useNestedContentRenderer as u,
1037
- $createKaTeXBlockNode as v,
1038
- $createFootnoteNode as w,
1039
- $createSpoilerNode as x
1040
- };