feat: sync with upstream shadcn/ui (through shadcn@3.8.4)

Squash merge of shadcn-ui/ui main branch into hanzo/ui, bringing in:
- shadcn@3.6.3 through shadcn@3.8.4 releases
- New apps/v4 directory structure
- Registry system improvements and MCP server
- Framework support (Vue, Svelte, React Native)
- New templates (vite-app, monorepo-next, laravel)
- Zod 4 compatibility (scoped override for zod@>4)
- Test fixture corrections for alias resolution

All 867 merge conflicts resolved preserving Hanzo customizations.
1020/1020 shadcn tests pass.
This commit is contained in:
Zach Kelling
2026-02-09 10:44:26 -08:00
parent 2164952cba
commit b74fc57590
9352 changed files with 724979 additions and 5798 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "shadcn-ui/ui" }],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["v4", "tests"]
}
+8
View File
@@ -0,0 +1,8 @@
node_modules/
target/
.next/
build/
dist/
/templates/
/fixtures/
+32
View File
@@ -0,0 +1,32 @@
{
"$schema": "https://json.schemastore.org/eslintrc",
"root": true,
"extends": [
"next/core-web-vitals",
"turbo",
"prettier",
"plugin:tailwindcss/recommended"
],
"plugins": ["tailwindcss"],
"ignorePatterns": ["**/fixtures/**"],
"rules": {
"@next/next/no-html-link-for-pages": "off",
"tailwindcss/no-custom-classname": "off",
"tailwindcss/classnames-order": "error"
},
"settings": {
"tailwindcss": {
"callees": ["cn", "cva"],
"config": "tailwind.config.cjs"
},
"next": {
"rootDir": ["apps/*/"]
}
},
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser"
}
]
}
@@ -0,0 +1,25 @@
title: "[blocks]: "
labels: ["Blocks Request"]
body:
- type: markdown
attributes:
value: |
### Thanks for taking the time to create a block request! Please search open/closed requests before submitting, as the block or a similar one may have already been requested.
- type: textarea
id: block-description
attributes:
label: Description
description: Tell us about your block request
placeholder: "A dashboard for an e-commerce website showing sales, orders, and customers..."
validations:
required: true
- type: input
id: block-example-url
attributes:
label: Example
description: Link to an example of the block
placeholder: ex. https://example.com
validations:
required: false
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [shadcn]
+85
View File
@@ -0,0 +1,85 @@
name: "Bug report"
description: Report an issue
title: '[bug]: '
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
### Thanks for taking the time to create a bug report. Please search open/closed issues before submitting, as the issue may have already been reported/addressed.
- type: markdown
attributes:
value: |
#### If you aren't sure this is a bug or not, please open a discussion instead:
- [Discussions](https://github.com/shadcn-ui/ui/discussions/new?category=general)
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us how in the description. Thanks!
placeholder: Bug description
validations:
required: true
- type: input
id: components-affected
attributes:
label: Affected component/components
description: Which shadcn/ui components are affected?
placeholder: ex. Button, Checkbox...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: How to reproduce
description: A step-by-step description of how to reproduce the bug.
placeholder: |
1. Go to '...'
2. Click on '....'
3. See error
validations:
required: true
- type: input
id: codesandbox-stackblitz
attributes:
label: Codesandbox/StackBlitz link
description: |
A link to a CodeSandbox or StackBlitz that includes a minimal reproduction of the problem. In rare cases when not applicable, you can link to a GitHub repository that we can easily run to recreate the issue. If a report is vague and does not have a reproduction, it will be closed without warning.
> [!CAUTION]
> If you skip this step, this issue might be **labeled** with `please add a reproduction` and **closed**.
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs
description: "Please include browser console and server logs around the time this bug occurred. Optional if provided reproduction. Please try not to insert an image but copy paste the log text."
render: bash
- type: textarea
id: system-info
attributes:
label: System Info
description: Information about browsers, system or binaries that's relevant.
render: bash
placeholder: System, Binaries, Browsers
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Before submitting
description: By submitting this issue, you agree to follow our [Contributing Guidelines](https://github.com/shadcn-ui/ui/blob/main/CONTRIBUTING.md).
options:
- label: I've made research efforts and searched the documentation
required: true
- label: I've searched for existing issues
required: true
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Get Help
url: https://github.com/shadcn-ui/ui/discussions/new?category=general
about: If you can't get something to work the way you expect, open a question in our discussion forums.
@@ -0,0 +1,55 @@
name: "Feature request"
description: Create a feature request for shadcn/ui
title: '[feat]: '
labels: ['area: request']
body:
- type: markdown
attributes:
value: |
### Thanks for taking the time to create a feature request! Please search open/closed issues before submitting, as the issue may have already been reported/addressed.
- type: markdown
attributes:
value: |
#### If you aren't sure this is a bug or not, please open a discussion instead:
- [Discussions](https://github.com/shadcn-ui/ui/discussions/new?category=general)
- type: textarea
id: feature-description
attributes:
label: Feature description
description: Tell us about your feature request
placeholder: 'I think this feature would be great because...'
value: 'Describe your feature request...'
validations:
required: true
- type: input
id: components-affected
attributes:
label: Affected component/components
description: Is this feature request relevant to any of the already existing components?
placeholder: ex. Button, Checkbox...
validations:
required: false
- type: textarea
id: context
attributes:
label: Additional Context
description: Add any other context about the feature here.
placeholder: ex. screenshots, Stack Overflow links, forum links, etc.
value: 'Additional details here...'
validations:
required: false
- type: checkboxes
id: terms
attributes:
label: Before submitting
description: By submitting this issue, you agree to follow our [Contributing Guidelines](https://github.com/shadcn-ui/ui/blob/main/CONTRIBUTING.md).
options:
- label: I've made research efforts and searched the documentation
required: true
- label: I've searched for existing issues and PRs
required: true
+5 -5
View File
@@ -1,12 +1,12 @@
// ORIGINALLY FROM CLOUDFLARE WRANGLER:
// https://github.com/cloudflare/wrangler2/blob/main/.github/changeset-version.js
import { exec } from "child_process"
import { execSync } from "child_process"
// This script is used by the `release.yml` workflow to update the version of the packages being released.
// The standard step is only to run `changeset version` but this does not update the package-lock.json file.
// So we also run `npm install`, which does this update.
// The standard step is only to run `changeset version` but this does not update the pnpm-lock.yaml file.
// So we also run `pnpm install`, which does this update.
// This is a workaround until this is handled automatically by `changeset version`.
// See https://github.com/changesets/changesets/issues/421.
exec("npx changeset version")
exec("npm install")
execSync("npx changeset version", { stdio: "inherit" })
execSync("pnpm install --lockfile-only", { stdio: "inherit" })
+6
View File
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
+3 -3
View File
@@ -16,7 +16,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm
@@ -52,7 +52,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm
@@ -90,7 +90,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm
+78
View File
@@ -0,0 +1,78 @@
name: Deprecated
on:
pull_request_target:
types: [opened, synchronize]
permissions:
issues: write
contents: read
pull-requests: write
jobs:
deprecated:
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v46
with:
files: |
apps/www/**
files_ignore: |
apps/www/public/r/**
base_sha: ${{ github.event.pull_request.base.sha }}
sha: ${{ github.event.pull_request.head.sha }}
- name: Comment on PR if www files changed
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const changedFiles = `${{ steps.changed-files.outputs.all_changed_files }}`.split(' ');
const wwwFiles = changedFiles.filter(file =>
file.startsWith('apps/www/') &&
!file.startsWith('apps/www/public/r/') &&
file !== 'apps/www/package.json'
);
if (wwwFiles.length > 0) {
const comment = `Looks like this PR modifies files in \`apps/www\`, which is deprecated.
Consider applying the change to \`apps/v4\` if relevant.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: comment
});
// Add deprecated label
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: ['deprecated']
});
} else {
// Remove deprecated label if no www files are changed
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'deprecated'
});
} catch (error) {
// Label doesn't exist, which is fine
console.log('Deprecated label not found, skipping removal');
}
}
+45
View File
@@ -0,0 +1,45 @@
# Adapted from vercel/next.js
name: "Stale issue handler"
on:
workflow_dispatch:
schedule:
# This runs every day 20 minutes before midnight: https://crontab.guru/#40_23_*_*_*
- cron: "40 23 * * *"
jobs:
stale:
runs-on: ubuntu-latest
if: github.repository_owner == 'shadcn-ui'
steps:
- uses: actions/stale@v9
id: issue-stale
name: "Mark stale issues, close stale issues"
with:
repo-token: ${{ secrets.STALE_TOKEN }}
ascending: true
days-before-issue-close: 7
days-before-issue-stale: 365
days-before-pr-stale: -1
days-before-pr-close: -1
remove-issue-stale-when-updated: true
stale-issue-label: "stale?"
exempt-issue-labels: "roadmap,next"
stale-issue-message: "This issue has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless theres further input. If you believe this issue is still relevant, please leave a comment or provide updated details. Thank you. (This is an automated message)"
close-issue-message: "This issue has been automatically closed due to one year of inactivity. If youre still experiencing a similar problem or have additional details to share, please open a new issue following our current issue template. Your updated report helps us investigate and address concerns more efficiently. Thank you for your understanding! (This is an automated message)"
operations-per-run: 300
- uses: actions/stale@v9
id: pr-state
name: "Mark stale PRs, close stale PRs"
with:
repo-token: ${{ secrets.STALE_TOKEN }}
ascending: true
days-before-issue-close: -1
days-before-issue-stale: -1
days-before-pr-close: 7
days-before-pr-stale: 365
remove-pr-stale-when-updated: true
exempt-pr-labels: "roadmap,next,bug"
stale-pr-label: "stale?"
stale-pr-message: "This PR has been automatically marked as stale due to one year of inactivity. It will be closed in 7 days unless theres further input. If you believe this PR is still relevant, please leave a comment or provide updated details. Thank you. (This is an automated message)"
close-pr-message: "This PR has been automatically closed due to one year of inactivity. Thank you for your understanding! (This is an automated message)"
operations-per-run: 300
+40 -19
View File
@@ -89,30 +89,51 @@ jobs:
local pkg_dir=$1
local pkg_name=$(cd $pkg_dir && node -p "require('./package.json').name")
local pkg_version=$(cd $pkg_dir && node -p "require('./package.json').version")
echo "Publishing $pkg_name@$pkg_version from $pkg_dir"
# Bump version
cd $pkg_dir
pnpm version ${{ github.event.inputs.version_bump }} --no-git-tag-version
echo "=== Publishing $pkg_name@$pkg_version from $pkg_dir ==="
# Change to package directory
pushd "$pkg_dir"
# Bump version manually using node to avoid any pnpm/npm hooks
echo "Bumping version (${{ github.event.inputs.version_bump }})..."
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const [major, minor, patch] = pkg.version.split('.').map(Number);
const bump = '${{ github.event.inputs.version_bump }}';
if (bump === 'major') pkg.version = (major + 1) + '.0.0';
else if (bump === 'minor') pkg.version = major + '.' + (minor + 1) + '.0';
else pkg.version = major + '.' + minor + '.' + (patch + 1);
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
console.log('New version:', pkg.version);
"
local new_version=$(node -p "require('./package.json').version")
echo "Version bumped to $new_version"
# Pack the tarball - this resolves workspace: protocols to real versions
echo "Version is now: $new_version"
# Pack the tarball
echo "Running pnpm pack..."
pnpm pack
pnpm pack --pack-gzip-level 9
local tarball=$(ls -t *.tgz | head -1)
echo "Created tarball: $tarball"
# Extract and inspect the tarball package.json
echo "Inspecting tarball package.json..."
tar -xzf "$tarball" -O package/package.json | head -60
# Create a temp directory completely outside the workspace
local temp_publish_dir="/tmp/npm-publish-$$"
mkdir -p "$temp_publish_dir"
cp "$tarball" "$temp_publish_dir/"
# Publish from temp dir using npm directly
echo "Publishing from $temp_publish_dir..."
(cd "$temp_publish_dir" && npm publish "$tarball" --access public)
rm -rf "$temp_publish_dir"
rm -f "$tarball"
# Verify tarball contents
echo "Tarball package.json:"
tar -xzf "$tarball" -O package/package.json
# Copy to temp dir and publish
local temp_dir="/tmp/publish-$$"
mkdir -p "$temp_dir"
cp "$tarball" "$temp_dir/"
echo "Publishing from $temp_dir..."
cd "$temp_dir"
npm publish "$tarball" --access public
cd -
# Cleanup
rm -rf "$temp_dir"
rm -f "$tarball"
popd
}
case "${{ github.event.inputs.package }}" in
+16 -9
View File
@@ -7,6 +7,11 @@ on:
branches:
- main
permissions:
id-token: write
contents: write
pull-requests: write
jobs:
release:
if: ${{ github.repository_owner == 'hanzoai-ui' }}
@@ -19,17 +24,20 @@ jobs:
fetch-depth: 0
- name: Use PNPM
uses: pnpm/action-setup@v2.2.4
uses: pnpm/action-setup@v4
with:
version: 8.6.1
version: 9.0.6
- name: Use Node.js 18
uses: actions/setup-node@v3
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
version: 8.6.1
node-version: 18
node-version: 20
registry-url: "https://registry.npmjs.org"
cache: "pnpm"
- name: Update npm for OIDC support
run: npm install -g npm@latest
- name: Install NPM Dependencies
run: pnpm install
@@ -37,11 +45,11 @@ jobs:
# run: pnpm check
- name: Build the package
run: pnpm build:cli
run: pnpm shadcn:build
- name: Create Version PR or Publish to NPM
id: changesets
uses: changesets/action@v1.4.1
uses: changesets/action@v1
with:
commit: "chore(release): version packages"
title: "chore(release): version packages"
@@ -49,5 +57,4 @@ jobs:
publish: npx changeset publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
NODE_ENV: "production"
+53
View File
@@ -0,0 +1,53 @@
name: Validate Registries
on:
pull_request:
paths:
- "apps/v4/public/r/registries.json"
- "apps/v4/registry/directory.json"
push:
branches:
- main
paths:
- "apps/v4/public/r/registries.json"
- "apps/v4/registry/directory.json"
jobs:
validate:
runs-on: ubuntu-latest
name: pnpm validate:registries
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 20
- uses: pnpm/action-setup@v4
name: Install pnpm
id: pnpm-install
with:
version: 9.0.6
run_install: false
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install
- name: Validate registries
run: pnpm --filter=v4 validate:registries
+6
View File
@@ -72,3 +72,9 @@ test-results/
playwright-report/
*BADGE_INSPECTION*.md
*BADGE_INSPECTION*.txt
# ide
.idea
.fleet
.notes
+18
View File
@@ -0,0 +1,18 @@
# .kodiak.toml
version = 1
[merge]
automerge_label = "automerge"
require_automerge_label = true
method = "squash"
delete_branch_on_merge = true
optimistic_updates = false
prioritize_ready_to_merge = true
notify_on_conflict = true
[merge.message]
title = "pull_request_title"
body = "pull_request_body"
include_pr_number = true
body_type = "markdown"
strip_html_comments = true
+2
View File
@@ -0,0 +1,2 @@
auto-install-peers=true
link-workspace-packages=true
+1
View File
@@ -0,0 +1 @@
v20.5.1
+20 -1
View File
@@ -1,5 +1,24 @@
{
"typescript.tsdk": "node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib",
"editor.gotoLocation.multipleDefinitions": "goto",
"typescript.preferences.quoteStyle": "single"
"typescript.preferences.quoteStyle": "single",
"eslint.workingDirectories": [
{ "pattern": "apps/*/" },
{ "pattern": "packages/*/" },
{ "pattern": "pkg/*/" }
],
"tailwindCSS.classFunctions": ["cva", "cn"],
"vitest.debugExclude": [
"<node_internals>/**",
"**/node_modules/**",
"**/fixtures/**"
],
"files.exclude": {
"deprecated": true
},
"search.exclude": {
"apps/v4/registry/radix-*": true,
"apps/v4/public/r/*": true,
"packages/shadcn/test/fixtures/*": true
}
}
+15 -84
View File
@@ -6,18 +6,18 @@ Accessible and customizable components for React, Vue, Svelte, and React Native.
## Features
- 🎯 **161+ Components** - 3x more than shadcn/ui
- 🌐 **Multi-Framework** - React, Vue, Svelte, React Native
- 🎨 **Two Themes** - Default & New York variants
- 🤖 **AI Components** - Chat, assistants, playground
- 🎮 **3D Components** - Interactive 3D elements
- **Animations** - Advanced motion components
- 🎛️ **Page Builder** - Visual drag-drop interface
- 🏷️ **White-Label** - Fork and rebrand easily
- 📦 **Blocks** - 24+ production-ready templates
- **Accessible** - Built with Radix UI primitives
- 🎭 **Customizable** - Tailwind CSS powered
- 📘 **TypeScript** - Fully typed
- **161+ Components** - 3x more than shadcn/ui
- **Multi-Framework** - React, Vue, Svelte, React Native
- **Two Themes** - Default & New York variants
- **AI Components** - Chat, assistants, playground
- **3D Components** - Interactive 3D elements
- **Animations** - Advanced motion components
- **Page Builder** - Visual drag-drop interface
- **White-Label** - Fork and rebrand easily
- **Blocks** - 24+ production-ready templates
- **Accessible** - Built with Radix UI primitives
- **Customizable** - Tailwind CSS powered
- **TypeScript** - Fully typed
## Quick Start
@@ -51,54 +51,17 @@ export function App() {
}
```
## Multi-Framework Support
```tsx
// React (default)
import { Button } from '@hanzo/ui'
// Vue
import { Button } from '@hanzo/ui/vue'
// Svelte
import { Button } from '@hanzo/ui/svelte'
// React Native
import { Button } from '@hanzo/ui/react-native'
```
## Documentation
📚 Visit **[ui.hanzo.ai](https://ui.hanzo.ai)** for:
- [Component Documentation](https://ui.hanzo.ai/docs/components)
- [Framework Guides](https://ui.hanzo.ai/docs/frameworks)
- [Installation Guide](https://ui.hanzo.ai/docs/installation)
- [Examples](https://ui.hanzo.ai/examples)
- [Page Builder](https://ui.hanzo.ai/builder)
- [Theme Generator](https://ui.hanzo.ai/theme-generator)
Visit **[ui.hanzo.ai](https://ui.hanzo.ai)** for full docs.
## CLI
Install components individually:
```bash
npx @hanzo/ui add button
npx @hanzo/ui add card dialog
```
## What's Different from shadcn/ui?
| Feature | shadcn/ui | @hanzo/ui |
|---------|-----------|-----------|
| Components | 58 | **161** |
| Frameworks | React only | React, Vue, Svelte, React Native |
| 3D Components | ❌ | ✅ (9 components) |
| AI Components | ❌ | ✅ (12 components) |
| Page Builder | ❌ | ✅ |
| White-Label | ❌ | ✅ |
| Blocks | Limited | **24+ templates** |
## Packages
- `@hanzo/ui` - Main UI library (161 components)
@@ -106,55 +69,23 @@ npx @hanzo/ui add card dialog
- `@hanzo/commerce` - E-commerce components
- `@hanzo/brand` - Branding system
## Examples
```tsx
// 3D Components
import { ThreeDButton, ThreeDCard } from '@hanzo/ui'
// AI Components
import { AIChat, AIAssistant } from '@hanzo/ui'
// Animations
import { AnimatedBeam, AnimatedText } from '@hanzo/ui'
```
## Development
```bash
# Clone repository
git clone https://github.com/hanzoai/ui.git
cd ui
# Install dependencies
pnpm install
# Start dev server
pnpm dev
# Build packages
pnpm build
# Run tests
pnpm test
```
## Contributing
We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md).
Please read the [contributing guide](/CONTRIBUTING.md).
## License
MIT - See [LICENSE.md](./LICENSE.md) for details.
## Links
- [Documentation](https://ui.hanzo.ai)
- [GitHub](https://github.com/hanzoai/ui)
- [npm](https://www.npmjs.com/package/@hanzo/ui)
- [Discord](https://discord.gg/hanzo)
- [Twitter](https://twitter.com/hanzoai)
---
Built with ❤️ by [Hanzo](https://hanzo.ai)
Built by [Hanzo](https://hanzo.ai)
+2
View File
@@ -4,3 +4,5 @@ node_modules
build
.contentlayer
apps/web/pages/api/registry.json
**/fixtures
deprecated
@@ -1,9 +1,4 @@
import {
ChevronDownIcon,
CircleIcon,
PlusIcon,
StarIcon,
} from "@radix-ui/react-icons"
import { ChevronDown, Circle, Plus, Star } from "lucide-react"
import { Button } from "@/registry/default/ui/button"
import {
@@ -37,14 +32,14 @@ export function DemoGithub() {
</div>
<div className="flex items-center space-x-1 rounded-md bg-secondary text-secondary-foreground">
<Button variant="secondary" className="px-3 shadow-none">
<StarIcon className="mr-2 h-4 w-4" />
<Star />
Star
</Button>
<Separator orientation="vertical" className="h-[20px]" />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="secondary" className="px-2 shadow-none">
<ChevronDownIcon className="h-4 w-4 text-secondary-foreground" />
<ChevronDown className="text-secondary-foreground" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
@@ -62,7 +57,7 @@ export function DemoGithub() {
<DropdownMenuCheckboxItem>Inspiration</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
<DropdownMenuItem>
<PlusIcon className="mr-2 h-4 w-4" /> Create List
<Plus /> Create List
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
@@ -71,11 +66,11 @@ export function DemoGithub() {
<CardContent>
<div className="flex space-x-4 text-sm text-muted-foreground">
<div className="flex items-center">
<CircleIcon className="mr-1 h-3 w-3 fill-sky-400 text-sky-400" />
<Circle className="mr-1 h-3 w-3 fill-sky-400 text-sky-400" />
TypeScript
</div>
<div className="flex items-center">
<StarIcon className="mr-1 h-3 w-3" />
<Star className="mr-1 h-3 w-3" />
20k
</div>
<div>Updated April 2023</div>
@@ -1,4 +1,4 @@
import { BellIcon, EyeNoneIcon, PersonIcon } from "@radix-ui/react-icons"
import { Bell, EyeOff, User } from "lucide-react"
import {
Card,
@@ -19,7 +19,7 @@ export function DemoNotifications() {
</CardHeader>
<CardContent className="grid gap-1">
<div className="-mx-2 flex items-start space-x-4 rounded-md p-2 transition-all hover:bg-accent hover:text-accent-foreground">
<BellIcon className="mt-px h-5 w-5" />
<Bell className="mt-px h-5 w-5" />
<div className="space-y-1">
<p className="text-sm font-medium leading-none">Everything</p>
<p className="text-sm text-muted-foreground">
@@ -28,7 +28,7 @@ export function DemoNotifications() {
</div>
</div>
<div className="-mx-2 flex items-start space-x-4 rounded-md bg-accent p-2 text-accent-foreground transition-all">
<PersonIcon className="mt-px h-5 w-5" />
<User className="mt-px h-5 w-5" />
<div className="space-y-1">
<p className="text-sm font-medium leading-none">Available</p>
<p className="text-sm text-muted-foreground">
@@ -37,7 +37,7 @@ export function DemoNotifications() {
</div>
</div>
<div className="-mx-2 flex items-start space-x-4 rounded-md p-2 transition-all hover:bg-accent hover:text-accent-foreground">
<EyeNoneIcon className="mt-px h-5 w-5" />
<EyeOff className="mt-px h-5 w-5" />
<div className="space-y-1">
<p className="text-sm font-medium leading-none">Ignoring</p>
<p className="text-sm text-muted-foreground">
@@ -41,7 +41,7 @@ export function DemoShareDocument() {
</div>
<Separator className="my-4" />
<div className="space-y-4">
<h4 className="text-sm font-medium">People with access</h4>
<div className="text-sm font-medium">People with access</div>
<div className="grid gap-6">
<div className="flex items-center justify-between space-x-4">
<div className="flex items-center space-x-4">
@@ -1,4 +1,4 @@
import { ChevronDownIcon } from "@radix-ui/react-icons"
import { ChevronDown } from "lucide-react"
import {
Avatar,
@@ -51,8 +51,7 @@ export function DemoTeamMembers() {
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="ml-auto">
Owner{" "}
<ChevronDownIcon className="ml-2 h-4 w-4 text-muted-foreground" />
Owner <ChevronDown className="text-muted-foreground" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="end">
@@ -105,8 +104,7 @@ export function DemoTeamMembers() {
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="ml-auto">
Member{" "}
<ChevronDownIcon className="ml-2 h-4 w-4 text-muted-foreground" />
Member <ChevronDown className="text-muted-foreground" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" align="end">
@@ -1,8 +1,8 @@
"use client"
import * as React from "react"
import { CalendarIcon } from "@radix-ui/react-icons"
import { addDays, format } from "date-fns"
import { CalendarIcon } from "lucide-react"
import { DateRange } from "react-day-picker"
import { cn } from "@/lib/utils"
@@ -1,11 +1,7 @@
"use client"
import * as React from "react"
import {
CaretSortIcon,
CheckIcon,
PlusCircledIcon,
} from "@radix-ui/react-icons"
import { Check, ChevronsUpDown, PlusCircle } from "lucide-react"
import { cn } from "@/lib/utils"
import {
@@ -105,13 +101,13 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) {
<AvatarFallback>SC</AvatarFallback>
</Avatar>
{selectedTeam.label}
<CaretSortIcon className="ml-auto h-4 w-4 shrink-0 opacity-50" />
<ChevronsUpDown className="ml-auto opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search team..." />
<CommandList>
<CommandInput placeholder="Search team..." />
<CommandEmpty>No team found.</CommandEmpty>
{groups.map((group) => (
<CommandGroup key={group.label} heading={group.label}>
@@ -133,9 +129,9 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) {
<AvatarFallback>SC</AvatarFallback>
</Avatar>
{team.label}
<CheckIcon
<Check
className={cn(
"ml-auto h-4 w-4",
"ml-auto",
selectedTeam.value === team.value
? "opacity-100"
: "opacity-0"
@@ -156,7 +152,7 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) {
setShowNewTeamDialog(true)
}}
>
<PlusCircledIcon className="mr-2 h-5 w-5" />
<PlusCircle className="h-5 w-5" />
Create Team
</CommandItem>
</DialogTrigger>
@@ -1,8 +1,8 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { CalendarIcon, CaretSortIcon, CheckIcon } from "@radix-ui/react-icons"
import { format } from "date-fns"
import { CalendarIcon, Check, ChevronsUpDown } from "lucide-react"
import { useForm } from "react-hook-form"
import { z } from "zod"
@@ -169,35 +169,37 @@ export function AccountForm() {
(language) => language.value === field.value
)?.label
: "Select language"}
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
<ChevronsUpDown className="opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search language..." />
<CommandEmpty>No language found.</CommandEmpty>
<CommandGroup>
{languages.map((language) => (
<CommandItem
value={language.label}
key={language.value}
onSelect={() => {
form.setValue("language", language.value)
}}
>
<CheckIcon
className={cn(
"mr-2 h-4 w-4",
language.value === field.value
? "opacity-100"
: "opacity-0"
)}
/>
{language.label}
</CommandItem>
))}
</CommandGroup>
<CommandList>
<CommandEmpty>No language found.</CommandEmpty>
<CommandGroup>
{languages.map((language) => (
<CommandItem
value={language.label}
key={language.value}
onSelect={() => {
form.setValue("language", language.value)
}}
>
<Check
className={cn(
"mr-2",
language.value === field.value
? "opacity-100"
: "opacity-0"
)}
/>
{language.label}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
@@ -1,7 +1,7 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { ChevronDownIcon } from "@radix-ui/react-icons"
import { ChevronDown } from "lucide-react"
import { useForm } from "react-hook-form"
import { z } from "zod"
@@ -73,7 +73,7 @@ export function AppearanceForm() {
<option value="system">System</option>
</select>
</FormControl>
<ChevronDownIcon className="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
<ChevronDown className="absolute right-3 top-2.5 h-4 w-4 opacity-50" />
</div>
<FormDescription>
Set the font you want to use in the dashboard.
@@ -1,5 +1,5 @@
import Image from "next/image"
import { PlusCircledIcon } from "@radix-ui/react-icons"
import { PlusCircle } from "lucide-react"
import { cn } from "@/lib/utils"
import {
@@ -55,7 +55,7 @@ export function AlbumArtwork({
<ContextMenuSubTrigger>Add to Playlist</ContextMenuSubTrigger>
<ContextMenuSubContent className="w-48">
<ContextMenuItem>
<PlusCircledIcon className="mr-2 h-4 w-4" />
<PlusCircle className="mr-2 h-4 w-4" />
New Playlist
</ContextMenuItem>
<ContextMenuSeparator />
+2 -2
View File
@@ -1,6 +1,6 @@
import { Metadata } from "next"
import Image from "next/image"
import { PlusCircledIcon } from "@radix-ui/react-icons"
import { PlusCircle } from "lucide-react"
import { Button } from "@/registry/default/ui/button"
import { ScrollArea, ScrollBar } from "@/registry/default/ui/scroll-area"
@@ -64,7 +64,7 @@ export default function MusicPage() {
</TabsList>
<div className="ml-auto mr-4">
<Button>
<PlusCircledIcon className="mr-2 h-4 w-4" />
<PlusCircle />
Add music
</Button>
</div>
@@ -1,8 +1,8 @@
"use client"
import * as React from "react"
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons"
import { PopoverProps } from "@radix-ui/react-popover"
import { Check, ChevronsUpDown } from "lucide-react"
import { cn } from "@/lib/utils"
import { useMutationObserver } from "@/hooks/use-mutation-observer"
@@ -64,7 +64,7 @@ export function ModelSelector({ models, types, ...props }: ModelSelectorProps) {
className="w-full justify-between"
>
{selectedModel ? selectedModel.name : "Select a model..."}
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
<ChevronsUpDown className="opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent align="end" className="w-[250px] p-0">
@@ -135,13 +135,15 @@ function ModelItem({ model, isSelected, onSelect, onPeek }: ModelItemProps) {
const ref = React.useRef<HTMLDivElement>(null)
useMutationObserver(ref, (mutations) => {
for (const mutation of mutations) {
if (mutation.type === "attributes") {
if (mutation.attributeName === "aria-selected") {
onPeek(model)
}
mutations.forEach((mutation) => {
if (
mutation.type === "attributes" &&
mutation.attributeName === "aria-selected" &&
ref.current?.getAttribute("aria-selected") === "true"
) {
onPeek(model)
}
}
})
})
return (
@@ -2,8 +2,9 @@
import * as React from "react"
import { Dialog } from "@radix-ui/react-dialog"
import { DotsHorizontalIcon } from "@radix-ui/react-icons"
import { MoreHorizontal } from "lucide-react"
import { toast } from "@/registry/new-york/hooks/use-toast"
import {
AlertDialog,
AlertDialogCancel,
@@ -40,9 +41,9 @@ export function PresetActions() {
<>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="secondary">
<Button variant="secondary" size="icon">
<span className="sr-only">Actions</span>
<DotsHorizontalIcon className="h-4 w-4" />
<MoreHorizontal />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
@@ -2,8 +2,8 @@
import * as React from "react"
import { useRouter } from "next/navigation"
import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons"
import { PopoverProps } from "@radix-ui/react-popover"
import { Check, ChevronsUpDown } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/registry/default/ui/button"
@@ -42,39 +42,41 @@ export function PresetSelector({ presets, ...props }: PresetSelectorProps) {
className="flex-1 justify-between md:max-w-[200px] lg:max-w-[300px]"
>
{selectedPreset ? selectedPreset.name : "Load a preset..."}
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
<ChevronsUpDown className="opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[300px] p-0">
<Command>
<CommandInput placeholder="Search presets..." />
<CommandEmpty>No presets found.</CommandEmpty>
<CommandGroup heading="Examples">
{presets.map((preset) => (
<CommandItem
key={preset.id}
onSelect={() => {
setSelectedPreset(preset)
setOpen(false)
}}
>
{preset.name}
<CheckIcon
className={cn(
"ml-auto h-4 w-4",
selectedPreset?.id === preset.id
? "opacity-100"
: "opacity-0"
)}
/>
<CommandList>
<CommandEmpty>No presets found.</CommandEmpty>
<CommandGroup heading="Examples">
{presets.map((preset) => (
<CommandItem
key={preset.id}
onSelect={() => {
setSelectedPreset(preset)
setOpen(false)
}}
>
{preset.name}
<Check
className={cn(
"ml-auto",
selectedPreset?.id === preset.id
? "opacity-100"
: "opacity-0"
)}
/>
</CommandItem>
))}
</CommandGroup>
<CommandGroup className="pt-0">
<CommandItem onSelect={() => router.push("/examples")}>
More examples
</CommandItem>
))}
</CommandGroup>
<CommandGroup className="pt-0">
<CommandItem onSelect={() => router.push("/examples")}>
More examples
</CommandItem>
</CommandGroup>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
@@ -1,4 +1,4 @@
import { CopyIcon } from "@radix-ui/react-icons"
import { Copy } from "lucide-react"
import { Button } from "@/registry/default/ui/button"
import { Input } from "@/registry/default/ui/input"
@@ -37,7 +37,7 @@ export function PresetShare() {
</div>
<Button type="submit" size="sm" className="px-3">
<span className="sr-only">Copy</span>
<CopyIcon className="h-4 w-4" />
<Copy />
</Button>
</div>
</PopoverContent>
+4 -4
View File
@@ -1,6 +1,6 @@
import { Metadata } from "next"
import Image from "next/image"
import { CounterClockwiseClockIcon } from "@radix-ui/react-icons"
import { RotateCcw } from "lucide-react"
import { Button } from "@/registry/default/ui/button"
import {
@@ -265,7 +265,7 @@ export default function PlaygroundPage() {
<Button>Submit</Button>
<Button variant="secondary">
<span className="sr-only">Show history</span>
<CounterClockwiseClockIcon className="h-4 w-4" />
<RotateCcw />
</Button>
</div>
</div>
@@ -283,7 +283,7 @@ export default function PlaygroundPage() {
<Button>Submit</Button>
<Button variant="secondary">
<span className="sr-only">Show history</span>
<CounterClockwiseClockIcon className="h-4 w-4" />
<RotateCcw />
</Button>
</div>
</div>
@@ -314,7 +314,7 @@ export default function PlaygroundPage() {
<Button>Submit</Button>
<Button variant="secondary">
<span className="sr-only">Show history</span>
<CounterClockwiseClockIcon className="h-4 w-4" />
<RotateCcw />
</Button>
</div>
</div>
+14 -1
View File
@@ -88,7 +88,19 @@ export default function RootLayout({ children }: RootLayoutProps) {
return (
<>
<html lang="en" suppressHydrationWarning>
<head />
<head>
<script
dangerouslySetInnerHTML={{
__html: `
try {
if (localStorage.theme === 'dark' || ((!('theme' in localStorage) || localStorage.theme === 'system') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '${META_THEME_COLORS.dark}')
}
} catch (_) {}
`,
}}
/>
</head>
<body
className={cn(
"min-h-svh bg-background font-sans antialiased",
@@ -101,6 +113,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
defaultTheme="system"
enableSystem
disableTransitionOnChange
enableColorScheme
>
<Web3Provider>
<ActiveThemeProvider initialTheme="neutral">
+9 -8
View File
@@ -1,18 +1,19 @@
import { cn } from "@/lib/utils"
import {
Alert,
AlertDescription,
AlertTitle,
} from "@/registry/default/ui/alert"
interface CalloutProps {
icon?: string
title?: string
children?: React.ReactNode
}
export function Callout({ title, children, icon, ...props }: CalloutProps) {
export function Callout({
title,
children,
icon,
className,
...props
}: React.ComponentProps<typeof Alert> & { icon?: string }) {
return (
<Alert {...props}>
<Alert className={cn("bg-muted/50", className)} {...props}>
{icon && <span className="mr-4 text-2xl">{icon}</span>}
{title && <AlertTitle>{title}</AlertTitle>}
<AlertDescription>{children}</AlertDescription>
+37 -10
View File
@@ -10,7 +10,9 @@ import { Event } from "@/lib/events"
import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"
import { Callout } from "@/components/callout"
import { CodeBlockCommand } from "@/components/code-block-command"
import { CodeBlockWrapper } from "@/components/code-block-wrapper"
import { CodeTabs } from "@/components/code-tabs"
import { ComponentExample } from "@/components/component-example"
import { ComponentPreview } from "@/components/component-preview"
import { ComponentSource } from "@/components/component-source"
@@ -45,6 +47,7 @@ const components = {
Alert,
AlertTitle,
AlertDescription,
Button,
h1: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h1
className={cn(
@@ -57,7 +60,7 @@ const components = {
h2: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h2
className={cn(
"font-heading mt-12 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight first:mt-0",
"font-heading mt-16 scroll-m-20 border-b pb-4 text-xl font-semibold tracking-tight first:mt-0",
className
)}
{...props}
@@ -66,7 +69,7 @@ const components = {
h3: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
<h3
className={cn(
"font-heading mt-8 scroll-m-20 text-xl font-semibold tracking-tight",
"font-heading mt-8 scroll-m-20 text-lg font-semibold tracking-tight",
className
)}
{...props}
@@ -107,10 +110,13 @@ const components = {
),
p: ({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (
<p
className={cn("leading-7 [&:not(:first-child)]:mt-6", className)}
className={cn("leading-[1.65rem] [&:not(:first-child)]:mt-6", className)}
{...props}
/>
),
strong: ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => (
<strong className={cn("font-semibold", className)} {...props} />
),
ul: ({ className, ...props }: React.HTMLAttributes<HTMLUListElement>) => (
<ul className={cn("my-6 ml-6 list-disc", className)} {...props} />
),
@@ -143,19 +149,25 @@ const components = {
),
table: ({ className, ...props }: React.HTMLAttributes<HTMLTableElement>) => (
<div className="my-6 w-full overflow-y-auto">
<table className={cn("w-full", className)} {...props} />
<table
className={cn(
"relative w-full overflow-hidden border-none text-sm",
className
)}
{...props}
/>
</div>
),
tr: ({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>) => (
<tr
className={cn("m-0 border-t p-0 even:bg-muted", className)}
className={cn("last:border-b-none m-0 border-b", className)}
{...props}
/>
),
th: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<th
className={cn(
"border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
"px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
@@ -164,7 +176,7 @@ const components = {
td: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<td
className={cn(
"border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
"px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right",
className
)}
{...props}
@@ -189,16 +201,30 @@ const components = {
__src__?: string
__event__?: Event["name"]
} & NpmCommands) => {
const isNpmCommand =
__npmCommand__ && __yarnCommand__ && __pnpmCommand__ && __bunCommand__
if (isNpmCommand) {
return (
<CodeBlockCommand
__npmCommand__={__npmCommand__}
__yarnCommand__={__yarnCommand__}
__pnpmCommand__={__pnpmCommand__}
__bunCommand__={__bunCommand__}
/>
)
}
return (
<StyleWrapper styleName={__style__}>
<pre
className={cn(
"mb-4 mt-6 max-h-[650px] overflow-x-auto rounded-lg border bg-zinc-950 py-4 dark:bg-zinc-900",
"mb-4 mt-6 max-h-[650px] overflow-x-auto rounded-xl bg-zinc-950 py-4 dark:bg-zinc-900",
className
)}
{...props}
/>
{__rawString__ && !__npmCommand__ && (
{__rawString__ && (
<CopyButton
value={__rawString__}
src={__src__}
@@ -241,6 +267,7 @@ const components = {
CodeBlockWrapper: ({ ...props }) => (
<CodeBlockWrapper className="rounded-md border" {...props} />
),
CodeTabs,
Step: ({ className, ...props }: React.ComponentProps<"h3">) => (
<h3
className={cn(
@@ -252,7 +279,7 @@ const components = {
),
Steps: ({ ...props }) => (
<div
className="[&>h3]:step steps mb-12 ml-4 border-l pl-8 [counter-reset:step]"
className="[&>h3]:step steps mb-12 [counter-reset:step] md:ml-4 md:border-l md:pl-8"
{...props}
/>
),
+12 -14
View File
@@ -21,22 +21,20 @@ export function DocsPager({ doc }: DocsPagerProps) {
return (
<div className="flex flex-row items-center justify-between">
{pager?.prev?.href && (
<Link
href={pager.prev.href}
className={buttonVariants({ variant: "outline" })}
>
<ChevronLeftIcon className="mr-2 h-4 w-4" />
{pager.prev.title}
</Link>
<Button variant="ghost" asChild>
<Link href={pager.prev.href}>
<ChevronLeft />
{pager.prev.title}
</Link>
</Button>
)}
{pager?.next?.href && (
<Link
href={pager.next.href}
className={cn(buttonVariants({ variant: "outline" }), "ml-auto")}
>
{pager.next.title}
<ChevronRightIcon className="ml-2 h-4 w-4" />
</Link>
<Button variant="ghost" className="ml-auto" asChild>
<Link href={pager.next.href}>
{pager.next.title}
<ChevronRight />
</Link>
</Button>
)}
</div>
)
+23 -21
View File
@@ -4,24 +4,28 @@ import Link from "next/link"
import { usePathname } from "next/navigation"
import { SidebarNavItem } from "types/nav"
import { type DocsConfig } from "@/config/docs"
import { cn } from "@/lib/utils"
export interface DocsSidebarNavProps {
items: SidebarNavItem[]
}
export function DocsSidebarNav({ items }: DocsSidebarNavProps) {
export function DocsNav({ config }: { config: DocsConfig }) {
const pathname = usePathname()
const items = config.sidebarNav
return items.length ? (
<div className="w-full">
<div className="flex flex-col gap-6">
{items.map((item, index) => (
<div key={index} className={cn("pb-4")}>
<h4 className="mb-1 rounded-md px-2 py-1 text-sm font-semibold">
{item.title}
<div key={index} className="flex flex-col gap-1">
<h4 className="rounded-md px-2 py-1 text-sm font-medium">
{item.title}{" "}
{item.label && (
<span className="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs font-normal leading-none text-[#000000] no-underline group-hover:no-underline">
{item.label}
</span>
)}
</h4>
{item?.items?.length && (
<DocsSidebarNavItems items={item.items} pathname={pathname} />
<DocsNavItems items={item.items} pathname={pathname} />
)}
</div>
))}
@@ -29,28 +33,26 @@ export function DocsSidebarNav({ items }: DocsSidebarNavProps) {
) : null
}
interface DocsSidebarNavItemsProps {
items: SidebarNavItem[]
pathname: string | null
}
export function DocsSidebarNavItems({
function DocsNavItems({
items,
pathname,
}: DocsSidebarNavItemsProps) {
}: {
items: SidebarNavItem[]
pathname: string | null
}) {
return items?.length ? (
<div className="grid grid-flow-row auto-rows-max text-sm">
<div className="grid grid-flow-row auto-rows-max gap-0.5 text-sm">
{items.map((item, index) =>
item.href && !item.disabled ? (
<Link
key={index}
href={item.href}
className={cn(
"group flex w-full items-center rounded-md border border-transparent px-2 py-1 hover:underline",
"group relative flex h-8 w-full items-center rounded-lg px-2 after:absolute after:inset-x-0 after:inset-y-[-2px] after:rounded-lg hover:bg-accent hover:text-accent-foreground ",
item.disabled && "cursor-not-allowed opacity-60",
pathname === item.href
? "font-medium text-foreground"
: "text-muted-foreground"
? "bg-accent font-medium text-accent-foreground"
: "font-normal text-foreground"
)}
target={item.external ? "_blank" : ""}
rel={item.external ? "noreferrer" : ""}
+1 -1
View File
@@ -3,7 +3,7 @@
import * as React from "react"
import { useConfig } from "@/hooks/use-config"
import { Style } from "@/registry/styles"
import { Style } from "@/registry/registry-styles"
interface StyleWrapperProps extends React.HTMLAttributes<HTMLDivElement> {
styleName?: Style["name"]
+4 -1
View File
@@ -2,7 +2,10 @@ export function TailwindIndicator() {
if (process.env.NODE_ENV === "production") return null
return (
<div className="fixed bottom-1 left-1 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-gray-800 p-3 font-mono text-xs text-white">
<div
data-tailwind-indicator=""
className="fixed bottom-1 left-1 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-gray-800 p-3 font-mono text-xs text-white"
>
<div className="block sm:hidden">xs</div>
<div className="hidden sm:block md:hidden">sm</div>
<div className="hidden md:block lg:hidden">md</div>
+1 -1
View File
@@ -26,7 +26,7 @@ export function DashboardTableOfContents({ toc }: TocProps) {
const activeHeading = useActiveItem(itemIds)
const mounted = useMounted()
if (!toc?.items || !mounted) {
if (!toc?.items?.length) {
return null
}
+19 -19
View File
@@ -1,7 +1,7 @@
---
title: Changelog
description: Latest updates and announcements.
toc: false
title: June 2023 - New CLI, Styles and more
description: Complete CLI rewrite with new styles, theming options, and more.
date: 2023-06-22
---
## April 2024 - Introducing Lift Mode
@@ -299,7 +299,7 @@ This file contains all the information about your components: where to install t
You can use this file to change the import path of a component, set a baseColor or change the styling method.
```json title="components.json"
```json title="components.json" showLineNumbers
{
"style": "default",
"tailwind": {
@@ -382,7 +382,7 @@ When you add new components, the CLI will automatically use the correct theming
To use utility classes for theming set `tailwind.cssVariables` to `false` in your `components.json` file.
```json {6} title="components.json"
```json {6} title="components.json" showLineNumbers
{
"tailwind": {
"config": "tailwind.config.js",
@@ -401,7 +401,7 @@ To use utility classes for theming set `tailwind.cssVariables` to `false` in you
To use CSS variables classes for theming set `tailwind.cssVariables` to `true` in your `components.json` file.
```json {6} title="components.json"
```json {6} title="components.json" showLineNumbers
{
"tailwind": {
"config": "tailwind.config.js",
@@ -418,7 +418,7 @@ To use CSS variables classes for theming set `tailwind.cssVariables` to `true` i
You can now configure the base color for your project. This will be used to generate the default color palette for your components.
```json {5} title="components.json"
```json {5} title="components.json" showLineNumbers
{
"tailwind": {
"config": "tailwind.config.js",
@@ -439,7 +439,7 @@ If you have `cssVariables` set to `true`, we will set the base colors as CSS var
If you're using a framework that does not support React Server Components, you can now opt out by setting `rsc` to `false`. We will automatically append or remove the `use client` directive when adding components.
```json title="components.json"
```json title="components.json" showLineNumbers
{
"rsc": false
}
@@ -460,7 +460,7 @@ We are shipping two styles: `default` and `new-york` (with more coming soon).
width="716"
height="402"
alt="Default vs New York style"
className="border rounded-lg overflow-hidden mt-6"
className="mt-6 overflow-hidden rounded-lg border"
/>
The `default` style is the one you are used to. It's the one we've been using since the beginning of this project. It uses `lucide-react` for icons and `tailwindcss-animate` for animations.
@@ -469,7 +469,7 @@ The `new-york` style is a new style. It ships with smaller buttons, cards with s
When you run the `init` command, you will be asked which style you would like to use. This is saved in your `components.json` file.
```json title="components.json"
```json title="components.json" showLineNumbers
{
"style": "new-york"
}
@@ -484,7 +484,7 @@ Start with a style as the base then theme using CSS variables or Tailwind CSS ut
width="716"
height="402"
alt="Style with theming"
className="border rounded-lg overflow-hidden mt-6"
className="mt-6 overflow-hidden rounded-lg border"
/>
---
@@ -532,7 +532,7 @@ Since we follow a copy and paste approach, you will need to manually update your
Creating a `components.json` file at the root:
```json title="components.json"
```json title="components.json" showLineNumbers
{
"style": "default",
"rsc": true,
@@ -555,7 +555,7 @@ Update the values for `tailwind.css` and `aliases` to match your project structu
Add the `icon` size to the `buttonVariants`:
```tsx {7} title="components/ui/button.tsx"
```tsx {7} title="components/ui/button.tsx" showLineNumbers
const buttonVariants = cva({
variants: {
size: {
@@ -572,7 +572,7 @@ const buttonVariants = cva({
1. Replace the content of `sheet.tsx` with the following:
```tsx title="components/ui/sheet.tsx"
```tsx title="components/ui/sheet.tsx" showLineNumbers
"use client"
import * as React from "react"
@@ -602,7 +602,7 @@ const SheetOverlay = React.forwardRef<
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
"bg-background/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 backdrop-blur-sm",
className
)}
{...props}
@@ -646,7 +646,7 @@ const SheetContent = React.forwardRef<
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:pointer-events-none">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
@@ -689,7 +689,7 @@ const SheetTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
className={cn("text-foreground text-lg font-semibold", className)}
{...props}
/>
))
@@ -701,7 +701,7 @@ const SheetDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
))
@@ -730,4 +730,4 @@ export {
### Thank you
I'd like to thank everyone who has been using this project, providing feedback and contributing to it. I really appreciate it. Thank you 🙏
I'd like to thank everyone who has been using this project, providing feedback and contributing to it. I really appreciate it. Thank you.
+3 -3
View File
@@ -37,11 +37,11 @@ The style for your components. **This cannot be changed after initialization.**
```json title="components.json"
{
"style": "default" | "new-york"
"style": "new-york"
}
```
<ComponentPreview name="card-with-form" />
The `default` style has been deprecated. Use the `new-york` style instead.
## tailwind
@@ -51,7 +51,7 @@ See the <Link href="/docs/installation">installation section</Link> for how to s
### tailwind.config
Path to where your `tailwind.config.js` file is located.
Path to where your `tailwind.config.js` file is located. **For Tailwind CSS v4, leave this blank.**
```json title="components.json"
{
+2 -6
View File
@@ -15,7 +15,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -24,10 +24,6 @@ links:
<TabsContent value="cli">
<Steps>
<Step>Run the following command:</Step>
```bash
npx @hanzo/ui@latest add accordion
```
@@ -112,7 +108,7 @@ module.exports = {
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -15,7 +15,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -49,7 +49,7 @@ npm install @radix-ui/react-alert-dialog
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ component: true
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -39,7 +39,7 @@ npx @hanzo/ui@latest add alert
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+7 -3
View File
@@ -7,11 +7,15 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/aspect-ratio#api-reference
---
<ComponentPreview name="aspect-ratio-demo" />
<ComponentPreview
name="aspect-ratio-demo"
title="Aspect Ratio"
description="A component that displays an image with a 16:9 aspect ratio."
/>
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +49,7 @@ npm install @radix-ui/react-aspect-ratio
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-avatar
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -8,7 +8,7 @@ component: true
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -36,7 +36,7 @@ npx @hanzo/ui@latest add badge
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+18 -3
View File
@@ -6,7 +6,11 @@ links:
doc: https://react-day-picker.js.org
---
<ComponentPreview name="calendar-demo" />
<ComponentPreview
name="calendar-demo"
title="Calendar"
description="A calendar showing the current date."
/>
## About
@@ -14,7 +18,7 @@ The `Calendar` component is built on top of [React DayPicker](https://react-day-
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -52,7 +56,7 @@ The `Calendar` component uses the `Button` component. Make sure you have it inst
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
@@ -84,3 +88,14 @@ You can use the `<Calendar>` component to build a date picker. See the [Date Pic
### Form
<ComponentPreview name="calendar-form" />
## Changelog
### 11-03-2024 day_outside color
- Changed the color of the `day_outside` class to the following to improve contrast:
```tsx showLineNumbers title="calendar.tsx"
"day_outside:
"day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground",
```
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-checkbox
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -15,7 +15,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -49,7 +49,7 @@ npm install @radix-ui/react-collapsible
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+19 -3
View File
@@ -4,7 +4,10 @@ description: Autocomplete input and command palette with a list of suggestions.
component: true
---
<ComponentPreview name="combobox-demo" />
<ComponentPreview
name="combobox-demo"
description="A combobox with a list of frameworks."
/>
## Installation
@@ -28,6 +31,7 @@ import {
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command"
import {
Popover,
@@ -112,7 +116,10 @@ export function ComboboxDemo() {
### Combobox
<ComponentPreview name="combobox-demo" />
<ComponentPreview
name="combobox-demo"
description="A combobox with a list of frameworks."
/>
### Popover
@@ -120,7 +127,16 @@ export function ComboboxDemo() {
### Dropdown menu
<ComponentPreview name="combobox-dropdown-menu" />
<ComponentPreview
name="combobox-dropdown-menu"
description="A combobox in a dropdown menu"
/>
### Responsive
You can create a responsive combobox by using the `<Popover />` on desktop and the `<Drawer />` components on mobile.
<ComponentPreview name="combobox-responsive" />
### Responsive
+30 -3
View File
@@ -19,7 +19,7 @@ The `<Command />` component uses the [`cmdk`](https://cmdk.paco.me) component by
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -53,7 +53,7 @@ npm install cmdk
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
@@ -95,7 +95,10 @@ import {
### Dialog
<ComponentPreview name="command-dialog" />
<ComponentPreview
name="command-dialog"
description="A command menu in a dialog"
/>
To show the command menu in a dialog, use the `<CommandDialog />` component.
@@ -133,3 +136,27 @@ export function CommandMenu() {
### Combobox
You can use the `<Command />` component as a combobox. See the [Combobox](/docs/components/combobox) page for more information.
## Changelog
### 2024-10-25 Classes for icons
Added `gap-2 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0` to the `<CommandItem />` to automatically style icon inside.
Add the following classes to the `cva` call in your `command.tsx` file.
```tsx showLineNumbers title="command.tsx"
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"... gap-2 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
className
)}
{...props}
/>
))
```
+2 -2
View File
@@ -14,7 +14,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -48,7 +48,7 @@ npm install @radix-ui/react-context-menu
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+9 -9
View File
@@ -6,13 +6,13 @@ links:
doc: https://tanstack.com/table/v8/docs/guide/introduction
---
<ComponentPreview name="data-table-demo" />
<ComponentPreview name="data-table-demo" className="[&_.preview]:items-start" />
## Introduction
Every data table or datagrid I've created has been unique. They all behave differently, have specific sorting and filtering requirements, and work with different data sources.
It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/guide/introduction#what-is-headless-ui) provides.
It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/introduction#what-is-headless-ui) provides.
So instead of a data-table component, I thought it would be more helpful to provide a guide on how to build your own.
@@ -185,7 +185,7 @@ export function DataTable<TData, TValue>({
})
return (
<div className="rounded-md border">
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
@@ -425,7 +425,7 @@ export function DataTable<TData, TValue>({
return (
<div>
<div className="rounded-md border">
<div className="overflow-hidden rounded-md border">
<Table>
{ // .... }
</Table>
@@ -499,7 +499,7 @@ export function DataTable<TData, TValue>({
return (
<div>
<div className="rounded-md border">
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
@@ -515,7 +515,7 @@ We can now update the `email` header cell to add sorting controls.
"use client"
import { ColumnDef } from "@tanstack/react-table"
import { ArrowUpDown, MoreHorizontal } from "lucide-react"
import { ArrowUpDown } from "lucide-react"
export const columns: ColumnDef<Payment>[] = [
{
@@ -602,7 +602,7 @@ export function DataTable<TData, TValue>({
className="max-w-sm"
/>
</div>
<div className="rounded-md border">
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
@@ -715,7 +715,7 @@ export function DataTable<TData, TValue>({
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="rounded-md border">
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
@@ -805,7 +805,7 @@ export function DataTable<TData, TValue>({
return (
<div>
<div className="rounded-md border">
<div className="overflow-hidden rounded-md border">
<Table />
</div>
</div>
+16 -4
View File
@@ -4,7 +4,10 @@ description: A date picker component with range and presets.
component: true
---
<ComponentPreview name="date-picker-demo" />
<ComponentPreview
name="date-picker-demo"
description="A date picker in a popover"
/>
## Installation
@@ -66,15 +69,24 @@ See the [React DayPicker](https://react-day-picker.js.org) documentation for mor
### Date Picker
<ComponentPreview name="date-picker-demo" />
<ComponentPreview
name="date-picker-demo"
description="A date picker in a popover"
/>
### Date Range Picker
<ComponentPreview name="date-picker-with-range" />
<ComponentPreview
name="date-picker-with-range"
description="A date range picker"
/>
### With Presets
<ComponentPreview name="date-picker-with-presets" />
<ComponentPreview
name="date-picker-with-presets"
description="A date picker with presets"
/>
### Form
+2 -2
View File
@@ -15,7 +15,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -49,7 +49,7 @@ npm install @radix-ui/react-dialog
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-hover-card
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -12,7 +12,7 @@ component: true
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -40,7 +40,7 @@ npx @hanzo/ui@latest add input
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-label
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+3 -3
View File
@@ -7,11 +7,11 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/menubar#api-reference
---
<ComponentPreview name="menubar-demo" />
<ComponentPreview name="menubar-demo" description="A menubar component." />
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-menubar
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-navigation-menu
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -14,7 +14,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -48,7 +48,7 @@ npm install @radix-ui/react-popover
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+6 -3
View File
@@ -7,11 +7,14 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/progress#api-reference
---
<ComponentPreview name="progress-demo" />
<ComponentPreview
name="progress-demo"
description="A progress bar component."
/>
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +48,7 @@ npm install @radix-ui/react-progress
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -14,7 +14,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -48,7 +48,7 @@ npm install @radix-ui/react-radio-group
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+6 -3
View File
@@ -7,11 +7,14 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/scroll-area#api-reference
---
<ComponentPreview name="scroll-area-demo" />
<ComponentPreview
name="scroll-area-demo"
description="A scroll area component."
/>
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +48,7 @@ npm install @radix-ui/react-scroll-area
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -15,7 +15,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -49,7 +49,7 @@ npm install @radix-ui/react-select
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -44,7 +44,7 @@ npm install @radix-ui/react-separator
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-dialog
</TabsContent>
</Tabs>
</CodeTabs>
### Usage
+2 -2
View File
@@ -8,7 +8,7 @@ component: true
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -36,7 +36,7 @@ npx @hanzo/ui@latest add skeleton
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-slider
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-switch
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+3 -3
View File
@@ -4,11 +4,11 @@ description: A responsive table component.
component: true
---
<ComponentPreview name="table-demo" />
<ComponentPreview name="table-demo" description="A table component." />
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -36,7 +36,7 @@ npx @hanzo/ui@latest add table
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -14,7 +14,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -48,7 +48,7 @@ npm install @radix-ui/react-tabs
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -8,7 +8,7 @@ component: true
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -36,7 +36,7 @@ npx @hanzo/ui@latest add textarea
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+10 -3
View File
@@ -7,11 +7,18 @@ links:
api: https://www.radix-ui.com/docs/primitives/components/toast#api-reference
---
<Callout>
We're deprecating the `toast` component in favor of `sonner` in projects using Tailwind v4 and React 19.
[Read more](https://ui.shadcn.com/docs/tailwind-v4#whats-new)
</Callout>
<ComponentPreview name="toast-demo" />
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -97,14 +104,14 @@ export default function RootLayout({ children }) {
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
The `useToast` hook returns a `toast` function that you can use to display a toast.
```tsx
import { useToast } from "@/components/ui/use-toast"
import { useToast } from "@/hooks/use-toast"
```
```tsx {2,7-10}
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-toggle
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+2 -2
View File
@@ -11,7 +11,7 @@ links:
## Installation
<Tabs defaultValue="cli">
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
@@ -45,7 +45,7 @@ npm install @radix-ui/react-tooltip
</TabsContent>
</Tabs>
</CodeTabs>
## Usage
+6 -3
View File
@@ -24,16 +24,19 @@ import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
import type { ThemeProviderProps } from "next-themes"
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
```
### Wrap your root layout
Add the `ThemeProvider` to your root layout.
Add the `ThemeProvider` to your root layout and add the `suppressHydrationWarning` prop to the `html` tag.
```tsx {1,9-11} title="app/layout.tsx"
```tsx {1,6,9-14,16} title="app/layout.tsx"
import { ThemeProvider } from "@/components/theme-provider"
export default function RootLayout({ children }: RootLayoutProps) {
+6
View File
@@ -3,6 +3,12 @@ title: Gatsby
description: Install and configure Gatsby.
---
<Callout className="mb-6 border-blue-600 bg-blue-50 dark:border-blue-900 dark:bg-blue-950 [&_code]:bg-blue-100 dark:[&_code]:bg-blue-900">
**Update:** We have added full support for React 19 and Tailwind v4 in the
`canary` release. See the docs for [Tailwind v4](/docs/tailwind-v4) for more
information.
</Callout>
<Steps>
### Create project
+16 -11
View File
@@ -1,8 +1,19 @@
---
title: Remix
description: Install and configure Remix.
description: Install and configure shadcn/ui for Remix.
---
<Callout className="bg-blue-50 border-blue-600 dark:border-blue-900 dark:bg-blue-950 mb-6 [&_code]:bg-blue-100 dark:[&_code]:bg-blue-900">
**Note:** The following guide is for Tailwind v4. If you are using Tailwind
v3, use `shadcn@2.3.0`.
</Callout>
<Callout>
**Note:** This guide is for Remix. For React Router, see the [React Router](/docs/installation/react-router) guide.
</Callout>
<Steps>
### Create project
@@ -26,15 +37,9 @@ npx @hanzo/ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? Default
Which color would you like to use as base color? Slate
Where is your global CSS file? app/tailwind.css
Which style would you like to use? New York
Which color would you like to use as base color? Zinc
Do you want to use CSS variables for colors? no / yes
Where is your tailwind.config.js located? tailwind.config.js
Configure the import alias for components: ~/components
Configure the import alias for utils: ~/lib/utils
Are you using React Server Components? no
```
### App structure
@@ -53,7 +58,7 @@ Are you using React Server Components? no
### Install Tailwind CSS
```bash
npm add -D tailwindcss@latest autoprefixer@latest
npm install -D tailwindcss@latest autoprefixer@latest
```
Then we create a `postcss.config.js` file:
@@ -84,7 +89,7 @@ export default {
In your `app/root.tsx` file, import the `tailwind.css` file:
```js {1, 4}
import styles from "./tailwind.css"
import styles from "./tailwind.css?url"
export const links: LinksFunction = () => [
{ rel: "stylesheet", href: styles },
+3 -7
View File
@@ -4,7 +4,7 @@ import {
defineDocumentType,
defineNestedType,
makeSource,
} from "contentlayer/source-files"
} from "contentlayer2/source-files"
import rehypeAutolinkHeadings from "rehype-autolink-headings"
import rehypePrettyCode from "rehype-pretty-code"
import rehypeSlug from "rehype-slug"
@@ -114,12 +114,8 @@ export default makeSource({
[
rehypePrettyCode,
{
getHighlighter: async () => {
const theme = await loadTheme(
path.join(process.cwd(), "/lib/themes/dark.json")
)
return await getHighlighter({ theme })
},
theme: "github-dark-default",
getHighlighter,
onVisitLine(node) {
// Prevent lines from collapsing in `display: grid` mode, and allow empty
// lines to be copy/pasted
-3
View File
@@ -1,9 +1,6 @@
import { useAtom } from "jotai"
import { atomWithStorage } from "jotai/utils"
import { Style } from "@/registry/styles"
import { Theme } from "@/registry/themes"
type Config = {
style: Style["name"]
theme: Theme["name"]
+4 -4
View File
@@ -6,7 +6,7 @@ import { u } from "unist-builder"
import { visit } from "unist-util-visit"
import { Index } from "../__registry__"
import { styles } from "../registry/styles"
import { styles } from "../registry/registry-styles"
export function rehypeComponent() {
return async (tree: UnistTree) => {
@@ -48,7 +48,7 @@ export function rehypeComponent() {
}
// Read the source file.
const filePath = path.join(process.cwd(), src)
const filePath = src
let source = fs.readFileSync(filePath, "utf8")
// Replace imports.
@@ -107,10 +107,10 @@ export function rehypeComponent() {
try {
for (const style of styles) {
const component = Index[style.name][name]
const src = component.files[0]
const src = component.files[0]?.path
// Read the source file.
const filePath = path.join(process.cwd(), src)
const filePath = src
let source = fs.readFileSync(filePath, "utf8")
// Replace imports.
+1 -1
View File
@@ -27,7 +27,7 @@ export function rehypeNpmCommand() {
)
}
// npx create.
// npx create-.
if (node.properties?.["__rawString__"]?.startsWith("npx create-")) {
const npmCommand = node.properties?.["__rawString__"]
node.properties["__npmCommand__"] = npmCommand
+12 -2
View File
@@ -63,7 +63,12 @@
"destructive-foreground": "210 20% 98%",
"border": "220 13% 91%",
"input": "220 13% 91%",
"ring": "224 71.4% 4.1%"
"ring": "224 71.4% 4.1%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "224 71.4% 4.1%",
@@ -84,7 +89,12 @@
"destructive-foreground": "210 20% 98%",
"border": "215 27.9% 16.9%",
"input": "215 27.9% 16.9%",
"ring": "216 12.2% 83.9%"
"ring": "216 12.2% 83.9%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
},
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
+12 -2
View File
@@ -63,7 +63,12 @@
"destructive-foreground": "0 0% 98%",
"border": "0 0% 89.8%",
"input": "0 0% 89.8%",
"ring": "0 0% 3.9%"
"ring": "0 0% 3.9%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "0 0% 3.9%",
@@ -84,7 +89,12 @@
"destructive-foreground": "0 0% 98%",
"border": "0 0% 14.9%",
"input": "0 0% 14.9%",
"ring": "0 0% 83.1%"
"ring": "0 0% 83.1%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
},
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
+6 -1
View File
@@ -63,7 +63,12 @@
"destructive-foreground": "210 40% 98%",
"border": "214.3 31.8% 91.4%",
"input": "214.3 31.8% 91.4%",
"ring": "222.2 84% 4.9%"
"ring": "222.2 84% 4.9%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "222.2 84% 4.9%",
+12 -2
View File
@@ -63,7 +63,12 @@
"destructive-foreground": "60 9.1% 97.8%",
"border": "20 5.9% 90%",
"input": "20 5.9% 90%",
"ring": "20 14.3% 4.1%"
"ring": "20 14.3% 4.1%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "20 14.3% 4.1%",
@@ -84,7 +89,12 @@
"destructive-foreground": "60 9.1% 97.8%",
"border": "12 6.5% 15.1%",
"input": "12 6.5% 15.1%",
"ring": "24 5.7% 82.9%"
"ring": "24 5.7% 82.9%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
},
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
+12 -2
View File
@@ -63,7 +63,12 @@
"destructive-foreground": "0 0% 98%",
"border": "240 5.9% 90%",
"input": "240 5.9% 90%",
"ring": "240 10% 3.9%"
"ring": "240 10% 3.9%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "240 10% 3.9%",
@@ -84,7 +89,12 @@
"destructive-foreground": "0 0% 98%",
"border": "240 3.7% 15.9%",
"input": "240 3.7% 15.9%",
"ring": "240 4.9% 83.9%"
"ring": "240 4.9% 83.9%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
},
"inlineColorsTemplate": "@tailwind base;\n @tailwind components;\n @tailwind utilities;\n ",
+12 -2
View File
@@ -21,7 +21,12 @@
"destructive-foreground": "210 20% 98%",
"border": "220 13% 91%",
"input": "220 13% 91%",
"ring": "224 71.4% 4.1%"
"ring": "224 71.4% 4.1%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "224 71.4% 4.1%",
@@ -42,7 +47,12 @@
"destructive-foreground": "210 20% 98%",
"border": "215 27.9% 16.9%",
"input": "215 27.9% 16.9%",
"ring": "216 12.2% 83.9%"
"ring": "216 12.2% 83.9%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
}
}
+12 -2
View File
@@ -21,7 +21,12 @@
"destructive-foreground": "0 0% 98%",
"border": "0 0% 89.8%",
"input": "0 0% 89.8%",
"ring": "0 0% 3.9%"
"ring": "0 0% 3.9%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "0 0% 3.9%",
@@ -42,7 +47,12 @@
"destructive-foreground": "0 0% 98%",
"border": "0 0% 14.9%",
"input": "0 0% 14.9%",
"ring": "0 0% 83.1%"
"ring": "0 0% 83.1%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
}
}
+6 -1
View File
@@ -21,7 +21,12 @@
"destructive-foreground": "210 40% 98%",
"border": "214.3 31.8% 91.4%",
"input": "214.3 31.8% 91.4%",
"ring": "222.2 84% 4.9%"
"ring": "222.2 84% 4.9%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "222.2 84% 4.9%",
+12 -2
View File
@@ -21,7 +21,12 @@
"destructive-foreground": "60 9.1% 97.8%",
"border": "20 5.9% 90%",
"input": "20 5.9% 90%",
"ring": "20 14.3% 4.1%"
"ring": "20 14.3% 4.1%",
"chart-1": "12 76% 61%",
"chart-2": "173 58% 39%",
"chart-3": "197 37% 24%",
"chart-4": "43 74% 66%",
"chart-5": "27 87% 67%"
},
"dark": {
"background": "20 14.3% 4.1%",
@@ -42,7 +47,12 @@
"destructive-foreground": "60 9.1% 97.8%",
"border": "12 6.5% 15.1%",
"input": "12 6.5% 15.1%",
"ring": "24 5.7% 82.9%"
"ring": "24 5.7% 82.9%",
"chart-1": "220 70% 50%",
"chart-2": "160 60% 45%",
"chart-3": "30 80% 55%",
"chart-4": "280 65% 60%",
"chart-5": "340 75% 55%"
}
}
}

Some files were not shown because too many files have changed in this diff Show More