@haklex/rich-editor 0.0.65 → 0.0.66
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.
- package/README.md +107 -300
- package/dist/AlertQuoteEditNode-AgVEMFEi.js +292 -0
- package/dist/KaTeXRenderer-C8jv_5xr.js +214 -0
- package/dist/LinkCardRenderer-QmkOlyXb.js +36 -0
- package/dist/{LinkFavicon-DpURZdO_.js → LinkFavicon-B9SOaYCR.js} +5 -24
- package/dist/MermaidPlugin-CIQbyjXF.js +97 -0
- package/dist/RubyRenderer-DbeobSoH.js +13 -0
- package/dist/SubmitShortcutPlugin-WQpet-vq.js +1512 -0
- package/dist/commands-entry.d.ts +9 -0
- package/dist/commands-entry.d.ts.map +1 -0
- package/dist/commands-entry.mjs +25 -0
- package/dist/components/ContentEditable.d.ts +2 -2
- package/dist/components/ContentEditable.d.ts.map +1 -1
- package/dist/components/CorePlugins.d.ts +2 -0
- package/dist/components/CorePlugins.d.ts.map +1 -0
- package/dist/components/LinkFavicon.d.ts.map +1 -1
- package/dist/components/RichEditor.d.ts +1 -1
- package/dist/components/RichEditor.d.ts.map +1 -1
- package/dist/components/RichEditorShell.d.ts +26 -0
- package/dist/components/RichEditorShell.d.ts.map +1 -0
- package/dist/components/decorators/AlertEditDecorator.d.ts +2 -2
- package/dist/components/decorators/AlertEditDecorator.d.ts.map +1 -1
- package/dist/components/decorators/BannerEditDecorator.d.ts +1 -1
- package/dist/components/decorators/BannerEditDecorator.d.ts.map +1 -1
- package/dist/components/decorators/CodeBlockEditDecorator.d.ts +2 -2
- package/dist/components/decorators/CodeBlockEditDecorator.d.ts.map +1 -1
- package/dist/components/decorators/GridEditDecorator.d.ts +2 -2
- package/dist/components/decorators/GridEditDecorator.d.ts.map +1 -1
- package/dist/components/renderers/AlertRenderer.d.ts +1 -1
- package/dist/components/renderers/AlertRenderer.d.ts.map +1 -1
- package/dist/components/renderers/AlertStaticDecorator.d.ts +1 -1
- package/dist/components/renderers/AlertStaticDecorator.d.ts.map +1 -1
- package/dist/components/renderers/BannerRenderer.d.ts +1 -1
- package/dist/components/renderers/BannerRenderer.d.ts.map +1 -1
- package/dist/components/renderers/BannerStaticDecorator.d.ts +1 -1
- package/dist/components/renderers/BannerStaticDecorator.d.ts.map +1 -1
- package/dist/components/renderers/CodeBlockRenderer.d.ts +5 -5
- package/dist/components/renderers/CodeBlockRenderer.d.ts.map +1 -1
- package/dist/components/renderers/FootnoteRenderer.d.ts.map +1 -1
- package/dist/components/renderers/FootnoteSectionEditRenderer.d.ts +1 -1
- package/dist/components/renderers/FootnoteSectionEditRenderer.d.ts.map +1 -1
- package/dist/components/renderers/FootnoteSectionRenderer.d.ts +1 -1
- package/dist/components/renderers/FootnoteSectionRenderer.d.ts.map +1 -1
- package/dist/components/renderers/FootnoteStaticRenderer.d.ts +1 -1
- package/dist/components/renderers/FootnoteStaticRenderer.d.ts.map +1 -1
- package/dist/components/renderers/GridStaticDecorator.d.ts +2 -2
- package/dist/components/renderers/GridStaticDecorator.d.ts.map +1 -1
- package/dist/components/renderers/ImageRenderer.d.ts +4 -4
- package/dist/components/renderers/ImageRenderer.d.ts.map +1 -1
- package/dist/components/renderers/KaTeXRenderer.d.ts +1 -1
- package/dist/components/renderers/KaTeXRenderer.d.ts.map +1 -1
- package/dist/components/renderers/LinkCardRenderer.d.ts +4 -4
- package/dist/components/renderers/LinkCardRenderer.d.ts.map +1 -1
- package/dist/components/renderers/MentionRenderer.d.ts +2 -2
- package/dist/components/renderers/MentionRenderer.d.ts.map +1 -1
- package/dist/components/renderers/RubyRenderer.d.ts +1 -1
- package/dist/components/renderers/RubyRenderer.d.ts.map +1 -1
- package/dist/components/renderers/VideoRenderer.d.ts +3 -3
- package/dist/components/renderers/VideoRenderer.d.ts.map +1 -1
- package/dist/config-QGdXDSW9.js +1235 -0
- package/dist/context/ImageUploadContext.d.ts.map +1 -1
- package/dist/context/RendererConfigContext.d.ts +1 -1
- package/dist/context/RendererConfigContext.d.ts.map +1 -1
- package/dist/favicon-BQgbXF_a.js +43 -0
- package/dist/index.d.ts +10 -80
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +151 -161
- package/dist/node-registry-CSRSWJ0q.js +765 -0
- package/dist/nodes/CodeBlockEditNode.d.ts +6 -6
- package/dist/nodes/DetailsNode.d.ts.map +1 -1
- package/dist/nodes/GridContainerNode.d.ts.map +1 -1
- package/dist/nodes/GridEditNode.d.ts.map +1 -1
- package/dist/nodes/ImageNode.d.ts +4 -4
- package/dist/nodes/ImageNode.d.ts.map +1 -1
- package/dist/nodes/LinkCardNode.d.ts +4 -4
- package/dist/nodes/LinkCardNode.d.ts.map +1 -1
- package/dist/nodes/VideoNode.d.ts +2 -2
- package/dist/nodes/VideoNode.d.ts.map +1 -1
- package/dist/nodes-entry.d.ts +28 -0
- package/dist/nodes-entry.d.ts.map +1 -0
- package/dist/nodes-entry.mjs +44 -0
- package/dist/plugins/AutoLinkPlugin.d.ts.map +1 -1
- package/dist/plugins/ImageUploadPlugin.d.ts +2 -2
- package/dist/plugins/ImageUploadPlugin.d.ts.map +1 -1
- package/dist/plugins/MarkdownPastePlugin.d.ts.map +1 -1
- package/dist/plugins/OnChangePlugin.d.ts +1 -1
- package/dist/plugins/OnChangePlugin.d.ts.map +1 -1
- package/dist/plugins/image-upload-command.d.ts.map +1 -1
- package/dist/plugins/image-upload.css.d.ts +1 -4
- package/dist/plugins/image-upload.css.d.ts.map +1 -1
- package/dist/plugins-entry.d.ts +22 -0
- package/dist/plugins-entry.d.ts.map +1 -0
- package/dist/plugins-entry.mjs +27 -0
- package/dist/renderers-entry.d.ts +23 -0
- package/dist/renderers-entry.d.ts.map +1 -0
- package/dist/renderers-entry.mjs +60 -0
- package/dist/rich-editor.css +1 -1
- package/dist/{utils-fpeaZV1R.js → shared.css-DNuMYx6Q.js} +4 -1
- package/dist/static-entry.mjs +23 -21
- package/dist/styles/article.css.d.ts.map +1 -1
- package/dist/styles-entry.mjs +1 -2
- package/dist/theme-CRza9nbF.js +924 -0
- package/dist/transformers/code-block.d.ts.map +1 -1
- package/dist/types/renderer-config.d.ts +6 -6
- package/dist/types/renderer-config.d.ts.map +1 -1
- package/dist/types/slash-menu.d.ts +6 -6
- package/dist/types/slash-menu.d.ts.map +1 -1
- package/dist/types.d.ts +18 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/comment-anchor.d.ts +8 -8
- package/dist/utils/comment-anchor.d.ts.map +1 -1
- package/package.json +50 -33
- package/dist/RichEditor-EI3rR1-9.js +0 -2789
- package/dist/components/decorators/nested-doc-dialog.css.d.ts +0 -28
- package/dist/components/decorators/nested-doc-dialog.css.d.ts.map +0 -1
- package/dist/editor.d.ts +0 -6
- package/dist/editor.d.ts.map +0 -1
- package/dist/editor.mjs +0 -12
- package/dist/favicon-C6Esc0tp.js +0 -2470
- package/dist/shared.css-BqX4HjVE.js +0 -5
package/dist/favicon-C6Esc0tp.js
DELETED
|
@@ -1,2470 +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 { CodeNode } from "@lexical/code";
|
|
5
|
-
import { HorizontalRuleNode } from "@lexical/extension";
|
|
6
|
-
import { LinkNode, AutoLinkNode } from "@lexical/link";
|
|
7
|
-
import { ListNode, ListItemNode } from "@lexical/list";
|
|
8
|
-
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
|
|
9
|
-
import { TableNode, TableCellNode, TableRowNode } from "@lexical/table";
|
|
10
|
-
import { DecoratorNode, $insertNodes, ElementNode, createCommand, $getSelection, $isRangeSelection, $getNodeByKey, $createTextNode } from "lexical";
|
|
11
|
-
import { createContext, use, useMemo, createElement, useState, useRef, useEffect, useCallback } from "react";
|
|
12
|
-
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
13
|
-
import { OctagonAlert, TriangleAlert, MessageSquareWarning, Lightbulb, Info, Code, ChevronRight, ImageIcon, Sigma, Link, Workflow, Video } from "lucide-react";
|
|
14
|
-
import { thumbHashToDataURL, rgbaToThumbHash } from "thumbhash";
|
|
15
|
-
const NestedContentRendererContext = createContext(
|
|
16
|
-
null
|
|
17
|
-
);
|
|
18
|
-
const NestedContentRendererProvider = NestedContentRendererContext.Provider;
|
|
19
|
-
function useOptionalNestedContentRenderer() {
|
|
20
|
-
return use(NestedContentRendererContext);
|
|
21
|
-
}
|
|
22
|
-
function useNestedContentRenderer() {
|
|
23
|
-
const fn = use(NestedContentRendererContext);
|
|
24
|
-
if (!fn) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
"useNestedContentRenderer must be used within a NestedContentRendererProvider"
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
return fn;
|
|
30
|
-
}
|
|
31
|
-
const RendererConfigContext = createContext({
|
|
32
|
-
config: void 0,
|
|
33
|
-
mode: "renderer",
|
|
34
|
-
variant: "article"
|
|
35
|
-
});
|
|
36
|
-
function RendererConfigProvider({
|
|
37
|
-
config,
|
|
38
|
-
mode,
|
|
39
|
-
variant,
|
|
40
|
-
children
|
|
41
|
-
}) {
|
|
42
|
-
const value = useMemo(
|
|
43
|
-
() => ({ config, mode, variant }),
|
|
44
|
-
[config, mode, variant]
|
|
45
|
-
);
|
|
46
|
-
return /* @__PURE__ */ jsx(RendererConfigContext.Provider, { value, children });
|
|
47
|
-
}
|
|
48
|
-
function useRendererConfig() {
|
|
49
|
-
return use(RendererConfigContext).config;
|
|
50
|
-
}
|
|
51
|
-
function useRendererMode() {
|
|
52
|
-
return use(RendererConfigContext).mode;
|
|
53
|
-
}
|
|
54
|
-
function useVariant() {
|
|
55
|
-
return use(RendererConfigContext).variant;
|
|
56
|
-
}
|
|
57
|
-
function RendererWrapper({
|
|
58
|
-
rendererKey,
|
|
59
|
-
defaultRenderer: DefaultRenderer,
|
|
60
|
-
props
|
|
61
|
-
}) {
|
|
62
|
-
const config = useRendererConfig();
|
|
63
|
-
const Renderer = config?.[rendererKey] ?? DefaultRenderer;
|
|
64
|
-
return /* @__PURE__ */ jsx(Renderer, { ...props });
|
|
65
|
-
}
|
|
66
|
-
function createRendererDecoration(rendererKey, defaultRenderer, props) {
|
|
67
|
-
return createElement(RendererWrapper, {
|
|
68
|
-
rendererKey,
|
|
69
|
-
defaultRenderer,
|
|
70
|
-
props
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
const InfoIcon = () => /* @__PURE__ */ jsx(Info, { size: 16 });
|
|
74
|
-
const LightbulbIcon = () => /* @__PURE__ */ jsx(Lightbulb, { size: 16 });
|
|
75
|
-
const MessageWarningIcon = () => /* @__PURE__ */ jsx(MessageSquareWarning, { size: 16 });
|
|
76
|
-
const TriangleAlertIcon = () => /* @__PURE__ */ jsx(TriangleAlert, { size: 16 });
|
|
77
|
-
const OctagonAlertIcon = () => /* @__PURE__ */ jsx(OctagonAlert, { size: 16 });
|
|
78
|
-
const ALERT_ICONS = {
|
|
79
|
-
note: InfoIcon,
|
|
80
|
-
tip: LightbulbIcon,
|
|
81
|
-
important: MessageWarningIcon,
|
|
82
|
-
warning: TriangleAlertIcon,
|
|
83
|
-
caution: OctagonAlertIcon
|
|
84
|
-
};
|
|
85
|
-
const AlertRenderer = ({ type }) => {
|
|
86
|
-
const Icon = ALERT_ICONS[type];
|
|
87
|
-
return /* @__PURE__ */ jsxs("div", { className: `rich-alert-header rich-alert-header-${type}`, children: [
|
|
88
|
-
/* @__PURE__ */ jsx("span", { className: "rich-alert-icon", children: /* @__PURE__ */ jsx(Icon, {}) }),
|
|
89
|
-
/* @__PURE__ */ jsx("span", { className: "rich-alert-label", children: ALERT_LABELS[type] })
|
|
90
|
-
] });
|
|
91
|
-
};
|
|
92
|
-
function AlertStaticDecorator({
|
|
93
|
-
alertType,
|
|
94
|
-
contentState
|
|
95
|
-
}) {
|
|
96
|
-
const renderContent = useNestedContentRenderer();
|
|
97
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
98
|
-
/* @__PURE__ */ jsx(
|
|
99
|
-
RendererWrapper,
|
|
100
|
-
{
|
|
101
|
-
rendererKey: "Alert",
|
|
102
|
-
defaultRenderer: AlertRenderer,
|
|
103
|
-
props: { type: alertType }
|
|
104
|
-
}
|
|
105
|
-
),
|
|
106
|
-
/* @__PURE__ */ jsx("div", { className: "rich-alert-content", children: renderContent(contentState) })
|
|
107
|
-
] });
|
|
108
|
-
}
|
|
109
|
-
function extractTextContent(state) {
|
|
110
|
-
function walk(node) {
|
|
111
|
-
if (node.text) return node.text;
|
|
112
|
-
if (node.children) return node.children.map(walk).join("");
|
|
113
|
-
if (node.root) return walk(node.root);
|
|
114
|
-
return "";
|
|
115
|
-
}
|
|
116
|
-
return walk(state);
|
|
117
|
-
}
|
|
118
|
-
const ALERT_TYPES = [
|
|
119
|
-
"note",
|
|
120
|
-
"tip",
|
|
121
|
-
"important",
|
|
122
|
-
"warning",
|
|
123
|
-
"caution"
|
|
124
|
-
];
|
|
125
|
-
const ALERT_LABELS = {
|
|
126
|
-
note: "Note",
|
|
127
|
-
tip: "Tip",
|
|
128
|
-
important: "Important",
|
|
129
|
-
warning: "Warning",
|
|
130
|
-
caution: "Caution"
|
|
131
|
-
};
|
|
132
|
-
class AlertQuoteNode extends DecoratorNode {
|
|
133
|
-
constructor(alertType, contentState, key) {
|
|
134
|
-
super(key);
|
|
135
|
-
__publicField(this, "__alertType");
|
|
136
|
-
__publicField(this, "__contentState");
|
|
137
|
-
this.__alertType = alertType;
|
|
138
|
-
this.__contentState = contentState || {
|
|
139
|
-
root: {
|
|
140
|
-
children: [
|
|
141
|
-
{
|
|
142
|
-
type: "paragraph",
|
|
143
|
-
children: [],
|
|
144
|
-
direction: null,
|
|
145
|
-
format: "",
|
|
146
|
-
indent: 0,
|
|
147
|
-
textFormat: 0,
|
|
148
|
-
textStyle: "",
|
|
149
|
-
version: 1
|
|
150
|
-
}
|
|
151
|
-
],
|
|
152
|
-
direction: null,
|
|
153
|
-
format: "",
|
|
154
|
-
indent: 0,
|
|
155
|
-
type: "root",
|
|
156
|
-
version: 1
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
static getType() {
|
|
161
|
-
return "alert-quote";
|
|
162
|
-
}
|
|
163
|
-
static clone(node) {
|
|
164
|
-
return new AlertQuoteNode(node.__alertType, node.__contentState, node.__key);
|
|
165
|
-
}
|
|
166
|
-
createDOM(_config) {
|
|
167
|
-
const div = document.createElement("div");
|
|
168
|
-
div.className = `rich-alert rich-alert-${this.__alertType}`;
|
|
169
|
-
return div;
|
|
170
|
-
}
|
|
171
|
-
updateDOM(prevNode, dom) {
|
|
172
|
-
if (prevNode.__alertType !== this.__alertType) {
|
|
173
|
-
dom.className = `rich-alert rich-alert-${this.__alertType}`;
|
|
174
|
-
}
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
isInline() {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
getAlertType() {
|
|
181
|
-
return this.__alertType;
|
|
182
|
-
}
|
|
183
|
-
setAlertType(alertType) {
|
|
184
|
-
const writable = this.getWritable();
|
|
185
|
-
writable.__alertType = alertType;
|
|
186
|
-
}
|
|
187
|
-
getContentState() {
|
|
188
|
-
return this.getLatest().__contentState;
|
|
189
|
-
}
|
|
190
|
-
setContentState(state) {
|
|
191
|
-
const writable = this.getWritable();
|
|
192
|
-
writable.__contentState = state;
|
|
193
|
-
}
|
|
194
|
-
getTextContent() {
|
|
195
|
-
return extractTextContent(this.__contentState);
|
|
196
|
-
}
|
|
197
|
-
static importJSON(serializedNode) {
|
|
198
|
-
return new AlertQuoteNode(serializedNode.alertType, serializedNode.content);
|
|
199
|
-
}
|
|
200
|
-
exportJSON() {
|
|
201
|
-
return {
|
|
202
|
-
...super.exportJSON(),
|
|
203
|
-
type: "alert-quote",
|
|
204
|
-
alertType: this.__alertType,
|
|
205
|
-
content: this.__contentState,
|
|
206
|
-
version: 1
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
decorate(_editor, _config) {
|
|
210
|
-
return createElement(AlertStaticDecorator, {
|
|
211
|
-
alertType: this.__alertType,
|
|
212
|
-
contentState: this.__contentState
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function $isAlertQuoteNode(node) {
|
|
217
|
-
return node instanceof AlertQuoteNode;
|
|
218
|
-
}
|
|
219
|
-
const BannerRenderer = ({ type }) => {
|
|
220
|
-
return /* @__PURE__ */ jsx("span", { className: `rich-banner-icon rich-banner-icon-${type}` });
|
|
221
|
-
};
|
|
222
|
-
function BannerStaticDecorator({
|
|
223
|
-
bannerType,
|
|
224
|
-
contentState
|
|
225
|
-
}) {
|
|
226
|
-
const renderContent = useNestedContentRenderer();
|
|
227
|
-
return /* @__PURE__ */ jsxs("div", { className: "rich-banner-inner", children: [
|
|
228
|
-
/* @__PURE__ */ jsx(
|
|
229
|
-
RendererWrapper,
|
|
230
|
-
{
|
|
231
|
-
rendererKey: "Banner",
|
|
232
|
-
defaultRenderer: BannerRenderer,
|
|
233
|
-
props: { type: bannerType }
|
|
234
|
-
}
|
|
235
|
-
),
|
|
236
|
-
/* @__PURE__ */ jsx("div", { className: "rich-banner-content", children: renderContent(contentState) })
|
|
237
|
-
] });
|
|
238
|
-
}
|
|
239
|
-
const LEGACY_TYPE_MAP = {
|
|
240
|
-
info: "note",
|
|
241
|
-
success: "tip",
|
|
242
|
-
error: "caution"
|
|
243
|
-
};
|
|
244
|
-
function normalizeBannerType(type) {
|
|
245
|
-
if (type in LEGACY_TYPE_MAP) return LEGACY_TYPE_MAP[type];
|
|
246
|
-
return type || "note";
|
|
247
|
-
}
|
|
248
|
-
const BANNER_TYPES = [
|
|
249
|
-
"note",
|
|
250
|
-
"tip",
|
|
251
|
-
"important",
|
|
252
|
-
"warning",
|
|
253
|
-
"caution"
|
|
254
|
-
];
|
|
255
|
-
const BANNER_LABELS = {
|
|
256
|
-
note: "Note",
|
|
257
|
-
tip: "Tip",
|
|
258
|
-
important: "Important",
|
|
259
|
-
warning: "Warning",
|
|
260
|
-
caution: "Caution"
|
|
261
|
-
};
|
|
262
|
-
class BannerNode extends DecoratorNode {
|
|
263
|
-
constructor(bannerType, contentState, key) {
|
|
264
|
-
super(key);
|
|
265
|
-
__publicField(this, "__bannerType");
|
|
266
|
-
__publicField(this, "__contentState");
|
|
267
|
-
this.__bannerType = bannerType;
|
|
268
|
-
this.__contentState = contentState || {
|
|
269
|
-
root: {
|
|
270
|
-
children: [
|
|
271
|
-
{
|
|
272
|
-
type: "paragraph",
|
|
273
|
-
children: [],
|
|
274
|
-
direction: null,
|
|
275
|
-
format: "",
|
|
276
|
-
indent: 0,
|
|
277
|
-
textFormat: 0,
|
|
278
|
-
textStyle: "",
|
|
279
|
-
version: 1
|
|
280
|
-
}
|
|
281
|
-
],
|
|
282
|
-
direction: null,
|
|
283
|
-
format: "",
|
|
284
|
-
indent: 0,
|
|
285
|
-
type: "root",
|
|
286
|
-
version: 1
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
static getType() {
|
|
291
|
-
return "banner";
|
|
292
|
-
}
|
|
293
|
-
static clone(node) {
|
|
294
|
-
return new BannerNode(node.__bannerType, node.__contentState, node.__key);
|
|
295
|
-
}
|
|
296
|
-
createDOM(_config) {
|
|
297
|
-
const div = document.createElement("div");
|
|
298
|
-
div.className = `rich-banner rich-banner-${this.__bannerType}`;
|
|
299
|
-
return div;
|
|
300
|
-
}
|
|
301
|
-
updateDOM(prevNode, dom) {
|
|
302
|
-
if (prevNode.__bannerType !== this.__bannerType) {
|
|
303
|
-
dom.className = `rich-banner rich-banner-${this.__bannerType}`;
|
|
304
|
-
}
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
isInline() {
|
|
308
|
-
return false;
|
|
309
|
-
}
|
|
310
|
-
getBannerType() {
|
|
311
|
-
return this.__bannerType;
|
|
312
|
-
}
|
|
313
|
-
setBannerType(bannerType) {
|
|
314
|
-
const writable = this.getWritable();
|
|
315
|
-
writable.__bannerType = bannerType;
|
|
316
|
-
}
|
|
317
|
-
getContentState() {
|
|
318
|
-
return this.getLatest().__contentState;
|
|
319
|
-
}
|
|
320
|
-
setContentState(state) {
|
|
321
|
-
const writable = this.getWritable();
|
|
322
|
-
writable.__contentState = state;
|
|
323
|
-
}
|
|
324
|
-
getTextContent() {
|
|
325
|
-
return extractTextContent(this.__contentState);
|
|
326
|
-
}
|
|
327
|
-
static importJSON(serializedNode) {
|
|
328
|
-
const legacy = serializedNode;
|
|
329
|
-
const bannerType = normalizeBannerType(serializedNode.bannerType);
|
|
330
|
-
if (serializedNode.content) {
|
|
331
|
-
return new BannerNode(bannerType, serializedNode.content);
|
|
332
|
-
}
|
|
333
|
-
if (legacy.children) {
|
|
334
|
-
const content = {
|
|
335
|
-
root: {
|
|
336
|
-
children: legacy.children,
|
|
337
|
-
direction: null,
|
|
338
|
-
format: "",
|
|
339
|
-
indent: 0,
|
|
340
|
-
type: "root",
|
|
341
|
-
version: 1
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
return new BannerNode(bannerType, content);
|
|
345
|
-
}
|
|
346
|
-
return new BannerNode(bannerType);
|
|
347
|
-
}
|
|
348
|
-
exportJSON() {
|
|
349
|
-
return {
|
|
350
|
-
...super.exportJSON(),
|
|
351
|
-
type: "banner",
|
|
352
|
-
bannerType: this.__bannerType,
|
|
353
|
-
content: this.__contentState,
|
|
354
|
-
version: 1
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
decorate(_editor, _config) {
|
|
358
|
-
return createElement(BannerStaticDecorator, {
|
|
359
|
-
bannerType: this.__bannerType,
|
|
360
|
-
contentState: this.__contentState
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
function $isBannerNode(node) {
|
|
365
|
-
return node instanceof BannerNode;
|
|
366
|
-
}
|
|
367
|
-
const ColorSchemeContext = createContext("light");
|
|
368
|
-
function ColorSchemeProvider({
|
|
369
|
-
colorScheme,
|
|
370
|
-
children
|
|
371
|
-
}) {
|
|
372
|
-
return /* @__PURE__ */ jsx(ColorSchemeContext.Provider, { value: colorScheme, children });
|
|
373
|
-
}
|
|
374
|
-
function useColorScheme() {
|
|
375
|
-
return use(ColorSchemeContext);
|
|
376
|
-
}
|
|
377
|
-
let codeToHtmlFn = null;
|
|
378
|
-
let shikiLoadPromise = null;
|
|
379
|
-
function loadCodeToHtml() {
|
|
380
|
-
if (codeToHtmlFn) return Promise.resolve(codeToHtmlFn);
|
|
381
|
-
if (!shikiLoadPromise) {
|
|
382
|
-
shikiLoadPromise = import("shiki/bundle/web").then((mod) => {
|
|
383
|
-
codeToHtmlFn = mod.codeToHtml;
|
|
384
|
-
return mod.codeToHtml;
|
|
385
|
-
}).catch((err) => {
|
|
386
|
-
shikiLoadPromise = null;
|
|
387
|
-
throw err;
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
return shikiLoadPromise;
|
|
391
|
-
}
|
|
392
|
-
function CodeBlockRenderer({
|
|
393
|
-
code,
|
|
394
|
-
language,
|
|
395
|
-
showLineNumbers: showLineNumbersProp
|
|
396
|
-
}) {
|
|
397
|
-
const variant = useVariant();
|
|
398
|
-
const showLineNumbers = showLineNumbersProp ?? variant !== "comment";
|
|
399
|
-
const colorScheme = useColorScheme();
|
|
400
|
-
const shikiTheme = colorScheme === "dark" ? "github-dark" : "github-light";
|
|
401
|
-
const [highlightedHtml, setHighlightedHtml] = useState(null);
|
|
402
|
-
const [copied, setCopied] = useState(false);
|
|
403
|
-
const copyTimerRef = useRef(void 0);
|
|
404
|
-
useEffect(() => {
|
|
405
|
-
let cancelled = false;
|
|
406
|
-
setHighlightedHtml(null);
|
|
407
|
-
loadCodeToHtml().then(
|
|
408
|
-
(toHtml) => toHtml(code, {
|
|
409
|
-
lang: language,
|
|
410
|
-
theme: shikiTheme
|
|
411
|
-
})
|
|
412
|
-
).then((html) => {
|
|
413
|
-
if (!cancelled) {
|
|
414
|
-
setHighlightedHtml(html);
|
|
415
|
-
}
|
|
416
|
-
}).catch(() => {
|
|
417
|
-
if (!cancelled) {
|
|
418
|
-
setHighlightedHtml(null);
|
|
419
|
-
}
|
|
420
|
-
});
|
|
421
|
-
return () => {
|
|
422
|
-
cancelled = true;
|
|
423
|
-
};
|
|
424
|
-
}, [code, language, shikiTheme]);
|
|
425
|
-
useEffect(() => {
|
|
426
|
-
return () => clearTimeout(copyTimerRef.current);
|
|
427
|
-
}, []);
|
|
428
|
-
const handleCopy = useCallback(() => {
|
|
429
|
-
navigator.clipboard.writeText(code).then(() => {
|
|
430
|
-
setCopied(true);
|
|
431
|
-
clearTimeout(copyTimerRef.current);
|
|
432
|
-
copyTimerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
433
|
-
}).catch(() => {
|
|
434
|
-
});
|
|
435
|
-
}, [code]);
|
|
436
|
-
const header = language ? /* @__PURE__ */ jsxs("div", { className: "rich-code-block-header", children: [
|
|
437
|
-
/* @__PURE__ */ jsx("span", { className: "rich-code-block-lang", children: language }),
|
|
438
|
-
/* @__PURE__ */ jsx(
|
|
439
|
-
"button",
|
|
440
|
-
{
|
|
441
|
-
type: "button",
|
|
442
|
-
className: "rich-code-block-copy",
|
|
443
|
-
onClick: handleCopy,
|
|
444
|
-
"aria-label": copied ? "Copied to clipboard" : "Copy code",
|
|
445
|
-
children: copied ? "Copied" : "Copy"
|
|
446
|
-
}
|
|
447
|
-
)
|
|
448
|
-
] }) : null;
|
|
449
|
-
const wrapperClass = showLineNumbers ? "rich-code-block rich-code-block-numbered" : "rich-code-block";
|
|
450
|
-
if (highlightedHtml) {
|
|
451
|
-
return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
|
|
452
|
-
header,
|
|
453
|
-
/* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: highlightedHtml } })
|
|
454
|
-
] });
|
|
455
|
-
}
|
|
456
|
-
const lines = code.split("\n");
|
|
457
|
-
return /* @__PURE__ */ jsxs("div", { className: wrapperClass, children: [
|
|
458
|
-
header,
|
|
459
|
-
/* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => /* @__PURE__ */ jsxs("span", { className: "line", children: [
|
|
460
|
-
line,
|
|
461
|
-
i < lines.length - 1 ? "\n" : ""
|
|
462
|
-
] }, i)) }) })
|
|
463
|
-
] });
|
|
464
|
-
}
|
|
465
|
-
const _CodeBlockNode = class _CodeBlockNode extends DecoratorNode {
|
|
466
|
-
constructor(code, language, key) {
|
|
467
|
-
super(key);
|
|
468
|
-
__publicField(this, "__code");
|
|
469
|
-
__publicField(this, "__language");
|
|
470
|
-
this.__code = code;
|
|
471
|
-
this.__language = language;
|
|
472
|
-
}
|
|
473
|
-
static getType() {
|
|
474
|
-
return "code-block";
|
|
475
|
-
}
|
|
476
|
-
static clone(node) {
|
|
477
|
-
return new _CodeBlockNode(node.__code, node.__language, node.__key);
|
|
478
|
-
}
|
|
479
|
-
createDOM(_config) {
|
|
480
|
-
const div = document.createElement("div");
|
|
481
|
-
div.className = "rich-code-block-wrapper";
|
|
482
|
-
return div;
|
|
483
|
-
}
|
|
484
|
-
updateDOM() {
|
|
485
|
-
return false;
|
|
486
|
-
}
|
|
487
|
-
isInline() {
|
|
488
|
-
return false;
|
|
489
|
-
}
|
|
490
|
-
isKeyboardSelectable() {
|
|
491
|
-
return true;
|
|
492
|
-
}
|
|
493
|
-
static importJSON(serializedNode) {
|
|
494
|
-
return $createCodeBlockNode(serializedNode.code, serializedNode.language);
|
|
495
|
-
}
|
|
496
|
-
exportJSON() {
|
|
497
|
-
return {
|
|
498
|
-
...super.exportJSON(),
|
|
499
|
-
type: "code-block",
|
|
500
|
-
code: this.__code,
|
|
501
|
-
language: this.__language,
|
|
502
|
-
version: 1
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
getCode() {
|
|
506
|
-
return this.__code;
|
|
507
|
-
}
|
|
508
|
-
setCode(code) {
|
|
509
|
-
const writable = this.getWritable();
|
|
510
|
-
writable.__code = code;
|
|
511
|
-
}
|
|
512
|
-
getLanguage() {
|
|
513
|
-
return this.__language;
|
|
514
|
-
}
|
|
515
|
-
setLanguage(language) {
|
|
516
|
-
const writable = this.getWritable();
|
|
517
|
-
writable.__language = language;
|
|
518
|
-
}
|
|
519
|
-
decorate(_editor, _config) {
|
|
520
|
-
return createRendererDecoration("CodeBlock", CodeBlockRenderer, {
|
|
521
|
-
code: this.__code,
|
|
522
|
-
language: this.__language
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
__publicField(_CodeBlockNode, "commandItems", [
|
|
527
|
-
{
|
|
528
|
-
title: "Code Block",
|
|
529
|
-
icon: createElement(Code, { size: 20 }),
|
|
530
|
-
description: "Syntax-highlighted code",
|
|
531
|
-
keywords: ["code", "snippet", "codeblock"],
|
|
532
|
-
section: "MEDIA",
|
|
533
|
-
placement: ["slash", "toolbar"],
|
|
534
|
-
group: "insert",
|
|
535
|
-
onSelect: (editor) => {
|
|
536
|
-
editor.update(() => {
|
|
537
|
-
$insertNodes([$createCodeBlockNode("", "text")]);
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
]);
|
|
542
|
-
let CodeBlockNode = _CodeBlockNode;
|
|
543
|
-
function $createCodeBlockNode(code, language) {
|
|
544
|
-
return new CodeBlockNode(code, language);
|
|
545
|
-
}
|
|
546
|
-
function $isCodeBlockNode(node) {
|
|
547
|
-
return node instanceof CodeBlockNode;
|
|
548
|
-
}
|
|
549
|
-
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
550
|
-
const DEFAULT_ATTRS = {
|
|
551
|
-
xmlns: SVG_NS,
|
|
552
|
-
width: "24",
|
|
553
|
-
height: "24",
|
|
554
|
-
viewBox: "0 0 24 24",
|
|
555
|
-
fill: "none",
|
|
556
|
-
stroke: "currentColor",
|
|
557
|
-
"stroke-width": "2",
|
|
558
|
-
"stroke-linecap": "round",
|
|
559
|
-
"stroke-linejoin": "round"
|
|
560
|
-
};
|
|
561
|
-
function createLucideSvg(iconNode, attrs = {}) {
|
|
562
|
-
const svg = document.createElementNS(SVG_NS, "svg");
|
|
563
|
-
const merged = { ...DEFAULT_ATTRS, ...attrs };
|
|
564
|
-
for (const [k, v] of Object.entries(merged)) {
|
|
565
|
-
svg.setAttribute(k, v);
|
|
566
|
-
}
|
|
567
|
-
for (const [tag, elAttrs] of iconNode) {
|
|
568
|
-
const el = document.createElementNS(SVG_NS, tag);
|
|
569
|
-
for (const [k, v] of Object.entries(elAttrs)) {
|
|
570
|
-
if (k === "key") continue;
|
|
571
|
-
el.setAttribute(k, v);
|
|
572
|
-
}
|
|
573
|
-
svg.append(el);
|
|
574
|
-
}
|
|
575
|
-
return svg;
|
|
576
|
-
}
|
|
577
|
-
const ChevronDownIconNode = [["path", { d: "M6 8L10 12L14 8" }]];
|
|
578
|
-
const _DetailsNode = class _DetailsNode extends ElementNode {
|
|
579
|
-
constructor(summary, open = false, key) {
|
|
580
|
-
super(key);
|
|
581
|
-
__publicField(this, "__summary");
|
|
582
|
-
__publicField(this, "__open");
|
|
583
|
-
this.__summary = summary;
|
|
584
|
-
this.__open = open;
|
|
585
|
-
}
|
|
586
|
-
static getType() {
|
|
587
|
-
return "details";
|
|
588
|
-
}
|
|
589
|
-
static clone(node) {
|
|
590
|
-
return new _DetailsNode(node.__summary, node.__open, node.__key);
|
|
591
|
-
}
|
|
592
|
-
createDOM(_config) {
|
|
593
|
-
const details = document.createElement("details");
|
|
594
|
-
details.className = "rich-details";
|
|
595
|
-
if (this.__open) {
|
|
596
|
-
details.open = true;
|
|
597
|
-
}
|
|
598
|
-
const summary = document.createElement("summary");
|
|
599
|
-
summary.className = "rich-details-summary";
|
|
600
|
-
const label = document.createElement("span");
|
|
601
|
-
label.className = "rich-details-summary-text";
|
|
602
|
-
label.textContent = this.__summary;
|
|
603
|
-
summary.append(label);
|
|
604
|
-
const chevron = document.createElement("span");
|
|
605
|
-
chevron.className = "rich-details-chevron";
|
|
606
|
-
chevron.append(
|
|
607
|
-
createLucideSvg(ChevronDownIconNode, {
|
|
608
|
-
width: "20",
|
|
609
|
-
height: "20",
|
|
610
|
-
viewBox: "0 0 20 20",
|
|
611
|
-
"stroke-width": "1.5"
|
|
612
|
-
})
|
|
613
|
-
);
|
|
614
|
-
summary.append(chevron);
|
|
615
|
-
const content = document.createElement("div");
|
|
616
|
-
content.className = "rich-details-content";
|
|
617
|
-
details.append(summary, content);
|
|
618
|
-
return details;
|
|
619
|
-
}
|
|
620
|
-
updateDOM(prevNode, dom) {
|
|
621
|
-
const details = dom;
|
|
622
|
-
if (prevNode.__open !== this.__open) {
|
|
623
|
-
details.open = this.__open;
|
|
624
|
-
}
|
|
625
|
-
if (prevNode.__summary !== this.__summary) {
|
|
626
|
-
const label = dom.querySelector(".rich-details-summary-text");
|
|
627
|
-
if (label) {
|
|
628
|
-
label.textContent = this.__summary;
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
return false;
|
|
632
|
-
}
|
|
633
|
-
static importJSON(serializedNode) {
|
|
634
|
-
return $createDetailsNode(serializedNode.summary, serializedNode.open);
|
|
635
|
-
}
|
|
636
|
-
exportJSON() {
|
|
637
|
-
return {
|
|
638
|
-
...super.exportJSON(),
|
|
639
|
-
type: "details",
|
|
640
|
-
summary: this.__summary,
|
|
641
|
-
open: this.__open,
|
|
642
|
-
version: 1
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
getSummary() {
|
|
646
|
-
return this.getLatest().__summary;
|
|
647
|
-
}
|
|
648
|
-
setSummary(summary) {
|
|
649
|
-
const writable = this.getWritable();
|
|
650
|
-
writable.__summary = summary;
|
|
651
|
-
}
|
|
652
|
-
getOpen() {
|
|
653
|
-
return this.getLatest().__open;
|
|
654
|
-
}
|
|
655
|
-
setOpen(open) {
|
|
656
|
-
const writable = this.getWritable();
|
|
657
|
-
writable.__open = open;
|
|
658
|
-
}
|
|
659
|
-
toggleOpen() {
|
|
660
|
-
this.setOpen(!this.getOpen());
|
|
661
|
-
}
|
|
662
|
-
getDOMSlot(element) {
|
|
663
|
-
const content = element.querySelector(
|
|
664
|
-
".rich-details-content"
|
|
665
|
-
);
|
|
666
|
-
return super.getDOMSlot(element).withElement(content);
|
|
667
|
-
}
|
|
668
|
-
isInline() {
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
671
|
-
};
|
|
672
|
-
__publicField(_DetailsNode, "slashMenuItems", [
|
|
673
|
-
{
|
|
674
|
-
title: "Details",
|
|
675
|
-
icon: createElement(ChevronRight, { size: 20 }),
|
|
676
|
-
description: "Collapsible content block",
|
|
677
|
-
keywords: ["details", "toggle", "collapse", "accordion"],
|
|
678
|
-
section: "ADVANCED",
|
|
679
|
-
onSelect: (editor) => {
|
|
680
|
-
editor.update(() => {
|
|
681
|
-
$insertNodes([$createDetailsNode("Details")]);
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
]);
|
|
686
|
-
let DetailsNode = _DetailsNode;
|
|
687
|
-
function $createDetailsNode(summary, open = false) {
|
|
688
|
-
return new DetailsNode(summary, open);
|
|
689
|
-
}
|
|
690
|
-
const FootnoteDefinitionsContext = createContext({
|
|
691
|
-
definitions: {},
|
|
692
|
-
displayNumberMap: {}
|
|
693
|
-
});
|
|
694
|
-
function FootnoteDefinitionsProvider({
|
|
695
|
-
definitions,
|
|
696
|
-
displayNumberMap,
|
|
697
|
-
children
|
|
698
|
-
}) {
|
|
699
|
-
const value = useMemo(
|
|
700
|
-
() => ({ definitions, displayNumberMap }),
|
|
701
|
-
[definitions, displayNumberMap]
|
|
702
|
-
);
|
|
703
|
-
return /* @__PURE__ */ jsx(FootnoteDefinitionsContext, { value, children });
|
|
704
|
-
}
|
|
705
|
-
function useFootnoteDefinitions() {
|
|
706
|
-
return use(FootnoteDefinitionsContext);
|
|
707
|
-
}
|
|
708
|
-
function useFootnoteContent(identifier) {
|
|
709
|
-
const { definitions } = use(FootnoteDefinitionsContext);
|
|
710
|
-
return definitions[identifier];
|
|
711
|
-
}
|
|
712
|
-
function useFootnoteDisplayNumber(identifier) {
|
|
713
|
-
const { displayNumberMap } = use(FootnoteDefinitionsContext);
|
|
714
|
-
return displayNumberMap[identifier];
|
|
715
|
-
}
|
|
716
|
-
function FootnoteStaticRenderer({
|
|
717
|
-
identifier
|
|
718
|
-
}) {
|
|
719
|
-
const content = useFootnoteContent(identifier);
|
|
720
|
-
const displayNumber = useFootnoteDisplayNumber(identifier);
|
|
721
|
-
const referenceId = `footnote-ref-${identifier}`;
|
|
722
|
-
const targetId = `footnote-${identifier}`;
|
|
723
|
-
const handleClick = useCallback(
|
|
724
|
-
(e) => {
|
|
725
|
-
const target = document.getElementById(targetId) || document.getElementById(`fn-${identifier}`);
|
|
726
|
-
if (!target) return;
|
|
727
|
-
e.preventDefault();
|
|
728
|
-
target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
729
|
-
target.classList.add("rich-footnote-highlight");
|
|
730
|
-
window.setTimeout(() => {
|
|
731
|
-
target.classList.remove("rich-footnote-highlight");
|
|
732
|
-
}, 1200);
|
|
733
|
-
},
|
|
734
|
-
[identifier, targetId]
|
|
735
|
-
);
|
|
736
|
-
const label = displayNumber ?? identifier;
|
|
737
|
-
return /* @__PURE__ */ jsx("span", { className: "rich-footnote-ref-wrapper", children: /* @__PURE__ */ jsx(
|
|
738
|
-
"a",
|
|
739
|
-
{
|
|
740
|
-
className: "rich-footnote-ref",
|
|
741
|
-
href: `#${targetId}`,
|
|
742
|
-
id: referenceId,
|
|
743
|
-
role: "doc-noteref",
|
|
744
|
-
"aria-label": content ? `Footnote ${label}: ${content}` : `Footnote ${label}`,
|
|
745
|
-
onClick: handleClick,
|
|
746
|
-
"data-footnote-ref": identifier,
|
|
747
|
-
children: label
|
|
748
|
-
}
|
|
749
|
-
) });
|
|
750
|
-
}
|
|
751
|
-
class FootnoteNode extends DecoratorNode {
|
|
752
|
-
constructor(identifier, key) {
|
|
753
|
-
super(key);
|
|
754
|
-
__publicField(this, "__identifier");
|
|
755
|
-
this.__identifier = identifier;
|
|
756
|
-
}
|
|
757
|
-
static getType() {
|
|
758
|
-
return "footnote";
|
|
759
|
-
}
|
|
760
|
-
static clone(node) {
|
|
761
|
-
return new FootnoteNode(node.__identifier, node.__key);
|
|
762
|
-
}
|
|
763
|
-
createDOM(_config) {
|
|
764
|
-
const sup = document.createElement("sup");
|
|
765
|
-
sup.className = "rich-footnote";
|
|
766
|
-
return sup;
|
|
767
|
-
}
|
|
768
|
-
updateDOM() {
|
|
769
|
-
return false;
|
|
770
|
-
}
|
|
771
|
-
isInline() {
|
|
772
|
-
return true;
|
|
773
|
-
}
|
|
774
|
-
static importJSON(serializedNode) {
|
|
775
|
-
return $createFootnoteNode(serializedNode.identifier);
|
|
776
|
-
}
|
|
777
|
-
exportJSON() {
|
|
778
|
-
return {
|
|
779
|
-
...super.exportJSON(),
|
|
780
|
-
type: "footnote",
|
|
781
|
-
identifier: this.__identifier,
|
|
782
|
-
version: 1
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
|
-
getIdentifier() {
|
|
786
|
-
return this.getLatest().__identifier;
|
|
787
|
-
}
|
|
788
|
-
setIdentifier(identifier) {
|
|
789
|
-
const writable = this.getWritable();
|
|
790
|
-
writable.__identifier = identifier;
|
|
791
|
-
}
|
|
792
|
-
decorate(_editor, _config) {
|
|
793
|
-
return createRendererDecoration("Footnote", FootnoteStaticRenderer, {
|
|
794
|
-
identifier: this.__identifier
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
function $createFootnoteNode(identifier) {
|
|
799
|
-
return new FootnoteNode(identifier);
|
|
800
|
-
}
|
|
801
|
-
function FootnoteSectionRenderer({
|
|
802
|
-
definitions
|
|
803
|
-
}) {
|
|
804
|
-
const { displayNumberMap } = useFootnoteDefinitions();
|
|
805
|
-
const sortedEntries = Object.entries(definitions).sort(
|
|
806
|
-
([a], [b]) => (displayNumberMap[a] ?? 0) - (displayNumberMap[b] ?? 0)
|
|
807
|
-
);
|
|
808
|
-
if (sortedEntries.length === 0) return null;
|
|
809
|
-
return /* @__PURE__ */ jsxs("div", { className: "rich-footnote-section-content", role: "doc-endnotes", children: [
|
|
810
|
-
/* @__PURE__ */ jsx("hr", { className: "rich-footnote-section-divider" }),
|
|
811
|
-
/* @__PURE__ */ jsx("ol", { className: "rich-footnote-section-list", children: sortedEntries.map(([identifier, content]) => {
|
|
812
|
-
const displayNum = displayNumberMap[identifier] ?? identifier;
|
|
813
|
-
return /* @__PURE__ */ jsx(
|
|
814
|
-
FootnoteSectionItem,
|
|
815
|
-
{
|
|
816
|
-
identifier,
|
|
817
|
-
content,
|
|
818
|
-
displayNum
|
|
819
|
-
},
|
|
820
|
-
identifier
|
|
821
|
-
);
|
|
822
|
-
}) })
|
|
823
|
-
] });
|
|
824
|
-
}
|
|
825
|
-
function FootnoteSectionItem({
|
|
826
|
-
identifier,
|
|
827
|
-
content,
|
|
828
|
-
displayNum
|
|
829
|
-
}) {
|
|
830
|
-
const targetId = `footnote-${identifier}`;
|
|
831
|
-
const refId = `footnote-ref-${identifier}`;
|
|
832
|
-
const handleBackClick = useCallback(
|
|
833
|
-
(e) => {
|
|
834
|
-
e.preventDefault();
|
|
835
|
-
const refElement = document.getElementById(refId);
|
|
836
|
-
if (!refElement) return;
|
|
837
|
-
refElement.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
838
|
-
refElement.classList.add("rich-footnote-highlight");
|
|
839
|
-
window.setTimeout(() => {
|
|
840
|
-
refElement.classList.remove("rich-footnote-highlight");
|
|
841
|
-
}, 1200);
|
|
842
|
-
},
|
|
843
|
-
[refId]
|
|
844
|
-
);
|
|
845
|
-
return /* @__PURE__ */ jsxs(
|
|
846
|
-
"li",
|
|
847
|
-
{
|
|
848
|
-
id: targetId,
|
|
849
|
-
className: "rich-footnote-section-item",
|
|
850
|
-
value: typeof displayNum === "number" ? displayNum : void 0,
|
|
851
|
-
children: [
|
|
852
|
-
/* @__PURE__ */ jsx("span", { className: "rich-footnote-section-item-content", children: content }),
|
|
853
|
-
/* @__PURE__ */ jsx(
|
|
854
|
-
"a",
|
|
855
|
-
{
|
|
856
|
-
href: `#${refId}`,
|
|
857
|
-
onClick: handleBackClick,
|
|
858
|
-
className: "rich-footnote-back-ref",
|
|
859
|
-
role: "doc-backlink",
|
|
860
|
-
"aria-label": `Back to reference ${displayNum}`,
|
|
861
|
-
children: "↩"
|
|
862
|
-
}
|
|
863
|
-
)
|
|
864
|
-
]
|
|
865
|
-
}
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
class FootnoteSectionNode extends DecoratorNode {
|
|
869
|
-
constructor(definitions, key) {
|
|
870
|
-
super(key);
|
|
871
|
-
__publicField(this, "__definitions");
|
|
872
|
-
this.__definitions = definitions;
|
|
873
|
-
}
|
|
874
|
-
static getType() {
|
|
875
|
-
return "footnote-section";
|
|
876
|
-
}
|
|
877
|
-
static clone(node) {
|
|
878
|
-
return new FootnoteSectionNode({ ...node.__definitions }, node.__key);
|
|
879
|
-
}
|
|
880
|
-
createDOM(_config) {
|
|
881
|
-
const div = document.createElement("div");
|
|
882
|
-
div.className = "rich-footnote-section";
|
|
883
|
-
return div;
|
|
884
|
-
}
|
|
885
|
-
updateDOM() {
|
|
886
|
-
return false;
|
|
887
|
-
}
|
|
888
|
-
isInline() {
|
|
889
|
-
return false;
|
|
890
|
-
}
|
|
891
|
-
static importJSON(serializedNode) {
|
|
892
|
-
return $createFootnoteSectionNode(serializedNode.definitions);
|
|
893
|
-
}
|
|
894
|
-
exportJSON() {
|
|
895
|
-
return {
|
|
896
|
-
...super.exportJSON(),
|
|
897
|
-
type: "footnote-section",
|
|
898
|
-
definitions: this.__definitions,
|
|
899
|
-
version: 1
|
|
900
|
-
};
|
|
901
|
-
}
|
|
902
|
-
getDefinitions() {
|
|
903
|
-
return this.getLatest().__definitions;
|
|
904
|
-
}
|
|
905
|
-
setDefinitions(definitions) {
|
|
906
|
-
const writable = this.getWritable();
|
|
907
|
-
writable.__definitions = definitions;
|
|
908
|
-
}
|
|
909
|
-
getDefinition(identifier) {
|
|
910
|
-
return this.getLatest().__definitions[identifier];
|
|
911
|
-
}
|
|
912
|
-
setDefinition(identifier, content) {
|
|
913
|
-
const writable = this.getWritable();
|
|
914
|
-
writable.__definitions = {
|
|
915
|
-
...writable.__definitions,
|
|
916
|
-
[identifier]: content
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
removeDefinition(identifier) {
|
|
920
|
-
const writable = this.getWritable();
|
|
921
|
-
const { [identifier]: _, ...rest } = writable.__definitions;
|
|
922
|
-
writable.__definitions = rest;
|
|
923
|
-
}
|
|
924
|
-
decorate(_editor, _config) {
|
|
925
|
-
return createRendererDecoration(
|
|
926
|
-
"FootnoteSection",
|
|
927
|
-
FootnoteSectionRenderer,
|
|
928
|
-
{
|
|
929
|
-
definitions: this.__definitions,
|
|
930
|
-
nodeKey: this.__key
|
|
931
|
-
}
|
|
932
|
-
);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
function $createFootnoteSectionNode(definitions = {}) {
|
|
936
|
-
return new FootnoteSectionNode(definitions);
|
|
937
|
-
}
|
|
938
|
-
function $isFootnoteSectionNode(node) {
|
|
939
|
-
return node instanceof FootnoteSectionNode;
|
|
940
|
-
}
|
|
941
|
-
function GridStaticDecorator({
|
|
942
|
-
cols,
|
|
943
|
-
gap,
|
|
944
|
-
cellStates
|
|
945
|
-
}) {
|
|
946
|
-
const renderContent = useNestedContentRenderer();
|
|
947
|
-
return /* @__PURE__ */ jsx(
|
|
948
|
-
"div",
|
|
949
|
-
{
|
|
950
|
-
className: "rich-grid-inner",
|
|
951
|
-
style: {
|
|
952
|
-
display: "grid",
|
|
953
|
-
gridTemplateColumns: `repeat(${cols}, 1fr)`,
|
|
954
|
-
gap
|
|
955
|
-
},
|
|
956
|
-
children: cellStates.map((state, i) => /* @__PURE__ */ jsx("div", { className: "rich-grid-cell", children: renderContent(state) }, i))
|
|
957
|
-
}
|
|
958
|
-
);
|
|
959
|
-
}
|
|
960
|
-
class GridContainerNode extends DecoratorNode {
|
|
961
|
-
constructor(cols = 2, gap, cellStates, key) {
|
|
962
|
-
super(key);
|
|
963
|
-
__publicField(this, "__cols");
|
|
964
|
-
__publicField(this, "__gap");
|
|
965
|
-
__publicField(this, "__cellStates");
|
|
966
|
-
this.__cols = cols;
|
|
967
|
-
this.__gap = gap || "16px";
|
|
968
|
-
if (cellStates) {
|
|
969
|
-
this.__cellStates = cellStates;
|
|
970
|
-
} else {
|
|
971
|
-
const emptyState = {
|
|
972
|
-
root: {
|
|
973
|
-
children: [
|
|
974
|
-
{
|
|
975
|
-
type: "paragraph",
|
|
976
|
-
children: [],
|
|
977
|
-
direction: null,
|
|
978
|
-
format: "",
|
|
979
|
-
indent: 0,
|
|
980
|
-
textFormat: 0,
|
|
981
|
-
textStyle: "",
|
|
982
|
-
version: 1
|
|
983
|
-
}
|
|
984
|
-
],
|
|
985
|
-
direction: null,
|
|
986
|
-
format: "",
|
|
987
|
-
indent: 0,
|
|
988
|
-
type: "root",
|
|
989
|
-
version: 1
|
|
990
|
-
}
|
|
991
|
-
};
|
|
992
|
-
this.__cellStates = Array.from({ length: cols }, () => emptyState);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
static getType() {
|
|
996
|
-
return "grid-container";
|
|
997
|
-
}
|
|
998
|
-
static clone(node) {
|
|
999
|
-
return new GridContainerNode(
|
|
1000
|
-
node.__cols,
|
|
1001
|
-
node.__gap,
|
|
1002
|
-
[...node.__cellStates],
|
|
1003
|
-
node.__key
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
createDOM(_config) {
|
|
1007
|
-
const div = document.createElement("div");
|
|
1008
|
-
div.className = "rich-grid-container";
|
|
1009
|
-
return div;
|
|
1010
|
-
}
|
|
1011
|
-
updateDOM() {
|
|
1012
|
-
return false;
|
|
1013
|
-
}
|
|
1014
|
-
isInline() {
|
|
1015
|
-
return false;
|
|
1016
|
-
}
|
|
1017
|
-
getCols() {
|
|
1018
|
-
return this.getLatest().__cols;
|
|
1019
|
-
}
|
|
1020
|
-
setCols(cols) {
|
|
1021
|
-
const writable = this.getWritable();
|
|
1022
|
-
const prev = writable.__cellStates.length;
|
|
1023
|
-
writable.__cols = cols;
|
|
1024
|
-
if (cols > prev) {
|
|
1025
|
-
const emptyState = {
|
|
1026
|
-
root: {
|
|
1027
|
-
children: [
|
|
1028
|
-
{
|
|
1029
|
-
type: "paragraph",
|
|
1030
|
-
children: [],
|
|
1031
|
-
direction: null,
|
|
1032
|
-
format: "",
|
|
1033
|
-
indent: 0,
|
|
1034
|
-
textFormat: 0,
|
|
1035
|
-
textStyle: "",
|
|
1036
|
-
version: 1
|
|
1037
|
-
}
|
|
1038
|
-
],
|
|
1039
|
-
direction: null,
|
|
1040
|
-
format: "",
|
|
1041
|
-
indent: 0,
|
|
1042
|
-
type: "root",
|
|
1043
|
-
version: 1
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
for (let i = prev; i < cols; i++) {
|
|
1047
|
-
writable.__cellStates.push(emptyState);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
getGap() {
|
|
1052
|
-
return this.getLatest().__gap;
|
|
1053
|
-
}
|
|
1054
|
-
setGap(gap) {
|
|
1055
|
-
const writable = this.getWritable();
|
|
1056
|
-
writable.__gap = gap;
|
|
1057
|
-
}
|
|
1058
|
-
getCellStates() {
|
|
1059
|
-
return this.getLatest().__cellStates;
|
|
1060
|
-
}
|
|
1061
|
-
addCells(count) {
|
|
1062
|
-
const writable = this.getWritable();
|
|
1063
|
-
const emptyState = {
|
|
1064
|
-
root: {
|
|
1065
|
-
children: [
|
|
1066
|
-
{
|
|
1067
|
-
type: "paragraph",
|
|
1068
|
-
children: [],
|
|
1069
|
-
direction: null,
|
|
1070
|
-
format: "",
|
|
1071
|
-
indent: 0,
|
|
1072
|
-
textFormat: 0,
|
|
1073
|
-
textStyle: "",
|
|
1074
|
-
version: 1
|
|
1075
|
-
}
|
|
1076
|
-
],
|
|
1077
|
-
direction: null,
|
|
1078
|
-
format: "",
|
|
1079
|
-
indent: 0,
|
|
1080
|
-
type: "root",
|
|
1081
|
-
version: 1
|
|
1082
|
-
}
|
|
1083
|
-
};
|
|
1084
|
-
for (let i = 0; i < count; i++) {
|
|
1085
|
-
writable.__cellStates.push(emptyState);
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
removeCells(count) {
|
|
1089
|
-
const writable = this.getWritable();
|
|
1090
|
-
const states = writable.__cellStates;
|
|
1091
|
-
const toRemove = Math.min(count, states.length);
|
|
1092
|
-
for (let i = 0; i < toRemove; i++) {
|
|
1093
|
-
const state = states.at(-1);
|
|
1094
|
-
if (!state) break;
|
|
1095
|
-
const isEmpty = extractTextContent(state).trim() === "";
|
|
1096
|
-
if (!isEmpty) break;
|
|
1097
|
-
states.pop();
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
getTextContent() {
|
|
1101
|
-
return this.__cellStates.map((s) => extractTextContent(s)).join("\n");
|
|
1102
|
-
}
|
|
1103
|
-
static importJSON(serializedNode) {
|
|
1104
|
-
const legacy = serializedNode;
|
|
1105
|
-
const cols = legacy.cols || 2;
|
|
1106
|
-
const rawGap = legacy.gap;
|
|
1107
|
-
const gap = typeof rawGap === "number" ? `${rawGap}px` : rawGap;
|
|
1108
|
-
if (legacy.cells && legacy.cells.length > 0) {
|
|
1109
|
-
return new GridContainerNode(cols, gap, legacy.cells);
|
|
1110
|
-
}
|
|
1111
|
-
if (legacy.children) {
|
|
1112
|
-
const cellStates = legacy.children.map(
|
|
1113
|
-
(child) => {
|
|
1114
|
-
return {
|
|
1115
|
-
root: {
|
|
1116
|
-
children: [child],
|
|
1117
|
-
direction: null,
|
|
1118
|
-
format: "",
|
|
1119
|
-
indent: 0,
|
|
1120
|
-
type: "root",
|
|
1121
|
-
version: 1
|
|
1122
|
-
}
|
|
1123
|
-
};
|
|
1124
|
-
}
|
|
1125
|
-
);
|
|
1126
|
-
return new GridContainerNode(cols, gap, cellStates);
|
|
1127
|
-
}
|
|
1128
|
-
return new GridContainerNode(cols, gap);
|
|
1129
|
-
}
|
|
1130
|
-
exportJSON() {
|
|
1131
|
-
return {
|
|
1132
|
-
...super.exportJSON(),
|
|
1133
|
-
type: "grid-container",
|
|
1134
|
-
cols: this.__cols,
|
|
1135
|
-
gap: this.__gap,
|
|
1136
|
-
cells: this.__cellStates,
|
|
1137
|
-
version: 1
|
|
1138
|
-
};
|
|
1139
|
-
}
|
|
1140
|
-
decorate(_editor, _config) {
|
|
1141
|
-
return createElement(GridStaticDecorator, {
|
|
1142
|
-
cols: this.__cols,
|
|
1143
|
-
gap: this.__gap,
|
|
1144
|
-
cellStates: this.__cellStates
|
|
1145
|
-
});
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
function $createGridContainerNode(cols = 2, gap) {
|
|
1149
|
-
return new GridContainerNode(cols, gap);
|
|
1150
|
-
}
|
|
1151
|
-
function $isGridContainerNode(node) {
|
|
1152
|
-
return node instanceof GridContainerNode;
|
|
1153
|
-
}
|
|
1154
|
-
const MAX_DIM = 100;
|
|
1155
|
-
async function computeImageMeta(file) {
|
|
1156
|
-
const url = URL.createObjectURL(file);
|
|
1157
|
-
try {
|
|
1158
|
-
const img = await loadImage(url);
|
|
1159
|
-
const { naturalWidth: w, naturalHeight: h } = img;
|
|
1160
|
-
const scale = Math.min(MAX_DIM / w, MAX_DIM / h, 1);
|
|
1161
|
-
const sw = Math.round(w * scale);
|
|
1162
|
-
const sh = Math.round(h * scale);
|
|
1163
|
-
const canvas = document.createElement("canvas");
|
|
1164
|
-
canvas.width = sw;
|
|
1165
|
-
canvas.height = sh;
|
|
1166
|
-
const ctx = canvas.getContext("2d");
|
|
1167
|
-
ctx.drawImage(img, 0, 0, sw, sh);
|
|
1168
|
-
const { data } = ctx.getImageData(0, 0, sw, sh);
|
|
1169
|
-
const hash = rgbaToThumbHash(sw, sh, data);
|
|
1170
|
-
const thumbhash = uint8ToBase64(hash);
|
|
1171
|
-
return { width: w, height: h, thumbhash };
|
|
1172
|
-
} finally {
|
|
1173
|
-
URL.revokeObjectURL(url);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
function decodeThumbHash(hash) {
|
|
1177
|
-
try {
|
|
1178
|
-
const bytes = base64ToUint8(hash);
|
|
1179
|
-
return thumbHashToDataURL(bytes);
|
|
1180
|
-
} catch {
|
|
1181
|
-
return void 0;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
function loadImage(src) {
|
|
1185
|
-
return new Promise((resolve, reject) => {
|
|
1186
|
-
const img = new Image();
|
|
1187
|
-
img.onload = () => resolve(img);
|
|
1188
|
-
img.onerror = reject;
|
|
1189
|
-
img.src = src;
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
function uint8ToBase64(bytes) {
|
|
1193
|
-
let bin = "";
|
|
1194
|
-
for (const b of bytes) bin += String.fromCodePoint(b);
|
|
1195
|
-
return btoa(bin);
|
|
1196
|
-
}
|
|
1197
|
-
function base64ToUint8(str) {
|
|
1198
|
-
const bin = atob(str);
|
|
1199
|
-
const bytes = new Uint8Array(bin.length);
|
|
1200
|
-
for (let i = 0; i < bin.length; i++) bytes[i] = bin.codePointAt(i);
|
|
1201
|
-
return bytes;
|
|
1202
|
-
}
|
|
1203
|
-
function ImageRenderer({
|
|
1204
|
-
src,
|
|
1205
|
-
altText,
|
|
1206
|
-
width,
|
|
1207
|
-
height,
|
|
1208
|
-
caption,
|
|
1209
|
-
thumbhash,
|
|
1210
|
-
accent
|
|
1211
|
-
}) {
|
|
1212
|
-
const [loaded, setLoaded] = useState(false);
|
|
1213
|
-
const [zoomed, setZoomed] = useState(false);
|
|
1214
|
-
const handleLoad = useCallback(() => setLoaded(true), []);
|
|
1215
|
-
const handleZoomOpen = useCallback(() => {
|
|
1216
|
-
if (!loaded) return;
|
|
1217
|
-
setZoomed(true);
|
|
1218
|
-
}, [loaded]);
|
|
1219
|
-
const handleZoomClose = useCallback(() => setZoomed(false), []);
|
|
1220
|
-
useEffect(() => {
|
|
1221
|
-
if (!zoomed) return;
|
|
1222
|
-
const onKeyDown = (e) => {
|
|
1223
|
-
if (e.key === "Escape") setZoomed(false);
|
|
1224
|
-
};
|
|
1225
|
-
document.addEventListener("keydown", onKeyDown);
|
|
1226
|
-
return () => document.removeEventListener("keydown", onKeyDown);
|
|
1227
|
-
}, [zoomed]);
|
|
1228
|
-
useEffect(() => {
|
|
1229
|
-
if (!zoomed) return;
|
|
1230
|
-
const prev = document.body.style.overflow;
|
|
1231
|
-
document.body.style.overflow = "hidden";
|
|
1232
|
-
return () => {
|
|
1233
|
-
document.body.style.overflow = prev;
|
|
1234
|
-
};
|
|
1235
|
-
}, [zoomed]);
|
|
1236
|
-
const handleContainerKeyDown = useCallback(
|
|
1237
|
-
(e) => {
|
|
1238
|
-
if ((e.key === "Enter" || e.key === " ") && loaded) {
|
|
1239
|
-
e.preventDefault();
|
|
1240
|
-
setZoomed(true);
|
|
1241
|
-
}
|
|
1242
|
-
},
|
|
1243
|
-
[loaded]
|
|
1244
|
-
);
|
|
1245
|
-
const placeholderUrl = useMemo(
|
|
1246
|
-
() => thumbhash ? decodeThumbHash(thumbhash) : void 0,
|
|
1247
|
-
[thumbhash]
|
|
1248
|
-
);
|
|
1249
|
-
const aspectStyle = width && height ? { aspectRatio: `${width} / ${height}`, maxWidth: "100%", width } : { maxWidth: "100%" };
|
|
1250
|
-
return /* @__PURE__ */ jsxs("figure", { className: "rich-image", children: [
|
|
1251
|
-
/* @__PURE__ */ jsx(
|
|
1252
|
-
"div",
|
|
1253
|
-
{
|
|
1254
|
-
className: `rich-image-container${loaded ? " rich-image-loaded" : ""}`,
|
|
1255
|
-
style: {
|
|
1256
|
-
...aspectStyle,
|
|
1257
|
-
backgroundColor: !loaded && !placeholderUrl ? accent : void 0,
|
|
1258
|
-
backgroundImage: !loaded && placeholderUrl ? `url(${placeholderUrl})` : void 0,
|
|
1259
|
-
backgroundSize: "cover",
|
|
1260
|
-
cursor: loaded ? "zoom-in" : void 0
|
|
1261
|
-
},
|
|
1262
|
-
onClick: handleZoomOpen,
|
|
1263
|
-
onKeyDown: handleContainerKeyDown,
|
|
1264
|
-
role: "button",
|
|
1265
|
-
tabIndex: loaded ? 0 : -1,
|
|
1266
|
-
"aria-label": loaded ? `Zoom image: ${altText}` : void 0,
|
|
1267
|
-
children: /* @__PURE__ */ jsx(
|
|
1268
|
-
"img",
|
|
1269
|
-
{
|
|
1270
|
-
src,
|
|
1271
|
-
alt: altText,
|
|
1272
|
-
width,
|
|
1273
|
-
height,
|
|
1274
|
-
loading: "lazy",
|
|
1275
|
-
onLoad: handleLoad,
|
|
1276
|
-
style: { maxWidth: "100%", height: "auto" },
|
|
1277
|
-
className: loaded ? "rich-image-visible" : "rich-image-hidden"
|
|
1278
|
-
}
|
|
1279
|
-
)
|
|
1280
|
-
}
|
|
1281
|
-
),
|
|
1282
|
-
caption && /* @__PURE__ */ jsx("figcaption", { children: caption }),
|
|
1283
|
-
zoomed && /* @__PURE__ */ jsx(
|
|
1284
|
-
"div",
|
|
1285
|
-
{
|
|
1286
|
-
className: "rich-image-zoom-overlay",
|
|
1287
|
-
onClick: handleZoomClose,
|
|
1288
|
-
role: "dialog",
|
|
1289
|
-
"aria-modal": "true",
|
|
1290
|
-
"aria-label": `Zoomed image: ${altText}`,
|
|
1291
|
-
tabIndex: 0,
|
|
1292
|
-
children: /* @__PURE__ */ jsx("img", { src, alt: altText, className: "rich-image-zoom-img" })
|
|
1293
|
-
}
|
|
1294
|
-
)
|
|
1295
|
-
] });
|
|
1296
|
-
}
|
|
1297
|
-
const OPEN_IMAGE_UPLOAD_DIALOG_COMMAND = createCommand(
|
|
1298
|
-
"OPEN_IMAGE_UPLOAD_DIALOG_COMMAND"
|
|
1299
|
-
);
|
|
1300
|
-
function sanitizeImageSrc(src) {
|
|
1301
|
-
const trimmed = src.trim();
|
|
1302
|
-
if (/^(javascript\s*:|vbscript\s*:|data\s*:(?!image\/))/i.test(trimmed)) {
|
|
1303
|
-
return "";
|
|
1304
|
-
}
|
|
1305
|
-
return trimmed;
|
|
1306
|
-
}
|
|
1307
|
-
function sanitizeColor(value) {
|
|
1308
|
-
if (!value) return void 0;
|
|
1309
|
-
const trimmed = value.trim();
|
|
1310
|
-
if (/^#[\da-f]{3,8}$/i.test(trimmed)) return trimmed;
|
|
1311
|
-
if (/^(rgb|hsl)a?\([^)]+\)$/i.test(trimmed)) return trimmed;
|
|
1312
|
-
if (/^[a-z]{3,20}$/i.test(trimmed)) return trimmed;
|
|
1313
|
-
return void 0;
|
|
1314
|
-
}
|
|
1315
|
-
const _ImageNode = class _ImageNode extends DecoratorNode {
|
|
1316
|
-
constructor(payload, key) {
|
|
1317
|
-
super(key);
|
|
1318
|
-
__publicField(this, "__src");
|
|
1319
|
-
__publicField(this, "__altText");
|
|
1320
|
-
__publicField(this, "__width");
|
|
1321
|
-
__publicField(this, "__height");
|
|
1322
|
-
__publicField(this, "__caption");
|
|
1323
|
-
__publicField(this, "__thumbhash");
|
|
1324
|
-
__publicField(this, "__accent");
|
|
1325
|
-
this.__src = sanitizeImageSrc(payload.src);
|
|
1326
|
-
this.__altText = payload.altText;
|
|
1327
|
-
this.__width = payload.width;
|
|
1328
|
-
this.__height = payload.height;
|
|
1329
|
-
this.__caption = payload.caption;
|
|
1330
|
-
this.__thumbhash = payload.thumbhash;
|
|
1331
|
-
this.__accent = sanitizeColor(payload.accent);
|
|
1332
|
-
}
|
|
1333
|
-
static getType() {
|
|
1334
|
-
return "image";
|
|
1335
|
-
}
|
|
1336
|
-
static clone(node) {
|
|
1337
|
-
return new _ImageNode(
|
|
1338
|
-
{
|
|
1339
|
-
src: node.__src,
|
|
1340
|
-
altText: node.__altText,
|
|
1341
|
-
width: node.__width,
|
|
1342
|
-
height: node.__height,
|
|
1343
|
-
caption: node.__caption,
|
|
1344
|
-
thumbhash: node.__thumbhash,
|
|
1345
|
-
accent: node.__accent
|
|
1346
|
-
},
|
|
1347
|
-
node.__key
|
|
1348
|
-
);
|
|
1349
|
-
}
|
|
1350
|
-
createDOM(_config) {
|
|
1351
|
-
const div = document.createElement("div");
|
|
1352
|
-
div.className = "rich-image-wrapper";
|
|
1353
|
-
return div;
|
|
1354
|
-
}
|
|
1355
|
-
updateDOM() {
|
|
1356
|
-
return false;
|
|
1357
|
-
}
|
|
1358
|
-
isInline() {
|
|
1359
|
-
return false;
|
|
1360
|
-
}
|
|
1361
|
-
static importJSON(serializedNode) {
|
|
1362
|
-
return $createImageNode({
|
|
1363
|
-
src: serializedNode.src,
|
|
1364
|
-
altText: serializedNode.altText,
|
|
1365
|
-
width: serializedNode.width,
|
|
1366
|
-
height: serializedNode.height,
|
|
1367
|
-
caption: serializedNode.caption,
|
|
1368
|
-
thumbhash: serializedNode.thumbhash,
|
|
1369
|
-
accent: serializedNode.accent
|
|
1370
|
-
});
|
|
1371
|
-
}
|
|
1372
|
-
exportJSON() {
|
|
1373
|
-
return {
|
|
1374
|
-
...super.exportJSON(),
|
|
1375
|
-
type: "image",
|
|
1376
|
-
src: this.__src,
|
|
1377
|
-
altText: this.__altText,
|
|
1378
|
-
width: this.__width,
|
|
1379
|
-
height: this.__height,
|
|
1380
|
-
caption: this.__caption,
|
|
1381
|
-
thumbhash: this.__thumbhash,
|
|
1382
|
-
accent: this.__accent,
|
|
1383
|
-
version: 1
|
|
1384
|
-
};
|
|
1385
|
-
}
|
|
1386
|
-
setSrc(src) {
|
|
1387
|
-
const writable = this.getWritable();
|
|
1388
|
-
writable.__src = sanitizeImageSrc(src);
|
|
1389
|
-
}
|
|
1390
|
-
setAltText(altText) {
|
|
1391
|
-
const writable = this.getWritable();
|
|
1392
|
-
writable.__altText = altText;
|
|
1393
|
-
}
|
|
1394
|
-
setCaption(caption) {
|
|
1395
|
-
const writable = this.getWritable();
|
|
1396
|
-
writable.__caption = caption;
|
|
1397
|
-
}
|
|
1398
|
-
setDimensions(width, height) {
|
|
1399
|
-
const writable = this.getWritable();
|
|
1400
|
-
writable.__width = width;
|
|
1401
|
-
writable.__height = height;
|
|
1402
|
-
}
|
|
1403
|
-
setThumbhash(thumbhash) {
|
|
1404
|
-
const writable = this.getWritable();
|
|
1405
|
-
writable.__thumbhash = thumbhash;
|
|
1406
|
-
}
|
|
1407
|
-
setAccent(accent) {
|
|
1408
|
-
const writable = this.getWritable();
|
|
1409
|
-
writable.__accent = sanitizeColor(accent);
|
|
1410
|
-
}
|
|
1411
|
-
getSrc() {
|
|
1412
|
-
return this.__src;
|
|
1413
|
-
}
|
|
1414
|
-
getAltText() {
|
|
1415
|
-
return this.__altText;
|
|
1416
|
-
}
|
|
1417
|
-
getCaption() {
|
|
1418
|
-
return this.__caption;
|
|
1419
|
-
}
|
|
1420
|
-
getWidth() {
|
|
1421
|
-
return this.__width;
|
|
1422
|
-
}
|
|
1423
|
-
getHeight() {
|
|
1424
|
-
return this.__height;
|
|
1425
|
-
}
|
|
1426
|
-
getThumbhash() {
|
|
1427
|
-
return this.__thumbhash;
|
|
1428
|
-
}
|
|
1429
|
-
getAccent() {
|
|
1430
|
-
return this.__accent;
|
|
1431
|
-
}
|
|
1432
|
-
decorate(_editor, _config) {
|
|
1433
|
-
return createRendererDecoration("Image", ImageRenderer, {
|
|
1434
|
-
src: this.__src,
|
|
1435
|
-
altText: this.__altText,
|
|
1436
|
-
width: this.__width,
|
|
1437
|
-
height: this.__height,
|
|
1438
|
-
caption: this.__caption,
|
|
1439
|
-
thumbhash: this.__thumbhash,
|
|
1440
|
-
accent: this.__accent
|
|
1441
|
-
});
|
|
1442
|
-
}
|
|
1443
|
-
};
|
|
1444
|
-
__publicField(_ImageNode, "commandItems", [
|
|
1445
|
-
{
|
|
1446
|
-
title: "Image",
|
|
1447
|
-
icon: createElement(ImageIcon, { size: 20 }),
|
|
1448
|
-
description: "Upload or embed an image",
|
|
1449
|
-
keywords: ["image", "picture", "photo"],
|
|
1450
|
-
section: "MEDIA",
|
|
1451
|
-
placement: ["slash", "toolbar"],
|
|
1452
|
-
group: "insert",
|
|
1453
|
-
onSelect: (editor) => {
|
|
1454
|
-
const opened = editor.dispatchCommand(
|
|
1455
|
-
OPEN_IMAGE_UPLOAD_DIALOG_COMMAND,
|
|
1456
|
-
void 0
|
|
1457
|
-
);
|
|
1458
|
-
if (opened) return;
|
|
1459
|
-
editor.update(() => {
|
|
1460
|
-
$insertNodes([$createImageNode({ src: "", altText: "" })]);
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
]);
|
|
1465
|
-
let ImageNode = _ImageNode;
|
|
1466
|
-
function $createImageNode(payload) {
|
|
1467
|
-
return new ImageNode(payload);
|
|
1468
|
-
}
|
|
1469
|
-
function $isImageNode(node) {
|
|
1470
|
-
return node instanceof ImageNode;
|
|
1471
|
-
}
|
|
1472
|
-
let katexModule = null;
|
|
1473
|
-
let katexLoadPromise = null;
|
|
1474
|
-
function loadKaTeX() {
|
|
1475
|
-
if (katexModule) return Promise.resolve(katexModule);
|
|
1476
|
-
if (!katexLoadPromise) {
|
|
1477
|
-
katexLoadPromise = import("katex").then((mod) => {
|
|
1478
|
-
katexModule = mod;
|
|
1479
|
-
return katexModule;
|
|
1480
|
-
});
|
|
1481
|
-
}
|
|
1482
|
-
return katexLoadPromise;
|
|
1483
|
-
}
|
|
1484
|
-
function KaTeXRenderer({ equation, displayMode }) {
|
|
1485
|
-
const [html, setHtml] = useState(null);
|
|
1486
|
-
const [error, setError] = useState(null);
|
|
1487
|
-
useEffect(() => {
|
|
1488
|
-
let cancelled = false;
|
|
1489
|
-
loadKaTeX().then((katex) => {
|
|
1490
|
-
if (cancelled) return;
|
|
1491
|
-
const rendered = katex.default.renderToString(equation, {
|
|
1492
|
-
displayMode,
|
|
1493
|
-
throwOnError: false
|
|
1494
|
-
});
|
|
1495
|
-
setHtml(rendered);
|
|
1496
|
-
setError(null);
|
|
1497
|
-
}).catch(() => {
|
|
1498
|
-
if (cancelled) return;
|
|
1499
|
-
setHtml(null);
|
|
1500
|
-
setError("KaTeX is not available");
|
|
1501
|
-
});
|
|
1502
|
-
return () => {
|
|
1503
|
-
cancelled = true;
|
|
1504
|
-
};
|
|
1505
|
-
}, [equation, displayMode]);
|
|
1506
|
-
if (error) {
|
|
1507
|
-
return /* @__PURE__ */ jsx("code", { className: "rich-katex-fallback", children: equation });
|
|
1508
|
-
}
|
|
1509
|
-
if (html) {
|
|
1510
|
-
return /* @__PURE__ */ jsx(
|
|
1511
|
-
"span",
|
|
1512
|
-
{
|
|
1513
|
-
className: displayMode ? "rich-katex-block" : "rich-katex-inline",
|
|
1514
|
-
dangerouslySetInnerHTML: { __html: html }
|
|
1515
|
-
}
|
|
1516
|
-
);
|
|
1517
|
-
}
|
|
1518
|
-
return /* @__PURE__ */ jsx("code", { className: "rich-katex-fallback", children: equation });
|
|
1519
|
-
}
|
|
1520
|
-
const _KaTeXBlockNode = class _KaTeXBlockNode extends DecoratorNode {
|
|
1521
|
-
constructor(equation, key) {
|
|
1522
|
-
super(key);
|
|
1523
|
-
__publicField(this, "__equation");
|
|
1524
|
-
this.__equation = equation;
|
|
1525
|
-
}
|
|
1526
|
-
static getType() {
|
|
1527
|
-
return "katex-block";
|
|
1528
|
-
}
|
|
1529
|
-
static clone(node) {
|
|
1530
|
-
return new _KaTeXBlockNode(node.__equation, node.__key);
|
|
1531
|
-
}
|
|
1532
|
-
createDOM(_config) {
|
|
1533
|
-
const div = document.createElement("div");
|
|
1534
|
-
div.className = "rich-katex-block-wrapper";
|
|
1535
|
-
return div;
|
|
1536
|
-
}
|
|
1537
|
-
updateDOM() {
|
|
1538
|
-
return false;
|
|
1539
|
-
}
|
|
1540
|
-
isInline() {
|
|
1541
|
-
return false;
|
|
1542
|
-
}
|
|
1543
|
-
static importJSON(serializedNode) {
|
|
1544
|
-
return $createKaTeXBlockNode(serializedNode.equation);
|
|
1545
|
-
}
|
|
1546
|
-
exportJSON() {
|
|
1547
|
-
return {
|
|
1548
|
-
...super.exportJSON(),
|
|
1549
|
-
type: "katex-block",
|
|
1550
|
-
equation: this.__equation,
|
|
1551
|
-
version: 1
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
|
-
getEquation() {
|
|
1555
|
-
return this.__equation;
|
|
1556
|
-
}
|
|
1557
|
-
setEquation(equation) {
|
|
1558
|
-
const writable = this.getWritable();
|
|
1559
|
-
writable.__equation = equation;
|
|
1560
|
-
}
|
|
1561
|
-
decorate(_editor, _config) {
|
|
1562
|
-
return createRendererDecoration("KaTeX", KaTeXRenderer, {
|
|
1563
|
-
equation: this.__equation,
|
|
1564
|
-
displayMode: true
|
|
1565
|
-
});
|
|
1566
|
-
}
|
|
1567
|
-
};
|
|
1568
|
-
__publicField(_KaTeXBlockNode, "slashMenuItems", [
|
|
1569
|
-
{
|
|
1570
|
-
title: "Math Equation",
|
|
1571
|
-
icon: createElement(Sigma, { size: 20 }),
|
|
1572
|
-
description: "KaTeX block formula",
|
|
1573
|
-
keywords: ["math", "equation", "latex", "katex"],
|
|
1574
|
-
section: "ADVANCED",
|
|
1575
|
-
onSelect: (editor) => {
|
|
1576
|
-
editor.update(() => {
|
|
1577
|
-
$insertNodes([$createKaTeXBlockNode("")]);
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
]);
|
|
1582
|
-
let KaTeXBlockNode = _KaTeXBlockNode;
|
|
1583
|
-
function $createKaTeXBlockNode(equation) {
|
|
1584
|
-
return new KaTeXBlockNode(equation);
|
|
1585
|
-
}
|
|
1586
|
-
function $isKaTeXBlockNode(node) {
|
|
1587
|
-
return node instanceof KaTeXBlockNode;
|
|
1588
|
-
}
|
|
1589
|
-
class KaTeXInlineNode extends DecoratorNode {
|
|
1590
|
-
constructor(equation, key) {
|
|
1591
|
-
super(key);
|
|
1592
|
-
__publicField(this, "__equation");
|
|
1593
|
-
this.__equation = equation;
|
|
1594
|
-
}
|
|
1595
|
-
static getType() {
|
|
1596
|
-
return "katex-inline";
|
|
1597
|
-
}
|
|
1598
|
-
static clone(node) {
|
|
1599
|
-
return new KaTeXInlineNode(node.__equation, node.__key);
|
|
1600
|
-
}
|
|
1601
|
-
createDOM(_config) {
|
|
1602
|
-
return document.createElement("span");
|
|
1603
|
-
}
|
|
1604
|
-
updateDOM() {
|
|
1605
|
-
return false;
|
|
1606
|
-
}
|
|
1607
|
-
isInline() {
|
|
1608
|
-
return true;
|
|
1609
|
-
}
|
|
1610
|
-
static importJSON(serializedNode) {
|
|
1611
|
-
return $createKaTeXInlineNode(serializedNode.equation);
|
|
1612
|
-
}
|
|
1613
|
-
exportJSON() {
|
|
1614
|
-
return {
|
|
1615
|
-
...super.exportJSON(),
|
|
1616
|
-
type: "katex-inline",
|
|
1617
|
-
equation: this.__equation,
|
|
1618
|
-
version: 1
|
|
1619
|
-
};
|
|
1620
|
-
}
|
|
1621
|
-
getEquation() {
|
|
1622
|
-
return this.__equation;
|
|
1623
|
-
}
|
|
1624
|
-
setEquation(equation) {
|
|
1625
|
-
const writable = this.getWritable();
|
|
1626
|
-
writable.__equation = equation;
|
|
1627
|
-
}
|
|
1628
|
-
decorate(_editor, _config) {
|
|
1629
|
-
return createRendererDecoration("KaTeX", KaTeXRenderer, {
|
|
1630
|
-
equation: this.__equation,
|
|
1631
|
-
displayMode: false
|
|
1632
|
-
});
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
function $createKaTeXInlineNode(equation) {
|
|
1636
|
-
return new KaTeXInlineNode(equation);
|
|
1637
|
-
}
|
|
1638
|
-
function $isKaTeXInlineNode(node) {
|
|
1639
|
-
return node instanceof KaTeXInlineNode;
|
|
1640
|
-
}
|
|
1641
|
-
function LinkCardRenderer({
|
|
1642
|
-
url,
|
|
1643
|
-
title,
|
|
1644
|
-
description,
|
|
1645
|
-
favicon,
|
|
1646
|
-
image
|
|
1647
|
-
}) {
|
|
1648
|
-
const displayTitle = title || url;
|
|
1649
|
-
return /* @__PURE__ */ jsxs(
|
|
1650
|
-
"a",
|
|
1651
|
-
{
|
|
1652
|
-
className: "rich-link-card",
|
|
1653
|
-
href: url,
|
|
1654
|
-
target: "_blank",
|
|
1655
|
-
rel: "noopener noreferrer",
|
|
1656
|
-
children: [
|
|
1657
|
-
image && /* @__PURE__ */ jsx("span", { className: "rich-link-card-image", children: /* @__PURE__ */ jsx("img", { src: image, alt: "", loading: "lazy" }) }),
|
|
1658
|
-
/* @__PURE__ */ jsxs("span", { className: "rich-link-card-content", children: [
|
|
1659
|
-
/* @__PURE__ */ jsxs("span", { className: "rich-link-card-title", children: [
|
|
1660
|
-
favicon && /* @__PURE__ */ jsx(
|
|
1661
|
-
"img",
|
|
1662
|
-
{
|
|
1663
|
-
className: "rich-link-card-favicon",
|
|
1664
|
-
src: favicon,
|
|
1665
|
-
alt: "",
|
|
1666
|
-
width: 16,
|
|
1667
|
-
height: 16,
|
|
1668
|
-
onError: (e) => {
|
|
1669
|
-
e.target.style.display = "none";
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
),
|
|
1673
|
-
displayTitle
|
|
1674
|
-
] }),
|
|
1675
|
-
description && /* @__PURE__ */ jsx("span", { className: "rich-link-card-description", children: description }),
|
|
1676
|
-
/* @__PURE__ */ jsx("span", { className: "rich-link-card-url", children: url })
|
|
1677
|
-
] })
|
|
1678
|
-
]
|
|
1679
|
-
}
|
|
1680
|
-
);
|
|
1681
|
-
}
|
|
1682
|
-
const _LinkCardNode = class _LinkCardNode extends DecoratorNode {
|
|
1683
|
-
constructor(payload, key) {
|
|
1684
|
-
super(key);
|
|
1685
|
-
__publicField(this, "__url");
|
|
1686
|
-
__publicField(this, "__source");
|
|
1687
|
-
__publicField(this, "__id");
|
|
1688
|
-
__publicField(this, "__title");
|
|
1689
|
-
__publicField(this, "__description");
|
|
1690
|
-
__publicField(this, "__favicon");
|
|
1691
|
-
__publicField(this, "__image");
|
|
1692
|
-
this.__url = payload.url;
|
|
1693
|
-
this.__source = payload.source;
|
|
1694
|
-
this.__id = payload.id;
|
|
1695
|
-
this.__title = payload.title;
|
|
1696
|
-
this.__description = payload.description;
|
|
1697
|
-
this.__favicon = payload.favicon;
|
|
1698
|
-
this.__image = payload.image;
|
|
1699
|
-
}
|
|
1700
|
-
static getType() {
|
|
1701
|
-
return "link-card";
|
|
1702
|
-
}
|
|
1703
|
-
static clone(node) {
|
|
1704
|
-
return new _LinkCardNode(
|
|
1705
|
-
{
|
|
1706
|
-
url: node.__url,
|
|
1707
|
-
source: node.__source,
|
|
1708
|
-
id: node.__id,
|
|
1709
|
-
title: node.__title,
|
|
1710
|
-
description: node.__description,
|
|
1711
|
-
favicon: node.__favicon,
|
|
1712
|
-
image: node.__image
|
|
1713
|
-
},
|
|
1714
|
-
node.__key
|
|
1715
|
-
);
|
|
1716
|
-
}
|
|
1717
|
-
createDOM(_config) {
|
|
1718
|
-
const div = document.createElement("div");
|
|
1719
|
-
div.className = "rich-link-card-wrapper";
|
|
1720
|
-
return div;
|
|
1721
|
-
}
|
|
1722
|
-
updateDOM() {
|
|
1723
|
-
return false;
|
|
1724
|
-
}
|
|
1725
|
-
isInline() {
|
|
1726
|
-
return false;
|
|
1727
|
-
}
|
|
1728
|
-
static importJSON(serializedNode) {
|
|
1729
|
-
return $createLinkCardNode({
|
|
1730
|
-
url: serializedNode.url,
|
|
1731
|
-
source: serializedNode.source,
|
|
1732
|
-
id: serializedNode.id,
|
|
1733
|
-
title: serializedNode.title,
|
|
1734
|
-
description: serializedNode.description,
|
|
1735
|
-
favicon: serializedNode.favicon,
|
|
1736
|
-
image: serializedNode.image
|
|
1737
|
-
});
|
|
1738
|
-
}
|
|
1739
|
-
exportJSON() {
|
|
1740
|
-
return {
|
|
1741
|
-
...super.exportJSON(),
|
|
1742
|
-
type: "link-card",
|
|
1743
|
-
url: this.__url,
|
|
1744
|
-
source: this.__source,
|
|
1745
|
-
id: this.__id,
|
|
1746
|
-
title: this.__title,
|
|
1747
|
-
description: this.__description,
|
|
1748
|
-
favicon: this.__favicon,
|
|
1749
|
-
image: this.__image,
|
|
1750
|
-
version: 1
|
|
1751
|
-
};
|
|
1752
|
-
}
|
|
1753
|
-
getUrl() {
|
|
1754
|
-
return this.getLatest().__url;
|
|
1755
|
-
}
|
|
1756
|
-
setUrl(url) {
|
|
1757
|
-
const writable = this.getWritable();
|
|
1758
|
-
writable.__url = url;
|
|
1759
|
-
}
|
|
1760
|
-
getSource() {
|
|
1761
|
-
return this.getLatest().__source;
|
|
1762
|
-
}
|
|
1763
|
-
setSource(source) {
|
|
1764
|
-
const writable = this.getWritable();
|
|
1765
|
-
writable.__source = source;
|
|
1766
|
-
}
|
|
1767
|
-
getId() {
|
|
1768
|
-
return this.getLatest().__id;
|
|
1769
|
-
}
|
|
1770
|
-
setId(id) {
|
|
1771
|
-
const writable = this.getWritable();
|
|
1772
|
-
writable.__id = id;
|
|
1773
|
-
}
|
|
1774
|
-
decorate(_editor, _config) {
|
|
1775
|
-
return createRendererDecoration("LinkCard", LinkCardRenderer, {
|
|
1776
|
-
url: this.__url,
|
|
1777
|
-
source: this.__source,
|
|
1778
|
-
id: this.__id,
|
|
1779
|
-
title: this.__title,
|
|
1780
|
-
description: this.__description,
|
|
1781
|
-
favicon: this.__favicon,
|
|
1782
|
-
image: this.__image
|
|
1783
|
-
});
|
|
1784
|
-
}
|
|
1785
|
-
};
|
|
1786
|
-
__publicField(_LinkCardNode, "commandItems", [
|
|
1787
|
-
{
|
|
1788
|
-
title: "Link Card",
|
|
1789
|
-
icon: createElement(Link, { size: 20 }),
|
|
1790
|
-
description: "Link preview card",
|
|
1791
|
-
keywords: ["link", "card", "bookmark", "embed"],
|
|
1792
|
-
section: "MEDIA",
|
|
1793
|
-
placement: ["slash", "toolbar"],
|
|
1794
|
-
group: "insert",
|
|
1795
|
-
onSelect: (editor) => {
|
|
1796
|
-
editor.update(() => {
|
|
1797
|
-
$insertNodes([$createLinkCardNode({ url: "" })]);
|
|
1798
|
-
});
|
|
1799
|
-
}
|
|
1800
|
-
}
|
|
1801
|
-
]);
|
|
1802
|
-
let LinkCardNode = _LinkCardNode;
|
|
1803
|
-
function $createLinkCardNode(payload) {
|
|
1804
|
-
return new LinkCardNode(payload);
|
|
1805
|
-
}
|
|
1806
|
-
function $isLinkCardNode(node) {
|
|
1807
|
-
return node instanceof LinkCardNode;
|
|
1808
|
-
}
|
|
1809
|
-
function MentionRenderer({ handle, displayName }) {
|
|
1810
|
-
const normalizedHandle = handle.replace(/^@+/, "");
|
|
1811
|
-
const label = displayName || normalizedHandle;
|
|
1812
|
-
return /* @__PURE__ */ jsx("span", { className: "rich-mention rich-mention-plain", children: /* @__PURE__ */ jsxs("span", { className: "rich-mention-handle", children: [
|
|
1813
|
-
"@",
|
|
1814
|
-
label
|
|
1815
|
-
] }) });
|
|
1816
|
-
}
|
|
1817
|
-
const _MentionNode = class _MentionNode extends DecoratorNode {
|
|
1818
|
-
constructor(platform, handle, displayName, key) {
|
|
1819
|
-
super(key);
|
|
1820
|
-
__publicField(this, "__platform");
|
|
1821
|
-
__publicField(this, "__handle");
|
|
1822
|
-
__publicField(this, "__displayName");
|
|
1823
|
-
this.__platform = platform;
|
|
1824
|
-
this.__handle = handle;
|
|
1825
|
-
this.__displayName = displayName;
|
|
1826
|
-
}
|
|
1827
|
-
static getType() {
|
|
1828
|
-
return "mention";
|
|
1829
|
-
}
|
|
1830
|
-
static clone(node) {
|
|
1831
|
-
return new _MentionNode(
|
|
1832
|
-
node.__platform,
|
|
1833
|
-
node.__handle,
|
|
1834
|
-
node.__displayName,
|
|
1835
|
-
node.__key
|
|
1836
|
-
);
|
|
1837
|
-
}
|
|
1838
|
-
createDOM(_config) {
|
|
1839
|
-
const el = document.createElement("span");
|
|
1840
|
-
el.style.display = "inline-flex";
|
|
1841
|
-
el.style.alignItems = "center";
|
|
1842
|
-
el.style.height = "1lh";
|
|
1843
|
-
return el;
|
|
1844
|
-
}
|
|
1845
|
-
updateDOM() {
|
|
1846
|
-
return false;
|
|
1847
|
-
}
|
|
1848
|
-
isInline() {
|
|
1849
|
-
return true;
|
|
1850
|
-
}
|
|
1851
|
-
getPlatform() {
|
|
1852
|
-
return this.getLatest().__platform;
|
|
1853
|
-
}
|
|
1854
|
-
getHandle() {
|
|
1855
|
-
return this.getLatest().__handle;
|
|
1856
|
-
}
|
|
1857
|
-
getDisplayName() {
|
|
1858
|
-
return this.getLatest().__displayName;
|
|
1859
|
-
}
|
|
1860
|
-
static importJSON(serializedNode) {
|
|
1861
|
-
return $createMentionNode(
|
|
1862
|
-
serializedNode.platform,
|
|
1863
|
-
serializedNode.handle,
|
|
1864
|
-
serializedNode.displayName
|
|
1865
|
-
);
|
|
1866
|
-
}
|
|
1867
|
-
exportJSON() {
|
|
1868
|
-
return {
|
|
1869
|
-
...super.exportJSON(),
|
|
1870
|
-
type: "mention",
|
|
1871
|
-
platform: this.__platform,
|
|
1872
|
-
handle: this.__handle,
|
|
1873
|
-
...this.__displayName ? { displayName: this.__displayName } : {},
|
|
1874
|
-
version: 1
|
|
1875
|
-
};
|
|
1876
|
-
}
|
|
1877
|
-
decorate(_editor, _config) {
|
|
1878
|
-
return createRendererDecoration("Mention", MentionRenderer, {
|
|
1879
|
-
platform: this.__platform,
|
|
1880
|
-
handle: this.__handle,
|
|
1881
|
-
displayName: this.__displayName
|
|
1882
|
-
});
|
|
1883
|
-
}
|
|
1884
|
-
};
|
|
1885
|
-
__publicField(_MentionNode, "slashMenuItems", [
|
|
1886
|
-
{
|
|
1887
|
-
title: "Mention",
|
|
1888
|
-
icon: createElement(
|
|
1889
|
-
"span",
|
|
1890
|
-
{ style: { fontSize: 16, fontWeight: 700 } },
|
|
1891
|
-
"@"
|
|
1892
|
-
),
|
|
1893
|
-
description: "Mention a social account",
|
|
1894
|
-
keywords: ["mention", "at", "@", "github", "twitter"],
|
|
1895
|
-
section: "INLINE",
|
|
1896
|
-
onSelect: (editor) => {
|
|
1897
|
-
editor.update(() => {
|
|
1898
|
-
const selection = $getSelection();
|
|
1899
|
-
if ($isRangeSelection(selection)) {
|
|
1900
|
-
selection.insertText("@");
|
|
1901
|
-
}
|
|
1902
|
-
});
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
|
-
]);
|
|
1906
|
-
let MentionNode = _MentionNode;
|
|
1907
|
-
function $createMentionNode(platform, handle, displayName) {
|
|
1908
|
-
return new MentionNode(platform, handle, displayName);
|
|
1909
|
-
}
|
|
1910
|
-
function $isMentionNode(node) {
|
|
1911
|
-
return node instanceof MentionNode;
|
|
1912
|
-
}
|
|
1913
|
-
function MermaidRenderer({ content }) {
|
|
1914
|
-
return /* @__PURE__ */ jsx("div", { className: "rich-mermaid-block", children: /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: content }) }) });
|
|
1915
|
-
}
|
|
1916
|
-
const _MermaidNode = class _MermaidNode extends DecoratorNode {
|
|
1917
|
-
constructor(diagram, key) {
|
|
1918
|
-
super(key);
|
|
1919
|
-
__publicField(this, "__diagram");
|
|
1920
|
-
this.__diagram = diagram;
|
|
1921
|
-
}
|
|
1922
|
-
static getType() {
|
|
1923
|
-
return "mermaid";
|
|
1924
|
-
}
|
|
1925
|
-
static clone(node) {
|
|
1926
|
-
return new _MermaidNode(node.__diagram, node.__key);
|
|
1927
|
-
}
|
|
1928
|
-
createDOM(_config) {
|
|
1929
|
-
const div = document.createElement("div");
|
|
1930
|
-
div.className = "rich-mermaid-wrapper";
|
|
1931
|
-
return div;
|
|
1932
|
-
}
|
|
1933
|
-
updateDOM() {
|
|
1934
|
-
return false;
|
|
1935
|
-
}
|
|
1936
|
-
isInline() {
|
|
1937
|
-
return false;
|
|
1938
|
-
}
|
|
1939
|
-
static importJSON(serializedNode) {
|
|
1940
|
-
return $createMermaidNode(serializedNode.diagram);
|
|
1941
|
-
}
|
|
1942
|
-
exportJSON() {
|
|
1943
|
-
return {
|
|
1944
|
-
...super.exportJSON(),
|
|
1945
|
-
type: "mermaid",
|
|
1946
|
-
diagram: this.__diagram,
|
|
1947
|
-
version: 1
|
|
1948
|
-
};
|
|
1949
|
-
}
|
|
1950
|
-
getDiagram() {
|
|
1951
|
-
return this.__diagram;
|
|
1952
|
-
}
|
|
1953
|
-
setDiagram(diagram) {
|
|
1954
|
-
const writable = this.getWritable();
|
|
1955
|
-
writable.__diagram = diagram;
|
|
1956
|
-
}
|
|
1957
|
-
decorate(editor, _config) {
|
|
1958
|
-
const nodeKey = this.__key;
|
|
1959
|
-
return createRendererDecoration("Mermaid", MermaidRenderer, {
|
|
1960
|
-
content: this.__diagram,
|
|
1961
|
-
onContentChange: (newDiagram) => {
|
|
1962
|
-
editor.update(() => {
|
|
1963
|
-
const node = $getNodeByKey(nodeKey);
|
|
1964
|
-
if (node) {
|
|
1965
|
-
node.setDiagram(newDiagram);
|
|
1966
|
-
}
|
|
1967
|
-
});
|
|
1968
|
-
}
|
|
1969
|
-
});
|
|
1970
|
-
}
|
|
1971
|
-
};
|
|
1972
|
-
__publicField(_MermaidNode, "commandItems", [
|
|
1973
|
-
{
|
|
1974
|
-
title: "Mermaid Diagram",
|
|
1975
|
-
icon: createElement(Workflow, { size: 20 }),
|
|
1976
|
-
description: "Flowchart, sequence diagram",
|
|
1977
|
-
keywords: ["mermaid", "diagram", "chart", "flowchart"],
|
|
1978
|
-
section: "MEDIA",
|
|
1979
|
-
placement: ["slash", "toolbar"],
|
|
1980
|
-
group: "insert",
|
|
1981
|
-
onSelect: (editor) => {
|
|
1982
|
-
editor.update(() => {
|
|
1983
|
-
$insertNodes([
|
|
1984
|
-
$createMermaidNode("graph TD\n A[Start] --> B[End]")
|
|
1985
|
-
]);
|
|
1986
|
-
});
|
|
1987
|
-
}
|
|
1988
|
-
}
|
|
1989
|
-
]);
|
|
1990
|
-
let MermaidNode = _MermaidNode;
|
|
1991
|
-
function $createMermaidNode(diagram) {
|
|
1992
|
-
return new MermaidNode(diagram);
|
|
1993
|
-
}
|
|
1994
|
-
function $isMermaidNode(node) {
|
|
1995
|
-
return node instanceof MermaidNode;
|
|
1996
|
-
}
|
|
1997
|
-
function readBaseTextFromRuby(element) {
|
|
1998
|
-
let base = "";
|
|
1999
|
-
for (const child of Array.from(element.childNodes)) {
|
|
2000
|
-
if (child.nodeType === Node.TEXT_NODE) {
|
|
2001
|
-
base += child.textContent ?? "";
|
|
2002
|
-
continue;
|
|
2003
|
-
}
|
|
2004
|
-
if (child.nodeType !== Node.ELEMENT_NODE) continue;
|
|
2005
|
-
const childElement = child;
|
|
2006
|
-
const tag = childElement.tagName.toLowerCase();
|
|
2007
|
-
if (tag === "rt" || tag === "rp") continue;
|
|
2008
|
-
base += childElement.textContent ?? "";
|
|
2009
|
-
}
|
|
2010
|
-
return base;
|
|
2011
|
-
}
|
|
2012
|
-
class RubyNode extends ElementNode {
|
|
2013
|
-
constructor(reading, key) {
|
|
2014
|
-
super(key);
|
|
2015
|
-
__publicField(this, "__reading");
|
|
2016
|
-
this.__reading = reading;
|
|
2017
|
-
}
|
|
2018
|
-
static getType() {
|
|
2019
|
-
return "ruby";
|
|
2020
|
-
}
|
|
2021
|
-
static clone(node) {
|
|
2022
|
-
return new RubyNode(node.__reading, node.__key);
|
|
2023
|
-
}
|
|
2024
|
-
static importJSON(serializedNode) {
|
|
2025
|
-
return $createRubyNode(serializedNode.reading ?? "");
|
|
2026
|
-
}
|
|
2027
|
-
exportJSON() {
|
|
2028
|
-
return {
|
|
2029
|
-
...super.exportJSON(),
|
|
2030
|
-
type: "ruby",
|
|
2031
|
-
reading: this.__reading,
|
|
2032
|
-
version: 1
|
|
2033
|
-
};
|
|
2034
|
-
}
|
|
2035
|
-
static importDOM() {
|
|
2036
|
-
return {
|
|
2037
|
-
ruby: () => ({
|
|
2038
|
-
conversion: (domNode) => {
|
|
2039
|
-
if (!(domNode instanceof HTMLElement)) return null;
|
|
2040
|
-
const reading = domNode.querySelector("rt")?.textContent ?? "";
|
|
2041
|
-
const baseText = readBaseTextFromRuby(domNode);
|
|
2042
|
-
const node = $createRubyNode(reading);
|
|
2043
|
-
if (baseText) {
|
|
2044
|
-
node.append($createTextNode(baseText));
|
|
2045
|
-
}
|
|
2046
|
-
return { node };
|
|
2047
|
-
},
|
|
2048
|
-
priority: 2
|
|
2049
|
-
})
|
|
2050
|
-
};
|
|
2051
|
-
}
|
|
2052
|
-
exportDOM() {
|
|
2053
|
-
const ruby = document.createElement("ruby");
|
|
2054
|
-
ruby.className = "rich-ruby";
|
|
2055
|
-
const baseText = this.getTextContent();
|
|
2056
|
-
if (baseText) {
|
|
2057
|
-
ruby.append(baseText);
|
|
2058
|
-
}
|
|
2059
|
-
if (this.__reading) {
|
|
2060
|
-
const rt = document.createElement("rt");
|
|
2061
|
-
rt.className = "rich-ruby-rt";
|
|
2062
|
-
rt.textContent = this.__reading;
|
|
2063
|
-
ruby.append(rt);
|
|
2064
|
-
}
|
|
2065
|
-
return { element: ruby };
|
|
2066
|
-
}
|
|
2067
|
-
createDOM(_config) {
|
|
2068
|
-
const span = document.createElement("span");
|
|
2069
|
-
span.className = "rich-ruby";
|
|
2070
|
-
if (this.__reading) {
|
|
2071
|
-
span.dataset.ruby = this.__reading;
|
|
2072
|
-
}
|
|
2073
|
-
return span;
|
|
2074
|
-
}
|
|
2075
|
-
updateDOM(prevNode, dom) {
|
|
2076
|
-
if (prevNode.__reading !== this.__reading) {
|
|
2077
|
-
if (this.__reading) {
|
|
2078
|
-
dom.dataset.ruby = this.__reading;
|
|
2079
|
-
} else {
|
|
2080
|
-
delete dom.dataset.ruby;
|
|
2081
|
-
}
|
|
2082
|
-
}
|
|
2083
|
-
return false;
|
|
2084
|
-
}
|
|
2085
|
-
canInsertTextBefore() {
|
|
2086
|
-
return true;
|
|
2087
|
-
}
|
|
2088
|
-
canInsertTextAfter() {
|
|
2089
|
-
return true;
|
|
2090
|
-
}
|
|
2091
|
-
isInline() {
|
|
2092
|
-
return true;
|
|
2093
|
-
}
|
|
2094
|
-
getReading() {
|
|
2095
|
-
return this.getLatest().__reading;
|
|
2096
|
-
}
|
|
2097
|
-
setReading(reading) {
|
|
2098
|
-
const writable = this.getWritable();
|
|
2099
|
-
writable.__reading = reading;
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
function $createRubyNode(reading) {
|
|
2103
|
-
return new RubyNode(reading);
|
|
2104
|
-
}
|
|
2105
|
-
function $isRubyNode(node) {
|
|
2106
|
-
return node instanceof RubyNode;
|
|
2107
|
-
}
|
|
2108
|
-
class SpoilerNode extends ElementNode {
|
|
2109
|
-
static getType() {
|
|
2110
|
-
return "spoiler";
|
|
2111
|
-
}
|
|
2112
|
-
static clone(node) {
|
|
2113
|
-
return new SpoilerNode(node.__key);
|
|
2114
|
-
}
|
|
2115
|
-
constructor(key) {
|
|
2116
|
-
super(key);
|
|
2117
|
-
}
|
|
2118
|
-
createDOM(_config) {
|
|
2119
|
-
const span = document.createElement("span");
|
|
2120
|
-
span.className = "rich-spoiler";
|
|
2121
|
-
span.setAttribute("role", "button");
|
|
2122
|
-
span.setAttribute("tabindex", "0");
|
|
2123
|
-
span.setAttribute("aria-label", "Spoiler (click to reveal)");
|
|
2124
|
-
const toggle = () => {
|
|
2125
|
-
if (span.isContentEditable) return;
|
|
2126
|
-
const revealed = span.classList.toggle("rich-spoiler-revealed");
|
|
2127
|
-
span.setAttribute(
|
|
2128
|
-
"aria-label",
|
|
2129
|
-
revealed ? "Spoiler (revealed)" : "Spoiler (click to reveal)"
|
|
2130
|
-
);
|
|
2131
|
-
};
|
|
2132
|
-
span.addEventListener("click", toggle);
|
|
2133
|
-
span.addEventListener("keydown", (e) => {
|
|
2134
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
2135
|
-
e.preventDefault();
|
|
2136
|
-
toggle();
|
|
2137
|
-
}
|
|
2138
|
-
});
|
|
2139
|
-
return span;
|
|
2140
|
-
}
|
|
2141
|
-
updateDOM() {
|
|
2142
|
-
return false;
|
|
2143
|
-
}
|
|
2144
|
-
static importJSON(_serializedNode) {
|
|
2145
|
-
return $createSpoilerNode();
|
|
2146
|
-
}
|
|
2147
|
-
exportJSON() {
|
|
2148
|
-
return {
|
|
2149
|
-
...super.exportJSON(),
|
|
2150
|
-
type: "spoiler",
|
|
2151
|
-
version: 1
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
|
-
canInsertTextBefore() {
|
|
2155
|
-
return true;
|
|
2156
|
-
}
|
|
2157
|
-
canInsertTextAfter() {
|
|
2158
|
-
return true;
|
|
2159
|
-
}
|
|
2160
|
-
isInline() {
|
|
2161
|
-
return true;
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2164
|
-
function $createSpoilerNode() {
|
|
2165
|
-
return new SpoilerNode();
|
|
2166
|
-
}
|
|
2167
|
-
function VideoRenderer({
|
|
2168
|
-
src,
|
|
2169
|
-
poster,
|
|
2170
|
-
width,
|
|
2171
|
-
height
|
|
2172
|
-
}) {
|
|
2173
|
-
return /* @__PURE__ */ jsx("figure", { className: "rich-video", children: /* @__PURE__ */ jsx(
|
|
2174
|
-
"video",
|
|
2175
|
-
{
|
|
2176
|
-
src,
|
|
2177
|
-
poster,
|
|
2178
|
-
width,
|
|
2179
|
-
height,
|
|
2180
|
-
controls: true,
|
|
2181
|
-
preload: "metadata",
|
|
2182
|
-
style: { maxWidth: "100%", height: "auto" }
|
|
2183
|
-
}
|
|
2184
|
-
) });
|
|
2185
|
-
}
|
|
2186
|
-
const _VideoNode = class _VideoNode extends DecoratorNode {
|
|
2187
|
-
constructor(payload, key) {
|
|
2188
|
-
super(key);
|
|
2189
|
-
__publicField(this, "__src");
|
|
2190
|
-
__publicField(this, "__poster");
|
|
2191
|
-
__publicField(this, "__width");
|
|
2192
|
-
__publicField(this, "__height");
|
|
2193
|
-
this.__src = payload.src;
|
|
2194
|
-
this.__poster = payload.poster;
|
|
2195
|
-
this.__width = payload.width;
|
|
2196
|
-
this.__height = payload.height;
|
|
2197
|
-
}
|
|
2198
|
-
static getType() {
|
|
2199
|
-
return "video";
|
|
2200
|
-
}
|
|
2201
|
-
static clone(node) {
|
|
2202
|
-
return new _VideoNode(
|
|
2203
|
-
{
|
|
2204
|
-
src: node.__src,
|
|
2205
|
-
poster: node.__poster,
|
|
2206
|
-
width: node.__width,
|
|
2207
|
-
height: node.__height
|
|
2208
|
-
},
|
|
2209
|
-
node.__key
|
|
2210
|
-
);
|
|
2211
|
-
}
|
|
2212
|
-
createDOM(_config) {
|
|
2213
|
-
const div = document.createElement("div");
|
|
2214
|
-
div.className = "rich-video-wrapper";
|
|
2215
|
-
return div;
|
|
2216
|
-
}
|
|
2217
|
-
updateDOM() {
|
|
2218
|
-
return false;
|
|
2219
|
-
}
|
|
2220
|
-
isInline() {
|
|
2221
|
-
return false;
|
|
2222
|
-
}
|
|
2223
|
-
static importJSON(serializedNode) {
|
|
2224
|
-
return $createVideoNode({
|
|
2225
|
-
src: serializedNode.src,
|
|
2226
|
-
poster: serializedNode.poster,
|
|
2227
|
-
width: serializedNode.width,
|
|
2228
|
-
height: serializedNode.height
|
|
2229
|
-
});
|
|
2230
|
-
}
|
|
2231
|
-
exportJSON() {
|
|
2232
|
-
return {
|
|
2233
|
-
...super.exportJSON(),
|
|
2234
|
-
type: "video",
|
|
2235
|
-
src: this.__src,
|
|
2236
|
-
poster: this.__poster,
|
|
2237
|
-
width: this.__width,
|
|
2238
|
-
height: this.__height,
|
|
2239
|
-
version: 1
|
|
2240
|
-
};
|
|
2241
|
-
}
|
|
2242
|
-
getSrc() {
|
|
2243
|
-
return this.getLatest().__src;
|
|
2244
|
-
}
|
|
2245
|
-
setSrc(src) {
|
|
2246
|
-
const writable = this.getWritable();
|
|
2247
|
-
writable.__src = src;
|
|
2248
|
-
}
|
|
2249
|
-
decorate(_editor, _config) {
|
|
2250
|
-
return createRendererDecoration("Video", VideoRenderer, {
|
|
2251
|
-
src: this.__src,
|
|
2252
|
-
poster: this.__poster,
|
|
2253
|
-
width: this.__width,
|
|
2254
|
-
height: this.__height
|
|
2255
|
-
});
|
|
2256
|
-
}
|
|
2257
|
-
};
|
|
2258
|
-
__publicField(_VideoNode, "commandItems", [
|
|
2259
|
-
{
|
|
2260
|
-
title: "Video",
|
|
2261
|
-
icon: createElement(Video, { size: 20 }),
|
|
2262
|
-
description: "Embed a video",
|
|
2263
|
-
keywords: ["video", "media", "mp4"],
|
|
2264
|
-
section: "MEDIA",
|
|
2265
|
-
placement: ["slash", "toolbar"],
|
|
2266
|
-
group: "insert",
|
|
2267
|
-
onSelect: (editor) => {
|
|
2268
|
-
editor.update(() => {
|
|
2269
|
-
$insertNodes([$createVideoNode({ src: "" })]);
|
|
2270
|
-
});
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
]);
|
|
2274
|
-
let VideoNode = _VideoNode;
|
|
2275
|
-
function $createVideoNode(payload) {
|
|
2276
|
-
return new VideoNode(payload);
|
|
2277
|
-
}
|
|
2278
|
-
const builtinNodes = [
|
|
2279
|
-
HeadingNode,
|
|
2280
|
-
QuoteNode,
|
|
2281
|
-
ListNode,
|
|
2282
|
-
ListItemNode,
|
|
2283
|
-
LinkNode,
|
|
2284
|
-
AutoLinkNode,
|
|
2285
|
-
HorizontalRuleNode,
|
|
2286
|
-
TableNode,
|
|
2287
|
-
TableCellNode,
|
|
2288
|
-
TableRowNode,
|
|
2289
|
-
CodeNode
|
|
2290
|
-
];
|
|
2291
|
-
const customNodes = [
|
|
2292
|
-
SpoilerNode,
|
|
2293
|
-
MentionNode,
|
|
2294
|
-
KaTeXInlineNode,
|
|
2295
|
-
KaTeXBlockNode,
|
|
2296
|
-
ImageNode,
|
|
2297
|
-
AlertQuoteNode,
|
|
2298
|
-
CodeBlockNode,
|
|
2299
|
-
FootnoteNode,
|
|
2300
|
-
FootnoteSectionNode,
|
|
2301
|
-
VideoNode,
|
|
2302
|
-
LinkCardNode,
|
|
2303
|
-
DetailsNode,
|
|
2304
|
-
GridContainerNode,
|
|
2305
|
-
BannerNode,
|
|
2306
|
-
MermaidNode,
|
|
2307
|
-
RubyNode
|
|
2308
|
-
];
|
|
2309
|
-
const allNodes = [
|
|
2310
|
-
...builtinNodes,
|
|
2311
|
-
...customNodes
|
|
2312
|
-
];
|
|
2313
|
-
const editorTheme = {
|
|
2314
|
-
text: {
|
|
2315
|
-
bold: "rich-text-bold",
|
|
2316
|
-
italic: "rich-text-italic",
|
|
2317
|
-
underline: "rich-text-underline",
|
|
2318
|
-
strikethrough: "rich-text-strikethrough",
|
|
2319
|
-
superscript: "rich-text-superscript",
|
|
2320
|
-
subscript: "rich-text-subscript",
|
|
2321
|
-
code: "rich-text-code",
|
|
2322
|
-
highlight: "rich-text-highlight"
|
|
2323
|
-
},
|
|
2324
|
-
heading: {
|
|
2325
|
-
h1: "rich-heading-h1",
|
|
2326
|
-
h2: "rich-heading-h2",
|
|
2327
|
-
h3: "rich-heading-h3",
|
|
2328
|
-
h4: "rich-heading-h4",
|
|
2329
|
-
h5: "rich-heading-h5",
|
|
2330
|
-
h6: "rich-heading-h6"
|
|
2331
|
-
},
|
|
2332
|
-
list: {
|
|
2333
|
-
ol: "rich-list-ol",
|
|
2334
|
-
ul: "rich-list-ul",
|
|
2335
|
-
listitem: "rich-list-item",
|
|
2336
|
-
listitemChecked: "rich-list-item-checked",
|
|
2337
|
-
listitemUnchecked: "rich-list-item-unchecked",
|
|
2338
|
-
checklist: "rich-checklist",
|
|
2339
|
-
nested: {
|
|
2340
|
-
listitem: "rich-list-nested-item"
|
|
2341
|
-
}
|
|
2342
|
-
},
|
|
2343
|
-
quote: "rich-quote",
|
|
2344
|
-
link: "rich-link",
|
|
2345
|
-
paragraph: "rich-paragraph",
|
|
2346
|
-
code: "rich-code-block",
|
|
2347
|
-
table: "rich-table",
|
|
2348
|
-
tableCell: "rich-table-cell",
|
|
2349
|
-
tableCellHeader: "rich-table-cell-header",
|
|
2350
|
-
tableScrollableWrapper: "rich-table-scrollable-wrapper",
|
|
2351
|
-
/** Used by @lexical/extension HorizontalRuleNode */
|
|
2352
|
-
hr: "rich-hr"
|
|
2353
|
-
};
|
|
2354
|
-
const FAVICON_VARIANTS = [
|
|
2355
|
-
"/favicon.ico",
|
|
2356
|
-
"/favicon.png",
|
|
2357
|
-
"/favicon.svg",
|
|
2358
|
-
"/apple-touch-icon.png",
|
|
2359
|
-
"/apple-touch-icon-precomposed.png"
|
|
2360
|
-
];
|
|
2361
|
-
const faviconCache = /* @__PURE__ */ new Map();
|
|
2362
|
-
function getHostname(href) {
|
|
2363
|
-
try {
|
|
2364
|
-
const url = new URL(href);
|
|
2365
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
2366
|
-
return url.hostname;
|
|
2367
|
-
} catch {
|
|
2368
|
-
return null;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
function probeImage(url) {
|
|
2372
|
-
return new Promise((resolve) => {
|
|
2373
|
-
const img = new Image();
|
|
2374
|
-
img.onload = () => resolve(url);
|
|
2375
|
-
img.onerror = () => resolve(null);
|
|
2376
|
-
img.src = url;
|
|
2377
|
-
});
|
|
2378
|
-
}
|
|
2379
|
-
async function probeFavicon(hostname) {
|
|
2380
|
-
const cached = faviconCache.get(hostname);
|
|
2381
|
-
if (cached !== void 0) return cached;
|
|
2382
|
-
for (const variant of FAVICON_VARIANTS) {
|
|
2383
|
-
const url = `https://${hostname}${variant}`;
|
|
2384
|
-
const result = await probeImage(url);
|
|
2385
|
-
if (result) {
|
|
2386
|
-
faviconCache.set(hostname, result);
|
|
2387
|
-
return result;
|
|
2388
|
-
}
|
|
2389
|
-
}
|
|
2390
|
-
faviconCache.set(hostname, null);
|
|
2391
|
-
return null;
|
|
2392
|
-
}
|
|
2393
|
-
export {
|
|
2394
|
-
$createFootnoteSectionNode as $,
|
|
2395
|
-
$isImageNode as A,
|
|
2396
|
-
$isKaTeXBlockNode as B,
|
|
2397
|
-
ColorSchemeProvider as C,
|
|
2398
|
-
$isKaTeXInlineNode as D,
|
|
2399
|
-
$isLinkCardNode as E,
|
|
2400
|
-
FootnoteDefinitionsProvider as F,
|
|
2401
|
-
$isMentionNode as G,
|
|
2402
|
-
$isMermaidNode as H,
|
|
2403
|
-
$isRubyNode as I,
|
|
2404
|
-
ALERT_LABELS as J,
|
|
2405
|
-
ALERT_TYPES as K,
|
|
2406
|
-
BANNER_LABELS as L,
|
|
2407
|
-
BANNER_TYPES as M,
|
|
2408
|
-
NestedContentRendererProvider as N,
|
|
2409
|
-
FootnoteSectionNode as O,
|
|
2410
|
-
FootnoteStaticRenderer as P,
|
|
2411
|
-
GridContainerNode as Q,
|
|
2412
|
-
RendererConfigProvider as R,
|
|
2413
|
-
ImageNode as S,
|
|
2414
|
-
KaTeXBlockNode as T,
|
|
2415
|
-
KaTeXInlineNode as U,
|
|
2416
|
-
KaTeXRenderer as V,
|
|
2417
|
-
LinkCardNode as W,
|
|
2418
|
-
LinkCardRenderer as X,
|
|
2419
|
-
MentionNode as Y,
|
|
2420
|
-
MermaidNode as Z,
|
|
2421
|
-
OPEN_IMAGE_UPLOAD_DIALOG_COMMAND as _,
|
|
2422
|
-
allNodes as a,
|
|
2423
|
-
RubyNode as a0,
|
|
2424
|
-
computeImageMeta as a1,
|
|
2425
|
-
decodeThumbHash as a2,
|
|
2426
|
-
$isAlertQuoteNode as a3,
|
|
2427
|
-
AlertRenderer as a4,
|
|
2428
|
-
SpoilerNode as a5,
|
|
2429
|
-
FootnoteNode as a6,
|
|
2430
|
-
AlertQuoteNode as a7,
|
|
2431
|
-
$isBannerNode as a8,
|
|
2432
|
-
BannerRenderer as a9,
|
|
2433
|
-
BannerNode as aa,
|
|
2434
|
-
normalizeBannerType as ab,
|
|
2435
|
-
$isCodeBlockNode as ac,
|
|
2436
|
-
CodeBlockRenderer as ad,
|
|
2437
|
-
CodeBlockNode as ae,
|
|
2438
|
-
VideoNode as af,
|
|
2439
|
-
DetailsNode as ag,
|
|
2440
|
-
$createKaTeXInlineNode as ah,
|
|
2441
|
-
$createKaTeXBlockNode as ai,
|
|
2442
|
-
$createDetailsNode as aj,
|
|
2443
|
-
$createFootnoteNode as ak,
|
|
2444
|
-
$createSpoilerNode as al,
|
|
2445
|
-
builtinNodes as b,
|
|
2446
|
-
customNodes as c,
|
|
2447
|
-
RendererWrapper as d,
|
|
2448
|
-
createRendererDecoration as e,
|
|
2449
|
-
editorTheme as f,
|
|
2450
|
-
extractTextContent as g,
|
|
2451
|
-
useFootnoteContent as h,
|
|
2452
|
-
useFootnoteDefinitions as i,
|
|
2453
|
-
useFootnoteDisplayNumber as j,
|
|
2454
|
-
useNestedContentRenderer as k,
|
|
2455
|
-
useOptionalNestedContentRenderer as l,
|
|
2456
|
-
useRendererConfig as m,
|
|
2457
|
-
useRendererMode as n,
|
|
2458
|
-
useVariant as o,
|
|
2459
|
-
getHostname as p,
|
|
2460
|
-
probeFavicon as q,
|
|
2461
|
-
$createGridContainerNode as r,
|
|
2462
|
-
$createImageNode as s,
|
|
2463
|
-
$createLinkCardNode as t,
|
|
2464
|
-
useColorScheme as u,
|
|
2465
|
-
$createMentionNode as v,
|
|
2466
|
-
$createMermaidNode as w,
|
|
2467
|
-
$createRubyNode as x,
|
|
2468
|
-
$isFootnoteSectionNode as y,
|
|
2469
|
-
$isGridContainerNode as z
|
|
2470
|
-
};
|