@lobehub/editor 4.6.1 → 4.6.2

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.
Files changed (2) hide show
  1. package/es/renderer.js +10 -211
  2. package/package.json +1 -1
package/es/renderer.js CHANGED
@@ -4,19 +4,17 @@ import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
4
4
  import { $getRoot, $isElementNode, $isTextNode } from "lexical";
5
5
  import { HeadingNode, QuoteNode } from "@lexical/rich-text";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import { createElement, useCallback, useMemo, useState } from "react";
8
- import { ActionIcon, Block, Flexbox, MaterialFileTypeIcon, Mermaid, Text } from "@lobehub/ui";
7
+ import { createElement, useMemo } from "react";
8
+ import { Highlighter, Mermaid } from "@lobehub/ui";
9
9
  import katex from "katex";
10
10
  import { createStaticStyles, cx } from "antd-style";
11
11
  import { ListItemNode, ListNode } from "@lexical/list";
12
- import { Check, ChevronDown, ChevronRight, CopyIcon } from "lucide-react";
13
- import { createHighlighterCoreSync, isSpecialLang, stringifyTokenStyle } from "@shikijs/core";
12
+ import { createHighlighterCoreSync, isSpecialLang } from "@shikijs/core";
14
13
  import { createJavaScriptRegexEngine } from "@shikijs/engine-javascript";
15
14
  import { bundledLanguagesInfo } from "shiki";
16
15
  import { createHeadlessEditor } from "@lexical/headless";
17
16
  //#region src/renderer/engine/shiki.ts
18
17
  let _highlighter = null;
19
- let _themeLoaded = false;
20
18
  function getHighlighter() {
21
19
  if (!_highlighter) _highlighter = createHighlighterCoreSync({
22
20
  engine: createJavaScriptRegexEngine(),
@@ -25,63 +23,15 @@ function getHighlighter() {
25
23
  });
26
24
  return _highlighter;
27
25
  }
28
- async function ensureTheme(highlighter) {
29
- if (_themeLoaded) return;
30
- try {
31
- const { ShikiLobeTheme } = await import("@lobehub/ui");
32
- highlighter.loadThemeSync(ShikiLobeTheme);
33
- _themeLoaded = true;
34
- } catch {}
35
- }
36
26
  function isLanguageLoaded(language) {
37
27
  if (isSpecialLang(language)) return true;
38
28
  return getHighlighter().getLoadedLanguages().includes(language);
39
29
  }
40
- function parseInlineStyle(style) {
41
- const result = {};
42
- for (const part of style.split(";")) {
43
- const colonIdx = part.indexOf(":");
44
- if (colonIdx === -1) continue;
45
- const prop = part.slice(0, colonIdx).trim();
46
- const val = part.slice(colonIdx + 1).trim();
47
- if (!prop || !val) continue;
48
- const camelProp = prop.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
49
- result[camelProp] = val;
50
- }
51
- return result;
52
- }
53
30
  async function loadLanguage(language) {
54
31
  if (isLanguageLoaded(language)) return;
55
32
  const info = bundledLanguagesInfo.find((desc) => desc.id === language || desc.aliases?.includes(language));
56
33
  if (info) await getHighlighter().loadLanguage(info.import());
57
34
  }
58
- function highlightCode(code, language, key) {
59
- if (!language || !isLanguageLoaded(language)) return null;
60
- const highlighter = getHighlighter();
61
- ensureTheme(highlighter);
62
- const theme = _themeLoaded ? "lobe-theme" : highlighter.getLoadedThemes()[0] || "none";
63
- try {
64
- const { tokens } = highlighter.codeToTokens(code, {
65
- lang: language,
66
- theme
67
- });
68
- const nodes = [];
69
- for (const [lineIdx, line] of tokens.entries()) {
70
- if (lineIdx > 0) nodes.push(createElement("br", { key: `${key}-br-${lineIdx}` }));
71
- for (const [tokenIdx, token] of line.entries()) {
72
- const tokenStyle = stringifyTokenStyle(token.htmlStyle || (token.color ? `color: ${token.color}` : ""));
73
- if (tokenStyle) nodes.push(createElement("span", {
74
- key: `${key}-${lineIdx}-${tokenIdx}`,
75
- style: parseInlineStyle(tokenStyle)
76
- }, token.content));
77
- else nodes.push(token.content);
78
- }
79
- }
80
- return nodes;
81
- } catch {
82
- return null;
83
- }
84
- }
85
35
  //#endregion
86
36
  //#region src/renderer/style.ts
87
37
  const tableHeaderFix = createStaticStyles(({ css, cssVar }) => css`
@@ -375,170 +325,19 @@ function renderMermaidBlock(node, key) {
375
325
  }
376
326
  //#endregion
377
327
  //#region src/renderer/renderers/codeblock.tsx
378
- const useStyles$1 = createStaticStyles(({ css, cssVar }) => css`
379
- cursor: default;
380
-
381
- overflow: hidden;
382
- display: flex;
383
- flex-direction: column;
384
- align-items: center;
385
-
386
- width: 100%;
387
- margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);
388
- border-radius: var(--lobe-markdown-border-radius);
389
-
390
- background: ${cssVar.colorFillQuaternary};
391
-
392
- .renderer-cm-header {
393
- width: 100%;
394
- }
395
-
396
- .renderer-cm-code {
397
- width: 100%;
398
- border-block-start: 1px solid ${cssVar.colorFillQuaternary};
399
- }
400
-
401
- .renderer-cm-pre {
402
- overflow-x: auto;
403
-
404
- margin: 0;
405
- padding: 16px;
406
-
407
- font-family: ${cssVar.fontFamilyCode};
408
- font-size: calc(var(--lobe-markdown-font-size) * 0.85);
409
- line-height: 1.6;
410
- white-space: pre;
411
-
412
- background: transparent;
413
-
414
- code {
415
- font-family: inherit;
416
- font-size: inherit;
417
- }
418
- }
419
-
420
- .renderer-cm-collapsed {
421
- overflow: hidden;
422
- height: 0;
423
- border-block-start: none;
424
- }
425
- `);
426
- function CodeBlockCopyButton({ code }) {
427
- const [copied, setCopied] = useState(false);
428
- const handleCopy = useCallback(() => {
429
- navigator.clipboard.writeText(code).catch(() => {});
430
- setCopied(true);
431
- setTimeout(() => setCopied(false), 1e3);
432
- }, [code]);
433
- return /* @__PURE__ */ jsx(ActionIcon, {
434
- active: copied,
435
- icon: copied ? Check : CopyIcon,
436
- onClick: handleCopy,
437
- size: "small",
438
- title: "Copy"
439
- });
440
- }
441
- function getLanguageName(lang) {
442
- return {
443
- bash: "Bash",
444
- c: "C",
445
- cpp: "C++",
446
- csharp: "C#",
447
- css: "CSS",
448
- dart: "Dart",
449
- go: "Go",
450
- graphql: "GraphQL",
451
- html: "HTML",
452
- java: "Java",
453
- javascript: "JavaScript",
454
- json: "JSON",
455
- jsx: "JSX",
456
- kotlin: "Kotlin",
457
- lua: "Lua",
458
- markdown: "Markdown",
459
- php: "PHP",
460
- python: "Python",
461
- ruby: "Ruby",
462
- rust: "Rust",
463
- scss: "SCSS",
464
- shell: "Shell",
465
- sql: "SQL",
466
- swift: "Swift",
467
- tsx: "TSX",
468
- typescript: "TypeScript",
469
- xml: "XML",
470
- yaml: "YAML"
471
- }[lang] || lang.charAt(0).toUpperCase() + lang.slice(1);
472
- }
473
- function getFileExt(lang) {
474
- return {
475
- bash: "sh",
476
- csharp: "cs",
477
- javascript: "js",
478
- kotlin: "kt",
479
- markdown: "md",
480
- python: "py",
481
- ruby: "rb",
482
- rust: "rs",
483
- shell: "sh",
484
- swift: "swift",
485
- typescript: "ts",
486
- yaml: "yml"
487
- }[lang] || lang;
488
- }
489
- function CodeBlockRenderer({ node, codeChildren }) {
328
+ function CodeBlockRenderer({ node }) {
490
329
  const language = node.language || "";
491
330
  const code = node.code || "";
492
- const [expand, setExpand] = useState(true);
493
- const codeContent = codeChildren || highlightCode(code, language, "cb") || code;
494
- return /* @__PURE__ */ jsxs(Block, {
495
- className: useStyles$1,
331
+ return /* @__PURE__ */ jsx(Highlighter, {
332
+ defaultExpand: true,
333
+ language: language || "text",
496
334
  variant: "filled",
497
- children: [/* @__PURE__ */ jsxs(Flexbox, {
498
- align: "center",
499
- className: "renderer-cm-header",
500
- horizontal: true,
501
- justify: "space-between",
502
- padding: 4,
503
- children: [/* @__PURE__ */ jsxs(Flexbox, {
504
- align: "center",
505
- gap: 4,
506
- horizontal: true,
507
- children: [language && /* @__PURE__ */ jsx(MaterialFileTypeIcon, {
508
- fallbackUnknownType: false,
509
- filename: `*.${getFileExt(language)}`,
510
- size: 18,
511
- type: "file",
512
- variant: "raw"
513
- }), /* @__PURE__ */ jsx(Text, {
514
- ellipsis: true,
515
- fontSize: 13,
516
- children: language ? getLanguageName(language) : "Plain Text"
517
- })]
518
- }), /* @__PURE__ */ jsxs(Flexbox, {
519
- gap: 4,
520
- horizontal: true,
521
- children: [/* @__PURE__ */ jsx(CodeBlockCopyButton, { code }), /* @__PURE__ */ jsx(ActionIcon, {
522
- icon: expand ? ChevronDown : ChevronRight,
523
- onClick: () => setExpand(!expand),
524
- size: "small"
525
- })]
526
- })]
527
- }), /* @__PURE__ */ jsx("div", {
528
- className: expand ? "renderer-cm-code" : "renderer-cm-code renderer-cm-collapsed",
529
- children: /* @__PURE__ */ jsx("pre", {
530
- className: "renderer-cm-pre",
531
- children: /* @__PURE__ */ jsx("code", { children: codeContent })
532
- })
533
- })]
335
+ children: code
534
336
  });
535
337
  }
536
- function renderCodeBlock(node, key, children) {
338
+ function renderCodeBlock(node, key) {
537
339
  if ((node.language || "").toLowerCase() === "mermaid") return renderMermaidBlock(node, key);
538
- return /* @__PURE__ */ jsx(CodeBlockRenderer, {
539
- codeChildren: children,
540
- node
541
- }, key);
340
+ return /* @__PURE__ */ jsx(CodeBlockRenderer, { node }, key);
542
341
  }
543
342
  //#endregion
544
343
  //#region src/renderer/renderers/file.tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/editor",
3
- "version": "4.6.1",
3
+ "version": "4.6.2",
4
4
  "description": "A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.",
5
5
  "keywords": [
6
6
  "lobehub",