@sntlr/registry-shell 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/adapter/custom.d.ts +47 -0
- package/dist/adapter/custom.js +53 -0
- package/dist/adapter/custom.js.map +1 -0
- package/dist/adapter/default.d.ts +40 -0
- package/dist/adapter/default.js +202 -0
- package/dist/adapter/default.js.map +1 -0
- package/dist/cli/build.d.ts +1 -0
- package/dist/cli/build.js +31 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/dev.d.ts +1 -0
- package/dist/cli/dev.js +26 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.js +49 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.js +70 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/shared.d.ts +33 -0
- package/dist/cli/shared.js +278 -0
- package/dist/cli/shared.js.map +1 -0
- package/dist/cli/start.d.ts +1 -0
- package/dist/cli/start.js +24 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/config-loader.d.ts +49 -0
- package/dist/config-loader.js +140 -0
- package/dist/define-config.d.ts +188 -0
- package/dist/define-config.js +21 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +9 -0
- package/package.json +124 -0
- package/src/adapter/custom.ts +90 -0
- package/src/adapter/default.ts +241 -0
- package/src/cli/build.ts +38 -0
- package/src/cli/dev.ts +38 -0
- package/src/cli/index.ts +52 -0
- package/src/cli/init.ts +76 -0
- package/src/cli/shared.ts +306 -0
- package/src/cli/start.ts +28 -0
- package/src/config-loader.ts +190 -0
- package/src/define-config.ts +206 -0
- package/src/index.ts +17 -0
- package/src/next-app/app/[...asset]/route.ts +81 -0
- package/src/next-app/app/_user-global.css +6 -0
- package/src/next-app/app/_user-sources.css +9 -0
- package/src/next-app/app/a11y/[name]/route.ts +19 -0
- package/src/next-app/app/api/search-index/route.ts +19 -0
- package/src/next-app/app/components/[name]/page.tsx +61 -0
- package/src/next-app/app/components/layout.tsx +18 -0
- package/src/next-app/app/docs/[slug]/page.tsx +53 -0
- package/src/next-app/app/docs/layout.tsx +18 -0
- package/src/next-app/app/globals.css +329 -0
- package/src/next-app/app/layout.tsx +102 -0
- package/src/next-app/app/page.tsx +9 -0
- package/src/next-app/app/preview-snapshot/[name]/page.tsx +20 -0
- package/src/next-app/app/preview-snapshot/layout.tsx +17 -0
- package/src/next-app/app/props/[name]/route.ts +19 -0
- package/src/next-app/app/r/[name]/route.ts +14 -0
- package/src/next-app/app/tests/[name]/route.ts +19 -0
- package/src/next-app/components/a11y-info.tsx +287 -0
- package/src/next-app/components/a11y-provider.tsx +39 -0
- package/src/next-app/components/component-breadcrumb.tsx +55 -0
- package/src/next-app/components/component-icon.tsx +140 -0
- package/src/next-app/components/component-preview.tsx +13 -0
- package/src/next-app/components/component-tabs.tsx +209 -0
- package/src/next-app/components/docs-toc.tsx +86 -0
- package/src/next-app/components/global-mobile-sidebar.tsx +35 -0
- package/src/next-app/components/header.tsx +188 -0
- package/src/next-app/components/heading-anchor.tsx +52 -0
- package/src/next-app/components/homepage-demo.tsx +180 -0
- package/src/next-app/components/locale-toggle.tsx +35 -0
- package/src/next-app/components/localized-mdx-client.tsx +14 -0
- package/src/next-app/components/localized-mdx.tsx +27 -0
- package/src/next-app/components/mobile-sidebar.tsx +22 -0
- package/src/next-app/components/nav-data-provider.tsx +37 -0
- package/src/next-app/components/navigation-progress.tsx +62 -0
- package/src/next-app/components/preview-canvas.tsx +368 -0
- package/src/next-app/components/preview-controls.tsx +94 -0
- package/src/next-app/components/preview-layout.tsx +218 -0
- package/src/next-app/components/props-table.tsx +134 -0
- package/src/next-app/components/resizable-preview.tsx +101 -0
- package/src/next-app/components/search.tsx +177 -0
- package/src/next-app/components/settings-modal.tsx +98 -0
- package/src/next-app/components/shell-ui/accordion.tsx +70 -0
- package/src/next-app/components/shell-ui/backdrop.tsx +29 -0
- package/src/next-app/components/shell-ui/badge.tsx +55 -0
- package/src/next-app/components/shell-ui/breadcrumb.tsx +120 -0
- package/src/next-app/components/shell-ui/button.tsx +64 -0
- package/src/next-app/components/shell-ui/card.tsx +127 -0
- package/src/next-app/components/shell-ui/checkbox.tsx +33 -0
- package/src/next-app/components/shell-ui/dialog.tsx +171 -0
- package/src/next-app/components/shell-ui/empty-state.tsx +66 -0
- package/src/next-app/components/shell-ui/input.tsx +27 -0
- package/src/next-app/components/shell-ui/kbd.tsx +30 -0
- package/src/next-app/components/shell-ui/label.tsx +25 -0
- package/src/next-app/components/shell-ui/select.tsx +204 -0
- package/src/next-app/components/shell-ui/separator.tsx +32 -0
- package/src/next-app/components/shell-ui/skeleton.tsx +18 -0
- package/src/next-app/components/shell-ui/table.tsx +124 -0
- package/src/next-app/components/shell-ui/tabs.tsx +102 -0
- package/src/next-app/components/shell-ui/toggle.tsx +56 -0
- package/src/next-app/components/sidebar-layout.tsx +37 -0
- package/src/next-app/components/sidebar-provider.tsx +75 -0
- package/src/next-app/components/sidebar.tsx +222 -0
- package/src/next-app/components/snapshot-preview.tsx +28 -0
- package/src/next-app/components/test-info.tsx +155 -0
- package/src/next-app/components/theme-provider.tsx +16 -0
- package/src/next-app/components/theme-toggle.tsx +21 -0
- package/src/next-app/components/translated-text.tsx +8 -0
- package/src/next-app/fallback/homepage.tsx +112 -0
- package/src/next-app/fallback/previews.ts +17 -0
- package/src/next-app/hooks/use-active-section.ts +23 -0
- package/src/next-app/hooks/use-controls.ts +72 -0
- package/src/next-app/hooks/use-mobile.ts +19 -0
- package/src/next-app/lib/branding.ts +52 -0
- package/src/next-app/lib/components-nav.ts +8 -0
- package/src/next-app/lib/docs.ts +16 -0
- package/src/next-app/lib/github.ts +38 -0
- package/src/next-app/lib/i18n.tsx +630 -0
- package/src/next-app/lib/locales.ts +17 -0
- package/src/next-app/lib/preview-loader.ts +7 -0
- package/src/next-app/lib/registry-adapter.ts +199 -0
- package/src/next-app/lib/utils.ts +6 -0
- package/src/next-app/next-env.d.ts +6 -0
- package/src/next-app/next.config.ts +101 -0
- package/src/next-app/postcss.config.mjs +7 -0
- package/src/next-app/public/favicon.ico +0 -0
- package/src/next-app/public/favicon_dark.svg +3 -0
- package/src/next-app/public/favicon_light.svg +3 -0
- package/src/next-app/registry.config.ts +50 -0
- package/src/next-app/tsconfig.json +29 -0
- package/src/next-app/user-aliases.d.ts +17 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
|
3
|
+
import { Slot } from "radix-ui"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@shell/lib/utils"
|
|
6
|
+
|
|
7
|
+
/** Navigation wrapper that provides an accessible breadcrumb landmark. */
|
|
8
|
+
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
|
|
9
|
+
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Ordered list that lays out breadcrumb items horizontally with wrapping. */
|
|
13
|
+
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
|
|
14
|
+
return (
|
|
15
|
+
<ol
|
|
16
|
+
data-slot="breadcrumb-list"
|
|
17
|
+
className={cn(
|
|
18
|
+
"flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2.5",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** A single breadcrumb entry that contains a link or the current page indicator. */
|
|
27
|
+
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
28
|
+
return (
|
|
29
|
+
<li
|
|
30
|
+
data-slot="breadcrumb-item"
|
|
31
|
+
className={cn("inline-flex items-center gap-1.5", className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A navigational link within a breadcrumb item.
|
|
39
|
+
* @param props.asChild - When true, renders the child element instead of an anchor tag.
|
|
40
|
+
*/
|
|
41
|
+
function BreadcrumbLink({
|
|
42
|
+
asChild,
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<"a"> & {
|
|
46
|
+
/** When true, renders the child element instead of an anchor tag. */
|
|
47
|
+
asChild?: boolean
|
|
48
|
+
}) {
|
|
49
|
+
const Comp = asChild ? Slot.Root : "a"
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Comp
|
|
53
|
+
data-slot="breadcrumb-link"
|
|
54
|
+
className={cn("transition-colors hover:text-foreground", className)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Marks the current page in the breadcrumb trail with `aria-current="page"`. */
|
|
61
|
+
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
|
62
|
+
return (
|
|
63
|
+
<span
|
|
64
|
+
data-slot="breadcrumb-page"
|
|
65
|
+
role="link"
|
|
66
|
+
aria-disabled="true"
|
|
67
|
+
aria-current="page"
|
|
68
|
+
className={cn("font-normal text-foreground", className)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Visual separator between breadcrumb items, defaulting to a chevron icon. */
|
|
75
|
+
function BreadcrumbSeparator({
|
|
76
|
+
children,
|
|
77
|
+
className,
|
|
78
|
+
...props
|
|
79
|
+
}: React.ComponentProps<"li">) {
|
|
80
|
+
return (
|
|
81
|
+
<li
|
|
82
|
+
data-slot="breadcrumb-separator"
|
|
83
|
+
role="presentation"
|
|
84
|
+
aria-hidden="true"
|
|
85
|
+
className={cn("[&>svg]:size-3.5", className)}
|
|
86
|
+
{...props}
|
|
87
|
+
>
|
|
88
|
+
{children ?? <ChevronRight />}
|
|
89
|
+
</li>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Ellipsis indicator used to represent collapsed breadcrumb items. */
|
|
94
|
+
function BreadcrumbEllipsis({
|
|
95
|
+
className,
|
|
96
|
+
...props
|
|
97
|
+
}: React.ComponentProps<"span">) {
|
|
98
|
+
return (
|
|
99
|
+
<span
|
|
100
|
+
data-slot="breadcrumb-ellipsis"
|
|
101
|
+
role="presentation"
|
|
102
|
+
aria-hidden="true"
|
|
103
|
+
className={cn("flex size-9 items-center justify-center", className)}
|
|
104
|
+
{...props}
|
|
105
|
+
>
|
|
106
|
+
<MoreHorizontal className="size-4" />
|
|
107
|
+
<span className="sr-only">More</span>
|
|
108
|
+
</span>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
Breadcrumb,
|
|
114
|
+
BreadcrumbList,
|
|
115
|
+
BreadcrumbItem,
|
|
116
|
+
BreadcrumbLink,
|
|
117
|
+
BreadcrumbPage,
|
|
118
|
+
BreadcrumbSeparator,
|
|
119
|
+
BreadcrumbEllipsis,
|
|
120
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
import { Slot } from "radix-ui"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@shell/lib/utils"
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap cursor-pointer transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
13
|
+
destructive:
|
|
14
|
+
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
15
|
+
outline:
|
|
16
|
+
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
17
|
+
secondary:
|
|
18
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
19
|
+
ghost:
|
|
20
|
+
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
21
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
25
|
+
xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
26
|
+
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
27
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
28
|
+
icon: "size-9",
|
|
29
|
+
"icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
30
|
+
"icon-sm": "size-8",
|
|
31
|
+
"icon-lg": "size-10",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
variant: "default",
|
|
36
|
+
size: "default",
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
function Button({
|
|
42
|
+
className,
|
|
43
|
+
variant = "default",
|
|
44
|
+
size = "default",
|
|
45
|
+
asChild = false,
|
|
46
|
+
...props
|
|
47
|
+
}: React.ComponentProps<"button"> &
|
|
48
|
+
VariantProps<typeof buttonVariants> & {
|
|
49
|
+
asChild?: boolean
|
|
50
|
+
}) {
|
|
51
|
+
const Comp = asChild ? Slot.Root : "button"
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Comp
|
|
55
|
+
data-slot="button"
|
|
56
|
+
data-variant={variant}
|
|
57
|
+
data-size={size}
|
|
58
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@shell/lib/utils"
|
|
4
|
+
|
|
5
|
+
/** A styled container card with rounded corners, border, and shadow. */
|
|
6
|
+
function Card({
|
|
7
|
+
/** Additional CSS classes to apply to the card. */
|
|
8
|
+
className,
|
|
9
|
+
...props
|
|
10
|
+
}: React.ComponentProps<"div">) {
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
data-slot="card"
|
|
14
|
+
className={cn(
|
|
15
|
+
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Header section of a Card, typically containing a title and description. */
|
|
24
|
+
function CardHeader({
|
|
25
|
+
/** Additional CSS classes to apply to the card header. */
|
|
26
|
+
className,
|
|
27
|
+
...props
|
|
28
|
+
}: React.ComponentProps<"div">) {
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
data-slot="card-header"
|
|
32
|
+
className={cn(
|
|
33
|
+
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Title element within a CardHeader. */
|
|
42
|
+
function CardTitle({
|
|
43
|
+
/** Additional CSS classes to apply to the card title. */
|
|
44
|
+
className,
|
|
45
|
+
...props
|
|
46
|
+
}: React.ComponentProps<"div">) {
|
|
47
|
+
return (
|
|
48
|
+
<div
|
|
49
|
+
data-slot="card-title"
|
|
50
|
+
className={cn("leading-none font-semibold", className)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Description text within a CardHeader, rendered in muted style. */
|
|
57
|
+
function CardDescription({
|
|
58
|
+
/** Additional CSS classes to apply to the card description. */
|
|
59
|
+
className,
|
|
60
|
+
...props
|
|
61
|
+
}: React.ComponentProps<"div">) {
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
data-slot="card-description"
|
|
65
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Action area positioned at the top-right of a CardHeader. */
|
|
72
|
+
function CardAction({
|
|
73
|
+
/** Additional CSS classes to apply to the card action. */
|
|
74
|
+
className,
|
|
75
|
+
...props
|
|
76
|
+
}: React.ComponentProps<"div">) {
|
|
77
|
+
return (
|
|
78
|
+
<div
|
|
79
|
+
data-slot="card-action"
|
|
80
|
+
className={cn(
|
|
81
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
82
|
+
className
|
|
83
|
+
)}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Main content area of a Card. */
|
|
90
|
+
function CardContent({
|
|
91
|
+
/** Additional CSS classes to apply to the card content. */
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentProps<"div">) {
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
data-slot="card-content"
|
|
98
|
+
className={cn("px-6", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Footer section of a Card, typically used for actions or metadata. */
|
|
105
|
+
function CardFooter({
|
|
106
|
+
/** Additional CSS classes to apply to the card footer. */
|
|
107
|
+
className,
|
|
108
|
+
...props
|
|
109
|
+
}: React.ComponentProps<"div">) {
|
|
110
|
+
return (
|
|
111
|
+
<div
|
|
112
|
+
data-slot="card-footer"
|
|
113
|
+
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
|
|
114
|
+
{...props}
|
|
115
|
+
/>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
Card,
|
|
121
|
+
CardHeader,
|
|
122
|
+
CardFooter,
|
|
123
|
+
CardTitle,
|
|
124
|
+
CardAction,
|
|
125
|
+
CardDescription,
|
|
126
|
+
CardContent,
|
|
127
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { CheckIcon } from "lucide-react"
|
|
5
|
+
import { Checkbox as CheckboxPrimitive } from "radix-ui"
|
|
6
|
+
|
|
7
|
+
import { cn } from "@shell/lib/utils"
|
|
8
|
+
|
|
9
|
+
function Checkbox({
|
|
10
|
+
/** Additional CSS class names to apply to the checkbox. */
|
|
11
|
+
className,
|
|
12
|
+
...props
|
|
13
|
+
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
|
14
|
+
return (
|
|
15
|
+
<CheckboxPrimitive.Root
|
|
16
|
+
data-slot="checkbox"
|
|
17
|
+
className={cn(
|
|
18
|
+
"peer size-4 shrink-0 rounded-[4px] border border-input shadow-xs cursor-pointer transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
>
|
|
23
|
+
<CheckboxPrimitive.Indicator
|
|
24
|
+
data-slot="checkbox-indicator"
|
|
25
|
+
className="grid place-content-center text-current transition-none"
|
|
26
|
+
>
|
|
27
|
+
<CheckIcon className="size-3.5" />
|
|
28
|
+
</CheckboxPrimitive.Indicator>
|
|
29
|
+
</CheckboxPrimitive.Root>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { Checkbox }
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { XIcon } from "lucide-react"
|
|
5
|
+
import { Dialog as DialogPrimitive } from "radix-ui"
|
|
6
|
+
|
|
7
|
+
import { cn } from "@shell/lib/utils"
|
|
8
|
+
import { Button } from "@shell/components/shell-ui/button"
|
|
9
|
+
|
|
10
|
+
/** Root dialog component that manages open/closed state. */
|
|
11
|
+
function Dialog({
|
|
12
|
+
...props
|
|
13
|
+
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
14
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Button that opens the dialog when clicked. */
|
|
18
|
+
function DialogTrigger({
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
21
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Renders dialog content into a React portal outside the DOM hierarchy. */
|
|
25
|
+
function DialogPortal({
|
|
26
|
+
...props
|
|
27
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
28
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Button that closes the dialog when clicked. */
|
|
32
|
+
function DialogClose({
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
35
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Semi-transparent backdrop rendered behind the dialog content. */
|
|
39
|
+
function DialogOverlay({
|
|
40
|
+
className,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
43
|
+
return (
|
|
44
|
+
<DialogPrimitive.Overlay
|
|
45
|
+
data-slot="dialog-overlay"
|
|
46
|
+
className={cn(
|
|
47
|
+
"fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
48
|
+
className
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Dialog content container rendered inside a portal with an overlay backdrop.
|
|
57
|
+
* Includes an optional close button in the top-right corner (shown by default).
|
|
58
|
+
*/
|
|
59
|
+
function DialogContent({
|
|
60
|
+
className,
|
|
61
|
+
children,
|
|
62
|
+
showCloseButton = true,
|
|
63
|
+
...props
|
|
64
|
+
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
65
|
+
showCloseButton?: boolean
|
|
66
|
+
}) {
|
|
67
|
+
return (
|
|
68
|
+
<DialogPortal data-slot="dialog-portal">
|
|
69
|
+
<DialogOverlay />
|
|
70
|
+
<DialogPrimitive.Content
|
|
71
|
+
data-slot="dialog-content"
|
|
72
|
+
className={cn(
|
|
73
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",
|
|
74
|
+
className
|
|
75
|
+
)}
|
|
76
|
+
{...props}
|
|
77
|
+
>
|
|
78
|
+
{children}
|
|
79
|
+
{showCloseButton && (
|
|
80
|
+
<DialogPrimitive.Close
|
|
81
|
+
data-slot="dialog-close"
|
|
82
|
+
className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background cursor-pointer transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
83
|
+
>
|
|
84
|
+
<XIcon />
|
|
85
|
+
<span className="sr-only">Close</span>
|
|
86
|
+
</DialogPrimitive.Close>
|
|
87
|
+
)}
|
|
88
|
+
</DialogPrimitive.Content>
|
|
89
|
+
</DialogPortal>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Layout container for the dialog title and description. */
|
|
94
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
data-slot="dialog-header"
|
|
98
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Layout container for dialog action buttons, with an optional close button. */
|
|
105
|
+
function DialogFooter({
|
|
106
|
+
className,
|
|
107
|
+
showCloseButton = false,
|
|
108
|
+
children,
|
|
109
|
+
...props
|
|
110
|
+
}: React.ComponentProps<"div"> & {
|
|
111
|
+
showCloseButton?: boolean
|
|
112
|
+
}) {
|
|
113
|
+
return (
|
|
114
|
+
<div
|
|
115
|
+
data-slot="dialog-footer"
|
|
116
|
+
className={cn(
|
|
117
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
118
|
+
className
|
|
119
|
+
)}
|
|
120
|
+
{...props}
|
|
121
|
+
>
|
|
122
|
+
{children}
|
|
123
|
+
{showCloseButton && (
|
|
124
|
+
<DialogPrimitive.Close asChild>
|
|
125
|
+
<Button variant="outline">Close</Button>
|
|
126
|
+
</DialogPrimitive.Close>
|
|
127
|
+
)}
|
|
128
|
+
</div>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** The dialog heading, rendered as an accessible title. */
|
|
133
|
+
function DialogTitle({
|
|
134
|
+
className,
|
|
135
|
+
...props
|
|
136
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
137
|
+
return (
|
|
138
|
+
<DialogPrimitive.Title
|
|
139
|
+
data-slot="dialog-title"
|
|
140
|
+
className={cn("text-lg leading-none font-semibold", className)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Secondary descriptive text displayed below the dialog title. */
|
|
147
|
+
function DialogDescription({
|
|
148
|
+
className,
|
|
149
|
+
...props
|
|
150
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
151
|
+
return (
|
|
152
|
+
<DialogPrimitive.Description
|
|
153
|
+
data-slot="dialog-description"
|
|
154
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
155
|
+
{...props}
|
|
156
|
+
/>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export {
|
|
161
|
+
Dialog,
|
|
162
|
+
DialogClose,
|
|
163
|
+
DialogContent,
|
|
164
|
+
DialogDescription,
|
|
165
|
+
DialogFooter,
|
|
166
|
+
DialogHeader,
|
|
167
|
+
DialogOverlay,
|
|
168
|
+
DialogPortal,
|
|
169
|
+
DialogTitle,
|
|
170
|
+
DialogTrigger,
|
|
171
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { cn } from "@shell/lib/utils"
|
|
2
|
+
|
|
3
|
+
/** A placeholder shown when a section has no content. Displays an icon, title, and optional description. */
|
|
4
|
+
function EmptyState({
|
|
5
|
+
/** Additional CSS classes. */
|
|
6
|
+
className,
|
|
7
|
+
...props
|
|
8
|
+
}: React.ComponentProps<"div">) {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
data-slot="empty-state"
|
|
12
|
+
className={cn(
|
|
13
|
+
"flex flex-col items-center justify-center rounded-lg border border-dashed border-border py-10 px-6 text-center",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Icon container for the empty state. */
|
|
22
|
+
function EmptyStateIcon({
|
|
23
|
+
className,
|
|
24
|
+
...props
|
|
25
|
+
}: React.ComponentProps<"div">) {
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
data-slot="empty-state-icon"
|
|
29
|
+
className={cn(
|
|
30
|
+
"mb-3 flex items-center justify-center rounded-full bg-muted p-3 text-muted-foreground [&_svg]:size-6",
|
|
31
|
+
className
|
|
32
|
+
)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Title text for the empty state. */
|
|
39
|
+
function EmptyStateTitle({
|
|
40
|
+
className,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<"h3">) {
|
|
43
|
+
return (
|
|
44
|
+
<h3
|
|
45
|
+
data-slot="empty-state-title"
|
|
46
|
+
className={cn("text-sm font-semibold text-foreground mb-1", className)}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Description text for the empty state. */
|
|
53
|
+
function EmptyStateDescription({
|
|
54
|
+
className,
|
|
55
|
+
...props
|
|
56
|
+
}: React.ComponentProps<"p">) {
|
|
57
|
+
return (
|
|
58
|
+
<p
|
|
59
|
+
data-slot="empty-state-description"
|
|
60
|
+
className={cn("text-sm text-muted-foreground max-w-sm", className)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { EmptyState, EmptyStateIcon, EmptyStateTitle, EmptyStateDescription }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "@shell/lib/utils"
|
|
4
|
+
|
|
5
|
+
function Input({
|
|
6
|
+
/** Additional CSS class names to apply to the input. */
|
|
7
|
+
className,
|
|
8
|
+
/** The HTML input type attribute (e.g. "text", "password", "email"). */
|
|
9
|
+
type,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<"input">) {
|
|
12
|
+
return (
|
|
13
|
+
<input
|
|
14
|
+
type={type}
|
|
15
|
+
data-slot="input"
|
|
16
|
+
className={cn(
|
|
17
|
+
"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
|
|
18
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
19
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
20
|
+
className
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Input }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cn } from "@shell/lib/utils"
|
|
2
|
+
|
|
3
|
+
/** Displays a keyboard shortcut or key in a styled inline badge. */
|
|
4
|
+
function Kbd({ className, ...props }: React.ComponentProps<"kbd">) {
|
|
5
|
+
return (
|
|
6
|
+
<kbd
|
|
7
|
+
data-slot="kbd"
|
|
8
|
+
className={cn(
|
|
9
|
+
"pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none",
|
|
10
|
+
"[&_svg:not([class*='size-'])]:size-3",
|
|
11
|
+
"[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Groups multiple Kbd elements with a separator, representing a key combination. */
|
|
20
|
+
function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
21
|
+
return (
|
|
22
|
+
<kbd
|
|
23
|
+
data-slot="kbd-group"
|
|
24
|
+
className={cn("inline-flex items-center gap-1", className)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { Kbd, KbdGroup }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Label as LabelPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@shell/lib/utils"
|
|
7
|
+
|
|
8
|
+
function Label({
|
|
9
|
+
/** Additional CSS class names to apply to the label. */
|
|
10
|
+
className,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
|
13
|
+
return (
|
|
14
|
+
<LabelPrimitive.Root
|
|
15
|
+
data-slot="label"
|
|
16
|
+
className={cn(
|
|
17
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { Label }
|