diff --git a/.changeset/fix-shiki-type-declarations.md b/.changeset/fix-shiki-type-declarations.md new file mode 100644 index 00000000..38fb891c --- /dev/null +++ b/.changeset/fix-shiki-type-declarations.md @@ -0,0 +1,7 @@ +--- +"streamdown": patch +--- + +Fix type declarations requiring a `shiki` install. + +`BundledLanguage`, `BundledTheme`, and `ThemeRegistrationAny` are now defined locally and re-exported from `streamdown`, so consumers can type-check without installing `shiki`. Runtime highlighting remains in `@streamdown/code`, which still depends on `shiki`. diff --git a/packages/streamdown/index.tsx b/packages/streamdown/index.tsx index be32d9fd..736bd597 100644 --- a/packages/streamdown/index.tsx +++ b/packages/streamdown/index.tsx @@ -46,11 +46,6 @@ import { } from "./lib/translations-context"; import { createCn } from "./lib/utils"; -export type { - BundledLanguage, - BundledTheme, - ThemeRegistrationAny, -} from "shiki"; export type { AnimateOptions } from "./lib/animate"; // biome-ignore lint/performance/noBarrelFile: "required" export { createAnimatePlugin } from "./lib/animate"; @@ -73,6 +68,8 @@ export type { export { defaultUrlTransform } from "./lib/markdown"; export { parseMarkdownIntoBlocks } from "./lib/parse-blocks"; export type { + BundledLanguage, + BundledTheme, CjkPlugin, CodeHighlighterPlugin, CustomRenderer, @@ -82,6 +79,7 @@ export type { MathPlugin, PluginConfig, ThemeInput, + ThemeRegistrationAny, } from "./lib/plugin-types"; export { TableCopyDropdown, diff --git a/packages/streamdown/lib/code-block/highlighted-body.tsx b/packages/streamdown/lib/code-block/highlighted-body.tsx index 87ef2924..fe68d013 100644 --- a/packages/streamdown/lib/code-block/highlighted-body.tsx +++ b/packages/streamdown/lib/code-block/highlighted-body.tsx @@ -1,8 +1,7 @@ import { type HTMLAttributes, useContext, useEffect, useState } from "react"; -import type { BundledLanguage } from "shiki"; import { StreamdownContext } from "../../index"; import { useCodePlugin } from "../plugin-context"; -import type { HighlightResult } from "../plugin-types"; +import type { BundledLanguage, HighlightResult } from "../plugin-types"; import { CodeBlockBody } from "./body"; type HighlightedCodeBlockBodyProps = HTMLAttributes & { diff --git a/packages/streamdown/lib/plugin-types.ts b/packages/streamdown/lib/plugin-types.ts index 95130362..01c45b64 100644 --- a/packages/streamdown/lib/plugin-types.ts +++ b/packages/streamdown/lib/plugin-types.ts @@ -1,11 +1,17 @@ import type { MermaidConfig } from "mermaid"; import type React from "react"; +import type { Pluggable } from "unified"; import type { BundledLanguage, BundledTheme, ThemeRegistrationAny, -} from "shiki"; -import type { Pluggable } from "unified"; +} from "./shiki-types"; + +export type { + BundledLanguage, + BundledTheme, + ThemeRegistrationAny, +} from "./shiki-types"; export type ThemeInput = BundledTheme | ThemeRegistrationAny; @@ -42,30 +48,34 @@ export interface HighlightOptions { /** * Plugin for code syntax highlighting (Shiki) + * + * Method syntax is intentional: parameter types stay bivariant so plugins + * from `@streamdown/code` (which use Shiki's narrower language/theme unions) + * remain assignable without requiring a `shiki` type dependency here. */ export interface CodeHighlighterPlugin { /** * Get list of supported languages */ - getSupportedLanguages: () => BundledLanguage[]; + getSupportedLanguages(): BundledLanguage[]; /** * Get the configured themes */ - getThemes: () => [ThemeInput, ThemeInput]; + getThemes(): [ThemeInput, ThemeInput]; /** * Highlight code and return tokens * Returns null if highlighting not ready yet (async loading) * Use callback for async result */ - highlight: ( + highlight( options: HighlightOptions, callback?: (result: HighlightResult) => void - ) => HighlightResult | null; + ): HighlightResult | null; name: "shiki"; /** * Check if language is supported */ - supportsLanguage: (language: BundledLanguage) => boolean; + supportsLanguage(language: BundledLanguage): boolean; type: "code-highlighter"; } diff --git a/packages/streamdown/lib/shiki-types.ts b/packages/streamdown/lib/shiki-types.ts new file mode 100644 index 00000000..5acd6d66 --- /dev/null +++ b/packages/streamdown/lib/shiki-types.ts @@ -0,0 +1,43 @@ +/** + * Types compatible with Shiki, defined locally so consumers of `streamdown` + * can type-check without installing the `shiki` package. + * + * Runtime highlighting lives in `@streamdown/code`, which depends on `shiki`. + * Streamdown only needs these types for its plugin API surface (`shikiTheme`, + * `CodeHighlighterPlugin`, and related re-exports). + * + * @see https://shiki.style/languages + * @see https://shiki.style/themes + */ + +/** + * Language identifier for syntax highlighting. + * Compatible with Shiki's `BundledLanguage`. + */ +export type BundledLanguage = string; + +/** + * Built-in theme name for syntax highlighting. + * Compatible with Shiki's `BundledTheme`. + */ +export type BundledTheme = string; + +/** + * Custom theme registration object compatible with Shiki's + * `ThemeRegistrationAny` (raw, resolved, or intermediate forms). + * + * Kept structural and permissive so custom theme objects from + * `@streamdown/code` / Shiki remain assignable without a type dependency. + */ +export interface ThemeRegistrationAny { + bg?: string; + colors?: Record; + displayName?: string; + fg?: string; + name?: string; + semanticHighlighting?: boolean; + semanticTokenColors?: Record; + settings?: unknown[]; + tokenColors?: unknown[]; + type?: "light" | "dark"; +} diff --git a/packages/streamdown/package.json b/packages/streamdown/package.json index b44b3474..cecaba75 100644 --- a/packages/streamdown/package.json +++ b/packages/streamdown/package.json @@ -52,7 +52,6 @@ "react-markdown": "^10.1.0", "rehype-parse": "^9.0.1", "rehype-stringify": "^10.0.1", - "shiki": "^3.19.0", "tsup": "^8.5.1", "vitest": "^4.0.15" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a055b22c..2e7ac6d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -158,7 +158,7 @@ importers: version: 1.6.1(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) '@vercel/geistdocs': specifier: 1.11.0 - version: 1.11.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@tanstack/react-router@1.151.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(micromark-util-types@2.0.2)(micromark@4.0.2)(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(unified@11.0.5)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) + version: 1.11.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@tanstack/react-router@1.151.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(unified@11.0.5)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) '@vercel/speed-insights': specifier: ^1.3.1 version: 1.3.1(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) @@ -377,9 +377,6 @@ importers: rehype-stringify: specifier: ^10.0.1 version: 10.0.1 - shiki: - specifier: ^3.19.0 - version: 3.21.0 tsup: specifier: ^8.5.1 version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3) @@ -8933,7 +8930,7 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@streamdown/cjk@1.0.3(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(react@19.2.3)(unified@11.0.5)': + '@streamdown/cjk@1.0.3(@types/mdast@4.0.4)(react@19.2.3)(unified@11.0.5)': dependencies: react: 19.2.3 remark-cjk-friendly: 2.0.1(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(unified@11.0.5) @@ -9347,13 +9344,13 @@ snapshots: next: 16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 - '@vercel/geistdocs@1.11.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@tanstack/react-router@1.151.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(micromark-util-types@2.0.2)(micromark@4.0.2)(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(unified@11.0.5)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': + '@vercel/geistdocs@1.11.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@tanstack/react-router@1.151.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(tailwindcss@4.1.18)(unified@11.0.5)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': dependencies: '@ai-sdk/react': 3.0.201(react@19.2.3)(zod@4.3.5) '@clack/prompts': 0.11.0 '@icons-pack/react-simple-icons': 13.8.0(react@19.2.3) '@orama/tokenizers': 3.1.18 - '@streamdown/cjk': 1.0.3(@types/mdast@4.0.4)(micromark-util-types@2.0.2)(micromark@4.0.2)(react@19.2.3)(unified@11.0.5) + '@streamdown/cjk': 1.0.3(@types/mdast@4.0.4)(react@19.2.3)(unified@11.0.5) '@streamdown/code': 1.1.1(react@19.2.3) '@vercel/agent-readability': 0.2.1(next@16.2.6(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) ai: 6.0.199(zod@4.3.5)