@haklex/rich-renderer-codeblock 0.0.80 → 0.0.81
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/CodeBlockRenderer-ECu_hR7l.js +134 -0
- package/dist/constants.mjs +67 -70
- package/dist/icons-CnFW5y6g.js +230 -0
- package/dist/icons.mjs +2 -91
- package/dist/index.mjs +238 -270
- package/dist/rich-renderer-codeblock.css +2 -1
- package/dist/shiki.mjs +19 -28
- package/dist/static.mjs +3 -4
- package/package.json +5 -5
- package/dist/CodeBlockRenderer-DSXP75Xm.js +0 -125
- package/dist/language-UrxzhGSS.js +0 -154
package/dist/shiki.mjs
CHANGED
|
@@ -1,33 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/shiki.ts
|
|
2
|
+
var highlighterPromise = null;
|
|
2
3
|
function getHighlighter() {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
})
|
|
9
|
-
);
|
|
10
|
-
}
|
|
11
|
-
return highlighterPromise;
|
|
4
|
+
if (!highlighterPromise) highlighterPromise = import("shiki/bundle/web").then((mod) => mod.createHighlighter({
|
|
5
|
+
langs: [],
|
|
6
|
+
themes: ["github-light", "github-dark"]
|
|
7
|
+
}));
|
|
8
|
+
return highlighterPromise;
|
|
12
9
|
}
|
|
13
10
|
async function getHighlighterWithLang(language) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return highlighter;
|
|
11
|
+
const highlighter = await getHighlighter();
|
|
12
|
+
if (language && language !== "text" && language !== "plaintext") {
|
|
13
|
+
if (!highlighter.getLoadedLanguages().includes(language)) try {
|
|
14
|
+
await highlighter.loadLanguage(language);
|
|
15
|
+
} catch {}
|
|
16
|
+
}
|
|
17
|
+
return highlighter;
|
|
25
18
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
};
|
|
30
|
-
export {
|
|
31
|
-
SHIKI_DUAL_THEMES,
|
|
32
|
-
getHighlighterWithLang
|
|
19
|
+
var SHIKI_DUAL_THEMES = {
|
|
20
|
+
light: "github-light",
|
|
21
|
+
dark: "github-dark"
|
|
33
22
|
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { SHIKI_DUAL_THEMES, getHighlighterWithLang };
|
package/dist/static.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
1
|
+
import "./icons-CnFW5y6g.js";
|
|
2
|
+
import { t as CodeBlockRenderer } from "./CodeBlockRenderer-ECu_hR7l.js";
|
|
3
|
+
export { CodeBlockRenderer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haklex/rich-renderer-codeblock",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.81",
|
|
4
4
|
"description": "Code block renderer with Shiki syntax highlighting",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"@iconify/utils": "^3.1.0",
|
|
45
45
|
"lucide-react": "^0.577.0",
|
|
46
46
|
"shiki": "^4.0.1",
|
|
47
|
-
"@haklex/cm-editor": "0.0.
|
|
48
|
-
"@haklex/rich-editor": "0.0.
|
|
49
|
-
"@haklex/rich-
|
|
50
|
-
"@haklex/rich-
|
|
47
|
+
"@haklex/cm-editor": "0.0.81",
|
|
48
|
+
"@haklex/rich-editor": "0.0.81",
|
|
49
|
+
"@haklex/rich-editor-ui": "0.0.81",
|
|
50
|
+
"@haklex/rich-style-token": "0.0.81"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/react": "^19.2.14",
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useRef, useEffect, useCallback, useMemo } from "react";
|
|
3
|
-
import { Check, Copy, ChevronDown } from "lucide-react";
|
|
4
|
-
import { normalizeLanguage, getLanguageDisplayName, languageToColorMap } from "./constants.mjs";
|
|
5
|
-
import "@iconify/utils";
|
|
6
|
-
import "@iconify-json/material-icon-theme";
|
|
7
|
-
import { i as card, s as semanticClassNames, l as lang, h as hasLanguageIcon, a as LanguageIcon, j as copyButton, k as bodyBackground, m as expandWrap, n as expandButton, o as scroll, p as scrollCollapsed, c as lined, d as linedWithNumbers } from "./language-UrxzhGSS.js";
|
|
8
|
-
import { getHighlighterWithLang, SHIKI_DUAL_THEMES } from "./shiki.mjs";
|
|
9
|
-
const CopyIcon = /* @__PURE__ */ jsx(Copy, { size: 16 });
|
|
10
|
-
const CheckIcon = /* @__PURE__ */ jsx(Check, { size: 16 });
|
|
11
|
-
const ExpandIcon = /* @__PURE__ */ jsx(ChevronDown, { size: 14 });
|
|
12
|
-
function CodeBlockCard({
|
|
13
|
-
code,
|
|
14
|
-
language,
|
|
15
|
-
collapsible = true,
|
|
16
|
-
langSlot,
|
|
17
|
-
children
|
|
18
|
-
}) {
|
|
19
|
-
const normalizedLanguage = normalizeLanguage(language);
|
|
20
|
-
const [copied, setCopied] = useState(false);
|
|
21
|
-
const copyTimerRef = useRef(void 0);
|
|
22
|
-
const [isCollapsed, setIsCollapsed] = useState(true);
|
|
23
|
-
const [isOverflow, setIsOverflow] = useState(false);
|
|
24
|
-
const scrollRef = useRef(null);
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (!collapsible) {
|
|
27
|
-
setIsOverflow(false);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const el = scrollRef.current;
|
|
31
|
-
if (!el) return;
|
|
32
|
-
const check = () => {
|
|
33
|
-
const halfVh = window.innerHeight / 2;
|
|
34
|
-
setIsOverflow(el.scrollHeight >= halfVh);
|
|
35
|
-
};
|
|
36
|
-
const raf = requestAnimationFrame(check);
|
|
37
|
-
return () => cancelAnimationFrame(raf);
|
|
38
|
-
}, [code, collapsible]);
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
return () => clearTimeout(copyTimerRef.current);
|
|
41
|
-
}, []);
|
|
42
|
-
const handleCopy = useCallback(() => {
|
|
43
|
-
navigator.clipboard.writeText(code).then(() => {
|
|
44
|
-
setCopied(true);
|
|
45
|
-
clearTimeout(copyTimerRef.current);
|
|
46
|
-
copyTimerRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
47
|
-
}).catch(() => {
|
|
48
|
-
});
|
|
49
|
-
}, [code]);
|
|
50
|
-
const languageLabel = getLanguageDisplayName(normalizedLanguage);
|
|
51
|
-
const accent = languageToColorMap[normalizedLanguage] || "#737373";
|
|
52
|
-
const cardStyle = useMemo(() => ({ "--rr-code-accent": accent }), [accent]);
|
|
53
|
-
const scrollClassName = [
|
|
54
|
-
scroll,
|
|
55
|
-
semanticClassNames.scroll,
|
|
56
|
-
collapsible && isCollapsed && isOverflow && scrollCollapsed,
|
|
57
|
-
collapsible && isCollapsed && isOverflow && semanticClassNames.scrollCollapsed
|
|
58
|
-
].filter(Boolean).join(" ");
|
|
59
|
-
return /* @__PURE__ */ jsxs("div", { className: `${card} ${semanticClassNames.card}`, style: cardStyle, children: [
|
|
60
|
-
langSlot ?? (normalizedLanguage !== "text" && /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: `${lang} ${semanticClassNames.lang}`, children: hasLanguageIcon(normalizedLanguage) ? /* @__PURE__ */ jsx(LanguageIcon, { language: normalizedLanguage, size: 14 }) : /* @__PURE__ */ jsx("span", { children: languageLabel }) })),
|
|
61
|
-
/* @__PURE__ */ jsx(
|
|
62
|
-
"button",
|
|
63
|
-
{
|
|
64
|
-
"aria-label": copied ? "Copied" : "Copy code",
|
|
65
|
-
className: `${copyButton} ${semanticClassNames.copyButton}`,
|
|
66
|
-
type: "button",
|
|
67
|
-
onClick: handleCopy,
|
|
68
|
-
children: copied ? CheckIcon : CopyIcon
|
|
69
|
-
}
|
|
70
|
-
),
|
|
71
|
-
/* @__PURE__ */ jsxs("div", { className: `${bodyBackground} ${semanticClassNames.bodyBackground}`, children: [
|
|
72
|
-
/* @__PURE__ */ jsx("div", { className: scrollClassName, ref: scrollRef, children }),
|
|
73
|
-
collapsible && isOverflow && isCollapsed && /* @__PURE__ */ jsx("div", { className: `${expandWrap} ${semanticClassNames.expandWrap}`, children: /* @__PURE__ */ jsxs(
|
|
74
|
-
"button",
|
|
75
|
-
{
|
|
76
|
-
className: `${expandButton} ${semanticClassNames.expandButton}`,
|
|
77
|
-
type: "button",
|
|
78
|
-
onClick: () => setIsCollapsed(false),
|
|
79
|
-
children: [
|
|
80
|
-
ExpandIcon,
|
|
81
|
-
/* @__PURE__ */ jsx("span", { children: "展开" })
|
|
82
|
-
]
|
|
83
|
-
}
|
|
84
|
-
) })
|
|
85
|
-
] })
|
|
86
|
-
] });
|
|
87
|
-
}
|
|
88
|
-
const CodeBlockRenderer = ({
|
|
89
|
-
code,
|
|
90
|
-
language,
|
|
91
|
-
showLineNumbers: showLineNumbersProp
|
|
92
|
-
}) => {
|
|
93
|
-
const showLineNumbers = showLineNumbersProp ?? false;
|
|
94
|
-
const normalizedLanguage = normalizeLanguage(language);
|
|
95
|
-
const [html, setHtml] = useState(null);
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
let cancelled = false;
|
|
98
|
-
(async () => {
|
|
99
|
-
const highlighter = await getHighlighterWithLang(normalizedLanguage);
|
|
100
|
-
if (cancelled) return;
|
|
101
|
-
const loaded = highlighter.getLoadedLanguages();
|
|
102
|
-
const lang2 = loaded.includes(normalizedLanguage) ? normalizedLanguage : "text";
|
|
103
|
-
const result = highlighter.codeToHtml(code, {
|
|
104
|
-
lang: lang2,
|
|
105
|
-
themes: SHIKI_DUAL_THEMES
|
|
106
|
-
});
|
|
107
|
-
if (!cancelled) setHtml(result);
|
|
108
|
-
})();
|
|
109
|
-
return () => {
|
|
110
|
-
cancelled = true;
|
|
111
|
-
};
|
|
112
|
-
}, [code, normalizedLanguage]);
|
|
113
|
-
const fallbackLines = useMemo(() => code.split("\n"), [code]);
|
|
114
|
-
const linedClassName = [
|
|
115
|
-
showLineNumbers && lined,
|
|
116
|
-
showLineNumbers && semanticClassNames.lined,
|
|
117
|
-
showLineNumbers && linedWithNumbers,
|
|
118
|
-
showLineNumbers && semanticClassNames.linedWithNumbers
|
|
119
|
-
].filter(Boolean).join(" ");
|
|
120
|
-
return /* @__PURE__ */ jsx(CodeBlockCard, { code, language, children: html ? /* @__PURE__ */ jsx("div", { className: linedClassName, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx("pre", { className: linedClassName, children: /* @__PURE__ */ jsx("code", { children: fallbackLines.map((line, i) => /* @__PURE__ */ jsx("span", { className: "line", children: line }, i)) }) }) });
|
|
121
|
-
};
|
|
122
|
-
export {
|
|
123
|
-
CodeBlockRenderer as C,
|
|
124
|
-
CodeBlockCard as a
|
|
125
|
-
};
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo } from "react";
|
|
3
|
-
import { getIconData, iconToSVG, iconToHTML } from "@iconify/utils";
|
|
4
|
-
import { icons } from "@iconify-json/material-icon-theme";
|
|
5
|
-
function getMaterialIconSvg(iconName) {
|
|
6
|
-
const data = getIconData(icons, iconName);
|
|
7
|
-
if (!data) return null;
|
|
8
|
-
const svg = iconToSVG(data);
|
|
9
|
-
return iconToHTML(svg.body, svg.attributes);
|
|
10
|
-
}
|
|
11
|
-
var semanticClassNames = { card: "rr-code-card", lang: "rr-code-lang", langIcon: "rr-code-lang-icon", copyButton: "rr-code-copy", bodyBackground: "rr-code-bg", scroll: "rr-code-scroll", scrollCollapsed: "rr-code-scroll-collapsed", body: "rr-code-body", bodyReadonly: "rr-code-readonly", expandWrap: "rr-code-expand-wrap", expandButton: "rr-code-expand", lined: "rr-code-lined", linedWithNumbers: "rr-code-lined-ln" };
|
|
12
|
-
var card = "_1pn9r4q0";
|
|
13
|
-
var langInput = "_1pn9r4q1";
|
|
14
|
-
var lang = "_1pn9r4q2";
|
|
15
|
-
var langIcon = "_1pn9r4q3";
|
|
16
|
-
var copyButton = "_1pn9r4q4";
|
|
17
|
-
var bodyBackground = "_1pn9r4q5";
|
|
18
|
-
var scroll = "_1pn9r4q6";
|
|
19
|
-
var scrollCollapsed = "_1pn9r4q7";
|
|
20
|
-
var body = "_1pn9r4q8";
|
|
21
|
-
var bodyReadonly = "_1pn9r4q9";
|
|
22
|
-
var expandWrap = "_1pn9r4qa";
|
|
23
|
-
var expandButton = "_1pn9r4qb";
|
|
24
|
-
var lined = "_1pn9r4qc";
|
|
25
|
-
var linedWithNumbers = "_1pn9r4qd";
|
|
26
|
-
const LANG_TO_ICON = {
|
|
27
|
-
"javascript": "javascript",
|
|
28
|
-
"js": "javascript",
|
|
29
|
-
"typescript": "typescript",
|
|
30
|
-
"ts": "typescript",
|
|
31
|
-
"angular-ts": "angular",
|
|
32
|
-
"angular-html": "angular",
|
|
33
|
-
"jsx": "react",
|
|
34
|
-
"tsx": "react",
|
|
35
|
-
"html": "html",
|
|
36
|
-
"html-derivative": "html",
|
|
37
|
-
"css": "css",
|
|
38
|
-
"scss": "sass",
|
|
39
|
-
"sass": "sass",
|
|
40
|
-
"less": "sass",
|
|
41
|
-
"postcss": "postcss",
|
|
42
|
-
"stylus": "stylus",
|
|
43
|
-
"json": "json",
|
|
44
|
-
"json5": "json",
|
|
45
|
-
"jsonc": "json",
|
|
46
|
-
"jsonl": "json",
|
|
47
|
-
"markdown": "markdown",
|
|
48
|
-
"md": "markdown",
|
|
49
|
-
"mdx": "markdown",
|
|
50
|
-
"mdc": "markdown",
|
|
51
|
-
"bash": "console",
|
|
52
|
-
"sh": "console",
|
|
53
|
-
"shell": "console",
|
|
54
|
-
"shellscript": "console",
|
|
55
|
-
"zsh": "console",
|
|
56
|
-
"python": "python",
|
|
57
|
-
"py": "python",
|
|
58
|
-
"rust": "rust",
|
|
59
|
-
"go": "go",
|
|
60
|
-
"java": "java",
|
|
61
|
-
"c": "c",
|
|
62
|
-
"cpp": "cpp",
|
|
63
|
-
"c++": "cpp",
|
|
64
|
-
"swift": "swift",
|
|
65
|
-
"kotlin": "kotlin",
|
|
66
|
-
"kt": "kotlin",
|
|
67
|
-
"yaml": "yaml",
|
|
68
|
-
"yml": "yaml",
|
|
69
|
-
"sql": "database",
|
|
70
|
-
"xml": "xml",
|
|
71
|
-
"vue": "vue",
|
|
72
|
-
"vue-html": "vue",
|
|
73
|
-
"vue-vine": "vue",
|
|
74
|
-
"svelte": "svelte",
|
|
75
|
-
"astro": "astro",
|
|
76
|
-
"php": "php",
|
|
77
|
-
"rb": "ruby",
|
|
78
|
-
"r": "r",
|
|
79
|
-
"julia": "julia",
|
|
80
|
-
"lua": "lua",
|
|
81
|
-
"zig": "zig",
|
|
82
|
-
"toml": "toml",
|
|
83
|
-
"graphql": "graphql",
|
|
84
|
-
"gql": "graphql",
|
|
85
|
-
"dockerfile": "docker",
|
|
86
|
-
"coffee": "coffee",
|
|
87
|
-
"pug": "pug",
|
|
88
|
-
"haml": "haml",
|
|
89
|
-
"handlebars": "handlebars",
|
|
90
|
-
"marko": "markojs",
|
|
91
|
-
"imba": "imba",
|
|
92
|
-
"hurl": "hurl",
|
|
93
|
-
"http": "http"
|
|
94
|
-
};
|
|
95
|
-
function getLanguageIconSvg(lang2) {
|
|
96
|
-
const iconName = LANG_TO_ICON[lang2] ?? "code";
|
|
97
|
-
return getMaterialIconSvg(iconName);
|
|
98
|
-
}
|
|
99
|
-
function hasLanguageIcon(lang2) {
|
|
100
|
-
return getLanguageIconSvg(lang2) !== null;
|
|
101
|
-
}
|
|
102
|
-
const LanguageIcon = ({
|
|
103
|
-
language,
|
|
104
|
-
size = 14,
|
|
105
|
-
className = `${langIcon} ${semanticClassNames.langIcon}`
|
|
106
|
-
}) => {
|
|
107
|
-
const html = useMemo(() => getLanguageIconSvg(language), [language]);
|
|
108
|
-
if (!html) {
|
|
109
|
-
return /* @__PURE__ */ jsx(
|
|
110
|
-
"span",
|
|
111
|
-
{
|
|
112
|
-
className,
|
|
113
|
-
style: {
|
|
114
|
-
width: size,
|
|
115
|
-
height: size,
|
|
116
|
-
display: "inline-flex",
|
|
117
|
-
alignItems: "center",
|
|
118
|
-
justifyContent: "center",
|
|
119
|
-
opacity: 0.6,
|
|
120
|
-
fontSize: size * 0.6
|
|
121
|
-
},
|
|
122
|
-
children: "•"
|
|
123
|
-
}
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
return /* @__PURE__ */ jsx(
|
|
127
|
-
"span",
|
|
128
|
-
{
|
|
129
|
-
className,
|
|
130
|
-
dangerouslySetInnerHTML: { __html: html },
|
|
131
|
-
style: { width: size, height: size }
|
|
132
|
-
}
|
|
133
|
-
);
|
|
134
|
-
};
|
|
135
|
-
export {
|
|
136
|
-
LANG_TO_ICON as L,
|
|
137
|
-
LanguageIcon as a,
|
|
138
|
-
langInput as b,
|
|
139
|
-
lined as c,
|
|
140
|
-
linedWithNumbers as d,
|
|
141
|
-
body as e,
|
|
142
|
-
bodyReadonly as f,
|
|
143
|
-
getMaterialIconSvg as g,
|
|
144
|
-
hasLanguageIcon as h,
|
|
145
|
-
card as i,
|
|
146
|
-
copyButton as j,
|
|
147
|
-
bodyBackground as k,
|
|
148
|
-
lang as l,
|
|
149
|
-
expandWrap as m,
|
|
150
|
-
expandButton as n,
|
|
151
|
-
scroll as o,
|
|
152
|
-
scrollCollapsed as p,
|
|
153
|
-
semanticClassNames as s
|
|
154
|
-
};
|