react-shiki 0.11.0 → 0.11.1
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/README.md +228 -111
- package/dist/{component-DdW14SOw.mjs → component-Cf8Topxy.mjs} +118 -78
- package/dist/component-Cf8Topxy.mjs.map +1 -0
- package/dist/{component-B-gutZRK.d.mts → component-DlK6KonE.d.mts} +36 -24
- package/dist/core.d.mts +2 -3
- package/dist/core.mjs +2 -2
- package/dist/core.mjs.map +1 -1
- package/dist/factory-DySLHBEo.mjs +17 -0
- package/dist/factory-DySLHBEo.mjs.map +1 -0
- package/dist/index.d.mts +2 -3
- package/dist/index.mjs +6 -12
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +1 -68
- package/dist/web.d.mts +2 -3
- package/dist/web.mjs +7 -13
- package/dist/web.mjs.map +1 -1
- package/package.json +7 -7
- package/dist/component-DdW14SOw.mjs.map +0 -1
- package/src/styles/features.css +0 -54
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
|
|
@@ -36,36 +36,103 @@ const throttleHighlighting = (performHighlight, timeoutControl, throttleMs) => {
|
|
|
36
36
|
}, delay);
|
|
37
37
|
};
|
|
38
38
|
//#endregion
|
|
39
|
+
//#region src/styles/component.css?inline
|
|
40
|
+
var component_default = ":where(.rs-root){position:relative}:where(.rs-root.rs-default-styles pre){border-radius:.5rem;padding-block:1.25rem;padding-inline:1.5rem;overflow:auto}:where(.rs-root .rs-language-label){z-index:1;letter-spacing:-.05em;color:#6b7280d9;font-family:monospace;font-size:.75rem;position:absolute;top:.5rem;right:.75rem}\n";
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/styles/features.css?inline
|
|
43
|
+
var features_default = ":where(.rs-has-line-numbers){counter-reset:line-number calc(var(--line-start,1) - 1)}:where(.rs-has-line-numbers .rs-line-number):before{counter-increment:line-number;content:counter(line-number);box-sizing:content-box;min-width:var(--rs-line-numbers-width,2ch);padding-left:var(--rs-line-numbers-padding-left,0ch);padding-right:var(--rs-line-numbers-padding-right,2ch);color:var(--rs-line-numbers-foreground,#6b728080);font-size:var(--rs-line-numbers-font-size,inherit);font-weight:var(--rs-line-numbers-font-weight,inherit);line-height:var(--rs-line-numbers-line-height,inherit);font-family:var(--rs-line-numbers-font-family,inherit);opacity:var(--rs-line-numbers-opacity,1);user-select:none;pointer-events:none;justify-content:flex-end;align-items:flex-start;display:inline-flex}:where(.rs-has-highlighted-lines){width:fit-content;min-width:100%;display:block}:where(.rs-highlighted-line){--_rs-hl-background:var(--rs-highlighted-line-background,color-mix(in srgb, currentColor 10%, transparent));background-color:var(--_rs-hl-background);width:100%;min-height:1lh;display:inline-block}:where(.rs-default-styles .rs-highlighted-line){border-image:linear-gradient(var(--_rs-hl-background) 0 0) fill 0 / 0 / 0 100vw;background-color:#0000}:where(.rs-has-line-numbers .rs-highlighted-line):before{color:var(--rs-highlighted-line-number-foreground,color-mix(in srgb, currentColor 65%, transparent))}\n";
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/lib/styles.ts
|
|
46
|
+
const injected = /* @__PURE__ */ new Set();
|
|
47
|
+
const useStyleInsertionEffect = React.useInsertionEffect ?? React.useLayoutEffect;
|
|
48
|
+
const inject = (css, key) => {
|
|
49
|
+
if (injected.has(key) || typeof document === "undefined") return;
|
|
50
|
+
injected.add(key);
|
|
51
|
+
try {
|
|
52
|
+
const sheet = new CSSStyleSheet();
|
|
53
|
+
sheet.replaceSync(css);
|
|
54
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
55
|
+
} catch {
|
|
56
|
+
const style = document.createElement("style");
|
|
57
|
+
style.dataset.reactShiki = key;
|
|
58
|
+
style.textContent = css;
|
|
59
|
+
document.head.append(style);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
/** Installs component styles before layout without triggering a render. */
|
|
63
|
+
const useComponentStyles = () => {
|
|
64
|
+
useStyleInsertionEffect(() => {
|
|
65
|
+
inject(component_default, "component");
|
|
66
|
+
}, []);
|
|
67
|
+
};
|
|
68
|
+
/** Installs line-number/highlight styles only when those options are used. */
|
|
69
|
+
const useFeatureStyles = (enabled) => {
|
|
70
|
+
useStyleInsertionEffect(() => {
|
|
71
|
+
if (enabled) inject(features_default, "features");
|
|
72
|
+
}, [enabled]);
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
39
75
|
//#region src/lib/language.ts
|
|
40
76
|
const FALLBACK_LANGUAGE = "plaintext";
|
|
41
|
-
const getEmbeddedLanguages = (code, languageId, highlighter) => {
|
|
42
|
-
const bundled = highlighter.getBundledLanguages();
|
|
43
|
-
return guessEmbeddedLanguages(code, languageId).flatMap((language) => bundled[language] ?? []);
|
|
44
|
-
};
|
|
45
77
|
const toArray = (value) => value == null ? [] : Array.isArray(value) ? value : [value];
|
|
78
|
+
const isDynamicLanguage = (lang) => typeof lang === "function" || lang instanceof Promise || Array.isArray(lang) || typeof lang === "object" && lang != null && "default" in lang;
|
|
79
|
+
const isRegistration = (lang) => typeof lang === "object" && lang != null && !isDynamicLanguage(lang);
|
|
80
|
+
/** Dedupe identity: strings and registrations by value, dynamic inputs by reference */
|
|
46
81
|
const languageKey = (lang) => {
|
|
47
82
|
if (lang == null) return null;
|
|
48
83
|
if (typeof lang === "string") return `s:${lang}`;
|
|
84
|
+
if (isDynamicLanguage(lang)) return lang;
|
|
49
85
|
return `o:${lang.name}::${lang.scopeName}`;
|
|
50
86
|
};
|
|
51
87
|
const dedupeLanguages = (langs) => {
|
|
52
88
|
const seen = /* @__PURE__ */ new Set();
|
|
53
|
-
|
|
54
|
-
for (const lang of langs) {
|
|
89
|
+
return langs.filter((lang) => {
|
|
55
90
|
const key = languageKey(lang);
|
|
56
|
-
if (key == null || seen.has(key))
|
|
91
|
+
if (key == null || seen.has(key)) return false;
|
|
57
92
|
seen.add(key);
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
93
|
+
return true;
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* A registration matches a query by name, scopeName (full or its last
|
|
98
|
+
* segment, e.g. "source.tsx" -> "tsx"), aliases, or fileTypes.
|
|
99
|
+
*/
|
|
100
|
+
const registrationMatches = (candidate, matches) => matches(candidate.name) || matches(candidate.scopeName) || matches(candidate.scopeName?.split(".").pop()) || !!candidate.aliases?.some(matches) || !!candidate.fileTypes?.some(matches);
|
|
101
|
+
/**
|
|
102
|
+
* Resolves the language prop to a shiki language id plus everything the
|
|
103
|
+
* factory should load (primary, preloaded, and custom grammars, deduped).
|
|
104
|
+
*/
|
|
105
|
+
const resolveLanguage = (lang, customLanguages, langAliases, preloadLanguages) => {
|
|
106
|
+
const customLangs = toArray(customLanguages);
|
|
107
|
+
const preloadLangs = toArray(preloadLanguages);
|
|
108
|
+
const result = (languageId, primary) => ({
|
|
109
|
+
languageId,
|
|
110
|
+
langsToLoad: dedupeLanguages([
|
|
111
|
+
primary,
|
|
112
|
+
...preloadLangs,
|
|
113
|
+
...customLangs
|
|
114
|
+
])
|
|
115
|
+
});
|
|
116
|
+
if (lang == null || typeof lang === "string" && !lang.trim()) return result(FALLBACK_LANGUAGE);
|
|
117
|
+
if (typeof lang === "object") return result(lang.name, lang);
|
|
118
|
+
const normalized = lang.trim();
|
|
119
|
+
const query = normalized.toLowerCase();
|
|
120
|
+
const matches = (str) => str?.toLowerCase() === query;
|
|
121
|
+
const customMatch = [...customLangs, ...preloadLangs].filter(isRegistration).find((candidate) => registrationMatches(candidate, matches));
|
|
122
|
+
if (customMatch) return result(customMatch.name || normalized, customMatch);
|
|
123
|
+
const alias = Object.entries(langAliases ?? {}).find(([name]) => matches(name))?.[1];
|
|
124
|
+
if (alias) return result(alias, alias);
|
|
125
|
+
return result(normalized, normalized);
|
|
61
126
|
};
|
|
62
127
|
/**
|
|
63
128
|
* Used in factories to check if language is supported.
|
|
64
|
-
* Objects are validated as grammar registrations (name + scopeName)
|
|
129
|
+
* Objects are validated as grammar registrations (name + scopeName);
|
|
130
|
+
* dynamic imports pass through for shiki to resolve.
|
|
65
131
|
*/
|
|
66
132
|
const isLoadableLanguage = (lang, bundledLanguages) => {
|
|
67
133
|
if (lang == null) return false;
|
|
68
134
|
if (typeof lang === "string") return lang in bundledLanguages;
|
|
135
|
+
if (isDynamicLanguage(lang)) return true;
|
|
69
136
|
return typeof lang.name === "string" && typeof lang.scopeName === "string";
|
|
70
137
|
};
|
|
71
138
|
/**
|
|
@@ -73,51 +140,9 @@ const isLoadableLanguage = (lang, bundledLanguages) => {
|
|
|
73
140
|
* Falls back to "plaintext" if not supported.
|
|
74
141
|
*/
|
|
75
142
|
const resolveLoadedLanguage = (languageId, loadedLanguages) => isSpecialLang(languageId) || loadedLanguages.includes(languageId) ? languageId : FALLBACK_LANGUAGE;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
* @param customLanguages An array of custom textmate grammar objects or a single grammar object
|
|
80
|
-
* @returns A LanguageResult object containing:
|
|
81
|
-
* - languageId: The resolved language ID
|
|
82
|
-
* - langsToLoad: The language objects/string ids to load
|
|
83
|
-
*/
|
|
84
|
-
const resolveLanguage = (lang, customLanguages, langAliases, preloadLanguages) => {
|
|
85
|
-
const customLangs = toArray(customLanguages);
|
|
86
|
-
const preloadLangs = toArray(preloadLanguages);
|
|
87
|
-
const customMatchPool = [...customLangs, ...preloadLangs];
|
|
88
|
-
let languageId = FALLBACK_LANGUAGE;
|
|
89
|
-
let primaryLang;
|
|
90
|
-
if (lang == null || typeof lang === "string" && !lang.trim()) return {
|
|
91
|
-
languageId,
|
|
92
|
-
langsToLoad: dedupeLanguages([...preloadLangs, ...customLangs])
|
|
93
|
-
};
|
|
94
|
-
if (typeof lang === "object") {
|
|
95
|
-
languageId = lang.name;
|
|
96
|
-
primaryLang = lang;
|
|
97
|
-
} else {
|
|
98
|
-
const normalizedLang = lang.trim();
|
|
99
|
-
const lowerLang = normalizedLang.toLowerCase();
|
|
100
|
-
const matches = (str) => str?.toLowerCase() === lowerLang;
|
|
101
|
-
const customMatch = customMatchPool.find((candidate) => typeof candidate === "object" && candidate != null && !!(matches(candidate.name) || matches(candidate.scopeName) || matches(candidate.scopeName?.split(".").pop()) || candidate.aliases?.some(matches) || candidate.fileTypes?.some(matches)));
|
|
102
|
-
if (customMatch) {
|
|
103
|
-
languageId = customMatch.name || normalizedLang;
|
|
104
|
-
primaryLang = customMatch;
|
|
105
|
-
} else if (langAliases?.[normalizedLang]) {
|
|
106
|
-
languageId = langAliases[normalizedLang];
|
|
107
|
-
primaryLang = langAliases[normalizedLang];
|
|
108
|
-
} else {
|
|
109
|
-
languageId = normalizedLang;
|
|
110
|
-
primaryLang = normalizedLang;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
languageId,
|
|
115
|
-
langsToLoad: dedupeLanguages([
|
|
116
|
-
primaryLang,
|
|
117
|
-
...preloadLangs,
|
|
118
|
-
...customLangs
|
|
119
|
-
])
|
|
120
|
-
};
|
|
143
|
+
const getEmbeddedLanguages = (code, languageId, highlighter) => {
|
|
144
|
+
const bundled = highlighter.getBundledLanguages();
|
|
145
|
+
return guessEmbeddedLanguages(code, languageId).flatMap((language) => bundled[language] ?? []);
|
|
121
146
|
};
|
|
122
147
|
//#endregion
|
|
123
148
|
//#region src/lib/theme.ts
|
|
@@ -155,6 +180,31 @@ function resolveTheme(themeInput) {
|
|
|
155
180
|
};
|
|
156
181
|
}
|
|
157
182
|
//#endregion
|
|
183
|
+
//#region src/lib/engine.ts
|
|
184
|
+
const engines = /* @__PURE__ */ new Map();
|
|
185
|
+
const loaders = {
|
|
186
|
+
javascript: () => import("shiki/engine/javascript").then((m) => m.createJavaScriptRegexEngine()),
|
|
187
|
+
oniguruma: () => import("shiki/engine/oniguruma").then((m) => m.createOnigurumaEngine(import("shiki/wasm")))
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Resolves a named engine to a lazily created, cached instance.
|
|
191
|
+
* Engine instances and undefined pass through untouched.
|
|
192
|
+
*
|
|
193
|
+
* The cache makes named engines referentially stable across renders and
|
|
194
|
+
* call sites, unlike inline `createJavaScriptRegexEngine()` calls.
|
|
195
|
+
*/
|
|
196
|
+
const resolveEngine = (engine) => {
|
|
197
|
+
if (typeof engine !== "string") return engine;
|
|
198
|
+
const load = loaders[engine];
|
|
199
|
+
if (!load) throw new Error(`[react-shiki] unknown engine '${engine}', expected 'javascript' or 'oniguruma'`);
|
|
200
|
+
const cached = engines.get(engine);
|
|
201
|
+
if (cached) return cached;
|
|
202
|
+
const instance = load();
|
|
203
|
+
instance.catch(() => engines.delete(engine));
|
|
204
|
+
engines.set(engine, instance);
|
|
205
|
+
return instance;
|
|
206
|
+
};
|
|
207
|
+
//#endregion
|
|
158
208
|
//#region src/lib/transformers.ts
|
|
159
209
|
const toLineNumberSet = (lineNumbers) => new Set(lineNumbers.filter(Number.isInteger));
|
|
160
210
|
/**
|
|
@@ -167,11 +217,10 @@ function lineNumbersTransformer(startLine = 1) {
|
|
|
167
217
|
code(node) {
|
|
168
218
|
this.addClassToHast(node, "rs-has-line-numbers");
|
|
169
219
|
if (startLine !== 1) {
|
|
170
|
-
const
|
|
171
|
-
const newStyle = existingStyle ? `${existingStyle}; --line-start: ${startLine}` : `--line-start: ${startLine}`;
|
|
220
|
+
const existing = node.properties?.style;
|
|
172
221
|
node.properties = {
|
|
173
222
|
...node.properties,
|
|
174
|
-
style:
|
|
223
|
+
style: [existing, `--line-start: ${startLine}`].filter(Boolean).join("; ")
|
|
175
224
|
};
|
|
176
225
|
}
|
|
177
226
|
},
|
|
@@ -228,7 +277,7 @@ async function highlight(code, resolved, opts, factory) {
|
|
|
228
277
|
const { languageId, langsToLoad, themesToLoad, shikiOptions } = resolved;
|
|
229
278
|
const format = opts.outputFormat ?? "react";
|
|
230
279
|
const highlighter = opts.highlighter ?? await (async () => {
|
|
231
|
-
const hl = await factory(langsToLoad, themesToLoad, opts.engine);
|
|
280
|
+
const hl = await factory(langsToLoad, themesToLoad, resolveEngine(opts.engine));
|
|
232
281
|
await hl.loadLanguage(...getEmbeddedLanguages(code, languageId, hl));
|
|
233
282
|
return hl;
|
|
234
283
|
})();
|
|
@@ -250,6 +299,7 @@ async function highlight(code, resolved, opts, factory) {
|
|
|
250
299
|
}
|
|
251
300
|
const useHighlight = (code, lang, themeInput, options = {}, highlighterFactory) => {
|
|
252
301
|
const [highlightedCode, setHighlightedCode] = useState(null);
|
|
302
|
+
useFeatureStyles(Boolean(options.showLineNumbers || options.highlightLineNumbers?.length));
|
|
253
303
|
const stableLang = useStableValue(lang);
|
|
254
304
|
const stableTheme = useStableValue(themeInput);
|
|
255
305
|
const stableOpts = useStableValue(options);
|
|
@@ -347,22 +397,13 @@ const resolveOutputFormat = (outputFormat) => {
|
|
|
347
397
|
* This creates a component that uses the provided hook implementation.
|
|
348
398
|
*/
|
|
349
399
|
const createShikiHighlighterComponent = (useShikiHighlighterImpl) => {
|
|
350
|
-
return forwardRef(({ language, theme,
|
|
351
|
-
|
|
352
|
-
delay,
|
|
353
|
-
transformers,
|
|
354
|
-
customLanguages,
|
|
355
|
-
preloadLanguages,
|
|
356
|
-
showLineNumbers,
|
|
357
|
-
defaultColor,
|
|
358
|
-
cssVariablePrefix,
|
|
359
|
-
startingLineNumber,
|
|
360
|
-
highlightLineNumbers,
|
|
361
|
-
outputFormat: resolveOutputFormat(outputFormat),
|
|
362
|
-
...shikiOptions
|
|
363
|
-
};
|
|
400
|
+
return forwardRef(({ language, theme, addDefaultStyles = true, style, langStyle, className, langClassName, showLanguage = true, children: code, as: Element = "div", outputFormat, ...options }, ref) => {
|
|
401
|
+
useComponentStyles();
|
|
364
402
|
const displayLanguageId = typeof language === "object" ? language.name || null : language?.trim() || null;
|
|
365
|
-
const highlightedCode = useShikiHighlighterImpl(code, language, theme,
|
|
403
|
+
const highlightedCode = useShikiHighlighterImpl(code, language, theme, {
|
|
404
|
+
...options,
|
|
405
|
+
outputFormat: resolveOutputFormat(outputFormat)
|
|
406
|
+
});
|
|
366
407
|
return /* @__PURE__ */ jsxs(Element, {
|
|
367
408
|
ref,
|
|
368
409
|
"data-testid": "shiki-container",
|
|
@@ -370,7 +411,6 @@ const createShikiHighlighterComponent = (useShikiHighlighterImpl) => {
|
|
|
370
411
|
className: clsx("rs-root", "not-prose", addDefaultStyles && "rs-default-styles", className),
|
|
371
412
|
style,
|
|
372
413
|
children: [showLanguage && displayLanguageId ? /* @__PURE__ */ jsx("span", {
|
|
373
|
-
id: "language-label",
|
|
374
414
|
"data-slot": "language-label",
|
|
375
415
|
className: clsx("rs-language-label", langClassName),
|
|
376
416
|
style: langStyle,
|
|
@@ -385,4 +425,4 @@ const createShikiHighlighterComponent = (useShikiHighlighterImpl) => {
|
|
|
385
425
|
//#endregion
|
|
386
426
|
export { isLoadableLanguage as a, useHighlight as i, isInlineCode as n, rehypeInlineCodeProperty as r, createShikiHighlighterComponent as t };
|
|
387
427
|
|
|
388
|
-
//# sourceMappingURL=component-
|
|
428
|
+
//# sourceMappingURL=component-Cf8Topxy.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-Cf8Topxy.mjs","names":["componentCss","featuresCss"],"sources":["../src/lib/utils.ts","../src/styles/component.css?inline","../src/styles/features.css?inline","../src/lib/styles.ts","../src/lib/language.ts","../src/lib/theme.ts","../src/lib/engine.ts","../src/lib/transformers.ts","../src/lib/options.ts","../src/lib/hook.ts","../src/lib/plugins.ts","../src/lib/component.tsx"],"sourcesContent":["import { useRef } from 'react';\nimport { dequal } from 'dequal';\n\nimport type { TimeoutState } from './types';\n\n/**\n * Returns a referentially stable version of `value` that only updates when content changes.\n * Uses reference equality as a fast path and deep comparison to prevent unnecessary updates.\n */\nexport const useStableValue = <T>(value: T): T => {\n const ref = useRef(value);\n\n if (value !== ref.current && !dequal(value, ref.current)) {\n ref.current = value;\n }\n\n return ref.current;\n};\n\n/**\n * Optionally throttles rapid sequential highlighting operations\n *\n * @example\n * const timeoutControl = useRef<TimeoutState>({\n * nextAllowedTime: 0,\n * timeoutId: undefined\n * });\n *\n * throttleHighlighting(highlightCode, timeoutControl, 1000);\n */\nexport const throttleHighlighting = (\n performHighlight: () => Promise<void>,\n timeoutControl: React.RefObject<TimeoutState>,\n throttleMs: number\n) => {\n clearTimeout(timeoutControl.current.timeoutId);\n\n const delay = Math.max(\n 0,\n timeoutControl.current.nextAllowedTime - Date.now()\n );\n timeoutControl.current.timeoutId = setTimeout(() => {\n performHighlight();\n timeoutControl.current.nextAllowedTime = Date.now() + throttleMs;\n }, delay);\n};\n","/* Unlayered :where() defaults: immune to layered resets, overridden by any user rule. */\n:where(.rs-root) {\n position: relative;\n}\n\n:where(.rs-root.rs-default-styles pre) {\n overflow: auto;\n border-radius: 0.5rem;\n padding-inline: 1.5rem;\n padding-block: 1.25rem;\n}\n\n:where(.rs-root .rs-language-label) {\n position: absolute;\n z-index: 1;\n right: 0.75rem;\n top: 0.5rem;\n font-family: monospace;\n font-size: 0.75rem;\n letter-spacing: -0.05em;\n color: rgba(107, 114, 128, 0.85);\n}\n",":where(.rs-has-line-numbers) {\n counter-reset: line-number calc(var(--line-start, 1) - 1);\n}\n\n:where(.rs-has-line-numbers .rs-line-number)::before {\n counter-increment: line-number;\n content: counter(line-number);\n display: inline-flex;\n justify-content: flex-end;\n align-items: flex-start;\n box-sizing: content-box;\n min-width: var(--rs-line-numbers-width, 2ch);\n padding-left: var(--rs-line-numbers-padding-left, 0ch);\n padding-right: var(--rs-line-numbers-padding-right, 2ch);\n color: var(--rs-line-numbers-foreground, rgba(107, 114, 128, 0.5));\n font-size: var(--rs-line-numbers-font-size, inherit);\n font-weight: var(--rs-line-numbers-font-weight, inherit);\n line-height: var(--rs-line-numbers-line-height, inherit);\n font-family: var(--rs-line-numbers-font-family, inherit);\n opacity: var(--rs-line-numbers-opacity, 1);\n user-select: none;\n pointer-events: none;\n}\n\n:where(.rs-has-highlighted-lines) {\n display: block;\n width: fit-content;\n min-width: 100%;\n}\n\n:where(.rs-highlighted-line) {\n --_rs-hl-background: var(\n --rs-highlighted-line-background,\n color-mix(in srgb, currentColor 10%, transparent)\n );\n display: inline-block;\n width: 100%;\n min-height: 1lh;\n background-color: var(--_rs-hl-background);\n}\n\n/* Full bleed: the 100vw outset paints into the pre's padding, clipped by its overflow. */\n:where(.rs-default-styles .rs-highlighted-line) {\n background-color: transparent;\n border-image:\n linear-gradient(var(--_rs-hl-background) 0 0) fill 0 / 0 / 0 100vw;\n}\n\n:where(.rs-has-line-numbers .rs-highlighted-line)::before {\n color: var(\n --rs-highlighted-line-number-foreground,\n color-mix(in srgb, currentColor 65%, transparent)\n );\n}\n","import componentCss from '../styles/component.css?inline';\nimport featuresCss from '../styles/features.css?inline';\nimport * as React from 'react';\n// Side-effect import so tsdown emits dist/style.css for the ./css export;\n// stripped from the built JS, guarded by check:package\nimport '../styles/index.css';\n\nconst injected = new Set<string>();\nconst useStyleInsertionEffect =\n React.useInsertionEffect ?? React.useLayoutEffect;\n\nconst inject = (css: string, key: string) => {\n if (injected.has(key) || typeof document === 'undefined') return;\n injected.add(key);\n try {\n // Not governed by CSP style-src in current browsers, unlike the <style> fallback\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(css);\n document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];\n } catch {\n const style = document.createElement('style');\n style.dataset.reactShiki = key;\n style.textContent = css;\n document.head.append(style);\n }\n};\n\n/** Installs component styles before layout without triggering a render. */\nexport const useComponentStyles = () => {\n useStyleInsertionEffect(() => {\n inject(componentCss, 'component');\n }, []);\n};\n\n/** Installs line-number/highlight styles only when those options are used. */\nexport const useFeatureStyles = (enabled: boolean) => {\n useStyleInsertionEffect(() => {\n if (enabled) inject(featuresCss, 'features');\n }, [enabled]);\n};\n","import type { Language, PreloadLanguage } from './types';\nimport { guessEmbeddedLanguages, isSpecialLang } from 'shiki/core';\nimport type {\n DynamicImportLanguageRegistration,\n Highlighter,\n HighlighterCore,\n LanguageInput,\n LanguageRegistration,\n} from 'shiki';\n\nexport const FALLBACK_LANGUAGE = 'plaintext';\n\nconst toArray = <T>(value?: T | T[]): T[] =>\n value == null ? [] : Array.isArray(value) ? value : [value];\n\n/** Deferred `LanguageInput` forms (getter, promise, module, array) that shiki resolves itself */\ntype DynamicLanguage = Exclude<LanguageInput, LanguageRegistration>;\n\nconst isDynamicLanguage = (\n lang: PreloadLanguage\n): lang is DynamicLanguage =>\n typeof lang === 'function' ||\n lang instanceof Promise ||\n Array.isArray(lang) ||\n (typeof lang === 'object' && lang != null && 'default' in lang);\n\nconst isRegistration = (\n lang: PreloadLanguage\n): lang is LanguageRegistration =>\n typeof lang === 'object' && lang != null && !isDynamicLanguage(lang);\n\n/** Dedupe identity: strings and registrations by value, dynamic inputs by reference */\nconst languageKey = (lang: PreloadLanguage): string | object | null => {\n if (lang == null) return null;\n if (typeof lang === 'string') return `s:${lang}`;\n if (isDynamicLanguage(lang)) return lang;\n return `o:${lang.name}::${lang.scopeName}`;\n};\n\nconst dedupeLanguages = (langs: PreloadLanguage[]): PreloadLanguage[] => {\n const seen = new Set<string | object>();\n return langs.filter((lang) => {\n const key = languageKey(lang);\n if (key == null || seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n};\n\n/**\n * A registration matches a query by name, scopeName (full or its last\n * segment, e.g. \"source.tsx\" -> \"tsx\"), aliases, or fileTypes.\n */\nconst registrationMatches = (\n candidate: LanguageRegistration,\n matches: (str: string | undefined) => boolean\n): boolean =>\n matches(candidate.name) ||\n matches(candidate.scopeName) ||\n matches(candidate.scopeName?.split('.').pop()) ||\n !!candidate.aliases?.some(matches) ||\n !!candidate.fileTypes?.some(matches);\n\ntype LanguageResult = {\n languageId: string;\n langsToLoad: PreloadLanguage[];\n};\n\n/**\n * Resolves the language prop to a shiki language id plus everything the\n * factory should load (primary, preloaded, and custom grammars, deduped).\n */\nexport const resolveLanguage = (\n lang: Language,\n customLanguages?: LanguageRegistration | LanguageRegistration[],\n langAliases?: Record<string, string>,\n preloadLanguages?: PreloadLanguage | PreloadLanguage[]\n): LanguageResult => {\n const customLangs = toArray(customLanguages);\n const preloadLangs = toArray(preloadLanguages);\n\n const result = (\n languageId: string,\n primary?: Language\n ): LanguageResult => ({\n languageId,\n langsToLoad: dedupeLanguages([\n primary,\n ...preloadLangs,\n ...customLangs,\n ]),\n });\n\n if (lang == null || (typeof lang === 'string' && !lang.trim())) {\n return result(FALLBACK_LANGUAGE);\n }\n\n if (typeof lang === 'object') {\n return result(lang.name, lang);\n }\n\n const normalized = lang.trim();\n const query = normalized.toLowerCase();\n const matches = (str: string | undefined): boolean =>\n str?.toLowerCase() === query;\n\n // Custom registrations (from both customLanguages and preloadLanguages)\n const customMatch = [...customLangs, ...preloadLangs]\n .filter(isRegistration)\n .find((candidate) => registrationMatches(candidate, matches));\n if (customMatch) {\n return result(customMatch.name || normalized, customMatch);\n }\n\n const alias = Object.entries(langAliases ?? {}).find(([name]) =>\n matches(name)\n )?.[1];\n if (alias) {\n return result(alias, alias);\n }\n\n // Any other string passes through to the factory\n return result(normalized, normalized);\n};\n\n/**\n * Used in factories to check if language is supported.\n * Objects are validated as grammar registrations (name + scopeName);\n * dynamic imports pass through for shiki to resolve.\n */\nexport const isLoadableLanguage = <T extends string>(\n lang: PreloadLanguage,\n bundledLanguages: Record<T, DynamicImportLanguageRegistration>\n): lang is NonNullable<PreloadLanguage> => {\n if (lang == null) return false;\n if (typeof lang === 'string') return lang in bundledLanguages;\n if (isDynamicLanguage(lang)) return true;\n return (\n typeof lang.name === 'string' && typeof lang.scopeName === 'string'\n );\n};\n\n/**\n * Used in hook to resolve loaded language for highlighting.\n * Falls back to \"plaintext\" if not supported.\n */\nexport const resolveLoadedLanguage = (\n languageId: string,\n loadedLanguages: string[]\n): string =>\n isSpecialLang(languageId) || loadedLanguages.includes(languageId)\n ? languageId\n : FALLBACK_LANGUAGE;\n\nexport const getEmbeddedLanguages = (\n code: string,\n languageId: string,\n highlighter: Highlighter | HighlighterCore\n): LanguageInput[] => {\n const bundled: Record<string, LanguageInput> =\n highlighter.getBundledLanguages();\n return guessEmbeddedLanguages(code, languageId).flatMap(\n (language) => bundled[language] ?? []\n );\n};\n","import type { Theme, Themes } from './types';\nimport type { ThemeRegistrationAny } from 'shiki/core';\n\nexport const DEFAULT_THEMES: Themes = {\n light: 'github-light',\n dark: 'github-dark',\n};\n\nexport type ResolvedTheme =\n | { isMulti: true; themes: Themes; themesToLoad: Theme[] }\n | { isMulti: false; theme: Theme; themesToLoad: Theme[] };\n\nconst isTextmateTheme = (\n value: unknown\n): value is ThemeRegistrationAny => {\n if (typeof value !== 'object' || value === null) return false;\n const v = value as Partial<ThemeRegistrationAny> & {\n settings?: unknown;\n };\n const hasTokens =\n Array.isArray(v.tokenColors) || Array.isArray(v.settings);\n const hasIdentity =\n typeof v.name === 'string' || typeof v.type === 'string';\n return hasTokens && hasIdentity;\n};\n\nexport function resolveTheme(themeInput: Theme | Themes): ResolvedTheme {\n if (\n typeof themeInput !== 'object' ||\n themeInput === null ||\n isTextmateTheme(themeInput)\n ) {\n return {\n isMulti: false,\n theme: themeInput,\n themesToLoad: [themeInput],\n };\n }\n\n const validEntries = Object.entries(themeInput).filter(\n ([key, value]) =>\n key.trim() !== '' &&\n ((typeof value === 'string' && value.trim() !== '') ||\n isTextmateTheme(value))\n );\n\n if (validEntries.length === 0) {\n console.warn(\n '[react-shiki] invalid multi-theme config, falling back to defaults'\n );\n return {\n isMulti: true,\n themes: DEFAULT_THEMES,\n themesToLoad: Object.values(DEFAULT_THEMES),\n };\n }\n\n if (validEntries.length !== Object.keys(themeInput).length) {\n console.warn(\n '[react-shiki] multi-theme config contained invalid entries; they were dropped'\n );\n }\n\n const themes = Object.fromEntries(validEntries) as Themes;\n return {\n isMulti: true,\n themes,\n themesToLoad: validEntries.map(([, value]) => value as Theme),\n };\n}\n","import type { Awaitable, RegexEngine } from 'shiki/core';\nimport type { EngineName } from './types';\n\nconst engines = new Map<EngineName, Promise<RegexEngine>>();\n\n// Dynamic imports keep unused engines out of the loaded graph: naming an\n// engine loads only that engine, and 'javascript' never fetches the wasm.\nconst loaders: Record<EngineName, () => Promise<RegexEngine>> = {\n javascript: () =>\n import('shiki/engine/javascript').then((m) =>\n m.createJavaScriptRegexEngine()\n ),\n oniguruma: () =>\n import('shiki/engine/oniguruma').then((m) =>\n m.createOnigurumaEngine(import('shiki/wasm'))\n ),\n};\n\n/**\n * Resolves a named engine to a lazily created, cached instance.\n * Engine instances and undefined pass through untouched.\n *\n * The cache makes named engines referentially stable across renders and\n * call sites, unlike inline `createJavaScriptRegexEngine()` calls.\n */\nexport const resolveEngine = (\n engine: EngineName | Awaitable<RegexEngine> | undefined\n): Awaitable<RegexEngine> | undefined => {\n if (typeof engine !== 'string') return engine;\n\n const load = loaders[engine];\n if (!load) {\n throw new Error(\n `[react-shiki] unknown engine '${engine}', expected 'javascript' or 'oniguruma'`\n );\n }\n\n const cached = engines.get(engine);\n if (cached) return cached;\n\n const instance = load();\n // Evict rejected loads (e.g. transient wasm fetch failure) so the\n // next highlight retries instead of reusing the cached rejection.\n instance.catch(() => engines.delete(engine));\n engines.set(engine, instance);\n return instance;\n};\n","import type { ShikiTransformer } from 'shiki/core';\n\nconst toLineNumberSet = (lineNumbers: readonly number[]) =>\n new Set(lineNumbers.filter(Number.isInteger));\n\n/**\n * Creates a transformer that enables line numbers display\n * @param startLine - The starting line number (defaults to 1)\n */\nexport function lineNumbersTransformer(startLine = 1): ShikiTransformer {\n return {\n name: 'react-shiki:line-numbers',\n code(node) {\n this.addClassToHast(node, 'rs-has-line-numbers');\n if (startLine !== 1) {\n const existing = node.properties?.style as string | undefined;\n node.properties = {\n ...node.properties,\n style: [existing, `--line-start: ${startLine}`]\n .filter(Boolean)\n .join('; '),\n };\n }\n },\n line(node) {\n this.addClassToHast(node, 'rs-line-number');\n return node;\n },\n };\n}\n\n/**\n * Creates a transformer that marks selected displayed line numbers.\n * @param lineNumbers - Displayed line numbers to highlight\n * @param startLine - The starting line number (defaults to 1)\n */\nexport function highlightedLinesTransformer(\n lineNumbers: readonly number[],\n startLine = 1\n): ShikiTransformer {\n const highlightedLines = toLineNumberSet(lineNumbers);\n\n return {\n name: 'react-shiki:highlight-lines',\n code(node) {\n this.addClassToHast(node, 'rs-has-highlighted-lines');\n },\n line(node, line) {\n const displayedLine = startLine + line - 1;\n\n if (highlightedLines.has(displayedLine)) {\n this.addClassToHast(node, 'rs-highlighted-line');\n }\n\n return node;\n },\n };\n}\n","import type {\n BundledTheme,\n CodeOptionsMultipleThemes,\n CodeOptionsSingleTheme,\n CodeToHastOptions,\n} from 'shiki';\n\nimport type {\n HighlighterOptions,\n HighlighterOptionsFor,\n OutputFormat,\n} from './types';\nimport type { ResolvedTheme } from './theme';\nimport {\n highlightedLinesTransformer,\n lineNumbersTransformer,\n} from './transformers';\n\nconst buildThemeOptions = (\n resolvedTheme: ResolvedTheme,\n defaultColor: HighlighterOptions['defaultColor'],\n cssVariablePrefix: HighlighterOptions['cssVariablePrefix']\n):\n | CodeOptionsMultipleThemes<BundledTheme>\n | CodeOptionsSingleTheme<BundledTheme> => {\n if (resolvedTheme.isMulti) {\n return {\n themes: resolvedTheme.themes,\n defaultColor,\n cssVariablePrefix,\n };\n }\n\n return {\n theme: resolvedTheme.theme,\n };\n};\n\nexport const buildShikiOptions = (\n languageId: string,\n resolvedTheme: ResolvedTheme,\n options: HighlighterOptionsFor<OutputFormat>\n): CodeToHastOptions => {\n const {\n delay,\n customLanguages,\n preloadLanguages,\n outputFormat,\n highlighter,\n langAlias,\n engine,\n defaultColor,\n cssVariablePrefix,\n showLineNumbers,\n startingLineNumber,\n highlightLineNumbers,\n transformers: userTransformers,\n ...shikiPassthrough\n } = options;\n\n const transformers = [...(userTransformers || [])];\n if (showLineNumbers) {\n transformers.push(lineNumbersTransformer(startingLineNumber));\n }\n if (highlightLineNumbers?.length) {\n transformers.push(\n highlightedLinesTransformer(\n highlightLineNumbers,\n startingLineNumber\n )\n );\n }\n\n return {\n lang: languageId,\n ...buildThemeOptions(resolvedTheme, defaultColor, cssVariablePrefix),\n ...shikiPassthrough,\n transformers,\n };\n};\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport { jsx, jsxs, Fragment } from 'react/jsx-runtime';\nimport { toJsxRuntime } from 'hast-util-to-jsx-runtime';\nimport type { CodeToHastOptions } from 'shiki';\n\nimport type {\n HighlighterFactory,\n HighlighterOptions,\n HighlighterOptionsFor,\n HighlightResult,\n HighlightResultMap,\n Language,\n OutputFormat,\n PreloadLanguage,\n Theme,\n Themes,\n TimeoutState,\n} from './types';\n\nimport { throttleHighlighting, useStableValue } from './utils';\nimport { useFeatureStyles } from './styles';\nimport {\n getEmbeddedLanguages,\n resolveLanguage,\n resolveLoadedLanguage,\n} from './language';\nimport { resolveTheme } from './theme';\nimport { resolveEngine } from './engine';\nimport { buildShikiOptions } from './options';\n\nexport async function highlight<F extends OutputFormat = 'react'>(\n code: string,\n resolved: {\n languageId: string;\n langsToLoad: PreloadLanguage[];\n themesToLoad: Theme[];\n shikiOptions: CodeToHastOptions;\n },\n opts: Pick<HighlighterOptions, 'highlighter' | 'engine'> & {\n outputFormat?: F;\n },\n factory: HighlighterFactory\n): Promise<HighlightResultMap[F]> {\n const { languageId, langsToLoad, themesToLoad, shikiOptions } =\n resolved;\n const format: OutputFormat = opts.outputFormat ?? 'react';\n\n const highlighter =\n opts.highlighter ??\n (await (async () => {\n const hl = await factory(\n langsToLoad,\n themesToLoad,\n resolveEngine(opts.engine)\n );\n await hl.loadLanguage(\n ...getEmbeddedLanguages(code, languageId, hl)\n );\n return hl;\n })());\n\n const language = resolveLoadedLanguage(\n languageId,\n highlighter.getLoadedLanguages()\n );\n const options = { ...shikiOptions, lang: language };\n\n const outputs: { [K in OutputFormat]: () => HighlightResultMap[K] } = {\n react: () =>\n toJsxRuntime(highlighter.codeToHast(code, options), {\n jsx,\n jsxs,\n Fragment,\n }),\n html: () => highlighter.codeToHtml(code, options),\n tokens: () => highlighter.codeToTokens(code, options),\n };\n\n // Untyped call sites can pass formats outside OutputFormat; degrade to\n // react rendering like the pre-tokens ternary did instead of throwing.\n return (outputs[format] ?? outputs.react)() as HighlightResultMap[F];\n}\n\nexport const useHighlight = <F extends OutputFormat = 'react'>(\n code: string,\n lang: Language,\n themeInput: Theme | Themes,\n options: HighlighterOptionsFor<F> = {},\n highlighterFactory: HighlighterFactory\n): HighlightResult<F> => {\n const [highlightedCode, setHighlightedCode] =\n useState<HighlightResult<F>>(null);\n\n // This hook owns the line-number/highlight output, so it also owns the\n // corresponding styles. The primitive boolean limits effect reruns.\n useFeatureStyles(\n Boolean(\n options.showLineNumbers || options.highlightLineNumbers?.length\n )\n );\n\n const stableLang = useStableValue(lang);\n const stableTheme = useStableValue(themeInput);\n const stableOpts = useStableValue(options);\n\n const resolved = useMemo(() => {\n const { languageId, langsToLoad } = resolveLanguage(\n stableLang,\n stableOpts.customLanguages,\n stableOpts.langAlias,\n stableOpts.preloadLanguages\n );\n\n const theme = resolveTheme(stableTheme);\n\n const shikiOptions = buildShikiOptions(languageId, theme, stableOpts);\n return {\n languageId,\n langsToLoad,\n themesToLoad: theme.themesToLoad,\n shikiOptions,\n };\n }, [stableLang, stableTheme, stableOpts]);\n\n const requestIdRef = useRef(0);\n\n const timeoutControl = useRef<TimeoutState>({\n nextAllowedTime: 0,\n timeoutId: undefined,\n });\n\n // Factory is invoked imperatively; its identity is not semantic, so it must\n // not invalidate the effect on every render. See issue #161.\n const highlighterFactoryRef = useRef(highlighterFactory);\n highlighterFactoryRef.current = highlighterFactory;\n\n useEffect(() => {\n const requestId = ++requestIdRef.current;\n\n if (!resolved.languageId) return;\n\n const run = async () => {\n try {\n const result = await highlight<F>(\n code,\n resolved,\n stableOpts,\n highlighterFactoryRef.current\n );\n if (requestId === requestIdRef.current) {\n setHighlightedCode(result);\n }\n } catch (error) {\n console.error('[react-shiki] highlight failed', error);\n }\n };\n\n if (stableOpts.delay) {\n throttleHighlighting(run, timeoutControl, stableOpts.delay);\n } else {\n run();\n }\n\n return () => {\n clearTimeout(timeoutControl.current.timeoutId);\n };\n }, [code, resolved, stableOpts]);\n\n return highlightedCode;\n};\n","import { visit } from 'unist-util-visit';\nimport type { Root } from 'hast';\nimport type { Element } from './types';\n\n/**\n * Rehype plugin to add an 'inline' property to <code> elements\n * Sets 'inline' property to true if the <code> is not within a <pre> tag\n *\n * Pass this plugin to the `rehypePlugins` prop of react-markdown\n * You can then access `inline` as a prop in components passed to react-markdown\n *\n * @example\n * <ReactMarkdown rehypePlugins={[rehypeInlineCodeProperty]} />\n */\nexport function rehypeInlineCodeProperty() {\n return (tree: Root): undefined => {\n visit(tree, 'element', (node: Element, _index, parent) => {\n if (\n node.tagName === 'code' &&\n parent?.type === 'element' &&\n parent.tagName !== 'pre'\n ) {\n node.properties.inline = true;\n }\n });\n };\n}\n\n/**\n * Function to determine if code is inline based on the presence of line breaks\n *\n * @example\n * const isInline = node && isInlineCode(node: Element)\n */\nexport const isInlineCode = (node: Element): boolean => {\n const textContent = (node.children || [])\n .filter((child) => child.type === 'text')\n .map((child) => child.value)\n .join('');\n\n return !textContent.includes('\\n');\n};\n","import { clsx } from 'clsx';\n\nimport type {\n HighlighterOptions,\n Language,\n OutputFormat,\n Theme,\n Themes,\n UseShikiHighlighter,\n} from './types';\nimport { forwardRef } from 'react';\nimport { useComponentStyles } from './styles';\n\nlet warnedTokensOutputFormat = false;\n\n/**\n * The component's props exclude `outputFormat: 'tokens'`, but plain-JS\n * callers can still pass it. Tokens are not renderable React children,\n * so fall back to 'react' instead of crashing the render.\n */\nconst resolveOutputFormat = (\n outputFormat: HighlighterOptions['outputFormat']\n): HighlighterOptions['outputFormat'] => {\n if ((outputFormat as OutputFormat) !== 'tokens') return outputFormat;\n\n if (!warnedTokensOutputFormat) {\n warnedTokensOutputFormat = true;\n console.warn(\n \"[react-shiki] outputFormat 'tokens' is only supported by the useShikiHighlighter hook, falling back to 'react'\"\n );\n }\n return 'react';\n};\n\n/**\n * Props for the ShikiHighlighter component\n */\nexport interface ShikiHighlighterProps extends HighlighterOptions {\n /**\n * The programming language for syntax highlighting\n * Supports custom textmate grammar objects in addition to Shiki's bundled languages\n * @see https://shiki.style/languages\n */\n language: Language;\n\n /**\n * The code to be highlighted\n */\n children: string;\n\n /**\n * The color theme or themes for syntax highlighting\n * Supports single, dual, or multiple themes\n * Supports custom textmate theme objects in addition to Shiki's bundled themes\n *\n * @example\n * theme='github-dark' // single theme\n * theme={{ light: 'github-light', dark: 'github-dark' }} // multi-theme\n *\n * @see https://shiki.style/themes\n */\n theme: Theme | Themes;\n\n /**\n * Controls the application of default styles to the generated code blocks\n *\n * Default styles include padding, overflow handling, border radius, language label styling, and font settings\n * @default true\n */\n addDefaultStyles?: boolean;\n\n /**\n * Add custom inline styles to the generated code block\n */\n style?: React.CSSProperties;\n\n /**\n * Add custom inline styles to the language label\n */\n langStyle?: React.CSSProperties;\n\n /**\n * Add custom CSS class names to the generated code block\n */\n className?: string;\n\n /**\n * Add custom CSS class names to the language label\n */\n langClassName?: string;\n\n /**\n * Whether to show the language label\n * @default true\n */\n showLanguage?: boolean;\n\n /**\n * The HTML element that wraps the generated code block.\n * @default 'div'\n */\n as?: React.ElementType;\n}\n\n/**\n * Base ShikiHighlighter component factory.\n * This creates a component that uses the provided hook implementation.\n */\nexport const createShikiHighlighterComponent = (\n useShikiHighlighterImpl: UseShikiHighlighter\n) => {\n return forwardRef<HTMLElement, ShikiHighlighterProps>(\n (\n {\n language,\n theme,\n addDefaultStyles = true,\n style,\n langStyle,\n className,\n langClassName,\n showLanguage = true,\n children: code,\n as: Element = 'div',\n outputFormat,\n ...options\n },\n ref\n ) => {\n // Kept inside the component so hook-only bundles can tree-shake it\n // together with the component CSS.\n useComponentStyles();\n\n const displayLanguageId =\n typeof language === 'object'\n ? language.name || null\n : language?.trim() || null;\n\n const highlightedCode = useShikiHighlighterImpl(\n code,\n language,\n theme,\n {\n ...options,\n outputFormat: resolveOutputFormat(outputFormat),\n }\n );\n\n return (\n <Element\n ref={ref}\n data-testid=\"shiki-container\"\n data-slot=\"container\"\n className={clsx(\n 'rs-root',\n 'not-prose',\n addDefaultStyles && 'rs-default-styles',\n className\n )}\n style={style}\n >\n {showLanguage && displayLanguageId ? (\n <span\n data-slot=\"language-label\"\n className={clsx('rs-language-label', langClassName)}\n style={langStyle}\n >\n {displayLanguageId}\n </span>\n ) : null}\n {typeof highlightedCode === 'string' ? (\n <div\n data-slot=\"content\"\n dangerouslySetInnerHTML={{ __html: highlightedCode }}\n />\n ) : (\n highlightedCode\n )}\n </Element>\n );\n }\n );\n};\n"],"mappings":";;;;;;;;;;;;;AASA,MAAa,kBAAqB,UAAgB;CAChD,MAAM,MAAM,OAAO,KAAK;CAExB,IAAI,UAAU,IAAI,WAAW,CAAC,OAAO,OAAO,IAAI,OAAO,GACrD,IAAI,UAAU;CAGhB,OAAO,IAAI;AACb;;;;;;;;;;;;AAaA,MAAa,wBACX,kBACA,gBACA,eACG;CACH,aAAa,eAAe,QAAQ,SAAS;CAE7C,MAAM,QAAQ,KAAK,IACjB,GACA,eAAe,QAAQ,kBAAkB,KAAK,IAAI,CACpD;CACA,eAAe,QAAQ,YAAY,iBAAiB;EAClD,iBAAiB;EACjB,eAAe,QAAQ,kBAAkB,KAAK,IAAI,IAAI;CACxD,GAAG,KAAK;AACV;;;AC5CA,IAAA,oBAAA;;;ACDA,IAAA,mBAAA;;;ACOA,MAAM,2BAAW,IAAI,IAAY;AACjC,MAAM,0BACJ,MAAM,sBAAsB,MAAM;AAEpC,MAAM,UAAU,KAAa,QAAgB;CAC3C,IAAI,SAAS,IAAI,GAAG,KAAK,OAAO,aAAa,aAAa;CAC1D,SAAS,IAAI,GAAG;CAChB,IAAI;EAEF,MAAM,QAAQ,IAAI,cAAc;EAChC,MAAM,YAAY,GAAG;EACrB,SAAS,qBAAqB,CAAC,GAAG,SAAS,oBAAoB,KAAK;CACtE,QAAQ;EACN,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,QAAQ,aAAa;EAC3B,MAAM,cAAc;EACpB,SAAS,KAAK,OAAO,KAAK;CAC5B;AACF;;AAGA,MAAa,2BAA2B;CACtC,8BAA8B;EAC5B,OAAOA,mBAAc,WAAW;CAClC,GAAG,CAAC,CAAC;AACP;;AAGA,MAAa,oBAAoB,YAAqB;CACpD,8BAA8B;EAC5B,IAAI,SAAS,OAAOC,kBAAa,UAAU;CAC7C,GAAG,CAAC,OAAO,CAAC;AACd;;;AC7BA,MAAa,oBAAoB;AAEjC,MAAM,WAAc,UAClB,SAAS,OAAO,CAAC,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAK5D,MAAM,qBACJ,SAEA,OAAO,SAAS,cAChB,gBAAgB,WAChB,MAAM,QAAQ,IAAI,KACjB,OAAO,SAAS,YAAY,QAAQ,QAAQ,aAAa;AAE5D,MAAM,kBACJ,SAEA,OAAO,SAAS,YAAY,QAAQ,QAAQ,CAAC,kBAAkB,IAAI;;AAGrE,MAAM,eAAe,SAAkD;CACrE,IAAI,QAAQ,MAAM,OAAO;CACzB,IAAI,OAAO,SAAS,UAAU,OAAO,KAAK;CAC1C,IAAI,kBAAkB,IAAI,GAAG,OAAO;CACpC,OAAO,KAAK,KAAK,KAAK,IAAI,KAAK;AACjC;AAEA,MAAM,mBAAmB,UAAgD;CACvE,MAAM,uBAAO,IAAI,IAAqB;CACtC,OAAO,MAAM,QAAQ,SAAS;EAC5B,MAAM,MAAM,YAAY,IAAI;EAC5B,IAAI,OAAO,QAAQ,KAAK,IAAI,GAAG,GAAG,OAAO;EACzC,KAAK,IAAI,GAAG;EACZ,OAAO;CACT,CAAC;AACH;;;;;AAMA,MAAM,uBACJ,WACA,YAEA,QAAQ,UAAU,IAAI,KACtB,QAAQ,UAAU,SAAS,KAC3B,QAAQ,UAAU,WAAW,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,KAC7C,CAAC,CAAC,UAAU,SAAS,KAAK,OAAO,KACjC,CAAC,CAAC,UAAU,WAAW,KAAK,OAAO;;;;;AAWrC,MAAa,mBACX,MACA,iBACA,aACA,qBACmB;CACnB,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,eAAe,QAAQ,gBAAgB;CAE7C,MAAM,UACJ,YACA,aACoB;EACpB;EACA,aAAa,gBAAgB;GAC3B;GACA,GAAG;GACH,GAAG;EACL,CAAC;CACH;CAEA,IAAI,QAAQ,QAAS,OAAO,SAAS,YAAY,CAAC,KAAK,KAAK,GAC1D,OAAO,OAAO,iBAAiB;CAGjC,IAAI,OAAO,SAAS,UAClB,OAAO,OAAO,KAAK,MAAM,IAAI;CAG/B,MAAM,aAAa,KAAK,KAAK;CAC7B,MAAM,QAAQ,WAAW,YAAY;CACrC,MAAM,WAAW,QACf,KAAK,YAAY,MAAM;CAGzB,MAAM,cAAc,CAAC,GAAG,aAAa,GAAG,YAAY,CAAC,CAClD,OAAO,cAAc,CAAC,CACtB,MAAM,cAAc,oBAAoB,WAAW,OAAO,CAAC;CAC9D,IAAI,aACF,OAAO,OAAO,YAAY,QAAQ,YAAY,WAAW;CAG3D,MAAM,QAAQ,OAAO,QAAQ,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UACrD,QAAQ,IAAI,CACd,CAAC,GAAG;CACJ,IAAI,OACF,OAAO,OAAO,OAAO,KAAK;CAI5B,OAAO,OAAO,YAAY,UAAU;AACtC;;;;;;AAOA,MAAa,sBACX,MACA,qBACyC;CACzC,IAAI,QAAQ,MAAM,OAAO;CACzB,IAAI,OAAO,SAAS,UAAU,OAAO,QAAQ;CAC7C,IAAI,kBAAkB,IAAI,GAAG,OAAO;CACpC,OACE,OAAO,KAAK,SAAS,YAAY,OAAO,KAAK,cAAc;AAE/D;;;;;AAMA,MAAa,yBACX,YACA,oBAEA,cAAc,UAAU,KAAK,gBAAgB,SAAS,UAAU,IAC5D,aACA;AAEN,MAAa,wBACX,MACA,YACA,gBACoB;CACpB,MAAM,UACJ,YAAY,oBAAoB;CAClC,OAAO,uBAAuB,MAAM,UAAU,CAAC,CAAC,SAC7C,aAAa,QAAQ,aAAa,CAAC,CACtC;AACF;;;ACjKA,MAAa,iBAAyB;CACpC,OAAO;CACP,MAAM;AACR;AAMA,MAAM,mBACJ,UACkC;CAClC,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,IAAI;CAGV,MAAM,YACJ,MAAM,QAAQ,EAAE,WAAW,KAAK,MAAM,QAAQ,EAAE,QAAQ;CAC1D,MAAM,cACJ,OAAO,EAAE,SAAS,YAAY,OAAO,EAAE,SAAS;CAClD,OAAO,aAAa;AACtB;AAEA,SAAgB,aAAa,YAA2C;CACtE,IACE,OAAO,eAAe,YACtB,eAAe,QACf,gBAAgB,UAAU,GAE1B,OAAO;EACL,SAAS;EACT,OAAO;EACP,cAAc,CAAC,UAAU;CAC3B;CAGF,MAAM,eAAe,OAAO,QAAQ,UAAU,CAAC,CAAC,QAC7C,CAAC,KAAK,WACL,IAAI,KAAK,MAAM,OACb,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,MAC9C,gBAAgB,KAAK,EAC3B;CAEA,IAAI,aAAa,WAAW,GAAG;EAC7B,QAAQ,KACN,oEACF;EACA,OAAO;GACL,SAAS;GACT,QAAQ;GACR,cAAc,OAAO,OAAO,cAAc;EAC5C;CACF;CAEA,IAAI,aAAa,WAAW,OAAO,KAAK,UAAU,CAAC,CAAC,QAClD,QAAQ,KACN,+EACF;CAIF,OAAO;EACL,SAAS;EACT,QAHa,OAAO,YAAY,YAG3B;EACL,cAAc,aAAa,KAAK,GAAG,WAAW,KAAc;CAC9D;AACF;;;AClEA,MAAM,0BAAU,IAAI,IAAsC;AAI1D,MAAM,UAA0D;CAC9D,kBACE,OAAO,0BAA0B,CAAC,MAAM,MACtC,EAAE,4BAA4B,CAChC;CACF,iBACE,OAAO,yBAAyB,CAAC,MAAM,MACrC,EAAE,sBAAsB,OAAO,aAAa,CAC9C;AACJ;;;;;;;;AASA,MAAa,iBACX,WACuC;CACvC,IAAI,OAAO,WAAW,UAAU,OAAO;CAEvC,MAAM,OAAO,QAAQ;CACrB,IAAI,CAAC,MACH,MAAM,IAAI,MACR,iCAAiC,OAAO,wCAC1C;CAGF,MAAM,SAAS,QAAQ,IAAI,MAAM;CACjC,IAAI,QAAQ,OAAO;CAEnB,MAAM,WAAW,KAAK;CAGtB,SAAS,YAAY,QAAQ,OAAO,MAAM,CAAC;CAC3C,QAAQ,IAAI,QAAQ,QAAQ;CAC5B,OAAO;AACT;;;AC5CA,MAAM,mBAAmB,gBACvB,IAAI,IAAI,YAAY,OAAO,OAAO,SAAS,CAAC;;;;;AAM9C,SAAgB,uBAAuB,YAAY,GAAqB;CACtE,OAAO;EACL,MAAM;EACN,KAAK,MAAM;GACT,KAAK,eAAe,MAAM,qBAAqB;GAC/C,IAAI,cAAc,GAAG;IACnB,MAAM,WAAW,KAAK,YAAY;IAClC,KAAK,aAAa;KAChB,GAAG,KAAK;KACR,OAAO,CAAC,UAAU,iBAAiB,WAAW,CAAC,CAC5C,OAAO,OAAO,CAAC,CACf,KAAK,IAAI;IACd;GACF;EACF;EACA,KAAK,MAAM;GACT,KAAK,eAAe,MAAM,gBAAgB;GAC1C,OAAO;EACT;CACF;AACF;;;;;;AAOA,SAAgB,4BACd,aACA,YAAY,GACM;CAClB,MAAM,mBAAmB,gBAAgB,WAAW;CAEpD,OAAO;EACL,MAAM;EACN,KAAK,MAAM;GACT,KAAK,eAAe,MAAM,0BAA0B;EACtD;EACA,KAAK,MAAM,MAAM;GACf,MAAM,gBAAgB,YAAY,OAAO;GAEzC,IAAI,iBAAiB,IAAI,aAAa,GACpC,KAAK,eAAe,MAAM,qBAAqB;GAGjD,OAAO;EACT;CACF;AACF;;;ACvCA,MAAM,qBACJ,eACA,cACA,sBAG0C;CAC1C,IAAI,cAAc,SAChB,OAAO;EACL,QAAQ,cAAc;EACtB;EACA;CACF;CAGF,OAAO,EACL,OAAO,cAAc,MACvB;AACF;AAEA,MAAa,qBACX,YACA,eACA,YACsB;CACtB,MAAM,EACJ,OACA,iBACA,kBACA,cACA,aACA,WACA,QACA,cACA,mBACA,iBACA,oBACA,sBACA,cAAc,kBACd,GAAG,qBACD;CAEJ,MAAM,eAAe,CAAC,GAAI,oBAAoB,CAAC,CAAE;CACjD,IAAI,iBACF,aAAa,KAAK,uBAAuB,kBAAkB,CAAC;CAE9D,IAAI,sBAAsB,QACxB,aAAa,KACX,4BACE,sBACA,kBACF,CACF;CAGF,OAAO;EACL,MAAM;EACN,GAAG,kBAAkB,eAAe,cAAc,iBAAiB;EACnE,GAAG;EACH;CACF;AACF;;;ACjDA,eAAsB,UACpB,MACA,UAMA,MAGA,SACgC;CAChC,MAAM,EAAE,YAAY,aAAa,cAAc,iBAC7C;CACF,MAAM,SAAuB,KAAK,gBAAgB;CAElD,MAAM,cACJ,KAAK,eACJ,OAAO,YAAY;EAClB,MAAM,KAAK,MAAM,QACf,aACA,cACA,cAAc,KAAK,MAAM,CAC3B;EACA,MAAM,GAAG,aACP,GAAG,qBAAqB,MAAM,YAAY,EAAE,CAC9C;EACA,OAAO;CACT,EAAA,CAAG;CAEL,MAAM,WAAW,sBACf,YACA,YAAY,mBAAmB,CACjC;CACA,MAAM,UAAU;EAAE,GAAG;EAAc,MAAM;CAAS;CAElD,MAAM,UAAgE;EACpE,aACE,aAAa,YAAY,WAAW,MAAM,OAAO,GAAG;GAClD;GACA;GACA;EACF,CAAC;EACH,YAAY,YAAY,WAAW,MAAM,OAAO;EAChD,cAAc,YAAY,aAAa,MAAM,OAAO;CACtD;CAIA,QAAQ,QAAQ,WAAW,QAAQ,MAAA,CAAO;AAC5C;AAEA,MAAa,gBACX,MACA,MACA,YACA,UAAoC,CAAC,GACrC,uBACuB;CACvB,MAAM,CAAC,iBAAiB,sBACtB,SAA6B,IAAI;CAInC,iBACE,QACE,QAAQ,mBAAmB,QAAQ,sBAAsB,MAC3D,CACF;CAEA,MAAM,aAAa,eAAe,IAAI;CACtC,MAAM,cAAc,eAAe,UAAU;CAC7C,MAAM,aAAa,eAAe,OAAO;CAEzC,MAAM,WAAW,cAAc;EAC7B,MAAM,EAAE,YAAY,gBAAgB,gBAClC,YACA,WAAW,iBACX,WAAW,WACX,WAAW,gBACb;EAEA,MAAM,QAAQ,aAAa,WAAW;EAEtC,MAAM,eAAe,kBAAkB,YAAY,OAAO,UAAU;EACpE,OAAO;GACL;GACA;GACA,cAAc,MAAM;GACpB;EACF;CACF,GAAG;EAAC;EAAY;EAAa;CAAU,CAAC;CAExC,MAAM,eAAe,OAAO,CAAC;CAE7B,MAAM,iBAAiB,OAAqB;EAC1C,iBAAiB;EACjB,WAAW,KAAA;CACb,CAAC;CAID,MAAM,wBAAwB,OAAO,kBAAkB;CACvD,sBAAsB,UAAU;CAEhC,gBAAgB;EACd,MAAM,YAAY,EAAE,aAAa;EAEjC,IAAI,CAAC,SAAS,YAAY;EAE1B,MAAM,MAAM,YAAY;GACtB,IAAI;IACF,MAAM,SAAS,MAAM,UACnB,MACA,UACA,YACA,sBAAsB,OACxB;IACA,IAAI,cAAc,aAAa,SAC7B,mBAAmB,MAAM;GAE7B,SAAS,OAAO;IACd,QAAQ,MAAM,kCAAkC,KAAK;GACvD;EACF;EAEA,IAAI,WAAW,OACb,qBAAqB,KAAK,gBAAgB,WAAW,KAAK;OAE1D,IAAI;EAGN,aAAa;GACX,aAAa,eAAe,QAAQ,SAAS;EAC/C;CACF,GAAG;EAAC;EAAM;EAAU;CAAU,CAAC;CAE/B,OAAO;AACT;;;;;;;;;;;;;AC3JA,SAAgB,2BAA2B;CACzC,QAAQ,SAA0B;EAChC,MAAM,MAAM,YAAY,MAAe,QAAQ,WAAW;GACxD,IACE,KAAK,YAAY,UACjB,QAAQ,SAAS,aACjB,OAAO,YAAY,OAEnB,KAAK,WAAW,SAAS;EAE7B,CAAC;CACH;AACF;;;;;;;AAQA,MAAa,gBAAgB,SAA2B;CAMtD,OAAO,EALc,KAAK,YAAY,CAAC,EAAA,CACpC,QAAQ,UAAU,MAAM,SAAS,MAAM,CAAC,CACxC,KAAK,UAAU,MAAM,KAAK,CAAC,CAC3B,KAAK,EAEU,CAAC,CAAC,SAAS,IAAI;AACnC;;;AC5BA,IAAI,2BAA2B;;;;;;AAO/B,MAAM,uBACJ,iBACuC;CACvC,IAAK,iBAAkC,UAAU,OAAO;CAExD,IAAI,CAAC,0BAA0B;EAC7B,2BAA2B;EAC3B,QAAQ,KACN,gHACF;CACF;CACA,OAAO;AACT;;;;;AA4EA,MAAa,mCACX,4BACG;CACH,OAAO,YAEH,EACE,UACA,OACA,mBAAmB,MACnB,OACA,WACA,WACA,eACA,eAAe,MACf,UAAU,MACV,IAAI,UAAU,OACd,cACA,GAAG,WAEL,QACG;EAGH,mBAAmB;EAEnB,MAAM,oBACJ,OAAO,aAAa,WAChB,SAAS,QAAQ,OACjB,UAAU,KAAK,KAAK;EAE1B,MAAM,kBAAkB,wBACtB,MACA,UACA,OACA;GACE,GAAG;GACH,cAAc,oBAAoB,YAAY;EAChD,CACF;EAEA,OACE,qBAAC,SAAD;GACO;GACL,eAAY;GACZ,aAAU;GACV,WAAW,KACT,WACA,aACA,oBAAoB,qBACpB,SACF;GACO;GAVT,UAAA,CAYG,gBAAgB,oBACf,oBAAC,QAAD;IACE,aAAU;IACV,WAAW,KAAK,qBAAqB,aAAa;IAClD,OAAO;IAEN,UAAA;GACG,CAAA,IACJ,MACH,OAAO,oBAAoB,WAC1B,oBAAC,OAAD;IACE,aAAU;IACV,yBAAyB,EAAE,QAAQ,gBAAgB;GACpD,CAAA,IAED,eAEK;;CAEb,CACF;AACF"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ReactElement } from "react";
|
|
2
|
-
import { BundledHighlighterOptions, BundledLanguage, BundledTheme, CodeOptionsMultipleThemes, CodeToHastOptions, Highlighter, HighlighterCore, LanguageRegistration, SpecialLanguage, StringLiteralUnion, ThemeRegistrationAny, TokensResult } from "shiki";
|
|
3
|
-
|
|
2
|
+
import { Awaitable, BundledHighlighterOptions, BundledLanguage, BundledTheme, CodeOptionsMultipleThemes, CodeToHastOptions, Highlighter, HighlighterCore, LanguageInput, LanguageRegistration, RegexEngine, SpecialLanguage, StringLiteralUnion, ThemeRegistrationAny, TokensResult } from "shiki";
|
|
4
3
|
//#region ../node_modules/.pnpm/@types+unist@3.0.3/node_modules/@types/unist/index.d.ts
|
|
5
4
|
// ## Interfaces
|
|
6
5
|
/**
|
|
@@ -317,6 +316,12 @@ type Element = Element$1;
|
|
|
317
316
|
* @see https://shiki.style/languages
|
|
318
317
|
*/
|
|
319
318
|
type Language = LanguageRegistration | StringLiteralUnion<BundledLanguage> | SpecialLanguage | undefined;
|
|
319
|
+
/**
|
|
320
|
+
* A `preloadLanguages` entry: a bundled language id, a custom grammar
|
|
321
|
+
* object, or a dynamic grammar import (shiki's `LanguageInput`), e.g.
|
|
322
|
+
* `() => import('../langs/mcfunction.json')`
|
|
323
|
+
*/
|
|
324
|
+
type PreloadLanguage = Language | LanguageInput;
|
|
320
325
|
type MultiThemeKey = 'dark' | 'light' | (string & {});
|
|
321
326
|
/**
|
|
322
327
|
* A Shiki BundledTheme or a custom textmate theme object
|
|
@@ -339,7 +344,11 @@ type Theme = ThemeRegistrationAny | StringLiteralUnion<BundledTheme>;
|
|
|
339
344
|
*
|
|
340
345
|
* @see https://shiki.style/guide/dual-themes
|
|
341
346
|
*/
|
|
342
|
-
type Themes = { [Key in MultiThemeKey]: Theme };
|
|
347
|
+
type Themes = { [Key in MultiThemeKey]: Theme; };
|
|
348
|
+
/**
|
|
349
|
+
* Named RegExp engines that react-shiki creates and caches internally.
|
|
350
|
+
*/
|
|
351
|
+
type EngineName = 'javascript' | 'oniguruma';
|
|
343
352
|
/**
|
|
344
353
|
* Configuration options specific to react-shiki
|
|
345
354
|
*/
|
|
@@ -349,6 +358,18 @@ interface ReactShikiOptions {
|
|
|
349
358
|
* @default undefined (no throttling)
|
|
350
359
|
*/
|
|
351
360
|
delay?: number;
|
|
361
|
+
/**
|
|
362
|
+
* RegExp engine for syntax highlighting.
|
|
363
|
+
* - 'oniguruma': compiled WebAssembly engine, maximum grammar support
|
|
364
|
+
* - 'javascript': pure-JS engine, no WASM fetch, faster startup
|
|
365
|
+
*
|
|
366
|
+
* Named engines are created lazily and cached by react-shiki, so they
|
|
367
|
+
* are safe to pass inline. A custom engine instance is also accepted;
|
|
368
|
+
* create it once at module scope, as a new instance on every render
|
|
369
|
+
* re-triggers highlighting.
|
|
370
|
+
* @default 'oniguruma'
|
|
371
|
+
*/
|
|
372
|
+
engine?: EngineName | Awaitable<RegexEngine>;
|
|
352
373
|
/**
|
|
353
374
|
* Custom textmate grammars to be preloaded for highlighting.
|
|
354
375
|
* @deprecated Use preloadLanguages instead.
|
|
@@ -357,8 +378,16 @@ interface ReactShikiOptions {
|
|
|
357
378
|
/**
|
|
358
379
|
* Preload custom grammars or bundled languages.
|
|
359
380
|
* Supports custom textmate grammars, replaces deprecated `customLanguages`
|
|
381
|
+
*
|
|
382
|
+
* Full/web bundles also accept dynamic grammar imports, keeping custom
|
|
383
|
+
* grammars out of the main bundle. Define them at module scope, preferring
|
|
384
|
+
* getters: a fresh getter each render re-triggers highlighting, while
|
|
385
|
+
* swapping a bare promise at runtime is not detected.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* const preload = [() => import('../langs/mcfunction.json')];
|
|
360
389
|
*/
|
|
361
|
-
preloadLanguages?:
|
|
390
|
+
preloadLanguages?: PreloadLanguage | PreloadLanguage[];
|
|
362
391
|
/**
|
|
363
392
|
* Output format for the highlighted code.
|
|
364
393
|
* - 'react': Returns React nodes (default, safer)
|
|
@@ -418,10 +447,7 @@ interface ReactShikiOptions {
|
|
|
418
447
|
* Configuration options for the syntax highlighter
|
|
419
448
|
* Extends CodeToHastOptions to allow passing any Shiki options directly
|
|
420
449
|
*/
|
|
421
|
-
interface HighlighterOptions extends ReactShikiOptions, Pick<CodeOptionsMultipleThemes<BundledTheme>, 'defaultColor' | 'cssVariablePrefix'>, Omit<CodeToHastOptions, 'lang' | 'theme' | 'themes'>, Pick<BundledHighlighterOptions<string, string>, 'langAlias'
|
|
422
|
-
/**
|
|
423
|
-
* State for the throttling logic
|
|
424
|
-
*/
|
|
450
|
+
interface HighlighterOptions extends ReactShikiOptions, Pick<CodeOptionsMultipleThemes<BundledTheme>, 'defaultColor' | 'cssVariablePrefix'>, Omit<CodeToHastOptions, 'lang' | 'theme' | 'themes'>, Pick<BundledHighlighterOptions<string, string>, 'langAlias'> {}
|
|
425
451
|
/**
|
|
426
452
|
* Supported output formats and their corresponding result shapes.
|
|
427
453
|
*/
|
|
@@ -521,20 +547,6 @@ interface ShikiHighlighterProps extends HighlighterOptions {
|
|
|
521
547
|
* @default true
|
|
522
548
|
*/
|
|
523
549
|
showLanguage?: boolean;
|
|
524
|
-
/**
|
|
525
|
-
* Whether to show line numbers
|
|
526
|
-
* @default false
|
|
527
|
-
*/
|
|
528
|
-
showLineNumbers?: boolean;
|
|
529
|
-
/**
|
|
530
|
-
* Starting line number (when showLineNumbers is true)
|
|
531
|
-
* @default 1
|
|
532
|
-
*/
|
|
533
|
-
startingLineNumber?: number;
|
|
534
|
-
/**
|
|
535
|
-
* Displayed line numbers to highlight
|
|
536
|
-
*/
|
|
537
|
-
highlightLineNumbers?: number[];
|
|
538
550
|
/**
|
|
539
551
|
* The HTML element that wraps the generated code block.
|
|
540
552
|
* @default 'div'
|
|
@@ -542,5 +554,5 @@ interface ShikiHighlighterProps extends HighlighterOptions {
|
|
|
542
554
|
as?: React.ElementType;
|
|
543
555
|
}
|
|
544
556
|
//#endregion
|
|
545
|
-
export {
|
|
546
|
-
//# sourceMappingURL=component-
|
|
557
|
+
export { EngineName as a, HighlighterOptionsFor as c, PreloadLanguage as d, Theme as f, Element as i, Language as l, UseShikiHighlighter as m, isInlineCode as n, HighlightResult as o, Themes as p, rehypeInlineCodeProperty as r, HighlighterOptions as s, ShikiHighlighterProps as t, OutputFormat as u };
|
|
558
|
+
//# sourceMappingURL=component-DlK6KonE.d.mts.map
|
package/dist/core.d.mts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as EngineName, c as HighlighterOptionsFor, d as PreloadLanguage, f as Theme, i as Element, l as Language, m as UseShikiHighlighter, n as isInlineCode, o as HighlightResult, p as Themes, r as rehypeInlineCodeProperty, s as HighlighterOptions, t as ShikiHighlighterProps, u as OutputFormat } from "./component-DlK6KonE.mjs";
|
|
2
2
|
import { LanguageRegistration, TokensResult, createHighlighterCore } from "shiki/core";
|
|
3
3
|
import { createOnigurumaEngine } from "shiki/engine/oniguruma";
|
|
4
4
|
import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
5
|
-
|
|
6
5
|
//#region src/core.d.ts
|
|
7
6
|
/**
|
|
8
7
|
* Highlight code with shiki (core bundle)
|
|
@@ -44,5 +43,5 @@ declare const useShikiHighlighter: UseShikiHighlighter;
|
|
|
44
43
|
*/
|
|
45
44
|
declare const ShikiHighlighter: import("react").ForwardRefExoticComponent<ShikiHighlighterProps & import("react").RefAttributes<HTMLElement>>;
|
|
46
45
|
//#endregion
|
|
47
|
-
export { type Element, type HighlightResult, type HighlighterOptions, type HighlighterOptionsFor, type Language, type LanguageRegistration, type OutputFormat, ShikiHighlighter, ShikiHighlighter as default, type ShikiHighlighterProps, type Theme, type Themes, type TokensResult, type UseShikiHighlighter, createHighlighterCore, createJavaScriptRawEngine, createJavaScriptRegexEngine, createOnigurumaEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
|
|
46
|
+
export { type Element, type EngineName, type HighlightResult, type HighlighterOptions, type HighlighterOptionsFor, type Language, type LanguageRegistration, type OutputFormat, type PreloadLanguage, ShikiHighlighter, ShikiHighlighter as default, type ShikiHighlighterProps, type Theme, type Themes, type TokensResult, type UseShikiHighlighter, createHighlighterCore, createJavaScriptRawEngine, createJavaScriptRegexEngine, createOnigurumaEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
|
|
48
47
|
//# sourceMappingURL=core.d.mts.map
|
package/dist/core.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as useHighlight, n as isInlineCode, r as rehypeInlineCodeProperty, t as createShikiHighlighterComponent } from "./component-
|
|
1
|
+
import { i as useHighlight, n as isInlineCode, r as rehypeInlineCodeProperty, t as createShikiHighlighterComponent } from "./component-Cf8Topxy.mjs";
|
|
2
2
|
import { createHighlighterCore } from "shiki/core";
|
|
3
3
|
import { createOnigurumaEngine } from "shiki/engine/oniguruma";
|
|
4
4
|
import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
@@ -57,7 +57,7 @@ const useShikiHighlighter = (code, lang, themeInput, options = {}) => {
|
|
|
57
57
|
* ShikiHighlighter component using a custom highlighter.
|
|
58
58
|
* Requires a highlighter to be provided.
|
|
59
59
|
*/
|
|
60
|
-
const ShikiHighlighter = createShikiHighlighterComponent(useShikiHighlighter);
|
|
60
|
+
const ShikiHighlighter = /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);
|
|
61
61
|
//#endregion
|
|
62
62
|
export { ShikiHighlighter, ShikiHighlighter as default, createHighlighterCore, createJavaScriptRawEngine, createJavaScriptRegexEngine, createOnigurumaEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
|
|
63
63
|
|
package/dist/core.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.mjs","names":[],"sources":["../src/bundles/core.ts","../src/core.ts"],"sourcesContent":["import type { HighlighterCore } from 'shiki';\n\n/**\n * Validates that a highlighter is provided for the core bundle.\n * The core bundle requires users to provide their own highlighter instance.\n */\nexport function validateCoreHighlighter(\n highlighter: HighlighterCore | undefined\n): HighlighterCore {\n if (!highlighter) {\n throw new Error(\n 'react-shiki/core requires a custom highlighter. ' +\n 'Use createHighlighterCore() from react-shiki or switch to react-shiki for plug-and-play usage.'\n );\n }\n return highlighter;\n}\n","import { useHighlight } from './lib/hook';\nimport { validateCoreHighlighter } from './bundles/core';\nimport type { UseShikiHighlighter } from './lib/types';\n\nexport { isInlineCode, rehypeInlineCodeProperty } from './lib/plugins';\n\nimport {\n createShikiHighlighterComponent,\n type ShikiHighlighterProps,\n} from './lib/component';\n\nexport type { ShikiHighlighterProps };\n\nexport type {\n UseShikiHighlighter,\n Language,\n Theme,\n Themes,\n Element,\n HighlighterOptions,\n HighlighterOptionsFor,\n HighlightResult,\n OutputFormat,\n} from './lib/types';\n\nexport { createHighlighterCore } from 'shiki/core';\nexport { createOnigurumaEngine } from 'shiki/engine/oniguruma';\nexport {\n createJavaScriptRegexEngine,\n createJavaScriptRawEngine,\n} from 'shiki/engine/javascript';\n\nexport type { LanguageRegistration, TokensResult } from 'shiki/core';\n\n/**\n * Highlight code with shiki (core bundle)\n *\n * @param code - Code to highlight\n * @param lang - Language (bundled or custom)\n * @param theme - Theme (bundled, multi-theme, or custom)\n * @param options - react-shiki options + shiki options\n * @returns Highlighted code as React elements (default), HTML string, or Shiki tokens, based on `outputFormat`\n *\n * @example\n * ```tsx\n * import { createHighlighterCore, createOnigurumaEngine } from 'react-shiki/core';\n *\n *\n * const highlighter = await createHighlighterCore({\n * themes: [import('@shikijs/themes/github-light'), import('@shikijs/themes/github-dark')],\n * langs: [import('@shikijs/langs/typescript')],\n * engine: createOnigurumaEngine(import('shiki/wasm'))\n * });\n *\n * const highlighted = useShikiHighlighter(\n * 'const x = 1;',\n * 'typescript',\n * {\n * light: 'github-light',\n * dark: 'github-dark'\n * },\n * { highlighter }\n * );\n * ```\n *\n * Core bundle (minimal). For plug-and-play: `react-shiki` or `react-shiki/web`\n */\nexport const useShikiHighlighter: UseShikiHighlighter = (\n code,\n lang,\n themeInput,\n options = {}\n) => {\n
|
|
1
|
+
{"version":3,"file":"core.mjs","names":[],"sources":["../src/bundles/core.ts","../src/core.ts"],"sourcesContent":["import type { HighlighterCore } from 'shiki';\n\n/**\n * Validates that a highlighter is provided for the core bundle.\n * The core bundle requires users to provide their own highlighter instance.\n */\nexport function validateCoreHighlighter(\n highlighter: HighlighterCore | undefined\n): HighlighterCore {\n if (!highlighter) {\n throw new Error(\n 'react-shiki/core requires a custom highlighter. ' +\n 'Use createHighlighterCore() from react-shiki or switch to react-shiki for plug-and-play usage.'\n );\n }\n return highlighter;\n}\n","import { useHighlight } from './lib/hook';\nimport { validateCoreHighlighter } from './bundles/core';\nimport type { UseShikiHighlighter } from './lib/types';\n\nexport { isInlineCode, rehypeInlineCodeProperty } from './lib/plugins';\n\nimport {\n createShikiHighlighterComponent,\n type ShikiHighlighterProps,\n} from './lib/component';\n\nexport type { ShikiHighlighterProps };\n\nexport type {\n UseShikiHighlighter,\n Language,\n PreloadLanguage,\n Theme,\n Themes,\n Element,\n EngineName,\n HighlighterOptions,\n HighlighterOptionsFor,\n HighlightResult,\n OutputFormat,\n} from './lib/types';\n\nexport { createHighlighterCore } from 'shiki/core';\nexport { createOnigurumaEngine } from 'shiki/engine/oniguruma';\nexport {\n createJavaScriptRegexEngine,\n createJavaScriptRawEngine,\n} from 'shiki/engine/javascript';\n\nexport type { LanguageRegistration, TokensResult } from 'shiki/core';\n\n/**\n * Highlight code with shiki (core bundle)\n *\n * @param code - Code to highlight\n * @param lang - Language (bundled or custom)\n * @param theme - Theme (bundled, multi-theme, or custom)\n * @param options - react-shiki options + shiki options\n * @returns Highlighted code as React elements (default), HTML string, or Shiki tokens, based on `outputFormat`\n *\n * @example\n * ```tsx\n * import { createHighlighterCore, createOnigurumaEngine } from 'react-shiki/core';\n *\n *\n * const highlighter = await createHighlighterCore({\n * themes: [import('@shikijs/themes/github-light'), import('@shikijs/themes/github-dark')],\n * langs: [import('@shikijs/langs/typescript')],\n * engine: createOnigurumaEngine(import('shiki/wasm'))\n * });\n *\n * const highlighted = useShikiHighlighter(\n * 'const x = 1;',\n * 'typescript',\n * {\n * light: 'github-light',\n * dark: 'github-dark'\n * },\n * { highlighter }\n * );\n * ```\n *\n * Core bundle (minimal). For plug-and-play: `react-shiki` or `react-shiki/web`\n */\nexport const useShikiHighlighter: UseShikiHighlighter = (\n code,\n lang,\n themeInput,\n options = {}\n) => {\n const highlighter = validateCoreHighlighter(options.highlighter);\n\n return useHighlight(\n code,\n lang,\n themeInput,\n {\n ...options,\n highlighter,\n },\n async () => highlighter\n );\n};\n\n/**\n * ShikiHighlighter component using a custom highlighter.\n * Requires a highlighter to be provided.\n */\nexport const ShikiHighlighter =\n /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);\nexport default ShikiHighlighter;\n"],"mappings":";;;;;;;;;AAMA,SAAgB,wBACd,aACiB;CACjB,IAAI,CAAC,aACH,MAAM,IAAI,MACR,gJAEF;CAEF,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACqDA,MAAa,uBACX,MACA,MACA,YACA,UAAU,CAAC,MACR;CACH,MAAM,cAAc,wBAAwB,QAAQ,WAAW;CAE/D,OAAO,aACL,MACA,MACA,YACA;EACE,GAAG;EACH;CACF,GACA,YAAY,WACd;AACF;;;;;AAMA,MAAa,mBACG,8CAAgC,mBAAmB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { a as isLoadableLanguage } from "./component-Cf8Topxy.mjs";
|
|
2
|
+
import { createOnigurumaEngine } from "shiki/engine/oniguruma";
|
|
3
|
+
//#region src/bundles/factory.ts
|
|
4
|
+
/**
|
|
5
|
+
* Builds a highlighter factory for a Shiki bundle (full or web).
|
|
6
|
+
* Unloadable languages are filtered out so unknown ids fall back to
|
|
7
|
+
* plaintext instead of throwing.
|
|
8
|
+
*/
|
|
9
|
+
const bundledHighlighterFactory = (getSingletonHighlighter, bundledLanguages) => (langsToLoad, themesToLoad, engine) => getSingletonHighlighter({
|
|
10
|
+
langs: langsToLoad.filter((lang) => isLoadableLanguage(lang, bundledLanguages)),
|
|
11
|
+
themes: themesToLoad,
|
|
12
|
+
engine: engine ?? createOnigurumaEngine(import("shiki/wasm"))
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { bundledHighlighterFactory as t };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=factory-DySLHBEo.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory-DySLHBEo.mjs","names":[],"sources":["../src/bundles/factory.ts"],"sourcesContent":["import { createOnigurumaEngine } from 'shiki/engine/oniguruma';\nimport type {\n Awaitable,\n DynamicImportLanguageRegistration,\n HighlighterCore,\n RegexEngine,\n} from 'shiki/core';\nimport type {\n HighlighterFactory,\n PreloadLanguage,\n Theme,\n} from '../lib/types';\nimport { isLoadableLanguage } from '../lib/language';\n\ntype GetSingletonHighlighter = (options: {\n langs: NonNullable<PreloadLanguage>[];\n themes: Theme[];\n engine: Awaitable<RegexEngine>;\n}) => Promise<HighlighterCore>;\n\n/**\n * Builds a highlighter factory for a Shiki bundle (full or web).\n * Unloadable languages are filtered out so unknown ids fall back to\n * plaintext instead of throwing.\n */\nexport const bundledHighlighterFactory =\n (\n getSingletonHighlighter: GetSingletonHighlighter,\n bundledLanguages: Record<string, DynamicImportLanguageRegistration>\n ): HighlighterFactory =>\n (langsToLoad, themesToLoad, engine) =>\n getSingletonHighlighter({\n langs: langsToLoad.filter((lang) =>\n isLoadableLanguage(lang, bundledLanguages)\n ),\n themes: themesToLoad,\n engine: engine ?? createOnigurumaEngine(import('shiki/wasm')),\n });\n"],"mappings":";;;;;;;;AAyBA,MAAa,6BAET,yBACA,sBAED,aAAa,cAAc,WAC1B,wBAAwB;CACtB,OAAO,YAAY,QAAQ,SACzB,mBAAmB,MAAM,gBAAgB,CAC3C;CACA,QAAQ;CACR,QAAQ,UAAU,sBAAsB,OAAO,aAAa;AAC9D,CAAC"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as EngineName, c as HighlighterOptionsFor, d as PreloadLanguage, f as Theme, i as Element, l as Language, m as UseShikiHighlighter, n as isInlineCode, o as HighlightResult, p as Themes, r as rehypeInlineCodeProperty, s as HighlighterOptions, t as ShikiHighlighterProps, u as OutputFormat } from "./component-DlK6KonE.mjs";
|
|
2
2
|
import { LanguageRegistration, TokensResult } from "shiki";
|
|
3
3
|
import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
4
|
-
|
|
5
4
|
//#region src/index.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* Highlight code with shiki (full bundle)
|
|
@@ -33,5 +32,5 @@ declare const useShikiHighlighter: UseShikiHighlighter;
|
|
|
33
32
|
*/
|
|
34
33
|
declare const ShikiHighlighter: import("react").ForwardRefExoticComponent<ShikiHighlighterProps & import("react").RefAttributes<HTMLElement>>;
|
|
35
34
|
//#endregion
|
|
36
|
-
export { type Element, type HighlightResult, type HighlighterOptions, type HighlighterOptionsFor, type Language, type LanguageRegistration, type OutputFormat, ShikiHighlighter, ShikiHighlighter as default, type ShikiHighlighterProps, type Theme, type Themes, type TokensResult, type UseShikiHighlighter, createJavaScriptRawEngine, createJavaScriptRegexEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
|
|
35
|
+
export { type Element, type EngineName, type HighlightResult, type HighlighterOptions, type HighlighterOptionsFor, type Language, type LanguageRegistration, type OutputFormat, type PreloadLanguage, ShikiHighlighter, ShikiHighlighter as default, type ShikiHighlighterProps, type Theme, type Themes, type TokensResult, type UseShikiHighlighter, createJavaScriptRawEngine, createJavaScriptRegexEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
|
|
37
36
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as useHighlight, n as isInlineCode, r as rehypeInlineCodeProperty, t as createShikiHighlighterComponent } from "./component-Cf8Topxy.mjs";
|
|
2
|
+
import { t as bundledHighlighterFactory } from "./factory-DySLHBEo.mjs";
|
|
2
3
|
import { bundledLanguages, getSingletonHighlighter } from "shiki";
|
|
3
|
-
import { createOnigurumaEngine } from "shiki/engine/oniguruma";
|
|
4
4
|
import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
5
5
|
//#region src/bundles/full.ts
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Highlighter factory for the full Shiki bundle: every language and
|
|
8
|
+
* theme, largest size, maximum compatibility.
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
|
-
return await getSingletonHighlighter({
|
|
12
|
-
langs: langsToLoad.filter((lang) => isLoadableLanguage(lang, bundledLanguages)),
|
|
13
|
-
themes: themesToLoad,
|
|
14
|
-
engine: engine ?? createOnigurumaEngine(import("shiki/wasm"))
|
|
15
|
-
});
|
|
16
|
-
}
|
|
10
|
+
const createFullHighlighter = bundledHighlighterFactory(getSingletonHighlighter, bundledLanguages);
|
|
17
11
|
//#endregion
|
|
18
12
|
//#region src/index.ts
|
|
19
13
|
/**
|
|
@@ -44,7 +38,7 @@ const useShikiHighlighter = (code, lang, themeInput, options = {}) => useHighlig
|
|
|
44
38
|
* ShikiHighlighter component using the full bundle.
|
|
45
39
|
* Includes all languages and themes for maximum compatibility.
|
|
46
40
|
*/
|
|
47
|
-
const ShikiHighlighter = createShikiHighlighterComponent(useShikiHighlighter);
|
|
41
|
+
const ShikiHighlighter = /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);
|
|
48
42
|
//#endregion
|
|
49
43
|
export { ShikiHighlighter, ShikiHighlighter as default, createJavaScriptRawEngine, createJavaScriptRegexEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
|
|
50
44
|
|