UNPKG

16.2 kBMarkdownView Raw
1[![Maintenance Status][maintenance-image]](#maintenance-status)
2
3
4<h1 align="center">
5 prism-react-renderer 🖌️
6 <br>
7</h1>
8<p align="center" style="font-size: 1.2rem;">
9 A lean <a href="https://github.com/PrismJS/prism">Prism</a> highlighter component for React<br>
10 Comes with everything to render Prismjs highlighted code directly to React (Native) elements, global-pollution-free!
11</p>
12
13## Why?
14
15Maybe you need to render some extra UI with your Prismjs-highlighted code,
16or maybe you'd like to manipulate what Prism renders completely,
17or maybe you're just using Prism with React and are searching for an easier,
18global-pollution-free way?
19
20Then you're right where you want to be!
21
22## How?
23
24This library tokenises code using Prism and provides a small render-props-driven
25component to quickly render it out into React. This is why it even works with
26React Native! It's bundled with a modified version of Prism that won't pollute
27the global namespace and comes with
28[a couple of common language syntaxes](./src/vendor/prism/includeLangs.js).
29
30_(There's also an [escape-hatch](https://github.com/FormidableLabs/prism-react-renderer#prism) to use your own Prism setup, just in case)_
31
32It also comes with its own [VSCode-like theming format](#theming), which means by default
33you can easily drop in different themes, use the ones this library ships with, or
34create new ones programmatically on the fly.
35
36_(If you just want to use your Prism CSS-file themes, that's also no problem)_
37
38## Table of Contents
39
40<!-- START doctoc generated TOC please keep comment here to allow auto update -->
41<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
42
43- [Installation](#installation)
44- [Usage](#usage)
45- [Basic Props](#basic-props)
46 - [children](#children)
47 - [language](#language)
48 - [code](#code)
49- [Advanced Props](#advanced-props)
50 - [theme](#theme)
51 - [Prism](#prism)
52- [Children Function](#children-function)
53 - [state](#state)
54 - [prop getters](#prop-getters)
55 - [`getLineProps`](#getlineprops)
56 - [`getTokenProps`](#gettokenprops)
57- [Theming](#theming)
58- [FAQ](#faq)
59- [LICENSE](#license)
60
61<!-- END doctoc generated TOC please keep comment here to allow auto update -->
62
63## Installation
64
65This module is distributed via npm which is bundled with node and
66should be installed as one of your project's `dependencies`:
67
68```sh
69# npm
70npm install --save prism-react-renderer
71# yarn
72yarn add prism-react-renderer
73```
74
75> This package also depends on `react`. Please make sure you
76> have those installed as well.
77
78## Usage
79
80> [Try it out in the browser](https://codesandbox.io/s/prism-react-renderer-example-u6vhk)
81
82<img src="./.readme/basic.png" width="237" alt="Screenshot showing highlighted code block" />
83
84```jsx
85import React from "react";
86import { render } from "react-dom";
87import Highlight, { defaultProps } from "prism-react-renderer";
88
89const exampleCode = `
90(function someDemo() {
91 var test = "Hello World!";
92 console.log(test);
93})();
94
95return () => <App />;
96`;
97
98render((
99 <Highlight {...defaultProps} code={exampleCode} language="jsx">
100 {({ className, style, tokens, getLineProps, getTokenProps }) => (
101 <pre className={className} style={style}>
102 {tokens.map((line, i) => (
103 <div {...getLineProps({ line, key: i })}>
104 {line.map((token, key) => (
105 <span {...getTokenProps({ token, key })} />
106 ))}
107 </div>
108 ))}
109 </pre>
110 )}
111 </Highlight>,
112 document.getElementById('root')
113);
114```
115
116`<Highlight />` is the only component exposed by this package, as inspired by
117[downshift](https://github.com/paypal/downshift).
118
119It also exports a `defaultProps` object which for basic usage can simply be spread
120onto the `<Highlight />` component. It also provides some default theming.
121
122It doesn't render anything itself, it just calls the render function and renders that.
123["Use a render prop!"](https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce)!
124`<Highlight>{highlight => <pre>/* your JSX here! */</pre>}</Highlight>`
125
126### Line Numbers
127
128Add line numbers to your highlighted code blocks using the `index` parameter in your `line.map` function:
129
130<img src="./.readme/line-numbers.png" width="453" alt="Screenshot showing line numbers in highlighted code block" />
131
132For example, if you were using `styled-components`, it could look like the following demo.
133
134> [Demo with `styled-components`](https://codesandbox.io/s/prism-react-renderer-example-u6vhk?file=/src/WithLineNumbers.js)
135
136```js
137import React from "react";
138import styled from "styled-components";
139import Highlight, { defaultProps } from "prism-react-renderer";
140import theme from "prism-react-renderer/themes/nightOwl";
141
142const exampleCode = `
143import React, { useState } from "react";
144
145function Example() {
146 const [count, setCount] = useState(0);
147
148 return (
149 <div>
150 <p>You clicked {count} times</p>
151 <button onClick={() => setCount(count + 1)}>
152 Click me
153 </button>
154 </div>
155 );
156}
157`.trim();
158
159const Pre = styled.pre`
160 text-align: left;
161 margin: 1em 0;
162 padding: 0.5em;
163 overflow: scroll;
164`;
165
166const Line = styled.div`
167 display: table-row;
168`;
169
170const LineNo = styled.span`
171 display: table-cell;
172 text-align: right;
173 padding-right: 1em;
174 user-select: none;
175 opacity: 0.5;
176`;
177
178const LineContent = styled.span`
179 display: table-cell;
180`;
181
182const WithLineNumbers = () => (
183 <Highlight {...defaultProps} theme={theme} code={exampleCode} language="jsx">
184 {({ className, style, tokens, getLineProps, getTokenProps }) => (
185 <Pre className={className} style={style}>
186 {tokens.map((line, i) => (
187 <Line key={i} {...getLineProps({ line, key: i })}>
188 <LineNo>{i + 1}</LineNo>
189 <LineContent>
190 {line.map((token, key) => (
191 <span key={key} {...getTokenProps({ token, key })} />
192 ))}
193 </LineContent>
194 </Line>
195 ))}
196 </Pre>
197 )}
198 </Highlight>
199);
200
201export default WithLineNumbers;
202```
203
204## Basic Props
205
206This is the list of props that you should probably know about. There are some
207[advanced props](#advanced-props) below as well.
208
209Most of these [advanced props](#advanced-props) are included in the `defaultProps`.
210
211### children
212
213> `function({})` | _required_
214
215This is called with an object. Read more about the properties of this object in
216the section "[Children Function](#children-function)".
217
218### language
219
220> `string` | _required_
221
222This is the language that your code will be highlighted as. You can see a list
223of 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)
224
225### code
226
227> `string` | _required_
228
229This is the code that will be highlighted.
230
231## Advanced Props
232
233### theme
234
235> `PrismTheme` | _required; default is provided in `defaultProps` export_
236
237If a theme is passed, it is used to generate style props which can be retrieved
238via the prop-getters which are described in "[Children Function](#children-function)".
239
240A default theme is provided by the `defaultProps` object.
241
242Read more about how to theme `react-prism-renderer` in
243the section "[Theming](#theming)".
244
245### Prism
246
247> `PrismLib` | _required; default is provided in `defaultProps` export_
248
249This is the [Prismjs](https://github.com/PrismJS/prism) library itself.
250A vendored version of Prism is provided (and also exported) as part of this library.
251This vendored version doesn't pollute the global namespace, is slimmed down,
252and doesn't conflict with any installation of `prismjs` you might have.
253
254If you're only using `Prism.highlight` you can choose to use `prism-react-renderer`'s
255exported, vendored version of Prism instead.
256
257But if you choose to use your own Prism setup, simply pass Prism as a prop:
258
259```jsx
260// Whichever way you're retrieving Prism here:
261import Prism from 'prismjs/components/prism-core';
262
263<Highlight Prism={Prism} {/* ... */} />
264```
265
266## Children Function
267
268This is where you render whatever you want to based on the output of `<Highlight />`.
269You use it like so:
270
271```js
272const ui = (
273 <Highlight>
274 {highlight => (
275 // use utilities and prop getters here, like highlight.className, highlight.getTokenProps, etc.
276 <pre>{/* more jsx here */}</pre>
277 )}
278 </Highlight>
279);
280```
281
282The properties of this `highlight` object can be split into two categories as indicated below:
283
284### state
285
286These properties are the flat output of `<Highlight />`. They're generally "state" and are what
287you'd usually expect from a render-props-based API.
288
289| property | type | description |
290| ----------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
291| `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. |
292| `className` | `string` | This is the class you should apply to your wrapping element, typically a `<pre>` |
293
294A "Token" is an object that represents a piece of content for Prism. It has a `types` property, which is an array
295of types that indicate the purpose and styling of a piece of text, and a `content` property, which is the actual
296text.
297
298You'd typically iterate over `tokens`, rendering each line, and iterate over its items, rendering out each token, which is a piece of
299this line.
300
301### prop getters
302
303> See
304> [Kent C. Dodds' blog post about prop getters](https://blog.kentcdodds.com/how-to-give-rendering-control-to-users-with-prop-getters-549eaef76acf)
305
306These functions are used to apply props to the elements that you render. This
307gives you maximum flexibility to render what, when, and wherever you like.
308
309You'd typically call these functions with some dictated input and add on all other
310props that it should pass through. It'll correctly override and modify the props
311that it returns to you, so passing props to it instead of adding them directly is
312advisable.
313
314| property | type | description |
315| --------------- | -------------- | ----------------------------------------------------------------------------------------------------- |
316| `getLineProps` | `function({})` | returns the props you should apply to any list of tokens, i.e. the element that contains your tokens. |
317| `getTokenProps` | `function({})` | returns the props you should apply to the elements displaying tokens that you render. |
318
319#### `getLineProps`
320
321You need to add a `line` property (type: `Token[]`) to the object you're passing to
322`getLineProps`; It's also advisable to add a `key`.
323
324This getter will return you props to spread onto your line elements (typically `<div>s`).
325
326It will typically return a `className` (if you pass one it'll be appended), `children`,
327`style` (if you pass one it'll be merged). It also passes on all other props you pass
328to the input.
329
330The `className` will always contain `.token-line`.
331
332#### `getTokenProps`
333
334You need to add a `token` property (type: `Token`) to the object you're passing to
335`getTokenProps`; It's also advisable to add a `key`.
336
337This getter will return you props to spread onto your token elements (typically `<span>s`).
338
339It will typically return a `className` (if you pass one it'll be appended), `children`,
340`style` (if you pass one it'll be merged). It also passes on all other props you pass
341to the input.
342
343The `className` will always contain `.token`. This also provides full compatibility with
344your old Prism CSS-file themes.
345
346## Theming
347
348The `defaultProps` you'd typically apply in a basic use-case, contain a default theme.
349This theme is [duotoneDark](./src/themes/duotoneDark.js).
350
351While all `className`s are provided with `<Highlight />`, so that you could use your good
352old Prism CSS-file themes, you can also choose to use `react-prism-renderer`'s themes like so:
353
354```jsx
355import dracula from 'prism-react-renderer/themes/dracula';
356
357<Highlight theme={dracula} {/* ... */} />
358```
359
360These themes are JSON-based and are heavily inspired by VSCode's theme format.
361
362Their syntax, expressed in Flow looks like the following:
363
364```js
365{
366 plain: StyleObj,
367 styles: Array<{
368 types: string[],
369 languages?: string[],
370 style: StyleObj
371 }>
372}
373```
374
375The `plain` property provides a base style-object. This style object is directly used
376in the `style` props that you'll receive from the prop getters, if a `theme` prop has
377been passed to `<Highlight />`.
378
379The `styles` property contains an array of definitions. Each definition contains a `style`
380property, that is also just a style object. These styles are limited by the `types`
381and `languages` properties.
382
383The `types` properties is an array of token types that Prism outputs. The `languages`
384property limits styles to highlighted languages.
385
386When converting a Prism CSS theme it's mostly just necessary to use classes as
387`types` and convert the declarations to object-style-syntax and put them on `style`.
388
389## FAQ
390
391<details>
392
393<summary>How do I add more language highlighting support?</summary>
394
395By default `prism-react-renderer` only includes an [arbitrary subset of the languages](https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/vendor/prism/includeLangs.js) that Prism supports. You can add support for more by including their definitions from the main `prismjs` package:
396
397```js
398import Prism from "prism-react-renderer/prism";
399
400(typeof global !== "undefined" ? global : window).Prism = Prism;
401
402require("prismjs/components/prism-kotlin");
403require("prismjs/components/prism-csharp");
404```
405</details>
406
407<details>
408
409<summary>How do I use my old Prism css themes?</summary>
410
411`prism-react-renderer` still returns you all proper `className`s via the prop getters,
412when you use it. By default however it uses its new theming system, which output a
413couple of `style` props as well.
414
415If you don't pass `theme` to the `<Highlight />` component it will default to not
416outputting any `style` props, while still returning you the `className` props, like
417so:
418
419```js
420<Highlight
421 {...defaultProps}
422 code={exampleCode}
423 language="jsx"
424 theme={undefined}
425>
426 {highlight => null /* ... */}
427</Highlight>
428```
429
430</details>
431
432<details>
433
434<summary>How do I prevent a theme and the vendored Prism to be bundled?</summary>
435
436Since the default theme and the vendored Prism library in `prism-react-renderer`
437come from `defaultProps`, if you wish to pass your own Prism library in, and not
438use the built-in theming, you simply need to leave it out to allow your bundler
439to tree-shake those:
440
441```js
442import Highlight from "prism-react-renderer";
443import Prism from "prismjs"; // Different source
444
445<Highlight Prism={Prism} code={exampleCode} language="jsx">
446 {highlight => null /* ... */}
447</Highlight>;
448```
449
450You can also import the vendored Prism library on its own:
451
452```js
453import { Prism } from "prism-react-renderer";
454// or
455import Prism from "prism-react-renderer/prism";
456```
457
458</details>
459
460## LICENSE
461
462MIT
463
464## Maintenance Status
465
466**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.
467
468[maintenance-image]: https://img.shields.io/badge/maintenance-active-green.svg
469