@haklex/rich-ext-embed 0.1.1 → 0.2.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.
@@ -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 };