@haklex/rich-ext-embed 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/EmbedLinkRenderer-c7CLy9Mi.js +690 -0
- package/dist/index.mjs +86 -115
- package/dist/rich-ext-embed.css +2 -1
- package/dist/static.mjs +5 -21
- package/package.json +15 -15
- package/dist/EmbedLinkRenderer-Cw-Doj2u.js +0 -599
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
import { $getNodeByKey, DecoratorNode } from "lexical";
|
|
2
|
+
import { Component, Suspense, createContext, createElement, lazy, use, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { useColorScheme } from "@haklex/rich-editor";
|
|
4
|
+
import { SiGithub } from "@icons-pack/react-simple-icons";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { ExternalLink, Trash2 } from "lucide-react";
|
|
7
|
+
import { ActionBar, ActionButton } from "@haklex/rich-editor-ui";
|
|
8
|
+
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
9
|
+
//#region src/styles.css.ts
|
|
10
|
+
var semanticClassNames$1 = {
|
|
11
|
+
wrapper: "rich-embed-link-wrapper",
|
|
12
|
+
embed: "rich-embed",
|
|
13
|
+
embedGeneric: "rich-embed--generic",
|
|
14
|
+
embedTweet: "rich-embed--tweet",
|
|
15
|
+
embedYoutube: "rich-embed--youtube",
|
|
16
|
+
embedCodesandbox: "rich-embed--codesandbox",
|
|
17
|
+
embedBilibili: "rich-embed--bilibili",
|
|
18
|
+
embedGithubFile: "rich-embed--github-file",
|
|
19
|
+
embedGithubGist: "rich-embed--github-gist",
|
|
20
|
+
embedThinking: "rich-embed--thinking",
|
|
21
|
+
badge: "rich-embed__badge",
|
|
22
|
+
dot: "rich-embed__dot",
|
|
23
|
+
divider: "rich-embed__divider",
|
|
24
|
+
input: "rich-embed__input"
|
|
25
|
+
};
|
|
26
|
+
var semanticEmbedModifierClass = {
|
|
27
|
+
generic: "rich-embed--generic",
|
|
28
|
+
tweet: "rich-embed--tweet",
|
|
29
|
+
youtube: "rich-embed--youtube",
|
|
30
|
+
codesandbox: "rich-embed--codesandbox",
|
|
31
|
+
bilibili: "rich-embed--bilibili",
|
|
32
|
+
"github-file": "rich-embed--github-file",
|
|
33
|
+
"github-gist": "rich-embed--github-gist",
|
|
34
|
+
thinking: "rich-embed--thinking"
|
|
35
|
+
};
|
|
36
|
+
var wrapper = "_1qucygc1";
|
|
37
|
+
var embed = "_1qucygc2";
|
|
38
|
+
var embedType = {
|
|
39
|
+
generic: "_1qucygc3",
|
|
40
|
+
tweet: "_1qucygc4",
|
|
41
|
+
youtube: "_1qucygc5",
|
|
42
|
+
codesandbox: "_1qucygc6",
|
|
43
|
+
bilibili: "_1qucygc7",
|
|
44
|
+
"github-file": "_1qucygc8",
|
|
45
|
+
"github-gist": "_1qucygc9",
|
|
46
|
+
thinking: "_1qucygca"
|
|
47
|
+
};
|
|
48
|
+
var badge = "_1qucygcb";
|
|
49
|
+
var dot = "_1qucygcc";
|
|
50
|
+
var divider = "_1qucygcd";
|
|
51
|
+
var input = "_1qucygce";
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/context/EmbedRendererContext.tsx
|
|
54
|
+
var EmbedRendererCtx = createContext({});
|
|
55
|
+
var EmbedRendererProvider = EmbedRendererCtx.Provider;
|
|
56
|
+
function useEmbedRenderers() {
|
|
57
|
+
return use(EmbedRendererCtx);
|
|
58
|
+
}
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/styles-static.css.ts
|
|
61
|
+
var semanticClassNames = {
|
|
62
|
+
ratioContainer: "embed-static-ratio-container",
|
|
63
|
+
ratioInner: "embed-static-ratio-inner",
|
|
64
|
+
iframe: "embed-static-iframe",
|
|
65
|
+
gist: "embed-static-gist",
|
|
66
|
+
gistIframe: "embed-static-gist__iframe",
|
|
67
|
+
sourceLink: "embed-static-source-link",
|
|
68
|
+
githubFile: "embed-static-github-file",
|
|
69
|
+
githubFileCode: "embed-static-github-file__code",
|
|
70
|
+
githubFileCodeLong: "embed-static-github-file__code--long",
|
|
71
|
+
githubFileLine: "embed-static-github-file__line",
|
|
72
|
+
githubFileLineNum: "embed-static-github-file__line-num",
|
|
73
|
+
shiki: "embed-static-shiki",
|
|
74
|
+
fallback: "embed-static-fallback",
|
|
75
|
+
fallbackGeneric: "embed-static-fallback--generic",
|
|
76
|
+
fallbackTweet: "embed-static-fallback--tweet",
|
|
77
|
+
fallbackYoutube: "embed-static-fallback--youtube",
|
|
78
|
+
fallbackCodesandbox: "embed-static-fallback--codesandbox",
|
|
79
|
+
fallbackBilibili: "embed-static-fallback--bilibili",
|
|
80
|
+
fallbackGithubFile: "embed-static-fallback--github-file",
|
|
81
|
+
fallbackGithubGist: "embed-static-fallback--github-gist",
|
|
82
|
+
fallbackThinking: "embed-static-fallback--thinking",
|
|
83
|
+
fallbackBadge: "embed-static-fallback__badge",
|
|
84
|
+
fallbackDot: "embed-static-fallback__dot",
|
|
85
|
+
fallbackLink: "embed-static-fallback__link",
|
|
86
|
+
tweet: "embed-static-tweet",
|
|
87
|
+
loading: "embed-static-loading"
|
|
88
|
+
};
|
|
89
|
+
var semanticFallbackModifierClass = {
|
|
90
|
+
generic: "embed-static-fallback--generic",
|
|
91
|
+
tweet: "embed-static-fallback--tweet",
|
|
92
|
+
youtube: "embed-static-fallback--youtube",
|
|
93
|
+
codesandbox: "embed-static-fallback--codesandbox",
|
|
94
|
+
bilibili: "embed-static-fallback--bilibili",
|
|
95
|
+
"github-file": "embed-static-fallback--github-file",
|
|
96
|
+
"github-gist": "embed-static-fallback--github-gist",
|
|
97
|
+
thinking: "embed-static-fallback--thinking"
|
|
98
|
+
};
|
|
99
|
+
var ratioContainer = "_1xclnej1";
|
|
100
|
+
var ratioInner = "_1xclnej2";
|
|
101
|
+
var iframe = "_1xclnej3";
|
|
102
|
+
var gist = "_1xclnej4";
|
|
103
|
+
var gistIframe = "_1xclnej5";
|
|
104
|
+
var sourceLink = "_1xclnej6";
|
|
105
|
+
var githubFile = "_1xclnej7";
|
|
106
|
+
var githubFileCode = "_1xclnej8";
|
|
107
|
+
var githubFileCodeLong = "_1xclnej9";
|
|
108
|
+
var githubFileLine = "_1xclneja";
|
|
109
|
+
var githubFileLineNum = "_1xclnejb";
|
|
110
|
+
var shiki = "_1xclnejc";
|
|
111
|
+
var fallback = "_1xclnejd";
|
|
112
|
+
var fallbackType = {
|
|
113
|
+
generic: "_1xclneje",
|
|
114
|
+
tweet: "_1xclnejf",
|
|
115
|
+
youtube: "_1xclnejg",
|
|
116
|
+
codesandbox: "_1xclnejh",
|
|
117
|
+
bilibili: "_1xclneji",
|
|
118
|
+
"github-file": "_1xclnejj",
|
|
119
|
+
"github-gist": "_1xclnejk",
|
|
120
|
+
thinking: "_1xclnejl"
|
|
121
|
+
};
|
|
122
|
+
var fallbackBadge = "_1xclnejm";
|
|
123
|
+
var fallbackDot = "_1xclnejn";
|
|
124
|
+
var fallbackLink = "_1xclnejo";
|
|
125
|
+
var tweet = "_1xclnejp";
|
|
126
|
+
var loading = "_1xclnejq";
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/typeof.js
|
|
129
|
+
function _typeof(o) {
|
|
130
|
+
"@babel/helpers - typeof";
|
|
131
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
|
|
132
|
+
return typeof o;
|
|
133
|
+
} : function(o) {
|
|
134
|
+
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
|
135
|
+
}, _typeof(o);
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/toPrimitive.js
|
|
139
|
+
function toPrimitive(t, r) {
|
|
140
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
141
|
+
var e = t[Symbol.toPrimitive];
|
|
142
|
+
if (void 0 !== e) {
|
|
143
|
+
var i = e.call(t, r || "default");
|
|
144
|
+
if ("object" != _typeof(i)) return i;
|
|
145
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
146
|
+
}
|
|
147
|
+
return ("string" === r ? String : Number)(t);
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/toPropertyKey.js
|
|
151
|
+
function toPropertyKey(t) {
|
|
152
|
+
var i = toPrimitive(t, "string");
|
|
153
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region \0@oxc-project+runtime@0.127.0/helpers/defineProperty.js
|
|
157
|
+
function _defineProperty(e, r, t) {
|
|
158
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
159
|
+
value: t,
|
|
160
|
+
enumerable: !0,
|
|
161
|
+
configurable: !0,
|
|
162
|
+
writable: !0
|
|
163
|
+
}) : e[r] = t, e;
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/renderers/EmbedStaticRenderer.tsx
|
|
167
|
+
var extToLang = {
|
|
168
|
+
".js": "javascript",
|
|
169
|
+
".ts": "typescript",
|
|
170
|
+
".mjs": "javascript",
|
|
171
|
+
".cjs": "javascript",
|
|
172
|
+
".mts": "typescript",
|
|
173
|
+
".cts": "typescript",
|
|
174
|
+
".jsx": "jsx",
|
|
175
|
+
".tsx": "tsx",
|
|
176
|
+
".md": "markdown",
|
|
177
|
+
".css": "css",
|
|
178
|
+
".scss": "scss",
|
|
179
|
+
".html": "html",
|
|
180
|
+
".json": "json",
|
|
181
|
+
".yml": "yaml",
|
|
182
|
+
".yaml": "yaml",
|
|
183
|
+
".toml": "toml",
|
|
184
|
+
".xml": "xml",
|
|
185
|
+
".sh": "bash",
|
|
186
|
+
".bash": "bash",
|
|
187
|
+
".zsh": "bash",
|
|
188
|
+
".go": "go",
|
|
189
|
+
".py": "python",
|
|
190
|
+
".rb": "ruby",
|
|
191
|
+
".java": "java",
|
|
192
|
+
".c": "c",
|
|
193
|
+
".cpp": "cpp",
|
|
194
|
+
".cs": "csharp",
|
|
195
|
+
".rs": "rust",
|
|
196
|
+
".swift": "swift",
|
|
197
|
+
".kt": "kotlin",
|
|
198
|
+
".lua": "lua",
|
|
199
|
+
".sql": "sql",
|
|
200
|
+
".graphql": "graphql",
|
|
201
|
+
".scala": "scala",
|
|
202
|
+
".dart": "dart",
|
|
203
|
+
".vue": "vue",
|
|
204
|
+
".h": "c",
|
|
205
|
+
".hpp": "cpp",
|
|
206
|
+
".m": "objectivec",
|
|
207
|
+
".ex": "elixir",
|
|
208
|
+
".r": "r"
|
|
209
|
+
};
|
|
210
|
+
function getLangFromPath(path) {
|
|
211
|
+
const dot = path.lastIndexOf(".");
|
|
212
|
+
if (dot === -1) return "text";
|
|
213
|
+
return extToLang[path.slice(dot).toLowerCase()] || "text";
|
|
214
|
+
}
|
|
215
|
+
var shikiPromise = import("shiki/bundle/web").catch(() => null);
|
|
216
|
+
var typeLabels$1 = {
|
|
217
|
+
"tweet": "X / Twitter",
|
|
218
|
+
"youtube": "YouTube",
|
|
219
|
+
"codesandbox": "CodeSandbox",
|
|
220
|
+
"bilibili": "Bilibili",
|
|
221
|
+
"github-file": "GitHub File",
|
|
222
|
+
"github-gist": "GitHub Gist",
|
|
223
|
+
"thinking": "Thinking"
|
|
224
|
+
};
|
|
225
|
+
var LazyTweet = lazy(() => import("react-tweet").then((mod) => ({ default: mod.IsolatedTweet })));
|
|
226
|
+
var EmbedErrorBoundary = class extends Component {
|
|
227
|
+
constructor(..._args) {
|
|
228
|
+
super(..._args);
|
|
229
|
+
_defineProperty(this, "state", { hasError: false });
|
|
230
|
+
}
|
|
231
|
+
static getDerivedStateFromError() {
|
|
232
|
+
return { hasError: true };
|
|
233
|
+
}
|
|
234
|
+
render() {
|
|
235
|
+
return this.state.hasError ? this.props.fallback : this.props.children;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
function GitHubSvg() {
|
|
239
|
+
return /* @__PURE__ */ jsx(SiGithub, { size: 16 });
|
|
240
|
+
}
|
|
241
|
+
function FixedRatioContainer({ children, ratio = 58 }) {
|
|
242
|
+
return /* @__PURE__ */ jsx("div", {
|
|
243
|
+
className: `${ratioContainer} ${semanticClassNames.ratioContainer}`,
|
|
244
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
245
|
+
className: `${ratioInner} ${semanticClassNames.ratioInner}`,
|
|
246
|
+
style: { paddingBottom: `${ratio}%` },
|
|
247
|
+
children
|
|
248
|
+
})
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function FallbackLink({ url, type }) {
|
|
252
|
+
const label = type ? typeLabels$1[type] : "Embed";
|
|
253
|
+
const cssModifier = type || "generic";
|
|
254
|
+
const fallbackTypeClass = fallbackType[cssModifier];
|
|
255
|
+
const semanticModifierClass = semanticFallbackModifierClass[cssModifier];
|
|
256
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
257
|
+
className: `${fallback} ${fallbackTypeClass} ${semanticClassNames.fallback} ${semanticModifierClass}`.trim(),
|
|
258
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
259
|
+
className: `${fallbackBadge} ${semanticClassNames.fallbackBadge}`,
|
|
260
|
+
children: [/* @__PURE__ */ jsx("span", { className: `${fallbackDot} ${semanticClassNames.fallbackDot}` }), label]
|
|
261
|
+
}), /* @__PURE__ */ jsx("a", {
|
|
262
|
+
className: `${fallbackLink} ${semanticClassNames.fallbackLink}`,
|
|
263
|
+
href: url,
|
|
264
|
+
rel: "noreferrer",
|
|
265
|
+
target: "_blank",
|
|
266
|
+
children: url
|
|
267
|
+
})]
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function TweetRenderer({ url }) {
|
|
271
|
+
const colorScheme = useColorScheme();
|
|
272
|
+
let parsedUrl;
|
|
273
|
+
try {
|
|
274
|
+
parsedUrl = new URL(url);
|
|
275
|
+
} catch {
|
|
276
|
+
return /* @__PURE__ */ jsx(FallbackLink, {
|
|
277
|
+
type: "tweet",
|
|
278
|
+
url
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
const id = parsedUrl.pathname.split("/").pop();
|
|
282
|
+
if (!id) return /* @__PURE__ */ jsx(FallbackLink, {
|
|
283
|
+
type: "tweet",
|
|
284
|
+
url
|
|
285
|
+
});
|
|
286
|
+
return /* @__PURE__ */ jsx(EmbedErrorBoundary, {
|
|
287
|
+
fallback: /* @__PURE__ */ jsx(FallbackLink, {
|
|
288
|
+
type: "tweet",
|
|
289
|
+
url
|
|
290
|
+
}),
|
|
291
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
292
|
+
className: `${tweet} ${semanticClassNames.tweet}`,
|
|
293
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
294
|
+
fallback: /* @__PURE__ */ jsx("div", {
|
|
295
|
+
className: `${loading} ${semanticClassNames.loading}`,
|
|
296
|
+
children: "Loading tweet..."
|
|
297
|
+
}),
|
|
298
|
+
children: /* @__PURE__ */ jsx(LazyTweet, {
|
|
299
|
+
id,
|
|
300
|
+
style: { width: "100%" },
|
|
301
|
+
theme: colorScheme === "dark" ? "dark" : "light"
|
|
302
|
+
})
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function GithubFileEmbed({ url, href }) {
|
|
308
|
+
const shikiTheme = useColorScheme() === "dark" ? "github-dark" : "github-light";
|
|
309
|
+
const [, owner, repo, , ...rest] = url.pathname.split("/");
|
|
310
|
+
const ref = rest[0];
|
|
311
|
+
const path = ref ? rest.slice(1).join("/") : rest.join("/");
|
|
312
|
+
const matchResult = url.hash.match(/L\d+/g);
|
|
313
|
+
let startLine = 0;
|
|
314
|
+
let endLine;
|
|
315
|
+
if (matchResult) if (matchResult.length === 1) {
|
|
316
|
+
startLine = Number.parseInt(matchResult[0].slice(1)) - 1;
|
|
317
|
+
endLine = startLine + 1;
|
|
318
|
+
} else {
|
|
319
|
+
startLine = Number.parseInt(matchResult[0].slice(1)) - 1;
|
|
320
|
+
endLine = Number.parseInt(matchResult[1].slice(1));
|
|
321
|
+
}
|
|
322
|
+
const [content, setContent] = useState(null);
|
|
323
|
+
const [highlightedHtml, setHighlightedHtml] = useState(null);
|
|
324
|
+
const [loading$1, setLoading] = useState(true);
|
|
325
|
+
const [error, setError] = useState(false);
|
|
326
|
+
const lang = useMemo(() => getLangFromPath(path), [path]);
|
|
327
|
+
useEffect(() => {
|
|
328
|
+
let cancelled = false;
|
|
329
|
+
setContent(null);
|
|
330
|
+
setHighlightedHtml(null);
|
|
331
|
+
setLoading(true);
|
|
332
|
+
setError(false);
|
|
333
|
+
const fetchPromise = fetch(`https://cdn.jsdelivr.net/gh/${owner}/${repo}${ref ? `@${ref}` : ""}/${path}`).then((res) => {
|
|
334
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
335
|
+
return res.text();
|
|
336
|
+
});
|
|
337
|
+
Promise.all([fetchPromise, shikiPromise]).then(([text, shikiMod]) => {
|
|
338
|
+
if (cancelled) return;
|
|
339
|
+
setContent(text);
|
|
340
|
+
const lines = text.split("\n");
|
|
341
|
+
const end = endLine ?? lines.length;
|
|
342
|
+
const displayCode = lines.slice(startLine, end).join("\n");
|
|
343
|
+
if (!shikiMod) {
|
|
344
|
+
setLoading(false);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
shikiMod.codeToHtml(displayCode, {
|
|
348
|
+
lang,
|
|
349
|
+
theme: shikiTheme
|
|
350
|
+
}).then((html) => {
|
|
351
|
+
if (!cancelled) {
|
|
352
|
+
setHighlightedHtml(html);
|
|
353
|
+
setLoading(false);
|
|
354
|
+
}
|
|
355
|
+
}).catch(() => {
|
|
356
|
+
if (!cancelled) setLoading(false);
|
|
357
|
+
});
|
|
358
|
+
}).catch(() => {
|
|
359
|
+
if (!cancelled) {
|
|
360
|
+
setError(true);
|
|
361
|
+
setLoading(false);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
return () => {
|
|
365
|
+
cancelled = true;
|
|
366
|
+
};
|
|
367
|
+
}, [
|
|
368
|
+
owner,
|
|
369
|
+
repo,
|
|
370
|
+
ref,
|
|
371
|
+
path,
|
|
372
|
+
lang,
|
|
373
|
+
startLine,
|
|
374
|
+
endLine,
|
|
375
|
+
shikiTheme
|
|
376
|
+
]);
|
|
377
|
+
if (loading$1) return /* @__PURE__ */ jsx("div", {
|
|
378
|
+
className: `${loading} ${semanticClassNames.loading}`,
|
|
379
|
+
children: "Loading GitHub File Preview..."
|
|
380
|
+
});
|
|
381
|
+
if (error || content === null) return /* @__PURE__ */ jsx(FallbackLink, {
|
|
382
|
+
type: "github-file",
|
|
383
|
+
url: href
|
|
384
|
+
});
|
|
385
|
+
const lines = content.split("\n");
|
|
386
|
+
const end = endLine ?? lines.length;
|
|
387
|
+
const isLong = end - startLine > 20;
|
|
388
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
389
|
+
className: `${githubFile} ${semanticClassNames.githubFile}`,
|
|
390
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
391
|
+
className: `${githubFileCode} ${semanticClassNames.githubFileCode} ${isLong ? `${githubFileCodeLong} ${semanticClassNames.githubFileCodeLong}` : ""}`.trim(),
|
|
392
|
+
children: highlightedHtml ? /* @__PURE__ */ jsx("div", {
|
|
393
|
+
className: `${shiki} ${semanticClassNames.shiki}`,
|
|
394
|
+
dangerouslySetInnerHTML: { __html: highlightedHtml },
|
|
395
|
+
style: { "--start-line": startLine }
|
|
396
|
+
}) : /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: lines.slice(startLine, end).map((line, i) => /* @__PURE__ */ jsxs("span", {
|
|
397
|
+
className: `${githubFileLine} ${semanticClassNames.githubFileLine}`,
|
|
398
|
+
children: [
|
|
399
|
+
/* @__PURE__ */ jsx("span", {
|
|
400
|
+
className: `${githubFileLineNum} ${semanticClassNames.githubFileLineNum}`,
|
|
401
|
+
children: startLine + i + 1
|
|
402
|
+
}),
|
|
403
|
+
line,
|
|
404
|
+
"\n"
|
|
405
|
+
]
|
|
406
|
+
}, i)) }) })
|
|
407
|
+
}), /* @__PURE__ */ jsxs("a", {
|
|
408
|
+
className: `${sourceLink} ${semanticClassNames.sourceLink}`,
|
|
409
|
+
href,
|
|
410
|
+
rel: "noreferrer",
|
|
411
|
+
target: "_blank",
|
|
412
|
+
children: [/* @__PURE__ */ jsx(GitHubSvg, {}), /* @__PURE__ */ jsx("span", { children: href })]
|
|
413
|
+
})]
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
function EmbedStaticRenderer({ type, url }) {
|
|
417
|
+
const customRenderers = useEmbedRenderers();
|
|
418
|
+
if (!url) return null;
|
|
419
|
+
if (type && customRenderers[type]) {
|
|
420
|
+
const Custom = customRenderers[type];
|
|
421
|
+
return /* @__PURE__ */ jsx(Custom, {
|
|
422
|
+
type,
|
|
423
|
+
url
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
let parsedUrl;
|
|
427
|
+
try {
|
|
428
|
+
parsedUrl = new URL(url);
|
|
429
|
+
} catch {
|
|
430
|
+
return /* @__PURE__ */ jsx(FallbackLink, {
|
|
431
|
+
type,
|
|
432
|
+
url
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
switch (type) {
|
|
436
|
+
case "tweet": return /* @__PURE__ */ jsx(TweetRenderer, { url });
|
|
437
|
+
case "youtube": {
|
|
438
|
+
const id = parsedUrl.searchParams.get("v");
|
|
439
|
+
if (!id) return /* @__PURE__ */ jsx(FallbackLink, {
|
|
440
|
+
type,
|
|
441
|
+
url
|
|
442
|
+
});
|
|
443
|
+
return /* @__PURE__ */ jsx(FixedRatioContainer, { children: /* @__PURE__ */ jsx("iframe", {
|
|
444
|
+
allowFullScreen: true,
|
|
445
|
+
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
|
|
446
|
+
className: `${iframe} ${semanticClassNames.iframe}`,
|
|
447
|
+
src: `https://www.youtube.com/embed/${id}`,
|
|
448
|
+
title: "YouTube video player"
|
|
449
|
+
}) });
|
|
450
|
+
}
|
|
451
|
+
case "bilibili": {
|
|
452
|
+
const id = parsedUrl.pathname.split("/")[2];
|
|
453
|
+
if (!id) return /* @__PURE__ */ jsx(FallbackLink, {
|
|
454
|
+
type,
|
|
455
|
+
url
|
|
456
|
+
});
|
|
457
|
+
return /* @__PURE__ */ jsx(FixedRatioContainer, { children: /* @__PURE__ */ jsx("iframe", {
|
|
458
|
+
allowFullScreen: true,
|
|
459
|
+
className: `${iframe} ${semanticClassNames.iframe}`,
|
|
460
|
+
scrolling: "no",
|
|
461
|
+
src: `//player.bilibili.com/player.html?bvid=${id}&autoplay=0`
|
|
462
|
+
}) });
|
|
463
|
+
}
|
|
464
|
+
case "codesandbox": {
|
|
465
|
+
const path = parsedUrl.pathname.slice(2);
|
|
466
|
+
return /* @__PURE__ */ jsx(FixedRatioContainer, { children: /* @__PURE__ */ jsx("iframe", {
|
|
467
|
+
className: `${iframe} ${semanticClassNames.iframe}`,
|
|
468
|
+
src: `https://codesandbox.io/embed/${path}?fontsize=14&hidenavigation=1&theme=dark${parsedUrl.search}`
|
|
469
|
+
}) });
|
|
470
|
+
}
|
|
471
|
+
case "github-gist": {
|
|
472
|
+
const [, owner, id] = parsedUrl.pathname.split("/");
|
|
473
|
+
if (!owner || !id) return /* @__PURE__ */ jsx(FallbackLink, {
|
|
474
|
+
type,
|
|
475
|
+
url
|
|
476
|
+
});
|
|
477
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
478
|
+
className: `${gist} ${semanticClassNames.gist}`,
|
|
479
|
+
children: [/* @__PURE__ */ jsx("iframe", {
|
|
480
|
+
className: `${gistIframe} ${semanticClassNames.gistIframe}`,
|
|
481
|
+
src: `https://gist.github.com/${owner}/${id}.pibb`
|
|
482
|
+
}), /* @__PURE__ */ jsxs("a", {
|
|
483
|
+
className: `${sourceLink} ${semanticClassNames.sourceLink}`,
|
|
484
|
+
href: url,
|
|
485
|
+
rel: "noreferrer",
|
|
486
|
+
target: "_blank",
|
|
487
|
+
children: [/* @__PURE__ */ jsx(GitHubSvg, {}), /* @__PURE__ */ jsx("span", { children: url })]
|
|
488
|
+
})]
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
case "github-file": return /* @__PURE__ */ jsx(GithubFileEmbed, {
|
|
492
|
+
href: url,
|
|
493
|
+
url: parsedUrl
|
|
494
|
+
});
|
|
495
|
+
default: return /* @__PURE__ */ jsx(FallbackLink, {
|
|
496
|
+
type,
|
|
497
|
+
url
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
//#endregion
|
|
502
|
+
//#region src/nodes/EmbedNode.ts
|
|
503
|
+
var EmbedNode = class EmbedNode extends DecoratorNode {
|
|
504
|
+
static getType() {
|
|
505
|
+
return "embed";
|
|
506
|
+
}
|
|
507
|
+
static clone(node) {
|
|
508
|
+
return new EmbedNode(node.__url, node.__source, node.__key);
|
|
509
|
+
}
|
|
510
|
+
constructor(url, source, key) {
|
|
511
|
+
super(key);
|
|
512
|
+
_defineProperty(this, "__url", void 0);
|
|
513
|
+
_defineProperty(this, "__source", void 0);
|
|
514
|
+
this.__url = url;
|
|
515
|
+
this.__source = source;
|
|
516
|
+
}
|
|
517
|
+
createDOM(_config) {
|
|
518
|
+
const div = document.createElement("div");
|
|
519
|
+
div.className = `${wrapper} ${semanticClassNames$1.wrapper}`;
|
|
520
|
+
return div;
|
|
521
|
+
}
|
|
522
|
+
updateDOM() {
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
isInline() {
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
static importJSON(serializedNode) {
|
|
529
|
+
return $createEmbedNode(serializedNode.url, serializedNode.source);
|
|
530
|
+
}
|
|
531
|
+
exportJSON() {
|
|
532
|
+
return {
|
|
533
|
+
...super.exportJSON(),
|
|
534
|
+
type: "embed",
|
|
535
|
+
url: this.__url,
|
|
536
|
+
source: this.__source,
|
|
537
|
+
version: 1
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
getUrl() {
|
|
541
|
+
return this.getLatest().__url;
|
|
542
|
+
}
|
|
543
|
+
setUrl(url) {
|
|
544
|
+
const writable = this.getWritable();
|
|
545
|
+
writable.__url = url;
|
|
546
|
+
}
|
|
547
|
+
getSource() {
|
|
548
|
+
return this.getLatest().__source;
|
|
549
|
+
}
|
|
550
|
+
setSource(source) {
|
|
551
|
+
const writable = this.getWritable();
|
|
552
|
+
writable.__source = source;
|
|
553
|
+
}
|
|
554
|
+
decorate(_editor, _config) {
|
|
555
|
+
return createElement(EmbedStaticRenderer, {
|
|
556
|
+
type: this.__source,
|
|
557
|
+
url: this.__url
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
function $createEmbedNode(url, source) {
|
|
562
|
+
return new EmbedNode(url, source);
|
|
563
|
+
}
|
|
564
|
+
function $isEmbedNode(node) {
|
|
565
|
+
return node instanceof EmbedNode;
|
|
566
|
+
}
|
|
567
|
+
//#endregion
|
|
568
|
+
//#region src/url-matchers.ts
|
|
569
|
+
var isTweetUrl = (url) => (url.hostname === "twitter.com" || url.hostname === "x.com") && url.pathname.startsWith("/");
|
|
570
|
+
var isYoutubeUrl = (url) => url.hostname === "www.youtube.com" && url.pathname.startsWith("/watch");
|
|
571
|
+
var isCodesandboxUrl = (url) => url.hostname === "codesandbox.io" && url.pathname.split("/").length === 3;
|
|
572
|
+
var isBilibiliVideoUrl = (url) => url.hostname.includes("bilibili.com") && url.pathname.startsWith("/video/BV");
|
|
573
|
+
var isGithubFilePreviewUrl = (url) => {
|
|
574
|
+
const [, , , type] = url.pathname.split("/");
|
|
575
|
+
return url.hostname === "github.com" && type === "blob";
|
|
576
|
+
};
|
|
577
|
+
var isGistUrl = (url) => url.hostname === "gist.github.com";
|
|
578
|
+
function createSelfThinkingMatcher(hostnames) {
|
|
579
|
+
return (url) => hostnames.includes(url.hostname) && url.pathname.startsWith("/thinking/");
|
|
580
|
+
}
|
|
581
|
+
function matchEmbedUrl(url, selfThinkingMatcher) {
|
|
582
|
+
if (isTweetUrl(url)) return "tweet";
|
|
583
|
+
if (isYoutubeUrl(url)) return "youtube";
|
|
584
|
+
if (isCodesandboxUrl(url)) return "codesandbox";
|
|
585
|
+
if (isBilibiliVideoUrl(url)) return "bilibili";
|
|
586
|
+
if (isGithubFilePreviewUrl(url)) return "github-file";
|
|
587
|
+
if (isGistUrl(url)) return "github-gist";
|
|
588
|
+
if (selfThinkingMatcher?.(url)) return "thinking";
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
//#endregion
|
|
592
|
+
//#region src/renderers/EmbedLinkRenderer.tsx
|
|
593
|
+
var typeLabels = {
|
|
594
|
+
"tweet": "X / Twitter",
|
|
595
|
+
"youtube": "YouTube",
|
|
596
|
+
"codesandbox": "CodeSandbox",
|
|
597
|
+
"bilibili": "Bilibili",
|
|
598
|
+
"github-file": "GitHub File",
|
|
599
|
+
"github-gist": "GitHub Gist",
|
|
600
|
+
"thinking": "Thinking"
|
|
601
|
+
};
|
|
602
|
+
function EmbedLinkRenderer({ type, url, nodeKey }) {
|
|
603
|
+
const [editor] = useLexicalComposerContext();
|
|
604
|
+
const [editUrl, setEditUrl] = useState(url);
|
|
605
|
+
const inputRef = useRef(null);
|
|
606
|
+
useEffect(() => {
|
|
607
|
+
setEditUrl(url);
|
|
608
|
+
}, [url]);
|
|
609
|
+
useEffect(() => {
|
|
610
|
+
if (!url) inputRef.current?.focus();
|
|
611
|
+
}, [url]);
|
|
612
|
+
const commitUrl = useCallback(() => {
|
|
613
|
+
const trimmed = editUrl.trim();
|
|
614
|
+
if (!trimmed) return;
|
|
615
|
+
editor.update(() => {
|
|
616
|
+
const node = $getNodeByKey(nodeKey);
|
|
617
|
+
if (!node || !("setUrl" in node)) return;
|
|
618
|
+
const n = node;
|
|
619
|
+
if (n.getUrl?.() !== trimmed) n.setUrl(trimmed);
|
|
620
|
+
if (n.setSource) try {
|
|
621
|
+
n.setSource(matchEmbedUrl(new URL(trimmed)));
|
|
622
|
+
} catch {}
|
|
623
|
+
});
|
|
624
|
+
}, [
|
|
625
|
+
editor,
|
|
626
|
+
nodeKey,
|
|
627
|
+
editUrl
|
|
628
|
+
]);
|
|
629
|
+
const handleKeyDown = useCallback((e) => {
|
|
630
|
+
if (e.key === "Enter") {
|
|
631
|
+
e.preventDefault();
|
|
632
|
+
commitUrl();
|
|
633
|
+
inputRef.current?.blur();
|
|
634
|
+
} else if (e.key === "Escape") {
|
|
635
|
+
e.preventDefault();
|
|
636
|
+
setEditUrl(url);
|
|
637
|
+
inputRef.current?.blur();
|
|
638
|
+
}
|
|
639
|
+
}, [commitUrl, url]);
|
|
640
|
+
const handleDelete = useCallback(() => {
|
|
641
|
+
editor.update(() => {
|
|
642
|
+
const node = $getNodeByKey(nodeKey);
|
|
643
|
+
if (node) node.remove();
|
|
644
|
+
});
|
|
645
|
+
}, [editor, nodeKey]);
|
|
646
|
+
const handleOpen = useCallback(() => {
|
|
647
|
+
if (url) window.open(url, "_blank", "noopener,noreferrer");
|
|
648
|
+
}, [url]);
|
|
649
|
+
const label = type ? typeLabels[type] : "Embed";
|
|
650
|
+
const cssModifier = type || "generic";
|
|
651
|
+
const embedModifierClass = embedType[cssModifier];
|
|
652
|
+
const semanticModifierClass = semanticEmbedModifierClass[cssModifier];
|
|
653
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
654
|
+
className: `${embed} ${embedModifierClass} ${semanticClassNames$1.embed} ${semanticModifierClass}`.trim(),
|
|
655
|
+
children: [
|
|
656
|
+
/* @__PURE__ */ jsxs("span", {
|
|
657
|
+
className: `${badge} ${semanticClassNames$1.badge}`,
|
|
658
|
+
children: [/* @__PURE__ */ jsx("span", { className: `${dot} ${semanticClassNames$1.dot}` }), label]
|
|
659
|
+
}),
|
|
660
|
+
/* @__PURE__ */ jsx("span", { className: `${divider} ${semanticClassNames$1.divider}` }),
|
|
661
|
+
/* @__PURE__ */ jsx("input", {
|
|
662
|
+
className: `${input} ${semanticClassNames$1.input}`,
|
|
663
|
+
placeholder: "https://...",
|
|
664
|
+
ref: inputRef,
|
|
665
|
+
type: "url",
|
|
666
|
+
value: editUrl,
|
|
667
|
+
onBlur: commitUrl,
|
|
668
|
+
onChange: (e) => setEditUrl(e.target.value),
|
|
669
|
+
onKeyDown: handleKeyDown
|
|
670
|
+
}),
|
|
671
|
+
/* @__PURE__ */ jsxs(ActionBar, { children: [/* @__PURE__ */ jsx(ActionButton, {
|
|
672
|
+
icon: true,
|
|
673
|
+
disabled: !url,
|
|
674
|
+
size: "md",
|
|
675
|
+
title: "Open in new tab",
|
|
676
|
+
onClick: handleOpen,
|
|
677
|
+
children: /* @__PURE__ */ jsx(ExternalLink, {})
|
|
678
|
+
}), /* @__PURE__ */ jsx(ActionButton, {
|
|
679
|
+
danger: true,
|
|
680
|
+
icon: true,
|
|
681
|
+
size: "md",
|
|
682
|
+
title: "Delete",
|
|
683
|
+
onClick: handleDelete,
|
|
684
|
+
children: /* @__PURE__ */ jsx(Trash2, {})
|
|
685
|
+
})] })
|
|
686
|
+
]
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
//#endregion
|
|
690
|
+
export { isGistUrl as a, isYoutubeUrl as c, $isEmbedNode as d, EmbedNode as f, useEmbedRenderers as g, EmbedRendererProvider as h, isCodesandboxUrl as i, matchEmbedUrl as l, _defineProperty as m, createSelfThinkingMatcher as n, isGithubFilePreviewUrl as o, EmbedStaticRenderer as p, isBilibiliVideoUrl as r, isTweetUrl as s, EmbedLinkRenderer as t, $createEmbedNode as u };
|