1 | <a href="https://formidable.com/open-source/" target="_blank">
|
2 | <img alt="Prism React Renderer — Formidable, We build the modern web" src="https://raw.githubusercontent.com/FormidableLabs/prism-react-renderer/master/prism-react-renderer-Hero.png" />
|
3 | </a>
|
4 |
|
5 | <p align="center" style="font-size: 1.2rem;">
|
6 | A lean <a href="https://github.com/PrismJS/prism">Prism</a> highlighter component for React<br>
|
7 | Comes with everything to render Prismjs highlighted code directly to React (Native) elements, global-pollution-free!
|
8 | </p>
|
9 |
|
10 | [![Maintenance Status][maintenance-image]](#maintenance-status)
|
11 | ## Why?
|
12 |
|
13 | Maybe you need to render some extra UI with your Prismjs-highlighted code,
|
14 | or maybe you'd like to manipulate what Prism renders completely,
|
15 | or maybe you're just using Prism with React and are searching for an easier,
|
16 | global-pollution-free way?
|
17 |
|
18 | Then you're right where you want to be!
|
19 |
|
20 | ## How?
|
21 |
|
22 | This library tokenises code using Prism and provides a small render-props-driven
|
23 | component to quickly render it out into React. This is why it even works with
|
24 | React Native! It's bundled with a modified version of Prism that won't pollute
|
25 | the global namespace and comes with
|
26 | [a couple of common language syntaxes](./src/vendor/prism/includeLangs.js).
|
27 |
|
28 | _(There's also an [escape-hatch](https://github.com/FormidableLabs/prism-react-renderer#prism) to use your own Prism setup, just in case)_
|
29 |
|
30 | It also comes with its own [VSCode-like theming format](#theming), which means by default
|
31 | you can easily drop in different themes, use the ones this library ships with, or
|
32 | create new ones programmatically on the fly.
|
33 |
|
34 | _(If you just want to use your Prism CSS-file themes, that's also no problem)_
|
35 |
|
36 | ## Table of Contents
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | - [Installation](#installation)
|
42 | - [Usage](#usage)
|
43 | - [Custom Language Support](#custom-language-support)
|
44 | - [Basic Props](#basic-props)
|
45 | - [children](#children)
|
46 | - [language](#language)
|
47 | - [code](#code)
|
48 | - [Advanced Props](#advanced-props)
|
49 | - [theme](#theme)
|
50 | - [Prism](#prism)
|
51 | - [Children Function](#children-function)
|
52 | - [state](#state)
|
53 | - [prop getters](#prop-getters)
|
54 | - [`getLineProps`](#getlineprops)
|
55 | - [`getTokenProps`](#gettokenprops)
|
56 | - [Theming](#theming)
|
57 | - [LICENSE](#license)
|
58 |
|
59 |
|
60 |
|
61 | ## Installation
|
62 |
|
63 | This module is distributed via npm which is bundled with node and
|
64 | should be installed as one of your project's `dependencies`:
|
65 |
|
66 | ```sh
|
67 | # npm
|
68 | npm install --save prism-react-renderer
|
69 | # yarn
|
70 | yarn add prism-react-renderer
|
71 | # pnpm
|
72 | pnpm add prism-react-renderer
|
73 | ```
|
74 |
|
75 | > Prism React Renderer has a peer dependency on `react`
|
76 |
|
77 | ### Usage
|
78 | Prism React Renderer has a named export for the `<Highlight />` component along with `themes`. To see Prism React Render in action with base styling check out `packages/demo` or run `pnpm run start:demo` from the root of this repository.
|
79 |
|
80 | ```tsx
|
81 | import React from "react"
|
82 | import ReactDOM from "react-dom/client"
|
83 | import { Highlight, themes } from "prism-react-renderer"
|
84 | import styles from 'styles.module.css'
|
85 |
|
86 | const codeBlock = `
|
87 | const GroceryItem: React.FC<GroceryItemProps> = ({ item }) => {
|
88 | return (
|
89 | <div>
|
90 | <h2>{item.name}</h2>
|
91 | <p>Price: {item.price}</p>
|
92 | <p>Quantity: {item.quantity}</p>
|
93 | </div>
|
94 | );
|
95 | }
|
96 | `
|
97 |
|
98 | export const App = () => (
|
99 | <Highlight
|
100 | theme={themes.shadesOfPurple}
|
101 | code={codeBlock}
|
102 | language="tsx"
|
103 | >
|
104 | {({ className, style, tokens, getLineProps, getTokenProps }) => (
|
105 | <pre style={style}>
|
106 | {tokens.map((line, i) => (
|
107 | <div key={i} {...getLineProps({ line })}>
|
108 | <span>{i + 1}</span>
|
109 | {line.map((token, key) => (
|
110 | <span key={key} {...getTokenProps({ token })} />
|
111 | ))}
|
112 | </div>
|
113 | ))}
|
114 | </pre>
|
115 | )}
|
116 | </Highlight>
|
117 | )
|
118 |
|
119 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
120 | .render(<App />)
|
121 |
|
122 | ```
|
123 |
|
124 | ### Custom Language Support
|
125 |
|
126 | By default `prism-react-renderer` only includes a [base set of languages](https://github.com/FormidableLabs/prism-react-renderer/blob/c914fdea48625ba59c8022174bb3df1ed802ce4d/packages/generate-prism-languages/index.ts#L9-L23) that Prism supports. **Depending on your app's build system you may need to `await` the `import` or use `require` to ensure `window.Prism` exists before importing the custom languages.** You can add support for more by including their definitions from the main `prismjs` package:
|
127 |
|
128 | ```js
|
129 | import { Highlight, Prism } from "prism-react-renderer";
|
130 |
|
131 | (typeof global !== "undefined" ? global : window).Prism = Prism
|
132 | await import("prismjs/components/prism-applescript")
|
133 | /** or **/
|
134 | require("prismjs/components/prism-applescript")
|
135 | ```
|
136 |
|
137 |
|
138 | ## Basic Props
|
139 |
|
140 | This is the list of props that you should probably know about. There are some
|
141 | [advanced props](#advanced-props) below as well.
|
142 |
|
143 | Most of these [advanced props](#advanced-props) are included in the `defaultProps`.
|
144 |
|
145 | ### children
|
146 |
|
147 | > `function({})` | _required_
|
148 |
|
149 | This is called with an object. Read more about the properties of this object in
|
150 | the section "[Children Function](#children-function)".
|
151 |
|
152 | ### language
|
153 |
|
154 | > `string` | _required_
|
155 |
|
156 | This is the language that your code will be highlighted as. You can see a list
|
157 | of all languages that are supported out of the box [here](./src/vendor/prism/includeLangs.js). Not all languages are included and the list of languages that are currently is a little arbitrary. You can use the [escape-hatch](https://github.com/FormidableLabs/prism-react-renderer#prism) to use your own Prism setup, just in case, or [add more languages to the bundled Prism.](https://github.com/FormidableLabs/prism-react-renderer#faq)
|
158 |
|
159 | ### code
|
160 |
|
161 | > `string` | _required_
|
162 |
|
163 | This is the code that will be highlighted.
|
164 |
|
165 | ## Advanced Props
|
166 |
|
167 | ### theme
|
168 |
|
169 | > `PrismTheme` | _optional; default is vsDark_
|
170 |
|
171 | If a theme is passed, it is used to generate style props which can be retrieved
|
172 | via the prop-getters which are described in "[Children Function](#children-function)".
|
173 |
|
174 | Read more about how to theme `prism-react-renderer` in
|
175 | the section "[Theming](#theming)".
|
176 |
|
177 | ### prism
|
178 |
|
179 | > `prism` | _optional; default is the vendored version_
|
180 |
|
181 | This is the [Prismjs](https://github.com/PrismJS/prism) library itself.
|
182 | A vendored version of Prism is provided (and also exported) as part of this library.
|
183 | This vendored version doesn't pollute the global namespace, is slimmed down,
|
184 | and doesn't conflict with any installation of `prismjs` you might have.
|
185 |
|
186 | If you're only using `Prism.highlight` you can choose to use `prism-react-renderer`'s
|
187 | exported, vendored version of Prism instead.
|
188 |
|
189 | But if you choose to use your own Prism setup, simply pass Prism as a prop:
|
190 |
|
191 | ```jsx
|
192 | // Whichever way you're retrieving Prism here:
|
193 | import Prism from 'prismjs/components/prism-core';
|
194 |
|
195 | <Highlight prism={prism} {/* ... */} />
|
196 | ```
|
197 |
|
198 | ## Children Function
|
199 |
|
200 | This is where you render whatever you want to based on the output of `<Highlight />`.
|
201 | You use it like so:
|
202 |
|
203 | ```js
|
204 | const ui = (
|
205 | <Highlight>
|
206 | {highlight => (
|
207 | // use utilities and prop getters here, like highlight.className, highlight.getTokenProps, etc.
|
208 | <pre>{/* more jsx here */}</pre>
|
209 | )}
|
210 | </Highlight>
|
211 | );
|
212 | ```
|
213 |
|
214 | The properties of this `highlight` object can be split into two categories as indicated below:
|
215 |
|
216 | ### state
|
217 |
|
218 | These properties are the flat output of `<Highlight />`. They're generally "state" and are what
|
219 | you'd usually expect from a render-props-based API.
|
220 |
|
221 | | property | type | description |
|
222 | | ----------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
223 | | `tokens` | `Token[][]` | This is a doubly nested array of tokens. The outer array is for separate lines, the inner for tokens, so the actual content. |
|
224 | | `className` | `string` | This is the class you should apply to your wrapping element, typically a `<pre>` |
|
225 |
|
226 | A "Token" is an object that represents a piece of content for Prism. It has a `types` property, which is an array
|
227 | of types that indicate the purpose and styling of a piece of text, and a `content` property, which is the actual
|
228 | text.
|
229 |
|
230 | You'd typically iterate over `tokens`, rendering each line, and iterate over its items, rendering out each token, which is a piece of
|
231 | this line.
|
232 |
|
233 | ### prop getters
|
234 |
|
235 | > See
|
236 | > [Kent C. Dodds' blog post about prop getters](https://blog.kentcdodds.com/how-to-give-rendering-control-to-users-with-prop-getters-549eaef76acf)
|
237 |
|
238 | These functions are used to apply props to the elements that you render. This
|
239 | gives you maximum flexibility to render what, when, and wherever you like.
|
240 |
|
241 | You'd typically call these functions with some dictated input and add on all other
|
242 | props that it should pass through. It'll correctly override and modify the props
|
243 | that it returns to you, so passing props to it instead of adding them directly is
|
244 | advisable.
|
245 |
|
246 | | property | type | description |
|
247 | | --------------- | -------------- | ----------------------------------------------------------------------------------------------------- |
|
248 | | `getLineProps` | `function({})` | returns the props you should apply to any list of tokens, i.e. the element that contains your tokens. |
|
249 | | `getTokenProps` | `function({})` | returns the props you should apply to the elements displaying tokens that you render. |
|
250 |
|
251 | #### `getLineProps`
|
252 |
|
253 | You need to add a `line` property (type: `Token[]`) to the object you're passing to
|
254 | `getLineProps`; It's also advisable to add a `key`.
|
255 |
|
256 | This getter will return you props to spread onto your line elements (typically `<div>s`).
|
257 |
|
258 | It will typically return a `className` (if you pass one it'll be appended), `children`,
|
259 | `style` (if you pass one it'll be merged). It also passes on all other props you pass
|
260 | to the input.
|
261 |
|
262 | The `className` will always contain `.token-line`.
|
263 |
|
264 | #### `getTokenProps`
|
265 |
|
266 | You need to add a `token` property (type: `Token`) to the object you're passing to
|
267 | `getTokenProps`; It's also advisable to add a `key`.
|
268 |
|
269 | This getter will return you props to spread onto your token elements (typically `<span>s`).
|
270 |
|
271 | It will typically return a `className` (if you pass one it'll be appended), `children`,
|
272 | `style` (if you pass one it'll be merged). It also passes on all other props you pass
|
273 | to the input.
|
274 |
|
275 | The `className` will always contain `.token`. This also provides full compatibility with
|
276 | your old Prism CSS-file themes.
|
277 |
|
278 | ## Theming
|
279 |
|
280 | The `defaultProps` you'd typically apply in a basic use-case, contain a default theme.
|
281 | This theme is [vsDark](./packages/prism-react-renderer/src/themes/vsDark.ts).
|
282 |
|
283 | While all `className`s are provided with `<Highlight />`, so that you could use your good
|
284 | old Prism CSS-file themes, you can also choose to use `prism-react-renderer`'s themes like so:
|
285 |
|
286 | ```jsx
|
287 | import { Highlight, themes } from 'prism-react-renderer';
|
288 |
|
289 | <Highlight theme={themes.dracula} {/* ... */} />
|
290 | ```
|
291 |
|
292 | These themes are JSON-based and are heavily inspired by VSCode's theme format.
|
293 |
|
294 | Their syntax, expressed in Flow looks like the following:
|
295 |
|
296 | ```js
|
297 | {
|
298 | plain: StyleObj,
|
299 | styles: Array<{
|
300 | types: string[],
|
301 | languages?: string[],
|
302 | style: StyleObj
|
303 | }>
|
304 | }
|
305 | ```
|
306 |
|
307 | The `plain` property provides a base style-object. This style object is directly used
|
308 | in the `style` props that you'll receive from the prop getters, if a `theme` prop has
|
309 | been passed to `<Highlight />`.
|
310 |
|
311 | The `styles` property contains an array of definitions. Each definition contains a `style`
|
312 | property, that is also just a style object. These styles are limited by the `types`
|
313 | and `languages` properties.
|
314 |
|
315 | The `types` properties is an array of token types that Prism outputs. The `languages`
|
316 | property limits styles to highlighted languages.
|
317 |
|
318 | When converting a Prism CSS theme it's mostly just necessary to use classes as
|
319 | `types` and convert the declarations to object-style-syntax and put them on `style`.
|
320 |
|
321 | ## LICENSE
|
322 |
|
323 | MIT
|
324 |
|
325 | ## Maintenance Status
|
326 |
|
327 | **Active:** Formidable is actively working on this project, and we expect to continue for work for the foreseeable future. Bug reports, feature requests and pull requests are welcome.
|
328 |
|
329 | [maintenance-image]: https://img.shields.io/badge/maintenance-active-green.svg
|
330 |
|