* fix(react): hide MessageScroller until the opening position applies
A server-rendered transcript paints at scrollTop 0, then jumps after
hydration. Emit data-pending-scroll on first paint and hide the styled
viewport until defaultScrollPosition runs.
* style: format MessageScroller docs tables and class order
* feat(shadcn): add migrate base-color
Add a `base-color` migration that switches a project's base color and
rewrites its theme CSS variables, mirroring `migrate icons`. Only tokens
that still hold the source base color's value are replaced; customized
tokens are left untouched and reported. `--from` defaults to the current
`baseColor`.
* chore: add changeset
* chore: changeset
---------
Co-authored-by: shadcn <m@shadcn.com>
ensureRegistriesInConfig now checks package.json registries before
falling back to the registries index. Registries declared in
package.json are merged into the config in memory and never persisted
to components.json: the components.json write is built from the file
on disk, and init only persists registries discovered from the index.
- getRegistriesConfig now merges registries from both package.json and
components.json, with components.json taking precedence per key.
- registry add now writes to package.json when components.json is not
present, mirroring how registries are resolved.
* fix(shadcn): replace node-fetch with undici
Removes the transitive node-domexception deprecation warning triggered
on install by node-fetch -> fetch-blob. Uses Node's global fetch with
undici.ProxyAgent as the dispatcher when https_proxy is set, preserving
existing proxy support.
Also declares the implicit Node version requirement (>=20.18.1, matching
undici@7's engines field) now that Node 20 is entering maintenance EOL.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: changeset
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(shadcn): expand proxy env-var support via EnvHttpProxyAgent
Switch the registry fetcher from undici.ProxyAgent (single-URI) to
undici.EnvHttpProxyAgent, which honors HTTPS_PROXY, HTTP_PROXY,
NO_PROXY (and lowercase variants). Previously only https_proxy
lowercase was respected.
Extracts the dispatcher selection into createProxyDispatcher in
packages/shadcn/src/registry/proxy.ts, with unit tests covering
all env-var permutations and an integration test that spins up a
local CONNECT-tunneling proxy to verify end-to-end routing and
NO_PROXY bypass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update changeset
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(shadcn): add SOCKS and PAC proxy support
Extends the registry's proxy capabilities beyond HTTP/HTTPS to cover
the standard proxy mechanisms users encounter:
- SOCKS4/SOCKS5 via ALL_PROXY=socks5://... (curl convention).
Implementation uses the `socks` package wired into a custom undici
Agent's `connect` factory, so SOCKS routing flows through the same
fetch dispatcher pipeline as HTTP/HTTPS.
- PAC files via PAC_URL, with full PROXY/SOCKS/DIRECT directive
support. PacDispatcher lazily fetches and compiles the PAC script
using `pac-resolver` (running PAC JavaScript in a QuickJS WASM
sandbox via `quickjs-wasi`), then resolves and routes per request.
Detection and routing priority is PAC > SOCKS > HTTP, matching the
specificity of each mechanism (PAC can return mixed directives
per request; SOCKS and HTTP are per-process configurations).
Coverage:
- 14 new unit tests (env-var detection, priority, edge cases)
- 7 new integration tests using a hand-rolled SOCKS5 server, a
CONNECT-tunneling HTTP proxy, and a PAC file server — verifying
end-to-end routing for each mechanism plus per-host PAC directives.
A local pac-resolver.d.ts stub mirrors the v9 surface we use,
because pac-resolver@9 ships its types only via the `exports` map
which the repo's classic `moduleResolution: node` doesn't read.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update changeset for SOCKS and PAC support
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(shadcn): tighten proxy integration tests per review
- Replace the dead "proxy-direct" response body in the test proxy's
request handler with a 502 reply. The request callback path was
never exercised (undici only sends CONNECT to the proxy), so the
unreachable JSON body was confusing dead code. Lock the new
CONNECT-only contract in with an explicit test.
- Tighten the NO_PROXY-non-match assertion from `.toHaveLength(1)` +
`.toBe("CONNECT")` to `.toEqual([{ url: originHost, method: "CONNECT" }])`,
matching the parallel HTTP_PROXY test. The looser version would
miss bugs where the dispatcher CONNECTed to the wrong host (e.g.,
the proxy's own address instead of the origin's) — the strict
version catches that bug class.
Both changes per @pomeh's review feedback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(shadcn): rescope proxy support to SOCKS only
Per review feedback, split the proxy work: this branch now lands SOCKS
support alone and PAC moves to a follow-up PR.
Removes the PacDispatcher, the PAC directive parser, the PAC_URL env
handling and the pac-resolver type stub, along with the pac-resolver and
quickjs-wasi dependencies (the latter being ~3 MB of WASM). The socks
dependency and the entire SOCKS code path are unchanged, as is
fetchWithProxy's cross-origin redirect hardening.
ALL_PROXY remains SOCKS-only: a non-socks scheme falls through to the
explicit HTTP_PROXY / HTTPS_PROXY variables rather than being absorbed.
Changeset bumped from patch to minor.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011YT4UiAoMUVeF9xaVm9ufi
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: shadcn <m@shadcn.com>
* fix(shadcn): create nested output directories in build
Registry item names can contain path segments (e.g. "extension/foo").
Both build commands wrote <outputDir>/<name>.json without creating the
implied nested directories, so builds failed with ENOENT on clean
checkouts where the output directory does not already exist. Create the
parent directory before writing each item.
Fixes#11321
* chore: format
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xq2q7jaDcyxyA6YjutStLn
---------
Co-authored-by: shadcn <m@shadcn.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(shadcn): scope component availability by base
* feat(base-toast): add Base UI toast component
* docs(base-toast): document toast and retire base sonner
* test(shadcn): add MCP formatter unit tests
Covers all five formatters in src/mcp/utils.ts (formatSearchResultsWithPagination,
findUnknownTypesMessage, formatSkippedRegistries, formatRegistryItems,
formatItemExamples). Pins the known npxShadcn-not-awaited bug with an
it.fails marker plus a companion test asserting today's broken
"[object Promise]" output, per plans/005 (fix deferred by operator).
* chore(shadcn): add shared test helpers for temp dirs and fixtures
Adds getFixturesDir and withTempDir under src/test-helpers so future
tests don't re-implement mkdtemp cleanup boilerplate or hand-build
fixture paths with __dirname.
* test(shadcn): delete dead vendored-starter test in remix fixture
test/fixtures/frameworks/remix-indie-stack/app/utils.test.ts tested the
vendored Remix Indie Stack starter's own validateEmail helper, not shadcn
code. It's excluded from discovery via the **/fixtures/** vitest exclude,
so this has zero effect on the suite total.
* test(shadcn): move addComponents workspace-routing tests into src/utils
Relocate test/utils/add-components.test.ts's "addComponents workspace
routing" describe block (real addComponents against mock workspace
configs) to a new sibling file, src/utils/add-components.workspace.test.ts,
instead of merging into the existing src/utils/add-components.test.ts.
The existing test file's vi.mock factories replace get-config and
update-files wholesale (no real getWorkspaceConfig/findPackageRoot/
updateFiles passthrough), which conflicts with what the workspace-routing
suite needs. vi.mock is per-file, so a sibling file keeps both real and
mocked variants working side by side.
Also drops the now-untyped `name` field from resolveRegistryTree mock
payloads (not part of registryResolvedItemsTreeSchema, and unused by
addComponents) now that these tests are typechecked as part of src/ for
the first time.
* test(shadcn): move registry and registries/add-registry tests into src/
- test/utils/registry.test.ts -> merged into src/registry/api.test.ts as
a new "resolveTree" describe (sole coverage of resolveTree).
- test/utils/get-item-target-path.test.ts -> merged into
src/registry/api.test.ts as a new "getItemTargetPath" describe;
fixture paths switched to getFixturesDir() from @/src/test-helpers.
- test/utils/registries.test.ts -> src/utils/registries.test.ts.
- test/utils/add-registries.test.ts -> src/commands/registry/add.test.ts
(tests parseRegistryArg, which lives in src/commands/registry/add.ts).
All four now typecheck as part of src/** for the first time. Only type
fix needed: getConfig() returns Config | null, so the moved
getItemTargetPath assertions non-null-assert its result.
* fix(shadcn): complete the registry test-move commit from the prior step
The previous commit's staging step used `git add -A -- <paths>` with a
stale pathspec that failed outright (exit 128), which meant the commit
silently went through with only the git-mv'd renames/deletions and
none of the follow-up import-path fixes and new describe blocks made
via Edit afterward. src/commands/registry/add.test.ts and
src/utils/registries.test.ts were committed still pointing at
../../src/... paths (broken from their new location), and
src/registry/api.test.ts was committed without the merged resolveTree
/getItemTargetPath describes at all. This commit captures those
already-verified changes so HEAD matches what was actually tested.
* test(shadcn): move get-config and get-project-info cluster into src/
- test/utils/get-config.test.ts -> src/utils/get-config.test.ts,
restructured into describe("getRawConfig"/"getProjectConfig"/
"getConfig"/"getWorkspaceConfig") blocks (test -> it), fixture paths
switched to getFixturesDir().
- test/utils/get-project-info.test.ts -> src/utils/get-project-info.test.ts,
test/test.each -> it/it.each; merged in as new describes:
- test/utils/get-tailwind-css-file.test.ts ("get tailwindcss file")
- test/utils/get-ts-config-alias-prefix.test.ts ("get ts config alias prefix")
- test/utils/is-typescript-project.test.ts ("is TypeScript project")
(all four test getters exported from src/utils/get-project-info.ts).
- test/utils/get-package-manager.test.ts -> src/utils/get-package-manager.test.ts,
split into describe blocks per exported function, test -> it.
All now typecheck as part of src/** for the first time; no type errors
surfaced.
* test(shadcn): move resolve-import and dry-run tests into src/utils
- test/utils/resolve-import.test.ts -> src/utils/resolve-import.test.ts,
restructured into describe("resolveImport") + the two pre-existing
describes, test -> it, fixture paths via getFixturesDir().
- test/utils/dry-run.test.ts -> src/utils/dry-run.test.ts, test -> it
throughout (already describe-organized), fixture/temp-dir paths via
getFixturesDir().
Dropped the unused `name` field from 10 resolveRegistryTree mock
payloads (not part of registryResolvedItemsTreeSchema) now that this
file typechecks as part of src/** for the first time.
* test(shadcn): move transformer tests into src/utils/transformers
- test/utils/apply-color-mapping.test.ts + test/utils/transform-css-vars.test.ts
-> merged into src/utils/transformers/transform-css-vars.test.ts.
- test/utils/apply-prefix.test.ts + test/utils/transform-tw-prefix.test.ts
-> merged into src/utils/transformers/transform-tw-prefix.test.ts.
- test/utils/transform-import.test.ts -> src/utils/transformers/transform-import.test.ts.
- test/utils/transform-rsc.test.ts -> src/utils/transformers/transform-rsc.test.ts.
- test/utils/transform-rtl.test.ts -> src/utils/transformers/transform-rtl.test.ts;
deleted 8 commented-out test() blocks that asserted nothing.
test -> it throughout; snapshot-bearing tests kept their exact top-level
title (no new describe wrapping) so vitest regenerates snapshots under
the identical key — diffed byte-identical against the originals before
deleting the orphaned test/utils/__snapshots__ files.
Per reviewer authorization: cast partial Config literals passed to
transform() with `as Config` (60 call sites across
transform-import/rsc/rtl/tw-prefix/css-vars.test.ts), and one
`baseColor: "stone" as any` where a bare string was passed where the
type expects a base-color object (preserves the original, intentional
runtime input unchanged). Also cast the ts-morph/TS-internal
`sourceFile.parseDiagnostics` access in transform-rtl.test.ts as `any`
rather than substituting a different (public) API. All casts only;
no assertions or literal values changed. Verified: every regenerated
snapshot is byte-identical to its pre-move original, and
`pnpm test src/utils/transformers/` passes 196/196 both before and
after the casts were added.
* test(shadcn): move updater tests into src/utils/updaters
- test/utils/updaters/update-tailwind-content.test.ts -> src/utils/updaters/update-tailwind-content.test.ts
- test/utils/updaters/update-dependencies.test.ts -> src/utils/updaters/update-dependencies.test.ts
- test/utils/updaters/update-css.test.ts -> src/utils/updaters/update-css.test.ts
- test/utils/updaters/update-css-vars.test.ts -> src/utils/updaters/update-css-vars.test.ts
- test/utils/updaters/update-tailwind-config.test.ts -> src/utils/updaters/update-tailwind-config.test.ts
- test/utils/updaters/update-files.test.ts (2604 lines, largest) -> src/utils/updaters/update-files.test.ts
test -> it / test.each -> it.each throughout; fixture and scratch-temp-dir
paths switched to getFixturesDir() from @/src/test-helpers. Snapshot-
bearing files (update-tailwind-content, update-tailwind-config) diffed
byte-identical against their pre-move originals before the old
test/utils/updaters/__snapshots__ files were deleted.
Also deleted test/utils/updaters/__snapshots__/initialize-tailwind-config.test.ts.snap,
an orphan with no corresponding test file anywhere in the repo (grep
confirmed) — out of the plan's 27-row map but required to satisfy the
"no orphaned snapshot dirs" done-criterion and let Step 8 rmdir the now-
empty test/utils/updaters directory.
Per reviewer authorization (round 1), fixed the resulting typecheck
errors with casts only, no restructuring or assertion changes:
- `as Config` on partial Config/resolvedPaths object literals passed to
transformTailwindContent/transformTailwindConfig/updateDependencies/
transformCssVars/resolveFilePath (update-files.test.ts alone needed
~59 such casts, plus a `(await getConfig(...))!` non-null assertion
on the 11 getConfig() calls that had no existing `if (!config) throw`
guard).
- `as any` on wrapper objects that don't fit any named type at all: the
`{ config: SHARED_CONFIG }` argument in update-tailwind-content/
update-tailwind-config tests (the production functions take `config`
directly, not a wrapped options object — this mismatch predates this
move and is left as-is per "casts only, do not restructure"), the
flat color-map literals passed to buildTailwindThemeColorsFromCssVars,
the `file` param in two resolveFilePath test.each callbacks (whose
`type` field widens to `string` across the array), and the partial
`ProjectInfo` literals passed to toAliasedImport tests.
Verified every regenerated snapshot is byte-identical to its pre-move
original, and `pnpm test src/utils/updaters/` passes 278/278 both
before and after the casts were added.
* test(shadcn): characterize registry source include resolution
Adds source.test.ts covering the previously-untested include resolver
in src/registry/source.ts: happy-path flattening (flat, single include,
two-level nested include), root validation, and every containment
guard (absolute/traversal/URL paths, non-registry.json includes, include
cycles, duplicate includes, max include depth, duplicate item names).
* test(shadcn): cover workspace adaptation in template scaffolding
Export getInstallArgs, adaptWorkspaceConfig, and rewriteWorkspaceProtocol
from create-template.ts (no logic changes) and add unit tests covering
the destructive package-manager adaptation that runs when scaffolding a
non-pnpm project: lockfile/workspace-config removal, packageManager and
workspaces rewriting, and workspace: protocol rewriting for npm.
Also removes the vestigial "**/templates/**" vitest exclude, which dates
to migration commit e51648139 and today only matches this CLI's own
source files under src/templates/ (no scaffold-template project
directories live there). Verified via `npx vitest list` before/after:
the collected test set changed by exactly one file,
src/templates/create-template.test.ts - nothing else was newly picked up.
Full suite: 83 files / 1584 tests passing (was 82/1571 baseline + this
file's 13 tests). typecheck and build both exit 0.
* test(shadcn): cover add command orchestration branches
Integration-style tests for the `add` command action handler, pinning the
routing between dry-run, the missing-config init flow, the empty-project
create-project flow, the registry:style/theme overwrite confirm, the
universal registry item short-circuit, the app-index update guard, and the
Tailwind v4 deprecated-components guard. Collaborators (runInit,
createProject, addComponents, updateAppIndex, dryRunComponents, prompts) are
mocked at their seams; preFlightAdd, getConfig, and the registry fetch path
run for real against temp-dir fixtures and an MSW-served registry.
* chore(shadcn): format test files with prettier
* feat(v4): generate cross-library icon mapping from registry placeholders
* feat(shadcn): migrate icons between any icon libraries
* fix(shadcn): harden icon template regexes flagged by CodeQL
* fix(shadcn): replace usage-template regexes with a linear scanner
The tail spacer makes a freshly anchored turn read as "at the end", so
reconcileFollowMode re-armed following-bottom one frame after the anchor
placement and the first streamed chunk yanked the reader off the anchor.
Exclude the anchored-to-message hold from arming, matching the existing
settling-jump exclusion.
Claude-Session: https://claude.ai/code/session_0186fcQpHo1aLQC4wRpwKFFu
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(create): default design system config to base ui
* feat(www): default docs and init to base ui
* feat(www): default preview styles to base-nova
* feat(shadcn): default init and prompts to base ui
* docs: default to base ui in guides and examples
* docs: add changelog
* chore: changeset
* fix: address base ui default review findings
* fix: init handling
* feat: add migrate-radix-to-base skills
* fix: typo
* feat(@shadcn/react): add message-scroller package
Add the @shadcn/react headless primitives package with MessageScroller
scroll anchoring, streaming follow, history prepend, and jump-to-message
behavior. Includes geometry helpers, use-render utility, and unit,
browser, and perf tests.
* feat(registry): add chat components
Add MessageScroller, Message, Bubble, Attachment, and Marker registry
sources for base and radix, style variants, preview-03 chat blocks,
and registry index wiring.
* feat(v4): integrate chat components into docs site
Wire chat components into the v4 app with docs routes, example preview
pages, message part renderers, markdown support, registry build updates,
and supporting lib utilities.
* feat(examples): add chat component demos
Add base and radix example demos for MessageScroller, Message, Bubble,
Attachment, Marker, scroll-fade, and shimmer.
* docs: add chat component documentation
Add component and utility docs for the chat component set, update docs
navigation, and add the June 2026 chat components changelog entry.
* chore: regenerate registry JSON output
Rebuild public registry artifacts for all style variants with the new
chat components.
* chore(release): add @shadcn/react publish and CI pipeline
Add Changesets prerelease workflow, browser test job, RELEASING docs,
and monorepo wiring for publishing @shadcn/react independently from
the shadcn CLI.
* docs: fix display of component preview on mobile
* fix
* fix
* docs: add message scroller docs
* style: format
* fix