react-shiki 0.11.1 → 0.11.3

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 CHANGED
@@ -306,6 +306,7 @@ The core inputs, positional arguments on the hook, props/children on the compone
306
306
  | Option | Type | Default | Description |
307
307
  | ------------------- | ------------------ | --------------- | ----------------------------------------------------------------------------- |
308
308
  | `delay` | `number` | - | Minimum time between highlights (in milliseconds), no throttling by default |
309
+ | `cache` | `Map` | - | Keeps highlighted output across unmounts, see [Caching Across Remounts](#caching-across-remounts) |
309
310
  | `engine` | `'javascript' \| 'oniguruma' \| RegexEngine` | `'oniguruma'` | RegExp engine for syntax highlighting; named engines are created and cached internally |
310
311
  | `highlighter` | `Highlighter \| HighlighterCore` | - | Custom highlighter instance, required for the core bundle |
311
312
  | `outputFormat` | `string` | `'react'` | Output format: 'react' for React nodes, 'html' for HTML string, or 'tokens' for Shiki tokens (hook only, experimental) |
@@ -798,6 +799,22 @@ const highlightedCode = useShikiHighlighter(code, "tsx", "github-dark", {
798
799
  });
799
800
  ```
800
801
 
802
+ ### Caching Across Remounts
803
+
804
+ Lists that remount their content, like chat transcripts when switching threads or virtualized lists while scrolling, highlight every code block again by default. Pass a `Map` as `cache` and unchanged blocks paint on their first render instead:
805
+
806
+ ```tsx
807
+ const cache = new Map();
808
+
809
+ <ShikiHighlighter language="tsx" theme="github-dark" cache={cache}>
810
+ {code}
811
+ </ShikiHighlighter>
812
+ ```
813
+
814
+ - A block's output is stored when it unmounts, so the partial code of a streaming block is never cached.
815
+ - Entries are keyed by code, language, theme and options, so blocks with different settings can share one cache. Transformers are told apart by `name`, so give blocks with different transformers of the same name their own cache.
816
+ - The cache is yours: keep one per app or per conversation and `clear()` it when that content goes away.
817
+
801
818
  ---
802
819
 
803
820
  Made with ❤️ by [Bassim (AVGVSTVS96)](https://github.com/AVGVSTVS96)
package/dist/core.d.mts CHANGED
@@ -1,8 +1,7 @@
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";
1
+ import { a as EngineName, c as HighlighterOptions, d as OutputFormat, f as PreloadLanguage, h as UseShikiHighlighter, i as Element, l as HighlighterOptionsFor, m as Themes, n as rehypeInlineCodeProperty, o as HighlightCache, p as Theme, r as ShikiHighlighterProps, s as HighlightResult, t as isInlineCode, u as Language } from "./plugins-DdjjMnbY.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
- //#region src/core.d.ts
6
5
  /**
7
6
  * Highlight code with shiki (core bundle)
8
7
  *
@@ -36,12 +35,10 @@ import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/en
36
35
  *
37
36
  * Core bundle (minimal). For plug-and-play: `react-shiki` or `react-shiki/web`
38
37
  */
39
- declare const useShikiHighlighter: UseShikiHighlighter;
38
+ export declare const useShikiHighlighter: UseShikiHighlighter;
40
39
  /**
41
40
  * ShikiHighlighter component using a custom highlighter.
42
41
  * Requires a highlighter to be provided.
43
42
  */
44
- declare const ShikiHighlighter: import("react").ForwardRefExoticComponent<ShikiHighlighterProps & import("react").RefAttributes<HTMLElement>>;
45
- //#endregion
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 };
47
- //# sourceMappingURL=core.d.mts.map
43
+ export declare const ShikiHighlighter: import("react").ForwardRefExoticComponent<ShikiHighlighterProps & import("react").RefAttributes<HTMLElement>>;
44
+ export { type Element, type EngineName, type HighlightCache, type HighlightResult, type HighlighterOptions, type HighlighterOptionsFor, type Language, type LanguageRegistration, type OutputFormat, type PreloadLanguage, ShikiHighlighter as default, type ShikiHighlighterProps, type Theme, type Themes, type TokensResult, type UseShikiHighlighter, createHighlighterCore, createJavaScriptRawEngine, createJavaScriptRegexEngine, createOnigurumaEngine, isInlineCode, rehypeInlineCodeProperty };
package/dist/core.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { i as useHighlight, n as isInlineCode, r as rehypeInlineCodeProperty, t as createShikiHighlighterComponent } from "./component-Cf8Topxy.mjs";
1
+ import { i as useHighlight, n as rehypeInlineCodeProperty, r as createShikiHighlighterComponent, t as isInlineCode } from "./plugins-C0Uf67_P.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";
5
- //#region src/bundles/core.ts
5
+ // src/bundles/core.ts
6
6
  /**
7
7
  * Validates that a highlighter is provided for the core bundle.
8
8
  * The core bundle requires users to provide their own highlighter instance.
@@ -11,8 +11,7 @@ function validateCoreHighlighter(highlighter) {
11
11
  if (!highlighter) throw new Error("react-shiki/core requires a custom highlighter. Use createHighlighterCore() from react-shiki or switch to react-shiki for plug-and-play usage.");
12
12
  return highlighter;
13
13
  }
14
- //#endregion
15
- //#region src/core.ts
14
+ // src/core.ts
16
15
  /**
17
16
  * Highlight code with shiki (core bundle)
18
17
  *
@@ -58,7 +57,6 @@ const useShikiHighlighter = (code, lang, themeInput, options = {}) => {
58
57
  * Requires a highlighter to be provided.
59
58
  */
60
59
  const ShikiHighlighter = /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);
61
- //#endregion
62
60
  export { ShikiHighlighter, ShikiHighlighter as default, createHighlighterCore, createJavaScriptRawEngine, createJavaScriptRegexEngine, createOnigurumaEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
63
61
 
64
62
  //# sourceMappingURL=core.mjs.map
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 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"}
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\n return highlighter;\n}\n","import { useHighlight } from './lib/hook';\nimport { validateCoreHighlighter } from './bundles/core';\nimport type { UseShikiHighlighter } from './lib/types';\nimport { createShikiHighlighterComponent } from './lib/component';\n// oxlint-disable-next-line unicorn/prefer-export-from -- `export type … from` here makes tsdown fold the core entry's declarations into the shared .d.mts chunk\nimport type { ShikiHighlighterProps } from './lib/component';\n\nexport { isInlineCode, rehypeInlineCodeProperty } from './lib/plugins';\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 HighlightCache,\n HighlightResult,\n OutputFormat,\n} from './lib/types';\n\nexport { createHighlighterCore } from 'shiki/core';\n\nexport { createOnigurumaEngine } from 'shiki/engine/oniguruma';\n\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 // oxlint-disable-next-line eslint/no-inline-comments -- the #__PURE__ annotation lets bundlers drop the component when only the hook is used\n /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);\n\nexport default ShikiHighlighter;\n"],"mappings":";;;;;;;;;AAMA,SAAgB,wBACd,aACiB;CACjB,IAAI,CAAC,aACH,MAAM,IAAI,MACR,gJAEF;CAGF,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,mBAEG,8CAAgC,mBAAmB"}
@@ -1,17 +1,16 @@
1
- import { a as isLoadableLanguage } from "./component-Cf8Topxy.mjs";
1
+ import { a as isLoadableLanguage } from "./plugins-C0Uf67_P.mjs";
2
2
  import { createOnigurumaEngine } from "shiki/engine/oniguruma";
3
- //#region src/bundles/factory.ts
3
+ // src/bundles/factory.ts
4
4
  /**
5
5
  * Builds a highlighter factory for a Shiki bundle (full or web).
6
6
  * Unloadable languages are filtered out so unknown ids fall back to
7
7
  * plaintext instead of throwing.
8
8
  */
9
- const bundledHighlighterFactory = (getSingletonHighlighter, bundledLanguages) => (langsToLoad, themesToLoad, engine) => getSingletonHighlighter({
9
+ const bundledHighlighterFactory = (getSingletonHighlighter, bundledLanguages) => async (langsToLoad, themesToLoad, engine) => await getSingletonHighlighter({
10
10
  langs: langsToLoad.filter((lang) => isLoadableLanguage(lang, bundledLanguages)),
11
11
  themes: themesToLoad,
12
12
  engine: engine ?? createOnigurumaEngine(import("shiki/wasm"))
13
13
  });
14
- //#endregion
15
14
  export { bundledHighlighterFactory as t };
16
15
 
17
- //# sourceMappingURL=factory-DySLHBEo.mjs.map
16
+ //# sourceMappingURL=factory-Ds5IsDw-.mjs.map
@@ -1 +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"}
1
+ {"version":3,"file":"factory-Ds5IsDw-.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 async (langsToLoad, themesToLoad, engine) =>\n await 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,qBAEF,OAAO,aAAa,cAAc,WAChC,MAAM,wBAAwB;CAC5B,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 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";
1
+ import { a as EngineName, c as HighlighterOptions, d as OutputFormat, f as PreloadLanguage, h as UseShikiHighlighter, i as Element, l as HighlighterOptionsFor, m as Themes, n as rehypeInlineCodeProperty, o as HighlightCache, p as Theme, r as ShikiHighlighterProps, s as HighlightResult, t as isInlineCode, u as Language } from "./plugins-DdjjMnbY.mjs";
2
2
  import { LanguageRegistration, TokensResult } from "shiki";
3
3
  import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/engine/javascript";
4
- //#region src/index.d.ts
5
4
  /**
6
5
  * Highlight code with shiki (full bundle)
7
6
  *
@@ -25,12 +24,10 @@ import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/en
25
24
  *
26
25
  * Full bundle (~6.4MB minified, 1.2MB gzipped). For smaller bundles: `react-shiki/web` or `react-shiki/core`
27
26
  */
28
- declare const useShikiHighlighter: UseShikiHighlighter;
27
+ export declare const useShikiHighlighter: UseShikiHighlighter;
29
28
  /**
30
29
  * ShikiHighlighter component using the full bundle.
31
30
  * Includes all languages and themes for maximum compatibility.
32
31
  */
33
- declare const ShikiHighlighter: import("react").ForwardRefExoticComponent<ShikiHighlighterProps & import("react").RefAttributes<HTMLElement>>;
34
- //#endregion
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 };
36
- //# sourceMappingURL=index.d.mts.map
32
+ export declare const ShikiHighlighter: import("react").ForwardRefExoticComponent<ShikiHighlighterProps & import("react").RefAttributes<HTMLElement>>;
33
+ export { type Element, type EngineName, type HighlightCache, type HighlightResult, type HighlighterOptions, type HighlighterOptionsFor, type Language, type LanguageRegistration, type OutputFormat, type PreloadLanguage, ShikiHighlighter as default, type ShikiHighlighterProps, type Theme, type Themes, type TokensResult, type UseShikiHighlighter, createJavaScriptRawEngine, createJavaScriptRegexEngine, isInlineCode, rehypeInlineCodeProperty };
package/dist/index.mjs CHANGED
@@ -1,15 +1,14 @@
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";
1
+ import { i as useHighlight, n as rehypeInlineCodeProperty, r as createShikiHighlighterComponent, t as isInlineCode } from "./plugins-C0Uf67_P.mjs";
2
+ import { t as bundledHighlighterFactory } from "./factory-Ds5IsDw-.mjs";
3
3
  import { bundledLanguages, getSingletonHighlighter } from "shiki";
4
4
  import { createJavaScriptRawEngine, createJavaScriptRegexEngine } from "shiki/engine/javascript";
5
- //#region src/bundles/full.ts
5
+ // src/bundles/full.ts
6
6
  /**
7
7
  * Highlighter factory for the full Shiki bundle: every language and
8
8
  * theme, largest size, maximum compatibility.
9
9
  */
10
10
  const createFullHighlighter = bundledHighlighterFactory(getSingletonHighlighter, bundledLanguages);
11
- //#endregion
12
- //#region src/index.ts
11
+ // src/index.ts
13
12
  /**
14
13
  * Highlight code with shiki (full bundle)
15
14
  *
@@ -39,7 +38,6 @@ const useShikiHighlighter = (code, lang, themeInput, options = {}) => useHighlig
39
38
  * Includes all languages and themes for maximum compatibility.
40
39
  */
41
40
  const ShikiHighlighter = /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);
42
- //#endregion
43
41
  export { ShikiHighlighter, ShikiHighlighter as default, createJavaScriptRawEngine, createJavaScriptRegexEngine, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
44
42
 
45
43
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/bundles/full.ts","../src/index.ts"],"sourcesContent":["import { getSingletonHighlighter, bundledLanguages } from 'shiki';\nimport { bundledHighlighterFactory } from './factory';\n\n/**\n * Highlighter factory for the full Shiki bundle: every language and\n * theme, largest size, maximum compatibility.\n */\nexport const createFullHighlighter = bundledHighlighterFactory(\n getSingletonHighlighter,\n bundledLanguages\n);\n","import { useHighlight } from './lib/hook';\nimport { createFullHighlighter } from './bundles/full';\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 {\n createJavaScriptRegexEngine,\n createJavaScriptRawEngine,\n} from 'shiki/engine/javascript';\n\nexport type { LanguageRegistration, TokensResult } from 'shiki';\n\n/**\n * Highlight code with shiki (full 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 * const highlighted = useShikiHighlighter(\n * 'const x = 1;',\n * 'typescript',\n * {\n * light: 'github-light',\n * dark: 'github-dark'\n * }\n * );\n * ```\n *\n * Full bundle (~6.4MB minified, 1.2MB gzipped). For smaller bundles: `react-shiki/web` or `react-shiki/core`\n */\nexport const useShikiHighlighter: UseShikiHighlighter = (\n code,\n lang,\n themeInput,\n options = {}\n) => useHighlight(code, lang, themeInput, options, createFullHighlighter);\n\n/**\n * ShikiHighlighter component using the full bundle.\n * Includes all languages and themes for maximum compatibility.\n */\nexport const ShikiHighlighter =\n /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);\nexport default ShikiHighlighter;\n"],"mappings":";;;;;;;;;AAOA,MAAa,wBAAwB,0BACnC,yBACA,gBACF;;;;;;;;;;;;;;;;;;;;;;;;;;AC+CA,MAAa,uBACX,MACA,MACA,YACA,UAAU,CAAC,MACR,aAAa,MAAM,MAAM,YAAY,SAAS,qBAAqB;;;;;AAMxE,MAAa,mBACG,8CAAgC,mBAAmB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/bundles/full.ts","../src/index.ts"],"sourcesContent":["import { getSingletonHighlighter, bundledLanguages } from 'shiki';\nimport { bundledHighlighterFactory } from './factory';\n\n/**\n * Highlighter factory for the full Shiki bundle: every language and\n * theme, largest size, maximum compatibility.\n */\nexport const createFullHighlighter = bundledHighlighterFactory(\n getSingletonHighlighter,\n bundledLanguages\n);\n","import { useHighlight } from './lib/hook';\nimport { createFullHighlighter } from './bundles/full';\nimport type { UseShikiHighlighter } from './lib/types';\nimport { createShikiHighlighterComponent } from './lib/component';\n// oxlint-disable-next-line unicorn/prefer-export-from -- `export type … from` here makes tsdown fold the core entry's declarations into the shared .d.mts chunk\nimport type { ShikiHighlighterProps } from './lib/component';\n\nexport { isInlineCode, rehypeInlineCodeProperty } from './lib/plugins';\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 HighlightCache,\n HighlightResult,\n OutputFormat,\n} from './lib/types';\n\nexport {\n createJavaScriptRegexEngine,\n createJavaScriptRawEngine,\n} from 'shiki/engine/javascript';\n\nexport type { LanguageRegistration, TokensResult } from 'shiki';\n\n/**\n * Highlight code with shiki (full 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 * const highlighted = useShikiHighlighter(\n * 'const x = 1;',\n * 'typescript',\n * {\n * light: 'github-light',\n * dark: 'github-dark'\n * }\n * );\n * ```\n *\n * Full bundle (~6.4MB minified, 1.2MB gzipped). For smaller bundles: `react-shiki/web` or `react-shiki/core`\n */\nexport const useShikiHighlighter: UseShikiHighlighter = (\n code,\n lang,\n themeInput,\n options = {}\n) => useHighlight(code, lang, themeInput, options, createFullHighlighter);\n\n/**\n * ShikiHighlighter component using the full bundle.\n * Includes all languages and themes for maximum compatibility.\n */\nexport const ShikiHighlighter =\n // oxlint-disable-next-line eslint/no-inline-comments -- the #__PURE__ annotation lets bundlers drop the component when only the hook is used\n /*#__PURE__*/ createShikiHighlighterComponent(useShikiHighlighter);\n\nexport default ShikiHighlighter;\n"],"mappings":";;;;;;;;;AAOA,MAAa,wBAAwB,0BACnC,yBACA,gBACF;;;;;;;;;;;;;;;;;;;;;;;;;AC8CA,MAAa,uBACX,MACA,MACA,YACA,UAAU,CAAC,MACR,aAAa,MAAM,MAAM,YAAY,SAAS,qBAAqB;;;;;AAMxE,MAAa,mBAEG,8CAAgC,mBAAmB"}
@@ -4,9 +4,9 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  import { toJsxRuntime } from "hast-util-to-jsx-runtime";
5
5
  import { dequal } from "dequal";
6
6
  import { guessEmbeddedLanguages, isSpecialLang } from "shiki/core";
7
- import { visit } from "unist-util-visit";
8
7
  import { clsx } from "clsx";
9
- //#region src/lib/utils.ts
8
+ import { visit } from "unist-util-visit";
9
+ // src/lib/utils.ts
10
10
  /**
11
11
  * Returns a referentially stable version of `value` that only updates when content changes.
12
12
  * Uses reference equality as a fast path and deep comparison to prevent unnecessary updates.
@@ -35,14 +35,11 @@ const throttleHighlighting = (performHighlight, timeoutControl, throttleMs) => {
35
35
  timeoutControl.current.nextAllowedTime = Date.now() + throttleMs;
36
36
  }, delay);
37
37
  };
38
- //#endregion
39
- //#region src/styles/component.css?inline
38
+ // src/styles/component.css?inline
40
39
  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
40
+ // src/styles/features.css?inline
43
41
  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
42
+ // src/lib/styles.ts
46
43
  const injected = /* @__PURE__ */ new Set();
47
44
  const useStyleInsertionEffect = React.useInsertionEffect ?? React.useLayoutEffect;
48
45
  const inject = (css, key) => {
@@ -71,10 +68,12 @@ const useFeatureStyles = (enabled) => {
71
68
  if (enabled) inject(features_default, "features");
72
69
  }, [enabled]);
73
70
  };
74
- //#endregion
75
- //#region src/lib/language.ts
71
+ // src/lib/language.ts
76
72
  const FALLBACK_LANGUAGE = "plaintext";
77
- const toArray = (value) => value == null ? [] : Array.isArray(value) ? value : [value];
73
+ const toArray = (value) => {
74
+ if (value == null) return [];
75
+ return Array.isArray(value) ? value : [value];
76
+ };
78
77
  const isDynamicLanguage = (lang) => typeof lang === "function" || lang instanceof Promise || Array.isArray(lang) || typeof lang === "object" && lang != null && "default" in lang;
79
78
  const isRegistration = (lang) => typeof lang === "object" && lang != null && !isDynamicLanguage(lang);
80
79
  /** Dedupe identity: strings and registrations by value, dynamic inputs by reference */
@@ -144,17 +143,15 @@ const getEmbeddedLanguages = (code, languageId, highlighter) => {
144
143
  const bundled = highlighter.getBundledLanguages();
145
144
  return guessEmbeddedLanguages(code, languageId).flatMap((language) => bundled[language] ?? []);
146
145
  };
147
- //#endregion
148
- //#region src/lib/theme.ts
146
+ // src/lib/theme.ts
149
147
  const DEFAULT_THEMES = {
150
148
  light: "github-light",
151
149
  dark: "github-dark"
152
150
  };
153
151
  const isTextmateTheme = (value) => {
154
152
  if (typeof value !== "object" || value === null) return false;
155
- const v = value;
156
- const hasTokens = Array.isArray(v.tokenColors) || Array.isArray(v.settings);
157
- const hasIdentity = typeof v.name === "string" || typeof v.type === "string";
153
+ const hasTokens = "tokenColors" in value && Array.isArray(value.tokenColors) || "settings" in value && Array.isArray(value.settings);
154
+ const hasIdentity = "name" in value && typeof value.name === "string" || "type" in value && typeof value.type === "string";
158
155
  return hasTokens && hasIdentity;
159
156
  };
160
157
  function resolveTheme(themeInput) {
@@ -179,12 +176,17 @@ function resolveTheme(themeInput) {
179
176
  themesToLoad: validEntries.map(([, value]) => value)
180
177
  };
181
178
  }
182
- //#endregion
183
- //#region src/lib/engine.ts
179
+ // src/lib/engine.ts
184
180
  const engines = /* @__PURE__ */ new Map();
185
181
  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")))
182
+ javascript: async () => {
183
+ const { createJavaScriptRegexEngine } = await import("shiki/engine/javascript");
184
+ return createJavaScriptRegexEngine();
185
+ },
186
+ oniguruma: async () => {
187
+ const { createOnigurumaEngine } = await import("shiki/engine/oniguruma");
188
+ return await createOnigurumaEngine(import("shiki/wasm"));
189
+ }
188
190
  };
189
191
  /**
190
192
  * Resolves a named engine to a lazily created, cached instance.
@@ -195,17 +197,15 @@ const loaders = {
195
197
  */
196
198
  const resolveEngine = (engine) => {
197
199
  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
+ if (!Object.hasOwn(loaders, engine)) throw new Error(`[react-shiki] unknown engine '${engine}', expected 'javascript' or 'oniguruma'`);
200
201
  const cached = engines.get(engine);
201
202
  if (cached) return cached;
202
- const instance = load();
203
+ const instance = loaders[engine]();
203
204
  instance.catch(() => engines.delete(engine));
204
205
  engines.set(engine, instance);
205
206
  return instance;
206
207
  };
207
- //#endregion
208
- //#region src/lib/transformers.ts
208
+ // src/lib/transformers.ts
209
209
  const toLineNumberSet = (lineNumbers) => new Set(lineNumbers.filter(Number.isInteger));
210
210
  /**
211
211
  * Creates a transformer that enables line numbers display
@@ -249,8 +249,7 @@ function highlightedLinesTransformer(lineNumbers, startLine = 1) {
249
249
  }
250
250
  };
251
251
  }
252
- //#endregion
253
- //#region src/lib/options.ts
252
+ // src/lib/options.ts
254
253
  const buildThemeOptions = (resolvedTheme, defaultColor, cssVariablePrefix) => {
255
254
  if (resolvedTheme.isMulti) return {
256
255
  themes: resolvedTheme.themes,
@@ -261,7 +260,7 @@ const buildThemeOptions = (resolvedTheme, defaultColor, cssVariablePrefix) => {
261
260
  };
262
261
  const buildShikiOptions = (languageId, resolvedTheme, options) => {
263
262
  const { delay, customLanguages, preloadLanguages, outputFormat, highlighter, langAlias, engine, defaultColor, cssVariablePrefix, showLineNumbers, startingLineNumber, highlightLineNumbers, transformers: userTransformers, ...shikiPassthrough } = options;
264
- const transformers = [...userTransformers || []];
263
+ const transformers = [...userTransformers ?? []];
265
264
  if (showLineNumbers) transformers.push(lineNumbersTransformer(startingLineNumber));
266
265
  if (highlightLineNumbers?.length) transformers.push(highlightedLinesTransformer(highlightLineNumbers, startingLineNumber));
267
266
  return {
@@ -271,8 +270,7 @@ const buildShikiOptions = (languageId, resolvedTheme, options) => {
271
270
  transformers
272
271
  };
273
272
  };
274
- //#endregion
275
- //#region src/lib/hook.ts
273
+ // src/lib/hook.ts
276
274
  async function highlight(code, resolved, opts, factory) {
277
275
  const { languageId, langsToLoad, themesToLoad, shikiOptions } = resolved;
278
276
  const format = opts.outputFormat ?? "react";
@@ -297,12 +295,19 @@ async function highlight(code, resolved, opts, factory) {
297
295
  };
298
296
  return (outputs[format] ?? outputs.react)();
299
297
  }
300
- const useHighlight = (code, lang, themeInput, options = {}, highlighterFactory) => {
301
- const [highlightedCode, setHighlightedCode] = useState(null);
302
- useFeatureStyles(Boolean(options.showLineNumbers || options.highlightLineNumbers?.length));
298
+ const readCache = (cache, key) => {
299
+ if (!key) return null;
300
+ const cached = cache?.get(key);
301
+ return cached === void 0 || cached === "" ? null : cached;
302
+ };
303
+ const useHighlight = (code, lang, themeInput, optionsInput, highlighterFactory) => {
304
+ const { cache, ...rest } = optionsInput ?? {};
305
+ const cacheRef = useRef(cache);
306
+ cacheRef.current = cache;
307
+ useFeatureStyles(Boolean(rest.showLineNumbers || rest.highlightLineNumbers?.length));
303
308
  const stableLang = useStableValue(lang);
304
309
  const stableTheme = useStableValue(themeInput);
305
- const stableOpts = useStableValue(options);
310
+ const stableOpts = useStableValue(rest);
306
311
  const resolved = useMemo(() => {
307
312
  const { languageId, langsToLoad } = resolveLanguage(stableLang, stableOpts.customLanguages, stableOpts.langAlias, stableOpts.preloadLanguages);
308
313
  const theme = resolveTheme(stableTheme);
@@ -318,6 +323,27 @@ const useHighlight = (code, lang, themeInput, options = {}, highlighterFactory)
318
323
  stableTheme,
319
324
  stableOpts
320
325
  ]);
326
+ const hasCache = Boolean(cache);
327
+ const cacheScope = useMemo(() => hasCache ? JSON.stringify([
328
+ stableOpts.outputFormat ?? "react",
329
+ resolved.shikiOptions,
330
+ stableOpts.startingLineNumber,
331
+ stableOpts.highlightLineNumbers
332
+ ]) : void 0, [
333
+ hasCache,
334
+ resolved,
335
+ stableOpts
336
+ ]);
337
+ const cacheKey = cacheScope && `${cacheScope}\n${code}`;
338
+ const [highlightedCode, setHighlightedCode] = useState(() => readCache(cache, cacheKey));
339
+ const shown = useRef({
340
+ key: cacheKey,
341
+ result: highlightedCode
342
+ });
343
+ useEffect(() => () => {
344
+ const { key, result } = shown.current;
345
+ if (key && result !== null && result !== "") cacheRef.current?.set(key, result);
346
+ }, []);
321
347
  const requestIdRef = useRef(0);
322
348
  const timeoutControl = useRef({
323
349
  nextAllowedTime: 0,
@@ -327,29 +353,85 @@ const useHighlight = (code, lang, themeInput, options = {}, highlighterFactory)
327
353
  highlighterFactoryRef.current = highlighterFactory;
328
354
  useEffect(() => {
329
355
  const requestId = ++requestIdRef.current;
330
- if (!resolved.languageId) return;
356
+ const timeouts = timeoutControl.current;
357
+ const show = (result) => {
358
+ shown.current = {
359
+ key: cacheKey,
360
+ result
361
+ };
362
+ setHighlightedCode(result);
363
+ };
331
364
  const run = async () => {
332
365
  try {
333
366
  const result = await highlight(code, resolved, stableOpts, highlighterFactoryRef.current);
334
- if (requestId === requestIdRef.current) setHighlightedCode(result);
367
+ if (requestId === requestIdRef.current) show(result);
335
368
  } catch (error) {
336
369
  console.error("[react-shiki] highlight failed", error);
337
370
  }
338
371
  };
339
- if (stableOpts.delay) throttleHighlighting(run, timeoutControl, stableOpts.delay);
372
+ const cached = readCache(cacheRef.current, cacheKey);
373
+ if (!resolved.languageId) return () => {
374
+ clearTimeout(timeouts.timeoutId);
375
+ };
376
+ if (cached !== null) {
377
+ if (shown.current.result !== cached) show(cached);
378
+ } else if (stableOpts.delay) throttleHighlighting(run, timeoutControl, stableOpts.delay);
340
379
  else run();
341
380
  return () => {
342
- clearTimeout(timeoutControl.current.timeoutId);
381
+ clearTimeout(timeouts.timeoutId);
343
382
  };
344
383
  }, [
345
384
  code,
385
+ cacheKey,
346
386
  resolved,
347
387
  stableOpts
348
388
  ]);
349
389
  return highlightedCode;
350
390
  };
351
- //#endregion
352
- //#region src/lib/plugins.ts
391
+ // src/lib/component.tsx
392
+ let warnedTokensOutputFormat = false;
393
+ /**
394
+ * The component's props exclude `outputFormat: 'tokens'`, but plain-JS
395
+ * callers can still pass it. Tokens are not renderable React children,
396
+ * so fall back to 'react' instead of crashing the render.
397
+ */
398
+ const resolveOutputFormat = (outputFormat) => {
399
+ if (outputFormat !== "tokens") return outputFormat;
400
+ if (!warnedTokensOutputFormat) {
401
+ warnedTokensOutputFormat = true;
402
+ console.warn("[react-shiki] outputFormat 'tokens' is only supported by the useShikiHighlighter hook, falling back to 'react'");
403
+ }
404
+ return "react";
405
+ };
406
+ /**
407
+ * Base ShikiHighlighter component factory.
408
+ * This creates a component that uses the provided hook implementation.
409
+ */
410
+ const createShikiHighlighterComponent = (useShikiHighlighterImpl) => forwardRef(({ language, theme, addDefaultStyles = true, style, langStyle, className, langClassName, showLanguage = true, children: code, as: Element = "div", outputFormat, ...options }, ref) => {
411
+ useComponentStyles();
412
+ const displayLanguageId = typeof language === "object" ? language.name || null : language?.trim() || null;
413
+ const highlightedCode = useShikiHighlighterImpl(code, language, theme, {
414
+ ...options,
415
+ outputFormat: resolveOutputFormat(outputFormat)
416
+ });
417
+ return /* @__PURE__ */ jsxs(Element, {
418
+ ref,
419
+ "data-testid": "shiki-container",
420
+ "data-slot": "container",
421
+ className: clsx("rs-root", "not-prose", addDefaultStyles && "rs-default-styles", className),
422
+ style,
423
+ children: [showLanguage && displayLanguageId ? /* @__PURE__ */ jsx("span", {
424
+ "data-slot": "language-label",
425
+ className: clsx("rs-language-label", langClassName),
426
+ style: langStyle,
427
+ children: displayLanguageId
428
+ }) : null, typeof highlightedCode === "string" ? /* @__PURE__ */ jsx("div", {
429
+ "data-slot": "content",
430
+ dangerouslySetInnerHTML: { __html: highlightedCode }
431
+ }) : highlightedCode]
432
+ });
433
+ });
434
+ // src/lib/plugins.ts
353
435
  /**
354
436
  * Rehype plugin to add an 'inline' property to <code> elements
355
437
  * Sets 'inline' property to true if the <code> is not within a <pre> tag
@@ -374,55 +456,8 @@ function rehypeInlineCodeProperty() {
374
456
  * const isInline = node && isInlineCode(node: Element)
375
457
  */
376
458
  const isInlineCode = (node) => {
377
- return !(node.children || []).filter((child) => child.type === "text").map((child) => child.value).join("").includes("\n");
378
- };
379
- //#endregion
380
- //#region src/lib/component.tsx
381
- let warnedTokensOutputFormat = false;
382
- /**
383
- * The component's props exclude `outputFormat: 'tokens'`, but plain-JS
384
- * callers can still pass it. Tokens are not renderable React children,
385
- * so fall back to 'react' instead of crashing the render.
386
- */
387
- const resolveOutputFormat = (outputFormat) => {
388
- if (outputFormat !== "tokens") return outputFormat;
389
- if (!warnedTokensOutputFormat) {
390
- warnedTokensOutputFormat = true;
391
- console.warn("[react-shiki] outputFormat 'tokens' is only supported by the useShikiHighlighter hook, falling back to 'react'");
392
- }
393
- return "react";
394
- };
395
- /**
396
- * Base ShikiHighlighter component factory.
397
- * This creates a component that uses the provided hook implementation.
398
- */
399
- const createShikiHighlighterComponent = (useShikiHighlighterImpl) => {
400
- return forwardRef(({ language, theme, addDefaultStyles = true, style, langStyle, className, langClassName, showLanguage = true, children: code, as: Element = "div", outputFormat, ...options }, ref) => {
401
- useComponentStyles();
402
- const displayLanguageId = typeof language === "object" ? language.name || null : language?.trim() || null;
403
- const highlightedCode = useShikiHighlighterImpl(code, language, theme, {
404
- ...options,
405
- outputFormat: resolveOutputFormat(outputFormat)
406
- });
407
- return /* @__PURE__ */ jsxs(Element, {
408
- ref,
409
- "data-testid": "shiki-container",
410
- "data-slot": "container",
411
- className: clsx("rs-root", "not-prose", addDefaultStyles && "rs-default-styles", className),
412
- style,
413
- children: [showLanguage && displayLanguageId ? /* @__PURE__ */ jsx("span", {
414
- "data-slot": "language-label",
415
- className: clsx("rs-language-label", langClassName),
416
- style: langStyle,
417
- children: displayLanguageId
418
- }) : null, typeof highlightedCode === "string" ? /* @__PURE__ */ jsx("div", {
419
- "data-slot": "content",
420
- dangerouslySetInnerHTML: { __html: highlightedCode }
421
- }) : highlightedCode]
422
- });
423
- });
459
+ return !(node.children ?? []).filter((child) => child.type === "text").map((child) => child.value).join("").includes("\n");
424
460
  };
425
- //#endregion
426
- export { isLoadableLanguage as a, useHighlight as i, isInlineCode as n, rehypeInlineCodeProperty as r, createShikiHighlighterComponent as t };
461
+ export { isLoadableLanguage as a, useHighlight as i, rehypeInlineCodeProperty as n, createShikiHighlighterComponent as r, isInlineCode as t };
427
462
 
428
- //# sourceMappingURL=component-Cf8Topxy.mjs.map
463
+ //# sourceMappingURL=plugins-C0Uf67_P.mjs.map