mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-18 13:21:35 +00:00
Compare commits
73 Commits
shadcn@4.1
...
shadcn@4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d718a8045f | ||
|
|
2c4678c8c8 | ||
|
|
2466a300f4 | ||
|
|
66fcf1e853 | ||
|
|
5ebd54198d | ||
|
|
3a2d812510 | ||
|
|
7811557088 | ||
|
|
575f1602a1 | ||
|
|
ae70ecc2f3 | ||
|
|
42284f4e64 | ||
|
|
abc65a4871 | ||
|
|
7d5af61468 | ||
|
|
2badcdc31f | ||
|
|
64b8263450 | ||
|
|
13b4593f37 | ||
|
|
7dc65da6b2 | ||
|
|
98e56b773c | ||
|
|
7ff9778ff0 | ||
|
|
4af7bbf4ba | ||
|
|
f00a94d9e5 | ||
|
|
187ae44fa7 | ||
|
|
034178bf7d | ||
|
|
4064c78bc7 | ||
|
|
943b023b7c | ||
|
|
e3d654fd26 | ||
|
|
71d0470be1 | ||
|
|
53bbdc738f | ||
|
|
97707ec08e | ||
|
|
b9ce2f10c3 | ||
|
|
7cb3b13a33 | ||
|
|
e3d2b14911 | ||
|
|
58c9dc2a7e | ||
|
|
3bdf60340d | ||
|
|
c1e29824cd | ||
|
|
62f6df75f2 | ||
|
|
62bae86e86 | ||
|
|
aa69fbf85a | ||
|
|
8d41295f2c | ||
|
|
2b053d916d | ||
|
|
0d1309f322 | ||
|
|
c26250dcfe | ||
|
|
07c5c36be8 | ||
|
|
21c9cc5246 | ||
|
|
058960046a | ||
|
|
be80c18ea9 | ||
|
|
3c59a0cd95 | ||
|
|
26d0228ee9 | ||
|
|
9050646893 | ||
|
|
3ca09b9647 | ||
|
|
720ccca653 | ||
|
|
1e3dff8daa | ||
|
|
c116b325ab | ||
|
|
5b266d3fc9 | ||
|
|
6095e6272d | ||
|
|
f3fc5a62f2 | ||
|
|
ef7507cc9a | ||
|
|
16b7bea50d | ||
|
|
ccc4caad9c | ||
|
|
ba2c4fc586 | ||
|
|
bb5afb2df1 | ||
|
|
53f45f5f6f | ||
|
|
990040691c | ||
|
|
83857679cb | ||
|
|
61989da8ec | ||
|
|
768d8a808f | ||
|
|
95479a06bb | ||
|
|
4289d5fe02 | ||
|
|
5a6702845d | ||
|
|
a7c3300d7a | ||
|
|
b50acc9d21 | ||
|
|
2c334c3c2d | ||
|
|
0c25e712e1 | ||
|
|
4f421aba65 |
@@ -63,11 +63,7 @@ export default function IndexPage() {
|
||||
</Button>
|
||||
</PageActions>
|
||||
</PageHeader>
|
||||
<PageNav className="hidden md:flex">
|
||||
<ExamplesNav className="flex-1 overflow-hidden [&>a:first-child]:text-primary" />
|
||||
<ThemeSelector className="mr-4 hidden md:flex" />
|
||||
</PageNav>
|
||||
<div className="container-wrapper flex-1 section-soft pb-6">
|
||||
<div className="container-wrapper flex-1 pb-6">
|
||||
<div className="container overflow-hidden">
|
||||
<section className="-mx-4 w-[160vw] overflow-hidden rounded-lg border border-border/50 md:hidden md:w-[150vw]">
|
||||
<Image
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import dynamic from "next/dynamic"
|
||||
import { type RegistryItem } from "shadcn/schema"
|
||||
|
||||
import { useIsMobile } from "@/hooks/use-mobile"
|
||||
@@ -31,6 +32,13 @@ import { V0Button } from "@/app/(app)/create/components/v0-button"
|
||||
import { FONT_HEADING_OPTIONS, FONTS } from "@/app/(app)/create/lib/fonts"
|
||||
import { useDesignSystemSearchParams } from "@/app/(app)/create/lib/search-params"
|
||||
|
||||
// Only visible when user clicks "Create Project".
|
||||
const ProjectForm = dynamic(() =>
|
||||
import("@/app/(app)/create/components/project-form").then(
|
||||
(m) => m.ProjectForm
|
||||
)
|
||||
)
|
||||
|
||||
export function Customizer({
|
||||
itemsByBase,
|
||||
}: {
|
||||
@@ -93,12 +101,15 @@ export function Customizer({
|
||||
{isMobile && <BasePicker isMobile={isMobile} anchorRef={anchorRef} />}
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="flex min-w-0 gap-2 md:flex-col md:**:[button,a]:w-full">
|
||||
<CardFooter className="flex min-w-0 gap-2 md:flex-col md:rounded-b-none md:**:[button,a]:w-full">
|
||||
<CopyPreset className="flex-1 md:flex-none" />
|
||||
<RandomButton className="flex-1 md:flex-none" />
|
||||
<ActionMenu itemsByBase={itemsByBase} />
|
||||
<ResetDialog />
|
||||
</CardFooter>
|
||||
<CardFooter className="-mt-3 hidden min-w-0 gap-2 md:flex md:flex-col md:**:[button,a]:w-full">
|
||||
<ProjectForm />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation"
|
||||
import { Suspense } from "react"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
|
||||
type HistoryContextValue = {
|
||||
canGoBack: boolean
|
||||
@@ -12,12 +13,28 @@ type HistoryContextValue = {
|
||||
|
||||
const HistoryContext = React.createContext<HistoryContextValue | null>(null)
|
||||
|
||||
export function HistoryProvider({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
// Reads useSearchParams() in its own Suspense boundary so the
|
||||
// provider never blanks out children while search params resolve.
|
||||
function PresetSync({
|
||||
onPresetChange,
|
||||
}: {
|
||||
onPresetChange: (preset: string) => void
|
||||
}) {
|
||||
const searchParams = useSearchParams()
|
||||
const preset = searchParams.get("preset") ?? ""
|
||||
|
||||
React.useEffect(() => {
|
||||
onPresetChange(preset)
|
||||
}, [preset, onPresetChange])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export function HistoryProvider({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter()
|
||||
|
||||
const [preset, setPreset] = React.useState("")
|
||||
|
||||
const entriesRef = React.useRef<string[]>([preset])
|
||||
const indexRef = React.useRef(0)
|
||||
const maxIndexRef = React.useRef(0)
|
||||
@@ -26,6 +43,10 @@ export function HistoryProvider({ children }: { children: React.ReactNode }) {
|
||||
const [index, setIndex] = React.useState(0)
|
||||
const [maxIndex, setMaxIndex] = React.useState(0)
|
||||
|
||||
const onPresetChange = React.useCallback((nextPreset: string) => {
|
||||
setPreset(nextPreset)
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isNavigatingRef.current) {
|
||||
isNavigatingRef.current = false
|
||||
@@ -67,9 +88,10 @@ export function HistoryProvider({ children }: { children: React.ReactNode }) {
|
||||
} else {
|
||||
params.delete("preset")
|
||||
}
|
||||
const pathname = window.location.pathname
|
||||
const query = params.toString()
|
||||
router.replace(query ? `${pathname}?${query}` : pathname)
|
||||
}, [pathname, router])
|
||||
}, [router])
|
||||
|
||||
const goForward = React.useCallback(() => {
|
||||
if (indexRef.current >= maxIndexRef.current) {
|
||||
@@ -88,9 +110,10 @@ export function HistoryProvider({ children }: { children: React.ReactNode }) {
|
||||
} else {
|
||||
params.delete("preset")
|
||||
}
|
||||
const pathname = window.location.pathname
|
||||
const query = params.toString()
|
||||
router.replace(query ? `${pathname}?${query}` : pathname)
|
||||
}, [pathname, router])
|
||||
}, [router])
|
||||
|
||||
React.useEffect(() => {
|
||||
const down = (e: KeyboardEvent) => {
|
||||
@@ -133,7 +156,14 @@ export function HistoryProvider({ children }: { children: React.ReactNode }) {
|
||||
[canGoBack, canGoForward, goBack, goForward]
|
||||
)
|
||||
|
||||
return <HistoryContext value={value}>{children}</HistoryContext>
|
||||
return (
|
||||
<HistoryContext value={value}>
|
||||
<Suspense>
|
||||
<PresetSync onPresetChange={onPresetChange} />
|
||||
</Suspense>
|
||||
{children}
|
||||
</HistoryContext>
|
||||
)
|
||||
}
|
||||
|
||||
export function useHistory() {
|
||||
|
||||
@@ -24,10 +24,15 @@ const LocksContext = React.createContext<LocksContextValue | null>(null)
|
||||
|
||||
export function LocksProvider({ children }: { children: React.ReactNode }) {
|
||||
const [locks, setLocks] = React.useState<Set<LockableParam>>(new Set())
|
||||
const locksRef = React.useRef(locks)
|
||||
React.useEffect(() => {
|
||||
locksRef.current = locks
|
||||
}, [locks])
|
||||
|
||||
// Stable callback — reads from ref so it doesn't change on every lock toggle.
|
||||
const isLocked = React.useCallback(
|
||||
(param: LockableParam) => locks.has(param),
|
||||
[locks]
|
||||
(param: LockableParam) => locksRef.current.has(param),
|
||||
[]
|
||||
)
|
||||
|
||||
const toggleLock = React.useCallback((param: LockableParam) => {
|
||||
|
||||
@@ -41,7 +41,7 @@ import { getPresetCode } from "@/app/(app)/create/lib/preset-code"
|
||||
import { resolvePresetOverrides } from "@/app/(app)/create/lib/preset-query"
|
||||
|
||||
const designSystemSearchParams = {
|
||||
preset: parseAsString.withDefault("b2D0wqNxT"),
|
||||
preset: parseAsString.withDefault("b0"),
|
||||
base: parseAsStringLiteral<BaseName>(BASES.map((b) => b.name)).withDefault(
|
||||
DEFAULT_CONFIG.base
|
||||
),
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { Suspense } from "react"
|
||||
import { type Metadata } from "next"
|
||||
import dynamic from "next/dynamic"
|
||||
|
||||
import { siteConfig } from "@/lib/config"
|
||||
import { absoluteUrl } from "@/lib/utils"
|
||||
import { Skeleton } from "@/styles/base-nova/ui/skeleton"
|
||||
import { Customizer } from "@/app/(app)/create/components/customizer"
|
||||
import { PresetHandler } from "@/app/(app)/create/components/preset-handler"
|
||||
import { Preview } from "@/app/(app)/create/components/preview"
|
||||
import { WelcomeDialog } from "@/app/(app)/create/components/welcome-dialog"
|
||||
import { getAllItems } from "@/app/(app)/create/lib/api"
|
||||
|
||||
// Only shown on first visit (checks localStorage).
|
||||
const WelcomeDialog = dynamic(() =>
|
||||
import("@/app/(app)/create/components/welcome-dialog").then(
|
||||
(m) => m.WelcomeDialog
|
||||
)
|
||||
)
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "New Project",
|
||||
description:
|
||||
@@ -37,9 +46,7 @@ export const metadata: Metadata = {
|
||||
},
|
||||
}
|
||||
|
||||
export default async function CreatePage() {
|
||||
const itemsByBase = await getAllItems()
|
||||
|
||||
export default function CreatePage() {
|
||||
return (
|
||||
<div className="relative z-10 flex min-h-0 flex-1 flex-col overflow-hidden section-soft [--customizer-width:--spacing(48)] [--gap:--spacing(4)] md:[--gap:--spacing(6)] 2xl:[--customizer-width:--spacing(56)]">
|
||||
<div
|
||||
@@ -47,10 +54,21 @@ export default async function CreatePage() {
|
||||
className="flex min-h-0 flex-1 flex-col gap-(--gap) p-(--gap) pt-[calc(var(--gap)*0.25)] md:flex-row-reverse"
|
||||
>
|
||||
<Preview />
|
||||
<Customizer itemsByBase={itemsByBase} />
|
||||
<Suspense
|
||||
fallback={
|
||||
<Skeleton className="isolate min-h-[151px] w-full self-start rounded-2xl md:h-full md:max-h-full md:min-h-0 md:w-(--customizer-width)" />
|
||||
}
|
||||
>
|
||||
<CustomizerLoader />
|
||||
</Suspense>
|
||||
</div>
|
||||
<PresetHandler />
|
||||
<WelcomeDialog />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
async function CustomizerLoader() {
|
||||
const itemsByBase = await getAllItems()
|
||||
return <Customizer itemsByBase={itemsByBase} />
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import { Button } from "@/styles/radix-nova/ui/button"
|
||||
export const revalidate = false
|
||||
export const dynamic = "force-static"
|
||||
|
||||
const NUMBER_OF_LATEST_PAGES = 2
|
||||
|
||||
export function generateMetadata() {
|
||||
return {
|
||||
title: "Changelog",
|
||||
@@ -34,8 +36,8 @@ export function generateMetadata() {
|
||||
|
||||
export default function ChangelogPage() {
|
||||
const pages = getChangelogPages()
|
||||
const latestPages = pages.slice(0, 5)
|
||||
const olderPages = pages.slice(5)
|
||||
const latestPages = pages.slice(0, NUMBER_OF_LATEST_PAGES)
|
||||
const olderPages = pages.slice(NUMBER_OF_LATEST_PAGES)
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -44,7 +46,7 @@ export default function ChangelogPage() {
|
||||
>
|
||||
<div className="flex min-w-0 flex-1 flex-col">
|
||||
<div className="h-(--top-spacing) shrink-0" />
|
||||
<div className="mx-auto flex w-full max-w-[40rem] min-w-0 flex-1 flex-col gap-6 px-4 py-6 text-neutral-800 md:px-0 lg:py-8 dark:text-neutral-300">
|
||||
<div className="mx-auto flex w-full max-w-160 min-w-0 flex-1 flex-col gap-6 px-4 py-6 text-neutral-800 md:px-0 lg:py-8 dark:text-neutral-300">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="scroll-m-24 text-4xl font-semibold tracking-tight sm:text-3xl">
|
||||
|
||||
@@ -337,6 +337,44 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/*
|
||||
* ```text composition trees use box-drawing characters; per-line padding makes
|
||||
* vertical connectors look broken. rehype-pretty-code sets `data-language` on
|
||||
* `pre`/`code` (not `language-*` classes). It also sets `code { display: grid }`,
|
||||
* which can add visible row separation — reset to a normal pre stack for text.
|
||||
*/
|
||||
[data-rehype-pretty-code-figure] pre[data-language="text"] code,
|
||||
[data-rehype-pretty-code-figure] pre[data-language="plaintext"] code,
|
||||
[data-slot="docs"] pre[data-language="text"] code,
|
||||
[data-slot="docs"] pre[data-language="plaintext"] code {
|
||||
display: block !important;
|
||||
white-space: pre;
|
||||
line-height: 0.95;
|
||||
font-family:
|
||||
ui-monospace,
|
||||
SFMono-Regular,
|
||||
Menlo,
|
||||
Monaco,
|
||||
Consolas,
|
||||
"Liberation Mono",
|
||||
"Courier New",
|
||||
monospace;
|
||||
font-variant-ligatures: none;
|
||||
}
|
||||
|
||||
[data-rehype-pretty-code-figure] pre[data-language="text"] [data-line],
|
||||
[data-rehype-pretty-code-figure] pre[data-language="plaintext"] [data-line],
|
||||
[data-rehype-pretty-code-figure] code[data-language="text"] [data-line],
|
||||
[data-rehype-pretty-code-figure] code[data-language="plaintext"] [data-line],
|
||||
[data-slot="docs"] pre[data-language="text"] [data-line],
|
||||
[data-slot="docs"] pre[data-language="plaintext"] [data-line] {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
min-height: unset;
|
||||
line-height: 0.95;
|
||||
display: block;
|
||||
}
|
||||
|
||||
[data-line] span {
|
||||
color: var(--shiki-light);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Badge } from "@/registry/new-york-v4/ui/badge"
|
||||
export function Announcement() {
|
||||
return (
|
||||
<Badge asChild variant="secondary" className="bg-muted">
|
||||
<Link href="/create">
|
||||
<Link href="/docs/changelog">
|
||||
Introducing Luma <ArrowRightIcon />
|
||||
</Link>
|
||||
</Badge>
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Use the shadcn CLI to add components to your project.
|
||||
|
||||
## init
|
||||
|
||||
Use the `init` command to initialize configuration and dependencies for a new project.
|
||||
Use the `init` command to initialize configuration and dependencies for an existing project, or create a new project with `--name`.
|
||||
|
||||
The `init` command installs dependencies, adds the `cn` util and configures CSS variables for the project.
|
||||
|
||||
@@ -21,26 +21,26 @@ Usage: shadcn init [options] [components...]
|
||||
initialize your project and install dependencies
|
||||
|
||||
Arguments:
|
||||
components name, url or local path to component
|
||||
components names, url or local path to component
|
||||
|
||||
Options:
|
||||
-t, --template <template> the template to use. (next, vite, start, react-router, laravel, astro)
|
||||
-b, --base <base> the component library to use. (radix, base)
|
||||
-p, --preset [name] use a preset configuration. (name, URL, or preset code)
|
||||
-n, --name <name> the name for the new project.
|
||||
-d, --defaults use default configuration. (default: false)
|
||||
-p, --preset [name] use a preset configuration
|
||||
-y, --yes skip confirmation prompt. (default: true)
|
||||
-d, --defaults use default configuration: --template=next --preset=nova (default: false)
|
||||
-f, --force force overwrite of existing configuration. (default: false)
|
||||
-c, --cwd <cwd> the working directory. defaults to the current directory.
|
||||
-n, --name <name> the name for the new project.
|
||||
-s, --silent mute output. (default: false)
|
||||
--monorepo scaffold a monorepo project.
|
||||
--no-monorepo skip the monorepo prompt.
|
||||
--reinstall re-install existing UI components.
|
||||
--no-reinstall do not re-install existing UI components.
|
||||
--rtl enable RTL support.
|
||||
--no-rtl disable RTL support.
|
||||
--css-variables use css variables for theming. (default: true)
|
||||
--no-css-variables do not use css variables for theming.
|
||||
--monorepo scaffold a monorepo project.
|
||||
--no-monorepo skip the monorepo prompt.
|
||||
--rtl enable RTL support.
|
||||
--no-rtl disable RTL support.
|
||||
--reinstall re-install existing UI components.
|
||||
--no-reinstall do not re-install existing UI components.
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
@@ -85,6 +85,34 @@ Options:
|
||||
|
||||
---
|
||||
|
||||
## apply
|
||||
|
||||
Use the `apply` command to apply a preset to an existing project.
|
||||
|
||||
```bash
|
||||
npx shadcn@latest apply --preset a2r6bw
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
```bash
|
||||
Usage: shadcn apply [options] [preset]
|
||||
|
||||
apply a preset to an existing project
|
||||
|
||||
Arguments:
|
||||
preset the preset to apply
|
||||
|
||||
Options:
|
||||
--preset <preset> preset configuration to apply
|
||||
-y, --yes skip confirmation prompt. (default: false)
|
||||
-c, --cwd <cwd> the working directory. defaults to the current directory.
|
||||
-s, --silent mute output. (default: false)
|
||||
-h, --help display help for command
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## view
|
||||
|
||||
Use the `view` command to view items from the registry before installing them.
|
||||
|
||||
37
apps/v4/content/docs/changelog/2026-03-luma.mdx
Normal file
37
apps/v4/content/docs/changelog/2026-03-luma.mdx
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
title: March 2026 - Introducing Luma
|
||||
description: Rounded geometry. Soft elevation. Breathable layouts. Inspired by macOS Tahoe, minus the glass.
|
||||
date: 2026-03-31
|
||||
---
|
||||
|
||||
Introducing Luma, a new shadcn/ui style. Rounded geometry. Soft elevation. Breathable layouts. Inspired by macOS Tahoe, minus the glass.
|
||||
|
||||
<a href="/create">
|
||||
<Image
|
||||
src="/images/luma-light.png"
|
||||
width="2160"
|
||||
height="1832"
|
||||
alt="Luma style preview"
|
||||
className="mt-6 w-full overflow-hidden rounded-lg border dark:hidden"
|
||||
/>
|
||||
<Image
|
||||
src="/images/luma-dark.png"
|
||||
width="2160"
|
||||
height="1832"
|
||||
alt="Luma style preview"
|
||||
className="mt-6 hidden w-full overflow-hidden rounded-lg border shadow-sm dark:block"
|
||||
/>
|
||||
<span className="sr-only">Try Luma in shadcn/create</span>
|
||||
</a>
|
||||
|
||||
Luma is a new foundation for your next app. It gives components softer surfaces, more open spacing, and a calmer visual rhythm while keeping the same shadcn/ui workflow.
|
||||
|
||||
Like the other new styles, Luma goes beyond theming. It changes the geometry, spacing, and feel of the components so your app starts from a different visual baseline.
|
||||
|
||||
Available now in [shadcn/create](/create) for both Radix and Base UI.
|
||||
|
||||
<Button asChild size="sm">
|
||||
<Link href="/create?preset=b2D0wqNxT" className="mt-6 no-underline!">
|
||||
Try Luma
|
||||
</Link>
|
||||
</Button>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
title: April 2026 - Component Composition
|
||||
description: Composition sections across component pages—structured trees that help you and your agents build correct UI.
|
||||
date: 2026-04-06
|
||||
---
|
||||
|
||||
We've added **Composition** sections across the component docs so you can see the correct structure at a glance: what wraps what, which subcomponents belong together, and how to avoid invalid nesting.
|
||||
|
||||
```text
|
||||
Card
|
||||
├── CardHeader
|
||||
│ ├── CardTitle
|
||||
│ ├── CardDescription
|
||||
│ └── CardAction
|
||||
├── CardContent
|
||||
└── CardFooter
|
||||
```
|
||||
|
||||
## Why we added this
|
||||
|
||||
We've found that **LLMs and coding agents compose elements more reliably** when they can see the full structure: fewer missing wrappers, fewer wrong hierarchies, better matches to the examples.
|
||||
|
||||
### Bring docs into your agent
|
||||
|
||||
You or your LLM can pull the same component documentation, including composition, usage, and examples, into context from the CLI:
|
||||
|
||||
```bash
|
||||
npx shadcn@latest docs card
|
||||
```
|
||||
|
||||
If you're using the [shadcn/skills](/docs/skills), this is done automatically for you.
|
||||
@@ -80,6 +80,20 @@ import {
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Accordion`:
|
||||
|
||||
```text
|
||||
Accordion
|
||||
├── AccordionItem
|
||||
│ ├── AccordionTrigger
|
||||
│ └── AccordionContent
|
||||
└── AccordionItem
|
||||
├── AccordionTrigger
|
||||
└── AccordionContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -94,6 +94,23 @@ import {
|
||||
</AlertDialog>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `AlertDialog`:
|
||||
|
||||
```text
|
||||
AlertDialog
|
||||
├── AlertDialogTrigger
|
||||
└── AlertDialogContent
|
||||
├── AlertDialogHeader
|
||||
│ ├── AlertDialogMedia
|
||||
│ ├── AlertDialogTitle
|
||||
│ └── AlertDialogDescription
|
||||
└── AlertDialogFooter
|
||||
├── AlertDialogCancel
|
||||
└── AlertDialogAction
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -67,6 +67,18 @@ import {
|
||||
</Alert>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Alert`:
|
||||
|
||||
```text
|
||||
Alert
|
||||
├── Icon
|
||||
├── AlertTitle
|
||||
├── AlertDescription
|
||||
└── AlertAction
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -69,6 +69,32 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
</Avatar>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Avatar`:
|
||||
|
||||
```text
|
||||
Avatar
|
||||
├── AvatarImage
|
||||
├── AvatarFallback
|
||||
└── AvatarBadge
|
||||
```
|
||||
|
||||
Use the following composition to build an `AvatarGroup`:
|
||||
|
||||
```text
|
||||
AvatarGroup
|
||||
├── Avatar
|
||||
│ ├── AvatarImage
|
||||
│ ├── AvatarFallback
|
||||
│ └── AvatarBadge
|
||||
├── Avatar
|
||||
│ ├── AvatarImage
|
||||
│ ├── AvatarFallback
|
||||
│ └── AvatarBadge
|
||||
└── AvatarGroupCount
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -80,6 +80,23 @@ import {
|
||||
</Breadcrumb>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Breadcrumb`:
|
||||
|
||||
```text
|
||||
Breadcrumb
|
||||
└── BreadcrumbList
|
||||
├── BreadcrumbItem
|
||||
│ └── BreadcrumbLink
|
||||
├── BreadcrumbSeparator
|
||||
├── BreadcrumbItem
|
||||
│ └── BreadcrumbLink
|
||||
├── BreadcrumbSeparator
|
||||
└── BreadcrumbItem
|
||||
└── BreadcrumbPage
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -66,6 +66,17 @@ import {
|
||||
</ButtonGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ButtonGroup`:
|
||||
|
||||
```text
|
||||
ButtonGroup
|
||||
├── Button or Input
|
||||
├── ButtonGroupSeparator
|
||||
└── ButtonGroupText
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
- The `ButtonGroup` component has the `role` attribute set to `group`.
|
||||
|
||||
@@ -77,6 +77,20 @@ import {
|
||||
</Card>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Card`:
|
||||
|
||||
```text
|
||||
Card
|
||||
├── CardHeader
|
||||
│ ├── CardTitle
|
||||
│ ├── CardDescription
|
||||
│ └── CardAction
|
||||
├── CardContent
|
||||
└── CardFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Size
|
||||
|
||||
@@ -85,6 +85,19 @@ import {
|
||||
</Carousel>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Carousel`:
|
||||
|
||||
```text
|
||||
Carousel
|
||||
├── CarouselContent
|
||||
│ ├── CarouselItem
|
||||
│ └── CarouselItem
|
||||
├── CarouselPrevious
|
||||
└── CarouselNext
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Sizes
|
||||
|
||||
@@ -73,6 +73,16 @@ import {
|
||||
</Collapsible>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Collapsible`:
|
||||
|
||||
```text
|
||||
Collapsible
|
||||
├── CollapsibleTrigger
|
||||
└── CollapsibleContent
|
||||
```
|
||||
|
||||
## Controlled State
|
||||
|
||||
Use the `open` and `onOpenChange` props to control the state.
|
||||
|
||||
@@ -90,6 +90,62 @@ export function ExampleCombobox() {
|
||||
}
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### Simple
|
||||
|
||||
A single-line input and a flat list (see [Basic](#basic)).
|
||||
|
||||
```text
|
||||
Combobox
|
||||
├── ComboboxInput
|
||||
└── ComboboxContent
|
||||
├── ComboboxEmpty
|
||||
└── ComboboxList
|
||||
├── ComboboxItem
|
||||
└── ComboboxItem
|
||||
```
|
||||
|
||||
### With chips
|
||||
|
||||
Multi-select with `multiple`, chips, and a chips input (see [Multiple](#multiple)).
|
||||
|
||||
```text
|
||||
Combobox
|
||||
├── ComboboxChips
|
||||
│ ├── ComboboxValue
|
||||
│ │ └── ComboboxChip
|
||||
│ └── ComboboxChipsInput
|
||||
└── ComboboxContent
|
||||
├── ComboboxEmpty
|
||||
└── ComboboxList
|
||||
├── ComboboxItem
|
||||
└── ComboboxItem
|
||||
```
|
||||
|
||||
### With groups and collection
|
||||
|
||||
Nested items per group using `ComboboxCollection` inside each `ComboboxGroup`, with a separator between groups (see [Groups](#groups)).
|
||||
|
||||
```text
|
||||
Combobox
|
||||
├── ComboboxInput
|
||||
└── ComboboxContent
|
||||
├── ComboboxEmpty
|
||||
└── ComboboxList
|
||||
├── ComboboxGroup
|
||||
│ ├── ComboboxLabel
|
||||
│ └── ComboboxCollection
|
||||
│ ├── ComboboxItem
|
||||
│ └── ComboboxItem
|
||||
├── ComboboxSeparator
|
||||
└── ComboboxGroup
|
||||
├── ComboboxLabel
|
||||
└── ComboboxCollection
|
||||
├── ComboboxItem
|
||||
└── ComboboxItem
|
||||
```
|
||||
|
||||
## Custom Items
|
||||
|
||||
Use `itemToStringValue` when your items are objects.
|
||||
|
||||
@@ -96,6 +96,24 @@ import {
|
||||
</Command>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Command`:
|
||||
|
||||
```text
|
||||
Command
|
||||
├── CommandInput
|
||||
└── CommandList
|
||||
├── CommandEmpty
|
||||
├── CommandGroup
|
||||
│ ├── CommandItem
|
||||
│ └── CommandItem
|
||||
├── CommandSeparator
|
||||
└── CommandGroup
|
||||
├── CommandItem
|
||||
└── CommandItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -79,6 +79,37 @@ import {
|
||||
</ContextMenu>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ContextMenu`:
|
||||
|
||||
```text
|
||||
ContextMenu
|
||||
├── ContextMenuTrigger
|
||||
└── ContextMenuContent
|
||||
├── ContextMenuGroup
|
||||
│ ├── ContextMenuLabel
|
||||
│ ├── ContextMenuItem
|
||||
│ └── ContextMenuItem
|
||||
├── ContextMenuSeparator
|
||||
├── ContextMenuGroup
|
||||
│ ├── ContextMenuLabel
|
||||
│ ├── ContextMenuCheckboxItem
|
||||
│ └── ContextMenuCheckboxItem
|
||||
├── ContextMenuSeparator
|
||||
├── ContextMenuGroup
|
||||
│ ├── ContextMenuLabel
|
||||
│ └── ContextMenuRadioGroup
|
||||
│ ├── ContextMenuRadioItem
|
||||
│ └── ContextMenuRadioItem
|
||||
└── ContextMenuSub
|
||||
├── ContextMenuSubTrigger
|
||||
└── ContextMenuSubContent
|
||||
└── ContextMenuGroup
|
||||
├── ContextMenuItem
|
||||
└── ContextMenuItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -58,6 +58,17 @@ export function DatePickerDemo() {
|
||||
|
||||
See the [React DayPicker](https://react-day-picker.js.org) documentation for more information.
|
||||
|
||||
## Composition
|
||||
|
||||
A date picker is built from `Popover` and `Calendar` (there is no `DatePicker` root component):
|
||||
|
||||
```text
|
||||
Popover
|
||||
├── PopoverTrigger
|
||||
└── PopoverContent
|
||||
└── Calendar
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -85,6 +85,20 @@ import {
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Dialog`:
|
||||
|
||||
```text
|
||||
Dialog
|
||||
├── DialogTrigger
|
||||
└── DialogContent
|
||||
├── DialogHeader
|
||||
│ ├── DialogTitle
|
||||
│ └── DialogDescription
|
||||
└── DialogFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Custom Close Button
|
||||
|
||||
@@ -88,6 +88,20 @@ import {
|
||||
</Drawer>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Drawer`:
|
||||
|
||||
```text
|
||||
Drawer
|
||||
├── DrawerTrigger
|
||||
└── DrawerContent
|
||||
├── DrawerHeader
|
||||
│ ├── DrawerTitle
|
||||
│ └── DrawerDescription
|
||||
└── DrawerFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Scrollable Content
|
||||
|
||||
@@ -92,6 +92,38 @@ import {
|
||||
</DropdownMenu>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `DropdownMenu`:
|
||||
|
||||
```text
|
||||
DropdownMenu
|
||||
├── DropdownMenuTrigger
|
||||
└── DropdownMenuContent
|
||||
├── DropdownMenuGroup
|
||||
│ ├── DropdownMenuLabel
|
||||
│ ├── DropdownMenuItem
|
||||
│ └── DropdownMenuItem
|
||||
├── DropdownMenuSeparator
|
||||
├── DropdownMenuGroup
|
||||
│ ├── DropdownMenuLabel
|
||||
│ ├── DropdownMenuCheckboxItem
|
||||
│ └── DropdownMenuCheckboxItem
|
||||
├── DropdownMenuSeparator
|
||||
├── DropdownMenuGroup
|
||||
│ ├── DropdownMenuLabel
|
||||
│ └── DropdownMenuRadioGroup
|
||||
│ ├── DropdownMenuRadioItem
|
||||
│ └── DropdownMenuRadioItem
|
||||
└── DropdownMenuSub
|
||||
├── DropdownMenuSubTrigger
|
||||
└── DropdownMenuSubContent
|
||||
└── DropdownMenuGroup
|
||||
├── DropdownMenuLabel
|
||||
├── DropdownMenuItem
|
||||
└── DropdownMenuItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -75,6 +75,19 @@ import {
|
||||
</Empty>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Empty` state:
|
||||
|
||||
```text
|
||||
Empty
|
||||
├── EmptyHeader
|
||||
│ ├── EmptyMedia
|
||||
│ ├── EmptyTitle
|
||||
│ └── EmptyDescription
|
||||
└── EmptyContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Outline
|
||||
|
||||
@@ -87,6 +87,56 @@ import {
|
||||
</FieldSet>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### Field
|
||||
|
||||
A single control with label, helper text, and validation.
|
||||
|
||||
```text
|
||||
Field
|
||||
├── FieldLabel
|
||||
├── Input / Textarea / Switch / Select
|
||||
├── FieldDescription
|
||||
└── FieldError
|
||||
```
|
||||
|
||||
### FieldGroup
|
||||
|
||||
Related fields in one group. Use `FieldSeparator` between sections when needed.
|
||||
|
||||
```text
|
||||
FieldGroup
|
||||
├── Field
|
||||
│ ├── FieldLabel
|
||||
│ ├── Input / Textarea / Switch / Select
|
||||
│ ├── FieldDescription
|
||||
│ └── FieldError
|
||||
├── FieldSeparator
|
||||
└── Field
|
||||
├── FieldLabel
|
||||
└── Input / Textarea / Switch / Select
|
||||
```
|
||||
|
||||
### FieldSet
|
||||
|
||||
Semantic grouping with a legend and description, usually containing a `FieldGroup`.
|
||||
|
||||
```text
|
||||
FieldSet
|
||||
├── FieldLegend
|
||||
├── FieldDescription
|
||||
└── FieldGroup
|
||||
├── Field
|
||||
│ ├── FieldLabel
|
||||
│ ├── Input / Textarea / Switch / Select
|
||||
│ ├── FieldDescription
|
||||
│ └── FieldError
|
||||
└── Field
|
||||
├── FieldLabel
|
||||
└── Input / Textarea / Switch / Select
|
||||
```
|
||||
|
||||
## Anatomy
|
||||
|
||||
The `Field` family is designed for composing accessible forms. A typical field is structured as follows:
|
||||
|
||||
@@ -75,6 +75,16 @@ import {
|
||||
</HoverCard>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `HoverCard`:
|
||||
|
||||
```text
|
||||
HoverCard
|
||||
├── HoverCardTrigger
|
||||
└── HoverCardContent
|
||||
```
|
||||
|
||||
## Trigger Delays
|
||||
|
||||
Use `delay` and `closeDelay` on the trigger to control when the card opens and
|
||||
|
||||
@@ -71,6 +71,18 @@ import {
|
||||
</InputGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `InputGroup`:
|
||||
|
||||
```text
|
||||
InputGroup
|
||||
├── InputGroupInput or InputGroupTextarea
|
||||
├── InputGroupAddon
|
||||
├── InputGroupButton
|
||||
└── InputGroupText
|
||||
```
|
||||
|
||||
## Align
|
||||
|
||||
Use the `align` prop on `InputGroupAddon` to position the addon relative to the input.
|
||||
|
||||
@@ -82,6 +82,27 @@ import {
|
||||
</InputOTP>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `InputOTP`:
|
||||
|
||||
```text
|
||||
InputOTP
|
||||
├── InputOTPGroup
|
||||
│ ├── InputOTPSlot
|
||||
│ ├── InputOTPSlot
|
||||
│ └── InputOTPSlot
|
||||
├── InputOTPSeparator
|
||||
├── InputOTPGroup
|
||||
│ ├── InputOTPSlot
|
||||
│ ├── InputOTPSlot
|
||||
│ └── InputOTPSlot
|
||||
├── InputOTPSeparator
|
||||
└── InputOTPGroup
|
||||
├── InputOTPSlot
|
||||
└── InputOTPSlot
|
||||
```
|
||||
|
||||
## Pattern
|
||||
|
||||
Use the `pattern` prop to define a custom pattern for the OTP input.
|
||||
|
||||
@@ -73,6 +73,22 @@ import {
|
||||
</Item>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Item`:
|
||||
|
||||
```text
|
||||
ItemGroup
|
||||
└── Item
|
||||
├── ItemHeader
|
||||
├── ItemMedia
|
||||
├── ItemContent
|
||||
│ ├── ItemTitle
|
||||
│ └── ItemDescription
|
||||
├── ItemActions
|
||||
└── ItemFooter
|
||||
```
|
||||
|
||||
## Item vs Field
|
||||
|
||||
Use `Field` if you need to display a form input such as a checkbox, input, radio, or select.
|
||||
|
||||
@@ -53,6 +53,17 @@ import { Kbd } from "@/components/ui/kbd"
|
||||
<Kbd>Ctrl</Kbd>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build `Kbd` and `KbdGroup`:
|
||||
|
||||
```text
|
||||
Kbd
|
||||
KbdGroup
|
||||
├── Kbd
|
||||
└── Kbd
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Group
|
||||
|
||||
@@ -88,6 +88,46 @@ import {
|
||||
</Menubar>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Menubar`:
|
||||
|
||||
```text
|
||||
Menubar
|
||||
├── MenubarMenu
|
||||
│ ├── MenubarTrigger
|
||||
│ └── MenubarContent
|
||||
│ ├── MenubarGroup
|
||||
│ │ ├── MenubarLabel
|
||||
│ │ ├── MenubarItem
|
||||
│ │ └── MenubarItem
|
||||
│ ├── MenubarSeparator
|
||||
│ ├── MenubarGroup
|
||||
│ │ ├── MenubarLabel
|
||||
│ │ ├── MenubarCheckboxItem
|
||||
│ │ └── MenubarCheckboxItem
|
||||
│ ├── MenubarSeparator
|
||||
│ ├── MenubarGroup
|
||||
│ │ ├── MenubarLabel
|
||||
│ │ └── MenubarRadioGroup
|
||||
│ │ ├── MenubarRadioItem
|
||||
│ │ └── MenubarRadioItem
|
||||
│ └── MenubarSub
|
||||
│ ├── MenubarSubTrigger
|
||||
│ └── MenubarSubContent
|
||||
│ └── MenubarGroup
|
||||
│ ├── MenubarLabel
|
||||
│ ├── MenubarItem
|
||||
│ └── MenubarItem
|
||||
└── MenubarMenu
|
||||
├── MenubarTrigger
|
||||
└── MenubarContent
|
||||
└── MenubarGroup
|
||||
├── MenubarLabel
|
||||
├── MenubarItem
|
||||
└── MenubarItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Checkbox
|
||||
|
||||
@@ -70,6 +70,34 @@ import {
|
||||
</NativeSelect>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### Simple
|
||||
|
||||
Options placed directly under `NativeSelect` (no `NativeSelectOptGroup`).
|
||||
|
||||
```text
|
||||
NativeSelect
|
||||
├── NativeSelectOption
|
||||
├── NativeSelectOption
|
||||
├── NativeSelectOption
|
||||
└── NativeSelectOption
|
||||
```
|
||||
|
||||
### With groups
|
||||
|
||||
Use `NativeSelectOptGroup` to organize options into categories.
|
||||
|
||||
```text
|
||||
NativeSelect
|
||||
├── NativeSelectOptGroup
|
||||
│ ├── NativeSelectOption
|
||||
│ └── NativeSelectOption
|
||||
└── NativeSelectOptGroup
|
||||
├── NativeSelectOption
|
||||
└── NativeSelectOption
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Groups
|
||||
|
||||
@@ -82,6 +82,23 @@ import {
|
||||
</NavigationMenu>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `NavigationMenu`:
|
||||
|
||||
```text
|
||||
NavigationMenu
|
||||
├── NavigationMenuList
|
||||
│ ├── NavigationMenuItem
|
||||
│ │ ├── NavigationMenuTrigger
|
||||
│ │ └── NavigationMenuContent
|
||||
│ │ ├── NavigationMenuLink
|
||||
│ │ └── NavigationMenuLink
|
||||
│ └── NavigationMenuItem
|
||||
│ └── NavigationMenuLink
|
||||
└── NavigationMenuIndicator
|
||||
```
|
||||
|
||||
## Link Component
|
||||
|
||||
Use the `render` prop to compose a custom link component such as Next.js `Link`.
|
||||
|
||||
@@ -84,6 +84,23 @@ import {
|
||||
</Pagination>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Pagination`:
|
||||
|
||||
```text
|
||||
Pagination
|
||||
└── PaginationContent
|
||||
├── PaginationItem
|
||||
│ └── PaginationPrevious
|
||||
├── PaginationItem
|
||||
│ └── PaginationLink
|
||||
├── PaginationItem
|
||||
│ └── PaginationEllipsis
|
||||
└── PaginationItem
|
||||
└── PaginationNext
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple
|
||||
|
||||
@@ -79,6 +79,16 @@ import {
|
||||
</Popover>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Popover`:
|
||||
|
||||
```text
|
||||
Popover
|
||||
├── PopoverTrigger
|
||||
└── PopoverContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -62,6 +62,33 @@ import { Progress } from "@/components/ui/progress"
|
||||
<Progress value={33} />
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### With label and value
|
||||
|
||||
Use `ProgressLabel` and `ProgressValue` to add a label and value display.
|
||||
|
||||
```tsx showLineNumbers
|
||||
import {
|
||||
Progress,
|
||||
ProgressLabel,
|
||||
ProgressValue,
|
||||
} from "@/components/ui/progress"
|
||||
|
||||
;<Progress value={56} className="w-full max-w-sm">
|
||||
<ProgressLabel>Upload progress</ProgressLabel>
|
||||
<ProgressValue />
|
||||
</Progress>
|
||||
```
|
||||
|
||||
```text
|
||||
Progress
|
||||
├── ProgressLabel
|
||||
├── ProgressValue
|
||||
└── ProgressTrack
|
||||
└── ProgressIndicator
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Label
|
||||
|
||||
@@ -72,6 +72,16 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `RadioGroup`:
|
||||
|
||||
```text
|
||||
RadioGroup
|
||||
├── RadioGroupItem
|
||||
└── RadioGroupItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Description
|
||||
|
||||
@@ -78,6 +78,17 @@ import {
|
||||
</ResizablePanelGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ResizablePanelGroup`:
|
||||
|
||||
```text
|
||||
ResizablePanelGroup
|
||||
├── ResizablePanel
|
||||
├── ResizableHandle
|
||||
└── ResizablePanel
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Vertical
|
||||
|
||||
@@ -68,6 +68,15 @@ import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
|
||||
</ScrollArea>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ScrollArea`:
|
||||
|
||||
```text
|
||||
ScrollArea
|
||||
└── ScrollBar
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Horizontal
|
||||
|
||||
@@ -89,6 +89,26 @@ const items = [
|
||||
</Select>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Select`:
|
||||
|
||||
```text
|
||||
Select
|
||||
├── SelectTrigger
|
||||
│ └── SelectValue
|
||||
└── SelectContent
|
||||
├── SelectGroup
|
||||
│ ├── SelectLabel
|
||||
│ ├── SelectItem
|
||||
│ └── SelectItem
|
||||
├── SelectSeparator
|
||||
└── SelectGroup
|
||||
├── SelectLabel
|
||||
├── SelectItem
|
||||
└── SelectItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Align Item With Trigger
|
||||
|
||||
@@ -79,6 +79,20 @@ import {
|
||||
</Sheet>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Sheet`:
|
||||
|
||||
```text
|
||||
Sheet
|
||||
├── SheetTrigger
|
||||
└── SheetContent
|
||||
├── SheetHeader
|
||||
│ ├── SheetTitle
|
||||
│ └── SheetDescription
|
||||
└── SheetFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Side
|
||||
|
||||
@@ -55,32 +55,6 @@ npx shadcn@latest add sidebar
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Structure
|
||||
|
||||
A `Sidebar` component is composed of the following parts:
|
||||
|
||||
- `SidebarProvider` - Handles collapsible state.
|
||||
- `Sidebar` - The sidebar container.
|
||||
- `SidebarHeader` and `SidebarFooter` - Sticky at the top and bottom of the sidebar.
|
||||
- `SidebarContent` - Scrollable content.
|
||||
- `SidebarGroup` - Section within the `SidebarContent`.
|
||||
- `SidebarTrigger` - Trigger for the `Sidebar`.
|
||||
|
||||
<Image
|
||||
src="/images/sidebar-structure.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 w-full overflow-hidden rounded-lg border dark:hidden"
|
||||
/>
|
||||
<Image
|
||||
src="/images/sidebar-structure-dark.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 hidden w-full overflow-hidden rounded-lg border dark:block"
|
||||
/>
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx showLineNumbers title="app/layout.tsx"
|
||||
@@ -123,6 +97,67 @@ export function AppSidebar() {
|
||||
}
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Sidebar` layout:
|
||||
|
||||
```text
|
||||
SidebarProvider
|
||||
├── Sidebar
|
||||
│ ├── SidebarHeader
|
||||
│ ├── SidebarContent
|
||||
│ │ ├── SidebarGroup
|
||||
│ │ │ ├── SidebarGroupLabel
|
||||
│ │ │ ├── SidebarGroupAction
|
||||
│ │ │ ├── SidebarGroupContent
|
||||
│ │ │ └── SidebarMenu
|
||||
│ │ │ ├── SidebarMenuItem
|
||||
│ │ │ │ ├── SidebarMenuButton
|
||||
│ │ │ │ ├── SidebarMenuAction
|
||||
│ │ │ │ └── SidebarMenuBadge
|
||||
│ │ │ └── SidebarMenuItem
|
||||
│ │ │ ├── SidebarMenuButton
|
||||
│ │ │ └── SidebarMenuSub
|
||||
│ │ │ ├── SidebarMenuSubItem
|
||||
│ │ │ └── SidebarMenuSubItem
|
||||
│ │ └── SidebarGroup
|
||||
│ │ └── SidebarMenu
|
||||
│ │ ├── SidebarMenuItem
|
||||
│ │ └── SidebarMenuItem
|
||||
│ ├── SidebarFooter
|
||||
│ └── SidebarRail
|
||||
├── SidebarInset
|
||||
└── SidebarTrigger
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
- **SidebarProvider** — Handles collapsible state and provides sidebar context to child components.
|
||||
- **Sidebar** — The main collapsible sidebar panel.
|
||||
- **SidebarHeader** — Sticky at the top; use for branding, titles, or workspace switchers.
|
||||
- **SidebarFooter** — Sticky at the bottom; use for user menus, settings, or actions.
|
||||
- **SidebarContent** — Scrollable region between the header and footer.
|
||||
- **SidebarGroup** — Groups related navigation with optional label, action, and content areas.
|
||||
- **SidebarMenu** / **SidebarMenuItem** — Menu structure for links, badges, actions, and nested submenus.
|
||||
- **SidebarRail** — Resize handle for adjusting sidebar width when applicable.
|
||||
- **SidebarInset** — Wraps main content when using the `inset` variant.
|
||||
- **SidebarTrigger** — Control that toggles the sidebar open or collapsed.
|
||||
|
||||
<Image
|
||||
src="/images/sidebar-structure.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 w-full overflow-hidden rounded-lg border dark:hidden"
|
||||
/>
|
||||
<Image
|
||||
src="/images/sidebar-structure-dark.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 hidden w-full overflow-hidden rounded-lg border dark:block"
|
||||
/>
|
||||
|
||||
## SidebarProvider
|
||||
|
||||
The `SidebarProvider` component is used to provide the sidebar context to the `Sidebar` component. You should always wrap your application in a `SidebarProvider` component.
|
||||
|
||||
@@ -83,6 +83,33 @@ import {
|
||||
</Table>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Table`:
|
||||
|
||||
```text
|
||||
Table
|
||||
├── TableCaption
|
||||
├── TableHeader
|
||||
│ └── TableRow
|
||||
│ ├── TableHead
|
||||
│ ├── TableHead
|
||||
│ ├── TableHead
|
||||
│ └── TableHead
|
||||
├── TableBody
|
||||
│ ├── TableRow
|
||||
│ │ ├── TableCell
|
||||
│ │ ├── TableCell
|
||||
│ │ ├── TableCell
|
||||
│ │ └── TableCell
|
||||
│ └── TableRow
|
||||
│ ├── TableCell
|
||||
│ ├── TableCell
|
||||
│ ├── TableCell
|
||||
│ └── TableCell
|
||||
└── TableFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Footer
|
||||
|
||||
@@ -73,6 +73,19 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build `Tabs`:
|
||||
|
||||
```text
|
||||
Tabs
|
||||
├── TabsList
|
||||
│ ├── TabsTrigger
|
||||
│ └── TabsTrigger
|
||||
├── TabsContent
|
||||
└── TabsContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Line
|
||||
|
||||
@@ -66,6 +66,16 @@ import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
|
||||
</ToggleGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ToggleGroup`:
|
||||
|
||||
```text
|
||||
ToggleGroup
|
||||
├── ToggleGroupItem
|
||||
└── ToggleGroupItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Outline
|
||||
|
||||
@@ -109,6 +109,16 @@ import {
|
||||
</Tooltip>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Tooltip`:
|
||||
|
||||
```text
|
||||
Tooltip
|
||||
├── TooltipTrigger
|
||||
└── TooltipContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Side
|
||||
|
||||
@@ -80,6 +80,20 @@ import {
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Accordion`:
|
||||
|
||||
```text
|
||||
Accordion
|
||||
├── AccordionItem
|
||||
│ ├── AccordionTrigger
|
||||
│ └── AccordionContent
|
||||
└── AccordionItem
|
||||
├── AccordionTrigger
|
||||
└── AccordionContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -94,6 +94,23 @@ import {
|
||||
</AlertDialog>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `AlertDialog`:
|
||||
|
||||
```text
|
||||
AlertDialog
|
||||
├── AlertDialogTrigger
|
||||
└── AlertDialogContent
|
||||
├── AlertDialogHeader
|
||||
│ ├── AlertDialogMedia
|
||||
│ ├── AlertDialogTitle
|
||||
│ └── AlertDialogDescription
|
||||
└── AlertDialogFooter
|
||||
├── AlertDialogCancel
|
||||
└── AlertDialogAction
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -71,6 +71,18 @@ import {
|
||||
</Alert>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Alert`:
|
||||
|
||||
```text
|
||||
Alert
|
||||
├── Icon
|
||||
├── AlertTitle
|
||||
├── AlertDescription
|
||||
└── AlertAction
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -65,6 +65,32 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
</Avatar>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Avatar`:
|
||||
|
||||
```text
|
||||
Avatar
|
||||
├── AvatarImage
|
||||
├── AvatarFallback
|
||||
└── AvatarBadge
|
||||
```
|
||||
|
||||
Use the following composition to build an `AvatarGroup`:
|
||||
|
||||
```text
|
||||
AvatarGroup
|
||||
├── Avatar
|
||||
│ ├── AvatarImage
|
||||
│ ├── AvatarFallback
|
||||
│ └── AvatarBadge
|
||||
├── Avatar
|
||||
│ ├── AvatarImage
|
||||
│ ├── AvatarFallback
|
||||
│ └── AvatarBadge
|
||||
└── AvatarGroupCount
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -74,6 +74,23 @@ import {
|
||||
</Breadcrumb>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Breadcrumb`:
|
||||
|
||||
```text
|
||||
Breadcrumb
|
||||
└── BreadcrumbList
|
||||
├── BreadcrumbItem
|
||||
│ └── BreadcrumbLink
|
||||
├── BreadcrumbSeparator
|
||||
├── BreadcrumbItem
|
||||
│ └── BreadcrumbLink
|
||||
├── BreadcrumbSeparator
|
||||
└── BreadcrumbItem
|
||||
└── BreadcrumbPage
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -66,6 +66,17 @@ import {
|
||||
</ButtonGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ButtonGroup`:
|
||||
|
||||
```text
|
||||
ButtonGroup
|
||||
├── Button or Input
|
||||
├── ButtonGroupSeparator
|
||||
└── ButtonGroupText
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
- The `ButtonGroup` component has the `role` attribute set to `group`.
|
||||
|
||||
@@ -77,6 +77,20 @@ import {
|
||||
</Card>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Card`:
|
||||
|
||||
```text
|
||||
Card
|
||||
├── CardHeader
|
||||
│ ├── CardTitle
|
||||
│ ├── CardDescription
|
||||
│ └── CardAction
|
||||
├── CardContent
|
||||
└── CardFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Size
|
||||
|
||||
@@ -85,6 +85,19 @@ import {
|
||||
</Carousel>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Carousel`:
|
||||
|
||||
```text
|
||||
Carousel
|
||||
├── CarouselContent
|
||||
│ ├── CarouselItem
|
||||
│ └── CarouselItem
|
||||
├── CarouselPrevious
|
||||
└── CarouselNext
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Sizes
|
||||
|
||||
@@ -77,6 +77,16 @@ import {
|
||||
</Collapsible>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Collapsible`:
|
||||
|
||||
```text
|
||||
Collapsible
|
||||
├── CollapsibleTrigger
|
||||
└── CollapsibleContent
|
||||
```
|
||||
|
||||
## Controlled State
|
||||
|
||||
Use the `open` and `onOpenChange` props to control the state.
|
||||
|
||||
@@ -90,6 +90,62 @@ export function ExampleCombobox() {
|
||||
}
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### Simple
|
||||
|
||||
A single-line input and a flat list (see [Basic](#basic)).
|
||||
|
||||
```text
|
||||
Combobox
|
||||
├── ComboboxInput
|
||||
└── ComboboxContent
|
||||
├── ComboboxEmpty
|
||||
└── ComboboxList
|
||||
├── ComboboxItem
|
||||
└── ComboboxItem
|
||||
```
|
||||
|
||||
### With chips
|
||||
|
||||
Multi-select with `multiple`, chips, and a chips input (see [Multiple](#multiple)).
|
||||
|
||||
```text
|
||||
Combobox
|
||||
├── ComboboxChips
|
||||
│ ├── ComboboxValue
|
||||
│ │ └── ComboboxChip
|
||||
│ └── ComboboxChipsInput
|
||||
└── ComboboxContent
|
||||
├── ComboboxEmpty
|
||||
└── ComboboxList
|
||||
├── ComboboxItem
|
||||
└── ComboboxItem
|
||||
```
|
||||
|
||||
### With groups and collection
|
||||
|
||||
Nested items per group using `ComboboxCollection` inside each `ComboboxGroup`, with a separator between groups (see [Groups](#groups)).
|
||||
|
||||
```text
|
||||
Combobox
|
||||
├── ComboboxInput
|
||||
└── ComboboxContent
|
||||
├── ComboboxEmpty
|
||||
└── ComboboxList
|
||||
├── ComboboxGroup
|
||||
│ ├── ComboboxLabel
|
||||
│ └── ComboboxCollection
|
||||
│ ├── ComboboxItem
|
||||
│ └── ComboboxItem
|
||||
├── ComboboxSeparator
|
||||
└── ComboboxGroup
|
||||
├── ComboboxLabel
|
||||
└── ComboboxCollection
|
||||
├── ComboboxItem
|
||||
└── ComboboxItem
|
||||
```
|
||||
|
||||
## Custom Items
|
||||
|
||||
Use `itemToStringValue` when your items are objects.
|
||||
|
||||
@@ -96,6 +96,24 @@ import {
|
||||
</Command>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Command`:
|
||||
|
||||
```text
|
||||
Command
|
||||
├── CommandInput
|
||||
└── CommandList
|
||||
├── CommandEmpty
|
||||
├── CommandGroup
|
||||
│ ├── CommandItem
|
||||
│ └── CommandItem
|
||||
├── CommandSeparator
|
||||
└── CommandGroup
|
||||
├── CommandItem
|
||||
└── CommandItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -79,6 +79,37 @@ import {
|
||||
</ContextMenu>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ContextMenu`:
|
||||
|
||||
```text
|
||||
ContextMenu
|
||||
├── ContextMenuTrigger
|
||||
└── ContextMenuContent
|
||||
├── ContextMenuGroup
|
||||
│ ├── ContextMenuLabel
|
||||
│ ├── ContextMenuItem
|
||||
│ └── ContextMenuItem
|
||||
├── ContextMenuSeparator
|
||||
├── ContextMenuGroup
|
||||
│ ├── ContextMenuLabel
|
||||
│ ├── ContextMenuCheckboxItem
|
||||
│ └── ContextMenuCheckboxItem
|
||||
├── ContextMenuSeparator
|
||||
├── ContextMenuGroup
|
||||
│ ├── ContextMenuLabel
|
||||
│ └── ContextMenuRadioGroup
|
||||
│ ├── ContextMenuRadioItem
|
||||
│ └── ContextMenuRadioItem
|
||||
└── ContextMenuSub
|
||||
├── ContextMenuSubTrigger
|
||||
└── ContextMenuSubContent
|
||||
└── ContextMenuGroup
|
||||
├── ContextMenuItem
|
||||
└── ContextMenuItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -56,6 +56,17 @@ export function DatePickerDemo() {
|
||||
|
||||
See the [React DayPicker](https://react-day-picker.js.org) documentation for more information.
|
||||
|
||||
## Composition
|
||||
|
||||
A date picker is built from `Popover` and `Calendar` (there is no `DatePicker` root component):
|
||||
|
||||
```text
|
||||
Popover
|
||||
├── PopoverTrigger
|
||||
└── PopoverContent
|
||||
└── Calendar
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -85,6 +85,20 @@ import {
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Dialog`:
|
||||
|
||||
```text
|
||||
Dialog
|
||||
├── DialogTrigger
|
||||
└── DialogContent
|
||||
├── DialogHeader
|
||||
│ ├── DialogTitle
|
||||
│ └── DialogDescription
|
||||
└── DialogFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Custom Close Button
|
||||
|
||||
@@ -88,6 +88,20 @@ import {
|
||||
</Drawer>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Drawer`:
|
||||
|
||||
```text
|
||||
Drawer
|
||||
├── DrawerTrigger
|
||||
└── DrawerContent
|
||||
├── DrawerHeader
|
||||
│ ├── DrawerTitle
|
||||
│ └── DrawerDescription
|
||||
└── DrawerFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Scrollable Content
|
||||
|
||||
@@ -92,6 +92,38 @@ import {
|
||||
</DropdownMenu>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `DropdownMenu`:
|
||||
|
||||
```text
|
||||
DropdownMenu
|
||||
├── DropdownMenuTrigger
|
||||
└── DropdownMenuContent
|
||||
├── DropdownMenuGroup
|
||||
│ ├── DropdownMenuLabel
|
||||
│ ├── DropdownMenuItem
|
||||
│ └── DropdownMenuItem
|
||||
├── DropdownMenuSeparator
|
||||
├── DropdownMenuGroup
|
||||
│ ├── DropdownMenuLabel
|
||||
│ ├── DropdownMenuCheckboxItem
|
||||
│ └── DropdownMenuCheckboxItem
|
||||
├── DropdownMenuSeparator
|
||||
├── DropdownMenuGroup
|
||||
│ ├── DropdownMenuLabel
|
||||
│ └── DropdownMenuRadioGroup
|
||||
│ ├── DropdownMenuRadioItem
|
||||
│ └── DropdownMenuRadioItem
|
||||
└── DropdownMenuSub
|
||||
├── DropdownMenuSubTrigger
|
||||
└── DropdownMenuSubContent
|
||||
└── DropdownMenuGroup
|
||||
├── DropdownMenuLabel
|
||||
├── DropdownMenuItem
|
||||
└── DropdownMenuItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -75,6 +75,19 @@ import {
|
||||
</Empty>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Empty` state:
|
||||
|
||||
```text
|
||||
Empty
|
||||
├── EmptyHeader
|
||||
│ ├── EmptyMedia
|
||||
│ ├── EmptyTitle
|
||||
│ └── EmptyDescription
|
||||
└── EmptyContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Outline
|
||||
|
||||
@@ -87,6 +87,56 @@ import {
|
||||
</FieldSet>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### Field
|
||||
|
||||
A single control with label, helper text, and validation.
|
||||
|
||||
```text
|
||||
Field
|
||||
├── FieldLabel
|
||||
├── Input / Textarea / Switch / Select
|
||||
├── FieldDescription
|
||||
└── FieldError
|
||||
```
|
||||
|
||||
### FieldGroup
|
||||
|
||||
Related fields in one group. Use `FieldSeparator` between sections when needed.
|
||||
|
||||
```text
|
||||
FieldGroup
|
||||
├── Field
|
||||
│ ├── FieldLabel
|
||||
│ ├── Input / Textarea / Switch / Select
|
||||
│ ├── FieldDescription
|
||||
│ └── FieldError
|
||||
├── FieldSeparator
|
||||
└── Field
|
||||
├── FieldLabel
|
||||
└── Input / Textarea / Switch / Select
|
||||
```
|
||||
|
||||
### FieldSet
|
||||
|
||||
Semantic grouping with a legend and description, usually containing a `FieldGroup`.
|
||||
|
||||
```text
|
||||
FieldSet
|
||||
├── FieldLegend
|
||||
├── FieldDescription
|
||||
└── FieldGroup
|
||||
├── Field
|
||||
│ ├── FieldLabel
|
||||
│ ├── Input / Textarea / Switch / Select
|
||||
│ ├── FieldDescription
|
||||
│ └── FieldError
|
||||
└── Field
|
||||
├── FieldLabel
|
||||
└── Input / Textarea / Switch / Select
|
||||
```
|
||||
|
||||
## Anatomy
|
||||
|
||||
The `Field` family is designed for composing accessible forms. A typical field is structured as follows:
|
||||
|
||||
@@ -75,6 +75,16 @@ import {
|
||||
</HoverCard>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `HoverCard`:
|
||||
|
||||
```text
|
||||
HoverCard
|
||||
├── HoverCardTrigger
|
||||
└── HoverCardContent
|
||||
```
|
||||
|
||||
## Trigger Delays
|
||||
|
||||
Use `openDelay` and `closeDelay` on the `HoverCard` to control when the card opens and
|
||||
|
||||
@@ -71,6 +71,18 @@ import {
|
||||
</InputGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `InputGroup`:
|
||||
|
||||
```text
|
||||
InputGroup
|
||||
├── InputGroupInput or InputGroupTextarea
|
||||
├── InputGroupAddon
|
||||
├── InputGroupButton
|
||||
└── InputGroupText
|
||||
```
|
||||
|
||||
## Align
|
||||
|
||||
Use the `align` prop on `InputGroupAddon` to position the addon relative to the input.
|
||||
|
||||
@@ -82,6 +82,27 @@ import {
|
||||
</InputOTP>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `InputOTP`:
|
||||
|
||||
```text
|
||||
InputOTP
|
||||
├── InputOTPGroup
|
||||
│ ├── InputOTPSlot
|
||||
│ ├── InputOTPSlot
|
||||
│ └── InputOTPSlot
|
||||
├── InputOTPSeparator
|
||||
├── InputOTPGroup
|
||||
│ ├── InputOTPSlot
|
||||
│ ├── InputOTPSlot
|
||||
│ └── InputOTPSlot
|
||||
├── InputOTPSeparator
|
||||
└── InputOTPGroup
|
||||
├── InputOTPSlot
|
||||
└── InputOTPSlot
|
||||
```
|
||||
|
||||
## Pattern
|
||||
|
||||
Use the `pattern` prop to define a custom pattern for the OTP input.
|
||||
|
||||
@@ -73,6 +73,22 @@ import {
|
||||
</Item>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build an `Item`:
|
||||
|
||||
```text
|
||||
ItemGroup
|
||||
└── Item
|
||||
├── ItemHeader
|
||||
├── ItemMedia
|
||||
├── ItemContent
|
||||
│ ├── ItemTitle
|
||||
│ └── ItemDescription
|
||||
├── ItemActions
|
||||
└── ItemFooter
|
||||
```
|
||||
|
||||
## Item vs Field
|
||||
|
||||
Use `Field` if you need to display a form input such as a checkbox, input, radio, or select.
|
||||
|
||||
@@ -53,6 +53,17 @@ import { Kbd } from "@/components/ui/kbd"
|
||||
<Kbd>Ctrl</Kbd>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build `Kbd` and `KbdGroup`:
|
||||
|
||||
```text
|
||||
Kbd
|
||||
KbdGroup
|
||||
├── Kbd
|
||||
└── Kbd
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Group
|
||||
|
||||
@@ -88,6 +88,46 @@ import {
|
||||
</Menubar>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Menubar`:
|
||||
|
||||
```text
|
||||
Menubar
|
||||
├── MenubarMenu
|
||||
│ ├── MenubarTrigger
|
||||
│ └── MenubarContent
|
||||
│ ├── MenubarGroup
|
||||
│ │ ├── MenubarLabel
|
||||
│ │ ├── MenubarItem
|
||||
│ │ └── MenubarItem
|
||||
│ ├── MenubarSeparator
|
||||
│ ├── MenubarGroup
|
||||
│ │ ├── MenubarLabel
|
||||
│ │ ├── MenubarCheckboxItem
|
||||
│ │ └── MenubarCheckboxItem
|
||||
│ ├── MenubarSeparator
|
||||
│ ├── MenubarGroup
|
||||
│ │ ├── MenubarLabel
|
||||
│ │ └── MenubarRadioGroup
|
||||
│ │ ├── MenubarRadioItem
|
||||
│ │ └── MenubarRadioItem
|
||||
│ └── MenubarSub
|
||||
│ ├── MenubarSubTrigger
|
||||
│ └── MenubarSubContent
|
||||
│ └── MenubarGroup
|
||||
│ ├── MenubarLabel
|
||||
│ ├── MenubarItem
|
||||
│ └── MenubarItem
|
||||
└── MenubarMenu
|
||||
├── MenubarTrigger
|
||||
└── MenubarContent
|
||||
└── MenubarGroup
|
||||
├── MenubarLabel
|
||||
├── MenubarItem
|
||||
└── MenubarItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Checkbox
|
||||
|
||||
@@ -70,6 +70,34 @@ import {
|
||||
</NativeSelect>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
### Simple
|
||||
|
||||
Options placed directly under `NativeSelect` (no `NativeSelectOptGroup`).
|
||||
|
||||
```text
|
||||
NativeSelect
|
||||
├── NativeSelectOption
|
||||
├── NativeSelectOption
|
||||
├── NativeSelectOption
|
||||
└── NativeSelectOption
|
||||
```
|
||||
|
||||
### With groups
|
||||
|
||||
Use `NativeSelectOptGroup` to organize options into categories.
|
||||
|
||||
```text
|
||||
NativeSelect
|
||||
├── NativeSelectOptGroup
|
||||
│ ├── NativeSelectOption
|
||||
│ └── NativeSelectOption
|
||||
└── NativeSelectOptGroup
|
||||
├── NativeSelectOption
|
||||
└── NativeSelectOption
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Groups
|
||||
|
||||
@@ -82,6 +82,23 @@ import {
|
||||
</NavigationMenu>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `NavigationMenu`:
|
||||
|
||||
```text
|
||||
NavigationMenu
|
||||
├── NavigationMenuList
|
||||
│ ├── NavigationMenuItem
|
||||
│ │ ├── NavigationMenuTrigger
|
||||
│ │ └── NavigationMenuContent
|
||||
│ │ ├── NavigationMenuLink
|
||||
│ │ └── NavigationMenuLink
|
||||
│ └── NavigationMenuItem
|
||||
│ └── NavigationMenuLink
|
||||
└── NavigationMenuIndicator
|
||||
```
|
||||
|
||||
## Link Component
|
||||
|
||||
Use the `asChild` prop to compose a custom link component such as Next.js `Link`.
|
||||
|
||||
@@ -84,6 +84,23 @@ import {
|
||||
</Pagination>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Pagination`:
|
||||
|
||||
```text
|
||||
Pagination
|
||||
└── PaginationContent
|
||||
├── PaginationItem
|
||||
│ └── PaginationPrevious
|
||||
├── PaginationItem
|
||||
│ └── PaginationLink
|
||||
├── PaginationItem
|
||||
│ └── PaginationEllipsis
|
||||
└── PaginationItem
|
||||
└── PaginationNext
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Simple
|
||||
|
||||
@@ -79,6 +79,16 @@ import {
|
||||
</Popover>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Popover`:
|
||||
|
||||
```text
|
||||
Popover
|
||||
├── PopoverTrigger
|
||||
└── PopoverContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic
|
||||
|
||||
@@ -72,6 +72,16 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `RadioGroup`:
|
||||
|
||||
```text
|
||||
RadioGroup
|
||||
├── RadioGroupItem
|
||||
└── RadioGroupItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Description
|
||||
|
||||
@@ -78,6 +78,17 @@ import {
|
||||
</ResizablePanelGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ResizablePanelGroup`:
|
||||
|
||||
```text
|
||||
ResizablePanelGroup
|
||||
├── ResizablePanel
|
||||
├── ResizableHandle
|
||||
└── ResizablePanel
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Vertical
|
||||
|
||||
@@ -68,6 +68,15 @@ import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
|
||||
</ScrollArea>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ScrollArea`:
|
||||
|
||||
```text
|
||||
ScrollArea
|
||||
└── ScrollBar
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Horizontal
|
||||
|
||||
@@ -81,6 +81,26 @@ import {
|
||||
</Select>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Select`:
|
||||
|
||||
```text
|
||||
Select
|
||||
├── SelectTrigger
|
||||
│ └── SelectValue
|
||||
└── SelectContent
|
||||
├── SelectGroup
|
||||
│ ├── SelectLabel
|
||||
│ ├── SelectItem
|
||||
│ └── SelectItem
|
||||
├── SelectSeparator
|
||||
└── SelectGroup
|
||||
├── SelectLabel
|
||||
├── SelectItem
|
||||
└── SelectItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Align Item With Trigger
|
||||
|
||||
@@ -79,6 +79,20 @@ import {
|
||||
</Sheet>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Sheet`:
|
||||
|
||||
```text
|
||||
Sheet
|
||||
├── SheetTrigger
|
||||
└── SheetContent
|
||||
├── SheetHeader
|
||||
│ ├── SheetTitle
|
||||
│ └── SheetDescription
|
||||
└── SheetFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Side
|
||||
|
||||
@@ -55,32 +55,6 @@ npx shadcn@latest add sidebar
|
||||
|
||||
</CodeTabs>
|
||||
|
||||
## Structure
|
||||
|
||||
A `Sidebar` component is composed of the following parts:
|
||||
|
||||
- `SidebarProvider` - Handles collapsible state.
|
||||
- `Sidebar` - The sidebar container.
|
||||
- `SidebarHeader` and `SidebarFooter` - Sticky at the top and bottom of the sidebar.
|
||||
- `SidebarContent` - Scrollable content.
|
||||
- `SidebarGroup` - Section within the `SidebarContent`.
|
||||
- `SidebarTrigger` - Trigger for the `Sidebar`.
|
||||
|
||||
<Image
|
||||
src="/images/sidebar-structure.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 w-full overflow-hidden rounded-lg border dark:hidden"
|
||||
/>
|
||||
<Image
|
||||
src="/images/sidebar-structure-dark.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 hidden w-full overflow-hidden rounded-lg border dark:block"
|
||||
/>
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx showLineNumbers title="app/layout.tsx"
|
||||
@@ -123,6 +97,67 @@ export function AppSidebar() {
|
||||
}
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Sidebar` layout:
|
||||
|
||||
```text
|
||||
SidebarProvider
|
||||
├── Sidebar
|
||||
│ ├── SidebarHeader
|
||||
│ ├── SidebarContent
|
||||
│ │ ├── SidebarGroup
|
||||
│ │ │ ├── SidebarGroupLabel
|
||||
│ │ │ ├── SidebarGroupAction
|
||||
│ │ │ ├── SidebarGroupContent
|
||||
│ │ │ └── SidebarMenu
|
||||
│ │ │ ├── SidebarMenuItem
|
||||
│ │ │ │ ├── SidebarMenuButton
|
||||
│ │ │ │ ├── SidebarMenuAction
|
||||
│ │ │ │ └── SidebarMenuBadge
|
||||
│ │ │ └── SidebarMenuItem
|
||||
│ │ │ ├── SidebarMenuButton
|
||||
│ │ │ └── SidebarMenuSub
|
||||
│ │ │ ├── SidebarMenuSubItem
|
||||
│ │ │ └── SidebarMenuSubItem
|
||||
│ │ └── SidebarGroup
|
||||
│ │ └── SidebarMenu
|
||||
│ │ ├── SidebarMenuItem
|
||||
│ │ └── SidebarMenuItem
|
||||
│ ├── SidebarFooter
|
||||
│ └── SidebarRail
|
||||
├── SidebarInset
|
||||
└── SidebarTrigger
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
- **SidebarProvider** — Handles collapsible state and provides sidebar context to child components.
|
||||
- **Sidebar** — The main collapsible sidebar panel.
|
||||
- **SidebarHeader** — Sticky at the top; use for branding, titles, or workspace switchers.
|
||||
- **SidebarFooter** — Sticky at the bottom; use for user menus, settings, or actions.
|
||||
- **SidebarContent** — Scrollable region between the header and footer.
|
||||
- **SidebarGroup** — Groups related navigation with optional label, action, and content areas.
|
||||
- **SidebarMenu** / **SidebarMenuItem** — Menu structure for links, badges, actions, and nested submenus.
|
||||
- **SidebarRail** — Resize handle for adjusting sidebar width when applicable.
|
||||
- **SidebarInset** — Wraps main content when using the `inset` variant.
|
||||
- **SidebarTrigger** — Control that toggles the sidebar open or collapsed.
|
||||
|
||||
<Image
|
||||
src="/images/sidebar-structure.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 w-full overflow-hidden rounded-lg border dark:hidden"
|
||||
/>
|
||||
<Image
|
||||
src="/images/sidebar-structure-dark.png"
|
||||
width="716"
|
||||
height="420"
|
||||
alt="Sidebar Structure"
|
||||
className="mt-6 hidden w-full overflow-hidden rounded-lg border dark:block"
|
||||
/>
|
||||
|
||||
## SidebarProvider
|
||||
|
||||
The `SidebarProvider` component is used to provide the sidebar context to the `Sidebar` component. You should always wrap your application in a `SidebarProvider` component.
|
||||
|
||||
@@ -83,6 +83,33 @@ import {
|
||||
</Table>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Table`:
|
||||
|
||||
```text
|
||||
Table
|
||||
├── TableCaption
|
||||
├── TableHeader
|
||||
│ └── TableRow
|
||||
│ ├── TableHead
|
||||
│ ├── TableHead
|
||||
│ ├── TableHead
|
||||
│ └── TableHead
|
||||
├── TableBody
|
||||
│ ├── TableRow
|
||||
│ │ ├── TableCell
|
||||
│ │ ├── TableCell
|
||||
│ │ ├── TableCell
|
||||
│ │ └── TableCell
|
||||
│ └── TableRow
|
||||
│ ├── TableCell
|
||||
│ ├── TableCell
|
||||
│ ├── TableCell
|
||||
│ └── TableCell
|
||||
└── TableFooter
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Footer
|
||||
|
||||
@@ -73,6 +73,19 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build `Tabs`:
|
||||
|
||||
```text
|
||||
Tabs
|
||||
├── TabsList
|
||||
│ ├── TabsTrigger
|
||||
│ └── TabsTrigger
|
||||
├── TabsContent
|
||||
└── TabsContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Line
|
||||
|
||||
@@ -66,6 +66,16 @@ import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
|
||||
</ToggleGroup>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `ToggleGroup`:
|
||||
|
||||
```text
|
||||
ToggleGroup
|
||||
├── ToggleGroupItem
|
||||
└── ToggleGroupItem
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Outline
|
||||
|
||||
@@ -109,6 +109,16 @@ import {
|
||||
</Tooltip>
|
||||
```
|
||||
|
||||
## Composition
|
||||
|
||||
Use the following composition to build a `Tooltip`:
|
||||
|
||||
```text
|
||||
Tooltip
|
||||
├── TooltipTrigger
|
||||
└── TooltipContent
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Side
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
"use client"
|
||||
|
||||
import { buttonVariants } from "@/styles/base-nova/ui/button"
|
||||
|
||||
export default function ButtonRender() {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"postinstall": "fumadocs-mdx"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base-ui/react": "1.1.0",
|
||||
"@base-ui/react": "1.3.0",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
@@ -76,7 +76,7 @@
|
||||
"rehype-pretty-code": "^0.14.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"server-only": "^0.0.1",
|
||||
"shadcn": "4.1.2",
|
||||
"shadcn": "4.2.0",
|
||||
"shiki": "^1.10.1",
|
||||
"sonner": "^2.0.0",
|
||||
"swr": "^2.3.6",
|
||||
|
||||
BIN
apps/v4/public/images/luma-dark.png
Normal file
BIN
apps/v4/public/images/luma-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
BIN
apps/v4/public/images/luma-light.png
Normal file
BIN
apps/v4/public/images/luma-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
@@ -239,6 +239,12 @@
|
||||
"url": "https://formcn.dev/r/{name}.json",
|
||||
"description": "Build production-ready forms with a few clicks using shadcn components and modern tools."
|
||||
},
|
||||
{
|
||||
"name": "@flightcn",
|
||||
"homepage": "https://flightcn.yencheng.dev",
|
||||
"url": "https://flightcn.yencheng.dev/r/{name}.json",
|
||||
"description": "Flight routes on interactive maps with great-circle arcs, airport markers, multi-leg journeys, and optional animation, built for mapcn."
|
||||
},
|
||||
{
|
||||
"name": "@gaia",
|
||||
"homepage": "https://ui.heygaia.io",
|
||||
@@ -647,6 +653,12 @@
|
||||
"url": "https://shadcncraft.com/r/{name}.json",
|
||||
"description": "A starter collection of polished shadcn/ui components and blocks built to production standards. Part of a larger Figma + React system designed to scale with your product."
|
||||
},
|
||||
{
|
||||
"name": "@shark",
|
||||
"homepage": "https://shark.vini.one",
|
||||
"url": "https://shark.vini.one/r/{name}.json",
|
||||
"description": "shadcn/ui-style components built on Ark UI."
|
||||
},
|
||||
{
|
||||
"name": "@smoothui",
|
||||
"homepage": "https://smoothui.dev",
|
||||
@@ -1000,5 +1012,17 @@
|
||||
"homepage": "https://www.openpolicy.sh",
|
||||
"url": "https://www.openpolicy.sh/r/{name}.json",
|
||||
"description": "Open-source components for building terms, privacy policies and cookie banners."
|
||||
},
|
||||
{
|
||||
"name": "@mksingh",
|
||||
"homepage": "https://mksingh.dev/docs",
|
||||
"url": "https://mksingh.dev/r/{name}.json",
|
||||
"description": "A personal registry of production-ready ShadCN components and utilities. Everything is built to drop into your existing ShadCN project with no extra setup."
|
||||
},
|
||||
{
|
||||
"name": "@flowkit-ui",
|
||||
"homepage": "https://flowkit-ui.vzkiss.com",
|
||||
"url": "https://flowkit-ui.vzkiss.com/r/{name}.json",
|
||||
"description": "Opinionated, accessible components on Base UI and shadcn-style primitives — starting with a Creatable Combobox."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-luma/ui/accordion.tsx",
|
||||
"content": "\"use client\"\n\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nfunction Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\n \"flex w-full flex-col overflow-hidden rounded-2xl border\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\"not-last:border-b data-open:bg-muted/50\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionPrimitive.Trigger.Props) {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"group/accordion-trigger relative flex flex-1 items-start justify-between gap-6 border border-transparent p-4 text-left text-sm font-medium transition-all outline-none hover:underline aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n <IconPlaceholder\n lucide=\"ChevronDownIcon\"\n tabler=\"IconChevronDown\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowDown01Icon\"\n phosphor=\"CaretDownIcon\"\n remixicon=\"RiArrowDownSLine\"\n className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\"\n />\n <IconPlaceholder\n lucide=\"ChevronUpIcon\"\n tabler=\"IconChevronUp\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowUp01Icon\"\n phosphor=\"CaretUpIcon\"\n remixicon=\"RiArrowUpSLine\"\n className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionPrimitive.Panel.Props) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className=\"overflow-hidden px-4 text-sm data-open:animate-accordion-down data-closed:animate-accordion-up\"\n {...props}\n >\n <div\n className={cn(\n \"h-(--accordion-panel-height) pt-0 pb-4 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n",
|
||||
"content": "import { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nfunction Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\n \"flex w-full flex-col overflow-hidden rounded-2xl border\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\"not-last:border-b data-open:bg-muted/50\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionPrimitive.Trigger.Props) {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"group/accordion-trigger relative flex flex-1 items-start justify-between gap-6 border border-transparent p-4 text-left text-sm font-medium transition-all outline-none hover:underline aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n <IconPlaceholder\n lucide=\"ChevronDownIcon\"\n tabler=\"IconChevronDown\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowDown01Icon\"\n phosphor=\"CaretDownIcon\"\n remixicon=\"RiArrowDownSLine\"\n className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\"\n />\n <IconPlaceholder\n lucide=\"ChevronUpIcon\"\n tabler=\"IconChevronUp\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowUp01Icon\"\n phosphor=\"CaretUpIcon\"\n remixicon=\"RiArrowUpSLine\"\n className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionPrimitive.Panel.Props) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className=\"overflow-hidden px-4 text-sm data-open:animate-accordion-down data-closed:animate-accordion-up\"\n {...props}\n >\n <div\n className={cn(\n \"h-(--accordion-panel-height) pt-0 pb-4 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-luma/ui/button.tsx",
|
||||
"content": "\"use client\"\n\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-transparent dark:hover:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5\",\n xs: \"h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n lg: \"h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n icon: \"size-9\",\n \"icon-xs\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n",
|
||||
"content": "import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-transparent dark:hover:bg-input/30\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5\",\n xs: \"h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n lg: \"h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3\",\n icon: \"size-9\",\n \"icon-xs\": \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-luma/ui/native-select.tsx",
|
||||
"content": "import * as React from \"react\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\ntype NativeSelectProps = Omit<React.ComponentProps<\"select\">, \"size\"> & {\n size?: \"sm\" | \"default\"\n}\n\nfunction NativeSelect({\n className,\n size = \"default\",\n ...props\n}: NativeSelectProps) {\n return (\n <div\n className={cn(\n \"group/native-select relative w-fit has-[select:disabled]:opacity-50\",\n className\n )}\n data-slot=\"native-select-wrapper\"\n data-size={size}\n >\n <select\n data-slot=\"native-select\"\n data-size={size}\n className=\"h-9 w-full min-w-0 appearance-none rounded-3xl border border-transparent bg-input/50 py-1 pr-8 pl-3 text-sm transition-[color,box-shadow,background-color] outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-8 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\"\n {...props}\n />\n <IconPlaceholder\n lucide=\"ChevronDownIcon\"\n tabler=\"IconSelector\"\n hugeicons=\"UnfoldMoreIcon\"\n phosphor=\"CaretDownIcon\"\n remixicon=\"RiArrowDownSLine\"\n className=\"pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground select-none\"\n aria-hidden=\"true\"\n data-slot=\"native-select-icon\"\n />\n </div>\n )\n}\n\nfunction NativeSelectOption({ ...props }: React.ComponentProps<\"option\">) {\n return <option data-slot=\"native-select-option\" {...props} />\n}\n\nfunction NativeSelectOptGroup({\n className,\n ...props\n}: React.ComponentProps<\"optgroup\">) {\n return (\n <optgroup\n data-slot=\"native-select-optgroup\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nexport { NativeSelect, NativeSelectOptGroup, NativeSelectOption }\n",
|
||||
"content": "import * as React from \"react\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\ntype NativeSelectProps = Omit<React.ComponentProps<\"select\">, \"size\"> & {\n size?: \"sm\" | \"default\"\n}\n\nfunction NativeSelect({\n className,\n size = \"default\",\n ...props\n}: NativeSelectProps) {\n return (\n <div\n className={cn(\n \"group/native-select relative w-fit has-[select:disabled]:opacity-50\",\n className\n )}\n data-slot=\"native-select-wrapper\"\n data-size={size}\n >\n <select\n data-slot=\"native-select\"\n data-size={size}\n className=\"h-9 w-full min-w-0 appearance-none rounded-3xl border border-transparent bg-input/50 py-1 pr-8 pl-3 text-sm transition-[color,box-shadow,background-color] outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-8 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40\"\n {...props}\n />\n <IconPlaceholder\n lucide=\"ChevronDownIcon\"\n tabler=\"IconSelector\"\n hugeicons=\"UnfoldMoreIcon\"\n phosphor=\"CaretDownIcon\"\n remixicon=\"RiArrowDownSLine\"\n className=\"pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground select-none\"\n aria-hidden=\"true\"\n data-slot=\"native-select-icon\"\n />\n </div>\n )\n}\n\nfunction NativeSelectOption({\n className,\n ...props\n}: React.ComponentProps<\"option\">) {\n return (\n <option\n data-slot=\"native-select-option\"\n className={cn(\"bg-[Canvas] text-[CanvasText]\", className)}\n {...props}\n />\n )\n}\n\nfunction NativeSelectOptGroup({\n className,\n ...props\n}: React.ComponentProps<\"optgroup\">) {\n return (\n <optgroup\n data-slot=\"native-select-optgroup\"\n className={cn(\"bg-[Canvas] text-[CanvasText]\", className)}\n {...props}\n />\n )\n}\n\nexport { NativeSelect, NativeSelectOptGroup, NativeSelectOption }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-luma/ui/slider.tsx",
|
||||
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Slider as SliderPrimitive } from \"@base-ui/react/slider\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\n\nfunction Slider({\n className,\n defaultValue,\n value,\n min = 0,\n max = 100,\n ...props\n}: SliderPrimitive.Root.Props) {\n const _values = React.useMemo(\n () =>\n Array.isArray(value)\n ? value\n : Array.isArray(defaultValue)\n ? defaultValue\n : [min, max],\n [value, defaultValue, min, max]\n )\n\n return (\n <SliderPrimitive.Root\n className={cn(\"data-horizontal:w-full data-vertical:h-full\", className)}\n data-slot=\"slider\"\n defaultValue={defaultValue}\n value={value}\n min={min}\n max={max}\n thumbAlignment=\"edge\"\n {...props}\n >\n <SliderPrimitive.Control className=\"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col\">\n <SliderPrimitive.Track\n data-slot=\"slider-track\"\n className=\"relative grow overflow-hidden rounded-full bg-input/90 select-none data-horizontal:h-2 data-horizontal:w-full data-vertical:h-full data-vertical:w-2\"\n >\n <SliderPrimitive.Indicator\n data-slot=\"slider-range\"\n className=\"bg-primary select-none data-horizontal:h-full data-vertical:w-full\"\n />\n </SliderPrimitive.Track>\n {Array.from({ length: _values.length }, (_, index) => (\n <SliderPrimitive.Thumb\n data-slot=\"slider-thumb\"\n key={index}\n className=\"block h-4 w-6 shrink-0 rounded-full bg-white shadow-md ring-1 ring-black/10 transition-[color,box-shadow,background-color] select-none not-dark:bg-clip-padding hover:ring-4 hover:ring-ring/30 focus-visible:ring-4 focus-visible:ring-ring/30 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 data-vertical:h-6 data-vertical:w-4\"\n />\n ))}\n </SliderPrimitive.Control>\n </SliderPrimitive.Root>\n )\n}\n\nexport { Slider }\n",
|
||||
"content": "import { Slider as SliderPrimitive } from \"@base-ui/react/slider\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\n\nfunction Slider({\n className,\n defaultValue,\n value,\n min = 0,\n max = 100,\n ...props\n}: SliderPrimitive.Root.Props) {\n const _values = Array.isArray(value)\n ? value\n : Array.isArray(defaultValue)\n ? defaultValue\n : [min, max]\n\n return (\n <SliderPrimitive.Root\n className={cn(\"data-horizontal:w-full data-vertical:h-full\", className)}\n data-slot=\"slider\"\n defaultValue={defaultValue}\n value={value}\n min={min}\n max={max}\n thumbAlignment=\"edge\"\n {...props}\n >\n <SliderPrimitive.Control className=\"relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-col\">\n <SliderPrimitive.Track\n data-slot=\"slider-track\"\n className=\"relative grow overflow-hidden rounded-full bg-input/90 select-none data-horizontal:h-2 data-horizontal:w-full data-vertical:h-full data-vertical:w-2\"\n >\n <SliderPrimitive.Indicator\n data-slot=\"slider-range\"\n className=\"bg-primary select-none data-horizontal:h-full data-vertical:w-full\"\n />\n </SliderPrimitive.Track>\n {Array.from({ length: _values.length }, (_, index) => (\n <SliderPrimitive.Thumb\n data-slot=\"slider-thumb\"\n key={index}\n className=\"block h-4 w-6 shrink-0 rounded-full bg-white shadow-md ring-1 ring-black/10 transition-[color,box-shadow,background-color] select-none not-dark:bg-clip-padding hover:ring-4 hover:ring-ring/30 focus-visible:ring-4 focus-visible:ring-ring/30 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50 data-vertical:h-6 data-vertical:w-4\"\n />\n ))}\n </SliderPrimitive.Control>\n </SliderPrimitive.Root>\n )\n}\n\nexport { Slider }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-lyra/ui/accordion.tsx",
|
||||
"content": "\"use client\"\n\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"@/registry/base-lyra/lib/utils\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nfunction Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\"flex w-full flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\"not-last:border-b\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionPrimitive.Trigger.Props) {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"group/accordion-trigger relative flex flex-1 items-start justify-between rounded-none border border-transparent py-2.5 text-left text-xs font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n <IconPlaceholder\n lucide=\"ChevronDownIcon\"\n tabler=\"IconChevronDown\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowDown01Icon\"\n phosphor=\"CaretDownIcon\"\n remixicon=\"RiArrowDownSLine\"\n className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\"\n />\n <IconPlaceholder\n lucide=\"ChevronUpIcon\"\n tabler=\"IconChevronUp\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowUp01Icon\"\n phosphor=\"CaretUpIcon\"\n remixicon=\"RiArrowUpSLine\"\n className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionPrimitive.Panel.Props) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className=\"overflow-hidden text-xs data-open:animate-accordion-down data-closed:animate-accordion-up\"\n {...props}\n >\n <div\n className={cn(\n \"h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n",
|
||||
"content": "import { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"@/registry/base-lyra/lib/utils\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\nfunction Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\"flex w-full flex-col\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\"not-last:border-b\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionPrimitive.Trigger.Props) {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"group/accordion-trigger relative flex flex-1 items-start justify-between rounded-none border border-transparent py-2.5 text-left text-xs font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground\",\n className\n )}\n {...props}\n >\n {children}\n <IconPlaceholder\n lucide=\"ChevronDownIcon\"\n tabler=\"IconChevronDown\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowDown01Icon\"\n phosphor=\"CaretDownIcon\"\n remixicon=\"RiArrowDownSLine\"\n className=\"pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden\"\n />\n <IconPlaceholder\n lucide=\"ChevronUpIcon\"\n tabler=\"IconChevronUp\"\n data-slot=\"accordion-trigger-icon\"\n hugeicons=\"ArrowUp01Icon\"\n phosphor=\"CaretUpIcon\"\n remixicon=\"RiArrowUpSLine\"\n className=\"pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline\"\n />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: AccordionPrimitive.Panel.Props) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className=\"overflow-hidden text-xs data-open:animate-accordion-down data-closed:animate-accordion-up\"\n {...props}\n >\n <div\n className={cn(\n \"h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4\",\n className\n )}\n >\n {children}\n </div>\n </AccordionPrimitive.Panel>\n )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/base-lyra/ui/button.tsx",
|
||||
"content": "\"use client\"\n\nimport { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-lyra/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n icon: \"size-8\",\n \"icon-xs\": \"size-6 rounded-none [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-7 rounded-none\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n",
|
||||
"content": "import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/registry/base-lyra/lib/utils\"\n\nconst buttonVariants = cva(\n \"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n outline:\n \"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n xs: \"h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: \"h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n icon: \"size-8\",\n \"icon-xs\": \"size-6 rounded-none [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\": \"size-7 rounded-none\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
],
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user