@@ -4,13 +4,16 @@ import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
44import type { CodeToHastOptions } from 'shiki' ;
55
66import type {
7- HighlightedCode ,
7+ BaseHighlighterOptions ,
88 HighlighterFactory ,
99 HighlighterOptions ,
10+ HighlightResultMap ,
1011 Language ,
12+ OutputFormat ,
1113 Theme ,
1214 Themes ,
1315 TimeoutState ,
16+ UseShikiHighlighter ,
1417} from './types' ;
1518
1619import { throttleHighlighting , useStableValue } from './utils' ;
@@ -22,22 +25,22 @@ import {
2225import { resolveTheme } from './theme' ;
2326import { buildShikiOptions } from './options' ;
2427
25- export async function highlight (
28+ export async function highlight < F extends OutputFormat = 'react' > (
2629 code : string ,
2730 resolved : {
2831 languageId : string ;
2932 langsToLoad : Language [ ] ;
3033 themesToLoad : Theme [ ] ;
3134 shikiOptions : CodeToHastOptions ;
3235 } ,
33- opts : Pick <
34- HighlighterOptions ,
35- 'highlighter' | 'outputFormat' | 'engine'
36- > ,
36+ opts : Pick < HighlighterOptions , 'highlighter' | 'engine' > & {
37+ outputFormat ?: F ;
38+ } ,
3739 factory : HighlighterFactory
38- ) {
40+ ) : Promise < HighlightResultMap [ F ] > {
3941 const { languageId, langsToLoad, themesToLoad, shikiOptions } =
4042 resolved ;
43+ const format : OutputFormat = opts . outputFormat ?? 'react' ;
4144
4245 const highlighter =
4346 opts . highlighter ??
@@ -55,24 +58,30 @@ export async function highlight(
5558 ) ;
5659 const options = { ...shikiOptions , lang : language } ;
5760
58- return opts . outputFormat === 'html'
59- ? highlighter . codeToHtml ( code , options )
60- : toJsxRuntime ( highlighter . codeToHast ( code , options ) , {
61+ const outputs : { [ K in OutputFormat ] : ( ) => HighlightResultMap [ K ] } = {
62+ react : ( ) =>
63+ toJsxRuntime ( highlighter . codeToHast ( code , options ) , {
6164 jsx,
6265 jsxs,
6366 Fragment,
64- } ) ;
67+ } ) ,
68+ html : ( ) => highlighter . codeToHtml ( code , options ) ,
69+ tokens : ( ) => highlighter . codeToTokens ( code , options ) ,
70+ } ;
71+
72+ return outputs [ format ] ( ) as HighlightResultMap [ F ] ;
6573}
6674
67- export const useHighlight = (
75+ export const useHighlight = < F extends OutputFormat = 'react' > (
6876 code : string ,
6977 lang : Language ,
7078 themeInput : Theme | Themes ,
71- options : HighlighterOptions = { } ,
79+ options : BaseHighlighterOptions & { outputFormat ?: F } = { } ,
7280 highlighterFactory : HighlighterFactory
73- ) => {
74- const [ highlightedCode , setHighlightedCode ] =
75- useState < HighlightedCode > ( null ) ;
81+ ) : HighlightResultMap [ F ] | null => {
82+ const [ highlightedCode , setHighlightedCode ] = useState <
83+ HighlightResultMap [ F ] | null
84+ > ( null ) ;
7685
7786 const stableLang = useStableValue ( lang ) ;
7887 const stableTheme = useStableValue ( themeInput ) ;
@@ -111,7 +120,7 @@ export const useHighlight = (
111120
112121 const run = async ( ) => {
113122 try {
114- const result = await highlight (
123+ const result = await highlight < F > (
115124 code ,
116125 resolved ,
117126 stableOpts ,
@@ -138,3 +147,18 @@ export const useHighlight = (
138147
139148 return highlightedCode ;
140149} ;
150+
151+ /**
152+ * Create a `useShikiHighlighter` hook bound to a specific highlighter factory.
153+ * Used by the bundled entry points (full / web / core).
154+ */
155+ export const createUseShikiHighlighter = (
156+ factory : HighlighterFactory
157+ ) : UseShikiHighlighter => {
158+ return < F extends OutputFormat = 'react' > (
159+ code : string ,
160+ lang : Language ,
161+ themeInput : Theme | Themes ,
162+ options ?: BaseHighlighterOptions & { outputFormat ?: F }
163+ ) => useHighlight < F > ( code , lang , themeInput , options , factory ) ;
164+ } ;
0 commit comments