react-shiki 0.2.0 → 0.2.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.
Files changed (2) hide show
  1. package/README.md +121 -19
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,17 +1,18 @@
1
- > [!WARNING]
2
- > This package is still a work in progress, it is not yet recommended for production use. Contributions are welcome! My goal is to eventually build this out as a near-drop-in replacement for `react-syntax-highlighter`
1
+ > [!NOTE]
2
+ > This package is still a work in progress, fully functional but not extensively tested.
3
3
 
4
4
  # 🎨 [react-shiki](https://react-shiki.vercel.app/)
5
5
 
6
6
  Syntax highlighting component and hook for react using [Shiki](https://shiki.matsu.io/)
7
7
 
8
- [See the demo page for a version of this README with highlighted code blocks showcasing several Shiki themes!](https://react-shiki.vercel.app/)
8
+ [See the demo page with highlighted code blocks showcasing several Shiki themes!](https://react-shiki.vercel.app/)
9
9
 
10
10
  ## Features
11
11
 
12
12
  - 🖼️ Provides a `ShikiHighlighter` component for highlighting code as children, as well as a `useShikiHighlighter` hook for more flexibility
13
13
  - 🔐 No `dangerouslySetInnerHTML`, output from Shiki is parsed using `html-react-parser`
14
14
  - 📦 Supports all Shiki languages and themes
15
+ - 🚰 Supports performant highlighting of streamed code on the client, with optional throttling
15
16
  - 📚 Includes minimal default styles for code blocks
16
17
  - 🚀 Shiki dynamically imports only the languages and themes used on a page, optimizing for performance
17
18
  - 🖥️ `ShikiHighlighter` component displays a language label for each code block when `showLanguage` is set to `true` (default)
@@ -20,7 +21,7 @@ Syntax highlighting component and hook for react using [Shiki](https://shiki.mat
20
21
  ## Installation
21
22
 
22
23
  ```bash
23
- [pnpm|bun|yarn|npm] [add|install] react-shiki
24
+ [pnpm|bun|yarn|npm] install react-shiki
24
25
  ```
25
26
 
26
27
  ## Usage
@@ -74,11 +75,27 @@ function Houston() {
74
75
  }
75
76
  ```
76
77
 
78
+ react-shiki exports `isInlineCode` to check if a code block is inline.
79
+
80
+ ```tsx
81
+ const isInline: boolean | undefined = node ? isInlineCode(node) : undefined;
82
+
83
+ return !isInline ? (
84
+ <ShikiHighlighter language={language} theme={"houston"} {...props}>
85
+ {String(children)}
86
+ </ShikiHighlighter>
87
+ ) : (
88
+ <code className={className} {...props}>
89
+ {children}
90
+ </code>
91
+ );
92
+ ```
93
+
77
94
  It can also be used with `react-markdown`:
78
95
 
79
96
  ```tsx
80
97
  import type { ReactNode } from "react";
81
- import ShikiHighlighter, { isInlineCode, type Element } from "react-shiki";
98
+ import ShikiHighlighter, { type Element } from "react-shiki";
82
99
 
83
100
  interface CodeHighlightProps {
84
101
  className?: string | undefined;
@@ -95,17 +112,9 @@ export const CodeHighlight = ({
95
112
  const match = className?.match(/language-(\w+)/);
96
113
  const language = match ? match[1] : undefined;
97
114
 
98
- const isInline: boolean | undefined = node ? isInlineCode(node) : undefined;
99
-
100
- return !isInline ? (
101
- <ShikiHighlighter language={language} theme={"houston"} {...props}>
102
- {String(children)}
103
- </ShikiHighlighter>
104
- ) : (
105
- <code className={className} {...props}>
106
- {children}
107
- </code>
108
- );
115
+ <ShikiHighlighter language={language} theme={"houston"} {...props}>
116
+ {String(children)}
117
+ </ShikiHighlighter>;
109
118
  };
110
119
  ```
111
120
 
@@ -124,9 +133,103 @@ import { CodeHighlight } from "./CodeHighlight";
124
133
  </ReactMarkdown>;
125
134
  ```
126
135
 
127
- This works great for highlighting in realtime on the client, I use it for an LLM chatbot UI, it renders markdown and highlights code in memoized chat messages:
136
+ ### Custom themes
128
137
 
129
- ```tsx
138
+ ```tsx:title=CodeHighlight.tsx
139
+ import tokyoNight from '@styles/tokyo-night.mjs';
140
+
141
+ <ShikiHighlighter language="tsx" theme={tokyoNight}>
142
+ {String(code)}
143
+ </ShikiHighlighter>;
144
+ ```
145
+
146
+ ## Client-side highlighting
147
+
148
+ This works great for highlighting in real-time on the client, I use it for an LLM chatbot UI, it renders markdown and highlights code in memoized chat messages. It also Supports an optional delay between highlights for throttling.
149
+
150
+ Using `useShikiHighlighter` hook:
151
+
152
+ ```tsx title=CodeHighlight.tsx
153
+ import type { ReactNode } from "react";
154
+ import { isInlineCode, useShikiHighlighter, type Element } from "react-shiki";
155
+ import tokyoNight from "@styles/tokyo-night.mjs";
156
+
157
+ interface CodeHighlightProps {
158
+ className?: string | undefined;
159
+ children?: ReactNode | undefined;
160
+ node?: Element | undefined;
161
+ }
162
+
163
+ export const CodeHighlight = ({
164
+ className,
165
+ children,
166
+ node,
167
+ ...props
168
+ }: CodeHighlightProps) => {
169
+ const code = String(children);
170
+ const language = className?.match(/language-(\w+)/)?.[1];
171
+
172
+ const isInline = node ? isInlineCode(node) : false;
173
+
174
+ const highlightedCode = useShikiHighlighter(language, code, tokyoNight, {
175
+ delay: 150,
176
+ });
177
+
178
+ return !isInline ? (
179
+ <div className="shiki not-prose relative [&_pre]:overflow-auto [&_pre]:rounded-lg [&_pre]:px-6 [&_pre]:py-5">
180
+ {language ? (
181
+ <span className="absolute right-3 top-2 text-xs tracking-tighter text-muted-foreground/85">
182
+ {language}
183
+ </span>
184
+ ) : null}
185
+ {highlightedCode}
186
+ </div>
187
+ ) : (
188
+ <code className={className} {...props}>
189
+ {children}
190
+ </code>
191
+ );
192
+ };
193
+ ```
194
+
195
+ Or using the `ShikiHighlighter` component:
196
+
197
+ ```tsx title=CodeHighlight.tsx
198
+ import type { ReactNode } from "react";
199
+ import ShikiHighlighter, { isInlineCode, type Element } from "react-shiki";
200
+
201
+ interface CodeHighlightProps {
202
+ className?: string | undefined;
203
+ children?: ReactNode | undefined;
204
+ node?: Element | undefined;
205
+ }
206
+
207
+ export const CodeHighlight = ({
208
+ className,
209
+ children,
210
+ node,
211
+ ...props
212
+ }: CodeHighlightProps): JSX.Element => {
213
+ const match = className?.match(/language-(\w+)/);
214
+ const language = match ? match[1] : undefined;
215
+
216
+ const isInline: boolean | undefined = node ? isInlineCode(node) : undefined;
217
+
218
+ return !isInline ? (
219
+ <ShikiHighlighter language={language} theme={"houston"} {...props}>
220
+ {String(children)}
221
+ </ShikiHighlighter>
222
+ ) : (
223
+ <code className={className} {...props}>
224
+ {children}
225
+ </code>
226
+ );
227
+ };
228
+ ```
229
+
230
+ Passed to `react-markdown` as a code component in memoized chat messages:
231
+
232
+ ```tsx title=ChatMessages.tsx
130
233
  const RenderedMessage = React.memo(({ message }: { message: Message }) => (
131
234
  <div className={cn(messageStyles[message.role])}>
132
235
  <ReactMarkdown components={{ code: CodeHighlight }}>
@@ -145,4 +248,3 @@ export const ChatMessages = ({ messages }: { messages: Message[] }) => {
145
248
  );
146
249
  };
147
250
  ```
148
-
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.2.0",
4
+ "version": "0.2.1",
5
5
  "license": "MIT",
6
6
  "author": {
7
7
  "name": "Bassim Shahidy",