@haklex/rich-renderer-codeblock 0.0.4 → 0.0.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockCard.d.ts","sourceRoot":"","sources":["../src/CodeBlockCard.tsx"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAA;AAGrB,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAcrD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,2CAwFpB"}
1
+ {"version":3,"file":"CodeBlockCard.d.ts","sourceRoot":"","sources":["../src/CodeBlockCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAerD,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,2CAuGpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockEditRenderer.d.ts","sourceRoot":"","sources":["../src/CodeBlockEditRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAO1C,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,sBAAsB,CA4KvE,CAAA"}
1
+ {"version":3,"file":"CodeBlockEditRenderer.d.ts","sourceRoot":"","sources":["../src/CodeBlockEditRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAQ1C,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,sBAAsB,CAmLvE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlockRenderer.d.ts","sourceRoot":"","sources":["../src/CodeBlockRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAO1C,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,sBAAsB,CA8DnE,CAAA;AAED,eAAe,iBAAiB,CAAA"}
1
+ {"version":3,"file":"CodeBlockRenderer.d.ts","sourceRoot":"","sources":["../src/CodeBlockRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAQ1C,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,sBAAsB,CAgEnE,CAAA;AAED,eAAe,iBAAiB,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { FC, ReactNode } from 'react';
2
+ /** Maps file extension to material-icon-theme icon name. */
3
+ export declare const EXT_TO_ICON: Record<string, string>;
4
+ export interface FileIconProps {
5
+ filename: string;
6
+ size?: number;
7
+ /** Optional class for the wrapper (e.g. consumer styles). */
8
+ className?: string;
9
+ /** Fallback when no icon is found. Default "F". */
10
+ fallback?: ReactNode;
11
+ }
12
+ export declare const FileIcon: FC<FileIconProps>;
13
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/icons/file.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAK1C,4DAA4D;AAC5D,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkD9C,CAAA;AAQD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAA;CACrB;AAED,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAiCtC,CAAA"}
@@ -0,0 +1,5 @@
1
+ export type { FileIconProps } from './file';
2
+ export { FileIcon } from './file';
3
+ export { hasLanguageIcon, LANG_TO_ICON, LanguageIcon } from './language';
4
+ export { getMaterialIconSvg } from './material-icon';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/icons/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACjC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAC,YAAY,EAAE,MAAM,YAAY,CAAA;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { FC } from 'react';
2
+ /** Maps normalized language to material-icon-theme icon name. */
3
+ export declare const LANG_TO_ICON: Record<string, string>;
4
+ /** Returns whether a Material icon is available for the given language. */
5
+ export declare function hasLanguageIcon(lang: string): boolean;
6
+ export declare const LanguageIcon: FC<{
7
+ language: string;
8
+ size?: number;
9
+ className?: string;
10
+ }>;
11
+ //# sourceMappingURL=language.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language.d.ts","sourceRoot":"","sources":["../../src/icons/language.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAM/B,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA8C/C,CAAA;AAOD,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAiCA,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** Get SVG markup for a material-icon-theme icon by name. Returns null if not found. */
2
+ export declare function getMaterialIconSvg(iconName: string): string | null;
3
+ //# sourceMappingURL=material-icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-icon.d.ts","sourceRoot":"","sources":["../../src/icons/material-icon.ts"],"names":[],"mappings":"AAGA,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlE"}
package/dist/icons.mjs ADDED
@@ -0,0 +1,96 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { n as getMaterialIconSvg } from "./language-AfAZN4lZ.js";
4
+ import { o, L, h } from "./language-AfAZN4lZ.js";
5
+ const EXT_TO_ICON = {
6
+ ts: "typescript",
7
+ tsx: "react-ts",
8
+ // TSX → React icon (same as JSX)
9
+ mts: "typescript",
10
+ cts: "typescript",
11
+ js: "javascript",
12
+ jsx: "react",
13
+ mjs: "javascript",
14
+ cjs: "javascript",
15
+ py: "python",
16
+ rs: "rust",
17
+ go: "go",
18
+ java: "java",
19
+ html: "html",
20
+ htm: "html",
21
+ css: "css",
22
+ scss: "sass",
23
+ sass: "sass",
24
+ less: "sass",
25
+ json: "json",
26
+ jsonc: "json",
27
+ json5: "json",
28
+ md: "markdown",
29
+ mdx: "markdown",
30
+ sh: "console",
31
+ bash: "console",
32
+ zsh: "console",
33
+ yml: "yaml",
34
+ yaml: "yaml",
35
+ sql: "database",
36
+ c: "c",
37
+ h: "c",
38
+ cpp: "cpp",
39
+ cc: "cpp",
40
+ cxx: "cpp",
41
+ hpp: "cpp",
42
+ swift: "swift",
43
+ kt: "kotlin",
44
+ kts: "kotlin",
45
+ rb: "ruby",
46
+ php: "php",
47
+ vue: "vue",
48
+ svelte: "svelte",
49
+ toml: "toml",
50
+ xml: "xml",
51
+ graphql: "graphql",
52
+ gql: "graphql",
53
+ dockerfile: "docker",
54
+ lua: "lua",
55
+ zig: "zig"
56
+ };
57
+ function getFileIconSvg(filename) {
58
+ const ext = filename.split(".").pop()?.toLowerCase() ?? "";
59
+ const iconName = EXT_TO_ICON[ext] ?? "file";
60
+ return getMaterialIconSvg(iconName);
61
+ }
62
+ const FileIcon = ({
63
+ filename,
64
+ size = 16,
65
+ className,
66
+ fallback = "F"
67
+ }) => {
68
+ const html = useMemo(() => getFileIconSvg(filename), [filename]);
69
+ const wrapperStyle = {
70
+ width: size,
71
+ height: size,
72
+ display: "inline-flex",
73
+ alignItems: "center",
74
+ justifyContent: "center",
75
+ opacity: html ? 1 : 0.5,
76
+ fontSize: size * 0.6
77
+ };
78
+ if (!html) {
79
+ return /* @__PURE__ */ jsx("span", { className, style: wrapperStyle, children: fallback });
80
+ }
81
+ return /* @__PURE__ */ jsx(
82
+ "span",
83
+ {
84
+ className,
85
+ style: { width: size, height: size },
86
+ dangerouslySetInnerHTML: { __html: html }
87
+ }
88
+ );
89
+ };
90
+ export {
91
+ FileIcon,
92
+ o as LANG_TO_ICON,
93
+ L as LanguageIcon,
94
+ getMaterialIconSvg,
95
+ h as hasLanguageIcon
96
+ };
package/dist/index.mjs CHANGED
@@ -2,7 +2,10 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useColorScheme } from "@haklex/rich-editor";
3
3
  import { useState, useRef, useEffect, useCallback, useMemo } from "react";
4
4
  import { Check, Copy, ChevronDown } from "lucide-react";
5
- import { normalizeLanguage, languageToIconMap, getLanguageDisplayName, languageToColorMap } from "./constants.mjs";
5
+ import { normalizeLanguage, getLanguageDisplayName, languageToColorMap } from "./constants.mjs";
6
+ import "@iconify/utils";
7
+ import "@iconify-json/material-icon-theme";
8
+ import { c as card, s as semanticClassNames, l as lang, h as hasLanguageIcon, L as LanguageIcon, a as copyButton, b as bodyBackground, e as expandWrap, d as expandButton, f as scroll, g as scrollCollapsed, i as lined, j as linedWithNumbers, k as body, m as bodyReadonly } from "./language-AfAZN4lZ.js";
6
9
  import { getHighlighterWithLang, SHIKI_THEMES } from "./shiki.mjs";
7
10
  const CopyIcon = /* @__PURE__ */ jsx(Copy, { size: 16 });
8
11
  const CheckIcon = /* @__PURE__ */ jsx(Check, { size: 16 });
@@ -39,7 +42,6 @@ function CodeBlockCard({
39
42
  }).catch(() => {
40
43
  });
41
44
  }, [code]);
42
- const languageIcon = languageToIconMap[normalizedLanguage] || "";
43
45
  const languageLabel = getLanguageDisplayName(normalizedLanguage);
44
46
  const accent = languageToColorMap[normalizedLanguage] || "#737373";
45
47
  const cardStyle = useMemo(
@@ -47,37 +49,65 @@ function CodeBlockCard({
47
49
  [accent]
48
50
  );
49
51
  const scrollClassName = [
50
- "rr-code-scroll",
51
- isCollapsed && isOverflow && "rr-code-scroll-collapsed"
52
+ scroll,
53
+ semanticClassNames.scroll,
54
+ isCollapsed && isOverflow && scrollCollapsed,
55
+ isCollapsed && isOverflow && semanticClassNames.scrollCollapsed
52
56
  ].filter(Boolean).join(" ");
53
- return /* @__PURE__ */ jsxs("div", { className: "rr-code-card", style: cardStyle, children: [
54
- normalizedLanguage !== "text" && /* @__PURE__ */ jsx("div", { className: "rr-code-lang", "aria-hidden": true, children: languageIcon || languageLabel }),
55
- /* @__PURE__ */ jsx(
56
- "button",
57
- {
58
- type: "button",
59
- className: "rr-code-copy",
60
- onClick: handleCopy,
61
- "aria-label": copied ? "Copied" : "Copy code",
62
- children: copied ? CheckIcon : CopyIcon
63
- }
64
- ),
65
- /* @__PURE__ */ jsxs("div", { className: "rr-code-bg", children: [
66
- /* @__PURE__ */ jsx("div", { ref: scrollRef, className: scrollClassName, children }),
67
- isOverflow && isCollapsed && /* @__PURE__ */ jsx("div", { className: "rr-code-expand-wrap", children: /* @__PURE__ */ jsxs(
68
- "button",
69
- {
70
- type: "button",
71
- className: "rr-code-expand",
72
- onClick: () => setIsCollapsed(false),
73
- children: [
74
- ExpandIcon,
75
- /* @__PURE__ */ jsx("span", { children: "展开" })
76
- ]
77
- }
78
- ) })
79
- ] })
80
- ] });
57
+ return /* @__PURE__ */ jsxs(
58
+ "div",
59
+ {
60
+ className: `${card} ${semanticClassNames.card}`,
61
+ style: cardStyle,
62
+ children: [
63
+ normalizedLanguage !== "text" && /* @__PURE__ */ jsx(
64
+ "div",
65
+ {
66
+ className: `${lang} ${semanticClassNames.lang}`,
67
+ "aria-hidden": true,
68
+ children: hasLanguageIcon(normalizedLanguage) ? /* @__PURE__ */ jsx(LanguageIcon, { language: normalizedLanguage, size: 14 }) : /* @__PURE__ */ jsx("span", { children: languageLabel })
69
+ }
70
+ ),
71
+ /* @__PURE__ */ jsx(
72
+ "button",
73
+ {
74
+ type: "button",
75
+ className: `${copyButton} ${semanticClassNames.copyButton}`,
76
+ onClick: handleCopy,
77
+ "aria-label": copied ? "Copied" : "Copy code",
78
+ children: copied ? CheckIcon : CopyIcon
79
+ }
80
+ ),
81
+ /* @__PURE__ */ jsxs(
82
+ "div",
83
+ {
84
+ className: `${bodyBackground} ${semanticClassNames.bodyBackground}`,
85
+ children: [
86
+ /* @__PURE__ */ jsx("div", { ref: scrollRef, className: scrollClassName, children }),
87
+ isOverflow && isCollapsed && /* @__PURE__ */ jsx(
88
+ "div",
89
+ {
90
+ className: `${expandWrap} ${semanticClassNames.expandWrap}`,
91
+ children: /* @__PURE__ */ jsxs(
92
+ "button",
93
+ {
94
+ type: "button",
95
+ className: `${expandButton} ${semanticClassNames.expandButton}`,
96
+ onClick: () => setIsCollapsed(false),
97
+ children: [
98
+ ExpandIcon,
99
+ /* @__PURE__ */ jsx("span", { children: "展开" })
100
+ ]
101
+ }
102
+ )
103
+ }
104
+ )
105
+ ]
106
+ }
107
+ )
108
+ ]
109
+ }
110
+ );
81
111
  }
82
112
  const CodeBlockEditRenderer = ({
83
113
  code,
@@ -121,13 +151,13 @@ const CodeBlockEditRenderer = ({
121
151
  if (disposed) return;
122
152
  const theme = SHIKI_THEMES[props.colorScheme];
123
153
  const loaded2 = highlighter.getLoadedLanguages();
124
- const lang = loaded2.includes(props.normalizedLanguage) ? props.normalizedLanguage : "text";
154
+ const lang2 = loaded2.includes(props.normalizedLanguage) ? props.normalizedLanguage : "text";
125
155
  const editor = shikiCode().withOptions({
126
156
  readOnly: !props.editable,
127
157
  lineNumbers: props.showLineNumbers ? "on" : "off"
128
158
  }).create(container, highlighter, {
129
159
  value: props.code,
130
- language: lang,
160
+ language: lang2,
131
161
  theme
132
162
  });
133
163
  if (!props.editable) {
@@ -180,10 +210,17 @@ const CodeBlockEditRenderer = ({
180
210
  }, [code, normalizedLanguage, colorScheme, showLineNumbers, editable]);
181
211
  const fallbackLines = useMemo(() => code.split("\n"), [code]);
182
212
  const fallbackClassName = [
183
- "rr-code-lined",
184
- showLineNumbers && "rr-code-lined-ln"
213
+ lined,
214
+ semanticClassNames.lined,
215
+ showLineNumbers && linedWithNumbers,
216
+ showLineNumbers && semanticClassNames.linedWithNumbers
217
+ ].filter(Boolean).join(" ");
218
+ const bodyClassName = [
219
+ body,
220
+ semanticClassNames.body,
221
+ !editable && bodyReadonly,
222
+ !editable && semanticClassNames.bodyReadonly
185
223
  ].filter(Boolean).join(" ");
186
- const bodyClassName = ["rr-code-body", !editable && "rr-code-readonly"].filter(Boolean).join(" ");
187
224
  return /* @__PURE__ */ jsxs(CodeBlockCard, { code, language, children: [
188
225
  !loaded && /* @__PURE__ */ jsx("pre", { className: fallbackClassName, children: /* @__PURE__ */ jsx("code", { children: fallbackLines.map((line, i) => /* @__PURE__ */ jsx("span", { className: "line", children: line }, i)) }) }),
189
226
  /* @__PURE__ */ jsx(
@@ -210,9 +247,9 @@ const CodeBlockRenderer = ({
210
247
  const highlighter = await getHighlighterWithLang(normalizedLanguage);
211
248
  if (cancelled) return;
212
249
  const loaded = highlighter.getLoadedLanguages();
213
- const lang = loaded.includes(normalizedLanguage) ? normalizedLanguage : "text";
250
+ const lang2 = loaded.includes(normalizedLanguage) ? normalizedLanguage : "text";
214
251
  const result = highlighter.codeToHtml(code, {
215
- lang,
252
+ lang: lang2,
216
253
  theme: SHIKI_THEMES[colorScheme]
217
254
  });
218
255
  if (!cancelled) setHtml(result);
@@ -223,8 +260,10 @@ const CodeBlockRenderer = ({
223
260
  }, [code, normalizedLanguage, colorScheme]);
224
261
  const fallbackLines = useMemo(() => code.split("\n"), [code]);
225
262
  const linedClassName = [
226
- "rr-code-lined",
227
- showLineNumbers && "rr-code-lined-ln"
263
+ lined,
264
+ semanticClassNames.lined,
265
+ showLineNumbers && linedWithNumbers,
266
+ showLineNumbers && semanticClassNames.linedWithNumbers
228
267
  ].filter(Boolean).join(" ");
229
268
  return /* @__PURE__ */ jsx(CodeBlockCard, { code, language, children: html ? /* @__PURE__ */ jsx(
230
269
  "div",
@@ -0,0 +1,131 @@
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 lang = "_1pn9r4q1";
14
+ var langIcon = "_1pn9r4q2";
15
+ var copyButton = "_1pn9r4q3";
16
+ var bodyBackground = "_1pn9r4q4";
17
+ var scroll = "_1pn9r4q5";
18
+ var scrollCollapsed = "_1pn9r4q6";
19
+ var body = "_1pn9r4q7";
20
+ var bodyReadonly = "_1pn9r4q8";
21
+ var expandWrap = "_1pn9r4q9";
22
+ var expandButton = "_1pn9r4qa";
23
+ var lined = "_1pn9r4qb";
24
+ var linedWithNumbers = "_1pn9r4qc";
25
+ const LANG_TO_ICON = {
26
+ javascript: "javascript",
27
+ js: "javascript",
28
+ typescript: "typescript",
29
+ ts: "typescript",
30
+ jsx: "react",
31
+ tsx: "react",
32
+ // TSX → React icon (same as JSX)
33
+ html: "html",
34
+ css: "css",
35
+ scss: "sass",
36
+ sass: "sass",
37
+ less: "sass",
38
+ json: "json",
39
+ jsonc: "json",
40
+ markdown: "markdown",
41
+ md: "markdown",
42
+ mdx: "markdown",
43
+ bash: "console",
44
+ sh: "console",
45
+ shell: "console",
46
+ zsh: "console",
47
+ python: "python",
48
+ py: "python",
49
+ rust: "rust",
50
+ go: "go",
51
+ java: "java",
52
+ c: "c",
53
+ cpp: "cpp",
54
+ "c++": "cpp",
55
+ swift: "swift",
56
+ kotlin: "kotlin",
57
+ kt: "kotlin",
58
+ yaml: "yaml",
59
+ yml: "yaml",
60
+ sql: "database",
61
+ xml: "xml",
62
+ vue: "vue",
63
+ svelte: "svelte",
64
+ php: "php",
65
+ rb: "ruby",
66
+ lua: "lua",
67
+ zig: "zig",
68
+ toml: "toml",
69
+ graphql: "graphql",
70
+ gql: "graphql",
71
+ dockerfile: "docker"
72
+ };
73
+ function getLanguageIconSvg(lang2) {
74
+ const iconName = LANG_TO_ICON[lang2] ?? "code";
75
+ return getMaterialIconSvg(iconName);
76
+ }
77
+ function hasLanguageIcon(lang2) {
78
+ return getLanguageIconSvg(lang2) !== null;
79
+ }
80
+ const LanguageIcon = ({
81
+ language,
82
+ size = 14,
83
+ className = `${langIcon} ${semanticClassNames.langIcon}`
84
+ }) => {
85
+ const html = useMemo(() => getLanguageIconSvg(language), [language]);
86
+ if (!html) {
87
+ return /* @__PURE__ */ jsx(
88
+ "span",
89
+ {
90
+ className,
91
+ style: {
92
+ width: size,
93
+ height: size,
94
+ display: "inline-flex",
95
+ alignItems: "center",
96
+ justifyContent: "center",
97
+ opacity: 0.6,
98
+ fontSize: size * 0.6
99
+ },
100
+ children: "•"
101
+ }
102
+ );
103
+ }
104
+ return /* @__PURE__ */ jsx(
105
+ "span",
106
+ {
107
+ className,
108
+ style: { width: size, height: size },
109
+ dangerouslySetInnerHTML: { __html: html }
110
+ }
111
+ );
112
+ };
113
+ export {
114
+ LanguageIcon as L,
115
+ copyButton as a,
116
+ bodyBackground as b,
117
+ card as c,
118
+ expandButton as d,
119
+ expandWrap as e,
120
+ scroll as f,
121
+ scrollCollapsed as g,
122
+ hasLanguageIcon as h,
123
+ lined as i,
124
+ linedWithNumbers as j,
125
+ body as k,
126
+ lang as l,
127
+ bodyReadonly as m,
128
+ getMaterialIconSvg as n,
129
+ LANG_TO_ICON as o,
130
+ semanticClassNames as s
131
+ };
@@ -1,4 +1,4 @@
1
- .rr-code-card {
1
+ ._1pn9r4q0 {
2
2
  --rr-code-accent: #737373;
3
3
  position: relative;
4
4
  margin: 1.5rem 0;
@@ -6,16 +6,27 @@
6
6
  overflow: hidden;
7
7
  font-size: 14px;
8
8
  }
9
- .rr-code-lang {
9
+ ._1pn9r4q1 {
10
10
  position: absolute;
11
11
  bottom: 0.75rem;
12
12
  right: 0.75rem;
13
13
  z-index: 2;
14
+ display: flex;
15
+ align-items: center;
16
+ gap: 0.375rem;
14
17
  font-size: 0.875rem;
15
18
  opacity: 0.6;
16
19
  pointer-events: none;
17
20
  }
18
- .rr-code-copy {
21
+ ._1pn9r4q2 {
22
+ display: inline-flex;
23
+ flex-shrink: 0;
24
+ }
25
+ ._1pn9r4q2 svg {
26
+ width: 100%;
27
+ height: 100%;
28
+ }
29
+ ._1pn9r4q3 {
19
30
  appearance: none;
20
31
  position: absolute;
21
32
  right: 0.5rem;
@@ -34,36 +45,36 @@
34
45
  transition: opacity 0.2s ease;
35
46
  backdrop-filter: blur(8px);
36
47
  }
37
- .rr-code-card:hover .rr-code-copy {
48
+ ._1pn9r4q0:hover ._1pn9r4q3 {
38
49
  opacity: 1;
39
50
  }
40
- .rr-code-bg {
51
+ ._1pn9r4q4 {
41
52
  position: relative;
42
53
  background: color-mix(in srgb, var(--rr-code-accent) 5%, transparent);
43
54
  padding: 1rem 0;
44
55
  }
45
- .rr-code-scroll {
56
+ ._1pn9r4q5 {
46
57
  position: relative;
47
58
  width: 100%;
48
59
  overflow: auto;
49
60
  }
50
- .rr-code-scroll-collapsed {
61
+ ._1pn9r4q6 {
51
62
  max-height: 50vh;
52
63
  overflow: hidden;
53
64
  }
54
- .rr-code-body {
65
+ ._1pn9r4q7 {
55
66
  position: relative;
56
67
  overflow: auto;
57
68
  background-color: transparent !important;
58
69
  }
59
- .rr-code-body > .shikicode.output {
70
+ ._1pn9r4q7 > .shikicode.output {
60
71
  position: static !important;
61
72
  inset: auto !important;
62
73
  }
63
- .rr-code-readonly > textarea.shikicode {
74
+ ._1pn9r4q8 > textarea.shikicode {
64
75
  display: none;
65
76
  }
66
- .rr-code-expand-wrap {
77
+ ._1pn9r4q9 {
67
78
  position: absolute;
68
79
  bottom: 0;
69
80
  left: 0;
@@ -74,7 +85,7 @@
74
85
  background: linear-gradient(to bottom, transparent 0%, var(--bg, var(--rc-bg-secondary)) 80%);
75
86
  pointer-events: none;
76
87
  }
77
- .rr-code-expand {
88
+ ._1pn9r4qa {
78
89
  appearance: none;
79
90
  border: none;
80
91
  background: none;
@@ -87,46 +98,47 @@
87
98
  opacity: 0.7;
88
99
  pointer-events: auto;
89
100
  }
90
- .rr-code-expand:hover {
101
+ ._1pn9r4qa:hover {
91
102
  opacity: 1;
92
103
  }
93
- .rr-code-card pre {
104
+ ._1pn9r4q0 pre {
94
105
  margin: 0 !important;
95
106
  padding: 0 !important;
96
107
  border-radius: 0;
97
108
  font-size: min(1em, 16px);
98
109
  }
99
- .rr-code-card pre code {
110
+ ._1pn9r4q0 pre code {
100
111
  display: flex;
101
112
  flex-direction: column;
102
113
  }
103
- .rr-code-card .shiki, .rr-code-card code, .rr-code-card pre {
114
+ ._1pn9r4q0 .shiki, ._1pn9r4q0 code, ._1pn9r4q0 pre {
104
115
  background: transparent !important;
105
116
  }
106
- .rr-code-card .shikicode.output .line::before {
117
+ ._1pn9r4q0 .shikicode.output .line::before {
107
118
  background-color: transparent !important;
119
+ color: color-mix(in srgb, var(--rc-text-secondary) 40%, transparent) !important;
108
120
  }
109
- .rr-code-card .line {
121
+ ._1pn9r4q0 .line {
110
122
  display: block;
111
123
  padding: 0 1.25rem;
112
124
  }
113
- .rr-code-card .shikicode.input.line-numbers {
125
+ ._1pn9r4q0 .shikicode.input.line-numbers {
114
126
  padding-left: calc(5em + 1.25rem);
115
127
  }
116
- .rr-code-card .shikicode.input:not(.line-numbers) {
128
+ ._1pn9r4q0 .shikicode.input:not(.line-numbers) {
117
129
  padding-left: 1.25rem;
118
130
  }
119
- .rr-code-card .line > span:last-child {
131
+ ._1pn9r4q0 .line > span:last-child {
120
132
  margin-right: 1.25rem;
121
133
  }
122
- .rr-code-card .line::after {
134
+ ._1pn9r4q0 .line::after {
123
135
  content: ' ';
124
136
  }
125
- .rr-code-card .highlighted, .rr-code-card .diff {
137
+ ._1pn9r4q0 .highlighted, ._1pn9r4q0 .diff {
126
138
  position: relative;
127
139
  overflow-wrap: break-word;
128
140
  }
129
- .rr-code-card .highlighted::before, .rr-code-card .diff::before {
141
+ ._1pn9r4q0 .highlighted::before, ._1pn9r4q0 .diff::before {
130
142
  content: '';
131
143
  position: absolute;
132
144
  left: 0;
@@ -134,43 +146,43 @@
134
146
  height: 100%;
135
147
  width: 2px;
136
148
  }
137
- .rr-code-card .highlighted {
149
+ ._1pn9r4q0 .highlighted {
138
150
  background: color-mix(in srgb, var(--rr-code-accent) 20%, transparent);
139
151
  }
140
- .rr-code-card .highlighted::before {
152
+ ._1pn9r4q0 .highlighted::before {
141
153
  background: var(--rr-code-accent);
142
154
  }
143
- .rr-code-card .diff.add {
155
+ ._1pn9r4q0 .diff.add {
144
156
  background: rgba(34, 197, 94, 0.15);
145
157
  }
146
- .rr-code-card .diff.add::before {
158
+ ._1pn9r4q0 .diff.add::before {
147
159
  background: #22c55e;
148
160
  }
149
- .rr-code-card .diff.add::after {
161
+ ._1pn9r4q0 .diff.add::after {
150
162
  content: ' +';
151
163
  position: absolute;
152
164
  left: 0;
153
165
  color: #22c55e;
154
166
  }
155
- .rr-code-card .diff.remove {
167
+ ._1pn9r4q0 .diff.remove {
156
168
  background: rgba(239, 68, 68, 0.15);
157
169
  }
158
- .rr-code-card .diff.remove::before {
170
+ ._1pn9r4q0 .diff.remove::before {
159
171
  background: #ef4444;
160
172
  }
161
- .rr-code-card .diff.remove::after {
173
+ ._1pn9r4q0 .diff.remove::after {
162
174
  content: ' -';
163
175
  position: absolute;
164
176
  left: 0;
165
177
  color: #ef4444;
166
178
  }
167
- .rr-code-lined {
179
+ ._1pn9r4qb {
168
180
  counter-reset: shiki-line 0;
169
181
  }
170
- .rr-code-lined .line {
182
+ ._1pn9r4qb .line {
171
183
  counter-increment: shiki-line 1;
172
184
  }
173
- .rr-code-lined .line::before {
185
+ ._1pn9r4qb .line::before {
174
186
  content: counter(shiki-line);
175
187
  color: transparent;
176
188
  text-align: right;
@@ -180,19 +192,57 @@
180
192
  position: sticky;
181
193
  left: 0;
182
194
  }
183
- .rr-code-lined-ln .line::before {
195
+ ._1pn9r4qc .line::before {
184
196
  color: inherit;
185
197
  opacity: 0.4;
186
198
  width: 5em;
187
199
  padding-right: 2em;
188
200
  }
189
- .rr-code-scroll pre::-webkit-scrollbar-track {
201
+ ._1pn9r4q5 pre::-webkit-scrollbar-track {
190
202
  margin-left: 1rem;
191
203
  margin-right: var(--sr-margin, 0);
192
204
  }
193
- .rr-code-scroll pre::-webkit-scrollbar {
205
+ ._1pn9r4q5 pre::-webkit-scrollbar {
194
206
  background-color: transparent !important;
195
207
  }
208
+ ._1pn9r4qd {
209
+ font-family: var(--rc-font-mono);
210
+ font-size: var(--rc-font-size-small);
211
+ background-color: var(--rc-code-bg);
212
+ border-radius: var(--rc-radius-md);
213
+ overflow: hidden;
214
+ margin: var(--rc-space-md) 0;
215
+ border: 1px solid var(--rc-border);
216
+ }
217
+ ._1pn9r4qe {
218
+ display: flex;
219
+ align-items: center;
220
+ justify-content: space-between;
221
+ padding: var(--rc-space-sm) var(--rc-space-md);
222
+ border-bottom: 1px solid var(--rc-border);
223
+ font-size: var(--rc-font-size-small);
224
+ color: var(--rc-text-secondary);
225
+ user-select: none;
226
+ }
227
+ ._1pn9r4qf {
228
+ font-family: var(--rc-font-mono);
229
+ font-size: 0.85em;
230
+ text-transform: uppercase;
231
+ letter-spacing: 0.05em;
232
+ }
233
+ ._1pn9r4qg {
234
+ appearance: none;
235
+ border: none;
236
+ background: none;
237
+ color: var(--rc-text-secondary);
238
+ cursor: pointer;
239
+ padding: var(--rc-space-xs) var(--rc-space-sm);
240
+ border-radius: var(--rc-radius-sm);
241
+ font-family: var(--rc-font-family);
242
+ font-size: var(--rc-font-size-small);
243
+ line-height: 1;
244
+ transition: color 0.15s ease, background-color 0.15s ease;
245
+ }
196
246
  .rich-code-block {
197
247
  font-family: var(--rc-font-mono);
198
248
  font-size: var(--rc-font-size-small);
@@ -260,7 +310,7 @@
260
310
  width: 2.5em;
261
311
  margin-right: var(--rc-space-md);
262
312
  text-align: right;
263
- color: color-mix(in srgb, var(--rc-text-secondary) 40%, transparent);
313
+ color: color-mix(in srgb, var(--rc-text-secondary) 40%, transparent) !important;
264
314
  opacity: 0.4;
265
315
  user-select: none;
266
316
  font-size: var(--rc-font-size-small);
@@ -1,2 +1,40 @@
1
- export {};
1
+ export declare const semanticClassNames: {
2
+ readonly card: "rr-code-card";
3
+ readonly lang: "rr-code-lang";
4
+ readonly langIcon: "rr-code-lang-icon";
5
+ readonly copyButton: "rr-code-copy";
6
+ readonly bodyBackground: "rr-code-bg";
7
+ readonly scroll: "rr-code-scroll";
8
+ readonly scrollCollapsed: "rr-code-scroll-collapsed";
9
+ readonly body: "rr-code-body";
10
+ readonly bodyReadonly: "rr-code-readonly";
11
+ readonly expandWrap: "rr-code-expand-wrap";
12
+ readonly expandButton: "rr-code-expand";
13
+ readonly lined: "rr-code-lined";
14
+ readonly linedWithNumbers: "rr-code-lined-ln";
15
+ };
16
+ export declare const card: string;
17
+ export declare const lang: string;
18
+ export declare const langIcon: string;
19
+ export declare const copyButton: string;
20
+ export declare const bodyBackground: string;
21
+ export declare const scroll: string;
22
+ export declare const scrollCollapsed: string;
23
+ export declare const body: string;
24
+ export declare const bodyReadonly: string;
25
+ export declare const expandWrap: string;
26
+ export declare const expandButton: string;
27
+ export declare const lined: string;
28
+ export declare const linedWithNumbers: string;
29
+ export declare const contentSemanticClassNames: {
30
+ readonly root: "rich-code-block";
31
+ readonly header: "rich-code-block-header";
32
+ readonly lang: "rich-code-block-lang";
33
+ readonly copyButton: "rich-code-block-copy";
34
+ readonly numbered: "rich-code-block-numbered";
35
+ };
36
+ export declare const contentRoot: string;
37
+ export declare const contentHeader: string;
38
+ export declare const contentLang: string;
39
+ export declare const contentCopyButton: string;
2
40
  //# sourceMappingURL=styles.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.css.d.ts","sourceRoot":"","sources":["../src/styles.css.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"styles.css.d.ts","sourceRoot":"","sources":["../src/styles.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;CAcrB,CAAA;AAGV,eAAO,MAAM,IAAI,QAOf,CAAA;AAGF,eAAO,MAAM,IAAI,QAWf,CAAA;AAEF,eAAO,MAAM,QAAQ,QAGnB,CAAA;AAQF,eAAO,MAAM,UAAU,QAuBrB,CAAA;AAGF,eAAO,MAAM,cAAc,QAIzB,CAAA;AAGF,eAAO,MAAM,MAAM,QAIjB,CAAA;AAEF,eAAO,MAAM,eAAe,QAG1B,CAAA;AAGF,eAAO,MAAM,IAAI,QAIf,CAAA;AAEF,eAAO,MAAM,YAAY,QAAY,CAAA;AAYrC,eAAO,MAAM,UAAU,QAUrB,CAAA;AAEF,eAAO,MAAM,YAAY,QAiBvB,CAAA;AA8FF,eAAO,MAAM,KAAK,QAEhB,CAAA;AAiBF,eAAO,MAAM,gBAAgB,QAAY,CAAA;AAmBzC,eAAO,MAAM,yBAAyB;;;;;;CAM5B,CAAA;AAiFV,eAAO,MAAM,WAAW,QAA2B,CAAA;AACnD,eAAO,MAAM,aAAa,QAA6B,CAAA;AACvD,eAAO,MAAM,WAAW,QAA2B,CAAA;AACnD,eAAO,MAAM,iBAAiB,QAAiC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haklex/rich-renderer-codeblock",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Code block renderer with Shiki syntax highlighting",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,18 +17,24 @@
17
17
  "import": "./dist/constants.mjs",
18
18
  "types": "./dist/constants.d.ts"
19
19
  },
20
- "./style.css": "./dist/rich-renderer-codeblock.css"
20
+ "./style.css": "./dist/rich-renderer-codeblock.css",
21
+ "./icons": {
22
+ "import": "./dist/icons.mjs",
23
+ "types": "./dist/icons.d.ts"
24
+ }
21
25
  },
22
26
  "main": "./dist/index.mjs",
23
27
  "files": [
24
28
  "dist"
25
29
  ],
26
30
  "dependencies": {
31
+ "@iconify-json/material-icon-theme": "^1.2.22",
32
+ "@iconify/utils": "^2.3.0",
27
33
  "lucide-react": "^0.574.0",
28
34
  "shiki": "^3.21.0",
29
35
  "shikicode": "*",
30
- "@haklex/rich-editor": "0.0.4",
31
- "@haklex/rich-style-token": "0.0.4"
36
+ "@haklex/rich-editor": "0.0.5",
37
+ "@haklex/rich-style-token": "0.0.5"
32
38
  },
33
39
  "devDependencies": {
34
40
  "@types/react": "^19.0.0",