Skip to content

Instantly share code, notes, and snippets.

@andrelandgraf
Created December 26, 2021 17:35
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrelandgraf/eebe0b710c189fef21dcd25bfe9a8da7 to your computer and use it in GitHub Desktop.
Save andrelandgraf/eebe0b710c189fef21dcd25bfe9a8da7 to your computer and use it in GitHub Desktop.
PrismJS custom component
​import​ ​type​ ​{​ ​FC​,​ ​HTMLAttributes​,​ ​ReactElement​ ​}​ ​from​ ​'react'​;
​import​ ​{​ ​Children​ ​}​ ​from​ ​'react'​;
​import​ ​invariant​ ​from​ ​'tiny-invariant'​;
​import​ ​Highlight​,​ ​{​ ​Language​,​ ​defaultProps​ ​}​ ​from​ ​'prism-react-renderer'​;
​import​ ​CopyClipboardButton​ ​from​ ​'../button/copyClipboardButton'​;
​function​ ​getLanguageFromClassName​(​className​: ​string​)​ ​{
​  ​const​ ​match​ ​=​ ​className​.​match​(​/​language-​(​\w​+​)​/​)​;
​  ​return​ ​match​ ? ​match​[​1​]​ : ​''​;
​}
​function​ ​isLanguageSupported​(​lang​: ​string​)​: ​lang​ is ​Language​ ​{
​  ​return​ ​(
​    ​lang​ ​===​ ​'markup'​ ​||
​    ​lang​ ​===​ ​'bash'​ ​||
​    ​lang​ ​===​ ​'clike'​ ​||
​    ​lang​ ​===​ ​'c'​ ​||
​    ​lang​ ​===​ ​'cpp'​ ​||
​    ​lang​ ​===​ ​'css'​ ​||
​    ​lang​ ​===​ ​'javascript'​ ​||
​    ​lang​ ​===​ ​'jsx'​ ​||
​    ​lang​ ​===​ ​'coffeescript'​ ​||
​    ​lang​ ​===​ ​'actionscript'​ ​||
​    ​lang​ ​===​ ​'css-extr'​ ​||
​    ​lang​ ​===​ ​'diff'​ ​||
​    ​lang​ ​===​ ​'git'​ ​||
​    ​lang​ ​===​ ​'go'​ ​||
​    ​lang​ ​===​ ​'graphql'​ ​||
​    ​lang​ ​===​ ​'handlebars'​ ​||
​    ​lang​ ​===​ ​'json'​ ​||
​    ​lang​ ​===​ ​'less'​ ​||
​    ​lang​ ​===​ ​'makefile'​ ​||
​    ​lang​ ​===​ ​'markdown'​ ​||
​    ​lang​ ​===​ ​'objectivec'​ ​||
​    ​lang​ ​===​ ​'ocaml'​ ​||
​    ​lang​ ​===​ ​'python'​ ​||
​    ​lang​ ​===​ ​'reason'​ ​||
​    ​lang​ ​===​ ​'sass'​ ​||
​    ​lang​ ​===​ ​'scss'​ ​||
​    ​lang​ ​===​ ​'sql'​ ​||
​    ​lang​ ​===​ ​'stylus'​ ​||
​    ​lang​ ​===​ ​'tsx'​ ​||
​    ​lang​ ​===​ ​'typescript'​ ​||
​    ​lang​ ​===​ ​'wasm'​ ​||
​    ​lang​ ​===​ ​'yaml'
​  ​)​;
​}
​const​ ​CodeBlock​: ​FC​<​HTMLAttributes​<​HTMLPreElement​>​>​ ​=​ ​(​{​ children ​}​)​ ​=>​ ​{
​  ​invariant​(​!​!​children​,​ ​'children is required'​)​;
​  ​const​ ​childrenArray​ ​=​ ​Children​.​toArray​(​children​)​;
​  ​const​ ​codeElement​ ​=​ ​childrenArray​[​0​]​ ​as​ ​ReactElement​;
​  ​const​ ​className​ ​=​ ​codeElement​?.​props​?.​className​ ​||​ ​''​;
​  ​const​ ​lang​ ​=​ ​getLanguageFromClassName​(​className​)​;
​  ​invariant​(​isLanguageSupported​(​lang​)​,​ ​'lang is required'​)​;
​  ​const​ ​code​ ​=​ ​codeElement​.​props​.​children​[​0​]​ ​||​ ​''​;
​  ​const​ ​identifier​ ​=​ ​code​;
​  ​return​ ​(
​    ​<​div​ ​className​=​"w-full my-5"​>
​      ​<​Highlight​ ​{​...​defaultProps​}​ ​code​=​{​code​.​trim​(​)​}​ ​language​=​{​lang​ ​||​ ​'bash'​}​>
​        ​{​(​{​ className​,​ tokens​,​ getLineProps​,​ getTokenProps ​}​)​ ​=>​ ​(
​          ​<​div​ ​className​=​"p-4 rounded-md font-normal text-sm md:text-base bg-docs w-full"​>
​            ​<​div​ ​className​=​"flex justify-end px-4 pb-2 text-particular-dark"​>
​              ​<​span​ ​className​=​"mr-5 text-particular-light"​>​{​lang​ ​||​ ​'text'​}​<​/​span​>
​              ​<​CopyClipboardButton​ ​title​=​"Copy code"​ ​content​=​{​code​}​ ​id​=​{​identifier​}​ ​/​>
​            ​<​/​div​>
​            ​<​pre​ ​className​=​{​`pb-2 overflow-scroll ​${​className​}​`​}​ ​style​=​{​{​}​}​>
​              ​<​code​ ​className​=​{​className​}​ ​style​=​{​{​}​}​>
​                ​{​tokens​.​map​(​(​line​,​ ​i​)​ ​=>​ ​(
​                  ​<​div​ ​key​=​{​i​}​ ​{​...​getLineProps​(​{​ line​,​ ​key​: ​i​ ​}​)​}​ ​style​=​{​{​}​}​>
​                    ​{​line​.​map​(​(​token​,​ ​key​)​ ​=>​ ​(
​                      ​<​span​ ​key​=​{​key​}​ ​{​...​getTokenProps​(​{​ token​,​ key ​}​)​}​ ​style​=​{​{​}​}​ ​/​>
​                    ​)​)​}
​                  ​<​/​div​>
​                ​)​)​}
​              ​<​/​code​>
​            ​<​/​pre​>
​          ​<​/​div​>
​        ​)​}
​      ​<​/​Highlight​>
​    ​<​/​div​>
​  ​)​;
​}​;
@andrelandgraf
Copy link
Author

@andrelandgraf
Copy link
Author

Be aware that the example code uses custom tailwind classes. You will need to update the background and text color classes.

@andrelandgraf
Copy link
Author

To style the code, pick a prismJS theme: https://github.com/PrismJS/prism-themes/tree/master/themes

@RafaelDavisH
Copy link

@andrelandgraf, I really appreciate you sharing this. Thank you 👍🏼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment