@webround/editor 0.0.0-stage → 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/blocks.d.ts +90 -0
- package/dist/blocks.js +119 -0
- package/dist/bridge.d.ts +96 -0
- package/dist/bridge.js +970 -0
- package/dist/check/aria.d.ts +19 -0
- package/dist/check/aria.js +106 -0
- package/dist/check/cli.d.ts +3 -0
- package/dist/check/cli.js +30 -0
- package/dist/check/css.d.ts +13 -0
- package/dist/check/css.js +63 -0
- package/dist/check/html.d.ts +8 -0
- package/dist/check/html.js +29 -0
- package/dist/check/index.d.ts +4 -0
- package/dist/check/index.js +5 -0
- package/dist/check/links.d.ts +7 -0
- package/dist/check/links.js +23 -0
- package/dist/check/orphans.d.ts +20 -0
- package/dist/check/orphans.js +57 -0
- package/dist/check/producer-code.d.ts +53 -0
- package/dist/check/producer-code.js +379 -0
- package/dist/check/producer-dom.d.ts +21 -0
- package/dist/check/producer-dom.js +52 -0
- package/dist/check/project.d.ts +20 -0
- package/dist/check/project.js +51 -0
- package/dist/check/rules.d.ts +7 -0
- package/dist/check/rules.js +517 -0
- package/dist/check/types.d.ts +160 -0
- package/dist/check/types.js +22 -0
- package/dist/components/WrAltcha.d.ts +5 -0
- package/dist/components/WrAltcha.js +8 -0
- package/dist/components/WrButton.d.ts +8 -0
- package/dist/components/WrButton.js +34 -0
- package/dist/components/WrForm.d.ts +6 -0
- package/dist/components/WrForm.js +29 -0
- package/dist/components/WrFormPrivacy.d.ts +4 -0
- package/dist/components/WrFormPrivacy.js +7 -0
- package/dist/components/WrFormSuccess.d.ts +4 -0
- package/dist/components/WrFormSuccess.js +12 -0
- package/dist/components/WrIframe.d.ts +12 -0
- package/dist/components/WrIframe.js +30 -0
- package/dist/components/WrImage.d.ts +9 -0
- package/dist/components/WrImage.js +28 -0
- package/dist/components/WrInput.d.ts +8 -0
- package/dist/components/WrInput.js +29 -0
- package/dist/components/WrLink.d.ts +10 -0
- package/dist/components/WrLink.js +38 -0
- package/dist/components/WrNav.d.ts +26 -0
- package/dist/components/WrNav.js +30 -0
- package/dist/components/WrSection.d.ts +11 -0
- package/dist/components/WrSection.js +5 -0
- package/dist/components/WrShared.d.ts +12 -0
- package/dist/components/WrShared.js +20 -0
- package/dist/components/WrText.d.ts +11 -0
- package/dist/components/WrText.js +41 -0
- package/dist/components/WrVideo.d.ts +9 -0
- package/dist/components/WrVideo.js +73 -0
- package/dist/components/text-editor/CodeThemeContext.d.ts +8 -0
- package/dist/components/text-editor/CodeThemeContext.js +10 -0
- package/dist/components/text-editor/ExampleTheme.d.ts +77 -0
- package/dist/components/text-editor/ExampleTheme.js +76 -0
- package/dist/components/text-editor/ToolbarContext.d.ts +17 -0
- package/dist/components/text-editor/ToolbarContext.js +32 -0
- package/dist/components/text-editor/WrTextEditor.d.ts +13 -0
- package/dist/components/text-editor/WrTextEditor.js +48 -0
- package/dist/components/text-editor/common/constants.d.ts +109 -0
- package/dist/components/text-editor/common/constants.js +58 -0
- package/dist/components/text-editor/common/surface.d.ts +3 -0
- package/dist/components/text-editor/common/surface.js +8 -0
- package/dist/components/text-editor/common/utils.d.ts +7 -0
- package/dist/components/text-editor/common/utils.js +78 -0
- package/dist/components/text-editor/hooks/useLexicalCommitOnBlur.d.ts +5 -0
- package/dist/components/text-editor/hooks/useLexicalCommitOnBlur.js +41 -0
- package/dist/components/text-editor/hooks/useLexicalMarkdown.d.ts +33 -0
- package/dist/components/text-editor/hooks/useLexicalMarkdown.js +284 -0
- package/dist/components/text-editor/nodes/CodeBlockNode.d.ts +23 -0
- package/dist/components/text-editor/nodes/CodeBlockNode.js +138 -0
- package/dist/components/text-editor/nodes/HorizontalRuleNode.d.ts +13 -0
- package/dist/components/text-editor/nodes/HorizontalRuleNode.js +22 -0
- package/dist/components/text-editor/plugins/CodeBlockPlugin.d.ts +2 -0
- package/dist/components/text-editor/plugins/CodeBlockPlugin.js +38 -0
- package/dist/components/text-editor/plugins/FontPlugin.d.ts +12 -0
- package/dist/components/text-editor/plugins/FontPlugin.js +114 -0
- package/dist/components/text-editor/plugins/FontSizePlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/FontSizePlugin.js +105 -0
- package/dist/components/text-editor/plugins/FontWeightPlugin.d.ts +6 -0
- package/dist/components/text-editor/plugins/FontWeightPlugin.js +103 -0
- package/dist/components/text-editor/plugins/HTMLTagPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/HTMLTagPlugin.js +82 -0
- package/dist/components/text-editor/plugins/HorizontalRulePlugin.d.ts +2 -0
- package/dist/components/text-editor/plugins/HorizontalRulePlugin.js +35 -0
- package/dist/components/text-editor/plugins/LineSpacingPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/LineSpacingPlugin.js +83 -0
- package/dist/components/text-editor/plugins/LinkPlugin.d.ts +8 -0
- package/dist/components/text-editor/plugins/LinkPlugin.js +183 -0
- package/dist/components/text-editor/plugins/ListToolbarPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/ListToolbarPlugin.js +40 -0
- package/dist/components/text-editor/plugins/LoadContentPlugin.d.ts +4 -0
- package/dist/components/text-editor/plugins/LoadContentPlugin.js +63 -0
- package/dist/components/text-editor/plugins/MarkdownExportPlugin.d.ts +4 -0
- package/dist/components/text-editor/plugins/MarkdownExportPlugin.js +17 -0
- package/dist/components/text-editor/plugins/MarkdownPastePlugin.d.ts +2 -0
- package/dist/components/text-editor/plugins/MarkdownPastePlugin.js +45 -0
- package/dist/components/text-editor/plugins/SanitizePastePlugin.d.ts +3 -0
- package/dist/components/text-editor/plugins/SanitizePastePlugin.js +40 -0
- package/dist/components/text-editor/plugins/TextAlignPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/TextAlignPlugin.js +65 -0
- package/dist/components/text-editor/plugins/TextColorPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/TextColorPlugin.js +117 -0
- package/dist/components/text-editor/plugins/ToolbarPlugin.d.ts +10 -0
- package/dist/components/text-editor/plugins/ToolbarPlugin.js +73 -0
- package/dist/components/text-editor/theme-colors.d.ts +11 -0
- package/dist/components/text-editor/theme-colors.js +28 -0
- package/dist/context/WrAppContext.d.ts +35 -0
- package/dist/context/WrAppContext.js +113 -0
- package/dist/context/WrLayout.d.ts +15 -0
- package/dist/context/WrLayout.js +22 -0
- package/dist/context/WrPageContext.d.ts +28 -0
- package/dist/context/WrPageContext.js +282 -0
- package/dist/context/restoreValues.d.ts +2 -0
- package/dist/context/restoreValues.js +6 -0
- package/dist/contrast.d.ts +45 -0
- package/dist/contrast.js +122 -0
- package/dist/drop.d.ts +7 -0
- package/dist/drop.js +51 -0
- package/dist/gaps.d.ts +14 -0
- package/dist/gaps.js +50 -0
- package/dist/hooks/useWrMessage.d.ts +5 -0
- package/dist/hooks/useWrMessage.js +24 -0
- package/dist/hooks/useWrSave.d.ts +2 -0
- package/dist/hooks/useWrSave.js +11 -0
- package/dist/index.css +467 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/interactive.d.ts +8 -0
- package/dist/interactive.js +13 -0
- package/dist/measure-rules.d.ts +34 -0
- package/dist/measure-rules.js +54 -0
- package/dist/measure.d.ts +11 -0
- package/dist/measure.js +139 -0
- package/dist/messages.d.ts +860 -0
- package/dist/messages.js +2 -0
- package/dist/nav.d.ts +5 -0
- package/dist/nav.js +10 -0
- package/dist/operations/animations-store.d.ts +6 -0
- package/dist/operations/animations-store.js +63 -0
- package/dist/operations/cli.d.ts +3 -0
- package/dist/operations/cli.js +52 -0
- package/dist/operations/comments-store.d.ts +17 -0
- package/dist/operations/comments-store.js +62 -0
- package/dist/operations/context.d.ts +12 -0
- package/dist/operations/context.js +35 -0
- package/dist/operations/define.d.ts +81 -0
- package/dist/operations/define.js +86 -0
- package/dist/operations/index.d.ts +6 -0
- package/dist/operations/index.js +6 -0
- package/dist/operations/ops/check.d.ts +5 -0
- package/dist/operations/ops/check.js +53 -0
- package/dist/operations/ops/comments.d.ts +6 -0
- package/dist/operations/ops/comments.js +133 -0
- package/dist/operations/ops/content.d.ts +16 -0
- package/dist/operations/ops/content.js +73 -0
- package/dist/operations/ops/json.d.ts +4 -0
- package/dist/operations/ops/json.js +27 -0
- package/dist/operations/ops/langs.d.ts +4 -0
- package/dist/operations/ops/langs.js +32 -0
- package/dist/operations/ops/nodes.d.ts +8 -0
- package/dist/operations/ops/nodes.js +270 -0
- package/dist/operations/ops/pages.d.ts +8 -0
- package/dist/operations/ops/pages.js +154 -0
- package/dist/operations/ops/project.d.ts +36 -0
- package/dist/operations/ops/project.js +97 -0
- package/dist/operations/ops/seo.d.ts +17 -0
- package/dist/operations/ops/seo.js +358 -0
- package/dist/operations/ops/style.d.ts +76 -0
- package/dist/operations/ops/style.js +268 -0
- package/dist/operations/ops/stylesets.d.ts +9 -0
- package/dist/operations/ops/stylesets.js +145 -0
- package/dist/operations/ops/theme.d.ts +6 -0
- package/dist/operations/ops/theme.js +304 -0
- package/dist/operations/registry.d.ts +8 -0
- package/dist/operations/registry.js +19 -0
- package/dist/operations/stylesets-store.d.ts +50 -0
- package/dist/operations/stylesets-store.js +216 -0
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js +24 -0
- package/dist/save.d.ts +65 -0
- package/dist/save.js +86 -0
- package/dist/schema.d.ts +69 -0
- package/dist/schema.js +110 -0
- package/dist/scope.d.ts +41 -0
- package/dist/scope.js +44 -0
- package/dist/vite-plugins/ast.d.ts +3 -0
- package/dist/vite-plugins/ast.js +238 -0
- package/dist/vite-plugins/core-swap.d.ts +3 -0
- package/dist/vite-plugins/core-swap.js +57 -0
- package/dist/vite-plugins/create-page.d.ts +4 -0
- package/dist/vite-plugins/create-page.js +59 -0
- package/dist/vite-plugins/guard.d.ts +15 -0
- package/dist/vite-plugins/guard.js +35 -0
- package/dist/vite-plugins/head.d.ts +13 -0
- package/dist/vite-plugins/head.js +53 -0
- package/dist/vite-plugins/index.d.ts +7 -0
- package/dist/vite-plugins/index.js +7 -0
- package/dist/vite-plugins/jsx-tree.d.ts +118 -0
- package/dist/vite-plugins/jsx-tree.js +686 -0
- package/dist/vite-plugins/langs.d.ts +3 -0
- package/dist/vite-plugins/langs.js +44 -0
- package/dist/vite-plugins/operations.d.ts +10 -0
- package/dist/vite-plugins/operations.js +66 -0
- package/dist/vite-plugins/pages-api.d.ts +3 -0
- package/dist/vite-plugins/pages-api.js +112 -0
- package/dist/vite-plugins/pages.d.ts +3 -0
- package/dist/vite-plugins/pages.js +64 -0
- package/dist/vite-plugins/read.d.ts +3 -0
- package/dist/vite-plugins/read.js +45 -0
- package/dist/vite-plugins/seo-files.d.ts +8 -0
- package/dist/vite-plugins/seo-files.js +42 -0
- package/dist/vite-plugins/theme.d.ts +3 -0
- package/dist/vite-plugins/theme.js +207 -0
- package/dist/vite-plugins/update.d.ts +3 -0
- package/dist/vite-plugins/update.js +46 -0
- package/dist/vite-plugins/wr-plugins.d.ts +15 -0
- package/dist/vite-plugins/wr-plugins.js +34 -0
- package/dist/vite-plugins.d.ts +11 -0
- package/dist/vite-plugins.js +518 -0
- package/package.json +96 -5
- package/README.md +0 -3
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
2
|
+
import { $getRoot, $createParagraphNode, $createTextNode, $isParagraphNode, $getSelection, $isRangeSelection, } from "lexical";
|
|
3
|
+
import { $createHeadingNode, $isHeadingNode } from "@lexical/rich-text";
|
|
4
|
+
import { $createLinkNode, $isLinkNode } from "@lexical/link";
|
|
5
|
+
import { $createListNode, $createListItemNode, $isListNode, $isListItemNode, } from "@lexical/list";
|
|
6
|
+
import { $createHorizontalRuleNode, $isHorizontalRuleNode } from "../nodes/HorizontalRuleNode";
|
|
7
|
+
import { $createCodeBlockNode, $isCodeBlockNode } from "../nodes/CodeBlockNode";
|
|
8
|
+
// Lexical format bitmask constants
|
|
9
|
+
const IS_BOLD = 1;
|
|
10
|
+
const IS_ITALIC = 2;
|
|
11
|
+
const IS_STRIKETHROUGH = 4;
|
|
12
|
+
const IS_UNDERLINE = 8;
|
|
13
|
+
const IS_CODE = 16;
|
|
14
|
+
// ─── Style helpers ────────────────────────────────────────────────────────────
|
|
15
|
+
function buildStyleVar(id) {
|
|
16
|
+
return [
|
|
17
|
+
`font-family: var(--text-style-${id}-font-family)`,
|
|
18
|
+
`font-size: var(--text-style-${id}-font-size)`,
|
|
19
|
+
`color: var(--text-style-${id}-text-color)`,
|
|
20
|
+
].join("; ") + ";";
|
|
21
|
+
}
|
|
22
|
+
// ─── Inline regex ─────────────────────────────────────────────────────────────
|
|
23
|
+
// Order matters: ** before *, <u> before nothing
|
|
24
|
+
const INLINE_RE = /\*\*(.+?)\*\*|\[(.+?)\]\((.+?)\)|\*(.+?)\*|`(.+?)`|~~(.+?)~~|<u>(.+?)<\/u>/g;
|
|
25
|
+
export function tokenizeInline(raw) {
|
|
26
|
+
const tokens = [];
|
|
27
|
+
let last = 0;
|
|
28
|
+
const re = /\*\*(.+?)\*\*|\[(.+?)\]\((.+?)\)|\*(.+?)\*|`(.+?)`|~~(.+?)~~|<u>(.+?)<\/u>/g;
|
|
29
|
+
let m;
|
|
30
|
+
while ((m = re.exec(raw)) !== null) {
|
|
31
|
+
if (m.index > last) {
|
|
32
|
+
tokens.push({ kind: "text", text: raw.slice(last, m.index) });
|
|
33
|
+
}
|
|
34
|
+
if (m[1] !== undefined) {
|
|
35
|
+
const inner = tokenizeInline(m[1]);
|
|
36
|
+
inner.forEach(t => {
|
|
37
|
+
if (t.kind === "text")
|
|
38
|
+
tokens.push({ kind: "bold", text: t.text });
|
|
39
|
+
else
|
|
40
|
+
tokens.push(t);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else if (m[2] !== undefined) {
|
|
44
|
+
tokens.push({ kind: "link", text: m[2], url: m[3] });
|
|
45
|
+
}
|
|
46
|
+
else if (m[4] !== undefined) {
|
|
47
|
+
const inner = tokenizeInline(m[4]);
|
|
48
|
+
inner.forEach(t => {
|
|
49
|
+
if (t.kind === "text")
|
|
50
|
+
tokens.push({ kind: "italic", text: t.text });
|
|
51
|
+
else
|
|
52
|
+
tokens.push(t);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
else if (m[5] !== undefined) {
|
|
56
|
+
tokens.push({ kind: "code", text: m[5] });
|
|
57
|
+
}
|
|
58
|
+
else if (m[6] !== undefined) {
|
|
59
|
+
tokens.push({ kind: "strike", text: m[6] });
|
|
60
|
+
}
|
|
61
|
+
else if (m[7] !== undefined) {
|
|
62
|
+
tokens.push({ kind: "under", text: m[7] });
|
|
63
|
+
}
|
|
64
|
+
last = re.lastIndex;
|
|
65
|
+
}
|
|
66
|
+
if (last < raw.length) {
|
|
67
|
+
tokens.push({ kind: "text", text: raw.slice(last) });
|
|
68
|
+
}
|
|
69
|
+
return tokens;
|
|
70
|
+
}
|
|
71
|
+
// ─── Lexical node builder from tokens ─────────────────────────────────────────
|
|
72
|
+
export function buildNodes(tokens, style) {
|
|
73
|
+
return tokens.map((tok) => {
|
|
74
|
+
if (tok.kind === "link") {
|
|
75
|
+
const linkNode = $createLinkNode(tok.url);
|
|
76
|
+
const t = $createTextNode(tok.text);
|
|
77
|
+
t.setStyle(style);
|
|
78
|
+
linkNode.append(t);
|
|
79
|
+
return linkNode; // ElementNode acceptable in append()
|
|
80
|
+
}
|
|
81
|
+
const t = $createTextNode(tok.text);
|
|
82
|
+
t.setStyle(style);
|
|
83
|
+
switch (tok.kind) {
|
|
84
|
+
case "bold":
|
|
85
|
+
t.setStyle(t.getStyle() + "; font-weight: 700");
|
|
86
|
+
break;
|
|
87
|
+
case "italic":
|
|
88
|
+
t.setFormat(IS_ITALIC);
|
|
89
|
+
break;
|
|
90
|
+
case "code":
|
|
91
|
+
t.setFormat(IS_CODE);
|
|
92
|
+
break;
|
|
93
|
+
case "strike":
|
|
94
|
+
t.setFormat(IS_STRIKETHROUGH);
|
|
95
|
+
break;
|
|
96
|
+
case "under":
|
|
97
|
+
t.setFormat(IS_UNDERLINE);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
return t;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// ─── Lexical → Markdown ───────────────────────────────────────────────────────
|
|
104
|
+
function nodeToMd(node) {
|
|
105
|
+
const type = node.getType();
|
|
106
|
+
if ($isCodeBlockNode(node)) {
|
|
107
|
+
return `\`\`\`${node.__language}\n${node.__code}\n\`\`\``;
|
|
108
|
+
}
|
|
109
|
+
if ($isHorizontalRuleNode(node))
|
|
110
|
+
return "---";
|
|
111
|
+
if (type === "text") {
|
|
112
|
+
let text = node.getTextContent();
|
|
113
|
+
const fmt = node.getFormat();
|
|
114
|
+
const style = node.getStyle() ?? "";
|
|
115
|
+
// bold → font-weight nello style inline, NON nel format flag
|
|
116
|
+
const weightMatch = style.match(/font-weight:\s*(\d+)/i);
|
|
117
|
+
const isBold = weightMatch ? parseInt(weightMatch[1]) >= 700 : false;
|
|
118
|
+
if (fmt & IS_CODE)
|
|
119
|
+
text = `\`${text}\``;
|
|
120
|
+
if (fmt & IS_STRIKETHROUGH)
|
|
121
|
+
text = `~~${text}~~`;
|
|
122
|
+
if (fmt & IS_UNDERLINE)
|
|
123
|
+
text = `<u>${text}</u>`;
|
|
124
|
+
if (fmt & IS_ITALIC)
|
|
125
|
+
text = `*${text}*`;
|
|
126
|
+
if (isBold)
|
|
127
|
+
text = `**${text}**`;
|
|
128
|
+
return text;
|
|
129
|
+
}
|
|
130
|
+
if ($isLinkNode(node)) {
|
|
131
|
+
const url = node.getURL();
|
|
132
|
+
const children = node.getChildren().map(nodeToMd).join("");
|
|
133
|
+
return `[${children}](${url})`;
|
|
134
|
+
}
|
|
135
|
+
if ($isHeadingNode(node)) {
|
|
136
|
+
const tag = node.getTag();
|
|
137
|
+
const hashes = "#".repeat(parseInt(tag[1]));
|
|
138
|
+
const children = node.getChildren().map(nodeToMd).join("");
|
|
139
|
+
return `${hashes} ${children}`;
|
|
140
|
+
}
|
|
141
|
+
if ($isParagraphNode(node)) {
|
|
142
|
+
return node.getChildren().map(nodeToMd).join("");
|
|
143
|
+
}
|
|
144
|
+
if ($isListNode(node)) {
|
|
145
|
+
const listType = node.getListType();
|
|
146
|
+
return node.getChildren().map((item, idx) => {
|
|
147
|
+
const prefix = listType === "number" ? `${idx + 1}. ` : "- ";
|
|
148
|
+
const content = $isListItemNode(item)
|
|
149
|
+
? item.getChildren().map(nodeToMd).join("")
|
|
150
|
+
: nodeToMd(item);
|
|
151
|
+
return prefix + content;
|
|
152
|
+
}).join("\n");
|
|
153
|
+
}
|
|
154
|
+
// fallback: plain text
|
|
155
|
+
return node.getTextContent?.() ?? "";
|
|
156
|
+
}
|
|
157
|
+
// ─── Hook ─────────────────────────────────────────────────────────────────────
|
|
158
|
+
export function useLexicalMarkdown() {
|
|
159
|
+
const [editor] = useLexicalComposerContext();
|
|
160
|
+
/** Returns the CSS-var style string for a given HTML tag (h1-h6 or p/default). */
|
|
161
|
+
const styleForTag = (tag) => {
|
|
162
|
+
return "";
|
|
163
|
+
};
|
|
164
|
+
const defaultStyle = () => styleForTag("p");
|
|
165
|
+
// ── toMarkdown ─────────────────────────────────────────────────────────
|
|
166
|
+
const toMarkdown = () => {
|
|
167
|
+
let md = "";
|
|
168
|
+
editor.getEditorState().read(() => {
|
|
169
|
+
const root = $getRoot();
|
|
170
|
+
md = root.getChildren().map(nodeToMd).join("\n\n");
|
|
171
|
+
});
|
|
172
|
+
return md;
|
|
173
|
+
};
|
|
174
|
+
// ── fromMarkdown ───────────────────────────────────────────────────────
|
|
175
|
+
const fromMarkdown = (md) => {
|
|
176
|
+
editor.update(() => {
|
|
177
|
+
const nodes = [];
|
|
178
|
+
let currentList = null;
|
|
179
|
+
let currentListType = null;
|
|
180
|
+
const flushList = () => {
|
|
181
|
+
if (currentList) {
|
|
182
|
+
nodes.push(currentList);
|
|
183
|
+
currentList = null;
|
|
184
|
+
currentListType = null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const lines = md.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
188
|
+
let i = 0;
|
|
189
|
+
while (i < lines.length) {
|
|
190
|
+
const line = lines[i];
|
|
191
|
+
if (line.trim() === "") {
|
|
192
|
+
flushList();
|
|
193
|
+
i++;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (line.trim() === "---") {
|
|
197
|
+
flushList();
|
|
198
|
+
nodes.push($createHorizontalRuleNode());
|
|
199
|
+
i++;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const fenceMatch = line.match(/^```(\w*)$/);
|
|
203
|
+
if (fenceMatch) {
|
|
204
|
+
flushList();
|
|
205
|
+
const language = fenceMatch[1] ?? "";
|
|
206
|
+
const codeLines = [];
|
|
207
|
+
i++;
|
|
208
|
+
while (i < lines.length && lines[i] !== "```") {
|
|
209
|
+
codeLines.push(lines[i]);
|
|
210
|
+
i++;
|
|
211
|
+
}
|
|
212
|
+
i++;
|
|
213
|
+
nodes.push($createCodeBlockNode(codeLines.join("\n"), language));
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const hMatch = line.match(/^(#{1,6}) (.+)$/);
|
|
217
|
+
if (hMatch) {
|
|
218
|
+
flushList();
|
|
219
|
+
const tag = `h${hMatch[1].length}`;
|
|
220
|
+
const style = styleForTag(tag);
|
|
221
|
+
const heading = $createHeadingNode(tag);
|
|
222
|
+
heading.setDirection("ltr");
|
|
223
|
+
buildNodes(tokenizeInline(hMatch[2]), style).forEach((n) => heading.append(n));
|
|
224
|
+
nodes.push(heading);
|
|
225
|
+
i++;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const ulMatch = line.match(/^[-*] (.+)$/);
|
|
229
|
+
if (ulMatch) {
|
|
230
|
+
if (currentListType !== "bullet") {
|
|
231
|
+
flushList();
|
|
232
|
+
currentList = $createListNode("bullet");
|
|
233
|
+
currentListType = "bullet";
|
|
234
|
+
}
|
|
235
|
+
const item = $createListItemNode();
|
|
236
|
+
buildNodes(tokenizeInline(ulMatch[1]), defaultStyle()).forEach((n) => item.append(n));
|
|
237
|
+
currentList.append(item);
|
|
238
|
+
i++;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const olMatch = line.match(/^\d+\. (.+)$/);
|
|
242
|
+
if (olMatch) {
|
|
243
|
+
if (currentListType !== "number") {
|
|
244
|
+
flushList();
|
|
245
|
+
currentList = $createListNode("number");
|
|
246
|
+
currentListType = "number";
|
|
247
|
+
}
|
|
248
|
+
const item = $createListItemNode();
|
|
249
|
+
buildNodes(tokenizeInline(olMatch[1]), defaultStyle()).forEach((n) => item.append(n));
|
|
250
|
+
currentList.append(item);
|
|
251
|
+
i++;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
flushList();
|
|
255
|
+
const para = $createParagraphNode();
|
|
256
|
+
para.setDirection("ltr");
|
|
257
|
+
buildNodes(tokenizeInline(line), defaultStyle()).forEach((n) => para.append(n));
|
|
258
|
+
nodes.push(para);
|
|
259
|
+
i++;
|
|
260
|
+
}
|
|
261
|
+
flushList();
|
|
262
|
+
const selection = $getSelection();
|
|
263
|
+
if ($isRangeSelection(selection)) {
|
|
264
|
+
// prima cancella la selezione se c'è testo selezionato
|
|
265
|
+
if (!selection.isCollapsed()) {
|
|
266
|
+
selection.deleteCharacter(false);
|
|
267
|
+
}
|
|
268
|
+
const anchorNode = selection.anchor.getNode();
|
|
269
|
+
const topLevel = anchorNode.getTopLevelElementOrThrow();
|
|
270
|
+
nodes.reverse().forEach(n => topLevel.insertAfter(n));
|
|
271
|
+
// rimuovi il nodo corrente se è vuoto
|
|
272
|
+
if (topLevel.getTextContent().trim() === "") {
|
|
273
|
+
topLevel.remove();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const root = $getRoot();
|
|
278
|
+
nodes.forEach(n => root.append(n));
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
return { toMarkdown, fromMarkdown };
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=useLexicalMarkdown.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DecoratorNode, LexicalNode, SerializedLexicalNode, Spread } from "lexical";
|
|
2
|
+
import { JSX } from "react";
|
|
3
|
+
type SerializedCodeBlockNode = Spread<{
|
|
4
|
+
code: string;
|
|
5
|
+
language: string;
|
|
6
|
+
}, SerializedLexicalNode>;
|
|
7
|
+
export declare class CodeBlockNode extends DecoratorNode<JSX.Element> {
|
|
8
|
+
__code: string;
|
|
9
|
+
__language: string;
|
|
10
|
+
static getType(): string;
|
|
11
|
+
static clone(node: CodeBlockNode): CodeBlockNode;
|
|
12
|
+
constructor(code: string, language?: string, key?: string);
|
|
13
|
+
createDOM(): HTMLElement;
|
|
14
|
+
updateDOM(): false;
|
|
15
|
+
isInline(): false;
|
|
16
|
+
decorate(): JSX.Element;
|
|
17
|
+
static importJSON(node: SerializedCodeBlockNode): CodeBlockNode;
|
|
18
|
+
exportJSON(): SerializedCodeBlockNode;
|
|
19
|
+
}
|
|
20
|
+
export declare function $createCodeBlockNode(code: string, language?: string): CodeBlockNode;
|
|
21
|
+
export declare function $isCodeBlockNode(node: LexicalNode | null | undefined): node is CodeBlockNode;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=CodeBlockNode.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DecoratorNode, $getNodeByKey } from "lexical";
|
|
3
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import hljs from "highlight.js";
|
|
6
|
+
import MonacoEditor from "@monaco-editor/react";
|
|
7
|
+
import { useCodeTheme } from "../CodeThemeContext";
|
|
8
|
+
const setHljsTheme = (dark) => {
|
|
9
|
+
let link = document.getElementById("hljs-theme");
|
|
10
|
+
if (!link) {
|
|
11
|
+
link = document.createElement("link");
|
|
12
|
+
link.id = "hljs-theme";
|
|
13
|
+
link.rel = "stylesheet";
|
|
14
|
+
document.head.appendChild(link);
|
|
15
|
+
}
|
|
16
|
+
link.href = dark
|
|
17
|
+
? new URL("highlight.js/styles/github-dark.css", import.meta.url).href
|
|
18
|
+
: new URL("highlight.js/styles/github.css", import.meta.url).href;
|
|
19
|
+
};
|
|
20
|
+
const LANGUAGE_MAP = {
|
|
21
|
+
ts: "typescript", tsx: "typescript",
|
|
22
|
+
js: "javascript", jsx: "javascript",
|
|
23
|
+
py: "python", rb: "ruby",
|
|
24
|
+
sh: "shell", bash: "shell",
|
|
25
|
+
yml: "yaml", md: "markdown",
|
|
26
|
+
};
|
|
27
|
+
const resolveLanguage = (lang) => LANGUAGE_MAP[lang.toLowerCase()] ?? lang.toLowerCase();
|
|
28
|
+
function CodeBlockComponent({ code, language, nodeKey }) {
|
|
29
|
+
const [editor] = useLexicalComposerContext();
|
|
30
|
+
const { theme, toggle } = useCodeTheme();
|
|
31
|
+
const isDark = theme === "vs-dark";
|
|
32
|
+
const [copied, setCopied] = useState(false);
|
|
33
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
34
|
+
const [localCode, setLocalCode] = useState(code);
|
|
35
|
+
const [height, setHeight] = useState(100);
|
|
36
|
+
const codeRef = useRef(null);
|
|
37
|
+
const containerRef = useRef(null);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setHljsTheme(isDark);
|
|
40
|
+
}, [isDark]);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (isEditing)
|
|
43
|
+
return;
|
|
44
|
+
if (!codeRef.current)
|
|
45
|
+
return;
|
|
46
|
+
codeRef.current.textContent = localCode;
|
|
47
|
+
hljs.highlightElement(codeRef.current);
|
|
48
|
+
}, [localCode, isDark, isEditing]);
|
|
49
|
+
const onChange = (value) => {
|
|
50
|
+
const next = value ?? "";
|
|
51
|
+
setLocalCode(next);
|
|
52
|
+
editor.update(() => {
|
|
53
|
+
const node = $getNodeByKey(nodeKey);
|
|
54
|
+
if ($isCodeBlockNode(node)) {
|
|
55
|
+
node.getWritable().__code = next;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const onMount = (monacoEditor) => {
|
|
60
|
+
const updateHeight = () => setHeight(Math.max(100, monacoEditor.getContentHeight()));
|
|
61
|
+
monacoEditor.onDidContentSizeChange(updateHeight);
|
|
62
|
+
updateHeight();
|
|
63
|
+
};
|
|
64
|
+
const handleCopy = async () => {
|
|
65
|
+
await navigator.clipboard.writeText(localCode);
|
|
66
|
+
setCopied(true);
|
|
67
|
+
setTimeout(() => setCopied(false), 1500);
|
|
68
|
+
};
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!isEditing)
|
|
71
|
+
return;
|
|
72
|
+
const handleClickOutside = (e) => {
|
|
73
|
+
if (!containerRef.current?.contains(e.target)) {
|
|
74
|
+
setIsEditing(false);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
78
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
79
|
+
}, [isEditing]);
|
|
80
|
+
return (_jsxs("div", { ref: containerRef, className: `relative my-2 rounded-lg overflow-hidden max-w-full text-sm ${isDark ? "bg-gray-900" : "bg-gray-100"}`, onKeyDown: e => e.stopPropagation(), onKeyUp: e => e.stopPropagation(), onCopy: e => e.stopPropagation(), onCut: e => e.stopPropagation(), onPaste: e => e.stopPropagation(), children: [_jsxs("div", { className: `flex items-center justify-between text-xs ${isDark ? "bg-gray-800 text-gray-400" : "bg-gray-200 text-gray-600"}`, children: [_jsx("span", { className: "p-2", children: language || "plaintext" }), _jsxs("div", { className: "flex items-center gap-3 p-2", children: [_jsx("button", { onClick: toggle, children: isDark ? "☀️" : "🌙" }), _jsx("button", { onClick: handleCopy, className: `transition-colors ${isDark ? "hover:text-white" : "hover:text-black"}`, children: copied ? "✓" : "Copy" })] })] }), isEditing ? (_jsx(MonacoEditor, { width: "100%", height: height, language: resolveLanguage(language), value: localCode, onChange: onChange, onMount: onMount, theme: theme, options: {
|
|
81
|
+
minimap: { enabled: false },
|
|
82
|
+
scrollBeyondLastLine: false,
|
|
83
|
+
fontSize: 14,
|
|
84
|
+
lineHeight: 20,
|
|
85
|
+
lineNumbers: "off",
|
|
86
|
+
folding: false,
|
|
87
|
+
padding: { top: 28, bottom: 28 },
|
|
88
|
+
automaticLayout: true,
|
|
89
|
+
scrollbar: { vertical: "hidden", handleMouseWheel: false },
|
|
90
|
+
glyphMargin: false,
|
|
91
|
+
lineDecorationsWidth: 16,
|
|
92
|
+
lineNumbersMinChars: 0,
|
|
93
|
+
} })) : (_jsx("pre", { className: `m-0 pl-0 pt-4 pb-4 pr-4 overflow-x-auto cursor-text font-mono text-sm leading-5 max-w-full ${isDark ? "bg-gray-900" : "bg-gray-100"}`, onClick: () => setIsEditing(true), children: _jsx("code", { ref: codeRef, className: language ? `language-${language}` : "" }) }))] }));
|
|
94
|
+
}
|
|
95
|
+
export class CodeBlockNode extends DecoratorNode {
|
|
96
|
+
__code;
|
|
97
|
+
__language;
|
|
98
|
+
static getType() { return "code-block"; }
|
|
99
|
+
static clone(node) {
|
|
100
|
+
return new CodeBlockNode(node.__code, node.__language, node.__key);
|
|
101
|
+
}
|
|
102
|
+
constructor(code, language = "", key) {
|
|
103
|
+
super(key);
|
|
104
|
+
this.__code = code;
|
|
105
|
+
this.__language = language;
|
|
106
|
+
}
|
|
107
|
+
createDOM() {
|
|
108
|
+
const div = document.createElement("div");
|
|
109
|
+
div.contentEditable = "false";
|
|
110
|
+
div.style.width = "0";
|
|
111
|
+
div.style.minWidth = "100%";
|
|
112
|
+
return div;
|
|
113
|
+
}
|
|
114
|
+
updateDOM() { return false; }
|
|
115
|
+
isInline() { return false; }
|
|
116
|
+
decorate() {
|
|
117
|
+
return (_jsx(CodeBlockComponent, { code: this.__code, language: this.__language, nodeKey: this.__key }));
|
|
118
|
+
}
|
|
119
|
+
static importJSON(node) {
|
|
120
|
+
return $createCodeBlockNode(node.code, node.language);
|
|
121
|
+
}
|
|
122
|
+
exportJSON() {
|
|
123
|
+
return {
|
|
124
|
+
...super.exportJSON(),
|
|
125
|
+
type: "code-block",
|
|
126
|
+
version: 1,
|
|
127
|
+
code: this.__code,
|
|
128
|
+
language: this.__language,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
export function $createCodeBlockNode(code, language = "") {
|
|
133
|
+
return new CodeBlockNode(code, language);
|
|
134
|
+
}
|
|
135
|
+
export function $isCodeBlockNode(node) {
|
|
136
|
+
return node?.getType() === "code-block";
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=CodeBlockNode.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DecoratorNode, LexicalNode } from "lexical";
|
|
2
|
+
import { JSX } from "react";
|
|
3
|
+
export declare class HorizontalRuleNode extends DecoratorNode<JSX.Element> {
|
|
4
|
+
static getType(): string;
|
|
5
|
+
static clone(node: HorizontalRuleNode): HorizontalRuleNode;
|
|
6
|
+
createDOM(): HTMLElement;
|
|
7
|
+
updateDOM(): false;
|
|
8
|
+
decorate(): JSX.Element;
|
|
9
|
+
isInline(): false;
|
|
10
|
+
}
|
|
11
|
+
export declare function $createHorizontalRuleNode(): HorizontalRuleNode;
|
|
12
|
+
export declare function $isHorizontalRuleNode(node: LexicalNode | null | undefined): node is HorizontalRuleNode;
|
|
13
|
+
//# sourceMappingURL=HorizontalRuleNode.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// nodes/HorizontalRuleNode.tsx
|
|
3
|
+
import { DecoratorNode } from "lexical";
|
|
4
|
+
export class HorizontalRuleNode extends DecoratorNode {
|
|
5
|
+
static getType() { return "horizontal-rule"; }
|
|
6
|
+
static clone(node) {
|
|
7
|
+
return new HorizontalRuleNode(node.__key);
|
|
8
|
+
}
|
|
9
|
+
createDOM() {
|
|
10
|
+
return document.createElement("hr");
|
|
11
|
+
}
|
|
12
|
+
updateDOM() { return false; }
|
|
13
|
+
decorate() { return _jsx("hr", {}); }
|
|
14
|
+
isInline() { return false; }
|
|
15
|
+
}
|
|
16
|
+
export function $createHorizontalRuleNode() {
|
|
17
|
+
return new HorizontalRuleNode();
|
|
18
|
+
}
|
|
19
|
+
export function $isHorizontalRuleNode(node) {
|
|
20
|
+
return node?.getType() === "horizontal-rule";
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=HorizontalRuleNode.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
3
|
+
import { $getSelection, $isRangeSelection, $isParagraphNode, $createParagraphNode, $createRangeSelection, $setSelection, KEY_ENTER_COMMAND, COMMAND_PRIORITY_LOW, } from "lexical";
|
|
4
|
+
import { $createCodeBlockNode } from "../nodes/CodeBlockNode";
|
|
5
|
+
export default function CodeBlockPlugin() {
|
|
6
|
+
const [editor] = useLexicalComposerContext();
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
return editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
9
|
+
const selection = $getSelection();
|
|
10
|
+
if (!$isRangeSelection(selection))
|
|
11
|
+
return false;
|
|
12
|
+
const anchor = selection.anchor.getNode();
|
|
13
|
+
const parent = anchor.getParent();
|
|
14
|
+
if (!$isParagraphNode(parent))
|
|
15
|
+
return false;
|
|
16
|
+
if (parent.getChildrenSize() !== 1)
|
|
17
|
+
return false;
|
|
18
|
+
const text = anchor.getTextContent().trim();
|
|
19
|
+
const match = text.match(/^```(\w*)$/);
|
|
20
|
+
if (!match)
|
|
21
|
+
return false;
|
|
22
|
+
event?.preventDefault();
|
|
23
|
+
const language = match[1] || "";
|
|
24
|
+
const codeBlock = $createCodeBlockNode("", language);
|
|
25
|
+
const para = $createParagraphNode();
|
|
26
|
+
parent.replace(codeBlock);
|
|
27
|
+
codeBlock.insertAfter(para);
|
|
28
|
+
const sel = $createRangeSelection();
|
|
29
|
+
const key = para.getKey();
|
|
30
|
+
sel.anchor.set(key, 0, "element");
|
|
31
|
+
sel.focus.set(key, 0, "element");
|
|
32
|
+
$setSelection(sel);
|
|
33
|
+
return true;
|
|
34
|
+
}, COMMAND_PRIORITY_LOW);
|
|
35
|
+
}, [editor]);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=CodeBlockPlugin.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface TextStyle {
|
|
3
|
+
fontFamily?: string;
|
|
4
|
+
}
|
|
5
|
+
interface Props {
|
|
6
|
+
editorPathKey?: string;
|
|
7
|
+
fonts?: string[];
|
|
8
|
+
textStyles?: TextStyle[];
|
|
9
|
+
}
|
|
10
|
+
declare function FontPlugin({ editorPathKey, fonts, textStyles, }: Props): React.JSX.Element;
|
|
11
|
+
export default FontPlugin;
|
|
12
|
+
//# sourceMappingURL=FontPlugin.d.ts.map
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect, useState, useCallback } from 'react';
|
|
3
|
+
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
|
|
4
|
+
import { $getSelection, $isRangeSelection } from 'lexical';
|
|
5
|
+
import { $patchStyleText } from '@lexical/selection';
|
|
6
|
+
import { PiTextT } from 'react-icons/pi';
|
|
7
|
+
import { createPortal } from 'react-dom';
|
|
8
|
+
import { wrGetTheme } from '../../../save';
|
|
9
|
+
import { WR_SURFACE_STYLE } from '../common/surface';
|
|
10
|
+
const DEFAULT_FONTS = [
|
|
11
|
+
'Manrope'
|
|
12
|
+
];
|
|
13
|
+
function themeFontNames(items) {
|
|
14
|
+
return items
|
|
15
|
+
.filter((i) => i.kind === 'google-font' || i.kind === 'custom-font')
|
|
16
|
+
.map(i => i.key);
|
|
17
|
+
}
|
|
18
|
+
function FontPlugin({ editorPathKey = '', fonts = DEFAULT_FONTS, textStyles = [], }) {
|
|
19
|
+
const [editor] = useLexicalComposerContext();
|
|
20
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
21
|
+
const [selectedFont, setSelectedFont] = useState(fonts[0]);
|
|
22
|
+
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
|
|
23
|
+
const [themeFonts, setThemeFonts] = useState([]);
|
|
24
|
+
const buttonRef = useRef(null);
|
|
25
|
+
const menuRef = useRef(null);
|
|
26
|
+
const refreshThemeFonts = useCallback(() => {
|
|
27
|
+
wrGetTheme()
|
|
28
|
+
.then(({ items }) => setThemeFonts(themeFontNames(items)))
|
|
29
|
+
.catch(() => setThemeFonts([]));
|
|
30
|
+
}, []);
|
|
31
|
+
useEffect(() => { refreshThemeFonts(); }, [refreshThemeFonts]);
|
|
32
|
+
const allFonts = [...fonts, ...themeFonts.filter(f => !fonts.includes(f))];
|
|
33
|
+
const toggleMenu = (e) => {
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
setIsMenuOpen(prev => !prev);
|
|
36
|
+
};
|
|
37
|
+
const applyFont = (font) => {
|
|
38
|
+
editor.update(() => {
|
|
39
|
+
const selection = $getSelection();
|
|
40
|
+
if ($isRangeSelection(selection)) {
|
|
41
|
+
$patchStyleText(selection, { 'font-family': font });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
setSelectedFont(font);
|
|
45
|
+
setIsMenuOpen(false);
|
|
46
|
+
};
|
|
47
|
+
const calculateMenuPosition = () => {
|
|
48
|
+
if (buttonRef.current && menuRef.current) {
|
|
49
|
+
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
50
|
+
const menuRect = menuRef.current.getBoundingClientRect();
|
|
51
|
+
let top = buttonRect.bottom;
|
|
52
|
+
let left = buttonRect.left;
|
|
53
|
+
const pageWidth = document.body.clientWidth;
|
|
54
|
+
if (left + menuRect.width > pageWidth)
|
|
55
|
+
left = pageWidth - menuRect.width - 10;
|
|
56
|
+
if (left < 0)
|
|
57
|
+
left = 10;
|
|
58
|
+
setMenuPosition({ top, left });
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
const handleClickOutside = (e) => {
|
|
63
|
+
if (menuRef.current && !menuRef.current.contains(e.target) && !buttonRef.current?.contains(e.target)) {
|
|
64
|
+
setIsMenuOpen(false);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if (isMenuOpen) {
|
|
68
|
+
document.addEventListener('click', handleClickOutside);
|
|
69
|
+
calculateMenuPosition();
|
|
70
|
+
}
|
|
71
|
+
return () => document.removeEventListener('click', handleClickOutside);
|
|
72
|
+
}, [isMenuOpen]);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
return editor.registerUpdateListener(() => {
|
|
75
|
+
editor.getEditorState().read(() => {
|
|
76
|
+
const selection = $getSelection();
|
|
77
|
+
if (!$isRangeSelection(selection))
|
|
78
|
+
return;
|
|
79
|
+
const anchorNode = selection.anchor.getNode();
|
|
80
|
+
if (!anchorNode)
|
|
81
|
+
return;
|
|
82
|
+
let fontFamily = selectedFont;
|
|
83
|
+
const styleString = anchorNode.getStyle?.();
|
|
84
|
+
if (styleString && typeof styleString === 'string') {
|
|
85
|
+
const match = styleString.match(/font-family:\s*['"]?([^;'"]+)['"]?/i);
|
|
86
|
+
if (match)
|
|
87
|
+
fontFamily = match[1].trim();
|
|
88
|
+
}
|
|
89
|
+
if (fontFamily.startsWith('var(')) {
|
|
90
|
+
const match = fontFamily.match(/--text-style-(\d+)-font-family/);
|
|
91
|
+
if (match) {
|
|
92
|
+
const style = textStyles[parseInt(match[1], 10)];
|
|
93
|
+
if (style?.fontFamily)
|
|
94
|
+
fontFamily = style.fontFamily;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
setSelectedFont(fontFamily);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}, [editor, textStyles]);
|
|
101
|
+
return (_jsxs("div", { className: `path-${editorPathKey} toolbarClass`, style: { position: 'relative', display: 'inline-block', textAlign: 'left' }, onClick: e => e.stopPropagation(), children: [_jsxs("button", { ref: buttonRef, type: "button", onClick: toggleMenu, "aria-expanded": isMenuOpen, className: "wr-toolbar-trigger", children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx(PiTextT, { style: { fontSize: 18 } }), _jsx("span", { style: { fontFamily: selectedFont }, children: selectedFont })] }), _jsx("svg", { className: `wr-toolbar-chevron ${isMenuOpen ? 'wr-toolbar-chevron--open' : ''}`, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) })] }), isMenuOpen && createPortal(_jsx("div", { ref: menuRef, className: `toolbarClass path-${editorPathKey} wr-toolbar-menu`, style: { ...WR_SURFACE_STYLE, top: menuPosition.top, left: menuPosition.left, width: 288 }, children: _jsx("div", { style: { padding: '4px 0' }, children: allFonts.map(font => (_jsx("div", { className: "wr-toolbar-item", style: { display: 'flex', alignItems: 'center', padding: 0 }, children: _jsx("button", { onClick: () => applyFont(font), style: {
|
|
102
|
+
fontFamily: font,
|
|
103
|
+
display: 'block',
|
|
104
|
+
padding: '8px 16px',
|
|
105
|
+
fontSize: 14,
|
|
106
|
+
width: '100%',
|
|
107
|
+
textAlign: 'left',
|
|
108
|
+
background: 'transparent',
|
|
109
|
+
border: 'none',
|
|
110
|
+
cursor: 'pointer',
|
|
111
|
+
}, children: font }) }, font))) }) }), document.body)] }));
|
|
112
|
+
}
|
|
113
|
+
export default FontPlugin;
|
|
114
|
+
//# sourceMappingURL=FontPlugin.js.map
|