mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-11 09:51:40 +00:00
Compare commits
55 Commits
shadcn@4.5
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fcae29af2 | ||
|
|
4a4dc8eb0f | ||
|
|
a33becad35 | ||
|
|
d60e8b6ce3 | ||
|
|
072c27fcd5 | ||
|
|
194dcc4571 | ||
|
|
51e3cfaf32 | ||
|
|
c8ab3801ec | ||
|
|
731e6dd8a2 | ||
|
|
d7066f4a2d | ||
|
|
5274de83d6 | ||
|
|
7e4dac7f31 | ||
|
|
28122dba18 | ||
|
|
93cde61946 | ||
|
|
c2dc06a99c | ||
|
|
c9930b7fda | ||
|
|
d1149454a8 | ||
|
|
36139f6200 | ||
|
|
15ac1be92b | ||
|
|
8ca30ed32c | ||
|
|
e2605bc7c2 | ||
|
|
b8608d0976 | ||
|
|
fc1ca40af4 | ||
|
|
f454f6e4d1 | ||
|
|
8cc7073aec | ||
|
|
031387a471 | ||
|
|
dd3567c39d | ||
|
|
ad2b8891a5 | ||
|
|
f6e18c65cf | ||
|
|
1c4a53a37a | ||
|
|
bc2db187aa | ||
|
|
92b4927a80 | ||
|
|
3cbabe012e | ||
|
|
1137b24a97 | ||
|
|
bb251e2ab6 | ||
|
|
28b3e5f360 | ||
|
|
309d95017f | ||
|
|
eb42ae25fd | ||
|
|
3977fb9ace | ||
|
|
7865621397 | ||
|
|
b07070cd07 | ||
|
|
ad68a44717 | ||
|
|
56161142f1 | ||
|
|
c2e1a5793f | ||
|
|
ea6086cbcc | ||
|
|
68a69d81f7 | ||
|
|
55fd4dc71b | ||
|
|
6dea65ebcb | ||
|
|
ba10089b8d | ||
|
|
8a814f926b | ||
|
|
c236d0c009 | ||
|
|
fd0e0c369b | ||
|
|
07d14abde1 | ||
|
|
8dd51c49f8 | ||
|
|
c20e0cc596 |
6
.github/workflows/code-check.yml
vendored
6
.github/workflows/code-check.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: Use PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
- name: Use PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
|
||||
75
.github/workflows/signed-commits.yml
vendored
Normal file
75
.github/workflows/signed-commits.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: Signed commits
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- ready_for_review
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
signed-commits:
|
||||
if: github.repository_owner == 'shadcn-ui'
|
||||
runs-on: ubuntu-latest
|
||||
name: Signed commits
|
||||
steps:
|
||||
- name: Check PR commits
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const body = "Can you sign the commits please? See https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits. Thank you."
|
||||
|
||||
const { owner, repo } = context.repo
|
||||
const pullNumber = context.payload.pull_request.number
|
||||
|
||||
const commits = await github.paginate(github.rest.pulls.listCommits, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: pullNumber,
|
||||
per_page: 100,
|
||||
})
|
||||
|
||||
const unsignedCommits = commits.filter((commit) => {
|
||||
return commit.commit.verification?.reason === "unsigned"
|
||||
})
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pullNumber,
|
||||
per_page: 100,
|
||||
})
|
||||
|
||||
const existingComments = comments.filter((comment) => {
|
||||
return comment.user.type === "Bot" && comment.body.trim() === body
|
||||
})
|
||||
|
||||
if (unsignedCommits.length > 0) {
|
||||
core.info(`Found ${unsignedCommits.length} unsigned commits.`)
|
||||
|
||||
if (existingComments.length === 0) {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pullNumber,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
core.info("All commits are signed.")
|
||||
|
||||
for (const comment of existingComments) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: comment.id,
|
||||
})
|
||||
}
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
|
||||
2
.github/workflows/validate-registries.yml
vendored
2
.github/workflows/validate-registries.yml
vendored
@@ -108,7 +108,7 @@ jobs:
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 9.0.6
|
||||
version: 10.33.4
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
|
||||
@@ -12,20 +12,25 @@ import { HugeiconsIcon } from "@hugeicons/react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useConfig } from "@/hooks/use-config"
|
||||
import { copyToClipboardWithMeta } from "@/components/copy-button"
|
||||
import { BASES, type BaseName } from "@/registry/config"
|
||||
import {
|
||||
BASES,
|
||||
buildThemeForPreset,
|
||||
DEFAULT_CONFIG,
|
||||
type BaseName,
|
||||
type DesignSystemConfig,
|
||||
} from "@/registry/config"
|
||||
import { Button } from "@/styles/base-nova/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/styles/base-nova/ui/dialog"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
@@ -41,6 +46,10 @@ import {
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/styles/base-nova/ui/tabs"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/styles/base-nova/ui/toggle-group"
|
||||
import { usePresetCode } from "@/app/(app)/create/hooks/use-design-system"
|
||||
import {
|
||||
useDesignSystemSearchParams,
|
||||
@@ -61,6 +70,54 @@ const SHADCN_VERSION = process.env.NEXT_PUBLIC_RC ? "@rc" : "@latest"
|
||||
const PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"] as const
|
||||
type PackageManager = (typeof PACKAGE_MANAGERS)[number]
|
||||
|
||||
const APPLY_MODES = [
|
||||
{
|
||||
value: "full",
|
||||
title: "Full preset",
|
||||
description:
|
||||
"Everything from the preset, including components, theme, and fonts.",
|
||||
flag: null,
|
||||
label: "full preset",
|
||||
},
|
||||
{
|
||||
value: "theme",
|
||||
title: "Theme only",
|
||||
description:
|
||||
"Theme tokens only, like colors, radii, and shadows. Components stay as they are.",
|
||||
flag: "--only theme",
|
||||
label: "--only theme",
|
||||
},
|
||||
{
|
||||
value: "font",
|
||||
title: "Fonts only",
|
||||
description:
|
||||
"Only preset fonts for body and headings. Components stay as they are.",
|
||||
flag: "--only font",
|
||||
label: "--only font",
|
||||
},
|
||||
] as const
|
||||
type ApplyMode = (typeof APPLY_MODES)[number]["value"]
|
||||
type ProjectFormTab = "new-project" | "existing-project" | "theme"
|
||||
type CopyTarget = "command" | "apply" | "theme"
|
||||
type ThemeCssVars = NonNullable<
|
||||
ReturnType<typeof buildThemeForPreset>["cssVars"]
|
||||
>
|
||||
|
||||
function formatCssVarsRule(selector: string, cssVars?: Record<string, string>) {
|
||||
const declarations = Object.entries(cssVars ?? {})
|
||||
.map(([key, value]) => ` --${key}: ${value};`)
|
||||
.join("\n")
|
||||
|
||||
return `${selector} {\n${declarations}\n}`
|
||||
}
|
||||
|
||||
function formatThemeCss(cssVars: ThemeCssVars) {
|
||||
return [
|
||||
formatCssVarsRule(":root", cssVars.light),
|
||||
formatCssVarsRule(".dark", cssVars.dark),
|
||||
].join("\n\n")
|
||||
}
|
||||
|
||||
export function ProjectForm({
|
||||
className,
|
||||
}: React.ComponentProps<typeof Button>) {
|
||||
@@ -68,7 +125,12 @@ export function ProjectForm({
|
||||
const [params, setParams] = useDesignSystemSearchParams()
|
||||
const presetCode = usePresetCode()
|
||||
const [config, setConfig] = useConfig()
|
||||
const [hasCopied, setHasCopied] = React.useState(false)
|
||||
const [copiedTarget, setCopiedTarget] = React.useState<CopyTarget | null>(
|
||||
null
|
||||
)
|
||||
const [applyMode, setApplyMode] = React.useState<ApplyMode>("full")
|
||||
const [activeTab, setActiveTab] =
|
||||
React.useState<ProjectFormTab>("new-project")
|
||||
|
||||
const packageManager = (config.packageManager || "pnpm") as PackageManager
|
||||
const framework = React.useMemo(
|
||||
@@ -117,12 +179,85 @@ export function ProjectForm({
|
||||
|
||||
const command = commands[packageManager]
|
||||
|
||||
const applyCommands = React.useMemo(() => {
|
||||
const presetFlag = ` --preset ${presetCode}`
|
||||
const onlyFlag =
|
||||
applyMode === "theme"
|
||||
? " --only theme"
|
||||
: applyMode === "font"
|
||||
? " --only font"
|
||||
: ""
|
||||
const flags = `${presetFlag}${onlyFlag}`
|
||||
|
||||
return IS_LOCAL_DEV
|
||||
? {
|
||||
pnpm: `shadcn apply${flags}`,
|
||||
npm: `shadcn apply${flags}`,
|
||||
yarn: `shadcn apply${flags}`,
|
||||
bun: `shadcn apply${flags}`,
|
||||
}
|
||||
: {
|
||||
pnpm: `pnpm dlx shadcn${SHADCN_VERSION} apply${flags}`,
|
||||
npm: `npx shadcn${SHADCN_VERSION} apply${flags}`,
|
||||
yarn: `yarn dlx shadcn${SHADCN_VERSION} apply${flags}`,
|
||||
bun: `bunx --bun shadcn${SHADCN_VERSION} apply${flags}`,
|
||||
}
|
||||
}, [applyMode, presetCode])
|
||||
|
||||
const applyCommand = applyCommands[packageManager]
|
||||
const themeConfig = React.useMemo<DesignSystemConfig>(() => {
|
||||
const isRadiusLocked = params.style === "lyra" || params.style === "sera"
|
||||
|
||||
return {
|
||||
...DEFAULT_CONFIG,
|
||||
base: params.base,
|
||||
style: params.style,
|
||||
baseColor: params.baseColor,
|
||||
theme: params.theme,
|
||||
chartColor: params.chartColor,
|
||||
iconLibrary: params.iconLibrary,
|
||||
font: params.font,
|
||||
fontHeading: params.fontHeading,
|
||||
menuAccent: params.menuAccent,
|
||||
menuColor: params.menuColor,
|
||||
radius: isRadiusLocked ? "none" : params.radius,
|
||||
template: params.template,
|
||||
rtl: params.rtl,
|
||||
pointer: params.pointer,
|
||||
}
|
||||
}, [
|
||||
params.base,
|
||||
params.baseColor,
|
||||
params.chartColor,
|
||||
params.font,
|
||||
params.fontHeading,
|
||||
params.iconLibrary,
|
||||
params.menuAccent,
|
||||
params.menuColor,
|
||||
params.pointer,
|
||||
params.radius,
|
||||
params.rtl,
|
||||
params.style,
|
||||
params.template,
|
||||
params.theme,
|
||||
])
|
||||
|
||||
const themeCss = React.useMemo(() => {
|
||||
const theme = buildThemeForPreset(themeConfig)
|
||||
|
||||
if (!theme.cssVars) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return formatThemeCss(theme.cssVars)
|
||||
}, [themeConfig])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (hasCopied) {
|
||||
const timer = setTimeout(() => setHasCopied(false), 2000)
|
||||
if (copiedTarget) {
|
||||
const timer = setTimeout(() => setCopiedTarget(null), 2000)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [hasCopied])
|
||||
}, [copiedTarget])
|
||||
|
||||
const handleCopy = React.useCallback(() => {
|
||||
const properties: Record<string, string> = {
|
||||
@@ -135,159 +270,316 @@ export function ProjectForm({
|
||||
name: "copy_npm_command",
|
||||
properties,
|
||||
})
|
||||
setHasCopied(true)
|
||||
setCopiedTarget("command")
|
||||
}, [command, params.template])
|
||||
|
||||
const handleCopyApply = React.useCallback(() => {
|
||||
copyToClipboardWithMeta(applyCommand, {
|
||||
name: "copy_apply_command",
|
||||
properties: {
|
||||
command: applyCommand,
|
||||
applyMode,
|
||||
},
|
||||
})
|
||||
setCopiedTarget("apply")
|
||||
}, [applyCommand, applyMode])
|
||||
|
||||
const handleCopyTheme = React.useCallback(() => {
|
||||
copyToClipboardWithMeta(themeCss, {
|
||||
name: "copy_theme_code",
|
||||
properties: {
|
||||
preset: presetCode,
|
||||
baseColor: params.baseColor,
|
||||
theme: params.theme,
|
||||
format: "css",
|
||||
},
|
||||
})
|
||||
setCopiedTarget("theme")
|
||||
}, [params.baseColor, params.theme, presetCode, themeCss])
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger render={<Button className={cn(className)} />}>
|
||||
Create Project
|
||||
Get Code
|
||||
</DialogTrigger>
|
||||
<DialogContent className="dark no-scrollbar max-h-[calc(100svh-2rem)] overflow-y-auto rounded-2xl p-6 shadow-xl **:data-[slot=field-separator]:h-2 sm:max-w-sm">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create Project</DialogTitle>
|
||||
<DialogDescription>
|
||||
Pick a template and configure your project.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div>
|
||||
<FieldGroup>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field className="-mt-2 gap-3">
|
||||
<FieldLabel>Template</FieldLabel>
|
||||
<TemplateGrid template={params.template} setParams={setParams} />
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field className="-mt-2">
|
||||
<FieldLabel>Base</FieldLabel>
|
||||
<BaseGrid base={params.base} setParams={setParams} />
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label" className="sr-only">
|
||||
Options
|
||||
</FieldLegend>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="pointer">
|
||||
<HugeiconsIcon
|
||||
icon={HandPointingRight04Icon}
|
||||
className="size-4 -rotate-90"
|
||||
/>
|
||||
Use pointer on buttons
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id="pointer"
|
||||
checked={params.pointer}
|
||||
onCheckedChange={(checked) =>
|
||||
setParams({ pointer: checked === true })
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-disabled={hasMonorepo ? undefined : "true"}
|
||||
>
|
||||
<FieldLabel htmlFor="monorepo">
|
||||
<span
|
||||
className="size-4 text-neutral-100 [&_svg]:size-4 [&_svg]:fill-current"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: TURBOREPO_LOGO,
|
||||
}}
|
||||
/>
|
||||
Create a monorepo
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id="monorepo"
|
||||
checked={params.template?.endsWith("-monorepo") ?? false}
|
||||
disabled={!hasMonorepo}
|
||||
onCheckedChange={(checked) => {
|
||||
const framework = getFramework(params.template ?? "next")
|
||||
setParams({
|
||||
template: getTemplateValue(
|
||||
framework,
|
||||
checked === true
|
||||
) as typeof params.template,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="rtl">
|
||||
<HugeiconsIcon icon={Globe02Icon} className="size-4" />
|
||||
Enable RTL support
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id="rtl"
|
||||
checked={params.rtl}
|
||||
onCheckedChange={(checked) =>
|
||||
setParams({ rtl: checked === true })
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
<DialogFooter className="-mx-6 -mb-6 min-w-0">
|
||||
<div className="flex w-full min-w-0 flex-col gap-3">
|
||||
<Tabs
|
||||
value={packageManager}
|
||||
onValueChange={(value) => {
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
packageManager: value as PackageManager,
|
||||
}))
|
||||
}}
|
||||
className="min-w-0 gap-0 overflow-hidden rounded-xl border-0 ring-1 ring-border"
|
||||
<DialogContent className="dark top-[64px] no-scrollbar flex max-h-[calc(100svh-2rem)] translate-y-0 flex-col rounded-2xl p-0 shadow-xl **:data-[slot=dialog-close]:top-4.5 **:data-[slot=dialog-close]:right-4 **:data-[slot=field-separator]:h-2 sm:max-w-md">
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-0 overflow-hidden rounded-2xl">
|
||||
<DialogHeader className="border-b px-6 py-5">
|
||||
<ToggleGroup
|
||||
value={[activeTab]}
|
||||
onValueChange={(values) =>
|
||||
setActiveTab((values[0] as typeof activeTab) ?? "new-project")
|
||||
}
|
||||
aria-label="Project type"
|
||||
spacing={2}
|
||||
className="**:data-[slot=toggle-group-item]:data-pressed:bg-neutral-700/70"
|
||||
>
|
||||
<div className="flex items-center gap-2 py-1 pr-1.5 pl-1">
|
||||
<TabsList className="bg-transparent font-mono">
|
||||
{PACKAGE_MANAGERS.map((manager) => {
|
||||
return (
|
||||
<TabsTrigger
|
||||
key={manager}
|
||||
value={manager}
|
||||
className="py-0 leading-none data-[state=active]:shadow-none"
|
||||
<ToggleGroupItem value="new-project">New Project</ToggleGroupItem>
|
||||
<ToggleGroupItem value="existing-project">
|
||||
Existing Project
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="theme">Theme</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</DialogHeader>
|
||||
{activeTab === "new-project" && (
|
||||
<div className="no-scrollbar overflow-y-auto">
|
||||
<FieldGroup className="px-6 py-4">
|
||||
<Field className="gap-3">
|
||||
<FieldLabel>Template</FieldLabel>
|
||||
<TemplateGrid
|
||||
template={params.template}
|
||||
setParams={setParams}
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field>
|
||||
<FieldLabel>Base</FieldLabel>
|
||||
<BaseGrid base={params.base} setParams={setParams} />
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label" className="sr-only">
|
||||
Options
|
||||
</FieldLegend>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="pointer">
|
||||
<HugeiconsIcon
|
||||
icon={HandPointingRight04Icon}
|
||||
className="size-4 -rotate-90"
|
||||
/>
|
||||
Use pointer on buttons
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id="pointer"
|
||||
checked={params.pointer}
|
||||
onCheckedChange={(checked) =>
|
||||
setParams({ pointer: checked === true })
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-disabled={hasMonorepo ? undefined : "true"}
|
||||
>
|
||||
<FieldLabel htmlFor="monorepo">
|
||||
<span
|
||||
className="size-4 text-neutral-100 [&_svg]:size-4 [&_svg]:fill-current"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: TURBOREPO_LOGO,
|
||||
}}
|
||||
/>
|
||||
Create a monorepo
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id="monorepo"
|
||||
checked={params.template?.endsWith("-monorepo") ?? false}
|
||||
disabled={!hasMonorepo}
|
||||
onCheckedChange={(checked) => {
|
||||
const framework = getFramework(
|
||||
params.template ?? "next"
|
||||
)
|
||||
setParams({
|
||||
template: getTemplateValue(
|
||||
framework,
|
||||
checked === true
|
||||
) as typeof params.template,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator className="-mx-6" />
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="rtl">
|
||||
<HugeiconsIcon icon={Globe02Icon} className="size-4" />
|
||||
Enable RTL support
|
||||
</FieldLabel>
|
||||
<Switch
|
||||
id="rtl"
|
||||
checked={params.rtl}
|
||||
onCheckedChange={(checked) =>
|
||||
setParams({ rtl: checked === true })
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
<DialogFooter className="m-0 min-w-0 p-6">
|
||||
<div className="flex w-full min-w-0 flex-col gap-3">
|
||||
<Tabs
|
||||
value={packageManager}
|
||||
onValueChange={(value) => {
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
packageManager: value as PackageManager,
|
||||
}))
|
||||
}}
|
||||
className="min-w-0 gap-0 overflow-hidden rounded-xl border-0 ring-1 ring-border"
|
||||
>
|
||||
<div className="flex items-center gap-2 py-1 pr-1.5 pl-1">
|
||||
<TabsList className="bg-transparent font-mono">
|
||||
{PACKAGE_MANAGERS.map((manager) => {
|
||||
return (
|
||||
<TabsTrigger
|
||||
key={manager}
|
||||
value={manager}
|
||||
className="py-0 leading-none data-[state=active]:shadow-none"
|
||||
>
|
||||
{manager}
|
||||
</TabsTrigger>
|
||||
)
|
||||
})}
|
||||
</TabsList>
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
className="ml-auto"
|
||||
onClick={handleCopy}
|
||||
>
|
||||
{manager}
|
||||
</TabsTrigger>
|
||||
)
|
||||
})}
|
||||
</TabsList>
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
className="ml-auto"
|
||||
onClick={handleCopy}
|
||||
>
|
||||
{hasCopied ? (
|
||||
<HugeiconsIcon icon={Tick02Icon} />
|
||||
) : (
|
||||
<HugeiconsIcon icon={Copy01Icon} />
|
||||
)}
|
||||
<span className="sr-only">Copy command</span>
|
||||
</Button>
|
||||
</div>
|
||||
{Object.entries(commands).map(([key, cmd]) => {
|
||||
return (
|
||||
<TabsContent key={key} value={key}>
|
||||
<div className="relative overflow-hidden border-t bg-popover p-3">
|
||||
<div className="no-scrollbar overflow-x-auto">
|
||||
<code className="font-mono text-sm whitespace-nowrap">
|
||||
{cmd}
|
||||
</code>
|
||||
</div>
|
||||
{copiedTarget === "command" ? (
|
||||
<HugeiconsIcon icon={Tick02Icon} />
|
||||
) : (
|
||||
<HugeiconsIcon icon={Copy01Icon} />
|
||||
)}
|
||||
<span className="sr-only">Copy command</span>
|
||||
</Button>
|
||||
</div>
|
||||
</TabsContent>
|
||||
)
|
||||
})}
|
||||
</Tabs>
|
||||
<Button onClick={handleCopy} className="h-9 w-full">
|
||||
{hasCopied ? "Copied" : "Copy Command"}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
{Object.entries(commands).map(([key, cmd]) => {
|
||||
return (
|
||||
<TabsContent key={key} value={key}>
|
||||
<div className="relative overflow-hidden border-t bg-popover p-3">
|
||||
<div className="no-scrollbar overflow-x-auto">
|
||||
<code className="font-mono text-sm whitespace-nowrap">
|
||||
{cmd}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
)
|
||||
})}
|
||||
</Tabs>
|
||||
<Button onClick={handleCopy} className="h-9 w-full">
|
||||
{copiedTarget === "command" ? "Copied" : "Copy Command"}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</div>
|
||||
)}
|
||||
{activeTab === "existing-project" && (
|
||||
<div className="no-scrollbar overflow-y-auto">
|
||||
<FieldGroup className="px-6 py-4">
|
||||
<FieldSet className="gap-3">
|
||||
<FieldLegend variant="label">Apply Preset</FieldLegend>
|
||||
<FieldDescription>
|
||||
Pick which parts of the preset to apply.
|
||||
</FieldDescription>
|
||||
<ApplyModeGrid mode={applyMode} setMode={setApplyMode} />
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
<DialogFooter className="m-0 min-w-0 p-6">
|
||||
<div className="flex w-full min-w-0 flex-col gap-3">
|
||||
<Tabs
|
||||
value={packageManager}
|
||||
onValueChange={(value) => {
|
||||
setConfig((prev) => ({
|
||||
...prev,
|
||||
packageManager: value as PackageManager,
|
||||
}))
|
||||
}}
|
||||
className="min-w-0 gap-0 overflow-hidden rounded-xl border-0 ring-1 ring-border"
|
||||
>
|
||||
<div className="flex items-center gap-2 py-1 pr-1.5 pl-1">
|
||||
<TabsList className="bg-transparent font-mono">
|
||||
{PACKAGE_MANAGERS.map((manager) => {
|
||||
return (
|
||||
<TabsTrigger
|
||||
key={manager}
|
||||
value={manager}
|
||||
className="py-0 leading-none data-[state=active]:shadow-none"
|
||||
>
|
||||
{manager}
|
||||
</TabsTrigger>
|
||||
)
|
||||
})}
|
||||
</TabsList>
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
className="ml-auto"
|
||||
onClick={handleCopyApply}
|
||||
>
|
||||
{copiedTarget === "apply" ? (
|
||||
<HugeiconsIcon icon={Tick02Icon} />
|
||||
) : (
|
||||
<HugeiconsIcon icon={Copy01Icon} />
|
||||
)}
|
||||
<span className="sr-only">Copy command</span>
|
||||
</Button>
|
||||
</div>
|
||||
{Object.entries(applyCommands).map(([key, cmd]) => {
|
||||
return (
|
||||
<TabsContent key={key} value={key}>
|
||||
<div className="relative overflow-hidden border-t bg-popover p-3">
|
||||
<div className="no-scrollbar overflow-x-auto">
|
||||
<code className="font-mono text-sm whitespace-nowrap">
|
||||
{cmd}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
)
|
||||
})}
|
||||
</Tabs>
|
||||
<Button onClick={handleCopyApply} className="h-9 w-full">
|
||||
{copiedTarget === "apply" ? "Copied" : "Copy Command"}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</div>
|
||||
)}
|
||||
{activeTab === "theme" && (
|
||||
<div className="no-scrollbar overflow-y-auto">
|
||||
<FieldGroup className="min-w-0 px-6 py-4">
|
||||
<FieldSet className="min-w-0 gap-3">
|
||||
<FieldLegend variant="label">Theme Tokens</FieldLegend>
|
||||
<FieldDescription>
|
||||
Copy the CSS variables for this preset.
|
||||
</FieldDescription>
|
||||
<div className="w-full min-w-0 overflow-hidden rounded-xl border-0 ring-1 ring-border">
|
||||
<div className="flex items-center gap-2 py-1 pr-1.5 pl-3">
|
||||
<div className="min-w-0 truncate font-mono text-sm text-muted-foreground">
|
||||
globals.css
|
||||
</div>
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
className="ml-auto"
|
||||
onClick={handleCopyTheme}
|
||||
>
|
||||
{copiedTarget === "theme" ? (
|
||||
<HugeiconsIcon icon={Tick02Icon} />
|
||||
) : (
|
||||
<HugeiconsIcon icon={Copy01Icon} />
|
||||
)}
|
||||
<span className="sr-only">Copy theme</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="relative no-scrollbar max-h-[45svh] overflow-auto border-t bg-popover p-3">
|
||||
<pre className="min-w-max font-mono leading-normal whitespace-pre">
|
||||
<code>{themeCss}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
<DialogFooter className="m-0 min-w-0 p-6">
|
||||
<Button onClick={handleCopyTheme} className="h-9 w-full">
|
||||
{copiedTarget === "theme" ? "Copied" : "Copy Theme"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
@@ -352,6 +644,34 @@ const TemplateGrid = React.memo(function TemplateGrid({
|
||||
)
|
||||
})
|
||||
|
||||
const ApplyModeGrid = React.memo(function ApplyModeGrid({
|
||||
mode,
|
||||
setMode,
|
||||
}: {
|
||||
mode: ApplyMode
|
||||
setMode: (mode: ApplyMode) => void
|
||||
}) {
|
||||
return (
|
||||
<RadioGroup
|
||||
value={mode}
|
||||
onValueChange={(value) => setMode(value as ApplyMode)}
|
||||
aria-label="Apply"
|
||||
>
|
||||
{APPLY_MODES.map((option) => (
|
||||
<FieldLabel key={option.value} htmlFor={`apply-${option.value}`}>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value={option.value} id={`apply-${option.value}`} />
|
||||
<FieldContent>
|
||||
<FieldTitle>{option.title}</FieldTitle>
|
||||
<FieldDescription>{option.description}</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
))}
|
||||
</RadioGroup>
|
||||
)
|
||||
})
|
||||
|
||||
const BaseGrid = React.memo(function BaseGrid({
|
||||
base,
|
||||
setParams,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import { PRESETS, type Style, type StyleName } from "@/registry/config"
|
||||
import { type Style, type StyleName } from "@/registry/config"
|
||||
import { LockButton } from "@/app/(app)/create/components/lock-button"
|
||||
import {
|
||||
Picker,
|
||||
@@ -53,24 +53,7 @@ export function StylePicker({
|
||||
<PickerRadioGroup
|
||||
value={currentStyle?.name}
|
||||
onValueChange={(value) => {
|
||||
const styleName = value as StyleName
|
||||
const preset = PRESETS.find(
|
||||
(p) => p.base === params.base && p.style === styleName
|
||||
)
|
||||
setParams({
|
||||
style: styleName,
|
||||
...(preset && {
|
||||
baseColor: preset.baseColor,
|
||||
theme: preset.theme,
|
||||
chartColor: preset.chartColor,
|
||||
iconLibrary: preset.iconLibrary,
|
||||
font: preset.font,
|
||||
fontHeading: preset.fontHeading,
|
||||
menuAccent: preset.menuAccent,
|
||||
menuColor: preset.menuColor,
|
||||
radius: preset.radius,
|
||||
}),
|
||||
})
|
||||
setParams({ style: value as StyleName })
|
||||
}}
|
||||
>
|
||||
<PickerGroup>
|
||||
|
||||
@@ -6,6 +6,8 @@ import { source } from "@/lib/source"
|
||||
import { getActiveStyle, type Style } from "@/registry/_legacy-styles"
|
||||
|
||||
export const revalidate = false
|
||||
export const dynamic = "force-static"
|
||||
export const dynamicParams = true
|
||||
|
||||
function getStyleFromSlug(slug: string[] | undefined, fallbackStyle: string) {
|
||||
// Detect base from URL: /docs/components/base/... or /docs/components/radix/...
|
||||
@@ -47,5 +49,5 @@ export async function GET(
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return source.generateParams()
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { notFound } from "next/navigation"
|
||||
import { siteConfig } from "@/lib/config"
|
||||
import { absoluteUrl } from "@/lib/utils"
|
||||
import { TailwindIndicator } from "@/components/tailwind-indicator"
|
||||
import { BASES, type Base, type BaseName } from "@/registry/config"
|
||||
import { BASES, type Base } from "@/registry/config"
|
||||
import { ActionMenuScript } from "@/app/(app)/create/components/action-menu"
|
||||
import { DesignSystemProvider } from "@/app/(app)/create/components/design-system-provider"
|
||||
import { HistoryScript } from "@/app/(app)/create/components/history-buttons"
|
||||
@@ -13,15 +13,13 @@ import { DarkModeScript } from "@/app/(app)/create/components/mode-switcher"
|
||||
import { OpenPresetScript } from "@/app/(app)/create/components/open-preset"
|
||||
import { PreviewStyle } from "@/app/(app)/create/components/preview-style"
|
||||
import { RandomizeScript } from "@/app/(app)/create/components/random-button"
|
||||
import {
|
||||
getBaseComponent,
|
||||
getBaseItem,
|
||||
getItemsForBase,
|
||||
} from "@/app/(app)/create/lib/api"
|
||||
import { getBaseComponent, getBaseItem } from "@/app/(app)/create/lib/api"
|
||||
|
||||
export const revalidate = false
|
||||
export const dynamic = "force-static"
|
||||
export const dynamicParams = false
|
||||
export const dynamicParams = true
|
||||
|
||||
const STATIC_PREVIEW_ITEMS = ["preview", "preview-02"] as const
|
||||
|
||||
function PreventScrollOnFocusScript() {
|
||||
return (
|
||||
@@ -96,19 +94,12 @@ export async function generateMetadata({
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const params: Array<{ base: string; name: string }> = []
|
||||
|
||||
for (const base of BASES) {
|
||||
const items = await getItemsForBase(base.name as BaseName)
|
||||
for (const item of items) {
|
||||
params.push({
|
||||
base: base.name,
|
||||
name: item.name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return params
|
||||
return BASES.flatMap((base) =>
|
||||
STATIC_PREVIEW_ITEMS.map((name) => ({
|
||||
base: base.name,
|
||||
name,
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
export default async function BlockPage({
|
||||
|
||||
@@ -6,8 +6,8 @@ import { Badge } from "@/registry/new-york-v4/ui/badge"
|
||||
export function Announcement() {
|
||||
return (
|
||||
<Badge asChild variant="secondary" className="bg-muted">
|
||||
<Link href="/sera">
|
||||
Introducing Sera <ArrowRightIcon />
|
||||
<Link href="/docs/changelog">
|
||||
New preset commands <ArrowRightIcon />
|
||||
</Link>
|
||||
</Badge>
|
||||
)
|
||||
|
||||
@@ -160,6 +160,18 @@ function DirectoryPaginationNext({
|
||||
}
|
||||
|
||||
export function DirectoryList() {
|
||||
return (
|
||||
<DirectoryAddProvider>
|
||||
<div className="mt-6">
|
||||
<React.Suspense fallback={<DirectoryListSkeleton />}>
|
||||
<DirectoryListContent />
|
||||
</React.Suspense>
|
||||
</div>
|
||||
</DirectoryAddProvider>
|
||||
)
|
||||
}
|
||||
|
||||
function DirectoryListContent() {
|
||||
const pathname = usePathname()
|
||||
const {
|
||||
isLoading,
|
||||
@@ -204,119 +216,115 @@ export function DirectoryList() {
|
||||
[page, setPage]
|
||||
)
|
||||
|
||||
if (isLoading) {
|
||||
return <DirectoryListSkeleton />
|
||||
}
|
||||
|
||||
return (
|
||||
<DirectoryAddProvider>
|
||||
<div className="mt-6">
|
||||
{isLoading ? (
|
||||
<DirectoryListSkeleton />
|
||||
) : (
|
||||
<>
|
||||
<SearchDirectory
|
||||
query={query}
|
||||
registriesCount={registries.length}
|
||||
setQuery={setQuery}
|
||||
/>
|
||||
<ItemGroup className="my-8">
|
||||
{paginatedRegistries.map((registry, index) => (
|
||||
<React.Fragment key={registry.name}>
|
||||
<Item className="group/item relative gap-6 px-0">
|
||||
<ItemMedia
|
||||
variant="image"
|
||||
dangerouslySetInnerHTML={{ __html: registry.logo }}
|
||||
className="grayscale *:[svg]:size-8 *:[svg]:fill-foreground"
|
||||
/>
|
||||
<ItemContent>
|
||||
<ItemTitle>
|
||||
<a
|
||||
href={getHomepageUrl(registry.homepage)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer external"
|
||||
className="group flex items-center gap-1"
|
||||
>
|
||||
{registry.name}{" "}
|
||||
<IconArrowUpRight className="size-4 opacity-0 group-hover:opacity-100" />
|
||||
</a>
|
||||
</ItemTitle>
|
||||
{registry.description && (
|
||||
<ItemDescription className="text-pretty">
|
||||
{registry.description}
|
||||
</ItemDescription>
|
||||
)}
|
||||
</ItemContent>
|
||||
<ItemActions className="relative z-10 hidden self-start sm:flex">
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemActions>
|
||||
<ItemFooter className="justify-start pl-16 sm:hidden">
|
||||
<Button size="sm" variant="outline">
|
||||
View <IconArrowUpRight />
|
||||
</Button>
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemFooter>
|
||||
</Item>
|
||||
{index < paginatedRegistries.length - 1 && (
|
||||
<ItemSeparator className="my-1" />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ItemGroup>
|
||||
{totalPages > 1 && (
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<DirectoryPaginationPrevious
|
||||
href={previousHref}
|
||||
aria-disabled={page <= 1 || undefined}
|
||||
tabIndex={page <= 1 ? -1 : undefined}
|
||||
onClick={(event) =>
|
||||
handlePageChange(event, page - 1, page <= 1)
|
||||
}
|
||||
className={cn(
|
||||
page <= 1
|
||||
? "pointer-events-none opacity-50"
|
||||
: "cursor-pointer"
|
||||
)}
|
||||
/>
|
||||
</PaginationItem>
|
||||
{getPageNumbers(page, totalPages).map((p, i) =>
|
||||
p === "ellipsis" ? (
|
||||
<PaginationItem key={`ellipsis-${i}`}>
|
||||
<PaginationEllipsis />
|
||||
</PaginationItem>
|
||||
) : (
|
||||
<PaginationItem key={p}>
|
||||
<DirectoryPaginationLink
|
||||
href={getPageHref(pathname, query, p)}
|
||||
isActive={p === page}
|
||||
onClick={(event) => handlePageChange(event, p)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{p}
|
||||
</DirectoryPaginationLink>
|
||||
</PaginationItem>
|
||||
)
|
||||
)}
|
||||
<PaginationItem>
|
||||
<DirectoryPaginationNext
|
||||
href={nextHref}
|
||||
aria-disabled={page >= totalPages || undefined}
|
||||
tabIndex={page >= totalPages ? -1 : undefined}
|
||||
onClick={(event) =>
|
||||
handlePageChange(event, page + 1, page >= totalPages)
|
||||
}
|
||||
className={cn(
|
||||
page >= totalPages
|
||||
? "pointer-events-none opacity-50"
|
||||
: "cursor-pointer"
|
||||
)}
|
||||
/>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
<>
|
||||
<SearchDirectory
|
||||
query={query}
|
||||
registriesCount={registries.length}
|
||||
setQuery={setQuery}
|
||||
/>
|
||||
<ItemGroup className="my-8">
|
||||
{paginatedRegistries.map((registry, index) => (
|
||||
<React.Fragment key={registry.name}>
|
||||
<Item className="group/item relative gap-6 px-0">
|
||||
<ItemMedia
|
||||
variant="image"
|
||||
dangerouslySetInnerHTML={{ __html: registry.logo }}
|
||||
className="grayscale *:[svg]:size-8 *:[svg]:fill-foreground"
|
||||
/>
|
||||
<ItemContent>
|
||||
<ItemTitle>
|
||||
<a
|
||||
href={getHomepageUrl(registry.homepage)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer external"
|
||||
className="group flex items-center gap-1"
|
||||
>
|
||||
{registry.name}{" "}
|
||||
<IconArrowUpRight className="size-4 opacity-0 group-hover:opacity-100" />
|
||||
</a>
|
||||
</ItemTitle>
|
||||
{registry.description && (
|
||||
<ItemDescription className="text-pretty">
|
||||
{registry.description}
|
||||
</ItemDescription>
|
||||
)}
|
||||
</ItemContent>
|
||||
<ItemActions className="relative z-10 hidden self-start sm:flex">
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemActions>
|
||||
<ItemFooter className="justify-start pl-16 sm:hidden">
|
||||
<Button size="sm" variant="outline">
|
||||
View <IconArrowUpRight />
|
||||
</Button>
|
||||
<DirectoryAddButton registry={registry} />
|
||||
</ItemFooter>
|
||||
</Item>
|
||||
{index < paginatedRegistries.length - 1 && (
|
||||
<ItemSeparator className="my-1" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</DirectoryAddProvider>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ItemGroup>
|
||||
{totalPages > 1 && (
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<DirectoryPaginationPrevious
|
||||
href={previousHref}
|
||||
aria-disabled={page <= 1 || undefined}
|
||||
tabIndex={page <= 1 ? -1 : undefined}
|
||||
onClick={(event) =>
|
||||
handlePageChange(event, page - 1, page <= 1)
|
||||
}
|
||||
className={cn(
|
||||
page <= 1
|
||||
? "pointer-events-none opacity-50"
|
||||
: "cursor-pointer"
|
||||
)}
|
||||
/>
|
||||
</PaginationItem>
|
||||
{getPageNumbers(page, totalPages).map((p, i) =>
|
||||
p === "ellipsis" ? (
|
||||
<PaginationItem key={`ellipsis-${i}`}>
|
||||
<PaginationEllipsis />
|
||||
</PaginationItem>
|
||||
) : (
|
||||
<PaginationItem key={p}>
|
||||
<DirectoryPaginationLink
|
||||
href={getPageHref(pathname, query, p)}
|
||||
isActive={p === page}
|
||||
onClick={(event) => handlePageChange(event, p)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
{p}
|
||||
</DirectoryPaginationLink>
|
||||
</PaginationItem>
|
||||
)
|
||||
)}
|
||||
<PaginationItem>
|
||||
<DirectoryPaginationNext
|
||||
href={nextHref}
|
||||
aria-disabled={page >= totalPages || undefined}
|
||||
tabIndex={page >= totalPages ? -1 : undefined}
|
||||
onClick={(event) =>
|
||||
handlePageChange(event, page + 1, page >= totalPages)
|
||||
}
|
||||
className={cn(
|
||||
page >= totalPages
|
||||
? "pointer-events-none opacity-50"
|
||||
: "cursor-pointer"
|
||||
)}
|
||||
/>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -92,13 +92,13 @@ Options:
|
||||
Use the `apply` command to apply a preset to an existing project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest apply --preset a2r6bw
|
||||
npx shadcn@latest apply a2r6bw
|
||||
```
|
||||
|
||||
You can apply only the theme or fonts from a preset without reinstalling UI components:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest apply --preset a2r6bw --only theme
|
||||
npx shadcn@latest apply a2r6bw --only theme
|
||||
```
|
||||
|
||||
Supported values for `--only` are `theme` and `font`.
|
||||
@@ -124,6 +124,110 @@ Options:
|
||||
|
||||
---
|
||||
|
||||
## preset
|
||||
|
||||
Use the `preset` command to inspect preset codes and resolve the preset for an existing project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset decode a2r6bw
|
||||
```
|
||||
|
||||
### preset decode
|
||||
|
||||
Use `preset decode` to decode a preset code.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset decode a2r6bw
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
```bash
|
||||
Usage: shadcn preset decode [options] <code>
|
||||
|
||||
decode a preset code
|
||||
|
||||
Arguments:
|
||||
code the preset code to decode
|
||||
|
||||
Options:
|
||||
--json output as JSON. (default: false)
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
### preset resolve
|
||||
|
||||
Use `preset resolve` to resolve the preset from the current project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset resolve
|
||||
```
|
||||
|
||||
The `preset info` command is an alias for `preset resolve`:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset info
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
```bash
|
||||
Usage: shadcn preset resolve|info [options]
|
||||
|
||||
resolve a preset from your project
|
||||
|
||||
Options:
|
||||
-c, --cwd <cwd> the working directory. defaults to the current directory.
|
||||
--json output as JSON. (default: false)
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
### preset url
|
||||
|
||||
Use `preset url` to print the create URL for a preset code.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset url a2r6bw
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
```bash
|
||||
Usage: shadcn preset url [options] <code>
|
||||
|
||||
get the create URL for a preset code
|
||||
|
||||
Arguments:
|
||||
code the preset code
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
### preset open
|
||||
|
||||
Use `preset open` to open a preset code in the browser.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset open a2r6bw
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
```bash
|
||||
Usage: shadcn preset open [options] <code>
|
||||
|
||||
open a preset code in the browser
|
||||
|
||||
Arguments:
|
||||
code the preset code
|
||||
|
||||
Options:
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## view
|
||||
|
||||
Use the `view` command to view items from the registry before installing them.
|
||||
|
||||
@@ -140,15 +140,91 @@ Setting this option to `false` allows components to be added as JavaScript with
|
||||
|
||||
## aliases
|
||||
|
||||
The CLI uses these values and the `paths` config from your `tsconfig.json` or `jsconfig.json` file to place generated components in the correct location.
|
||||
The CLI uses these values to place generated components in the correct location and rewrite imports.
|
||||
|
||||
Path aliases have to be set up in your `tsconfig.json` or `jsconfig.json` file.
|
||||
You can back these aliases with either:
|
||||
|
||||
1. `compilerOptions.paths` in your `tsconfig.json` or `jsconfig.json`
|
||||
2. `package.json#imports` with TypeScript package import resolution enabled
|
||||
|
||||
The aliases in `components.json` are still required when using the CLI. They tell the CLI which import roots map to `components`, `ui`, `lib`, `hooks`, and `utils`.
|
||||
|
||||
<Callout className="mt-6">
|
||||
**Important:** If you're using the `src` directory, make sure it is included
|
||||
under `paths` in your `tsconfig.json` or `jsconfig.json` file.
|
||||
**Important:** If you're using package imports, enable
|
||||
`resolvePackageJsonImports` and use `moduleResolution: "bundler"` in your
|
||||
`tsconfig.json`. If you're using `paths`, make sure your aliases include the
|
||||
`src` directory when applicable.
|
||||
</Callout>
|
||||
|
||||
### Using `tsconfig` or `jsconfig` paths
|
||||
|
||||
```json title="tsconfig.json"
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Using `package.json#imports`
|
||||
|
||||
Recommended setup for a single-package app:
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json title="tsconfig.json"
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "bundler",
|
||||
"resolvePackageJsonImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json title="components.json"
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "#components/ui",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "#lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The aliases in `components.json` still tell the CLI where to place
|
||||
`components`, `ui`, `lib`, `hooks`, and `utils`. `package.json#imports`
|
||||
provides the runtime and TypeScript resolution for those `#...` specifiers.
|
||||
|
||||
The matched `imports` target also controls whether generated `#...` imports keep
|
||||
file extensions:
|
||||
|
||||
- `"#components/*": "./src/components/*"` preserves source extensions and can
|
||||
generate imports like
|
||||
`#components/button.tsx`
|
||||
- `"#components/*": "./src/components/*.tsx"` strips source extensions and
|
||||
generates imports like
|
||||
`#components/button`
|
||||
|
||||
For monorepos, see the <Link href="/docs/monorepo">monorepo docs</Link>. Local
|
||||
workspace aliases can use `package.json#imports`, while shared workspace
|
||||
imports such as `@workspace/ui/components` are resolved from the target
|
||||
package's `exports`.
|
||||
|
||||
For framework-specific setup, see the [package imports guide](/docs/package-imports).
|
||||
|
||||
### aliases.utils
|
||||
|
||||
Import alias for your utility functions.
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
"index",
|
||||
"[Installation](/docs/installation)",
|
||||
"components-json",
|
||||
"package-imports",
|
||||
"theming",
|
||||
"[Dark Mode](/docs/dark-mode)",
|
||||
"[RTL](/docs/rtl)",
|
||||
"[CLI](/docs/cli)",
|
||||
"monorepo",
|
||||
"skills",
|
||||
"v0",
|
||||
"javascript",
|
||||
"blocks",
|
||||
"figma",
|
||||
|
||||
@@ -164,3 +164,91 @@ turbo.json
|
||||
4. **For Tailwind CSS v4, leave the `tailwind` config empty in the `components.json` file.**
|
||||
|
||||
By following these requirements, the CLI will be able to install ui components, blocks, libs and hooks to the correct paths and handle imports for you.
|
||||
|
||||
<Callout className="mt-6">
|
||||
`package.json#imports` works well for package-local aliases inside a
|
||||
workspace, for example inside `packages/ui`. For shared workspace imports such
|
||||
as `@workspace/ui/components`, keep explicit aliases in `components.json`. The
|
||||
CLI uses those aliases to route files across workspace boundaries.
|
||||
</Callout>
|
||||
|
||||
## Using `package.json#imports`
|
||||
|
||||
For a monorepo that uses package imports and does not rely on
|
||||
`tsconfig.json` `paths`, use:
|
||||
|
||||
- local `#...` aliases for files inside each workspace
|
||||
- workspace package `exports` for shared imports such as
|
||||
`@workspace/ui/components`
|
||||
|
||||
For example, an app workspace can use local package imports:
|
||||
|
||||
```json showLineNumbers title="apps/web/package.json"
|
||||
{
|
||||
"name": "web",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@workspace/ui": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json showLineNumbers title="apps/web/components.json"
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "@workspace/ui/components",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "@workspace/ui/lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And the shared UI package can expose its install targets with `exports`:
|
||||
|
||||
```json showLineNumbers title="packages/ui/package.json"
|
||||
{
|
||||
"name": "@workspace/ui",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
},
|
||||
"exports": {
|
||||
"./globals.css": "./src/styles/globals.css",
|
||||
"./components/*": "./src/components/*.tsx",
|
||||
"./lib/*": "./src/lib/*.ts",
|
||||
"./hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json showLineNumbers title="packages/ui/components.json"
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "#components",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "#lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this setup:
|
||||
|
||||
- files added from the app to the shared UI package are routed through
|
||||
`@workspace/ui/...`
|
||||
- files added inside `packages/ui` use the package-local `#...` aliases
|
||||
- the shared package must export any path referenced by another workspace
|
||||
|
||||
For framework-specific package import setup, see the [package imports guide](/docs/package-imports).
|
||||
|
||||
234
apps/v4/content/docs/(root)/package-imports.mdx
Normal file
234
apps/v4/content/docs/(root)/package-imports.mdx
Normal file
@@ -0,0 +1,234 @@
|
||||
---
|
||||
title: Package Imports
|
||||
description: Configure shadcn/ui with package.json imports.
|
||||
---
|
||||
|
||||
The `shadcn` CLI supports [package imports](https://nodejs.org/api/packages.html#imports)
|
||||
for installing components, rewriting imports, and resolving third-party
|
||||
registries.
|
||||
|
||||
Package imports let you use private `#...` import aliases from your
|
||||
`package.json` instead of `compilerOptions.paths` in `tsconfig.json`.
|
||||
|
||||
## Example
|
||||
|
||||
You configure `imports` in your `package.json`:
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then import generated components using `#...` specifiers:
|
||||
|
||||
```tsx
|
||||
import { Button } from "#components/ui/button"
|
||||
import { cn } from "#lib/utils"
|
||||
```
|
||||
|
||||
<Callout className="mt-6">
|
||||
Package import specifiers must start with `#`. Use TypeScript 5 or later with
|
||||
`moduleResolution: "bundler"` and `resolvePackageJsonImports: true`.
|
||||
</Callout>
|
||||
|
||||
## App
|
||||
|
||||
For Next.js, Vite, and TanStack Start apps that install
|
||||
components into the same workspace.
|
||||
|
||||
<Steps>
|
||||
|
||||
### Configure `package.json`
|
||||
|
||||
Add imports for the shadcn/ui install targets.
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If your app does not use a `src` directory, remove `src/` from the targets. For
|
||||
example:
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./components/*.tsx",
|
||||
"#lib/*": "./lib/*.ts",
|
||||
"#hooks/*": "./hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configure TypeScript
|
||||
|
||||
Enable package import resolution.
|
||||
|
||||
```json title="tsconfig.json" showLineNumbers
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "bundler",
|
||||
"resolvePackageJsonImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You do not need `compilerOptions.paths` for these aliases.
|
||||
|
||||
### Configure `components.json`
|
||||
|
||||
Use the same `#...` roots in `components.json`.
|
||||
|
||||
```json title="components.json" showLineNumbers
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "#components/ui",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "#lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `ui` alias uses `#components/ui`. It is still covered by the
|
||||
`#components/*` import in `package.json`.
|
||||
|
||||
The `utils` alias uses `#lib/utils`. It is covered by `#lib/*`, so you do not
|
||||
need a separate `#utils` import.
|
||||
|
||||
</Steps>
|
||||
|
||||
## Monorepo
|
||||
|
||||
In a monorepo, use package imports for files inside each package and package
|
||||
exports for files shared across workspaces.
|
||||
|
||||
For an app workspace:
|
||||
|
||||
```json title="apps/web/package.json" showLineNumbers
|
||||
{
|
||||
"name": "web",
|
||||
"private": true,
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@workspace/ui": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json title="apps/web/components.json" showLineNumbers
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "@workspace/ui/components",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "@workspace/ui/lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For the shared UI package:
|
||||
|
||||
```json title="packages/ui/package.json" showLineNumbers
|
||||
{
|
||||
"name": "@workspace/ui",
|
||||
"private": true,
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
},
|
||||
"exports": {
|
||||
"./globals.css": "./src/styles/globals.css",
|
||||
"./components/*": "./src/components/*.tsx",
|
||||
"./lib/*": "./src/lib/*.ts",
|
||||
"./hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json title="packages/ui/components.json" showLineNumbers
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "#components",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "#lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When you run `add` from `apps/web`, app-local files use `#...` imports and
|
||||
shared UI files are imported from `@workspace/ui`.
|
||||
|
||||
```tsx
|
||||
import { Button } from "@workspace/ui/components/button"
|
||||
import { LoginForm } from "#components/login-form"
|
||||
```
|
||||
|
||||
## File extensions
|
||||
|
||||
The target pattern in `package.json#imports` controls whether generated imports
|
||||
include file extensions.
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This generates imports without extensions:
|
||||
|
||||
```tsx
|
||||
import { Button } from "#components/ui/button"
|
||||
```
|
||||
|
||||
If you use a target without the extension:
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The generated import keeps the source extension:
|
||||
|
||||
```tsx
|
||||
import { Button } from "#components/ui/button.tsx"
|
||||
```
|
||||
|
||||
For most apps, use the extension in the target pattern.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If TypeScript cannot resolve a `#...` import, check that:
|
||||
|
||||
- the specifier starts with `#`
|
||||
- the `imports` entry is in the nearest `package.json`
|
||||
- `moduleResolution` is set to `bundler`
|
||||
- `resolvePackageJsonImports` is enabled
|
||||
- the matching target exists after components are added
|
||||
|
||||
If a component is installed but imports still point to `@/...`, check that
|
||||
`components.json` uses the same `#...` aliases as your package imports.
|
||||
@@ -116,7 +116,7 @@ npx shadcn@latest docs combobox
|
||||
|
||||
combobox
|
||||
- docs https://ui.shadcn.com/docs/components/radix/combobox
|
||||
- examples https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/combobox-example.tsx
|
||||
- examples https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/combobox-example.tsx
|
||||
- api https://base-ui.com/react/components/combobox
|
||||
```
|
||||
|
||||
|
||||
93
apps/v4/content/docs/changelog/2026-04-preset-commands.mdx
Normal file
93
apps/v4/content/docs/changelog/2026-04-preset-commands.mdx
Normal file
@@ -0,0 +1,93 @@
|
||||
---
|
||||
title: April 2026 - shadcn preset
|
||||
description: Decode, share, open, and resolve preset codes from the shadcn CLI.
|
||||
date: 2026-04-28
|
||||
---
|
||||
|
||||
We added `shadcn preset` commands for working with preset codes.
|
||||
|
||||
## Decode a preset
|
||||
|
||||
You can decode a preset code to see exactly what it contains:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset decode b5owWMfJ8l
|
||||
```
|
||||
|
||||
```txt
|
||||
Preset
|
||||
code b5owWMfJ8l
|
||||
version b
|
||||
style mira
|
||||
baseColor mauve
|
||||
theme mauve
|
||||
chartColor amber
|
||||
iconLibrary hugeicons
|
||||
font inter
|
||||
fontHeading oxanium
|
||||
radius large
|
||||
menuAccent subtle
|
||||
menuColor inverted-translucent
|
||||
url https://ui.shadcn.com/create?preset=b5owWMfJ8l
|
||||
```
|
||||
|
||||
## Resolve from a project
|
||||
|
||||
Use `preset resolve` in an existing project to see the preset that matches your current configuration.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset resolve
|
||||
```
|
||||
|
||||
```txt
|
||||
Preset
|
||||
code b5Kc6P0Vc
|
||||
version b
|
||||
style luma
|
||||
baseColor olive
|
||||
theme lime
|
||||
chartColor sky
|
||||
iconLibrary hugeicons
|
||||
font geist
|
||||
fontHeading inherit
|
||||
radius default
|
||||
menuAccent subtle
|
||||
menuColor default
|
||||
url https://ui.shadcn.com/create?preset=b5Kc6P0Vc
|
||||
```
|
||||
|
||||
It works with monorepos too:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset resolve -c apps/web
|
||||
```
|
||||
|
||||
## Share or open
|
||||
|
||||
Use `preset url` when you need a shareable link:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset url b5owWMfJ8l
|
||||
```
|
||||
|
||||
```txt
|
||||
https://ui.shadcn.com/create?preset=b5owWMfJ8l
|
||||
```
|
||||
|
||||
Use `preset open` to open the preset on shadcn/create for customization:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest preset open b5owWMfJ8l
|
||||
```
|
||||
|
||||
```txt
|
||||
Opening https://ui.shadcn.com/create?preset=b5owWMfJ8l in your browser.
|
||||
```
|
||||
|
||||
This makes presets easier to inspect, share, and hand off to coding agents without manually decoding codes or building URLs.
|
||||
|
||||
<Button asChild size="sm">
|
||||
<Link href="/create" className="mt-6 no-underline!">
|
||||
Try a Preset
|
||||
</Link>
|
||||
</Button>
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: May 2026 - Package Imports and Target Aliases
|
||||
description: Configure shadcn/ui with package.json imports and portable registry target aliases.
|
||||
date: 2026-05-05
|
||||
---
|
||||
|
||||
We've added support for package imports and aliases in `files.target` in `shadcn@4.7.0`.
|
||||
|
||||
## Package imports
|
||||
|
||||
The `shadcn` CLI now supports `package.json#imports` for installing components,
|
||||
rewriting imports, and resolving third-party registries. You can use private
|
||||
`#...` import aliases from your `package.json` instead of relying only on
|
||||
`compilerOptions.paths` in `tsconfig.json`.
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then use the same roots in `components.json`:
|
||||
|
||||
```json title="components.json" showLineNumbers
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"ui": "#components/ui",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks",
|
||||
"utils": "#lib/utils"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This also works in monorepos where app-local files use package imports and
|
||||
shared UI files are imported from workspace package exports.
|
||||
|
||||
See the [package imports guide](/docs/package-imports) for setup details.
|
||||
|
||||
## Target aliases
|
||||
|
||||
Registry items can now use target aliases in `files[].target` to install files
|
||||
under the user's configured shadcn directories. For example, the following registry item will install the `prompt-input.tsx` file under the `ui/ai` directory.
|
||||
|
||||
```json title="example.json" showLineNumbers
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/default/ai/prompt-input.tsx",
|
||||
"type": "registry:ui",
|
||||
"target": "@ui/ai/prompt-input.tsx"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See the [registry examples](/docs/registry/examples#target-placeholders) for
|
||||
more details.
|
||||
120
apps/v4/content/docs/changelog/2026-05-registry-include.mdx
Normal file
120
apps/v4/content/docs/changelog/2026-05-registry-include.mdx
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: May 2026 - Registry Include and Validate
|
||||
description: Organize and validate source registries.
|
||||
date: 2026-05-20
|
||||
---
|
||||
|
||||
This release adds two updates for registry authors:
|
||||
|
||||
- `include` for composing large source registries from multiple `registry.json`
|
||||
files.
|
||||
- `shadcn registry validate` for checking source registries before publishing.
|
||||
|
||||
This makes it easier to maintain source and dynamic registries without keeping
|
||||
one large `registry.json` file by hand.
|
||||
|
||||
Registry authors can now organize a large source registry across multiple
|
||||
`registry.json` files and compose them with `shadcn build`.
|
||||
|
||||
```txt /registry.json/
|
||||
registry.json
|
||||
components
|
||||
└── ui
|
||||
├── button.tsx
|
||||
├── input.tsx
|
||||
└── registry.json
|
||||
hooks
|
||||
├── registry.json
|
||||
├── use-media-query.ts
|
||||
└── use-toggle.ts
|
||||
```
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```json title="registry.json" showLineNumbers {6-7}
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"name": "acme",
|
||||
"homepage": "https://acme.com",
|
||||
"include": [
|
||||
"components/ui/registry.json",
|
||||
"hooks/registry.json"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Included `registry.json` files are valid registry files for composition and may
|
||||
omit `name` and `homepage`. Only the root `registry.json` must define the
|
||||
registry metadata.
|
||||
|
||||
```json title="components/ui/registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"items": [
|
||||
{
|
||||
"name": "button",
|
||||
"type": "registry:ui",
|
||||
"files": [
|
||||
{
|
||||
"path": "button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Build output
|
||||
|
||||
`shadcn build` resolves included registries and writes a flattened
|
||||
`registry.json` without `include`. Item file paths are preserved from the root
|
||||
registry, so a file declared in `components/ui/registry.json` is written as
|
||||
`components/ui/button.tsx` in the built registry item.
|
||||
|
||||
## Validate your registry
|
||||
|
||||
You can now validate a source registry before publishing or serving it.
|
||||
|
||||
```bash
|
||||
npx shadcn registry validate
|
||||
```
|
||||
|
||||
Validation runs against the source registry files directly. You do not need to
|
||||
run `shadcn build` first.
|
||||
|
||||
The command checks the root `registry.json`, included registry files, item
|
||||
schema errors, duplicate item names, include rules, and local item file paths.
|
||||
Validation reports all actionable errors it can find in one run.
|
||||
|
||||
## Registry loaders
|
||||
|
||||
The `shadcn/registry` package also exports `loadRegistry` and
|
||||
`loadRegistryItem` for dynamic registry routes.
|
||||
|
||||
```ts title="app/r/registry.json/route.ts" showLineNumbers
|
||||
import { loadRegistry } from "shadcn/registry"
|
||||
|
||||
export async function GET() {
|
||||
const registry = await loadRegistry()
|
||||
|
||||
return Response.json(registry)
|
||||
}
|
||||
```
|
||||
|
||||
```ts title="app/r/[name].json/route.ts" showLineNumbers
|
||||
import { loadRegistryItem } from "shadcn/registry"
|
||||
|
||||
export async function GET(
|
||||
_: Request,
|
||||
{ params }: { params: Promise<{ name: string }> }
|
||||
) {
|
||||
const { name } = await params
|
||||
const item = await loadRegistryItem(name)
|
||||
|
||||
return Response.json(item)
|
||||
}
|
||||
```
|
||||
|
||||
See the [registry.json documentation](/docs/registry/registry-json#include) and
|
||||
[getting started guide](/docs/registry/getting-started#structure-your-registry)
|
||||
for more details.
|
||||
@@ -156,7 +156,7 @@ The `Field` family is designed for composing accessible forms. A typical field i
|
||||
|
||||
## Form
|
||||
|
||||
See the [Form](/docs/forms) documentation for building forms with the `Field` component and [React Hook Form](/docs/forms/react-hook-form) or [Tanstack Form](/docs/forms/tanstack-form).
|
||||
See the [Form](/docs/forms) documentation for building forms with the `Field` component and [React Hook Form](/docs/forms/react-hook-form), [Tanstack Form](/docs/forms/tanstack-form), or [Formisch](/docs/forms/formisch).
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -129,3 +129,9 @@ To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl)
|
||||
## API Reference
|
||||
|
||||
See the [Base UI Toggle Group](https://base-ui.com/react/components/toggle-group#api-reference) documentation.
|
||||
|
||||
## Changelog
|
||||
|
||||
### 2026-05-17 Default Spacing
|
||||
|
||||
Changed the default `spacing` from `0` to `2` so toggle groups render with space between items by default. Use `spacing={0}` for connected items.
|
||||
|
||||
@@ -156,7 +156,7 @@ The `Field` family is designed for composing accessible forms. A typical field i
|
||||
|
||||
## Form
|
||||
|
||||
See the [Form](/docs/forms) documentation for building forms with the `Field` component and [React Hook Form](/docs/forms/react-hook-form) or [Tanstack Form](/docs/forms/tanstack-form).
|
||||
See the [Form](/docs/forms) documentation for building forms with the `Field` component and [React Hook Form](/docs/forms/react-hook-form), [Tanstack Form](/docs/forms/tanstack-form), or [Formisch](/docs/forms/formisch).
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@@ -129,3 +129,9 @@ To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl)
|
||||
## API Reference
|
||||
|
||||
See the [Radix Toggle Group](https://www.radix-ui.com/docs/primitives/components/toggle-group#api-reference) documentation.
|
||||
|
||||
## Changelog
|
||||
|
||||
### 2026-05-17 Default Spacing
|
||||
|
||||
Changed the default `spacing` from `0` to `2` so toggle groups render with space between items by default. Use `spacing={0}` for connected items.
|
||||
|
||||
669
apps/v4/content/docs/forms/formisch.mdx
Normal file
669
apps/v4/content/docs/forms/formisch.mdx
Normal file
@@ -0,0 +1,669 @@
|
||||
---
|
||||
title: Formisch
|
||||
description: Build forms in React using Formisch and Valibot.
|
||||
links:
|
||||
doc: https://formisch.dev
|
||||
---
|
||||
|
||||
import { InfoIcon } from "lucide-react"
|
||||
|
||||
This guide covers building forms with [Formisch](https://formisch.dev), the lightweight, schema-first, and fully type-safe form library for React. We'll create forms with the `<Field />` component, validate them with Valibot schemas, handle errors, and ensure accessibility.
|
||||
|
||||
## Demo
|
||||
|
||||
We'll build the following form. It has a simple text input and a textarea. On submit, we'll validate the form data and display any errors.
|
||||
|
||||
<Callout icon={<InfoIcon />}>
|
||||
**Note:** For the purpose of this demo, we have intentionally disabled browser
|
||||
validation to show how schema validation and form errors work in Formisch. It
|
||||
is recommended to add basic browser validation in your production code.
|
||||
</Callout>
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-demo"
|
||||
className="sm:[&_.preview]:h-[700px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
## Approach
|
||||
|
||||
This form leverages Formisch for headless, schema-first form handling. We'll build our form using the `<Field />` component, which gives you **complete flexibility over the markup and styling**.
|
||||
|
||||
- Uses Formisch's `useForm` hook for form state management.
|
||||
- `<Form />` component to wrap the native `<form>` element with submit handling.
|
||||
- `<Field />` render-prop component for controlled inputs.
|
||||
- Schema validation using [Valibot](https://valibot.dev).
|
||||
- Type-safe field paths inferred from the schema.
|
||||
|
||||
## Form Methods
|
||||
|
||||
Formisch exposes form operations as **top-level functions** rather than methods on a form object. Import only what you need:
|
||||
|
||||
```ts
|
||||
import { getInput, insert, reset, submit } from "@formisch/react"
|
||||
```
|
||||
|
||||
Every method follows the same signature: the **first parameter is always the form store**, and the **second parameter (if necessary) is always a config object**.
|
||||
|
||||
```ts
|
||||
// Read a field value
|
||||
const email = getInput(form, { path: ["email"] })
|
||||
|
||||
// Reset the form with new initial values
|
||||
reset(form, { initialInput: { email: "", password: "" } })
|
||||
|
||||
// Move an item in a field array
|
||||
move(form, { path: ["items"], from: 0, to: 3 })
|
||||
```
|
||||
|
||||
This design keeps the API flexible and consistent across all methods. You'll see the same `(form, config)` shape used throughout this guide for reading state (`getInput`, `getErrors`), writing state (`setInput`, `setErrors`), form control (`submit`, `validate`, `focus`), and array operations (`insert`, `remove`, `move`, `swap`, `replace`). See the [full methods reference](https://formisch.dev/react/guides/form-methods) for details.
|
||||
|
||||
## Anatomy
|
||||
|
||||
Here's a basic example of a form using the `<Field />` component from Formisch and the shadcn `<Field />` component.
|
||||
|
||||
```tsx showLineNumbers {3-21}
|
||||
<Form of={form} onSubmit={handleSubmit}>
|
||||
<FieldGroup>
|
||||
<FormischField of={form} path={["title"]}>
|
||||
{(field) => (
|
||||
<Field data-invalid={field.errors !== null}>
|
||||
<FieldLabel htmlFor="form-title">Bug Title</FieldLabel>
|
||||
<Input
|
||||
{...field.props}
|
||||
id="form-title"
|
||||
value={field.input}
|
||||
aria-invalid={field.errors !== null}
|
||||
placeholder="Login button not working on mobile"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<FieldDescription>
|
||||
Provide a concise title for your bug report.
|
||||
</FieldDescription>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</Field>
|
||||
)}
|
||||
</FormischField>
|
||||
</FieldGroup>
|
||||
</Form>
|
||||
```
|
||||
|
||||
<Callout icon={<InfoIcon />}>
|
||||
**Note:** Formisch ships its own `Field` component. To avoid a name clash with
|
||||
the shadcn `Field`, the examples below import the Formisch one as
|
||||
`FormischField` and keep the shadcn `Field` under its original name. In your
|
||||
own code you can alias either side — just be consistent.
|
||||
</Callout>
|
||||
|
||||
## Form
|
||||
|
||||
### Create a form schema
|
||||
|
||||
We'll start by defining the shape of our form using a Valibot schema. Formisch infers all input and output types directly from this schema.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx"
|
||||
import * as v from "valibot"
|
||||
|
||||
const FormSchema = v.object({
|
||||
title: v.pipe(
|
||||
v.string(),
|
||||
v.minLength(5, "Bug title must be at least 5 characters."),
|
||||
v.maxLength(32, "Bug title must be at most 32 characters.")
|
||||
),
|
||||
description: v.pipe(
|
||||
v.string(),
|
||||
v.minLength(20, "Description must be at least 20 characters."),
|
||||
v.maxLength(100, "Description must be at most 100 characters.")
|
||||
),
|
||||
})
|
||||
```
|
||||
|
||||
### Set up the form
|
||||
|
||||
Next, we'll use the `useForm` hook from Formisch to create our form instance. The schema is passed directly to `useForm` — there is no resolver step.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {1-2,21-25}
|
||||
import { Form, Field as FormischField, useForm } from "@formisch/react"
|
||||
import type { SubmitHandler } from "@formisch/react"
|
||||
import * as v from "valibot"
|
||||
|
||||
const FormSchema = v.object({
|
||||
title: v.pipe(
|
||||
v.string(),
|
||||
v.minLength(5, "Bug title must be at least 5 characters."),
|
||||
v.maxLength(32, "Bug title must be at most 32 characters.")
|
||||
),
|
||||
description: v.pipe(
|
||||
v.string(),
|
||||
v.minLength(20, "Description must be at least 20 characters."),
|
||||
v.maxLength(100, "Description must be at most 100 characters.")
|
||||
),
|
||||
})
|
||||
|
||||
export function BugReportForm() {
|
||||
const form = useForm({
|
||||
schema: FormSchema,
|
||||
initialInput: {
|
||||
title: "",
|
||||
description: "",
|
||||
},
|
||||
})
|
||||
|
||||
const handleSubmit: SubmitHandler<typeof FormSchema> = (output) => {
|
||||
// Do something with the validated form values.
|
||||
console.log(output)
|
||||
}
|
||||
|
||||
return (
|
||||
<Form of={form} onSubmit={handleSubmit}>
|
||||
{/* ... */}
|
||||
{/* Build the form here */}
|
||||
{/* ... */}
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The `<Form />` component wraps a native `<form>` element. It calls `event.preventDefault()`, runs validation, and only invokes `onSubmit` when the data is valid. The `output` you receive is fully typed from the schema.
|
||||
|
||||
### Build the form
|
||||
|
||||
We can now build the form using the `<Field />` component from Formisch and the shadcn `<Field />` component.
|
||||
|
||||
<ComponentSource
|
||||
src="/registry/new-york-v4/examples/form-formisch-demo.tsx"
|
||||
title="form.tsx"
|
||||
/>
|
||||
|
||||
### Done
|
||||
|
||||
That's it. You now have a fully accessible form with client-side validation.
|
||||
|
||||
When you submit the form, the `handleSubmit` function will be called with the validated form data. If the form data is invalid, Formisch will populate `field.errors` for each invalid field and the UI will display them.
|
||||
|
||||
## Validation
|
||||
|
||||
### Client-side Validation
|
||||
|
||||
Formisch validates your form data using the Valibot schema you pass to `useForm`. There is no resolver — the schema is the single source of truth for both runtime validation and static types.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {1,3-6,11}
|
||||
import { useForm } from "@formisch/react"
|
||||
|
||||
const FormSchema = v.object({
|
||||
title: v.string(),
|
||||
description: v.optional(v.string()),
|
||||
})
|
||||
|
||||
export function ExampleForm() {
|
||||
const form = useForm({
|
||||
schema: FormSchema,
|
||||
initialInput: {
|
||||
title: "",
|
||||
description: "",
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Validation Modes
|
||||
|
||||
Formisch separates the **first** validation from **subsequent** validations. You configure them with the `validate` and `revalidate` options on `useForm`.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {3-4}
|
||||
const form = useForm({
|
||||
schema: FormSchema,
|
||||
validate: "blur",
|
||||
revalidate: "input",
|
||||
})
|
||||
```
|
||||
|
||||
| Option | Value | Description |
|
||||
| ------------ | ----------- | --------------------------------------------------------------- |
|
||||
| `validate` | `"submit"` | Validate on form submission (default). |
|
||||
| `validate` | `"blur"` | Validate when a field loses focus. |
|
||||
| `validate` | `"input"` | Validate on every input change. |
|
||||
| `validate` | `"initial"` | Validate immediately on form creation. |
|
||||
| `revalidate` | `"input"` | Revalidate on every input change after the first run (default). |
|
||||
| `revalidate` | `"blur"` | Revalidate on blur after the first run. |
|
||||
| `revalidate` | `"submit"` | Revalidate only on form submission. |
|
||||
|
||||
## Displaying Errors
|
||||
|
||||
Display errors next to the field using `<FieldError />`. Formisch returns errors as an array of strings, so map them to the shape `<FieldError />` expects. For styling and accessibility:
|
||||
|
||||
- Add the `data-invalid` prop to the `<Field />` component.
|
||||
- Add the `aria-invalid` prop to the form control such as `<Input />`, `<SelectTrigger />`, `<Checkbox />`, etc.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {3,10,12-14}
|
||||
<FormischField of={form} path={["email"]}>
|
||||
{(field) => (
|
||||
<Field data-invalid={field.errors !== null}>
|
||||
<FieldLabel htmlFor="form-email">Email</FieldLabel>
|
||||
<Input
|
||||
{...field.props}
|
||||
id="form-email"
|
||||
value={field.input}
|
||||
type="email"
|
||||
aria-invalid={field.errors !== null}
|
||||
/>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</Field>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
## Working with Different Field Types
|
||||
|
||||
Formisch exposes two ways to bind a field to an element:
|
||||
|
||||
- **Native HTML elements** (like `<Input />` and `<Textarea />`) — spread `field.props` and provide `value={field.input}`. Formisch wires up `name`, `ref`, `onChange`, `onBlur`, and `onFocus` for you.
|
||||
- **Component-library inputs** (like Radix-based `<Select />`, `<Checkbox />`, `<RadioGroup />`, `<Switch />`) — read the value from `field.input` and call `field.onChange(value)` to update it.
|
||||
|
||||
### Input
|
||||
|
||||
- For input fields, spread `field.props` and provide `value={field.input}`.
|
||||
- To show errors, add the `aria-invalid` prop to the `<Input />` component and the `data-invalid` prop to the `<Field />` component.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-input"
|
||||
className="sm:[&_.preview]:h-[700px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {5-8}
|
||||
<FormischField of={form} path={["username"]}>
|
||||
{(field) => (
|
||||
<Field data-invalid={field.errors !== null}>
|
||||
<FieldLabel htmlFor="form-username">Username</FieldLabel>
|
||||
<Input
|
||||
{...field.props}
|
||||
id="form-username"
|
||||
value={field.input}
|
||||
aria-invalid={field.errors !== null}
|
||||
/>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</Field>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
### Textarea
|
||||
|
||||
- For textarea fields, spread `field.props` and provide `value={field.input}`.
|
||||
- To show errors, add the `aria-invalid` prop to the `<Textarea />` component and the `data-invalid` prop to the `<Field />` component.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-textarea"
|
||||
className="sm:[&_.preview]:h-[700px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {7-10}
|
||||
<FormischField of={form} path={["about"]}>
|
||||
{(field) => (
|
||||
<Field data-invalid={field.errors !== null}>
|
||||
<FieldLabel htmlFor="form-about">More about you</FieldLabel>
|
||||
<Textarea
|
||||
{...field.props}
|
||||
id="form-about"
|
||||
value={field.input}
|
||||
aria-invalid={field.errors !== null}
|
||||
placeholder="I'm a software engineer..."
|
||||
className="min-h-[120px]"
|
||||
/>
|
||||
<FieldDescription>
|
||||
Tell us more about yourself. This will be used to help us personalize
|
||||
your experience.
|
||||
</FieldDescription>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</Field>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
### Select
|
||||
|
||||
- For select components, read `field.input` and call `field.onChange` from `<Select />`'s `onValueChange`.
|
||||
- To show errors, add the `aria-invalid` prop to the `<SelectTrigger />` component and the `data-invalid` prop to the `<Field />` component.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-select"
|
||||
className="sm:[&_.preview]:h-[500px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {15-19}
|
||||
<FormischField of={form} path={["language"]}>
|
||||
{(field) => (
|
||||
<Field orientation="responsive" data-invalid={field.errors !== null}>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="form-language">Spoken Language</FieldLabel>
|
||||
<FieldDescription>
|
||||
For best results, select the language you speak.
|
||||
</FieldDescription>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</FieldContent>
|
||||
<Select value={field.input} onValueChange={field.onChange}>
|
||||
<SelectTrigger
|
||||
id="form-language"
|
||||
aria-invalid={field.errors !== null}
|
||||
className="min-w-[120px]"
|
||||
>
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent position="item-aligned">
|
||||
<SelectItem value="auto">Auto</SelectItem>
|
||||
<SelectItem value="en">English</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
### Checkbox
|
||||
|
||||
- For checkbox arrays, read `field.input` and update it from `onCheckedChange` using `field.onChange`.
|
||||
- To show errors, add the `aria-invalid` prop to the `<Checkbox />` component and the `data-invalid` prop to the `<Field />` component.
|
||||
- Remember to add `data-slot="checkbox-group"` to the `<FieldGroup />` component for proper styling and spacing.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-checkbox"
|
||||
className="sm:[&_.preview]:h-[700px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {16,19-25}
|
||||
<FormischField of={form} path={["tasks"]}>
|
||||
{(field) => (
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Tasks</FieldLegend>
|
||||
<FieldDescription>
|
||||
Get notified when tasks you've created have updates.
|
||||
</FieldDescription>
|
||||
<FieldGroup data-slot="checkbox-group">
|
||||
{tasks.map((task) => (
|
||||
<Field
|
||||
key={task.id}
|
||||
orientation="horizontal"
|
||||
data-invalid={field.errors !== null}
|
||||
>
|
||||
<Checkbox
|
||||
id={`form-checkbox-${task.id}`}
|
||||
aria-invalid={field.errors !== null}
|
||||
checked={field.input?.includes(task.id) ?? false}
|
||||
onCheckedChange={(checked) => {
|
||||
const current = field.input ?? []
|
||||
field.onChange(
|
||||
checked === true
|
||||
? [...current, task.id]
|
||||
: current.filter((value) => value !== task.id)
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<FieldLabel
|
||||
htmlFor={`form-checkbox-${task.id}`}
|
||||
className="font-normal"
|
||||
>
|
||||
{task.label}
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
))}
|
||||
</FieldGroup>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</FieldSet>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
### Radio Group
|
||||
|
||||
- For radio groups, read `field.input` and call `field.onChange` from `onValueChange`.
|
||||
- To show errors, add the `aria-invalid` prop to the `<RadioGroupItem />` component and the `data-invalid` prop to the `<Field />` component.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-radiogroup"
|
||||
className="sm:[&_.preview]:h-[700px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {9-13,21}
|
||||
<FormischField of={form} path={["plan"]}>
|
||||
{(field) => (
|
||||
<FieldSet>
|
||||
<FieldLegend>Plan</FieldLegend>
|
||||
<FieldDescription>
|
||||
You can upgrade or downgrade your plan at any time.
|
||||
</FieldDescription>
|
||||
<RadioGroup value={field.input} onValueChange={field.onChange}>
|
||||
{plans.map((plan) => (
|
||||
<FieldLabel key={plan.id} htmlFor={`form-radiogroup-${plan.id}`}>
|
||||
<Field
|
||||
orientation="horizontal"
|
||||
data-invalid={field.errors !== null}
|
||||
>
|
||||
<FieldContent>
|
||||
<FieldTitle>{plan.title}</FieldTitle>
|
||||
<FieldDescription>{plan.description}</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem
|
||||
value={plan.id}
|
||||
id={`form-radiogroup-${plan.id}`}
|
||||
aria-invalid={field.errors !== null}
|
||||
/>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
))}
|
||||
</RadioGroup>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</FieldSet>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
### Switch
|
||||
|
||||
- For switches, read `field.input` and call `field.onChange` from `onCheckedChange`.
|
||||
- To show errors, add the `aria-invalid` prop to the `<Switch />` component and the `data-invalid` prop to the `<Field />` component.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-switch"
|
||||
className="sm:[&_.preview]:h-[500px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {15-19}
|
||||
<FormischField of={form} path={["twoFactor"]}>
|
||||
{(field) => (
|
||||
<Field orientation="horizontal" data-invalid={field.errors !== null}>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="form-twoFactor">
|
||||
Multi-factor authentication
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable multi-factor authentication to secure your account.
|
||||
</FieldDescription>
|
||||
{field.errors && (
|
||||
<FieldError errors={field.errors.map((message) => ({ message }))} />
|
||||
)}
|
||||
</FieldContent>
|
||||
<Switch
|
||||
id="form-twoFactor"
|
||||
checked={field.input ?? false}
|
||||
onCheckedChange={field.onChange}
|
||||
aria-invalid={field.errors !== null}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
</FormischField>
|
||||
```
|
||||
|
||||
### Complex Forms
|
||||
|
||||
Here is an example of a more complex form with multiple fields and validation.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-complex"
|
||||
className="sm:[&_.preview]:h-[1300px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
## Resetting the Form
|
||||
|
||||
Formisch exposes a top-level `reset` function. Pass the form store to reset it to its initial input.
|
||||
|
||||
```tsx showLineNumbers
|
||||
<Button type="button" variant="outline" onClick={() => reset(form)}>
|
||||
Reset
|
||||
</Button>
|
||||
```
|
||||
|
||||
You can also reset to new initial values, or reset while keeping the user's current input:
|
||||
|
||||
```tsx showLineNumbers
|
||||
// Reset to a fresh set of initial values
|
||||
reset(form, { initialInput: { title: "", description: "" } })
|
||||
|
||||
// Sync the baseline to new server data, but keep the user's edits
|
||||
reset(form, { initialInput: serverData, keepInput: true })
|
||||
```
|
||||
|
||||
## Array Fields
|
||||
|
||||
Formisch provides a `<FieldArray />` component and a set of helper functions for managing dynamic array fields. Use it whenever you need to add, remove, or reorder items.
|
||||
|
||||
<ComponentPreview
|
||||
name="form-formisch-array"
|
||||
className="sm:[&_.preview]:h-[700px]"
|
||||
chromeLessOnMobile
|
||||
/>
|
||||
|
||||
### Using FieldArray
|
||||
|
||||
`<FieldArray />` follows the same render-prop pattern as `<Field />`. Its `items` array contains a stable key per item that you should use as the React `key`.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx" {1,7-22}
|
||||
import {
|
||||
Field as FormischField,
|
||||
FieldArray,
|
||||
insert,
|
||||
remove,
|
||||
} from "@formisch/react"
|
||||
|
||||
export function ExampleForm() {
|
||||
// ... form config
|
||||
|
||||
return (
|
||||
<FieldArray of={form} path={["emails"]}>
|
||||
{(fieldArray) => (
|
||||
<FieldGroup className="gap-4">
|
||||
{fieldArray.items.map((item, index) => (
|
||||
<FormischField
|
||||
key={item}
|
||||
of={form}
|
||||
path={["emails", index, "address"]}
|
||||
>
|
||||
{(field) => /* ... */}
|
||||
</FormischField>
|
||||
))}
|
||||
</FieldGroup>
|
||||
)}
|
||||
</FieldArray>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Array Field Structure
|
||||
|
||||
Wrap your array fields in a `<FieldSet />` with a `<FieldLegend />` and `<FieldDescription />`.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx"
|
||||
<FieldSet className="gap-4">
|
||||
<FieldLegend variant="label">Email Addresses</FieldLegend>
|
||||
<FieldDescription>
|
||||
Add up to 5 email addresses where we can contact you.
|
||||
</FieldDescription>
|
||||
<FieldGroup className="gap-4">{/* Array items go here */}</FieldGroup>
|
||||
</FieldSet>
|
||||
```
|
||||
|
||||
### Adding Items
|
||||
|
||||
Use the `insert` function to add new items to the array. By default new items are appended to the end. You can also pass an `at` index to insert at a specific position.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx"
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
insert(form, { path: ["emails"], initialInput: { address: "" } })
|
||||
}
|
||||
disabled={fieldArray.items.length >= 5}
|
||||
>
|
||||
Add Email Address
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Removing Items
|
||||
|
||||
Use the `remove` function with an `at` index to remove items from the array.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx"
|
||||
import { remove } from "@formisch/react"
|
||||
|
||||
{
|
||||
fieldArray.items.length > 1 && (
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
onClick={() => remove(form, { path: ["emails"], at: index })}
|
||||
aria-label={`Remove email ${index + 1}`}
|
||||
>
|
||||
<XIcon />
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Formisch also exposes `move`, `swap`, and `replace` for reordering and replacing items. They follow the same `(form, config)` signature.
|
||||
|
||||
### Array Validation
|
||||
|
||||
Use Valibot's `array` and pipeline validators to constrain array fields.
|
||||
|
||||
```tsx showLineNumbers title="form.tsx"
|
||||
const FormSchema = v.object({
|
||||
emails: v.pipe(
|
||||
v.array(
|
||||
v.object({
|
||||
address: v.pipe(
|
||||
v.string(),
|
||||
v.nonEmpty("Enter an email address."),
|
||||
v.email("Enter a valid email address.")
|
||||
),
|
||||
})
|
||||
),
|
||||
v.minLength(1, "Add at least one email address."),
|
||||
v.maxLength(5, "You can add up to 5 email addresses.")
|
||||
),
|
||||
})
|
||||
```
|
||||
@@ -25,6 +25,24 @@ Start by selecting your framework. Then follow the instructions to learn how to
|
||||
</svg>
|
||||
<p className="mt-2 font-medium">TanStack Form</p>
|
||||
</LinkedCard>
|
||||
<LinkedCard href="/docs/forms/formisch">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
className="size-10"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="20"
|
||||
d="M90.9 291.7 49 299.4v125.5l193.3 63.8 221-63.8V304.7l-62-13.7m-352.2 8.6 193.2 53.6V488m221-183.2-221.1 48.4m-171-67.7 147.5 47 212.7-48.3L437 76 271.9 25 72.1 66.3Zm1-219.3L220.5 118l-1.8 214m1.8-214.3 216.2-41.6m-84.4 159.6-.9 1.9c-5.2 11.3-16.2 34.8-33.5 35.5h-1a22 22 0 0 1-9.7-2.2 26 26 0 0 1-7.4-5.5c-4.3-4.4-7.4-10-10-14.5q-1.2-2.4-2.7-4.7a54 54 0 0 0 21.7 4.1 74 74 0 0 0 23.6-4 70 70 0 0 0 11.4-5 64 64 0 0 0 8.5-5.6M247.6 168c19.5-20.8 34.8-12.3 36-18.4 1.5-7-12.2-7.7-22.2-2.6s-18 17.7-13.8 21m101.2-33.2c1.6 2.6 8.7-1.6 19.5-1.2s15.8 5.7 18 4.1-4.6-14.7-17.1-15.2-22 9.7-20.4 12.3m21.2 16.3c9.4.6 17.1 12.8 16.1 27.6s-10.4 25.9-19.8 25.2-17.1-12.9-16.1-27.7 10.4-25.8 19.8-25.1m-97.4 19c11 1.2 19 15.1 17.4 30.5s-12.3 27.4-23.4 26.2-19-15-17.4-30.5 12.3-27.3 23.4-26.2"
|
||||
/>
|
||||
</svg>
|
||||
<p className="mt-2 font-medium">Formisch</p>
|
||||
</LinkedCard>
|
||||
<LinkedCard href="#" className="border border-dashed bg-transparent">
|
||||
<svg
|
||||
role="img"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"pages": ["react-hook-form", "tanstack-form"]
|
||||
"pages": ["react-hook-form", "tanstack-form", "formisch"]
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ Add the following dependencies to your project:
|
||||
npm install shadcn class-variance-authority clsx tailwind-merge lucide-react tw-animate-css
|
||||
```
|
||||
|
||||
### Configure path aliases
|
||||
### Configure import aliases
|
||||
|
||||
Configure the path aliases in your `tsconfig.json` file.
|
||||
Choose one of the following alias setups.
|
||||
|
||||
#### Option A: `tsconfig.json` paths
|
||||
|
||||
```json {3-6} title="tsconfig.json" showLineNumbers
|
||||
{
|
||||
@@ -34,7 +36,31 @@ Configure the path aliases in your `tsconfig.json` file.
|
||||
}
|
||||
```
|
||||
|
||||
The `@` alias is a preference. You can use other aliases if you want.
|
||||
#### Option B: `package.json#imports`
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"imports": {
|
||||
"#components/*": "./src/components/*.tsx",
|
||||
"#lib/*": "./src/lib/*.ts",
|
||||
"#hooks/*": "./src/hooks/*.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json title="tsconfig.json" showLineNumbers
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "bundler",
|
||||
"resolvePackageJsonImports": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `@` alias is a preference. You can use other aliases if you want. If you
|
||||
use `package.json#imports`, keep the matching alias roots in `components.json`.
|
||||
See the <Link href="/docs/package-imports">package imports guide</Link> for
|
||||
framework-specific setup.
|
||||
|
||||
### Configure styles
|
||||
|
||||
@@ -211,6 +237,20 @@ Create a `components.json` file in the root of your project.
|
||||
}
|
||||
```
|
||||
|
||||
If you're using `package.json#imports`, use the corresponding `#...` aliases instead:
|
||||
|
||||
```json title="components.json" showLineNumbers
|
||||
{
|
||||
"aliases": {
|
||||
"components": "#components",
|
||||
"utils": "#lib/utils",
|
||||
"ui": "#components/ui",
|
||||
"lib": "#lib",
|
||||
"hooks": "#hooks"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### That's it
|
||||
|
||||
You can now start adding components to your project.
|
||||
|
||||
@@ -309,6 +309,94 @@ A `registry:hook` item is a custom React hook.
|
||||
}
|
||||
```
|
||||
|
||||
## Target Placeholders
|
||||
|
||||
Use `files[].target` placeholders when a registry item should install files
|
||||
under the user's configured shadcn directories. The available placeholders are
|
||||
`@components/`, `@ui/`, `@lib/` and `@hooks/`.
|
||||
|
||||
The placeholders are resolved from `components.json`, so the same registry item
|
||||
works in projects using `@/`, custom TypeScript aliases, package imports or
|
||||
workspace package exports.
|
||||
|
||||
Anything after the placeholder is preserved. For example,
|
||||
`@ui/ai/prompt-input.tsx` installs under the user's configured `ui` directory
|
||||
at `ai/prompt-input.tsx`.
|
||||
|
||||
```json title="alias-child.json" showLineNumbers {9,15,21}
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
||||
"name": "alias-child",
|
||||
"type": "registry:item",
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/alias/target-alias-button.tsx",
|
||||
"type": "registry:ui",
|
||||
"target": "@ui/target-alias-button.tsx",
|
||||
"content": "..."
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/alias/target-alias-helper.ts",
|
||||
"type": "registry:lib",
|
||||
"target": "@lib/target-alias-helper.ts",
|
||||
"content": "..."
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/alias/prompt-input.tsx",
|
||||
"type": "registry:ui",
|
||||
"target": "@ui/ai/prompt-input.tsx",
|
||||
"content": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Registry dependencies can use target placeholders too. In the following example,
|
||||
the child item installs a UI component and a helper, while the parent item
|
||||
installs an app component and a hook.
|
||||
|
||||
```json title="alias-parent.json" showLineNumbers {7,13}
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
||||
"name": "alias-parent",
|
||||
"type": "registry:item",
|
||||
"registryDependencies": ["https://example.com/r/alias-child.json"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/alias/target-alias-panel.tsx",
|
||||
"type": "registry:component",
|
||||
"target": "@components/target-alias-panel.tsx",
|
||||
"content": "..."
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/alias/use-target-alias.ts",
|
||||
"type": "registry:hook",
|
||||
"target": "@hooks/use-target-alias.ts",
|
||||
"content": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `target` controls where the file is written, even when it differs from the
|
||||
file `type`.
|
||||
|
||||
```json title="type-mismatch.json" showLineNumbers {9}
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
||||
"name": "type-mismatch",
|
||||
"type": "registry:item",
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/example/format-date.ts",
|
||||
"type": "registry:ui",
|
||||
"target": "@lib/format-date.ts",
|
||||
"content": "..."
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## registry:font
|
||||
|
||||
### Custom font
|
||||
|
||||
@@ -9,7 +9,9 @@ If you're starting a new registry project, you can use the [registry template](h
|
||||
|
||||
## Requirements
|
||||
|
||||
You are free to design and host your custom registry as you see fit. The only requirement is that your registry items must be valid JSON files that conform to the [registry-item schema specification](/docs/registry/registry-item-json).
|
||||
You are free to design and host your custom registry as you see fit. The only requirement is that your registry catalog and registry items must be valid JSON files that conform to the [registry schema specification](/docs/registry/registry-json) and [registry-item schema specification](/docs/registry/registry-item-json).
|
||||
|
||||
Your registry can be a Next.js, Vite, Vue, Svelte, PHP or any other framework as long as it supports serving JSON over HTTP.
|
||||
|
||||
If you'd like to see an example of a registry, we have a [template project](https://github.com/shadcn-ui/registry-template) for you to use as a starting point.
|
||||
|
||||
@@ -19,11 +21,7 @@ The `registry.json` is the entry point for the registry. It contains the registr
|
||||
|
||||
Your registry must have this file (or JSON payload) present at the root of the registry endpoint. The registry endpoint is the URL where your registry is hosted.
|
||||
|
||||
The `shadcn` CLI will automatically generate this file for you when you run the `build` command.
|
||||
|
||||
## Add a registry.json file
|
||||
|
||||
Create a `registry.json` file in the root of your project. Your project can be a Next.js, Vite, Vue, Svelte, PHP or any other framework as long as it supports serving JSON over HTTP.
|
||||
Here's an example `registry.json` file:
|
||||
|
||||
```json title="registry.json" showLineNumbers
|
||||
{
|
||||
@@ -31,44 +29,204 @@ Create a `registry.json` file in the root of your project. Your project can be a
|
||||
"name": "acme",
|
||||
"homepage": "https://acme.com",
|
||||
"items": [
|
||||
// ...
|
||||
{
|
||||
"name": "button",
|
||||
"type": "registry:ui",
|
||||
"title": "Button",
|
||||
"description": "A simple button component.",
|
||||
"files": [
|
||||
{
|
||||
"path": "components/ui/button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Structure your registry
|
||||
|
||||
You can structure your source registry in one of two ways:
|
||||
|
||||
- Define all items in a single root `registry.json`.
|
||||
- Use a root `registry.json` with `include` to compose multiple `registry.json` files.
|
||||
|
||||
### Option A: Single registry.json
|
||||
|
||||
Create a `registry.json` file in the root of your project. Add all your registry items to the `items` array. This is the simplest way to define a registry.
|
||||
|
||||
```json title="registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"name": "acme",
|
||||
"homepage": "https://acme.com",
|
||||
"items": [
|
||||
{
|
||||
"name": "button",
|
||||
"type": "registry:ui",
|
||||
"title": "Button",
|
||||
"description": "A simple button component.",
|
||||
"files": [
|
||||
{
|
||||
"path": "components/ui/button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hello-world",
|
||||
"type": "registry:block",
|
||||
"title": "Hello World",
|
||||
"description": "A simple hello world component.",
|
||||
"registryDependencies": ["button"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/default/hello-world/hello-world.tsx",
|
||||
"type": "registry:component"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This `registry.json` file must conform to the [registry schema specification](/docs/registry/registry-json).
|
||||
|
||||
## Add a registry item
|
||||
### Option B: Using include
|
||||
|
||||
### Create your component
|
||||
For larger registries, you can use `include` to compose your source registry
|
||||
from multiple `registry.json` files.
|
||||
|
||||
Add your first component. Here's an example of a simple `<HelloWorld />` component:
|
||||
```txt
|
||||
registry.json
|
||||
components
|
||||
└── ui
|
||||
├── button.tsx
|
||||
├── input.tsx
|
||||
└── registry.json
|
||||
hooks
|
||||
├── registry.json
|
||||
├── use-media-query.ts
|
||||
└── use-toggle.ts
|
||||
```
|
||||
|
||||
```tsx title="registry/new-york/hello-world/hello-world.tsx" showLineNumbers
|
||||
import { Button } from "@/components/ui/button"
|
||||
The root `registry.json` defines the registry metadata and includes the nested
|
||||
registry files.
|
||||
|
||||
export function HelloWorld() {
|
||||
return <Button>Hello World</Button>
|
||||
{/* prettier-ignore */}
|
||||
```json title="registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"name": "acme",
|
||||
"homepage": "https://acme.com",
|
||||
"include": [
|
||||
"components/ui/registry.json",
|
||||
"hooks/registry.json"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Included `registry.json` files are valid registry files for composition and may
|
||||
omit `name` and `homepage`. Only the root `registry.json` must define the
|
||||
registry metadata.
|
||||
|
||||
```json title="components/ui/registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"items": [
|
||||
{
|
||||
"name": "button",
|
||||
"type": "registry:ui",
|
||||
"files": [
|
||||
{
|
||||
"path": "button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "input",
|
||||
"type": "registry:ui",
|
||||
"files": [
|
||||
{
|
||||
"path": "input.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json title="hooks/registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"items": [
|
||||
{
|
||||
"name": "use-toggle",
|
||||
"type": "registry:hook",
|
||||
"files": [
|
||||
{
|
||||
"path": "use-toggle.ts",
|
||||
"type": "registry:hook"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "use-media-query",
|
||||
"type": "registry:hook",
|
||||
"files": [
|
||||
{
|
||||
"path": "use-media-query.ts",
|
||||
"type": "registry:hook"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
When using `include`, file paths are relative to the `registry.json` file that
|
||||
declares the item.
|
||||
|
||||
## Add an item
|
||||
|
||||
### Create a UI component
|
||||
|
||||
Add your first item. Here's an example of a simple `<Button />` component:
|
||||
|
||||
```tsx title="components/ui/button.tsx" showLineNumbers
|
||||
import * as React from "react"
|
||||
|
||||
export function Button(props: React.ComponentProps<"button">) {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
className="rounded-md bg-neutral-900 px-4 py-2 text-sm font-medium text-white"
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
<Callout className="mt-6">
|
||||
**Note:** This example places the component in the `registry/new-york`
|
||||
directory. You can place it anywhere in your project as long as you set the
|
||||
correct path in the `registry.json` file and you follow the `registry/[NAME]`
|
||||
directory structure.
|
||||
**Note:** This example places the component in the `components/ui` directory.
|
||||
You can place it anywhere in your project as long as you set the correct path
|
||||
in the `registry.json` file.
|
||||
</Callout>
|
||||
|
||||
```txt
|
||||
registry
|
||||
└── new-york
|
||||
└── hello-world
|
||||
└── hello-world.tsx
|
||||
components
|
||||
└── ui
|
||||
└── button.tsx
|
||||
```
|
||||
|
||||
### Add your component to the registry
|
||||
### Add the item to the registry
|
||||
|
||||
To add your component to the registry, you need to add your component definition to `registry.json`.
|
||||
To add your component to the registry, add an item definition to `registry.json`.
|
||||
If you are using `include`, add the item to the included `registry.json` file
|
||||
that owns the component. For example, add a UI component to
|
||||
`components/ui/registry.json`.
|
||||
|
||||
```json title="registry.json" showLineNumbers {6-17}
|
||||
{
|
||||
@@ -77,14 +235,14 @@ To add your component to the registry, you need to add your component definition
|
||||
"homepage": "https://acme.com",
|
||||
"items": [
|
||||
{
|
||||
"name": "hello-world",
|
||||
"type": "registry:block",
|
||||
"title": "Hello World",
|
||||
"description": "A simple hello world component.",
|
||||
"name": "button",
|
||||
"type": "registry:ui",
|
||||
"title": "Button",
|
||||
"description": "A simple button component.",
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/hello-world/hello-world.tsx",
|
||||
"type": "registry:component"
|
||||
"path": "components/ui/button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -94,76 +252,144 @@ To add your component to the registry, you need to add your component definition
|
||||
|
||||
You define your registry item by adding a `name`, `type`, `title`, `description` and `files`.
|
||||
|
||||
For every file you add, you must specify the `path` and `type` of the file. The `path` is the relative path to the file from the root of your project. The `type` is the type of the file.
|
||||
For every file you add, you must specify the `path` and `type` of the file. In a single-file registry, the `path` is relative to the root of your project. When using `include`, the `path` is relative to the `registry.json` file that declares the item. The `type` is the type of the file.
|
||||
|
||||
You can read more about the registry item schema and file types in the [registry item schema docs](/docs/registry/registry-item-json).
|
||||
|
||||
## Build your registry
|
||||
## Serve your registry
|
||||
|
||||
### Install the shadcn CLI
|
||||
You can serve your registry as static JSON files or from dynamic route handlers.
|
||||
|
||||
### Option A: Static JSON files
|
||||
|
||||
Run the build command to generate static registry JSON files.
|
||||
|
||||
```bash
|
||||
npm install shadcn@latest
|
||||
npx shadcn@latest build
|
||||
```
|
||||
|
||||
### Add a build script
|
||||
|
||||
Add a `registry:build` script to your `package.json` file.
|
||||
|
||||
```json title="package.json" showLineNumbers
|
||||
{
|
||||
"scripts": {
|
||||
"registry:build": "shadcn build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Run the build script
|
||||
|
||||
Run the build script to generate the registry JSON files.
|
||||
|
||||
```bash
|
||||
npm run registry:build
|
||||
```
|
||||
If your source registry uses `include`, `shadcn build` resolves the included
|
||||
registries and writes a flattened registry to your output directory. The
|
||||
generated `registry.json` does not contain `include`.
|
||||
|
||||
<Callout className="mt-6">
|
||||
**Note:** By default, the build script will generate the registry JSON files
|
||||
in `public/r` e.g `public/r/hello-world.json`.
|
||||
|
||||
You can change the output directory by passing the `--output` option. See the [shadcn build command](/docs/cli#build) for more information.
|
||||
**Note:** By default, the build command will generate the registry JSON files
|
||||
in `public/r` e.g `public/r/button.json`. You can change the output directory by passing the `--output` option. See the [shadcn build command](/docs/cli#build) for more information.
|
||||
|
||||
</Callout>
|
||||
|
||||
## Serve your registry
|
||||
|
||||
If you're running your registry on Next.js, you can now serve your registry by running the `next` server. The command might differ for other frameworks.
|
||||
If you're running your registry on Next.js, you can serve these files by running
|
||||
the `next` server. The command might differ for other frameworks.
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Your files will now be served at `http://localhost:3000/r/[NAME].json` eg. `http://localhost:3000/r/hello-world.json`.
|
||||
Your files will now be served at `http://localhost:3000/r/[NAME].json` eg. `http://localhost:3000/r/button.json`.
|
||||
|
||||
## Content negotiation
|
||||
### Option B: Dynamic route handlers
|
||||
|
||||
If you want to serve registry JSON from your source `registry.json` at request
|
||||
time, use the producer-side loader APIs from `shadcn/registry`.
|
||||
|
||||
Install `shadcn` as a runtime dependency:
|
||||
|
||||
```bash
|
||||
npm install shadcn
|
||||
```
|
||||
|
||||
Use `loadRegistry` to serve the registry catalog.
|
||||
|
||||
```ts title="app/r/registry.json/route.ts" showLineNumbers
|
||||
import { loadRegistry } from "shadcn/registry"
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const registry = await loadRegistry()
|
||||
|
||||
return Response.json(registry)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
||||
return Response.json({ error: "Failed to load registry." }, { status: 500 })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `loadRegistryItem` to serve individual registry items.
|
||||
|
||||
```ts title="app/r/[name].json/route.ts" showLineNumbers
|
||||
import { loadRegistryItem, RegistryItemNotFoundError } from "shadcn/registry"
|
||||
|
||||
export async function GET(
|
||||
_request: Request,
|
||||
context: {
|
||||
params: Promise<{
|
||||
name: string
|
||||
}>
|
||||
}
|
||||
) {
|
||||
const { name } = await context.params
|
||||
|
||||
try {
|
||||
const item = await loadRegistryItem(name)
|
||||
|
||||
return Response.json(item)
|
||||
} catch (error) {
|
||||
if (error instanceof RegistryItemNotFoundError) {
|
||||
return Response.json(
|
||||
{ error: `Registry item "${name}" was not found.` },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
|
||||
console.error(error)
|
||||
|
||||
return Response.json(
|
||||
{ error: "Failed to load registry item." },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Both loaders resolve `include` before returning JSON, so route handlers can use
|
||||
the same source `registry.json` structure without running `shadcn build`.
|
||||
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="content-negotiation">
|
||||
<AccordionTrigger>Content negotiation</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
|
||||
The `shadcn` CLI supports **HTTP Content Negotiation**. This allows you to host your registry at any endpoint — including the root of your domain — and serve different content depending on who is asking.
|
||||
|
||||
From a single URL, you can serve:
|
||||
|
||||
- **HTML** to browsers — a landing page, documentation, or marketing site.
|
||||
- **JSON** to the `shadcn` CLI — an installable registry item.
|
||||
- **Markdown** to AI agents and LLMs — a machine-readable version of your content.
|
||||
<ul>
|
||||
<li>
|
||||
<strong>HTML</strong> to browsers — a landing page, documentation, or
|
||||
marketing site.
|
||||
</li>
|
||||
<li>
|
||||
<strong>JSON</strong> to the <code>shadcn</code> CLI — an installable
|
||||
registry item.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Markdown</strong> to AI agents and LLMs — a machine-readable version
|
||||
of your content.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
The client signals its preference using the `Accept` request header, and your server decides what to return.
|
||||
|
||||
### Request headers
|
||||
#### Request headers
|
||||
|
||||
When the CLI makes a request to a registry, it sends the following headers:
|
||||
|
||||
- **User-Agent**: `shadcn`
|
||||
- **Accept**: `application/vnd.shadcn.v1+json, application/json;q=0.9`
|
||||
|
||||
### Root hosting
|
||||
#### Root hosting
|
||||
|
||||
By checking these headers on your server, you can route CLI traffic to an installable registry item while keeping browser traffic flowing to your documentation or homepage.
|
||||
|
||||
@@ -240,34 +466,179 @@ app.get("/", (req, res) => {
|
||||
|
||||
This enables:
|
||||
|
||||
- **Branded Registry URLs**: `shadcn add https://ui.example.com`
|
||||
- **Shorter URLs**: Users type your domain root, not `/r/` or `/registry/` sub-paths.
|
||||
- **Easy Mnemonics**: Easier for users to remember and share your registry.
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Branded Registry URLs</strong>:{" "}
|
||||
<code>shadcn add https://ui.example.com</code>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Shorter URLs</strong>: Users type your domain root, not{" "}
|
||||
<code>/r/</code> or <code>/registry/</code> sub-paths.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Easy Mnemonics</strong>: Easier for users to remember and share your
|
||||
registry.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</AccordionContent>
|
||||
|
||||
</AccordionItem>
|
||||
|
||||
</Accordion>
|
||||
|
||||
## Test your registry
|
||||
|
||||
After your registry is being served, test it with the same CLI commands that
|
||||
other developers will use.
|
||||
|
||||
### Using URL
|
||||
|
||||
Use the catalog URL for commands that discover items, like `list` and `search`.
|
||||
Use item URLs for commands that read or install a specific item, like `view` and
|
||||
`add`.
|
||||
|
||||
#### List items
|
||||
|
||||
Start by confirming that the registry catalog can be discovered.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest list http://localhost:3000/r/registry.json
|
||||
```
|
||||
|
||||
#### Search items
|
||||
|
||||
Search the registry by query.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest search http://localhost:3000/r/registry.json --query button
|
||||
```
|
||||
|
||||
#### View an item
|
||||
|
||||
Then view one registry item by name.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest view http://localhost:3000/r/button.json
|
||||
```
|
||||
|
||||
#### Add an item
|
||||
|
||||
To test the install flow, run `add` from a project where you want to install the
|
||||
item.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add http://localhost:3000/r/button.json
|
||||
```
|
||||
|
||||
### Using namespace
|
||||
|
||||
#### Add the registry
|
||||
|
||||
You can also test your registry with a namespace. From a project with a
|
||||
`components.json` file, add your registry URL template to the project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest registry add @acme=http://localhost:3000/r/{name}.json
|
||||
```
|
||||
|
||||
The `{name}` placeholder must resolve to an item JSON file. For example,
|
||||
`@acme/button` resolves to `http://localhost:3000/r/button.json`. The catalog is
|
||||
still served separately at `http://localhost:3000/r/registry.json`.
|
||||
|
||||
#### List items
|
||||
|
||||
Then list the items in your registry.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest list @acme
|
||||
```
|
||||
|
||||
#### Search items
|
||||
|
||||
Search the registry by query.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest search @acme --query button
|
||||
```
|
||||
|
||||
#### View an item
|
||||
|
||||
View one registry item by name.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest view @acme/button
|
||||
```
|
||||
|
||||
#### Add an item
|
||||
|
||||
To test the install flow, run `add` from a project where you want to install the
|
||||
item.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add @acme/button
|
||||
```
|
||||
|
||||
See the [Namespaced Registries](/docs/registry/namespace) docs for more
|
||||
information.
|
||||
|
||||
## Publish your registry
|
||||
|
||||
To make your registry available to other developers, you can publish it by deploying your project to a public URL.
|
||||
To make your registry available to other developers, publish your project to a
|
||||
public URL. Once deployed, users can install items directly from item URLs, or
|
||||
they can add your registry as a namespace in their project.
|
||||
|
||||
### Share namespace setup instructions
|
||||
|
||||
If you want users to install items with a namespace like `@acme/button`, tell
|
||||
them to add your registry URL template to their project. The `{name}`
|
||||
placeholder is replaced by the item name when the CLI resolves the registry
|
||||
item.
|
||||
|
||||
The template must resolve to item JSON files. For example, `@acme/button`
|
||||
resolves to `https://acme.com/r/button.json`. Your registry catalog should still
|
||||
be served separately at `https://acme.com/r/registry.json`.
|
||||
|
||||
They can add the namespace with the CLI.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest registry add @acme=https://acme.com/r/{name}.json
|
||||
```
|
||||
|
||||
Or they can add it manually under the `registries` field in their
|
||||
`components.json` file.
|
||||
|
||||
```json title="components.json" showLineNumbers
|
||||
{
|
||||
"registries": {
|
||||
"@acme": "https://acme.com/r/{name}.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Users can then consume items from your registry by namespace.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add @acme/button
|
||||
```
|
||||
|
||||
### Add your namespace to the registry index
|
||||
|
||||
If your registry is open source and publicly available, you can submit your
|
||||
namespace to the official registry index. This lets users add your namespace by
|
||||
name instead of pasting the full URL template.
|
||||
|
||||
See the [Registry Index](/docs/registry/registry-index) docs for the submission
|
||||
requirements.
|
||||
|
||||
## Guidelines
|
||||
|
||||
Here are some guidelines to follow when building components for a registry.
|
||||
|
||||
- Place your registry item in the `registry/[STYLE]/[NAME]` directory. I'm using `new-york` as an example. It can be anything you want as long as it's nested under the `registry` directory.
|
||||
- The following properties are required for the block definition: `name`, `description`, `type` and `files`.
|
||||
- Place your registry item in the `registry/[STYLE]/[NAME]` directory. I'm using `default` as an example. It can be anything you want as long as it's nested under the `registry` directory.
|
||||
- For blocks, the following properties are required: `name`, `description`, `type` and `files`.
|
||||
- It is recommended to add a proper name and description to your registry item. This helps LLMs understand the component and its purpose.
|
||||
- Make sure to list all registry dependencies in `registryDependencies`. A registry dependency is the name of the component in the registry eg. `input`, `button`, `card`, etc or a URL to a registry item eg. `http://localhost:3000/r/editor.json`.
|
||||
- Make sure to list all dependencies in `dependencies`. A dependency is the name of the package in the registry eg. `zod`, `sonner`, etc. To set a version, you can use the `name@version` format eg. `zod@^3.20.0`.
|
||||
- **Imports should always use the `@/registry` path.** eg. `import { HelloWorld } from "@/registry/new-york/hello-world/hello-world"`
|
||||
- **Imports should always use the `@/registry` path.** eg. `import { HelloWorld } from "@/registry/default/hello-world/hello-world"`
|
||||
- Ideally, place your files within a registry item in `components`, `hooks`, `lib` directories.
|
||||
|
||||
## Install using the CLI
|
||||
|
||||
To install a registry item using the `shadcn` CLI, use the `add` command followed by the URL of the registry item.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest add http://localhost:3000/r/hello-world.json
|
||||
```
|
||||
|
||||
See the [Namespaced
|
||||
Registries](/docs/registry/namespace) docs for more information on
|
||||
how to install registry items from a namespaced registry.
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"pages": [
|
||||
"index",
|
||||
"getting-started",
|
||||
"registry-index",
|
||||
"examples",
|
||||
"namespace",
|
||||
"authentication",
|
||||
"examples",
|
||||
"mcp",
|
||||
"registry-index",
|
||||
"open-in-v0",
|
||||
"registry-json",
|
||||
"registry-item-json"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Add a Registry
|
||||
title: Registry Directory
|
||||
description: Open Source Registry Index
|
||||
---
|
||||
|
||||
@@ -17,7 +17,7 @@ You can see the full list at [https://ui.shadcn.com/r/registries.json](https://u
|
||||
|
||||
Once you have submitted your request, it will be validated and reviewed by the team.
|
||||
|
||||
### Requirements
|
||||
## Requirements
|
||||
|
||||
1. The registry must be open source and publicly accessible.
|
||||
2. The registry must be a valid JSON file that conforms to the [registry schema specification](/docs/registry/registry-json).
|
||||
|
||||
@@ -226,6 +226,80 @@ By default, the `shadcn` cli will read a project's `components.json` file to det
|
||||
|
||||
Use `~` to refer to the root of the project e.g `~/foo.config.js`.
|
||||
|
||||
You can also use registry target placeholders to place files under the
|
||||
directories configured by the user's `components.json`. These placeholders are
|
||||
only supported at the start of `target` and are independent of the project's
|
||||
import prefix. For example, `@ui/button.tsx` works whether the project imports
|
||||
components with `@/`, `#`, package imports or workspace exports.
|
||||
|
||||
| Placeholder | Resolves to |
|
||||
| -------------- | -------------------- |
|
||||
| `@components/` | `aliases.components` |
|
||||
| `@ui/` | `aliases.ui` |
|
||||
| `@lib/` | `aliases.lib` |
|
||||
| `@hooks/` | `aliases.hooks` |
|
||||
|
||||
Use these placeholders when you want a registry item to install into the
|
||||
project's configured shadcn directories without hardcoding `components`, `src`
|
||||
or workspace package paths. Anything after the placeholder is preserved, so
|
||||
`@ui/ai/prompt-input.tsx` installs under the user's configured `ui` directory
|
||||
at `ai/prompt-input.tsx`.
|
||||
|
||||
```json title="registry-item.json" showLineNumbers
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/example/button.tsx",
|
||||
"type": "registry:ui",
|
||||
"target": "@ui/button.tsx"
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/example/prompt-input.tsx",
|
||||
"type": "registry:ui",
|
||||
"target": "@ui/ai/prompt-input.tsx"
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/example/card.tsx",
|
||||
"type": "registry:component",
|
||||
"target": "@components/card.tsx"
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/example/helper.ts",
|
||||
"type": "registry:lib",
|
||||
"target": "@lib/helper.ts"
|
||||
},
|
||||
{
|
||||
"path": "registry/new-york/example/use-demo.ts",
|
||||
"type": "registry:hook",
|
||||
"target": "@hooks/use-demo.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `target` property decides where the file is written. It can point to a
|
||||
different shadcn directory than the file `type`.
|
||||
|
||||
```json title="registry-item.json" showLineNumbers
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/example/format-date.ts",
|
||||
"type": "registry:ui",
|
||||
"target": "@lib/format-date.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Unknown placeholders are treated as regular target paths. For example,
|
||||
`@foo/bar.ts` is written as `foo/bar.ts`. Embedded placeholders such as
|
||||
`components/@ui/button.tsx` are also treated as regular paths.
|
||||
|
||||
<Callout>
|
||||
`@utils/` is not supported because `utils` points to a file, not a directory.
|
||||
</Callout>
|
||||
|
||||
### tailwind
|
||||
|
||||
**DEPRECATED:** Use `cssVars.theme` instead for Tailwind v4 projects.
|
||||
|
||||
@@ -24,7 +24,7 @@ The `registry.json` schema is used to define your custom component registry.
|
||||
"dependencies": ["is-even@3.0.0", "motion"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/hello-world/hello-world.tsx",
|
||||
"path": "registry/default/hello-world/hello-world.tsx",
|
||||
"type": "registry:component"
|
||||
}
|
||||
]
|
||||
@@ -33,6 +33,22 @@ The `registry.json` schema is used to define your custom component registry.
|
||||
}
|
||||
```
|
||||
|
||||
You can also organize a large registry across multiple `registry.json` files
|
||||
using `include`.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```json title="registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"name": "acme",
|
||||
"homepage": "https://acme.com",
|
||||
"include": [
|
||||
"components/ui/registry.json",
|
||||
"hooks/registry.json"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Definitions
|
||||
|
||||
You can see the JSON Schema for `registry.json` [here](https://ui.shadcn.com/schema/registry.json).
|
||||
@@ -67,6 +83,61 @@ The homepage of your registry. This is used for data attributes and other metada
|
||||
}
|
||||
```
|
||||
|
||||
### include
|
||||
|
||||
The `include` property is used to compose a registry from other `registry.json`
|
||||
files.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```json title="registry.json" showLineNumbers
|
||||
{
|
||||
"include": [
|
||||
"components/ui/registry.json",
|
||||
"hooks/registry.json"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each include path must be a relative path to an explicit `registry.json` file.
|
||||
Folder shorthand is not supported.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```json title="registry.json" showLineNumbers
|
||||
{
|
||||
"include": [
|
||||
"components/ui/registry.json"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Included `registry.json` files may omit `name` and `homepage`. These fields are
|
||||
required only on the root `registry.json`.
|
||||
|
||||
```json title="components/ui/registry.json" showLineNumbers
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"items": [
|
||||
{
|
||||
"name": "button",
|
||||
"type": "registry:ui",
|
||||
"files": [
|
||||
{
|
||||
"path": "button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
When `shadcn build` resolves includes, item file paths are read relative to the
|
||||
`registry.json` file that declares the item. The generated registry output is
|
||||
flattened and does not contain `include`.
|
||||
|
||||
Registry item names must be unique across the resolved registry, including all
|
||||
included files.
|
||||
|
||||
### items
|
||||
|
||||
The `items` in your registry. Each item must implement the [registry-item schema specification](https://ui.shadcn.com/schema/registry-item.json).
|
||||
@@ -87,7 +158,7 @@ The `items` in your registry. Each item must implement the [registry-item schema
|
||||
"dependencies": ["is-even@3.0.0", "motion"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/new-york/hello-world/hello-world.tsx",
|
||||
"path": "registry/default/hello-world/hello-world.tsx",
|
||||
"type": "registry:component"
|
||||
}
|
||||
]
|
||||
@@ -96,4 +167,7 @@ The `items` in your registry. Each item must implement the [registry-item schema
|
||||
}
|
||||
```
|
||||
|
||||
The root `registry.json` must define at least one of `items` or `include`. If
|
||||
`items` is omitted, it defaults to an empty array.
|
||||
|
||||
See the [registry-item schema documentation](/docs/registry/registry-item-json) for more information.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export const PAGES_NEW = [
|
||||
"/create",
|
||||
"/docs/cli",
|
||||
"/docs/registry",
|
||||
"/docs/registry/getting-started",
|
||||
"/docs/changelog",
|
||||
"/docs/skills",
|
||||
]
|
||||
|
||||
export const PAGES_UPDATED = ["/docs/components/button"]
|
||||
|
||||
@@ -21,6 +21,7 @@ const eventSchema = z.object({
|
||||
"copy_create_share_url",
|
||||
"copy_registry_add_command",
|
||||
"copy_preset_command",
|
||||
"copy_apply_command",
|
||||
]),
|
||||
// declare type AllowedPropertyValues = string | number | boolean | null
|
||||
properties: z
|
||||
|
||||
@@ -55,69 +55,156 @@ function ComponentsListWrapper() {
|
||||
)
|
||||
}
|
||||
|
||||
function getNodeText(node: React.ReactNode): string {
|
||||
if (typeof node === "string" || typeof node === "number") {
|
||||
return String(node)
|
||||
}
|
||||
|
||||
if (Array.isArray(node)) {
|
||||
return node.map((child) => getNodeText(child)).join("")
|
||||
}
|
||||
|
||||
if (React.isValidElement<{ children?: React.ReactNode }>(node)) {
|
||||
return getNodeText(node.props.children)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
function getHeadingId(children: React.ReactNode) {
|
||||
const id = getNodeText(children)
|
||||
.trim()
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/'/g, "")
|
||||
.replace(/\?/g, "")
|
||||
.toLowerCase()
|
||||
|
||||
return id || undefined
|
||||
}
|
||||
|
||||
function HeadingAnchor({
|
||||
id,
|
||||
children,
|
||||
}: {
|
||||
id?: string
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
if (!id) {
|
||||
return children
|
||||
}
|
||||
|
||||
return (
|
||||
<a className="group no-underline" href={`#${id}`}>
|
||||
<span className="underline-offset-4 group-hover:underline">
|
||||
{children}
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="ml-2 text-muted-foreground opacity-0 group-hover:opacity-100"
|
||||
>
|
||||
#
|
||||
</span>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export const mdxComponents = {
|
||||
h1: ({ className, ...props }: React.ComponentProps<"h1">) => (
|
||||
<h1
|
||||
className={cn(
|
||||
"mt-2 scroll-m-28 font-heading text-3xl font-bold tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
h2: ({ className, ...props }: React.ComponentProps<"h2">) => {
|
||||
h1: ({ className, children, id, ...props }: React.ComponentProps<"h1">) => {
|
||||
const headingId = id ?? getHeadingId(children)
|
||||
|
||||
return (
|
||||
<h1
|
||||
id={headingId}
|
||||
className={cn(
|
||||
"mt-2 scroll-m-28 font-heading text-3xl font-bold tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<HeadingAnchor id={headingId}>{children}</HeadingAnchor>
|
||||
</h1>
|
||||
)
|
||||
},
|
||||
h2: ({ className, children, id, ...props }: React.ComponentProps<"h2">) => {
|
||||
const headingId = id ?? getHeadingId(children)
|
||||
|
||||
return (
|
||||
<h2
|
||||
id={props.children
|
||||
?.toString()
|
||||
.replace(/ /g, "-")
|
||||
.replace(/'/g, "")
|
||||
.replace(/\?/g, "")
|
||||
.toLowerCase()}
|
||||
id={headingId}
|
||||
className={cn(
|
||||
"[&+]*:[code]:text-xl mt-10 scroll-m-28 font-heading text-xl font-medium tracking-tight first:mt-0 lg:mt-12 [&+.steps]:mt-0! [&+.steps>h3]:mt-4! [&+h3]:mt-6! [&+p]:mt-4!",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
<HeadingAnchor id={headingId}>{children}</HeadingAnchor>
|
||||
</h2>
|
||||
)
|
||||
},
|
||||
h3: ({ className, children, id, ...props }: React.ComponentProps<"h3">) => {
|
||||
const headingId = id ?? getHeadingId(children)
|
||||
|
||||
return (
|
||||
<h3
|
||||
id={headingId}
|
||||
className={cn(
|
||||
"mt-12 scroll-m-28 font-heading text-lg font-medium tracking-tight [&+p]:mt-4! *:[code]:text-xl",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<HeadingAnchor id={headingId}>{children}</HeadingAnchor>
|
||||
</h3>
|
||||
)
|
||||
},
|
||||
h4: ({ className, children, id, ...props }: React.ComponentProps<"h4">) => {
|
||||
const headingId = id ?? getHeadingId(children)
|
||||
|
||||
return (
|
||||
<h4
|
||||
id={headingId}
|
||||
className={cn(
|
||||
"mt-8 scroll-m-28 font-heading text-base font-medium tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<HeadingAnchor id={headingId}>{children}</HeadingAnchor>
|
||||
</h4>
|
||||
)
|
||||
},
|
||||
h5: ({ className, children, id, ...props }: React.ComponentProps<"h5">) => {
|
||||
const headingId = id ?? getHeadingId(children)
|
||||
|
||||
return (
|
||||
<h5
|
||||
id={headingId}
|
||||
className={cn(
|
||||
"mt-8 scroll-m-28 text-base font-medium tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<HeadingAnchor id={headingId}>{children}</HeadingAnchor>
|
||||
</h5>
|
||||
)
|
||||
},
|
||||
h6: ({ className, children, id, ...props }: React.ComponentProps<"h6">) => {
|
||||
const headingId = id ?? getHeadingId(children)
|
||||
|
||||
return (
|
||||
<h6
|
||||
id={headingId}
|
||||
className={cn(
|
||||
"mt-8 scroll-m-28 text-base font-medium tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<HeadingAnchor id={headingId}>{children}</HeadingAnchor>
|
||||
</h6>
|
||||
)
|
||||
},
|
||||
h3: ({ className, ...props }: React.ComponentProps<"h3">) => (
|
||||
<h3
|
||||
className={cn(
|
||||
"mt-12 scroll-m-28 font-heading text-lg font-medium tracking-tight [&+p]:mt-4! *:[code]:text-xl",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
h4: ({ className, ...props }: React.ComponentProps<"h4">) => (
|
||||
<h4
|
||||
className={cn(
|
||||
"mt-8 scroll-m-28 font-heading text-base font-medium tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
h5: ({ className, ...props }: React.ComponentProps<"h5">) => (
|
||||
<h5
|
||||
className={cn(
|
||||
"mt-8 scroll-m-28 text-base font-medium tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
h6: ({ className, ...props }: React.ComponentProps<"h6">) => (
|
||||
<h6
|
||||
className={cn(
|
||||
"mt-8 scroll-m-28 text-base font-medium tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
a: ({ className, ...props }: React.ComponentProps<"a">) => (
|
||||
<a
|
||||
className={cn("font-medium underline underline-offset-4", className)}
|
||||
|
||||
@@ -132,6 +132,12 @@ const nextConfig = {
|
||||
destination: "/create",
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: "/code/:path*",
|
||||
destination:
|
||||
"https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/:path*",
|
||||
permanent: false,
|
||||
},
|
||||
]
|
||||
},
|
||||
rewrites() {
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@faker-js/faker": "^10.1.0",
|
||||
"@formisch/react": "^0.4.4",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@hugeicons/core-free-icons": "^1.2.1",
|
||||
"@hugeicons/react": "^1.1.1",
|
||||
@@ -63,7 +64,7 @@
|
||||
"next": "16.1.6",
|
||||
"next-themes": "0.4.6",
|
||||
"nuqs": "^2.8.9",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss": "^8.5.10",
|
||||
"radix-ui": "^1.4.3",
|
||||
"react": "19.2.3",
|
||||
"react-day-picker": "^9.7.0",
|
||||
@@ -76,12 +77,13 @@
|
||||
"rehype-pretty-code": "^0.14.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"server-only": "^0.0.1",
|
||||
"shadcn": "4.5.0",
|
||||
"shadcn": "4.8.0",
|
||||
"shiki": "^1.10.1",
|
||||
"sonner": "^2.0.0",
|
||||
"swr": "^2.3.6",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
"ts-morph": "26.0.0",
|
||||
"valibot": "^1.4.0",
|
||||
"vaul": "1.1.2",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
@@ -103,6 +105,7 @@
|
||||
"tailwindcss": "^4",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^5",
|
||||
"typescript-eslint": "^8.46.2",
|
||||
"unist-builder": "3.0.0",
|
||||
"unist-util-visit": "^4.1.2"
|
||||
},
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
- [Forms Overview](https://ui.shadcn.com/docs/forms): Guide to building forms with shadcn/ui.
|
||||
- [React Hook Form](https://ui.shadcn.com/docs/forms/react-hook-form): Using shadcn/ui with React Hook Form.
|
||||
- [TanStack Form](https://ui.shadcn.com/docs/forms/tanstack-form): Using shadcn/ui with TanStack Form.
|
||||
- [Formisch](https://ui.shadcn.com/docs/forms/formisch): Using shadcn/ui with Formisch.
|
||||
- [Forms - Next.js](https://ui.shadcn.com/docs/forms/next): Building forms in Next.js with Server Actions.
|
||||
|
||||
## Advanced
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/accordion",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/accordion-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/accordion-example.tsx",
|
||||
"api": "https://www.radix-ui.com/primitives/docs/components/accordion.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/accordion",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/accordion.md"
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/alert",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/alert-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/alert-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,12 +59,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/alert-dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/alert-dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/alert-dialog-example.tsx",
|
||||
"api": "https://www.radix-ui.com/primitives/docs/components/alert-dialog.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert-dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/alert-dialog.md"
|
||||
}
|
||||
}
|
||||
@@ -83,12 +83,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/aspect-ratio",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/aspect-ratio-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/aspect-ratio-example.tsx",
|
||||
"api": "https://www.radix-ui.com/primitives/docs/components/aspect-ratio.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/aspect-ratio",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/aspect-ratio-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/aspect-ratio-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,12 +106,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/avatar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/avatar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/avatar-example.tsx",
|
||||
"api": "https://www.radix-ui.com/primitives/docs/components/avatar.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/avatar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/avatar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/avatar-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/avatar.md"
|
||||
}
|
||||
}
|
||||
@@ -130,11 +130,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/badge",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/badge-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/badge-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/badge",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/badge-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/badge-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,11 +152,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/breadcrumb",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/breadcrumb-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/breadcrumb-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/breadcrumb",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/breadcrumb-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/breadcrumb-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,11 +174,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/button",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/button-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/button-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/button",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/button-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/button-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,11 +197,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/button-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/button-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/button-group-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/button-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/button-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/button-group-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,12 +221,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/calendar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/calendar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/calendar-example.tsx",
|
||||
"api": "https://react-day-picker.js.org"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/calendar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/calendar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/calendar-example.tsx",
|
||||
"api": "https://react-day-picker.js.org"
|
||||
}
|
||||
}
|
||||
@@ -245,11 +245,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/card-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/card-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/card-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/card-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,12 +269,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/carousel",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/carousel-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/carousel-example.tsx",
|
||||
"api": "https://www.embla-carousel.com/get-started/react"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/carousel",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/carousel-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/carousel-example.tsx",
|
||||
"api": "https://www.embla-carousel.com/get-started/react"
|
||||
}
|
||||
}
|
||||
@@ -294,11 +294,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/chart",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/chart-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/chart-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/chart",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/chart-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/chart-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,12 +316,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/checkbox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/checkbox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/checkbox-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/checkbox.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/checkbox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/checkbox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/checkbox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/checkbox.md"
|
||||
}
|
||||
}
|
||||
@@ -340,12 +340,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/collapsible",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/collapsible-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/collapsible-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/collapsible.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/collapsible",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/collapsible-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/collapsible-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/collapsible.md"
|
||||
}
|
||||
}
|
||||
@@ -366,12 +366,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/combobox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/combobox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/combobox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/combobox"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/combobox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/combobox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/combobox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/combobox.md"
|
||||
}
|
||||
}
|
||||
@@ -392,12 +392,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/command",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/command-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/command-example.tsx",
|
||||
"api": "https://github.com/dip/cmdk"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/command",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/command-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/command-example.tsx",
|
||||
"api": "https://github.com/dip/cmdk"
|
||||
}
|
||||
}
|
||||
@@ -416,12 +416,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/context-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/context-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/context-menu-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/context-menu.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/context-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/context-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/context-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/context-menu.md"
|
||||
}
|
||||
}
|
||||
@@ -441,12 +441,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/dialog-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/dialog.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/dialog.md"
|
||||
}
|
||||
}
|
||||
@@ -488,12 +488,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/drawer",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/drawer-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/drawer-example.tsx",
|
||||
"api": "https://vaul.emilkowal.ski/getting-started"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/drawer",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/drawer-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/drawer-example.tsx",
|
||||
"api": "https://vaul.emilkowal.ski/getting-started"
|
||||
}
|
||||
}
|
||||
@@ -512,12 +512,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/dropdown-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/dropdown-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/dropdown-menu-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/dropdown-menu.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/dropdown-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/dropdown-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/dropdown-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/menu.md"
|
||||
}
|
||||
}
|
||||
@@ -536,11 +536,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/empty",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/empty-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/empty-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/empty",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/empty-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/empty-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -559,11 +559,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/field",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/field-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/field-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/field",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/field-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/field-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -585,12 +585,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/hover-card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/hover-card-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/hover-card-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/hover-card.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/hover-card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/hover-card-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/hover-card-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/hover-card.md"
|
||||
}
|
||||
}
|
||||
@@ -609,11 +609,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/input",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/input-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/input-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -632,11 +632,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/input-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/input-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/input-group-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-group-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,12 +655,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/input-otp",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/input-otp-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/input-otp-example.tsx",
|
||||
"api": "https://input-otp.rodz.dev"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input-otp",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-otp-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-otp-example.tsx",
|
||||
"api": "https://input-otp.rodz.dev"
|
||||
}
|
||||
}
|
||||
@@ -680,11 +680,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/item",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/item-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/item-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/item",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/item-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/item-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -702,11 +702,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/kbd",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/kbd-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/kbd-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/kbd",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/kbd-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/kbd-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -724,12 +724,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/label",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/label-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/label-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/label.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/label",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/label-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/label-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/label.md"
|
||||
}
|
||||
}
|
||||
@@ -748,12 +748,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/menubar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/menubar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/menubar-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/menubar.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/menubar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/menubar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/menubar-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/menubar.md"
|
||||
}
|
||||
}
|
||||
@@ -772,11 +772,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/native-select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/native-select-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/native-select-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/native-select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/native-select-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/native-select-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,12 +794,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/navigation-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/navigation-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/navigation-menu-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/navigation-menu.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/navigation-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/navigation-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/navigation-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/navigation-menu.md"
|
||||
}
|
||||
}
|
||||
@@ -819,11 +819,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/pagination",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/pagination-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/pagination-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/pagination",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/pagination-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/pagination-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -841,12 +841,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/popover",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/popover-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/popover-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/popover.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/popover",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/popover-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/popover-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/popover.md"
|
||||
}
|
||||
}
|
||||
@@ -865,12 +865,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/progress",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/progress-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/progress-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/progress.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/progress",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/progress-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/progress-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/progress.md"
|
||||
}
|
||||
}
|
||||
@@ -889,12 +889,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/radio-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/radio-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/radio-group-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/radio-group.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/radio-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/radio-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/radio-group-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/radio-group.md"
|
||||
}
|
||||
}
|
||||
@@ -914,12 +914,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/resizable",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/resizable-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/resizable-example.tsx",
|
||||
"api": "https://github.com/bvaughn/react-resizable-panels"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/resizable",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/resizable-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/resizable-example.tsx",
|
||||
"api": "https://github.com/bvaughn/react-resizable-panels"
|
||||
}
|
||||
}
|
||||
@@ -938,12 +938,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/scroll-area",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/scroll-area-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/scroll-area-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/scroll-area.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/scroll-area",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/scroll-area-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/scroll-area-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/scroll-area.md"
|
||||
}
|
||||
}
|
||||
@@ -962,12 +962,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/select-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/select-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/select.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/select-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/select-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/select.md"
|
||||
}
|
||||
}
|
||||
@@ -986,12 +986,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/separator",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/separator-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/separator-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/separator.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/separator",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/separator-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/separator-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/separator.md"
|
||||
}
|
||||
}
|
||||
@@ -1011,12 +1011,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/sheet",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/sheet-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/sheet-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/dialog.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sheet",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sheet-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sheet-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/dialog.md"
|
||||
}
|
||||
}
|
||||
@@ -1044,11 +1044,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/sidebar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/sidebar-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/sidebar-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sidebar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sidebar-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sidebar-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1066,11 +1066,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/skeleton",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/skeleton-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/skeleton-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/skeleton",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/skeleton-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/skeleton-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1088,12 +1088,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/slider",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/slider-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/slider-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/slider.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/slider",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/slider-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/slider-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/slider.md"
|
||||
}
|
||||
}
|
||||
@@ -1113,12 +1113,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/sonner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/sonner-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/sonner-example.tsx",
|
||||
"api": "https://sonner.emilkowal.ski"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sonner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sonner-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sonner-example.tsx",
|
||||
"api": "https://sonner.emilkowal.ski"
|
||||
}
|
||||
}
|
||||
@@ -1137,11 +1137,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/spinner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/spinner-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/spinner-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/spinner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/spinner-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/spinner-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1159,12 +1159,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/switch",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/switch-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/switch-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/switch.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/switch",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/switch-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/switch-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/switch.md"
|
||||
}
|
||||
}
|
||||
@@ -1183,11 +1183,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/table",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/table-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/table-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/table",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/table-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/table-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1205,12 +1205,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/tabs",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/tabs-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/tabs-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/tabs.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/tabs",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/tabs-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/tabs-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/tabs.md"
|
||||
}
|
||||
}
|
||||
@@ -1229,11 +1229,11 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/textarea",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/textarea-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/textarea-example.tsx"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/textarea",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/textarea-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/textarea-example.tsx"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1251,12 +1251,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/toggle",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/toggle-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/toggle-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/toggle.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/toggle",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/toggle-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/toggle-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/toggle.md"
|
||||
}
|
||||
}
|
||||
@@ -1276,12 +1276,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/toggle-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/toggle-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/toggle-group-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/toggle-group.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/toggle-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/toggle-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/toggle-group-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/toggle-group.md"
|
||||
}
|
||||
}
|
||||
@@ -1301,12 +1301,12 @@
|
||||
"links": {
|
||||
"radix": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/radix/tooltip",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/radix/examples/tooltip-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/radix/examples/tooltip-example.tsx",
|
||||
"api": "https://www.radix-ui.com/docs/primitives/components/tooltip.md"
|
||||
},
|
||||
"base": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/tooltip",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/tooltip-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/tooltip-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/tooltip.md"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,12 @@
|
||||
"url": "https://aliimam.in/r/{name}.json",
|
||||
"description": "I create digital experiences that connect and inspire. I build apps, websites, brands, and products end-to-end."
|
||||
},
|
||||
{
|
||||
"name": "@amplo",
|
||||
"homepage": "https://amplo.ale.design",
|
||||
"url": "https://amplo.ale.design/r/{name}.json",
|
||||
"description": "OKLCH-native, Display-P3-aware composable fill picker with WCAG/APCA contrast metrics, gamut detection, and full keyboard accessibility."
|
||||
},
|
||||
{
|
||||
"name": "@animate-ui",
|
||||
"homepage": "https://animate-ui.com",
|
||||
@@ -131,6 +137,12 @@
|
||||
"url": "https://boldkit.dev/r/{name}.json",
|
||||
"description": "Neubrutalism component library with 43 components, 42 SVG shapes, thick borders, and hard shadows. Supports React, Vue, and Nuxt. Built on shadcn/ui."
|
||||
},
|
||||
{
|
||||
"name": "@bklit",
|
||||
"homepage": "https://ui.bklit.com",
|
||||
"url": "https://ui.bklit.com/r/{name}.json",
|
||||
"description": "Open-source composable chart components for React — line, area, bar, pie, radar, maps, and more. Built with Visx, Motion, and shadcn/ui."
|
||||
},
|
||||
{
|
||||
"name": "@bundui",
|
||||
"homepage": "https://bundui.io",
|
||||
@@ -161,12 +173,24 @@
|
||||
"url": "https://coderabbit-shadcn-registry.vercel.app/r/{name}.json",
|
||||
"description": "A framework-agnostic API client, pluggable storage adapters (LocalStorage, Convex, Supabase, PostgreSQL, MySQL), and React components for generating developer activity reports."
|
||||
},
|
||||
{
|
||||
"name": "@cognicatch",
|
||||
"homepage": "https://cognicatch.dev",
|
||||
"url": "https://cognicatch.dev/registry/{name}.json",
|
||||
"description": "Adaptive Error Boundaries and graceful fallback UIs (Banners, Modals, Toasts)."
|
||||
},
|
||||
{
|
||||
"name": "@commercn",
|
||||
"homepage": "https://commercn.com",
|
||||
"url": "https://commercn.com/r/{name}.json",
|
||||
"description": "Shadcn UI Blocks for Ecommerce websites"
|
||||
},
|
||||
{
|
||||
"name": "@corr",
|
||||
"homepage": "https://ui.corr.sh",
|
||||
"url": "https://ui.corr.sh/r/{name}.json",
|
||||
"description": "A collection of shadcn-based React components, charts, animated components, and blocks built over time."
|
||||
},
|
||||
{
|
||||
"name": "@coss",
|
||||
"homepage": "https://coss.com/ui",
|
||||
@@ -233,6 +257,12 @@
|
||||
"url": "https://eldoraui.site/r/{name}.json",
|
||||
"description": "An open-source, modern UI component library for React, built with TypeScript, Tailwind CSS, and Framer Motion. Eldora UI offers beautifully crafted, reusable components designed for performance and elegance."
|
||||
},
|
||||
{
|
||||
"name": "@evilcharts",
|
||||
"homepage": "https://evilcharts.com",
|
||||
"url": "https://evilcharts.com/r/{name}.json",
|
||||
"description": "EvilCharts is an open-source chart UI website built with shadcn and Recharts, beautifully designed and handcrafted."
|
||||
},
|
||||
{
|
||||
"name": "@formcn",
|
||||
"homepage": "https://formcn.dev",
|
||||
@@ -269,6 +299,18 @@
|
||||
"url": "https://glass-ui.crenspire.com/r/{name}.json",
|
||||
"description": "A shadcn-ui compatible registry distributing 40+ glassmorphic React/TypeScript components with Apple-inspired design. Components include enhanced visual effects (glow, shimmer, ripple), theme support, and customizable glassmorphism styling."
|
||||
},
|
||||
{
|
||||
"name": "@glasscn",
|
||||
"homepage": "https://glasscn-components.vercel.app/",
|
||||
"url": "https://glasscn-components.vercel.app/r/{name}.json",
|
||||
"description": "A shadcn-compatible registry of glassmorphism components inspired by Apple"
|
||||
},
|
||||
{
|
||||
"name": "@gymnopedies",
|
||||
"homepage": "https://gymnopedies.shoota.work",
|
||||
"url": "https://gymnopedies.shoota.work/r/{name}.json",
|
||||
"description": "A dark, serif, glow-leaning shadcn registry of read-only components for blogs, essays, and long-form reading experiences — inspired by the quiet, candlelit cabaret of Erik Satie's Gymnopédies."
|
||||
},
|
||||
{
|
||||
"name": "@ha-components",
|
||||
"homepage": "https://hacomponents.keshuac.com",
|
||||
@@ -293,6 +335,12 @@
|
||||
"url": "https://ui.inference.sh/r/{name}.json",
|
||||
"description": "batteries-included agent components by inference.sh. chat interfaces with streaming, tool invocation rendering, syntax-highlighted code blocks, markdown renderer, and more."
|
||||
},
|
||||
{
|
||||
"name": "@indiacn",
|
||||
"homepage": "https://indiacn.in",
|
||||
"url": "https://indiacn.in/r/{name}.json",
|
||||
"description": "UX4G 2.0 design system for India — many accessible React components and an 8-color theme preset for native apps."
|
||||
},
|
||||
{
|
||||
"name": "@intentui",
|
||||
"homepage": "https://intentui.com",
|
||||
@@ -407,11 +455,17 @@
|
||||
"url": "https://motion-primitives.com/c/{name}.json",
|
||||
"description": "Beautifully designed motions components. Easy copy-paste. Customizable. Open Source. Built for engineers and designers."
|
||||
},
|
||||
{
|
||||
"name": "@nordaun",
|
||||
"homepage": "https://ui.nordaun.com",
|
||||
"url": "https://ui.nordaun.com/r/{name}.json",
|
||||
"description": "Simple components for your extraordinary creations."
|
||||
},
|
||||
{
|
||||
"name": "@ncdai",
|
||||
"homepage": "https://chanhdai.com/components",
|
||||
"url": "https://chanhdai.com/r/{name}.json",
|
||||
"description": "A collection of reusable components."
|
||||
"description": "Pixel-perfect, uniquely crafted."
|
||||
},
|
||||
{
|
||||
"name": "@nteract",
|
||||
@@ -473,6 +527,12 @@
|
||||
"url": "https://gsap.pacekit.dev/r/{name}.json",
|
||||
"description": "Animated GSAP components crafted for smooth interaction and rich detail."
|
||||
},
|
||||
{
|
||||
"name": "@paddle",
|
||||
"homepage": "https://developer.paddle.com/",
|
||||
"url": "https://developer.paddle.com/r/{name}.json",
|
||||
"description": "Drop-in components for building checkouts, pricing pages, and subscription management screens using Paddle Billing."
|
||||
},
|
||||
{
|
||||
"name": "@pastecn",
|
||||
"homepage": "https://pastecn.com",
|
||||
@@ -719,6 +779,12 @@
|
||||
"url": "https://onboarding-tour.vercel.app/r/{name}.json",
|
||||
"description": "A component for building onboarding tours. Designed to integrate with shadcn/ui."
|
||||
},
|
||||
{
|
||||
"name": "@trophy-ui",
|
||||
"homepage": "https://ui.trophy.so",
|
||||
"url": "https://ui.trophy.so/r/{name}.json",
|
||||
"description": "Open-source gamification UI components for streaks, achievements, leaderboards, points, and more. Built on shadcn/ui and Tailwind CSS."
|
||||
},
|
||||
{
|
||||
"name": "@uitripled",
|
||||
"homepage": "https://ui.tripled.work",
|
||||
@@ -833,6 +899,12 @@
|
||||
"url": "https://darshitdev.in/r/{name}.json",
|
||||
"description": "Magic 3D Tabs component featuring mouse-interactive 3D rotation, floating particles background effect, and smooth spring animations."
|
||||
},
|
||||
{
|
||||
"name": "@devl",
|
||||
"homepage": "https://devl.dev",
|
||||
"url": "https://devl.dev/r/{name}.json",
|
||||
"description": "Hand-crafted layouts and UI primitives for shipping fast."
|
||||
},
|
||||
{
|
||||
"name": "@beste-ui",
|
||||
"homepage": "https://ui.beste.co",
|
||||
@@ -1054,5 +1126,65 @@
|
||||
"homepage": "https://ui.radiumcoders.com",
|
||||
"url": "https://ui.radiumcoders.com/r/xcn/{name}.json",
|
||||
"description": "Hand-crafted, beautiful, and minimal UI components built with Tailwind CSS and Motion."
|
||||
},
|
||||
{
|
||||
"name": "@dotmatrix",
|
||||
"homepage": "https://dotmatrix.zzzzshawn.cloud",
|
||||
"url": "https://dotmatrix.zzzzshawn.cloud/r/{name}.json",
|
||||
"description": "Production-ready dot-matrix loading components for React, featuring square, circular, and triangle animations with polished motion."
|
||||
},
|
||||
{
|
||||
"name": "@delta",
|
||||
"homepage": "https://deltacomponents.dev",
|
||||
"url": "https://deltacomponents.dev/r/{name}.json",
|
||||
"description": "A shadcn registry for AI and media-rich interfaces — streaming LLM chat, zoomable images, swipeable card decks, interactive maps, plus dashboard and landing-page blocks."
|
||||
},
|
||||
{
|
||||
"name": "@shieldcn",
|
||||
"homepage": "https://shieldcn.dev",
|
||||
"url": "https://shieldcn.dev/r/{name}.json",
|
||||
"description": "Beautiful README badges as a service. A shields.io alternative with the visual quality of shadcn/ui. Drop-in SVG badge components for npm, GitHub, Discord, and more."
|
||||
},
|
||||
{
|
||||
"name": "@evilbuttons",
|
||||
"homepage": "https://evilbuttons.radiumcoders.com/docs",
|
||||
"url": "https://evilbuttons.radiumcoders.com/r/{name}.json",
|
||||
"description": "A shadcn/ui registry featuring a collection of animated buttons built with Motion. Each component is designed to add punchy, interactive feedback to your UI with minimal setup."
|
||||
},
|
||||
{
|
||||
"name": "@stepper",
|
||||
"homepage": "https://francozeta-stepper.vercel.app",
|
||||
"url": "https://francozeta-stepper.vercel.app/{name}.json",
|
||||
"description": "A modern, accessible and composable Stepper component for React and Tailwind CSS. Built for shadcn/ui-style workflows with registry-first distribution."
|
||||
},
|
||||
{
|
||||
"name": "@text-ui",
|
||||
"homepage": "https://joelachance.github.io/text-ui/docs",
|
||||
"url": "https://joelachance.github.io/text-ui/r/{name}.json",
|
||||
"description": "A shadcn/ui registry with EchoText (`echo-text`): layered stroke text that follows the pointer—minimal setup, drop-in component."
|
||||
},
|
||||
{
|
||||
"name": "@framecn",
|
||||
"homepage": "https://framecn.vercel.app",
|
||||
"url": "https://framecn.vercel.app/r/{name}.json",
|
||||
"description": "Beautiful videos, made simple. Ready to use, customizable video components for React."
|
||||
},
|
||||
{
|
||||
"name": "@turbopills-ui",
|
||||
"homepage": "https://www.turbopills.com/ui/docs",
|
||||
"url": "https://ui.turbopills.com/r/{name}.json",
|
||||
"description": "Beautiful, accessible, and customizable React components for your telehealth applications."
|
||||
},
|
||||
{
|
||||
"name": "@nexus-labs",
|
||||
"homepage": "https://nexus-ui.com",
|
||||
"url": "https://nexus-ui.com/r/{name}.json",
|
||||
"description": "Motion-native animated components for Next.js — backgrounds, heroes, inputs, carousels, and more. Open source. Copy-ready TypeScript."
|
||||
},
|
||||
{
|
||||
"name": "@wensity",
|
||||
"homepage": "https://wensity.com",
|
||||
"url": "https://raw.githubusercontent.com/ksparth12/wensity-shadcn-registry/main/{name}.json",
|
||||
"description": "Motion-rich React components for AI interfaces, SaaS blocks, and cinematic interactions. Free Wensity components only."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/accordion",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/accordion.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert-dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/alert-dialog.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/aspect-ratio",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/aspect-ratio-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/aspect-ratio-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/avatar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/avatar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/avatar-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/avatar.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/badge",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/badge-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/badge-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/breadcrumb",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/breadcrumb-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/breadcrumb-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/button-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/button-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/button-group-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/button",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/button-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/button-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/calendar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/calendar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/calendar-example.tsx",
|
||||
"api": "https://react-day-picker.js.org"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/card-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/card-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/carousel",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/carousel-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/carousel-example.tsx",
|
||||
"api": "https://www.embla-carousel.com/get-started/react"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/chart",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/chart-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/chart-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/checkbox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/checkbox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/checkbox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/checkbox.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/collapsible",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/collapsible-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/collapsible-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/collapsible.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/combobox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/combobox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/combobox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/combobox.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/command",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/command-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/command-example.tsx",
|
||||
"api": "https://github.com/dip/cmdk"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/context-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/context-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/context-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/context-menu.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/dialog.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/drawer",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/drawer-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/drawer-example.tsx",
|
||||
"api": "https://vaul.emilkowal.ski/getting-started"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/dropdown-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/dropdown-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/dropdown-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/menu.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/empty",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/empty-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/empty-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/field",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/field-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/field-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/hover-card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/hover-card-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/hover-card-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/hover-card.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-group-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input-otp",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-otp-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-otp-example.tsx",
|
||||
"api": "https://input-otp.rodz.dev"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/item",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/item-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/item-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/kbd",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/kbd-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/kbd-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/label",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/label-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/label-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/label.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/menubar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/menubar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/menubar-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/menubar.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/native-select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/native-select-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/native-select-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/navigation-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/navigation-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/navigation-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/navigation-menu.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/pagination",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/pagination-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/pagination-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/popover",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/popover-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/popover-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/popover.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/progress",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/progress-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/progress-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/progress.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/radio-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/radio-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/radio-group-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/radio-group.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/accordion",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/accordion.md"
|
||||
}
|
||||
},
|
||||
@@ -80,7 +80,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -97,7 +97,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert-dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/alert-dialog.md"
|
||||
}
|
||||
},
|
||||
@@ -114,7 +114,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/aspect-ratio",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/aspect-ratio-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/aspect-ratio-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -130,7 +130,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/avatar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/avatar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/avatar-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/avatar.md"
|
||||
}
|
||||
},
|
||||
@@ -147,7 +147,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/badge",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/badge-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/badge-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -163,7 +163,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/breadcrumb",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/breadcrumb-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/breadcrumb-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -179,7 +179,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/button",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/button-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/button-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -196,7 +196,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/button-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/button-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/button-group-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -214,7 +214,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/calendar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/calendar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/calendar-example.tsx",
|
||||
"api": "https://react-day-picker.js.org"
|
||||
}
|
||||
},
|
||||
@@ -231,7 +231,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/card-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/card-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -249,7 +249,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/carousel",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/carousel-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/carousel-example.tsx",
|
||||
"api": "https://www.embla-carousel.com/get-started/react"
|
||||
}
|
||||
},
|
||||
@@ -268,7 +268,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/chart",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/chart-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/chart-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -284,7 +284,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/checkbox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/checkbox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/checkbox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/checkbox.md"
|
||||
}
|
||||
},
|
||||
@@ -301,7 +301,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/collapsible",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/collapsible-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/collapsible-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/collapsible.md"
|
||||
}
|
||||
},
|
||||
@@ -320,7 +320,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/combobox",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/combobox-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/combobox-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/combobox.md"
|
||||
}
|
||||
},
|
||||
@@ -339,7 +339,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/command",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/command-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/command-example.tsx",
|
||||
"api": "https://github.com/dip/cmdk"
|
||||
}
|
||||
},
|
||||
@@ -356,7 +356,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/context-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/context-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/context-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/context-menu.md"
|
||||
}
|
||||
},
|
||||
@@ -374,7 +374,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/dialog.md"
|
||||
}
|
||||
},
|
||||
@@ -392,7 +392,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/drawer",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/drawer-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/drawer-example.tsx",
|
||||
"api": "https://vaul.emilkowal.ski/getting-started"
|
||||
}
|
||||
},
|
||||
@@ -409,7 +409,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/dropdown-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/dropdown-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/dropdown-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/menu.md"
|
||||
}
|
||||
},
|
||||
@@ -426,7 +426,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/empty",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/empty-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/empty-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -443,7 +443,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/field",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/field-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/field-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -463,7 +463,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/hover-card",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/hover-card-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/hover-card-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/hover-card.md"
|
||||
}
|
||||
},
|
||||
@@ -480,7 +480,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -497,7 +497,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-group-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-group-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -514,7 +514,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/input-otp",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/input-otp-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/input-otp-example.tsx",
|
||||
"api": "https://input-otp.rodz.dev"
|
||||
}
|
||||
},
|
||||
@@ -532,7 +532,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/item",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/item-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/item-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -548,7 +548,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/label",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/label-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/label-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/label.md"
|
||||
}
|
||||
},
|
||||
@@ -566,7 +566,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/menubar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/menubar-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/menubar-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/menubar.md"
|
||||
}
|
||||
},
|
||||
@@ -583,7 +583,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/navigation-menu",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/navigation-menu-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/navigation-menu-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/navigation-menu.md"
|
||||
}
|
||||
},
|
||||
@@ -601,7 +601,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/pagination",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/pagination-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/pagination-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -617,7 +617,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/popover",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/popover-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/popover-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/popover.md"
|
||||
}
|
||||
},
|
||||
@@ -634,7 +634,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/progress",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/progress-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/progress-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/progress.md"
|
||||
}
|
||||
},
|
||||
@@ -651,7 +651,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/radio-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/radio-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/radio-group-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/radio-group.md"
|
||||
}
|
||||
},
|
||||
@@ -669,7 +669,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/resizable",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/resizable-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/resizable-example.tsx",
|
||||
"api": "https://github.com/bvaughn/react-resizable-panels"
|
||||
}
|
||||
},
|
||||
@@ -686,7 +686,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/scroll-area",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/scroll-area-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/scroll-area-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/scroll-area.md"
|
||||
}
|
||||
},
|
||||
@@ -703,7 +703,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/select-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/select-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/select.md"
|
||||
}
|
||||
},
|
||||
@@ -720,7 +720,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/separator",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/separator-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/separator-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/separator.md"
|
||||
}
|
||||
},
|
||||
@@ -738,7 +738,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sheet",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sheet-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sheet-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/dialog.md"
|
||||
}
|
||||
},
|
||||
@@ -764,7 +764,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sidebar",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sidebar-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sidebar-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -780,7 +780,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/skeleton",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/skeleton-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/skeleton-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -796,7 +796,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/slider",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/slider-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/slider-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/slider.md"
|
||||
}
|
||||
},
|
||||
@@ -814,7 +814,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sonner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sonner-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sonner-example.tsx",
|
||||
"api": "https://sonner.emilkowal.ski"
|
||||
}
|
||||
},
|
||||
@@ -831,7 +831,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/spinner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/spinner-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/spinner-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -847,7 +847,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/switch",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/switch-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/switch-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/switch.md"
|
||||
}
|
||||
},
|
||||
@@ -864,7 +864,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/table",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/table-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/table-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -880,7 +880,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/tabs",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/tabs-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/tabs-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/tabs.md"
|
||||
}
|
||||
},
|
||||
@@ -897,7 +897,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/textarea",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/textarea-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/textarea-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -913,7 +913,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/toggle",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/toggle-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/toggle-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/toggle.md"
|
||||
}
|
||||
},
|
||||
@@ -931,7 +931,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/toggle-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/toggle-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/toggle-group-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/toggle-group.md"
|
||||
}
|
||||
},
|
||||
@@ -948,7 +948,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/tooltip",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/tooltip-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/tooltip-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/tooltip.md"
|
||||
}
|
||||
},
|
||||
@@ -966,7 +966,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/kbd",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/kbd-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/kbd-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
@@ -982,7 +982,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/native-select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/native-select-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/native-select-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/resizable",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/resizable-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/resizable-example.tsx",
|
||||
"api": "https://github.com/bvaughn/react-resizable-panels"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/scroll-area",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/scroll-area-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/scroll-area-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/scroll-area.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/select",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/select-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/select-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/select.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/separator",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/separator-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/separator-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/separator.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sheet",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sheet-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sheet-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/dialog.md"
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/skeleton",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/skeleton-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/skeleton-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/slider",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/slider-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/slider-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/slider.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/sonner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/sonner-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/sonner-example.tsx",
|
||||
"api": "https://sonner.emilkowal.ski"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/spinner",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/spinner-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/spinner-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/switch",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/switch-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/switch-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/switch.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/table",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/table-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/table-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/tabs",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/tabs-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/tabs-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/tabs.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/textarea",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/textarea-example.tsx"
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/textarea-example.tsx"
|
||||
}
|
||||
},
|
||||
"type": "registry:ui"
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-luma/ui/toggle-group.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Toggle as TogglePrimitive } from \"@base-ui/react/toggle\"\nimport { ToggleGroup as ToggleGroupPrimitive } from \"@base-ui/react/toggle-group\"\nimport { type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\nimport { toggleVariants } from \"@/registry/base-luma/ui/toggle\"\n\nconst ToggleGroupContext = React.createContext<\n VariantProps<typeof toggleVariants> & {\n spacing?: number\n orientation?: \"horizontal\" | \"vertical\"\n }\n>({\n size: \"default\",\n variant: \"default\",\n spacing: 0,\n orientation: \"horizontal\",\n})\n\nfunction ToggleGroup({\n className,\n variant,\n size,\n spacing = 0,\n orientation = \"horizontal\",\n children,\n ...props\n}: ToggleGroupPrimitive.Props &\n VariantProps<typeof toggleVariants> & {\n spacing?: number\n orientation?: \"horizontal\" | \"vertical\"\n }) {\n return (\n <ToggleGroupPrimitive\n data-slot=\"toggle-group\"\n data-variant={variant}\n data-size={size}\n data-spacing={spacing}\n data-orientation={orientation}\n style={{ \"--gap\": spacing } as React.CSSProperties}\n className={cn(\n \"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] data-[spacing=0]:data-[variant=outline]:rounded-3xl data-vertical:flex-col data-vertical:items-stretch\",\n className\n )}\n {...props}\n >\n <ToggleGroupContext.Provider\n value={{ variant, size, spacing, orientation }}\n >\n {children}\n </ToggleGroupContext.Provider>\n </ToggleGroupPrimitive>\n )\n}\n\nfunction ToggleGroupItem({\n className,\n children,\n variant = \"default\",\n size = \"default\",\n ...props\n}: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {\n const context = React.useContext(ToggleGroupContext)\n\n return (\n <TogglePrimitive\n data-slot=\"toggle-group-item\"\n data-variant={context.variant || variant}\n data-size={context.size || size}\n data-spacing={context.spacing}\n className={cn(\n \"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-3 group-data-[spacing=0]/toggle-group:shadow-none focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-2.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-2.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-3xl group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-3xl group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-3xl group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-3xl data-[state=on]:bg-muted group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t\",\n toggleVariants({\n variant: context.variant || variant,\n size: context.size || size,\n }),\n className\n )}\n {...props}\n >\n {children}\n </TogglePrimitive>\n )\n}\n\nexport { ToggleGroup, ToggleGroupItem }\n",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Toggle as TogglePrimitive } from \"@base-ui/react/toggle\"\nimport { ToggleGroup as ToggleGroupPrimitive } from \"@base-ui/react/toggle-group\"\nimport { type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\nimport { toggleVariants } from \"@/registry/base-luma/ui/toggle\"\n\nconst ToggleGroupContext = React.createContext<\n VariantProps<typeof toggleVariants> & {\n spacing?: number\n orientation?: \"horizontal\" | \"vertical\"\n }\n>({\n size: \"default\",\n variant: \"default\",\n spacing: 2,\n orientation: \"horizontal\",\n})\n\nfunction ToggleGroup({\n className,\n variant,\n size,\n spacing = 2,\n orientation = \"horizontal\",\n children,\n ...props\n}: ToggleGroupPrimitive.Props &\n VariantProps<typeof toggleVariants> & {\n spacing?: number\n orientation?: \"horizontal\" | \"vertical\"\n }) {\n return (\n <ToggleGroupPrimitive\n data-slot=\"toggle-group\"\n data-variant={variant}\n data-size={size}\n data-spacing={spacing}\n data-orientation={orientation}\n style={{ \"--gap\": spacing } as React.CSSProperties}\n className={cn(\n \"group/toggle-group flex w-fit flex-row items-center gap-[--spacing(var(--gap))] data-[spacing=0]:data-[variant=outline]:rounded-3xl data-vertical:flex-col data-vertical:items-stretch\",\n className\n )}\n {...props}\n >\n <ToggleGroupContext.Provider\n value={{ variant, size, spacing, orientation }}\n >\n {children}\n </ToggleGroupContext.Provider>\n </ToggleGroupPrimitive>\n )\n}\n\nfunction ToggleGroupItem({\n className,\n children,\n variant = \"default\",\n size = \"default\",\n ...props\n}: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {\n const context = React.useContext(ToggleGroupContext)\n\n return (\n <TogglePrimitive\n data-slot=\"toggle-group-item\"\n data-variant={context.variant || variant}\n data-size={context.size || size}\n data-spacing={context.spacing}\n className={cn(\n \"shrink-0 group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:px-3 group-data-[spacing=0]/toggle-group:shadow-none focus:z-10 focus-visible:z-10 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-2.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-2.5 group-data-horizontal/toggle-group:data-[spacing=0]:first:rounded-l-3xl group-data-vertical/toggle-group:data-[spacing=0]:first:rounded-t-3xl group-data-horizontal/toggle-group:data-[spacing=0]:last:rounded-r-3xl group-data-vertical/toggle-group:data-[spacing=0]:last:rounded-b-3xl data-[state=on]:bg-muted group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-horizontal/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-vertical/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t\",\n toggleVariants({\n variant: context.variant || variant,\n size: context.size || size,\n }),\n className\n )}\n {...props}\n >\n {children}\n </TogglePrimitive>\n )\n}\n\nexport { ToggleGroup, ToggleGroupItem }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/toggle-group",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/toggle-group-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/toggle-group-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/toggle-group.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/toggle",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/toggle-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/toggle-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/toggle.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/tooltip",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/tooltip-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/tooltip-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/tooltip.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/accordion",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/accordion-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/accordion.md"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"meta": {
|
||||
"links": {
|
||||
"docs": "https://ui.shadcn.com/docs/components/base/alert-dialog",
|
||||
"examples": "https://raw.githubusercontent.com/shadcn-ui/ui/refs/heads/main/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"examples": "https://ui.shadcn.com/code/apps/v4/registry/bases/base/examples/alert-dialog-example.tsx",
|
||||
"api": "https://base-ui.com/react/components/alert-dialog.md"
|
||||
}
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user