🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more →

react-shiki

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-shiki - npm Package Compare versions

Comparing version

to
0.5.2

import React, { ReactNode } from 'react';
import { LanguageRegistration as LanguageRegistration$1, CodeOptionsMultipleThemes, BundledTheme, CodeToHastOptionsCommon, BundledLanguage, SpecialLanguage, ThemeRegistrationAny, StringLiteralUnion } from 'shiki';
import { Element } from 'hast';
export { Element } from 'hast';
import { LanguageRegistration as LanguageRegistration$1, StringLiteralUnion, BundledLanguage, SpecialLanguage, ThemeRegistrationAny, BundledTheme, CodeOptionsMultipleThemes, CodeToHastOptionsCommon } from 'shiki';
import { Element as Element$1 } from 'hast';

@@ -43,6 +42,10 @@ /**

/**
* HTML Element, use to type `node` from react-markdown
*/
type Element = Element$1;
/**
* A Shiki BundledLanguage or a custom textmate grammar object
* @see https://shiki.style/languages
*/
type Language = BundledLanguage | LanguageRegistration | SpecialLanguage | (string & {}) | undefined;
type Language = LanguageRegistration | StringLiteralUnion<BundledLanguage | SpecialLanguage> | undefined;
/**

@@ -75,3 +78,3 @@ * A Shiki BundledTheme or a custom textmate theme object

*/
type ReactShikiOptions = {
interface ReactShikiOptions {
/**

@@ -86,9 +89,69 @@ * Minimum time (in milliseconds) between highlight operations.

customLanguages?: LanguageRegistration | LanguageRegistration[];
};
}
/**
* Configuration options for the syntax highlighter
*/
type HighlighterOptions = ReactShikiOptions & Pick<CodeOptionsMultipleThemes<BundledTheme>, 'defaultColor' | 'cssVariablePrefix'> & Pick<CodeToHastOptionsCommon, 'transformers'>;
interface HighlighterOptions extends ReactShikiOptions, Pick<CodeOptionsMultipleThemes<BundledTheme>, 'defaultColor' | 'cssVariablePrefix'>, Pick<CodeToHastOptionsCommon, 'transformers'> {
}
/**
* A React hook that provides syntax highlighting using Shiki.
* Supports single theme and multi-theme highlighting, custom themes
* and languages, custom transformers, and optional throttling.
*
* ```ts
* // Basic Usage
* const highlightedCode = useShikiHighlighter( code, 'typescript', 'github-dark');
* ```
*
* ```ts
* // Custom Languages, Transformers, and Delay
* const highlightedCode = useShikiHighlighter(code, language, theme, {
* transformers: [customTransformer],
* delay: 150
* customLanguages: ['bosque', 'mcfunction']
* });
* ```
*
* ```ts
* // Multiple Themes, Custom Languages, Delay, and Custom Transformers
* const highlightedCode = useShikiHighlighter(
* code,
* language,
* {
* light: 'github-light',
* dark: 'github-dark',
* dim: 'github-dark-dimmed'
* },
* {
* delay: 150,
* defaultColor: 'dim',
* transformers: [customTransformer],
* customLanguages: ['bosque', 'mcfunction']
* }
* );
* ```
*/
declare const useShikiHighlighter: (code: string, lang: Language, themeInput: Theme | Themes, options?: HighlighterOptions) => ReactNode;
/**
* Rehype plugin to add an 'inline' property to <code> elements
* Sets 'inline' property to true if the <code> is not within a <pre> tag
*
* Pass this plugin to the `rehypePlugins` prop of react-markdown
* You can then access `inline` as a prop in components passed to react-markdown
*
* @example
* <ReactMarkdown rehypePlugins={[rehypeInlineCodeProperty]} />
*/
declare function rehypeInlineCodeProperty(): (tree: any) => undefined;
/**
* Function to determine if code is inline based on the presence of line breaks
*
* @example
* const isInline = node && isInlineCode(node: Element)
*/
declare const isInlineCode: (node: Element) => boolean;
/**
* Props for the ShikiHighlighter component

@@ -176,61 +239,2 @@ */

/**
* A React hook that provides syntax highlighting using Shiki.
* Supports single theme and multi-theme highlighting, custom themes
* and languages, custom transformers, and optional throttling.
*
* ```ts
* // Basic Usage
* const highlightedCode = useShikiHighlighter( code, 'typescript', 'github-dark');
* ```
*
* ```ts
* // Custom Languages, Transformers, and Delay
* const highlightedCode = useShikiHighlighter(code, language, theme, {
* transformers: [customTransformer],
* delay: 150
* customLanguages: ['bosque', 'mcfunction']
* });
* ```
*
* ```ts
* // Multiple Themes, Custom Languages, Delay, and Custom Transformers
* const highlightedCode = useShikiHighlighter(
* code,
* language,
* {
* light: 'github-light',
* dark: 'github-dark',
* dim: 'github-dark-dimmed'
* },
* {
* delay: 150,
* defaultColor: 'dim',
* transformers: [customTransformer],
* customLanguages: ['bosque', 'mcfunction']
* }
* );
* ```
*/
declare const useShikiHighlighter: (code: string, lang: Language, themeInput: Theme | Themes, options?: HighlighterOptions) => ReactNode;
/**
* Rehype plugin to add an 'inline' property to <code> elements
* Sets 'inline' property to true if the <code> is not within a <pre> tag
*
* Pass this plugin to the `rehypePlugins` prop of react-markdown
* You can then access `inline` as a prop in components passed to react-markdown
*
* @example
* <ReactMarkdown rehypePlugins={[rehypeInlineCodeProperty]} />
*/
declare function rehypeInlineCodeProperty(): (tree: any) => undefined;
/**
* Function to determine if code is inline based on the presence of line breaks
*
* @example
* const isInline = node && isInlineCode(node: Element)
*/
declare const isInlineCode: (node: Element) => boolean;
export { type HighlighterOptions, type Language, type Theme, type Themes, ShikiHighlighter as default, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };
export { type Element, type HighlighterOptions, type Language, type ShikiHighlighterProps, type Theme, type Themes, ShikiHighlighter as default, isInlineCode, rehypeInlineCodeProperty, useShikiHighlighter };

@@ -1,4 +0,4 @@

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}
`);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(`
`),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};
import{useEffect as D,useMemo as C,useRef as F,useState as B}from"react";import V from"html-react-parser";import{getSingletonHighlighter as _}from"shiki";import{visit as w}from"unist-util-visit";import{bundledLanguages as A,isSpecialLang as N}from"shiki";function P(){return e=>{w(e,"element",(i,o,t)=>{i.tagName==="code"&&t.tagName!=="pre"&&(i.properties.inline=!0)})}}var z=e=>!(e.children||[]).filter(o=>o.type==="text").map(o=>o.value).join("").includes(`
`),k={pre(e){return"properties"in e&&(e.properties.tabindex="-1"),e}},R=(e,i,o)=>{let t=Date.now();clearTimeout(i.current.timeoutId);let n=Math.max(0,i.current.nextAllowedTime-t);i.current.timeoutId=setTimeout(()=>{e().catch(console.error),i.current.nextAllowedTime=t+o},n)},p=(e,i=[])=>{let o=new Set(Object.keys(A).map(a=>a.toLowerCase()));if(e==null||typeof e=="string"&&!e.trim())return{languageId:"plaintext",displayLanguageId:"plaintext",langsToLoad:void 0};if(typeof e=="object")return{languageId:e.name,displayLanguageId:e.name||null,langsToLoad:e};let t=e.toLowerCase(),n=a=>a?.toLowerCase()===t,r=i.find(a=>n(a.name)||a.aliases?.some(n)||n(a.scopeName)||n(a.scopeName?.split(".").pop()));return r?{languageId:r.name||e,displayLanguageId:e,langsToLoad:r}:(o.has(t)||N(t))&&!r?{languageId:e,displayLanguageId:e,langsToLoad:e}:{languageId:"plaintext",displayLanguageId:e,langsToLoad:void 0}};function v(e){let i=typeof e=="object"&&"tokenColors"in e&&Array.isArray(e.tokenColors),o=typeof e=="object"&&e!==null&&!i,t=typeof e=="object"&&e!==null&&!i&&Object.entries(e).some(([n,r])=>n&&r&&n.trim()!==""&&r!==""&&(typeof r=="string"||i));return o?{isMultiTheme:!0,themeId:t?`multi-${Object.values(e).map(r=>(typeof r=="string"?r:r?.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 I={light:"github-light",dark:"github-dark"},H=(e,i,o,t={})=>{let[n,r]=B(null),a=t.customLanguages?Array.isArray(t.customLanguages)?t.customLanguages:[t.customLanguages]:[],g=a.map(l=>l.name||"").sort().join("-"),m=C(()=>[k,...t.transformers||[]],[t.transformers]),{isMultiTheme:c,themeId:f,multiTheme:T,singleTheme:y,themesToLoad:L}=C(()=>v(o),[o]),{languageId:s,langsToLoad:x}=C(()=>p(i,a),[i,g]),d=F({nextAllowedTime:0,timeoutId:void 0}),u=()=>{let{defaultColor:l,cssVariablePrefix:h}=t,S={lang:s,transformers:m},b=c?{themes:T||I,defaultColor:l,cssVariablePrefix:h}:{theme:y||I.dark};return{...S,...b}};return D(()=>{let l=!0,h=async()=>{if(!s)return;let S=await _({langs:[x],themes:L}),b=u(),M=S.codeToHtml(e,b);l&&r(V(M))};return t.delay?R(h,d,t.delay):h().catch(console.error),()=>{l=!1,clearTimeout(d.current.timeoutId)}},[e,s,f,g,m,t.delay,t.defaultColor,t.cssVariablePrefix]),n};function O(e,{insertAt:i}={}){if(!e||typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],t=document.createElement("style");t.type="text/css",i==="top"&&o.firstChild?o.insertBefore(t,o.firstChild):o.appendChild(t),t.styleSheet?t.styleSheet.cssText=e:t.appendChild(document.createTextNode(e))}O(`.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}
`);import j from"react";import{clsx as E}from"clsx";var U=({language:e,theme:i,delay:o,transformers:t,defaultColor:n,cssVariablePrefix:r,addDefaultStyles:a=!0,style:g,langStyle:m,className:c,langClassName:f,showLanguage:T=!0,children:y,as:L="pre",customLanguages:s})=>{let x={delay:o,transformers:t,customLanguages:s,defaultColor:n,cssVariablePrefix:r},d=s?Array.isArray(s)?s:[s]:[],{displayLanguageId:u}=p(e,d),l=H(y,e,i,x);return j.createElement(L,{"data-testid":"shiki-container",className:E("relative","not-prose",a&&"defaultStyles",c),style:g,id:"shiki-container"},T&&u?j.createElement("span",{className:E("languageLabel",f),style:m,id:"language-label"},u):null,l)};export{U as default,z as isInlineCode,P as rehypeInlineCodeProperty,H as useShikiHighlighter};
//# sourceMappingURL=index.js.map
{
"name": "react-shiki",
"description": "Syntax highlighter component for react using shiki",
"version": "0.5.1",
"version": "0.5.2",
"license": "MIT",

@@ -45,4 +45,4 @@ "author": {

"clsx": "^2.1.1",
"html-react-parser": "^5.1.12",
"shiki": "^3.0.0",
"html-react-parser": "^5.2.3",
"shiki": "^3.2.1",
"unist-util-visit": "^5.0.0"

@@ -54,7 +54,7 @@ },

"@types/hast": "^3.0.4",
"@types/node": "22.13.4",
"@types/react": "^18.3.18",
"@types/node": "22.14.0",
"@types/react": "^18.3.20",
"@vitejs/plugin-react": "^4.3.4",
"jsdom": "^22.1.0",
"tsup": "^8.3.6",
"tsup": "^8.4.0",
"vitest": "^0.34.6"

@@ -61,0 +61,0 @@ },

Sorry, the diff of this file is not supported yet