56 Commits

Author SHA1 Message Date
Dmitrii 163c63bc4e fix(code-block): use absolute positioning for action buttons to fix clicks in nested scroll containers (#498)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-09-10 13:04:55 +02:00
Aradhya C P b734cbf1e4 feat: add configurable download filenames through unified controls (#559)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-08-24 11:12:26 +02:00
dasheidt 725e390fc4 fix(code-block): forward rest props through block code (#585)
Co-authored-by: nrhof <nrhof@nrhof-Mac-mini.local>
2026-08-21 13:34:55 +02:00
Dmitrii 5faa6fa680 feat: add scrollable code blocks and tables with auto-scroll during streaming (#444)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-08-19 21:15:24 +02:00
Shayan 7e824007a3 fix: detect static text direction per block (#569)
Co-authored-by: Shayan SalehiRad <youtforsh@gmail.com>
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-08-14 15:59:00 +02:00
Aradhya C P b2500388a3 fix(a11y): add aria-labels for Mermaid toolbar buttons (#488)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-08-13 16:38:20 +02:00
Aradhya C P fe38e75ed9 fix: improve accessibility for code block control buttons (#560)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-08-12 17:46:14 +02:00
Aradhya C P dc3f1d2c27 fix: prevent code block line collapse when lineNumbers is disabled (#533)
Co-authored-by: Farnabaz <farnabaz@gmail.com>
2026-08-12 14:07:27 +02:00
Ghoshan Jaganathamani 9813dd646b fix(types): stop requiring shiki for type-checking streamdown (#565)
Co-authored-by: Ghoshan Jaganathamani <175198591+ghostyfreak@users.noreply.github.com>
2026-08-12 13:31:34 +02:00
Dmitrii d6666b6de3 feat: add lineNumbers prop to disable line numbers in code blocks (#460)
* feat: add lineNumbers prop to disable line numbers in code blocks

* docs: add lineNumbers prop and noLineNumbers meta string

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Troitskii <jsleitor@gmail.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-12 17:31:46 -07:00
Dmitrii 6a79e04690 fix(streamdown): preserve double newlines in literalTagContent tags (#459)
* fix(streamdown): preserve double newlines in literalTagContent tags

When a tag is in literalTagContent mode, double newlines (\n\n) inside
the tag content were incorrectly treated as paragraph separators by the
markdown parser, causing the content after the first blank line to be
excluded from the tag's children.

Fix: in preprocessLiteralTagContent, after escaping markdown metacharacters,
replace \n\n with &#10;&#10; HTML entities. This prevents the markdown
parser from interpreting blank lines as paragraph breaks while still
preserving the newline characters (rehype-raw decodes &#10; back to \n).

Fixes vercel/streamdown#456

* Run pnpm fix to resolve formatting issues

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix pre-existing formatting issue in code-block/index.tsx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix lint and formatting issues

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Troitskii <jsleitor@gmail.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:41:03 -07:00
Hayden Bleasel 6b49db1a20 Fix polynomial regular expression issue 2026-03-10 16:58:24 -07:00
Dmitrii add537414b fix(code-block): enable horizontal scrolling for long lines in code blocks (#439)
* fix(code-block): enable horizontal scrolling for long lines in code blocks

Change overflow-hidden to overflow-x-auto on the code block body container
so that long single-line comments and other long code lines are scrollable
horizontally instead of being silently clipped.

Fixes #438

* Add changeset for code block horizontal scroll fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Troitskii <jsleitor@gmail.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:59:05 -07:00
Jarvis f2a7e51ecb fix(code-block): preserve empty lines in code blocks (#420)
* fix(code-block): preserve empty lines in code blocks

## Summary

Fix empty lines collapsing in code blocks by inserting a newline character for empty rows.

## Problem

When rendering code blocks with empty lines, the `<span>` elements for empty rows had no content, causing them to collapse to zero height. This affected both visual display and copy behavior.

## Solution

Insert `"\n"` for empty lines instead of rendering an empty span. This ensures:
- **Visual**: Empty lines maintain proper height
- **Copy**: Copied text includes the empty lines correctly

## Changes

- `packages/streamdown/lib/code-block/body.tsx`: Add condition to detect empty rows (`row.length === 0` or single token with empty content) and render `"\n"` instead

* Fix lint issues

* Add tests

* Create fix-empty-lines.md

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
2026-03-03 15:58:29 -08:00
Dmitrii e129f09aa5 feat: add translations prop for i18n support (#415)
* feat: add translations/i18n support via translations prop

Implements #190 - adds a `translations` prop to the Streamdown component
that allows customizing all UI strings for internationalization.

Changes:
- Add `packages/streamdown/lib/translations-context.tsx` with
  StreamdownTranslations type, defaultTranslations, TranslationsContext,
  and useTranslations hook
- Add `translations?: Partial<StreamdownTranslations>` prop to Streamdown
- Wrap render output with TranslationsContext.Provider (both static and
  streaming modes)
- Export StreamdownTranslations type and defaultTranslations from index
- Replace all hardcoded UI strings in sub-components with translations:
  - code-block/copy-button: copyCode
  - code-block/download-button: downloadFile
  - mermaid/download-button: downloadDiagram, downloadDiagramAs{Svg,Png,Mmd},
    mermaidFormat{Svg,Png,Mmd}
  - mermaid/fullscreen-button: viewFullscreen, exitFullscreen
  - table/copy-dropdown: copyTable, copyTableAs{Markdown,Csv,Tsv},
    tableFormat{Markdown,Csv,Tsv}
  - table/download-dropdown: downloadTable, downloadTableAs{Csv,Markdown},
    tableFormat{Csv,Markdown}
  - image: imageNotAvailable, downloadImage
  - link-modal: openExternalLink, externalLinkWarning, close, copyLink,
    copied, openLink
- Add __tests__/translations.test.tsx with 12 tests covering defaults,
  custom translations, partial overrides, and context access
- Update download-dropdown.test.tsx to match new translation-based title

All 804 tests pass.

* Add changeset for translations prop

* Fix misplaced comments in translations type and broken test type assertion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Use value equality for translations memo to support inline objects

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Troitskii <jsleitor@gmail.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:17:11 -08:00
Dmitrii 57cd3b5a07 feat: allow customizing icons via icons prop (#414)
* feat: support custom starting line number in code blocks

Add support for specifying a custom starting line number via the code
fence meta string, e.g.:

```js startLine=10
const x = 1;
```

Implementation:
- Add `remarkCodeMeta` remark plugin that forwards the fenced-code meta
  string to hast as the `metastring` property so it is available to the
  custom React code component.
- Update the rehype-sanitize default schema to allow the `metastring`
  attribute on `code` elements.
- Parse `startLine=N` from the meta string in `CodeComponent` and pass
  the value down as a `startLine` prop.
- In `CodeBlockBody`, apply `counter-reset: line N-1` as an inline style
  when `startLine > 1`, which overrides the Tailwind counter-reset class
  and makes CSS counters begin from the specified number.
- Pass `startLine` through the `CodeBlock` and
  `HighlightedCodeBlockBody` call chains.
- Add 12 tests covering the remark plugin, CodeBlockBody prop, and
  CodeBlock integration.

Closes: resolves #287

* fix: lint errors — use literal keys, hoist regex, sort imports

* feat: allow customizing icons via icons prop

Add an IconContext-based system that lets users override any of the
built-in icons (CheckIcon, CopyIcon, DownloadIcon, etc.) by passing
a Partial<IconMap> via the new `icons` prop on <Streamdown>.

- Created lib/icon-context.tsx with IconMap type, IconProvider, and useIcons hook
- Updated all sub-components to consume icons via useIcons() instead of direct imports
- Added icons prop to StreamdownProps with IconProvider wrapper
- Exported IconMap type from package entry

Closes #412

* style: fix biome lint and formatting errors

* Merge branch 'main' into feat/custom-icons

* fix: review fixes for icons and startLine features

- Add missing changeset for icons feature (minor)
- Fix IconComponent type to include size prop matching actual usage
- Fix IconProvider memoization: use shallow comparison instead of
  referential equality so inline icon objects don't cause re-renders
- Move START_LINE_PATTERN constant below all imports
- Add bounds checking for startLine (must be >= 1)
- Convert dynamic imports to top-level imports in startLine tests
- Add icon-context tests (5 tests)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Troitskii <jsleitor@gmail.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:04:26 -08:00
Dmitrii 00872f0e10 feat: add Tailwind CSS prefix support (#408)
* feat: add Tailwind CSS prefix support

* fix: prevent double-prefixing of already-prefixed CSS classes

When cn() output (e.g. 'tw:size-full') is passed as className to a child
component that also calls cn() with the same prefix, prefixClasses() was
naively prepending the prefix again, producing 'tw:tw:size-full'.

Fix: skip classes that already start with the prefix+colon sentinel.

Add tests for both the all-already-prefixed and mixed cases.

* fix: lint errors — sort imports, format, hoist regex constants

* Add changeset for Tailwind prefix support

* fix: review fixes for tailwind prefix PR

- Bump changeset to minor (new feature, not patch)
- Rename shadowed cn import to baseCn in code-block/body.tsx
- Document that user className values are also prefixed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Dmitrii Troitskii <jsleitor@gmail.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:39:50 -08:00
Hayden Bleasel 1102f1855e Fix all Biome lint and formatting errors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 20:57:01 -08:00
Hayden Bleasel 0987479ebf Resolves #402 2026-02-18 20:21:55 -08:00
Hayden Bleasel 1ea5900b62 Redesign code block 2026-02-18 12:25:33 -08:00
Aradhya C P d73d7bbb4f feat: make code block header action buttons sticky (copy/download) (#401)
* refactor: simplify CodeBlockHeader component by removing unused children prop

* fix: remove overflow-hidden class from CodeBlockContainer

* feat: add sticky button for code block actions

* fix: update selector for code block action buttons in tests

* feat: add sticky action buttons to code block header for improved accessibility
2026-02-18 09:17:48 -08:00
Hayden Bleasel ce9b4c2336 Resolves #386 2026-02-17 17:21:12 -08:00
PaulSenon 15645da72e Feat/code block cls lower lazy boundary (#392)
* feat: Improve code block visual stability by moving lazy highlight boundary

* style: update contributing linter rules and fixed missed linter issues

* revert superfluous changes to CONTRIBUTING.md and geistdocs.tsx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:36:48 -08:00
Waseem 3657e42bcc feat: add useIsBlockIncomplete hook for detecting incomplete streaming blocks (#381)
* feat: add useIsBlockIncomplete hook for detecting incomplete streaming blocks

Custom components can now detect when the block they're rendering is still
being streamed (incomplete). This is useful for showing loading states in
code blocks during streaming.

- Add BlockIncompleteContext and useIsBlockIncomplete hook
- Add hasIncompleteCodeFence utility to detect unclosed code fences
- Calculate isIncomplete state per block during render
- Default CodeComponent uses the hook to set data-incomplete attribute
- Add comprehensive tests for the new functionality

* docs: add useIsBlockIncomplete documentation

- Add "Streaming State" section to components.mdx explaining the hook
- Add "Avoid Continuous Re-rendering" section to mermaid.mdx with example

* fix: support tilde code fences in hasIncompleteCodeFence

Adds support for detecting incomplete ~~~ code fences in addition to
backtick fences, per CommonMark/GFM spec.

* fix: address PR review — line-based fence detection, rename hook/context

- rewrite hasIncompleteCodeFence to walk line-by-line per CommonMark spec
  - fixes 6+ backtick fences being miscounted
  - fixes false positives from inline backticks in prose
  - respects fence character matching and length requirements
- rename block-position-context.ts → block-incomplete-context.ts
- rename useIsBlockIncomplete → useIsCodeFenceIncomplete
- add tests for edge cases (long fences, inline backticks, indentation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:14:57 -08:00
Hayden Bleasel 6be5da87df Resolves #374 2026-02-07 17:04:59 -08:00
Hayden Bleasel ca6feda934 Fix tests and lint 2026-01-20 14:44:23 -08:00
Hayden Bleasel e633ff73f2 Resolves #360 2026-01-20 14:40:32 -08:00
Hayden Bleasel 0b80aed583 Switch to plugin architecture (#352)
* Plugin trial

* Update docs and tests

* Update homepage add new section

* Update usage.tsx

* Split out CJK plugin

* Extract plugins into new packages

* Misc fixes

* Fix lint / formatting

* Fix: The Streamdown component's memo comparison doesn't compare the plugins prop, preventing re-renders when plugins change while other props stay the same

Co-authored-by: haydenbleasel <hello@haydenbleasel.com>

* Fix: TypeScript type mismatch at line 89 in `index.ts`: the visitor function's `index` parameter is typed as `number | undefined`, but the `visit` function expects `number | null`. The `undefined` type is not assignable to `number | null`.

This commit fixes the issue reported at /vercel/path0/packages/streamdown-cjk/index.ts:89

## TypeScript type incompatibility in visitor callback

**What fails:** TypeScript compiler fails during DTS (type definitions) build in `packages/streamdown-cjk/index.ts` at line 89

**How to reproduce:**
```bash
cd packages/streamdown-cjk
pnpm build
```

**Result:**
```
index.ts(89,3): error TS2769: No overload matches this call.
  Overload 1 of 2, '(tree: Root, check: "link", visitor: BuildVisitor<Root, "link">, reverse?: boolean | null | undefined): undefined', gave the following error.
    Argument of type '(node: Link, index: number | null, parent?: Parent) => number | undefined' is not assignable to parameter of type 'BuildVisitor<Root, "link">'.
      Types of parameters 'index' and 'index' are incompatible.
        Type 'number | undefined' is not assignable to type 'number | null'.
          Type 'undefined' is not assignable to type 'number | null'.
```

**Root cause:** The visitor callback function passed to the `visit()` function from `unist-util-visit` was declaring the `index` parameter as `number | null`, but the visitor can also receive `undefined` as the index value. The `BuildVisitor` type signature expects the callback to accept `number | null | undefined` to properly match the library's API.

**Fix:** Updated the `index` parameter type annotation on line 89 from `number | null` to `number | null | undefined` to match the actual possible values that the visitor receives and the expected `BuildVisitor` type signature.

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: haydenbleasel <hello@haydenbleasel.com>

* Fix tests

* Remove CDN paths

* Fix tests

* More cleanup

* Remove shiki from main bundle

* Update index.ts

* Cleanup test repo

* Cleanup website

* Delete next-env files

* Update .gitignore

* Fix lockfile

* Upgrade Next and React

* Simplify themes

* Update test site

* Misc fixes

* Type fixes

* Create perky-cobras-punch.md

---------

Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
2026-01-17 14:38:20 -08:00
Hayden Bleasel 61b368512d Fix Streamdown URL 2026-01-11 21:06:59 -08:00
Hayden Bleasel 010c1b3132 Full fixes 2026-01-09 14:26:43 -08:00
Hayden Bleasel 2509917b77 Run Ultracite 2026-01-09 14:24:07 -08:00
Hayden Bleasel 23f2a40612 Attempt to fallback to raw to prevent cdn-loader blocking 2026-01-08 21:25:46 -08:00
Hayden Bleasel 3880bab000 Recursively load language files 2026-01-06 17:11:04 -08:00
Hayden Bleasel 2b26070ebc Fix CDN implementation 2026-01-06 16:29:58 -08:00
Hayden Bleasel 3564f8e6c0 Replace lucide-react 2026-01-06 15:19:07 -08:00
Hayden Bleasel 20c7755bb5 Fix bundled themes, load alternate ones dynamically 2026-01-06 14:51:40 -08:00
Hayden Bleasel 8dcb49a9fd Fix bundle size by importing from shiki/core 2026-01-06 14:43:27 -08:00
Hayden Bleasel ee12ec8179 Resolves #297 2025-12-08 14:54:08 -08:00
Hayden Bleasel 75faa2ed26 Reduce bundle size by 98%, create Streamdown CDN (#295)
* Bundle minimal languages, load excess from CDN

* Update cdn-loader.ts

* Proxy rewrite CDN urls

* Create bold-worms-enjoy.md

* Update code-blocks.mdx

* Delete unused pages

* Add new CDN unit tests

* Run Ultracite

* Manual fixes

* Update sidebar.tsx
2025-12-07 22:16:45 -08:00
Hayden Bleasel d1635f016f Resolves #294 2025-12-07 20:49:58 -08:00
Hayden Bleasel d3ed120364 Remend (#279)
* Initial extraction

* Split up files

* Misc cleanup

* Break apart test file

* Add vitest/coverage-v8

* Increase coverage to 99.63%

* Fix cognitive complexity issues

* Run Ultracite

* Delete parse-incomplete-markdown.ts

* Add postbuild script for use client directive

* Update README.md

* Add default export

* Update docs

* Rename package

* Create wicked-badgers-decide.md

* Fix remend tests

* Fix remend benchmarks

* Fix remaining Streamdown tests

* Update underscore-bug.test.tsx

* Update test.yml

* Update test.yml
2025-12-03 11:17:18 -08:00
Eli Ozcan b2e832f667 fix: validate language before creating highlighter (#257)
* fix: validate language before highlighting

* fix: highlighter language validation function types

* add: changeset
2025-11-24 21:45:58 -08:00
kavinkasper a4899494e7 fix: add missing tooltip support to action buttons (#254)
* fix: add missing title attributes to action buttons for accessibility

* Create vast-cameras-move.md

---------

Co-authored-by: kavin kumar <kavin.kumar@agilepoint.com>
Co-authored-by: Hayden Bleasel <hello@haydenbleasel.com>
2025-11-24 09:46:17 -08:00
Hayden Bleasel 49c66e82e7 Misc cleanup 2025-11-23 14:44:51 -08:00
Hayden Bleasel 74cac00f9b Fix code block data attributes 2025-11-23 14:17:34 -08:00
Hayden Bleasel 1e547d492a Fix code blocks in dark mode 2025-11-23 13:58:18 -08:00
Hayden Bleasel dbd198f3cc Undo lucide import optimization 2025-11-23 11:32:29 -08:00
Hayden Bleasel 476167eab7 Bundle size optimization (#244)
* Direct icon imports

* Lazy load mermaid and shiki until used

* Only load KaTeX when maths is present

* Add changesets

* Improve test app output

* Create lucide-react.d.ts

* Update packages/streamdown/lib/code-block/skeleton.tsx

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2025-11-22 18:50:11 -08:00
Hayden Bleasel 62888665f8 Performance improvements, part 2 (#241)
* Add functional benchmarking suite

* Optimize regex performance

* Fix rendering issue with code blocks

* Fix bench commands

* Table optimizations

* Math Block Detection Caching

* Parse blocks optimizations

* More regex-to-loop optimizations

* Update layout.tsx

* Remove dependency on vfile

* Optimize string operations

* Create markdown.test.tsx

* Optimized cache key generation

* Fix display issue

* Add core Markdown parsing benchmarks

* Update section.tsx

* CSV / TSV escaping optimization

* More optimizations

* Run Ultracite

* Fix remaining lint issues
2025-11-21 17:45:53 -08:00
Hayden Bleasel c025bc5a31 Run Ultracite 2025-11-21 15:36:01 -08:00