From 03a75890dc282388dbf56777734735bdf619c65d Mon Sep 17 00:00:00 2001 From: Dmitrii Troitskii Date: Sun, 22 Feb 2026 03:18:48 +0000 Subject: [PATCH 1/5] feat: support custom shiki themes in code blocks Add support for custom shiki theme objects (ThemeRegistrationAny-compatible) in addition to built-in BundledTheme string names. - Add CustomTheme interface and ThemeInput type alias - Widen theme types across CodePluginOptions, CodeHighlighterPlugin, HighlightOptions, StreamdownProps, and StreamdownContextType - Extract theme names from objects for cache keys and codeToTokens - Pass theme objects to createHighlighter for registration - Add tests for custom theme objects and mixed themes - Full backward compatibility with existing BundledTheme usage Closes #409 --- .../streamdown-code/__tests__/index.test.ts | 84 +++++++++++++++++++ packages/streamdown-code/index.ts | 57 +++++++++---- packages/streamdown/index.tsx | 11 +-- packages/streamdown/lib/plugin-types.ts | 25 +++++- 4 files changed, 156 insertions(+), 21 deletions(-) diff --git a/packages/streamdown-code/__tests__/index.test.ts b/packages/streamdown-code/__tests__/index.test.ts index b786d5c8..f175d132 100644 --- a/packages/streamdown-code/__tests__/index.test.ts +++ b/packages/streamdown-code/__tests__/index.test.ts @@ -1,5 +1,6 @@ import type { BundledLanguage } from "shiki"; import { describe, expect, it, vi } from "vitest"; +import type { CustomTheme } from "../index"; import { code, createCodePlugin } from "../index"; describe("code", () => { @@ -303,4 +304,87 @@ describe("createCodePlugin", () => { expect(typeof plugin.getSupportedLanguages).toBe("function"); expect(typeof plugin.getThemes).toBe("function"); }); + + it("should create plugin with custom theme objects", () => { + const customLight: CustomTheme = { + name: "my-light-theme", + type: "light", + colors: { "editor.background": "#ffffff" }, + tokenColors: [], + }; + const customDark: CustomTheme = { + name: "my-dark-theme", + type: "dark", + colors: { "editor.background": "#1e1e1e" }, + tokenColors: [], + }; + const plugin = createCodePlugin({ + themes: [customLight, customDark], + }); + const themes = plugin.getThemes(); + expect(themes[0]).toBe(customLight); + expect(themes[1]).toBe(customDark); + }); + + it("should create plugin with mixed built-in and custom themes", () => { + const customDark: CustomTheme = { + name: "my-dark-theme", + type: "dark", + colors: { "editor.background": "#1e1e1e" }, + tokenColors: [], + }; + const plugin = createCodePlugin({ + themes: ["github-light", customDark], + }); + const themes = plugin.getThemes(); + expect(themes[0]).toBe("github-light"); + expect(themes[1]).toBe(customDark); + }); + + it("should highlight code with custom theme objects", async () => { + const customLight: CustomTheme = { + name: "custom-light", + type: "light", + colors: { + "editor.background": "#ffffff", + "editor.foreground": "#000000", + }, + tokenColors: [], + }; + const customDark: CustomTheme = { + name: "custom-dark", + type: "dark", + colors: { + "editor.background": "#1e1e1e", + "editor.foreground": "#d4d4d4", + }, + tokenColors: [], + }; + const plugin = createCodePlugin({ + themes: [customLight, customDark], + }); + + const callback = vi.fn(); + const result = plugin.highlight( + { + code: "const x = 1;", + language: "javascript", + themes: [customLight, customDark], + }, + callback + ); + + expect(result).toBeNull(); + + await vi.waitFor( + () => { + expect(callback).toHaveBeenCalled(); + }, + { timeout: 5000 } + ); + + const highlightResult = callback.mock.calls[0][0]; + expect(highlightResult.tokens).toBeDefined(); + expect(Array.isArray(highlightResult.tokens)).toBe(true); + }); }); diff --git a/packages/streamdown-code/index.ts b/packages/streamdown-code/index.ts index a459e283..d2475c33 100644 --- a/packages/streamdown-code/index.ts +++ b/packages/streamdown-code/index.ts @@ -14,6 +14,20 @@ import { createJavaScriptRegexEngine } from "shiki/engine/javascript"; const jsEngine = createJavaScriptRegexEngine({ forgiving: true }); +/** + * A custom theme object compatible with shiki's ThemeRegistrationAny. + * Must have a `name` property for identification and caching. + */ +export interface CustomTheme { + name: string; + [key: string]: unknown; +} + +/** + * Theme input type that accepts either a built-in theme name or a custom theme object. + */ +export type ThemeInput = BundledTheme | CustomTheme; + /** * Result from code highlighting */ @@ -25,7 +39,7 @@ export type HighlightResult = TokensResult; export interface HighlightOptions { code: string; language: BundledLanguage; - themes: [string, string]; + themes: [string, string] | [ThemeInput, ThemeInput]; } /** @@ -54,6 +68,14 @@ export interface CodeHighlighterPlugin { * Check if language is supported */ supportsLanguage: (language: BundledLanguage) => boolean; + /** + * Get list of supported languages + */ + getSupportedLanguages: () => BundledLanguage[]; + /** + * Get the configured themes + */ + getThemes: () => [ThemeInput, ThemeInput]; type: "code-highlighter"; } @@ -63,9 +85,10 @@ export interface CodeHighlighterPlugin { export interface CodePluginOptions { /** * Default themes for syntax highlighting [light, dark] + * Accepts built-in theme names or custom theme objects. * @default ["github-light", "github-dark"] */ - themes?: [BundledTheme, BundledTheme]; + themes?: [ThemeInput, ThemeInput]; } const languageAliases = Object.fromEntries( @@ -104,10 +127,13 @@ const tokensCache = new Map(); // Subscribers for async token updates const subscribers = new Map void>>(); +const getThemeName = (theme: ThemeInput): string => + typeof theme === "string" ? theme : theme.name; + const getHighlighterCacheKey = ( language: BundledLanguage, - themeNames: [string, string] -) => `${language}-${themeNames[0]}-${themeNames[1]}`; + themes: [ThemeInput, ThemeInput] +) => `${language}-${getThemeName(themes[0])}-${getThemeName(themes[1])}`; const getTokensCacheKey = ( code: string, @@ -121,9 +147,9 @@ const getTokensCacheKey = ( const getHighlighter = ( language: BundledLanguage, - themeNames: [string, string] + themes: [ThemeInput, ThemeInput] ): Promise> => { - const cacheKey = getHighlighterCacheKey(language, themeNames); + const cacheKey = getHighlighterCacheKey(language, themes); if (highlighterCache.has(cacheKey)) { return highlighterCache.get(cacheKey) as Promise< @@ -132,7 +158,7 @@ const getHighlighter = ( } const highlighterPromise = createHighlighter({ - themes: themeNames, + themes: themes as (string | Record)[], langs: [language], engine: jsEngine, }); @@ -147,7 +173,7 @@ const getHighlighter = ( export function createCodePlugin( options: CodePluginOptions = {} ): CodeHighlighterPlugin { - const defaultThemes: [BundledTheme, BundledTheme] = options.themes ?? [ + const defaultThemes: [ThemeInput, ThemeInput] = options.themes ?? [ "github-light", "github-dark", ]; @@ -165,19 +191,23 @@ export function createCodePlugin( return Array.from(languageNames); }, - getThemes(): [BundledTheme, BundledTheme] { + getThemes(): [ThemeInput, ThemeInput] { return defaultThemes; }, highlight( - { code, language, themes: themeNames }: HighlightOptions, + { code, language, themes }: HighlightOptions, callback?: (result: HighlightResult) => void ): HighlightResult | null { const resolvedLanguage = normalizeLanguage(language); + const themeNames: [string, string] = [ + getThemeName(themes[0]), + getThemeName(themes[1]), + ]; const tokensCacheKey = getTokensCacheKey( code, resolvedLanguage, - themeNames as [string, string] + themeNames ); // Return cached result if available @@ -197,10 +227,7 @@ export function createCodePlugin( } // Start highlighting in background - getHighlighter( - resolvedLanguage as BundledLanguage, - themeNames as [string, string] - ) + getHighlighter(resolvedLanguage as BundledLanguage, defaultThemes) .then((highlighter) => { const availableLangs = highlighter.getLoadedLanguages(); const langToUse = ( diff --git a/packages/streamdown/index.tsx b/packages/streamdown/index.tsx index 1f1d179e..20aeccd7 100644 --- a/packages/streamdown/index.tsx +++ b/packages/streamdown/index.tsx @@ -16,7 +16,6 @@ import rehypeRaw from "rehype-raw"; import rehypeSanitize, { defaultSchema } from "rehype-sanitize"; import remarkGfm from "remark-gfm"; import remend, { type RemendOptions } from "remend"; -import type { BundledTheme } from "shiki"; import type { Pluggable } from "unified"; import { type AnimateOptions, createAnimatePlugin } from "./lib/animate"; import { BlockIncompleteContext } from "./lib/block-incomplete-context"; @@ -25,7 +24,7 @@ import { hasIncompleteCodeFence, hasTable } from "./lib/incomplete-code-utils"; import { Markdown, type Options } from "./lib/markdown"; import { parseMarkdownIntoBlocks } from "./lib/parse-blocks"; import { PluginContext } from "./lib/plugin-context"; -import type { PluginConfig } from "./lib/plugin-types"; +import type { PluginConfig, ThemeInput } from "./lib/plugin-types"; import { preprocessCustomTags } from "./lib/preprocess-custom-tags"; import { cn } from "./lib/utils"; @@ -45,10 +44,12 @@ export { parseMarkdownIntoBlocks } from "./lib/parse-blocks"; export type { CjkPlugin, CodeHighlighterPlugin, + CustomTheme, DiagramPlugin, HighlightOptions, MathPlugin, PluginConfig, + ThemeInput, } from "./lib/plugin-types"; // Patterns for HTML indentation normalization @@ -128,7 +129,7 @@ export type StreamdownProps = Options & { /** Normalize HTML block indentation to prevent 4+ spaces being treated as code blocks. @default false */ normalizeHtmlIndentation?: boolean; className?: string; - shikiTheme?: [BundledTheme, BundledTheme]; + shikiTheme?: [ThemeInput, ThemeInput]; mermaid?: MermaidOptions; controls?: ControlsConfig; isAnimating?: boolean; @@ -179,12 +180,12 @@ const carets = { // Combined context for better performance - reduces React tree depth from 5 nested providers to 1 export interface StreamdownContextType { + shikiTheme: [ThemeInput, ThemeInput]; controls: ControlsConfig; isAnimating: boolean; linkSafety?: LinkSafetyConfig; mermaid?: MermaidOptions; mode: "static" | "streaming"; - shikiTheme: [BundledTheme, BundledTheme]; } const defaultStreamdownContext: StreamdownContextType = { @@ -285,7 +286,7 @@ export const Block = memo( Block.displayName = "Block"; -const defaultShikiTheme: [BundledTheme, BundledTheme] = [ +const defaultShikiTheme: [ThemeInput, ThemeInput] = [ "github-light", "github-dark", ]; diff --git a/packages/streamdown/lib/plugin-types.ts b/packages/streamdown/lib/plugin-types.ts index e4a293f7..62ace602 100644 --- a/packages/streamdown/lib/plugin-types.ts +++ b/packages/streamdown/lib/plugin-types.ts @@ -1,5 +1,20 @@ import type { MermaidConfig } from "mermaid"; import type { BundledLanguage, BundledTheme } from "shiki"; + +/** + * A custom theme object compatible with shiki's ThemeRegistrationAny. + * Must have a `name` property for identification and caching. + */ +export interface CustomTheme { + name: string; + [key: string]: unknown; +} + +/** + * Theme input type that accepts either a built-in theme name or a custom theme object. + */ +export type ThemeInput = BundledTheme | CustomTheme; + import type { Pluggable } from "unified"; /** @@ -30,7 +45,7 @@ export interface HighlightResult { export interface HighlightOptions { code: string; language: BundledLanguage; - themes: [string, string]; + themes: [string, string] | [ThemeInput, ThemeInput]; } /** @@ -59,6 +74,14 @@ export interface CodeHighlighterPlugin { * Check if language is supported */ supportsLanguage: (language: BundledLanguage) => boolean; + /** + * Get list of supported languages + */ + getSupportedLanguages: () => BundledLanguage[]; + /** + * Get the configured themes + */ + getThemes: () => [ThemeInput, ThemeInput]; type: "code-highlighter"; } From 77c649fc07b5e0bec15ecfdcdf236ea2064a3f9c Mon Sep 17 00:00:00 2001 From: Dmitrii Troitskii Date: Sun, 22 Feb 2026 10:10:11 +0000 Subject: [PATCH 2/5] fix: pass per-call themes to getHighlighter instead of defaultThemes --- packages/streamdown-code/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/streamdown-code/index.ts b/packages/streamdown-code/index.ts index d2475c33..ecccba0f 100644 --- a/packages/streamdown-code/index.ts +++ b/packages/streamdown-code/index.ts @@ -227,7 +227,10 @@ export function createCodePlugin( } // Start highlighting in background - getHighlighter(resolvedLanguage as BundledLanguage, defaultThemes) + getHighlighter( + resolvedLanguage as BundledLanguage, + themes as [ThemeInput, ThemeInput] + ) .then((highlighter) => { const availableLangs = highlighter.getLoadedLanguages(); const langToUse = ( From a24ebbc9a5fe314fc23b7656cf332dff90434635 Mon Sep 17 00:00:00 2001 From: Dmitrii Troitskii Date: Sun, 22 Feb 2026 11:35:14 +0000 Subject: [PATCH 3/5] fix: resolve duplicate interface properties and type errors in CodeHighlighterPlugin --- packages/streamdown-code/index.ts | 12 ++---------- packages/streamdown/index.tsx | 2 +- packages/streamdown/lib/plugin-types.ts | 10 +--------- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/packages/streamdown-code/index.ts b/packages/streamdown-code/index.ts index ecccba0f..c57710ea 100644 --- a/packages/streamdown-code/index.ts +++ b/packages/streamdown-code/index.ts @@ -53,7 +53,7 @@ export interface CodeHighlighterPlugin { /** * Get the configured themes */ - getThemes: () => [BundledTheme, BundledTheme]; + getThemes: () => [ThemeInput, ThemeInput]; /** * Highlight code and return tokens * Returns null if highlighting not ready yet (async loading) @@ -68,14 +68,6 @@ export interface CodeHighlighterPlugin { * Check if language is supported */ supportsLanguage: (language: BundledLanguage) => boolean; - /** - * Get list of supported languages - */ - getSupportedLanguages: () => BundledLanguage[]; - /** - * Get the configured themes - */ - getThemes: () => [ThemeInput, ThemeInput]; type: "code-highlighter"; } @@ -127,7 +119,7 @@ const tokensCache = new Map(); // Subscribers for async token updates const subscribers = new Map void>>(); -const getThemeName = (theme: ThemeInput): string => +const getThemeName = (theme: string | ThemeInput): string => typeof theme === "string" ? theme : theme.name; const getHighlighterCacheKey = ( diff --git a/packages/streamdown/index.tsx b/packages/streamdown/index.tsx index 20aeccd7..8d06756f 100644 --- a/packages/streamdown/index.tsx +++ b/packages/streamdown/index.tsx @@ -180,12 +180,12 @@ const carets = { // Combined context for better performance - reduces React tree depth from 5 nested providers to 1 export interface StreamdownContextType { - shikiTheme: [ThemeInput, ThemeInput]; controls: ControlsConfig; isAnimating: boolean; linkSafety?: LinkSafetyConfig; mermaid?: MermaidOptions; mode: "static" | "streaming"; + shikiTheme: [ThemeInput, ThemeInput]; } const defaultStreamdownContext: StreamdownContextType = { diff --git a/packages/streamdown/lib/plugin-types.ts b/packages/streamdown/lib/plugin-types.ts index 62ace602..57b6f86a 100644 --- a/packages/streamdown/lib/plugin-types.ts +++ b/packages/streamdown/lib/plugin-types.ts @@ -59,7 +59,7 @@ export interface CodeHighlighterPlugin { /** * Get the configured themes */ - getThemes: () => [BundledTheme, BundledTheme]; + getThemes: () => [ThemeInput, ThemeInput]; /** * Highlight code and return tokens * Returns null if highlighting not ready yet (async loading) @@ -74,14 +74,6 @@ export interface CodeHighlighterPlugin { * Check if language is supported */ supportsLanguage: (language: BundledLanguage) => boolean; - /** - * Get list of supported languages - */ - getSupportedLanguages: () => BundledLanguage[]; - /** - * Get the configured themes - */ - getThemes: () => [ThemeInput, ThemeInput]; type: "code-highlighter"; } From 771dcd242360a853ddf547a23b0e9ed86d4aea22 Mon Sep 17 00:00:00 2001 From: Hayden Bleasel Date: Tue, 3 Mar 2026 13:27:47 -0800 Subject: [PATCH 4/5] Add changeset for custom Shiki themes --- .changeset/custom-shiki-themes.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/custom-shiki-themes.md diff --git a/.changeset/custom-shiki-themes.md b/.changeset/custom-shiki-themes.md new file mode 100644 index 00000000..03780b6f --- /dev/null +++ b/.changeset/custom-shiki-themes.md @@ -0,0 +1,6 @@ +--- +"streamdown": patch +"streamdown-code": patch +--- + +Support custom Shiki themes in code blocks From 60aba578e28ab304ba598404d1451b54c81b657e Mon Sep 17 00:00:00 2001 From: Hayden Bleasel Date: Tue, 3 Mar 2026 14:35:44 -0800 Subject: [PATCH 5/5] fix: use shiki's ThemeRegistrationAny, deduplicate types, tighten API - Replace custom CustomTheme interface with shiki's ThemeRegistrationAny - Remove duplicated type definitions across packages - Simplify HighlightOptions.themes to [ThemeInput, ThemeInput] - Remove unsafe cast in createHighlighter call - Bump changeset to minor (new feature, not patch) Co-Authored-By: Claude Opus 4.6 --- .changeset/custom-shiki-themes.md | 4 +-- .../streamdown-code/__tests__/index.test.ts | 13 ++++----- packages/streamdown-code/index.ts | 29 +++++-------------- packages/streamdown/index.tsx | 2 +- packages/streamdown/lib/plugin-types.ts | 25 +++++----------- 5 files changed, 24 insertions(+), 49 deletions(-) diff --git a/.changeset/custom-shiki-themes.md b/.changeset/custom-shiki-themes.md index 03780b6f..971a4624 100644 --- a/.changeset/custom-shiki-themes.md +++ b/.changeset/custom-shiki-themes.md @@ -1,6 +1,6 @@ --- -"streamdown": patch -"streamdown-code": patch +"streamdown": minor +"streamdown-code": minor --- Support custom Shiki themes in code blocks diff --git a/packages/streamdown-code/__tests__/index.test.ts b/packages/streamdown-code/__tests__/index.test.ts index f175d132..e5dff7dc 100644 --- a/packages/streamdown-code/__tests__/index.test.ts +++ b/packages/streamdown-code/__tests__/index.test.ts @@ -1,6 +1,5 @@ -import type { BundledLanguage } from "shiki"; +import type { BundledLanguage, ThemeRegistrationAny } from "shiki"; import { describe, expect, it, vi } from "vitest"; -import type { CustomTheme } from "../index"; import { code, createCodePlugin } from "../index"; describe("code", () => { @@ -306,13 +305,13 @@ describe("createCodePlugin", () => { }); it("should create plugin with custom theme objects", () => { - const customLight: CustomTheme = { + const customLight: ThemeRegistrationAny = { name: "my-light-theme", type: "light", colors: { "editor.background": "#ffffff" }, tokenColors: [], }; - const customDark: CustomTheme = { + const customDark: ThemeRegistrationAny = { name: "my-dark-theme", type: "dark", colors: { "editor.background": "#1e1e1e" }, @@ -327,7 +326,7 @@ describe("createCodePlugin", () => { }); it("should create plugin with mixed built-in and custom themes", () => { - const customDark: CustomTheme = { + const customDark: ThemeRegistrationAny = { name: "my-dark-theme", type: "dark", colors: { "editor.background": "#1e1e1e" }, @@ -342,7 +341,7 @@ describe("createCodePlugin", () => { }); it("should highlight code with custom theme objects", async () => { - const customLight: CustomTheme = { + const customLight: ThemeRegistrationAny = { name: "custom-light", type: "light", colors: { @@ -351,7 +350,7 @@ describe("createCodePlugin", () => { }, tokenColors: [], }; - const customDark: CustomTheme = { + const customDark: ThemeRegistrationAny = { name: "custom-dark", type: "dark", colors: { diff --git a/packages/streamdown-code/index.ts b/packages/streamdown-code/index.ts index c57710ea..78d7a8c9 100644 --- a/packages/streamdown-code/index.ts +++ b/packages/streamdown-code/index.ts @@ -3,6 +3,7 @@ import { type BundledLanguage, type BundledTheme, + type ThemeRegistrationAny, bundledLanguages, bundledLanguagesInfo, createHighlighter, @@ -14,19 +15,7 @@ import { createJavaScriptRegexEngine } from "shiki/engine/javascript"; const jsEngine = createJavaScriptRegexEngine({ forgiving: true }); -/** - * A custom theme object compatible with shiki's ThemeRegistrationAny. - * Must have a `name` property for identification and caching. - */ -export interface CustomTheme { - name: string; - [key: string]: unknown; -} - -/** - * Theme input type that accepts either a built-in theme name or a custom theme object. - */ -export type ThemeInput = BundledTheme | CustomTheme; +export type ThemeInput = BundledTheme | ThemeRegistrationAny; /** * Result from code highlighting @@ -39,7 +28,7 @@ export type HighlightResult = TokensResult; export interface HighlightOptions { code: string; language: BundledLanguage; - themes: [string, string] | [ThemeInput, ThemeInput]; + themes: [ThemeInput, ThemeInput]; } /** @@ -77,7 +66,6 @@ export interface CodeHighlighterPlugin { export interface CodePluginOptions { /** * Default themes for syntax highlighting [light, dark] - * Accepts built-in theme names or custom theme objects. * @default ["github-light", "github-dark"] */ themes?: [ThemeInput, ThemeInput]; @@ -119,8 +107,8 @@ const tokensCache = new Map(); // Subscribers for async token updates const subscribers = new Map void>>(); -const getThemeName = (theme: string | ThemeInput): string => - typeof theme === "string" ? theme : theme.name; +const getThemeName = (theme: ThemeInput): string => + typeof theme === "string" ? theme : (theme.name ?? "custom"); const getHighlighterCacheKey = ( language: BundledLanguage, @@ -150,7 +138,7 @@ const getHighlighter = ( } const highlighterPromise = createHighlighter({ - themes: themes as (string | Record)[], + themes, langs: [language], engine: jsEngine, }); @@ -219,10 +207,7 @@ export function createCodePlugin( } // Start highlighting in background - getHighlighter( - resolvedLanguage as BundledLanguage, - themes as [ThemeInput, ThemeInput] - ) + getHighlighter(resolvedLanguage as BundledLanguage, themes) .then((highlighter) => { const availableLangs = highlighter.getLoadedLanguages(); const langToUse = ( diff --git a/packages/streamdown/index.tsx b/packages/streamdown/index.tsx index 47508be8..e4633fe8 100644 --- a/packages/streamdown/index.tsx +++ b/packages/streamdown/index.tsx @@ -45,13 +45,13 @@ export { parseMarkdownIntoBlocks } from "./lib/parse-blocks"; export type { CjkPlugin, CodeHighlighterPlugin, - CustomTheme, DiagramPlugin, HighlightOptions, MathPlugin, PluginConfig, ThemeInput, } from "./lib/plugin-types"; +export type { ThemeRegistrationAny } from "shiki"; export { TableCopyDropdown, type TableCopyDropdownProps, diff --git a/packages/streamdown/lib/plugin-types.ts b/packages/streamdown/lib/plugin-types.ts index 57b6f86a..ea124186 100644 --- a/packages/streamdown/lib/plugin-types.ts +++ b/packages/streamdown/lib/plugin-types.ts @@ -1,22 +1,13 @@ import type { MermaidConfig } from "mermaid"; -import type { BundledLanguage, BundledTheme } from "shiki"; - -/** - * A custom theme object compatible with shiki's ThemeRegistrationAny. - * Must have a `name` property for identification and caching. - */ -export interface CustomTheme { - name: string; - [key: string]: unknown; -} - -/** - * Theme input type that accepts either a built-in theme name or a custom theme object. - */ -export type ThemeInput = BundledTheme | CustomTheme; - +import type { + BundledLanguage, + BundledTheme, + ThemeRegistrationAny, +} from "shiki"; import type { Pluggable } from "unified"; +export type ThemeInput = BundledTheme | ThemeRegistrationAny; + /** * A single token in a highlighted line */ @@ -45,7 +36,7 @@ export interface HighlightResult { export interface HighlightOptions { code: string; language: BundledLanguage; - themes: [string, string] | [ThemeInput, ThemeInput]; + themes: [ThemeInput, ThemeInput]; } /**