From 839fc697b826b0dc144476ba354ab44613d33eb2 Mon Sep 17 00:00:00 2001 From: David McCabe <43038510+mccabe-david@users.noreply.github.com> Date: Thu, 8 Jan 2026 17:02:21 -0500 Subject: [PATCH] add optional header --- package.json | 2 +- packages/streamdown/index.tsx | 22 ++++++++++++++----- packages/streamdown/lib/code-block/header.tsx | 7 +++++- packages/streamdown/lib/code-block/index.tsx | 5 ++++- packages/streamdown/lib/components.tsx | 1 + pnpm-workspace.yaml | 2 +- 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index ddfe25c4..9724ecd3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "streamdown-monorepo", "private": true, "scripts": { - "build": "turbo run build", + "build": "pnpm dlx rimraf packages/streamdown/dist && turbo run build --force", "dev": "turbo run dev", "check": "ultracite check", "fix": "ultracite fix", diff --git a/packages/streamdown/index.tsx b/packages/streamdown/index.tsx index 69a79acb..e63b0fd3 100644 --- a/packages/streamdown/index.tsx +++ b/packages/streamdown/index.tsx @@ -5,6 +5,8 @@ import { type CSSProperties, createContext, memo, + ReactNode, + ComponentType, useEffect, useId, useMemo, @@ -28,6 +30,7 @@ import { parseMarkdownIntoBlocks } from "./lib/parse-blocks"; import { remarkCjkAutolinkBoundary } from "./lib/remark/cjk-autolink"; import { cn } from "./lib/utils"; import packageJson from "./package.json"; +import { CodeBlock } from "./lib/code-block"; // Regex patterns defined at top level for performance const MIDDLE_DOLLAR_PATTERN = /[^$]\$[^$]/; @@ -84,6 +87,7 @@ export type StreamdownProps = Options & { caret?: keyof typeof carets; cdnUrl?: string | null; remend?: RemendOptions; + extraCodeHeader?: ReactNode; }; export const defaultRehypePlugins: Record = { @@ -287,6 +291,7 @@ export const Streamdown = memo( caret, cdnUrl = defaultCdnUrl, remend: remendOptions, + extraCodeHeader, ...props }: StreamdownProps) => { // All hooks must be called before any conditional returns @@ -347,13 +352,20 @@ export const Streamdown = memo( ); // Memoize merged components to avoid recreating on every render - const mergedComponents = useMemo( - () => ({ + const mergedComponents = useMemo(() => { + if (!extraCodeHeader) { + return { ...defaultComponents, ...components }; + } + + const Code = defaultComponents?.code as ComponentType; + return { ...defaultComponents, + code: (props: any) => ( + + ), ...components, - }), - [components] - ); + }; + }, [components, extraCodeHeader]); // Only load KaTeX CSS when math syntax is detected in content useEffect(() => { diff --git a/packages/streamdown/lib/code-block/header.tsx b/packages/streamdown/lib/code-block/header.tsx index 1f1f7458..03489144 100644 --- a/packages/streamdown/lib/code-block/header.tsx +++ b/packages/streamdown/lib/code-block/header.tsx @@ -3,11 +3,13 @@ import type { ReactNode } from "react"; type CodeBlockHeaderProps = { language: string; children: ReactNode; + extraComponent: ReactNode }; export const CodeBlockHeader = ({ language, children, + extraComponent }: CodeBlockHeaderProps) => (
{language} -
{children}
+
+ {extraComponent} + {children} +
); diff --git a/packages/streamdown/lib/code-block/index.tsx b/packages/streamdown/lib/code-block/index.tsx index 6c3b6f93..9364b977 100644 --- a/packages/streamdown/lib/code-block/index.tsx +++ b/packages/streamdown/lib/code-block/index.tsx @@ -4,6 +4,7 @@ import { useEffect, useMemo, useState, + ReactNode } from "react"; import type { TokensResult } from "shiki"; import { StreamdownContext } from "../../index"; @@ -16,6 +17,7 @@ import { getHighlightedTokens } from "./highlight"; type CodeBlockProps = HTMLAttributes & { code: string; language: string; + extraCodeHeader?: ReactNode }; export const CodeBlock = ({ @@ -23,6 +25,7 @@ export const CodeBlock = ({ language, className, children, + extraCodeHeader, ...rest }: CodeBlockProps) => { const { shikiTheme, cdnUrl } = useContext(StreamdownContext); @@ -78,7 +81,7 @@ export const CodeBlock = ({ return ( - {children} + {children} } > {showCodeControls ? ( <> diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index db3ae5a3..e6d00fe9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,6 @@ packages: - "apps/*" - - "packages/*" + - "packages/streamdown" onlyBuiltDependencies: - '@vercel/speed-insights'