react-shiki 0.5.0 → 0.5.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 CHANGED
@@ -14,7 +14,8 @@ A performant client-side syntax highlighting component and hook for React, built
14
14
  - [Features](#features)
15
15
  - [Installation](#installation)
16
16
  - [Usage](#usage)
17
- - [Basic Usage](#basic-usage)
17
+ - [Common Configuration Options](#common-configuration-options)
18
+ - [Component-specific Props](#component-specific-props)
18
19
  - [Integration with react-markdown](#integration-with-react-markdown)
19
20
  - [Handling Inline Code](#handling-inline-code)
20
21
  - [Multi-theme Support](#multi-theme-support)
@@ -22,10 +23,10 @@ A performant client-side syntax highlighting component and hook for React, built
22
23
  - [Custom Languages](#custom-languages)
23
24
  - [Preloading Custom Languages](#preloading-custom-languages)
24
25
  - [Custom Transformers](#custom-transformers)
25
- - [Performance](#performance)
26
- - [Throttling Real-time Highlighting](#throttling-real-time-highlighting)
27
- - [Streaming and LLM Chat UI](#streaming-and-llm-chat-ui)
28
- <!--toc:end-->
26
+ - [Performance](#performance)
27
+ - [Throttling Real-time Highlighting](#throttling-real-time-highlighting)
28
+ - [Streaming and LLM Chat UI](#streaming-and-llm-chat-ui)
29
+ <!--toc:end-->
29
30
 
30
31
  ## Features
31
32
 
@@ -44,19 +45,17 @@ A performant client-side syntax highlighting component and hook for React, built
44
45
  ## Installation
45
46
 
46
47
  ```bash
47
- npm install react-shiki
48
+ npm i react-shiki
48
49
  ```
49
50
 
50
51
  ## Usage
51
52
 
52
- ### Basic Usage
53
-
54
53
  You can use either the `ShikiHighlighter` component or the `useShikiHighlighter` hook to highlight code.
55
54
 
56
55
  **Using the Component:**
57
56
 
58
57
  ```tsx
59
- import { ShikiHighlighter } from 'react-shiki';
58
+ import { ShikiHighlighter } from "react-shiki";
60
59
 
61
60
  function CodeBlock() {
62
61
  return (
@@ -67,57 +66,49 @@ function CodeBlock() {
67
66
  }
68
67
  ```
69
68
 
70
- The `ShikiHighlighter` component accepts the following props:
71
-
72
- | Prop | Type | Default | Description |
73
- |------|------|---------|-------------|
74
- | `language` | `string` | - | Language of the code to highlight |
75
- | `theme` | `string \| object` | 'github-dark' | Shiki theme to use |
76
- | `showLanguage` | `boolean` | true | Shows the language name in the top right corner |
77
- | `addDefaultStyles` | `boolean` | true | Adds default styling to the code block |
78
- | `as` | `string` | 'pre' | Root element to render |
79
- | `delay` | `number` | 0 | Delay between highlights in milliseconds |
80
- | `customLanguages` | `array` | - | Custom languages to preload |
81
- | `transformers` | `array` | - | Custom Shiki transformers |
82
- | `className` | `string` | - | Custom class names for the component |
83
- | `langClassName` | `string` | - | Class names for the language label |
84
- | `style` | `object` | - | Inline style object for the component |
85
- | `langStyle` | `object` | - | Inline style object for the language label |
86
-
87
-
88
69
  **Using the Hook:**
89
70
 
90
71
  ```tsx
91
- import { useShikiHighlighter } from 'react-shiki';
72
+ import { useShikiHighlighter } from "react-shiki";
73
+
74
+ function CodeBlock({ code, language }) {
75
+ const highlightedCode = useShikiHighlighter(code, language, "github-dark");
92
76
 
93
- function CustomCodeBlock({ code, language }) {
94
- const highlightedCode = useShikiHighlighter(code, language, 'github-dark');
95
-
96
- return <div className="custom-code-block">{highlightedCode}</div>;
77
+ return <div className="code-block">{highlightedCode}</div>;
97
78
  }
98
79
  ```
99
80
 
100
- **The hook accepts the following parameters:**
101
-
102
- | Param | Type | Description |
103
- |------|------|---------|
104
- | `code` | `string` | The code to be highlighted |
105
- | `language` | `string \| object` | The language for highlighting |
106
- | `themeInput` | `string \| object` | The theme or themes to be used for highlighting |
107
- | `options` | `object` | Optional configuration options |
108
-
109
- **`options`:**
110
- | Param | Type | Default | Description |
111
- |------|------|---------|-------------|
112
- | `delay` | `number` | `0` (disabled) | The delay between highlights in milliseconds |
113
- | `transformers` | `array` | `[]` | Transformers for the Shiki pipeline |
114
- | `customLanguages` | `array` | `[]` | Custom languages to preload |
115
- | `cssVariablePrefix` | `string` | `'--shiki'` | Prefix of CSS variables used to store theme colors |
116
- | `defaultColor` | `string` | `'light'` | The default theme mode when using multiple themes. Can be set to `false` to disable the default theme |
81
+ ### Common Configuration Options
82
+
83
+ | Option | Type | Default | Description |
84
+ | ------------------- | ------------------ | --------------- | ------------------------------------------------------------------------- |
85
+ | `code` | `string` | - | Code to highlight |
86
+ | `language` | `string \| object` | - | Language to highlight, built-in or custom textmate grammer object |
87
+ | `theme` | `string \| object` | `'github-dark'` | Single or multi-theme configuration, built-in or custom textmate theme object |
88
+ | `delay` | `number` | `0` | Delay between highlights (in milliseconds) |
89
+ | `transformers` | `array` | `[]` | Custom Shiki transformers for modifying the highlighting output |
90
+ | `customLanguages` | `array` | `[]` | Array of custom languages to preload |
91
+ | `cssVariablePrefix` | `string` | `'--shiki'` | Prefix for CSS variables storing theme colors |
92
+ | `defaultColor` | `string \| false` | `'light'` | Default theme mode when using multiple themes, can also disable default theme |
93
+
94
+ ### Component-specific Props
95
+
96
+ The `ShikiHighlighter` component offers minimal built-in styling and customization options out-of-the-box:
97
+
98
+ | Prop | Type | Default | Description |
99
+ | ------------------ | --------- | ------- | ---------------------------------------------------------- |
100
+ | `showLanguage` | `boolean` | `true` | Displays language label in top-right corner |
101
+ | `addDefaultStyles` | `boolean` | `true` | Adds minimal default styling to the highlighted code block |
102
+ | `as` | `string` | `'pre'` | Component's Root HTML element |
103
+ | `className` | `string` | - | Custom class name for the code block |
104
+ | `langClassName` | `string` | - | Class name for styling the language label |
105
+ | `style` | `object` | - | Inline style object for the code block |
106
+ | `langStyle` | `object` | - | Inline style object for the language label |
117
107
 
118
108
  ### Integration with react-markdown
119
109
 
120
110
  Create a component to handle syntax highlighting:
111
+
121
112
  ```tsx
122
113
  import ReactMarkdown from "react-markdown";
123
114
  import { ShikiHighlighter, isInlineCode } from "react-shiki";
@@ -141,6 +132,7 @@ const CodeHighlight = ({ className, children, node, ...props }) => {
141
132
  ```
142
133
 
143
134
  Pass the component to react-markdown as a code component:
135
+
144
136
  ```tsx
145
137
  <ReactMarkdown
146
138
  components={{
@@ -251,10 +243,10 @@ Or, when using the hook, pass it to the `theme` parameter:
251
243
  const highlightedCode = useShikiHighlighter(
252
244
  code,
253
245
  "tsx",
254
- {
246
+ {
255
247
  light: "github-light",
256
248
  dark: "github-dark",
257
- dim: "github-dark-dimmed"
249
+ dim: "github-dark-dimmed",
258
250
  },
259
251
  {
260
252
  defaultColor: "dark",
@@ -265,7 +257,7 @@ const highlightedCode = useShikiHighlighter(
265
257
  See [shiki's documentation](https://shiki.matsu.io/docs/themes) for more information on dual and multi theme support, and for the CSS needed to make the themes reactive to your site's theme.
266
258
 
267
259
  ### Custom Themes
268
-
260
+
269
261
  Custom themes can be passed as a TextMate theme in JavaScript object. For example, [it should look like this](https://github.com/antfu/textmate-grammars-themes/blob/main/packages/tm-themes/themes/dark-plus.json).
270
262
 
271
263
  ```tsx
package/dist/index.d.ts CHANGED
@@ -69,7 +69,7 @@ type Themes = {
69
69
  [key: string]: ThemeRegistrationAny | StringLiteralUnion<BundledTheme>;
70
70
  };
71
71
  /**
72
- * Configuration options for the syntax highlighter
72
+ * Configuration options specific to react-shiki
73
73
  */
74
74
  type ReactShikiOptions = {
75
75
  /**
@@ -82,6 +82,9 @@ type ReactShikiOptions = {
82
82
  */
83
83
  customLanguages?: LanguageRegistration | LanguageRegistration[];
84
84
  };
85
+ /**
86
+ * Configuration options for the syntax highlighter
87
+ */
85
88
  type HighlighterOptions = ReactShikiOptions & Pick<CodeOptionsMultipleThemes<BundledTheme>, 'defaultColor' | 'cssVariablePrefix'> & Pick<CodeToHastOptionsCommon, 'transformers'>;
86
89
 
87
90
  /**
@@ -226,4 +229,4 @@ declare function rehypeInlineCodeProperty(): (tree: any) => undefined;
226
229
  */
227
230
  declare const isInlineCode: (node: Element) => boolean;
228
231
 
229
- export { ShikiHighlighter as default, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
232
+ export { type HighlighterOptions, type Language, type Theme, type Themes, ShikiHighlighter as default, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  function v(e,{insertAt:o}={}){if(!e||typeof document>"u")return;let i=document.head||document.getElementsByTagName("head")[0],t=document.createElement("style");t.type="text/css",o==="top"&&i.firstChild?i.insertBefore(t,i.firstChild):i.appendChild(t),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document.createTextNode(e))}v(`.relative{position:relative}.defaultStyles pre{overflow:auto;border-radius:.5rem;padding:1.25rem 1.5rem}.languageLabel{position:absolute;right:.75rem;top:.5rem;font-family:monospace;font-size:.75rem;letter-spacing:-.05em;color:#6b7280d9}
2
2
  `);import A from"react";import{clsx as N}from"clsx";import{useEffect as V,useMemo as O,useRef as _,useState as U}from"react";import q from"html-react-parser";import{createHighlighter as w,createSingletonShorthands as G}from"shiki";import{visit as $}from"unist-util-visit";import{bundledLanguages as z,isSpecialLang as D}from"shiki";function F(){return e=>{$(e,"element",(o,i,t)=>{o.tagName==="code"&&t.tagName!=="pre"&&(o.properties.inline=!0)})}}var B=e=>!(e.children||[]).filter(i=>i.type==="text").map(i=>i.value).join("").includes(`
3
- `),k={pre(e){return"properties"in e&&(e.properties.tabindex="-1"),e}},E=(e,o,i)=>{let t=Date.now();clearTimeout(o.current.timeoutId);let r=Math.max(0,o.current.nextAllowedTime-t);o.current.timeoutId=setTimeout(()=>{e().catch(console.error),o.current.nextAllowedTime=t+i},r)},f=(e,o=[])=>{if(e&&typeof e=="object")return{isCustom:!0,languageId:e.name,displayLanguageId:e.name,resolvedLanguage:e};if(typeof e=="string"){let i=e;if(e in z||D(e))return{isCustom:!1,languageId:e,displayLanguageId:i};let t=o.find(r=>r.fileTypes?.includes(e)||r.scopeName?.split(".")[1]===e||r.name?.toLowerCase()===e.toLowerCase());return t?{isCustom:!0,languageId:t.name,displayLanguageId:i,resolvedLanguage:t}:{isCustom:!1,languageId:"plaintext",displayLanguageId:i}}return{isCustom:!1,languageId:"plaintext",displayLanguageId:"plaintext"}};function I(e){let o=typeof e=="object"&&"tokenColors"in e&&Array.isArray(e.tokenColors),i=typeof e=="object"&&e!==null&&!o,t=typeof e=="object"&&e!==null&&!o&&Object.entries(e).some(([r,s])=>r&&s&&r.trim()!==""&&s!==""&&(typeof s=="string"||o));return i?{isMultiTheme:!0,themeId:t?`multi-${Object.values(e).map(s=>(typeof s=="string"?s:s?.name)||"custom").sort().join("-")}`:"multi-default",multiTheme:t?e:null,themesToLoad:t?Object.values(e):[]}:{isMultiTheme:!1,themeId:typeof e=="string"?e:e?.name||"custom",singleTheme:e,themesToLoad:[e]}}var M={light:"github-light",dark:"github-dark"},J=G(w),j=new Map,K=async(e,o,i)=>{let t=j.get(e);return t||(t=w({langs:[o],themes:i}),j.set(e,t)),t},R=(e,o,i,t={})=>{let[r,s]=U(null),g=t.customLanguages?Array.isArray(t.customLanguages)?t.customLanguages:[t.customLanguages]:[],u=g.map(n=>n.name||"").sort().join("-"),h=O(()=>[k,...t.transformers||[]],[t.transformers]),{isMultiTheme:y,themeId:d,multiTheme:T,singleTheme:L,themesToLoad:C}=O(()=>I(i),[i]),{isCustom:a,languageId:m,resolvedLanguage:c}=O(()=>f(o,g),[o,u]),x=`${m}-${d}`,p=_({nextAllowedTime:0,timeoutId:void 0}),S=()=>{let{defaultColor:n,cssVariablePrefix:l}=t,b={lang:m,transformers:h},H=y?{themes:T||M,defaultColor:n,cssVariablePrefix:l}:{theme:L||M.dark};return{...b,...H}};return V(()=>{let n=!0,l=async()=>{let b=a&&c?await K(x,c,C):J,H=S(),P=await b.codeToHtml(e,H);n&&s(q(P))};return t.delay?E(l,p,t.delay):l().catch(console.error),()=>{n=!1,clearTimeout(p.current.timeoutId)}},[e,m,d,u,h,t.delay,t.defaultColor,t.cssVariablePrefix]),r};var Q=({language:e,theme:o,delay:i,transformers:t,defaultColor:r,cssVariablePrefix:s,addDefaultStyles:g=!0,style:u,langStyle:h,className:y,langClassName:d,showLanguage:T=!0,children:L,as:C="pre",customLanguages:a})=>{let m={delay:i,transformers:t,customLanguages:a,defaultColor:r,cssVariablePrefix:s},c=a?Array.isArray(a)?a:[a]:[],{isCustom:x,languageId:p,displayLanguageId:S,resolvedLanguage:n}=f(e,c),l=R(L,e,o,m);return A.createElement(C,{"data-testid":"shiki-container",className:N("relative","not-prose",g&&"defaultStyles",y),style:u,id:"shiki-container"},T&&e?A.createElement("span",{className:N("languageLabel",d),style:h,id:"language-label"},x?`${n?.scopeName.split(".")[1]}`:S||p):null,l)};export{Q as default,B as isInlineCode,F as rehypeInlineCodeProperty,R as useShikiHighlighter};
3
+ `),k={pre(e){return"properties"in e&&(e.properties.tabindex="-1"),e}},E=(e,o,i)=>{let t=Date.now();clearTimeout(o.current.timeoutId);let r=Math.max(0,o.current.nextAllowedTime-t);o.current.timeoutId=setTimeout(()=>{e().catch(console.error),o.current.nextAllowedTime=t+i},r)},f=(e,o=[])=>{if(e&&typeof e=="object")return{isCustom:!0,languageId:e.name,displayLanguageId:e.name,resolvedLanguage:e};if(typeof e=="string"){let i=e;if(e in z||D(e))return{isCustom:!1,languageId:e,displayLanguageId:i};let t=o.find(r=>r.fileTypes?.includes(e)||r.scopeName?.split(".")[1]===e||r.name?.toLowerCase()===e.toLowerCase());return t?{isCustom:!0,languageId:t.name,displayLanguageId:i,resolvedLanguage:t}:{isCustom:!1,languageId:"plaintext",displayLanguageId:i}}return{isCustom:!1,languageId:"plaintext",displayLanguageId:"plaintext"}};function I(e){let o=typeof e=="object"&&"tokenColors"in e&&Array.isArray(e.tokenColors),i=typeof e=="object"&&e!==null&&!o,t=typeof e=="object"&&e!==null&&!o&&Object.entries(e).some(([r,s])=>r&&s&&r.trim()!==""&&s!==""&&(typeof s=="string"||o));return i?{isMultiTheme:!0,themeId:t?`multi-${Object.values(e).map(s=>(typeof s=="string"?s:s?.name)||"custom").sort().join("-")}`:"multi-default",multiTheme:t?e:null,themesToLoad:t?Object.values(e):[]}:{isMultiTheme:!1,themeId:typeof e=="string"?e:e?.name||"custom",singleTheme:e,themesToLoad:[e]}}var M={light:"github-light",dark:"github-dark"},J=G(w),j=new Map,K=async(e,o,i)=>{let t=j.get(e);return t||(t=w({langs:[o],themes:i}),j.set(e,t)),t},R=(e,o,i,t={})=>{let[r,s]=U(null),m=t.customLanguages?Array.isArray(t.customLanguages)?t.customLanguages:[t.customLanguages]:[],u=m.map(n=>n.name||"").sort().join("-"),h=O(()=>[k,...t.transformers||[]],[t.transformers]),{isMultiTheme:y,themeId:d,multiTheme:T,singleTheme:L,themesToLoad:C}=O(()=>I(i),[i]),{isCustom:a,languageId:g,resolvedLanguage:c}=O(()=>f(o,m),[o,u]),x=`${g}-${d}`,p=_({nextAllowedTime:0,timeoutId:void 0}),S=()=>{let{defaultColor:n,cssVariablePrefix:l}=t,b={lang:g,transformers:h},H=y?{themes:T||M,defaultColor:n,cssVariablePrefix:l}:{theme:L||M.dark};return{...b,...H}};return V(()=>{let n=!0,l=async()=>{let b=a&&c?await K(x,c,C):J,H=S(),P=await b.codeToHtml(e,H);n&&s(q(P))};return t.delay?E(l,p,t.delay):l().catch(console.error),()=>{n=!1,clearTimeout(p.current.timeoutId)}},[e,g,d,u,h,t.delay,t.defaultColor,t.cssVariablePrefix]),r};var Q=({language:e,theme:o,delay:i,transformers:t,defaultColor:r,cssVariablePrefix:s,addDefaultStyles:m=!0,style:u,langStyle:h,className:y,langClassName:d,showLanguage:T=!0,children:L,as:C="pre",customLanguages:a})=>{let g={delay:i,transformers:t,customLanguages:a,defaultColor:r,cssVariablePrefix:s},c=a?Array.isArray(a)?a:[a]:[],{isCustom:x,languageId:p,displayLanguageId:S,resolvedLanguage:n}=f(e,c),l=R(L,e,o,g);return A.createElement(C,{"data-testid":"shiki-container",className:N("relative","not-prose",m&&"defaultStyles",y),style:u,id:"shiki-container"},T&&e?A.createElement("span",{className:N("languageLabel",d),style:h,id:"language-label"},x?`${n?.scopeName.split(".")[1]}`:S||p):null,l)};export{Q as default,B as isInlineCode,F as rehypeInlineCodeProperty,R as useShikiHighlighter};
4
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["#style-inject:#style-inject","../src/styles.css","../src/ShikiHighlighter.tsx","../src/useShiki.ts","../src/utils.ts"],"sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".relative{position:relative}.defaultStyles pre{overflow:auto;border-radius:.5rem;padding:1.25rem 1.5rem}.languageLabel{position:absolute;right:.75rem;top:.5rem;font-family:monospace;font-size:.75rem;letter-spacing:-.05em;color:#6b7280d9}\\n\")","import './styles.css';\n// biome-ignore lint/style/useImportType: React import is needed\nimport React from 'react';\nimport { clsx } from 'clsx';\nimport { useShikiHighlighter } from './useShiki';\nimport type {\n Language,\n Theme,\n HighlighterOptions,\n Themes,\n} from './types';\nimport { resolveLanguage } from './utils';\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 'pre'\n */\n as?: React.ElementType;\n}\n/**\n * ShikiHighlighter is a React component that provides syntax highlighting for code snippets.\n * It uses Shiki to render beautiful, theme-based syntax highlighting with optimized performance.\n *\n * @example\n * ```tsx\n * <ShikiHighlighter\n * language=\"typescript\"\n * theme=\"github-dark\"\n * delay={100}\n * transformers={[customTransformer]}\n * addDefaultStyles={false}\n * className=\"code-block\"\n * langClassName=\"lang-label\"\n * langStyle={{ color: 'blue' }},\n * style={{ fontSize: '1.2rem' }}\n * >\n * {code}\n * </ShikiHighlighter>\n * ```\n */\nexport const ShikiHighlighter = ({\n language,\n theme,\n delay,\n transformers,\n defaultColor,\n cssVariablePrefix,\n addDefaultStyles = true,\n style,\n langStyle,\n className,\n langClassName,\n showLanguage = true,\n children: code,\n as: Element = 'pre',\n customLanguages,\n}: ShikiHighlighterProps): React.ReactElement => {\n const options: HighlighterOptions = {\n delay,\n transformers,\n customLanguages,\n defaultColor,\n cssVariablePrefix,\n };\n\n const normalizedCustomLanguages = customLanguages\n ? Array.isArray(customLanguages)\n ? customLanguages\n : [customLanguages]\n : [];\n\n const { isCustom, languageId, displayLanguageId, resolvedLanguage } =\n resolveLanguage(language, normalizedCustomLanguages);\n\n const highlightedCode = useShikiHighlighter(\n code,\n language,\n theme,\n options\n );\n\n return (\n <Element\n data-testid=\"shiki-container\"\n className={clsx(\n 'relative',\n 'not-prose',\n addDefaultStyles && 'defaultStyles',\n className\n )}\n style={style}\n id=\"shiki-container\"\n >\n {showLanguage && language ? (\n <span\n className={clsx('languageLabel', langClassName)}\n style={langStyle}\n id=\"language-label\"\n >\n {isCustom\n ? `${resolvedLanguage?.scopeName.split('.')[1]}`\n : displayLanguageId || languageId}\n </span>\n ) : null}\n {highlightedCode}\n </Element>\n );\n};\n","import {\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\n\nimport parse from 'html-react-parser';\n\nimport {\n createHighlighter,\n createSingletonShorthands,\n type Highlighter,\n type CodeToHastOptions,\n type CodeOptionsSingleTheme,\n type CodeOptionsMultipleThemes,\n} from 'shiki';\n\nimport type {\n LanguageRegistration,\n ShikiLanguageRegistration,\n} from './customTypes';\n\nimport type {\n Language,\n Theme,\n HighlighterOptions,\n TimeoutState,\n Themes,\n} from './types';\n\nimport {\n removeTabIndexFromPre,\n throttleHighlighting,\n resolveLanguage,\n resolveTheme,\n} from './utils';\n\nconst DEFAULT_THEMES = {\n light: 'github-light',\n dark: 'github-dark',\n};\n\n// Use Shiki managed singleton for bundled languages, create and cache a fresh instance for custom languages\nconst bundledHighlighter = createSingletonShorthands(createHighlighter);\nconst customLangHighlighter = new Map<string, Promise<Highlighter>>();\n\nconst getCachedCustomHighlighter = async (\n cacheKey: string,\n customLang: LanguageRegistration,\n themesToLoad: Theme[]\n) => {\n let instance = customLangHighlighter.get(cacheKey);\n\n if (!instance) {\n instance = createHighlighter({\n langs: [customLang as ShikiLanguageRegistration],\n themes: themesToLoad,\n });\n customLangHighlighter.set(cacheKey, instance);\n }\n return instance;\n};\n\n/**\n * A React hook that provides syntax highlighting using Shiki.\n * Supports single theme and multi-theme highlighting, custom themes\n * and languages, custom transformers, and optional throttling.\n *\n * ```ts\n * // Basic Usage\n * const highlightedCode = useShikiHighlighter( code, 'typescript', 'github-dark');\n * ```\n *\n * ```ts\n * // Custom Languages, Transformers, and Delay\n * const highlightedCode = useShikiHighlighter(code, language, theme, {\n * transformers: [customTransformer],\n * delay: 150\n * customLanguages: ['bosque', 'mcfunction']\n * });\n * ```\n *\n * ```ts\n * // Multiple Themes, Custom Languages, Delay, and Custom Transformers\n * const highlightedCode = useShikiHighlighter(\n * code,\n * language,\n * {\n * light: 'github-light',\n * dark: 'github-dark',\n * dim: 'github-dark-dimmed'\n * },\n * {\n * delay: 150,\n * defaultColor: 'dim',\n * transformers: [customTransformer],\n * customLanguages: ['bosque', 'mcfunction']\n * }\n * );\n * ```\n */\nexport const useShikiHighlighter = (\n code: string,\n lang: Language,\n themeInput: Theme | Themes,\n options: HighlighterOptions = {}\n) => {\n const [highlightedCode, setHighlightedCode] =\n useState<ReactNode | null>(null);\n\n const normalizedCustomLanguages: LanguageRegistration[] =\n options.customLanguages\n ? Array.isArray(options.customLanguages)\n ? options.customLanguages\n : [options.customLanguages]\n : [];\n\n const customLangId = normalizedCustomLanguages\n .map((lang) => lang.name || '')\n .sort()\n .join('-');\n\n const transformers = useMemo(() => {\n return [removeTabIndexFromPre, ...(options.transformers || [])];\n }, [options.transformers]);\n\n const { isMultiTheme, themeId, multiTheme, singleTheme, themesToLoad } =\n useMemo(() => resolveTheme(themeInput), [themeInput]);\n\n const { isCustom, languageId, resolvedLanguage } = useMemo(\n () => resolveLanguage(lang, normalizedCustomLanguages),\n [lang, customLangId]\n );\n\n const cacheKey = `${languageId}-${themeId}`;\n\n const timeoutControl = useRef<TimeoutState>({\n nextAllowedTime: 0,\n timeoutId: undefined,\n });\n\n const buildShikiOptions = (): CodeToHastOptions => {\n const { defaultColor, cssVariablePrefix } = options;\n const commonOptions = { lang: languageId, transformers };\n\n const themeOptions = isMultiTheme\n ? ({\n themes: multiTheme || DEFAULT_THEMES,\n defaultColor,\n cssVariablePrefix,\n } as CodeOptionsMultipleThemes)\n : ({\n theme: singleTheme || DEFAULT_THEMES.dark,\n } as CodeOptionsSingleTheme);\n\n return { ...commonOptions, ...themeOptions };\n };\n\n useEffect(() => {\n let isMounted = true;\n\n const highlightCode = async () => {\n const codeHighlighter =\n isCustom && resolvedLanguage\n ? await getCachedCustomHighlighter(\n cacheKey,\n resolvedLanguage,\n themesToLoad\n )\n : bundledHighlighter;\n\n const highlighterOptions: CodeToHastOptions = buildShikiOptions();\n\n const html = await codeHighlighter.codeToHtml(\n code,\n highlighterOptions\n );\n if (isMounted) {\n setHighlightedCode(parse(html));\n }\n };\n\n if (options.delay) {\n throttleHighlighting(highlightCode, timeoutControl, options.delay);\n } else {\n highlightCode().catch(console.error);\n }\n\n return () => {\n isMounted = false;\n clearTimeout(timeoutControl.current.timeoutId);\n };\n }, [\n code,\n languageId,\n themeId,\n customLangId,\n transformers,\n options.delay,\n options.defaultColor,\n options.cssVariablePrefix,\n ]);\n\n return highlightedCode;\n};\n","import { visit } from 'unist-util-visit';\nimport { bundledLanguages, isSpecialLang } from 'shiki';\nimport type { ShikiTransformer, ThemeRegistrationAny } from 'shiki';\nimport type { Element } from 'hast';\nimport type { Language, Theme, Themes, TimeoutState } from './types';\nimport type { LanguageRegistration } from './customTypes';\n\n/**\n * Type for the HAST node, use to type `node` from react-markdown\n */\nexport type { Element };\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: any): undefined => {\n visit(tree, 'element', (node: Element, _index, parent: Element) => {\n if (node.tagName === 'code' && parent.tagName !== 'pre') {\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\n/**\n * Shiki transformer to remove tabindex from <pre> elements\n *\n * Consider retaining tabindex for WCAG 3.1 compliance, scrollable code blocks should be focusable\n * https://github.com/shikijs/shiki/issues/428\n * https://www.w3.org/WAI/standards-guidelines/act/rules/0ssw9k/proposed/\n */\nexport const removeTabIndexFromPre: ShikiTransformer = {\n pre(node) {\n if ('properties' in node) {\n node.properties.tabindex = '-1';\n }\n return node;\n },\n};\n\n/**\n * Optionally throttles rapid sequential highlighting operations\n * Exported for testing in __tests__/throttleHighlighting.test.ts\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.MutableRefObject<TimeoutState>,\n throttleMs: number\n) => {\n const now = Date.now();\n clearTimeout(timeoutControl.current.timeoutId);\n\n const delay = Math.max(0, timeoutControl.current.nextAllowedTime - now);\n timeoutControl.current.timeoutId = setTimeout(() => {\n performHighlight().catch(console.error);\n timeoutControl.current.nextAllowedTime = now + throttleMs;\n }, delay);\n};\n\ntype ResolvedLanguage = {\n isCustom: boolean;\n languageId: string;\n displayLanguageId?: string;\n resolvedLanguage?: LanguageRegistration;\n};\n\n/**\n * Determines whether a language is custom or built-in, normalizes\n * the language identifier and returns the resolved language with metadata\n *\n * @param lang - The language identifier, either as a string name or language object\n * @param customLanguages - Optional array of custom language definitions\n * @returns Object containing:\n * - isCustom: Whether the language requires custom highlighting\n * - languageId: The normalized language identifier\n * - displayLanguageId: The display name for language label\n * - resolvedLanguage: The full language definition if custom\n */\nexport const resolveLanguage = (\n lang: Language,\n customLanguages: LanguageRegistration[] = []\n): ResolvedLanguage => {\n // Language is custom but not preloaded\n if (lang && typeof lang === 'object') {\n return {\n isCustom: true,\n languageId: lang.name,\n displayLanguageId: lang.name,\n resolvedLanguage: lang,\n };\n }\n\n // Language is a string\n if (typeof lang === 'string') {\n const displayLanguageId = lang;\n\n // Check if its built-in\n if (lang in bundledLanguages || isSpecialLang(lang)) {\n return {\n isCustom: false,\n languageId: lang,\n displayLanguageId,\n };\n }\n\n // Check if it matches a preloaded custom language\n const customMatch = customLanguages.find(\n (cl) =>\n cl.fileTypes?.includes(lang) ||\n cl.scopeName?.split('.')[1] === lang ||\n cl.name?.toLowerCase() === lang.toLowerCase()\n );\n\n if (customMatch) {\n return {\n isCustom: true,\n languageId: customMatch.name,\n displayLanguageId,\n resolvedLanguage: customMatch,\n };\n }\n\n // If unknown, highlight in plaintext but display unknown language\n return {\n isCustom: false,\n languageId: 'plaintext',\n displayLanguageId,\n };\n }\n\n // Fallback\n return {\n isCustom: false,\n languageId: 'plaintext',\n displayLanguageId: 'plaintext',\n };\n};\n\n/**\n * Determines theme configuration and returns the resolved theme with metadata\n * @param themeInput - The theme input, either as a string name or theme object\n * @returns Object containing:\n * - isMultiTheme: If theme input is a multi-theme configuration\n * - themeId: Theme reference identifier\n * - multiTheme: The multi-theme config if it exists\n * - singleTheme: The single theme if it exists\n * - themesToLoad: The themes to load when creating the highlighter\n */\nexport function resolveTheme(themeInput: Theme | Themes): {\n isMultiTheme: boolean;\n themeId: Theme;\n multiTheme?: Themes | ThemeRegistrationAny | null;\n singleTheme?: Theme | undefined;\n themesToLoad: Theme[];\n} {\n const isTextmateTheme =\n typeof themeInput === 'object' &&\n 'tokenColors' in themeInput &&\n Array.isArray(themeInput.tokenColors);\n\n // Assume non textmate objects are multi theme configs\n const isMultiThemeConfig =\n typeof themeInput === 'object' &&\n themeInput !== null &&\n !isTextmateTheme;\n\n const validMultiThemeObj =\n typeof themeInput === 'object' &&\n themeInput !== null &&\n !isTextmateTheme &&\n Object.entries(themeInput).some(\n ([key, value]) =>\n key &&\n value &&\n key.trim() !== '' &&\n value !== '' &&\n (typeof value === 'string' || isTextmateTheme)\n );\n\n if (isMultiThemeConfig) {\n const themeId = validMultiThemeObj\n ? `multi-${Object.values(themeInput)\n .map(\n (theme) =>\n (typeof theme === 'string' ? theme : theme?.name) ||\n 'custom'\n )\n .sort()\n .join('-')}`\n : 'multi-default';\n\n // If config is invalid, return null to handle fallback in `buildShikiOptions()`\n return {\n isMultiTheme: true,\n themeId,\n multiTheme: validMultiThemeObj ? themeInput : null,\n themesToLoad: validMultiThemeObj ? Object.values(themeInput) : [],\n };\n }\n\n return {\n isMultiTheme: false,\n themeId:\n typeof themeInput === 'string'\n ? themeInput\n : themeInput?.name || 'custom',\n singleTheme: themeInput,\n themesToLoad: [themeInput],\n };\n}\n"],"mappings":"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","names":["styleInject","css","insertAt","head","style","styleInject","React","clsx","useEffect","useMemo","useRef","useState","parse","createHighlighter","createSingletonShorthands","visit","bundledLanguages","isSpecialLang","rehypeInlineCodeProperty","tree","node","_index","parent","isInlineCode","child","removeTabIndexFromPre","throttleHighlighting","performHighlight","timeoutControl","throttleMs","now","delay","resolveLanguage","lang","customLanguages","displayLanguageId","customMatch","cl","resolveTheme","themeInput","isTextmateTheme","isMultiThemeConfig","validMultiThemeObj","key","value","theme","DEFAULT_THEMES","bundledHighlighter","createSingletonShorthands","createHighlighter","customLangHighlighter","getCachedCustomHighlighter","cacheKey","customLang","themesToLoad","instance","useShikiHighlighter","code","lang","themeInput","options","highlightedCode","setHighlightedCode","useState","normalizedCustomLanguages","customLangId","transformers","useMemo","removeTabIndexFromPre","isMultiTheme","themeId","multiTheme","singleTheme","resolveTheme","isCustom","languageId","resolvedLanguage","resolveLanguage","timeoutControl","useRef","buildShikiOptions","defaultColor","cssVariablePrefix","commonOptions","themeOptions","useEffect","isMounted","highlightCode","codeHighlighter","highlighterOptions","html","parse","throttleHighlighting","ShikiHighlighter","language","theme","delay","transformers","defaultColor","cssVariablePrefix","addDefaultStyles","style","langStyle","className","langClassName","showLanguage","code","Element","customLanguages","options","normalizedCustomLanguages","isCustom","languageId","displayLanguageId","resolvedLanguage","resolveLanguage","highlightedCode","useShikiHighlighter","React","clsx"]}
1
+ {"version":3,"sources":["#style-inject:#style-inject","../src/styles.css","../src/component.tsx","../src/hook.ts","../src/utils.ts"],"sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\".relative{position:relative}.defaultStyles pre{overflow:auto;border-radius:.5rem;padding:1.25rem 1.5rem}.languageLabel{position:absolute;right:.75rem;top:.5rem;font-family:monospace;font-size:.75rem;letter-spacing:-.05em;color:#6b7280d9}\\n\")","import './styles.css';\n// biome-ignore lint/style/useImportType: React import is needed\nimport React from 'react';\nimport { clsx } from 'clsx';\nimport { useShikiHighlighter } from './hook';\nimport type {\n Language,\n Theme,\n HighlighterOptions,\n Themes,\n} from './types';\nimport { resolveLanguage } from './utils';\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 'pre'\n */\n as?: React.ElementType;\n}\n/**\n * ShikiHighlighter is a React component that provides syntax highlighting for code snippets.\n * It uses Shiki to render beautiful, theme-based syntax highlighting with optimized performance.\n *\n * @example\n * ```tsx\n * <ShikiHighlighter\n * language=\"typescript\"\n * theme=\"github-dark\"\n * delay={100}\n * transformers={[customTransformer]}\n * addDefaultStyles={false}\n * className=\"code-block\"\n * langClassName=\"lang-label\"\n * langStyle={{ color: 'blue' }},\n * style={{ fontSize: '1.2rem' }}\n * >\n * {code}\n * </ShikiHighlighter>\n * ```\n */\nexport const ShikiHighlighter = ({\n language,\n theme,\n delay,\n transformers,\n defaultColor,\n cssVariablePrefix,\n addDefaultStyles = true,\n style,\n langStyle,\n className,\n langClassName,\n showLanguage = true,\n children: code,\n as: Element = 'pre',\n customLanguages,\n}: ShikiHighlighterProps): React.ReactElement => {\n const options: HighlighterOptions = {\n delay,\n transformers,\n customLanguages,\n defaultColor,\n cssVariablePrefix,\n };\n\n const normalizedCustomLanguages = customLanguages\n ? Array.isArray(customLanguages)\n ? customLanguages\n : [customLanguages]\n : [];\n\n const { isCustom, languageId, displayLanguageId, resolvedLanguage } =\n resolveLanguage(language, normalizedCustomLanguages);\n\n const highlightedCode = useShikiHighlighter(\n code,\n language,\n theme,\n options\n );\n\n return (\n <Element\n data-testid=\"shiki-container\"\n className={clsx(\n 'relative',\n 'not-prose',\n addDefaultStyles && 'defaultStyles',\n className\n )}\n style={style}\n id=\"shiki-container\"\n >\n {showLanguage && language ? (\n <span\n className={clsx('languageLabel', langClassName)}\n style={langStyle}\n id=\"language-label\"\n >\n {isCustom\n ? `${resolvedLanguage?.scopeName.split('.')[1]}`\n : displayLanguageId || languageId}\n </span>\n ) : null}\n {highlightedCode}\n </Element>\n );\n};\n","import {\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\n\nimport parse from 'html-react-parser';\n\nimport {\n createHighlighter,\n createSingletonShorthands,\n type Highlighter,\n type CodeToHastOptions,\n type CodeOptionsSingleTheme,\n type CodeOptionsMultipleThemes,\n} from 'shiki';\n\nimport type {\n LanguageRegistration,\n ShikiLanguageRegistration,\n} from './extended-types';\n\nimport type {\n Language,\n Theme,\n HighlighterOptions,\n TimeoutState,\n Themes,\n} from './types';\n\nimport {\n removeTabIndexFromPre,\n throttleHighlighting,\n resolveLanguage,\n resolveTheme,\n} from './utils';\n\nconst DEFAULT_THEMES = {\n light: 'github-light',\n dark: 'github-dark',\n};\n\n// Use Shiki managed singleton for bundled languages, create and cache a fresh instance for custom languages\nconst bundledHighlighter = createSingletonShorthands(createHighlighter);\nconst customLangHighlighter = new Map<string, Promise<Highlighter>>();\n\nconst getCachedCustomHighlighter = async (\n cacheKey: string,\n customLang: LanguageRegistration,\n themesToLoad: Theme[]\n) => {\n let instance = customLangHighlighter.get(cacheKey);\n\n if (!instance) {\n instance = createHighlighter({\n langs: [customLang as ShikiLanguageRegistration],\n themes: themesToLoad,\n });\n customLangHighlighter.set(cacheKey, instance);\n }\n return instance;\n};\n\n/**\n * A React hook that provides syntax highlighting using Shiki.\n * Supports single theme and multi-theme highlighting, custom themes\n * and languages, custom transformers, and optional throttling.\n *\n * ```ts\n * // Basic Usage\n * const highlightedCode = useShikiHighlighter( code, 'typescript', 'github-dark');\n * ```\n *\n * ```ts\n * // Custom Languages, Transformers, and Delay\n * const highlightedCode = useShikiHighlighter(code, language, theme, {\n * transformers: [customTransformer],\n * delay: 150\n * customLanguages: ['bosque', 'mcfunction']\n * });\n * ```\n *\n * ```ts\n * // Multiple Themes, Custom Languages, Delay, and Custom Transformers\n * const highlightedCode = useShikiHighlighter(\n * code,\n * language,\n * {\n * light: 'github-light',\n * dark: 'github-dark',\n * dim: 'github-dark-dimmed'\n * },\n * {\n * delay: 150,\n * defaultColor: 'dim',\n * transformers: [customTransformer],\n * customLanguages: ['bosque', 'mcfunction']\n * }\n * );\n * ```\n */\nexport const useShikiHighlighter = (\n code: string,\n lang: Language,\n themeInput: Theme | Themes,\n options: HighlighterOptions = {}\n) => {\n const [highlightedCode, setHighlightedCode] =\n useState<ReactNode | null>(null);\n\n const normalizedCustomLanguages: LanguageRegistration[] =\n options.customLanguages\n ? Array.isArray(options.customLanguages)\n ? options.customLanguages\n : [options.customLanguages]\n : [];\n\n const customLangId = normalizedCustomLanguages\n .map((lang) => lang.name || '')\n .sort()\n .join('-');\n\n const transformers = useMemo(() => {\n return [removeTabIndexFromPre, ...(options.transformers || [])];\n }, [options.transformers]);\n\n const { isMultiTheme, themeId, multiTheme, singleTheme, themesToLoad } =\n useMemo(() => resolveTheme(themeInput), [themeInput]);\n\n const { isCustom, languageId, resolvedLanguage } = useMemo(\n () => resolveLanguage(lang, normalizedCustomLanguages),\n [lang, customLangId]\n );\n\n const cacheKey = `${languageId}-${themeId}`;\n\n const timeoutControl = useRef<TimeoutState>({\n nextAllowedTime: 0,\n timeoutId: undefined,\n });\n\n const buildShikiOptions = (): CodeToHastOptions => {\n const { defaultColor, cssVariablePrefix } = options;\n const commonOptions = { lang: languageId, transformers };\n\n const themeOptions = isMultiTheme\n ? ({\n themes: multiTheme || DEFAULT_THEMES,\n defaultColor,\n cssVariablePrefix,\n } as CodeOptionsMultipleThemes)\n : ({\n theme: singleTheme || DEFAULT_THEMES.dark,\n } as CodeOptionsSingleTheme);\n\n return { ...commonOptions, ...themeOptions };\n };\n\n useEffect(() => {\n let isMounted = true;\n\n const highlightCode = async () => {\n const codeHighlighter =\n isCustom && resolvedLanguage\n ? await getCachedCustomHighlighter(\n cacheKey,\n resolvedLanguage,\n themesToLoad\n )\n : bundledHighlighter;\n\n const highlighterOptions: CodeToHastOptions = buildShikiOptions();\n\n const html = await codeHighlighter.codeToHtml(\n code,\n highlighterOptions\n );\n if (isMounted) {\n setHighlightedCode(parse(html));\n }\n };\n\n if (options.delay) {\n throttleHighlighting(highlightCode, timeoutControl, options.delay);\n } else {\n highlightCode().catch(console.error);\n }\n\n return () => {\n isMounted = false;\n clearTimeout(timeoutControl.current.timeoutId);\n };\n }, [\n code,\n languageId,\n themeId,\n customLangId,\n transformers,\n options.delay,\n options.defaultColor,\n options.cssVariablePrefix,\n ]);\n\n return highlightedCode;\n};\n","import { visit } from 'unist-util-visit';\nimport { bundledLanguages, isSpecialLang } from 'shiki';\nimport type { ShikiTransformer, ThemeRegistrationAny } from 'shiki';\nimport type { Element } from 'hast';\nimport type { Language, Theme, Themes, TimeoutState } from './types';\nimport type { LanguageRegistration } from './extended-types';\n\n/**\n * Type for the HAST node, use to type `node` from react-markdown\n */\nexport type { Element };\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: any): undefined => {\n visit(tree, 'element', (node: Element, _index, parent: Element) => {\n if (node.tagName === 'code' && parent.tagName !== 'pre') {\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\n/**\n * Shiki transformer to remove tabindex from <pre> elements\n *\n * Consider retaining tabindex for WCAG 3.1 compliance, scrollable code blocks should be focusable\n * https://github.com/shikijs/shiki/issues/428\n * https://www.w3.org/WAI/standards-guidelines/act/rules/0ssw9k/proposed/\n */\nexport const removeTabIndexFromPre: ShikiTransformer = {\n pre(node) {\n if ('properties' in node) {\n node.properties.tabindex = '-1';\n }\n return node;\n },\n};\n\n/**\n * Optionally throttles rapid sequential highlighting operations\n * Exported for testing in __tests__/throttleHighlighting.test.ts\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.MutableRefObject<TimeoutState>,\n throttleMs: number\n) => {\n const now = Date.now();\n clearTimeout(timeoutControl.current.timeoutId);\n\n const delay = Math.max(0, timeoutControl.current.nextAllowedTime - now);\n timeoutControl.current.timeoutId = setTimeout(() => {\n performHighlight().catch(console.error);\n timeoutControl.current.nextAllowedTime = now + throttleMs;\n }, delay);\n};\n\ntype ResolvedLanguage = {\n isCustom: boolean;\n languageId: string;\n displayLanguageId?: string;\n resolvedLanguage?: LanguageRegistration;\n};\n\n/**\n * Determines whether a language is custom or built-in, normalizes\n * the language identifier and returns the resolved language with metadata\n *\n * @param lang - The language identifier, either as a string name or language object\n * @param customLanguages - Optional array of custom language definitions\n * @returns Object containing:\n * - isCustom: Whether the language requires custom highlighting\n * - languageId: The normalized language identifier\n * - displayLanguageId: The display name for language label\n * - resolvedLanguage: The full language definition if custom\n */\nexport const resolveLanguage = (\n lang: Language,\n customLanguages: LanguageRegistration[] = []\n): ResolvedLanguage => {\n // Language is custom but not preloaded\n if (lang && typeof lang === 'object') {\n return {\n isCustom: true,\n languageId: lang.name,\n displayLanguageId: lang.name,\n resolvedLanguage: lang,\n };\n }\n\n // Language is a string\n if (typeof lang === 'string') {\n const displayLanguageId = lang;\n\n // Check if its built-in\n if (lang in bundledLanguages || isSpecialLang(lang)) {\n return {\n isCustom: false,\n languageId: lang,\n displayLanguageId,\n };\n }\n\n // Check if it matches a preloaded custom language\n const customMatch = customLanguages.find(\n (cl) =>\n cl.fileTypes?.includes(lang) ||\n cl.scopeName?.split('.')[1] === lang ||\n cl.name?.toLowerCase() === lang.toLowerCase()\n );\n\n if (customMatch) {\n return {\n isCustom: true,\n languageId: customMatch.name,\n displayLanguageId,\n resolvedLanguage: customMatch,\n };\n }\n\n // If unknown, highlight in plaintext but display unknown language\n return {\n isCustom: false,\n languageId: 'plaintext',\n displayLanguageId,\n };\n }\n\n // Fallback\n return {\n isCustom: false,\n languageId: 'plaintext',\n displayLanguageId: 'plaintext',\n };\n};\n\n/**\n * Determines theme configuration and returns the resolved theme with metadata\n * @param themeInput - The theme input, either as a string name or theme object\n * @returns Object containing:\n * - isMultiTheme: If theme input is a multi-theme configuration\n * - themeId: Theme reference identifier\n * - multiTheme: The multi-theme config if it exists\n * - singleTheme: The single theme if it exists\n * - themesToLoad: The themes to load when creating the highlighter\n */\nexport function resolveTheme(themeInput: Theme | Themes): {\n isMultiTheme: boolean;\n themeId: Theme;\n multiTheme?: Themes | ThemeRegistrationAny | null;\n singleTheme?: Theme | undefined;\n themesToLoad: Theme[];\n} {\n const isTextmateTheme =\n typeof themeInput === 'object' &&\n 'tokenColors' in themeInput &&\n Array.isArray(themeInput.tokenColors);\n\n // Assume non textmate objects are multi theme configs\n const isMultiThemeConfig =\n typeof themeInput === 'object' &&\n themeInput !== null &&\n !isTextmateTheme;\n\n const validMultiThemeObj =\n typeof themeInput === 'object' &&\n themeInput !== null &&\n !isTextmateTheme &&\n Object.entries(themeInput).some(\n ([key, value]) =>\n key &&\n value &&\n key.trim() !== '' &&\n value !== '' &&\n (typeof value === 'string' || isTextmateTheme)\n );\n\n if (isMultiThemeConfig) {\n const themeId = validMultiThemeObj\n ? `multi-${Object.values(themeInput)\n .map(\n (theme) =>\n (typeof theme === 'string' ? theme : theme?.name) ||\n 'custom'\n )\n .sort()\n .join('-')}`\n : 'multi-default';\n\n // If config is invalid, return null to handle fallback in `buildShikiOptions()`\n return {\n isMultiTheme: true,\n themeId,\n multiTheme: validMultiThemeObj ? themeInput : null,\n themesToLoad: validMultiThemeObj ? Object.values(themeInput) : [],\n };\n }\n\n return {\n isMultiTheme: false,\n themeId:\n typeof themeInput === 'string'\n ? themeInput\n : themeInput?.name || 'custom',\n singleTheme: themeInput,\n themesToLoad: [themeInput],\n };\n}\n"],"mappings":"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","names":["styleInject","css","insertAt","head","style","styleInject","React","clsx","useEffect","useMemo","useRef","useState","parse","createHighlighter","createSingletonShorthands","visit","bundledLanguages","isSpecialLang","rehypeInlineCodeProperty","tree","node","_index","parent","isInlineCode","child","removeTabIndexFromPre","throttleHighlighting","performHighlight","timeoutControl","throttleMs","now","delay","resolveLanguage","lang","customLanguages","displayLanguageId","customMatch","cl","resolveTheme","themeInput","isTextmateTheme","isMultiThemeConfig","validMultiThemeObj","key","value","theme","DEFAULT_THEMES","bundledHighlighter","createSingletonShorthands","createHighlighter","customLangHighlighter","getCachedCustomHighlighter","cacheKey","customLang","themesToLoad","instance","useShikiHighlighter","code","lang","themeInput","options","highlightedCode","setHighlightedCode","useState","normalizedCustomLanguages","customLangId","transformers","useMemo","removeTabIndexFromPre","isMultiTheme","themeId","multiTheme","singleTheme","resolveTheme","isCustom","languageId","resolvedLanguage","resolveLanguage","timeoutControl","useRef","buildShikiOptions","defaultColor","cssVariablePrefix","commonOptions","themeOptions","useEffect","isMounted","highlightCode","codeHighlighter","highlighterOptions","html","parse","throttleHighlighting","ShikiHighlighter","language","theme","delay","transformers","defaultColor","cssVariablePrefix","addDefaultStyles","style","langStyle","className","langClassName","showLanguage","code","Element","customLanguages","options","normalizedCustomLanguages","isCustom","languageId","displayLanguageId","resolvedLanguage","resolveLanguage","highlightedCode","useShikiHighlighter","React","clsx"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-shiki",
3
3
  "description": "Syntax highlighter component for react using shiki",
4
- "version": "0.5.0",
4
+ "version": "0.5.1",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Bassim Shahidy",