@haklex/rich-editor 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AlertQuoteEditNode-C55sxsR3.js +267 -0
- package/dist/KaTeXRenderer-CQQT3BMw.js +215 -0
- package/dist/LinkCardRenderer-CigqFwCv.js +45 -0
- package/dist/MermaidPlugin-BrOr-wQi.js +67 -0
- package/dist/RubyRenderer-jOkydJHg.js +15 -0
- package/dist/SubmitShortcutPlugin-DhyVFzoj.js +2186 -0
- package/dist/commands-entry.mjs +54 -74
- package/dist/components/decorators/PollEditDecorator.d.ts +13 -0
- package/dist/components/decorators/PollEditDecorator.d.ts.map +1 -0
- package/dist/components/renderers/PollRenderer.d.ts +3 -0
- package/dist/components/renderers/PollRenderer.d.ts.map +1 -0
- package/dist/config-B5BuLljq.js +1633 -0
- package/dist/config-edit.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/context/PollDataContext.d.ts +11 -0
- package/dist/context/PollDataContext.d.ts.map +1 -0
- package/dist/extractPolls-DO31LNrp.js +116 -0
- package/dist/grid.css-CJCkLTZc.js +44 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +121 -180
- package/dist/katex.css-CIOEOXyd.js +145 -0
- package/dist/node-registry-Dz5OTkh4.js +946 -0
- package/dist/nodes/PollEditNode.d.ts +14 -0
- package/dist/nodes/PollEditNode.d.ts.map +1 -0
- package/dist/nodes/PollNode.d.ts +52 -0
- package/dist/nodes/PollNode.d.ts.map +1 -0
- package/dist/nodes-entry.d.ts +3 -0
- package/dist/nodes-entry.d.ts.map +1 -1
- package/dist/nodes-entry.mjs +5 -50
- package/dist/normalizeSerializedEditorState-B-1wmGzd.js +78 -0
- package/dist/plugins-entry.mjs +3 -28
- package/dist/renderers-entry.mjs +41 -61
- package/dist/rich-editor.css +2 -1
- package/dist/static-entry.d.ts +5 -0
- package/dist/static-entry.d.ts.map +1 -1
- package/dist/static-entry.mjs +16 -66
- package/dist/styles/index.d.ts +2 -0
- package/dist/styles/index.d.ts.map +1 -1
- package/dist/styles/poll-edit.css.d.ts +35 -0
- package/dist/styles/poll-edit.css.d.ts.map +1 -0
- package/dist/styles/poll.css.d.ts +43 -0
- package/dist/styles/poll.css.d.ts.map +1 -0
- package/dist/styles-entry.mjs +3 -21
- package/dist/theme-B5B2EOWM.js +1099 -0
- package/dist/types/poll.d.ts +36 -0
- package/dist/types/poll.d.ts.map +1 -0
- package/dist/types/renderer-config.d.ts +3 -0
- package/dist/types/renderer-config.d.ts.map +1 -1
- package/dist/utils/extractPolls.d.ts +4 -0
- package/dist/utils/extractPolls.d.ts.map +1 -0
- package/package.json +30 -30
- package/dist/AlertQuoteEditNode-sPNf3_7P.js +0 -293
- package/dist/KaTeXRenderer-CQyQzNTJ.js +0 -218
- package/dist/LinkCardRenderer-QmkOlyXb.js +0 -36
- package/dist/MermaidPlugin-DKuGUcCG.js +0 -101
- package/dist/PresentDialogContext-DRroMIoK.js +0 -71
- package/dist/RubyRenderer-CJQmODir.js +0 -14
- package/dist/SubmitShortcutPlugin-D9uKYHda.js +0 -2427
- package/dist/config-Dl3ZkytB.js +0 -1362
- package/dist/grid.css-Md5-Cfx_.js +0 -11
- package/dist/katex.css-Csc-7N7u.js +0 -28
- package/dist/node-registry-CovhHUB6.js +0 -824
- package/dist/normalizeSerializedEditorState-k5G4xSi9.js +0 -85
- package/dist/theme-lEwScxEX.js +0 -1113
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { A as AlertQuoteNode, D as $isAlertQuoteNode, E as FootnoteNode, N as AlertRenderer, _ as KaTeXInlineNode, c as SpoilerNode, i as TagNode, j as _defineProperty, m as MentionNode, t as editorTheme } from "./theme-B5B2EOWM.js";
|
|
2
|
+
import { l as RendererWrapper } from "./KaTeXRenderer-CQQT3BMw.js";
|
|
3
|
+
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
4
|
+
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
5
|
+
import { AutoLinkNode, LinkNode } from "@lexical/link";
|
|
6
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
7
|
+
import { createElement, useCallback, useEffect } from "react";
|
|
8
|
+
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
|
|
9
|
+
import { $createParagraphNode, $getNodeByKey, $getRoot, $getSelection, $insertNodes, $isParagraphNode, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, COMMAND_PRIORITY_HIGH, KEY_ARROW_DOWN_COMMAND, KEY_ENTER_COMMAND, createEditor } from "lexical";
|
|
10
|
+
import { HorizontalRuleNode } from "@lexical/extension";
|
|
11
|
+
import { CodeNode } from "@lexical/code-core";
|
|
12
|
+
import { ListItemNode, ListNode } from "@lexical/list";
|
|
13
|
+
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
|
|
14
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
import { Info, Lightbulb, TriangleAlert } from "lucide-react";
|
|
16
|
+
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
17
|
+
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
18
|
+
import { LexicalNestedComposer } from "@lexical/react/LexicalNestedComposer";
|
|
19
|
+
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
20
|
+
//#region src/components/decorators/AlertEditDecorator.tsx
|
|
21
|
+
function ExitBlockPlugin({ parentEditor, nodeKey }) {
|
|
22
|
+
const [editor] = useLexicalComposerContext();
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const focusParent = () => {
|
|
25
|
+
parentEditor.focus(() => {
|
|
26
|
+
parentEditor.update(() => {
|
|
27
|
+
const alertNode = $getNodeByKey(nodeKey);
|
|
28
|
+
if (alertNode) {
|
|
29
|
+
const next = alertNode.getNextSibling();
|
|
30
|
+
if (next) next.selectStart();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const exitAlert = (removeEmpty) => {
|
|
36
|
+
const root = $getRoot();
|
|
37
|
+
const lastChild = root.getLastChild();
|
|
38
|
+
const shouldRemoveAlert = removeEmpty && root.getChildrenSize() <= 1;
|
|
39
|
+
if (removeEmpty && lastChild) lastChild.remove();
|
|
40
|
+
if (shouldRemoveAlert) parentEditor.update(() => {
|
|
41
|
+
const alertNode = $getNodeByKey(nodeKey);
|
|
42
|
+
if (alertNode) {
|
|
43
|
+
const paragraph = $createParagraphNode();
|
|
44
|
+
alertNode.insertAfter(paragraph);
|
|
45
|
+
alertNode.remove();
|
|
46
|
+
paragraph.selectStart();
|
|
47
|
+
}
|
|
48
|
+
}, { onUpdate: focusParent });
|
|
49
|
+
else parentEditor.update(() => {
|
|
50
|
+
const alertNode = $getNodeByKey(nodeKey);
|
|
51
|
+
if (alertNode) {
|
|
52
|
+
let next = alertNode.getNextSibling();
|
|
53
|
+
if (!next || !$isParagraphNode(next)) {
|
|
54
|
+
next = $createParagraphNode();
|
|
55
|
+
alertNode.insertAfter(next);
|
|
56
|
+
}
|
|
57
|
+
next.selectStart();
|
|
58
|
+
}
|
|
59
|
+
}, { onUpdate: focusParent });
|
|
60
|
+
};
|
|
61
|
+
const isAtLastEmptyParagraph = () => {
|
|
62
|
+
const selection = $getSelection();
|
|
63
|
+
if (!$isRangeSelection(selection) || !selection.isCollapsed()) return false;
|
|
64
|
+
const topLevelElement = selection.anchor.getNode().getTopLevelElement();
|
|
65
|
+
return topLevelElement && $isParagraphNode(topLevelElement) && topLevelElement.getTextContent() === "" && topLevelElement.getNextSibling() === null;
|
|
66
|
+
};
|
|
67
|
+
const unregisterEnter = editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
68
|
+
if (event?.metaKey || event?.ctrlKey) {
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
exitAlert(false);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
if (!isAtLastEmptyParagraph()) return false;
|
|
74
|
+
event?.preventDefault();
|
|
75
|
+
exitAlert(true);
|
|
76
|
+
return true;
|
|
77
|
+
}, COMMAND_PRIORITY_CRITICAL);
|
|
78
|
+
const unregisterArrowDown = editor.registerCommand(KEY_ARROW_DOWN_COMMAND, (event) => {
|
|
79
|
+
if (!isAtLastEmptyParagraph()) return false;
|
|
80
|
+
event?.preventDefault();
|
|
81
|
+
exitAlert(false);
|
|
82
|
+
return true;
|
|
83
|
+
}, COMMAND_PRIORITY_HIGH);
|
|
84
|
+
return () => {
|
|
85
|
+
unregisterEnter();
|
|
86
|
+
unregisterArrowDown();
|
|
87
|
+
};
|
|
88
|
+
}, [
|
|
89
|
+
editor,
|
|
90
|
+
parentEditor,
|
|
91
|
+
nodeKey
|
|
92
|
+
]);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
function AlertEditDecorator({ nodeKey, alertType, contentEditor }) {
|
|
96
|
+
const [editor] = useLexicalComposerContext();
|
|
97
|
+
const editable = editor.isEditable();
|
|
98
|
+
const handleTypeChange = useCallback((newType) => {
|
|
99
|
+
editor.update(() => {
|
|
100
|
+
const node = $getNodeByKey(nodeKey);
|
|
101
|
+
if ($isAlertQuoteNode(node)) node.setAlertType(newType);
|
|
102
|
+
});
|
|
103
|
+
}, [editor, nodeKey]);
|
|
104
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(RendererWrapper, {
|
|
105
|
+
defaultRenderer: AlertRenderer,
|
|
106
|
+
rendererKey: "Alert",
|
|
107
|
+
props: {
|
|
108
|
+
type: alertType,
|
|
109
|
+
editable,
|
|
110
|
+
onTypeChange: editable ? handleTypeChange : void 0
|
|
111
|
+
}
|
|
112
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
113
|
+
className: "rich-alert-content",
|
|
114
|
+
children: /* @__PURE__ */ jsxs(LexicalNestedComposer, {
|
|
115
|
+
initialEditor: contentEditor,
|
|
116
|
+
children: [
|
|
117
|
+
/* @__PURE__ */ jsx(RichTextPlugin, {
|
|
118
|
+
ErrorBoundary: LexicalErrorBoundary,
|
|
119
|
+
contentEditable: /* @__PURE__ */ jsx(ContentEditable, {
|
|
120
|
+
"aria-placeholder": "",
|
|
121
|
+
className: "rich-alert-content-editable",
|
|
122
|
+
placeholder: /* @__PURE__ */ jsx("span", { style: { display: "none" } }),
|
|
123
|
+
style: { outline: "none" }
|
|
124
|
+
})
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ jsx(ListPlugin, {}),
|
|
127
|
+
/* @__PURE__ */ jsx(LinkPlugin, {}),
|
|
128
|
+
/* @__PURE__ */ jsx(ExitBlockPlugin, {
|
|
129
|
+
nodeKey,
|
|
130
|
+
parentEditor: editor
|
|
131
|
+
})
|
|
132
|
+
]
|
|
133
|
+
})
|
|
134
|
+
})] });
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/nodes/shared.ts
|
|
138
|
+
var NESTED_EDITOR_NODES = [
|
|
139
|
+
HeadingNode,
|
|
140
|
+
QuoteNode,
|
|
141
|
+
ListNode,
|
|
142
|
+
ListItemNode,
|
|
143
|
+
LinkNode,
|
|
144
|
+
AutoLinkNode,
|
|
145
|
+
HorizontalRuleNode,
|
|
146
|
+
CodeNode,
|
|
147
|
+
TableNode,
|
|
148
|
+
TableCellNode,
|
|
149
|
+
TableRowNode,
|
|
150
|
+
SpoilerNode,
|
|
151
|
+
MentionNode,
|
|
152
|
+
FootnoteNode,
|
|
153
|
+
KaTeXInlineNode,
|
|
154
|
+
TagNode
|
|
155
|
+
];
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/nodes/AlertQuoteEditNode.ts
|
|
158
|
+
function createContentEditor() {
|
|
159
|
+
return createEditor({
|
|
160
|
+
namespace: "AlertContent",
|
|
161
|
+
nodes: NESTED_EDITOR_NODES,
|
|
162
|
+
theme: editorTheme,
|
|
163
|
+
onError: (error) => {
|
|
164
|
+
console.error("[AlertContent]", error);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
var AlertQuoteEditNode = class AlertQuoteEditNode extends AlertQuoteNode {
|
|
169
|
+
static clone(node) {
|
|
170
|
+
const cloned = new AlertQuoteEditNode(node.__alertType, node.__contentState, node.__key);
|
|
171
|
+
cloned.__contentEditor = node.__contentEditor;
|
|
172
|
+
return cloned;
|
|
173
|
+
}
|
|
174
|
+
constructor(alertType, contentState, key) {
|
|
175
|
+
super(alertType, contentState, key);
|
|
176
|
+
_defineProperty(this, "__contentEditor", void 0);
|
|
177
|
+
this.__contentEditor = createContentEditor();
|
|
178
|
+
if (contentState) {
|
|
179
|
+
const editorState = this.__contentEditor.parseEditorState(contentState);
|
|
180
|
+
this.__contentEditor.setEditorState(editorState);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
getContentEditor() {
|
|
184
|
+
return this.__contentEditor;
|
|
185
|
+
}
|
|
186
|
+
static importJSON(serializedNode) {
|
|
187
|
+
return new AlertQuoteEditNode(serializedNode.alertType, serializedNode.content);
|
|
188
|
+
}
|
|
189
|
+
exportJSON() {
|
|
190
|
+
return {
|
|
191
|
+
...super.exportJSON(),
|
|
192
|
+
type: "alert-quote",
|
|
193
|
+
alertType: this.__alertType,
|
|
194
|
+
content: this.__contentEditor.getEditorState().toJSON(),
|
|
195
|
+
version: 1
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
decorate(_editor, _config) {
|
|
199
|
+
return createElement(AlertEditDecorator, {
|
|
200
|
+
nodeKey: this.__key,
|
|
201
|
+
alertType: this.__alertType,
|
|
202
|
+
contentEditor: this.__contentEditor
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
_defineProperty(AlertQuoteEditNode, "commandItems", [
|
|
207
|
+
{
|
|
208
|
+
title: "Callout",
|
|
209
|
+
icon: createElement(Info, { size: 20 }),
|
|
210
|
+
description: "Info callout block",
|
|
211
|
+
keywords: [
|
|
212
|
+
"alert",
|
|
213
|
+
"note",
|
|
214
|
+
"info",
|
|
215
|
+
"callout"
|
|
216
|
+
],
|
|
217
|
+
section: "ADVANCED",
|
|
218
|
+
placement: ["slash", "toolbar"],
|
|
219
|
+
group: "insert",
|
|
220
|
+
onSelect: (editor) => {
|
|
221
|
+
editor.update(() => {
|
|
222
|
+
$insertNodes([$createAlertQuoteEditNode("note")]);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
title: "Tip",
|
|
228
|
+
icon: createElement(Lightbulb, { size: 20 }),
|
|
229
|
+
description: "Highlight a useful tip",
|
|
230
|
+
keywords: [
|
|
231
|
+
"alert",
|
|
232
|
+
"tip",
|
|
233
|
+
"hint"
|
|
234
|
+
],
|
|
235
|
+
section: "ADVANCED",
|
|
236
|
+
placement: ["slash", "toolbar"],
|
|
237
|
+
group: "insert",
|
|
238
|
+
onSelect: (editor) => {
|
|
239
|
+
editor.update(() => {
|
|
240
|
+
$insertNodes([$createAlertQuoteEditNode("tip")]);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
title: "Warning",
|
|
246
|
+
icon: createElement(TriangleAlert, { size: 20 }),
|
|
247
|
+
description: "Warn about something",
|
|
248
|
+
keywords: [
|
|
249
|
+
"alert",
|
|
250
|
+
"warning",
|
|
251
|
+
"caution"
|
|
252
|
+
],
|
|
253
|
+
section: "ADVANCED",
|
|
254
|
+
placement: ["slash", "toolbar"],
|
|
255
|
+
group: "insert",
|
|
256
|
+
onSelect: (editor) => {
|
|
257
|
+
editor.update(() => {
|
|
258
|
+
$insertNodes([$createAlertQuoteEditNode("warning")]);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
]);
|
|
263
|
+
function $createAlertQuoteEditNode(alertType, contentState) {
|
|
264
|
+
return new AlertQuoteEditNode(alertType, contentState);
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
267
|
+
export { AlertQuoteEditNode as n, NESTED_EDITOR_NODES as r, $createAlertQuoteEditNode as t };
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { l as semanticClassNames, n as katexStyles, r as clsx, t as katexClassNames, u as sharedStyles } from "./katex.css-CIOEOXyd.js";
|
|
2
|
+
import { createContext, createElement, use, useCallback, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { rgbaToThumbHash, thumbHashToDataURL } from "thumbhash";
|
|
5
|
+
//#region src/context/RendererConfigContext.tsx
|
|
6
|
+
var RendererConfigContext = createContext({
|
|
7
|
+
config: void 0,
|
|
8
|
+
mode: "renderer",
|
|
9
|
+
variant: "article"
|
|
10
|
+
});
|
|
11
|
+
function RendererConfigProvider({ config, mode, variant, children }) {
|
|
12
|
+
const value = useMemo(() => ({
|
|
13
|
+
config,
|
|
14
|
+
mode,
|
|
15
|
+
variant
|
|
16
|
+
}), [
|
|
17
|
+
config,
|
|
18
|
+
mode,
|
|
19
|
+
variant
|
|
20
|
+
]);
|
|
21
|
+
return /* @__PURE__ */ jsx(RendererConfigContext.Provider, {
|
|
22
|
+
value,
|
|
23
|
+
children
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function useRendererConfig() {
|
|
27
|
+
return use(RendererConfigContext).config;
|
|
28
|
+
}
|
|
29
|
+
function useRendererMode() {
|
|
30
|
+
return use(RendererConfigContext).mode;
|
|
31
|
+
}
|
|
32
|
+
function useVariant() {
|
|
33
|
+
return use(RendererConfigContext).variant;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/components/RendererWrapper.tsx
|
|
37
|
+
/**
|
|
38
|
+
* Wrapper component that allows overriding default renderers with custom ones.
|
|
39
|
+
* Uses RendererConfig from context to determine which renderer to use.
|
|
40
|
+
*/
|
|
41
|
+
function RendererWrapper({ rendererKey, defaultRenderer: DefaultRenderer, props }) {
|
|
42
|
+
return /* @__PURE__ */ jsx(useRendererConfig()?.[rendererKey] ?? DefaultRenderer, { ...props });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Type-safe helper for creating RendererWrapper elements from .ts node files.
|
|
46
|
+
* Avoids the createElement + discriminated-union typing limitation.
|
|
47
|
+
*/
|
|
48
|
+
function createRendererDecoration(rendererKey, defaultRenderer, props) {
|
|
49
|
+
return createElement(RendererWrapper, {
|
|
50
|
+
rendererKey,
|
|
51
|
+
defaultRenderer,
|
|
52
|
+
props
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/context/FootnoteDefinitionsContext.tsx
|
|
57
|
+
var FootnoteDefinitionsContext = createContext({
|
|
58
|
+
definitions: {},
|
|
59
|
+
displayNumberMap: {}
|
|
60
|
+
});
|
|
61
|
+
function FootnoteDefinitionsProvider({ definitions, displayNumberMap, children }) {
|
|
62
|
+
return /* @__PURE__ */ jsx(FootnoteDefinitionsContext, {
|
|
63
|
+
value: useMemo(() => ({
|
|
64
|
+
definitions,
|
|
65
|
+
displayNumberMap
|
|
66
|
+
}), [definitions, displayNumberMap]),
|
|
67
|
+
children
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function useFootnoteDefinitions() {
|
|
71
|
+
return use(FootnoteDefinitionsContext);
|
|
72
|
+
}
|
|
73
|
+
function useFootnoteContent(identifier) {
|
|
74
|
+
const { definitions } = use(FootnoteDefinitionsContext);
|
|
75
|
+
return definitions[identifier];
|
|
76
|
+
}
|
|
77
|
+
function useFootnoteDisplayNumber(identifier) {
|
|
78
|
+
const { displayNumberMap } = use(FootnoteDefinitionsContext);
|
|
79
|
+
return displayNumberMap[identifier];
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/components/renderers/FootnoteStaticRenderer.tsx
|
|
83
|
+
function FootnoteStaticRenderer({ identifier }) {
|
|
84
|
+
const content = useFootnoteContent(identifier);
|
|
85
|
+
const displayNumber = useFootnoteDisplayNumber(identifier);
|
|
86
|
+
const referenceId = `footnote-ref-${identifier}`;
|
|
87
|
+
const targetId = `footnote-${identifier}`;
|
|
88
|
+
const handleClick = useCallback((e) => {
|
|
89
|
+
const target = document.getElementById(targetId) || document.getElementById(`fn-${identifier}`);
|
|
90
|
+
if (!target) return;
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
target.scrollIntoView({
|
|
93
|
+
behavior: "smooth",
|
|
94
|
+
block: "center"
|
|
95
|
+
});
|
|
96
|
+
target.classList.add(semanticClassNames.footnoteHighlight, sharedStyles.footnoteHighlight);
|
|
97
|
+
window.setTimeout(() => {
|
|
98
|
+
target.classList.remove(semanticClassNames.footnoteHighlight, sharedStyles.footnoteHighlight);
|
|
99
|
+
}, 1200);
|
|
100
|
+
}, [identifier, targetId]);
|
|
101
|
+
const label = displayNumber ?? identifier;
|
|
102
|
+
return /* @__PURE__ */ jsx("span", {
|
|
103
|
+
className: clsx(semanticClassNames.footnoteRefWrapper, sharedStyles.footnoteRefWrapper),
|
|
104
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
105
|
+
"aria-label": content ? `Footnote ${label}: ${content}` : `Footnote ${label}`,
|
|
106
|
+
className: clsx(semanticClassNames.footnoteRef, sharedStyles.footnoteRef),
|
|
107
|
+
"data-footnote-ref": identifier,
|
|
108
|
+
href: `#${targetId}`,
|
|
109
|
+
id: referenceId,
|
|
110
|
+
role: "doc-noteref",
|
|
111
|
+
onClick: handleClick,
|
|
112
|
+
children: label
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/utils/thumbhash.ts
|
|
118
|
+
var MAX_DIM = 100;
|
|
119
|
+
async function computeImageMeta(file) {
|
|
120
|
+
const url = URL.createObjectURL(file);
|
|
121
|
+
try {
|
|
122
|
+
const img = await loadImage(url);
|
|
123
|
+
const { naturalWidth: w, naturalHeight: h } = img;
|
|
124
|
+
const scale = Math.min(MAX_DIM / w, MAX_DIM / h, 1);
|
|
125
|
+
const sw = Math.round(w * scale);
|
|
126
|
+
const sh = Math.round(h * scale);
|
|
127
|
+
const canvas = document.createElement("canvas");
|
|
128
|
+
canvas.width = sw;
|
|
129
|
+
canvas.height = sh;
|
|
130
|
+
const ctx = canvas.getContext("2d");
|
|
131
|
+
ctx.drawImage(img, 0, 0, sw, sh);
|
|
132
|
+
const { data } = ctx.getImageData(0, 0, sw, sh);
|
|
133
|
+
return {
|
|
134
|
+
width: w,
|
|
135
|
+
height: h,
|
|
136
|
+
thumbhash: uint8ToBase64(rgbaToThumbHash(sw, sh, data))
|
|
137
|
+
};
|
|
138
|
+
} finally {
|
|
139
|
+
URL.revokeObjectURL(url);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function decodeThumbHash(hash) {
|
|
143
|
+
try {
|
|
144
|
+
return thumbHashToDataURL(base64ToUint8(hash));
|
|
145
|
+
} catch {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function loadImage(src) {
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const img = new Image();
|
|
152
|
+
img.onload = () => resolve(img);
|
|
153
|
+
img.onerror = reject;
|
|
154
|
+
img.src = src;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function uint8ToBase64(bytes) {
|
|
158
|
+
let bin = "";
|
|
159
|
+
for (const b of bytes) bin += String.fromCodePoint(b);
|
|
160
|
+
return btoa(bin);
|
|
161
|
+
}
|
|
162
|
+
function base64ToUint8(str) {
|
|
163
|
+
const bin = atob(str);
|
|
164
|
+
const bytes = new Uint8Array(bin.length);
|
|
165
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.codePointAt(i);
|
|
166
|
+
return bytes;
|
|
167
|
+
}
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/components/renderers/KaTeXRenderer.tsx
|
|
170
|
+
var katexModule = null;
|
|
171
|
+
var katexLoadPromise = null;
|
|
172
|
+
function loadKaTeX() {
|
|
173
|
+
if (katexModule) return Promise.resolve(katexModule);
|
|
174
|
+
if (!katexLoadPromise) katexLoadPromise = import("katex").then((mod) => {
|
|
175
|
+
katexModule = mod;
|
|
176
|
+
return katexModule;
|
|
177
|
+
});
|
|
178
|
+
return katexLoadPromise;
|
|
179
|
+
}
|
|
180
|
+
function KaTeXRenderer({ equation, displayMode }) {
|
|
181
|
+
const [html, setHtml] = useState(null);
|
|
182
|
+
const [error, setError] = useState(null);
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
let cancelled = false;
|
|
185
|
+
loadKaTeX().then((katex) => {
|
|
186
|
+
if (cancelled) return;
|
|
187
|
+
setHtml(katex.default.renderToString(equation, {
|
|
188
|
+
displayMode,
|
|
189
|
+
throwOnError: false
|
|
190
|
+
}));
|
|
191
|
+
setError(null);
|
|
192
|
+
}).catch(() => {
|
|
193
|
+
if (cancelled) return;
|
|
194
|
+
setHtml(null);
|
|
195
|
+
setError("KaTeX is not available");
|
|
196
|
+
});
|
|
197
|
+
return () => {
|
|
198
|
+
cancelled = true;
|
|
199
|
+
};
|
|
200
|
+
}, [equation, displayMode]);
|
|
201
|
+
if (error) return /* @__PURE__ */ jsx("code", {
|
|
202
|
+
className: clsx(katexClassNames.fallback, katexStyles.fallback),
|
|
203
|
+
children: equation
|
|
204
|
+
});
|
|
205
|
+
if (html) return /* @__PURE__ */ jsx("span", {
|
|
206
|
+
dangerouslySetInnerHTML: { __html: html },
|
|
207
|
+
className: displayMode ? clsx(katexClassNames.block, katexStyles.block) : clsx(katexClassNames.inline, katexStyles.inline)
|
|
208
|
+
});
|
|
209
|
+
return /* @__PURE__ */ jsx("code", {
|
|
210
|
+
className: clsx(katexClassNames.fallback, katexStyles.fallback),
|
|
211
|
+
children: equation
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
export { FootnoteDefinitionsProvider as a, useFootnoteDisplayNumber as c, RendererConfigProvider as d, useRendererConfig as f, FootnoteStaticRenderer as i, RendererWrapper as l, useVariant as m, computeImageMeta as n, useFootnoteContent as o, useRendererMode as p, decodeThumbHash as r, useFootnoteDefinitions as s, KaTeXRenderer as t, createRendererDecoration as u };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
//#region src/components/renderers/LinkCardRenderer.tsx
|
|
3
|
+
function LinkCardRenderer({ url, title, description, favicon, image }) {
|
|
4
|
+
return /* @__PURE__ */ jsxs("a", {
|
|
5
|
+
className: "rich-link-card",
|
|
6
|
+
href: url,
|
|
7
|
+
rel: "noopener noreferrer",
|
|
8
|
+
target: "_blank",
|
|
9
|
+
children: [image && /* @__PURE__ */ jsx("span", {
|
|
10
|
+
className: "rich-link-card-image",
|
|
11
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
12
|
+
alt: "",
|
|
13
|
+
loading: "lazy",
|
|
14
|
+
src: image
|
|
15
|
+
})
|
|
16
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
17
|
+
className: "rich-link-card-content",
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ jsxs("span", {
|
|
20
|
+
className: "rich-link-card-title",
|
|
21
|
+
children: [favicon && /* @__PURE__ */ jsx("img", {
|
|
22
|
+
alt: "",
|
|
23
|
+
className: "rich-link-card-favicon",
|
|
24
|
+
height: 16,
|
|
25
|
+
src: favicon,
|
|
26
|
+
width: 16,
|
|
27
|
+
onError: (e) => {
|
|
28
|
+
e.target.style.display = "none";
|
|
29
|
+
}
|
|
30
|
+
}), title || url]
|
|
31
|
+
}),
|
|
32
|
+
description && /* @__PURE__ */ jsx("span", {
|
|
33
|
+
className: "rich-link-card-description",
|
|
34
|
+
children: description
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ jsx("span", {
|
|
37
|
+
className: "rich-link-card-url",
|
|
38
|
+
children: url
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { LinkCardRenderer as t };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { h as $createKaTeXInlineNode, l as $createMermaidNode, v as $createKaTeXBlockNode, x as $createImageNode } from "./theme-B5B2EOWM.js";
|
|
2
|
+
import { t as $createAlertQuoteEditNode } from "./AlertQuoteEditNode-C55sxsR3.js";
|
|
3
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
import { $insertNodes, COMMAND_PRIORITY_EDITOR, createCommand } from "lexical";
|
|
6
|
+
//#region src/plugins/AlertPlugin.tsx
|
|
7
|
+
var INSERT_ALERT_COMMAND = createCommand("INSERT_ALERT");
|
|
8
|
+
function AlertPlugin() {
|
|
9
|
+
const [editor] = useLexicalComposerContext();
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
return editor.registerCommand(INSERT_ALERT_COMMAND, (alertType) => {
|
|
12
|
+
$insertNodes([$createAlertQuoteEditNode(alertType)]);
|
|
13
|
+
return true;
|
|
14
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
15
|
+
}, [editor]);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/plugins/ImagePlugin.tsx
|
|
20
|
+
var INSERT_IMAGE_COMMAND = createCommand("INSERT_IMAGE_COMMAND");
|
|
21
|
+
function ImagePlugin() {
|
|
22
|
+
const [editor] = useLexicalComposerContext();
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
return editor.registerCommand(INSERT_IMAGE_COMMAND, (payload) => {
|
|
25
|
+
$insertNodes([$createImageNode(payload)]);
|
|
26
|
+
return true;
|
|
27
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
28
|
+
}, [editor]);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/plugins/KaTeXPlugin.tsx
|
|
33
|
+
var INSERT_KATEX_INLINE_COMMAND = createCommand("INSERT_KATEX_INLINE");
|
|
34
|
+
var INSERT_KATEX_BLOCK_COMMAND = createCommand("INSERT_KATEX_BLOCK");
|
|
35
|
+
function KaTeXPlugin() {
|
|
36
|
+
const [editor] = useLexicalComposerContext();
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const unregisterInline = editor.registerCommand(INSERT_KATEX_INLINE_COMMAND, (equation) => {
|
|
39
|
+
$insertNodes([$createKaTeXInlineNode(equation, { autoOpenOnMount: !equation.trim() })]);
|
|
40
|
+
return true;
|
|
41
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
42
|
+
const unregisterBlock = editor.registerCommand(INSERT_KATEX_BLOCK_COMMAND, (equation) => {
|
|
43
|
+
$insertNodes([$createKaTeXBlockNode(equation, { autoOpenOnMount: !equation.trim() })]);
|
|
44
|
+
return true;
|
|
45
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
46
|
+
return () => {
|
|
47
|
+
unregisterInline();
|
|
48
|
+
unregisterBlock();
|
|
49
|
+
};
|
|
50
|
+
}, [editor]);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/plugins/MermaidPlugin.tsx
|
|
55
|
+
var INSERT_MERMAID_COMMAND = createCommand("INSERT_MERMAID");
|
|
56
|
+
function MermaidPlugin() {
|
|
57
|
+
const [editor] = useLexicalComposerContext();
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
return editor.registerCommand(INSERT_MERMAID_COMMAND, (diagram) => {
|
|
60
|
+
$insertNodes([$createMermaidNode(diagram)]);
|
|
61
|
+
return true;
|
|
62
|
+
}, COMMAND_PRIORITY_EDITOR);
|
|
63
|
+
}, [editor]);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { KaTeXPlugin as a, AlertPlugin as c, INSERT_KATEX_INLINE_COMMAND as i, INSERT_ALERT_COMMAND as l, MermaidPlugin as n, INSERT_IMAGE_COMMAND as o, INSERT_KATEX_BLOCK_COMMAND as r, ImagePlugin as s, INSERT_MERMAID_COMMAND as t };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { l as semanticClassNames, r as clsx, u as sharedStyles } from "./katex.css-CIOEOXyd.js";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/renderers/RubyRenderer.tsx
|
|
4
|
+
function RubyRenderer({ reading, children }) {
|
|
5
|
+
if (!reading) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
6
|
+
return /* @__PURE__ */ jsxs("ruby", {
|
|
7
|
+
className: clsx(semanticClassNames.ruby, sharedStyles.ruby),
|
|
8
|
+
children: [children, /* @__PURE__ */ jsx("rt", {
|
|
9
|
+
className: clsx(semanticClassNames.rubyRt, sharedStyles.rubyRt),
|
|
10
|
+
children: reading
|
|
11
|
+
})]
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { RubyRenderer as t };
|