@rlx-ui/mcp 0.0.1 → 0.0.3

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.
@@ -0,0 +1,1353 @@
1
+ {
2
+ "widgets": [
3
+ {
4
+ "name": "Accordion",
5
+ "slug": "accordion",
6
+ "category": "widget",
7
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Accordion({\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Root>) {\n return <AccordionPrimitive.Root data-slot=\"accordion\" {...props} />;\n}\n\nfunction AccordionItem({\n className,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Item>) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\"border-b last:border-b-0\", className)}\n {...props}\n />\n );\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {\n return (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\n \"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronDownIcon className=\"text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n );\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof AccordionPrimitive.Content>) {\n return (\n <AccordionPrimitive.Content\n data-slot=\"accordion-content\"\n className=\"data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm\"\n {...props}\n >\n <div className={cn(\"pt-0 pb-4\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n );\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
8
+ "demos": [
9
+ {
10
+ "name": "default-expanded",
11
+ "code": "import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from \"@rlx-widgets/accordion\";\n\nexport const Preview = () => { \n return (\n <Accordion type=\"single\" defaultValue=\"item-1\" className=\"w-full\">\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Is it accessible?</AccordionTrigger>\n <AccordionContent>\n Yes. It adheres to the WAI-ARIA design pattern.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-2\">\n <AccordionTrigger>Is it unstyled?</AccordionTrigger>\n <AccordionContent>\n Yes. It&apos;s unstyled by default, giving you full control over the look\n and feel.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-3\">\n <AccordionTrigger>Can it be animated?</AccordionTrigger>\n <AccordionContent>\n Yes! You can animate the Accordion with CSS or a library of your\n choice.\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n );\n};\n"
12
+ },
13
+ {
14
+ "name": "default-expanded-multiple",
15
+ "code": "import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from \"@rlx-widgets/accordion\";\n\nexport const Preview = () => {\n return (\n <Accordion\n type=\"multiple\"\n defaultValue={[\"item-1\", \"item-2\"]}\n className=\"w-full\"\n >\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Is it accessible?</AccordionTrigger>\n <AccordionContent>\n Yes. It adheres to the WAI-ARIA design pattern.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-2\">\n <AccordionTrigger>Is it unstyled?</AccordionTrigger>\n <AccordionContent>\n Yes. It&apos;s unstyled by default, giving you full control over the look\n and feel.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-3\">\n <AccordionTrigger>Can it be animated?</AccordionTrigger>\n <AccordionContent>\n Yes! You can animate the Accordion with CSS or a library of your\n choice.\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n );\n};\n"
16
+ },
17
+ {
18
+ "name": "multiple",
19
+ "code": "import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from \"@rlx-widgets/accordion\";\n\nexport const Preview = () => {\n return (\n <Accordion type=\"multiple\" className=\"w-full\">\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Is it accessible?</AccordionTrigger>\n <AccordionContent>\n Yes. It adheres to the WAI-ARIA design pattern.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-2\">\n <AccordionTrigger>Is it unstyled?</AccordionTrigger>\n <AccordionContent>\n Yes. It&apos;s unstyled by default, giving you full control over the look\n and feel.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-3\">\n <AccordionTrigger>Can it be animated?</AccordionTrigger>\n <AccordionContent>\n Yes! You can animate the Accordion with CSS or a library of your\n choice.\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n );\n};\n"
20
+ },
21
+ {
22
+ "name": "single",
23
+ "code": "import {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from \"@rlx-widgets/accordion\";\n\nexport const Preview = () => {\n return (\n <Accordion type=\"single\" collapsible className=\"w-full\">\n <AccordionItem value=\"item-1\">\n <AccordionTrigger>Is it accessible?</AccordionTrigger>\n <AccordionContent>\n Yes. It adheres to the WAI-ARIA design pattern.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-2\">\n <AccordionTrigger>Is it unstyled?</AccordionTrigger>\n <AccordionContent>\n Yes. It&apos;s unstyled by default, giving you full control over the look\n and feel.\n </AccordionContent>\n </AccordionItem>\n <AccordionItem value=\"item-3\">\n <AccordionTrigger>Can it be animated?</AccordionTrigger>\n <AccordionContent>\n Yes! You can animate the Accordion with CSS or a library of your\n choice.\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n );\n};\n"
24
+ }
25
+ ]
26
+ },
27
+ {
28
+ "name": "Alert",
29
+ "slug": "alert",
30
+ "category": "widget",
31
+ "sourceCode": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@rlx-widgets/base\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current\",\n {\n variants: {\n variant: {\n default: \"bg-card text-card-foreground\",\n destructive:\n \"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction Alert({\n className,\n variant,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof alertVariants>) {\n return (\n <div\n data-slot=\"alert\"\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nfunction AlertTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-title\"\n className={cn(\n \"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDescription({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-description\"\n className={cn(\n \"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Alert, AlertTitle, AlertDescription };\n",
32
+ "demos": [
33
+ {
34
+ "name": "error",
35
+ "code": "import { Alert, AlertDescription, AlertTitle } from \"@rlx-widgets/alert\";\nimport { AlertCircleIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <Alert variant=\"destructive\">\n <AlertCircleIcon />\n <AlertTitle>Unable to process your payment.</AlertTitle>\n <AlertDescription>\n <p>Please verify your billing information and try again.</p>\n <ul className=\"list-inside list-disc text-sm\">\n <li>Check your card details</li>\n <li>Ensure sufficient funds</li>\n <li>Verify billing address</li>\n </ul>\n </AlertDescription>\n </Alert>\n );\n};\n"
36
+ },
37
+ {
38
+ "name": "title",
39
+ "code": "import { Alert, AlertTitle } from \"@rlx-widgets/alert\";\nimport { PopcornIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <Alert>\n <PopcornIcon />\n <AlertTitle>\n This Alert has a title and an icon. No description.\n </AlertTitle>\n </Alert>\n );\n};\n"
40
+ },
41
+ {
42
+ "name": "with-subtitle",
43
+ "code": "import { Alert, AlertDescription, AlertTitle } from \"@rlx-widgets/alert\";\nimport { CheckCircle2Icon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <Alert>\n <CheckCircle2Icon />\n <AlertTitle>Success! Your changes have been saved</AlertTitle>\n <AlertDescription>\n This is an alert with icon, title and description.\n </AlertDescription>\n </Alert>\n );\n};\n"
44
+ }
45
+ ]
46
+ },
47
+ {
48
+ "name": "Alert Dialog",
49
+ "slug": "alert-dialog",
50
+ "category": "widget",
51
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { buttonVariants } from \"@rlx-widgets/button\";\n\nfunction AlertDialog({\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {\n return <AlertDialogPrimitive.Root data-slot=\"alert-dialog\" {...props} />;\n}\n\nfunction AlertDialogTrigger({\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\n return (\n <AlertDialogPrimitive.Trigger data-slot=\"alert-dialog-trigger\" {...props} />\n );\n}\n\nfunction AlertDialogPortal({\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {\n return (\n <AlertDialogPrimitive.Portal data-slot=\"alert-dialog-portal\" {...props} />\n );\n}\n\nfunction AlertDialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {\n return (\n <AlertDialogPrimitive.Overlay\n data-slot=\"alert-dialog-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogContent({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n data-slot=\"alert-dialog-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 p-6 shadow-lg duration-200 sm:max-w-lg\",\n className\n )}\n {...props}\n />\n </AlertDialogPortal>\n );\n}\n\nfunction AlertDialogHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-header\"\n className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"alert-dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction AlertDialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return (\n <AlertDialogPrimitive.Title\n data-slot=\"alert-dialog-title\"\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return (\n <AlertDialogPrimitive.Description\n data-slot=\"alert-dialog-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogAction({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {\n return (\n <AlertDialogPrimitive.Action\n className={cn(buttonVariants(), className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogCancel({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {\n return (\n <AlertDialogPrimitive.Cancel\n className={cn(buttonVariants({ variant: \"outline\" }), className)}\n {...props}\n />\n );\n}\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
52
+ "demos": [
53
+ {
54
+ "name": "default",
55
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"@rlx-widgets/alert-dialog\";\n\nexport const Preview = () => {\n return (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"outline\">Show Dialog</Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>\n <AlertDialogDescription>\n This action cannot be undone. This will permanently delete your\n account and remove your data from our servers.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction>Continue</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n );\n};\n"
56
+ }
57
+ ]
58
+ },
59
+ {
60
+ "name": "Aspect Ratio",
61
+ "slug": "aspect-ratio",
62
+ "category": "widget",
63
+ "sourceCode": "\"use client\";\n\nimport * as AspectRatioPrimitive from \"@radix-ui/react-aspect-ratio\";\n\nfunction AspectRatio({\n ...props\n}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {\n return <AspectRatioPrimitive.Root data-slot=\"aspect-ratio\" {...props} />;\n}\n\nexport { AspectRatio };\n",
64
+ "demos": [
65
+ {
66
+ "name": "default",
67
+ "code": "import Image from \"next/image\";\nimport { AspectRatio } from \"@rlx-widgets/aspect-ratio\";\n\nexport const Preview = () => {\n return (\n <AspectRatio ratio={16 / 9} className=\"bg-muted rounded-lg\">\n <Image\n src=\"https://images.unsplash.com/photo-1588345921523-c2dcdb7f1dcd?w=800&dpr=2&q=80\"\n alt=\"Photo by Drew Beamer\"\n fill\n className=\"h-full w-full rounded-lg object-cover dark:brightness-[0.2] dark:grayscale\"\n />\n </AspectRatio>\n );\n};\n"
68
+ }
69
+ ]
70
+ },
71
+ {
72
+ "name": "Avatar",
73
+ "slug": "avatar",
74
+ "category": "widget",
75
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as AvatarPrimitive from \"@radix-ui/react-avatar\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Avatar({\n className,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Root>) {\n return (\n <AvatarPrimitive.Root\n data-slot=\"avatar\"\n className={cn(\n \"relative flex size-8 shrink-0 overflow-hidden rounded-full\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction AvatarImage({\n className,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Image>) {\n return (\n <AvatarPrimitive.Image\n data-slot=\"avatar-image\"\n className={cn(\"aspect-square size-full\", className)}\n {...props}\n />\n );\n}\n\nfunction AvatarFallback({\n className,\n ...props\n}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {\n return (\n <AvatarPrimitive.Fallback\n data-slot=\"avatar-fallback\"\n className={cn(\n \"bg-muted flex size-full items-center justify-center rounded-full\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Avatar, AvatarImage, AvatarFallback };\n",
76
+ "demos": [
77
+ {
78
+ "name": "custom-rounded",
79
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\n\nexport const Preview = () => {\n return (\n <Avatar className=\"rounded-lg\">\n <AvatarImage src=\"https://github.com/evilrabbit.png\" alt=\"@evilrabbit\" />\n <AvatarFallback>ER</AvatarFallback>\n </Avatar>\n );\n};\n"
80
+ },
81
+ {
82
+ "name": "default",
83
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\n\nexport const Preview = () => {\n return (\n <Avatar>\n <AvatarImage src=\"https://github.com/shadcn.png\" alt=\"@shadcn\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n );\n};\n"
84
+ },
85
+ {
86
+ "name": "stacked",
87
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\n\nexport const Preview = () => {\n return (\n <div className=\"*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale\">\n <Avatar>\n <AvatarImage src=\"https://github.com/shadcn.png\" alt=\"@shadcn\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n <Avatar>\n <AvatarImage src=\"https://github.com/leerob.png\" alt=\"@leerob\" />\n <AvatarFallback>LR</AvatarFallback>\n </Avatar>\n <Avatar>\n <AvatarImage\n src=\"https://github.com/evilrabbit.png\"\n alt=\"@evilrabbit\"\n />\n <AvatarFallback>ER</AvatarFallback>\n </Avatar>\n </div>\n );\n};\n"
88
+ }
89
+ ]
90
+ },
91
+ {
92
+ "name": "Badge",
93
+ "slug": "badge",
94
+ "category": "widget",
95
+ "sourceCode": "import * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nconst badgeVariants = cva(\n \"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden\",\n {\n variants: {\n variant: {\n default:\n \"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90\",\n secondary:\n \"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90\",\n destructive:\n \"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction Badge({\n className,\n variant,\n asChild = false,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"span\";\n\n return (\n <Comp\n data-slot=\"badge\"\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n );\n}\n\nexport { Badge, badgeVariants };\n",
96
+ "demos": [
97
+ {
98
+ "name": "default",
99
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return <Badge>Badge</Badge>;\n};\n"
100
+ },
101
+ {
102
+ "name": "destructive",
103
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return <Badge variant=\"destructive\">Destructive</Badge>;\n};\n"
104
+ },
105
+ {
106
+ "name": "double-digit",
107
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return (\n <Badge\n className=\"h-5 min-w-5 rounded-full px-1 font-mono tabular-nums\"\n variant=\"destructive\"\n >\n 99\n </Badge>\n );\n};\n"
108
+ },
109
+ {
110
+ "name": "double-digit-plus",
111
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return (\n <Badge\n className=\"h-5 min-w-5 rounded-full px-1 font-mono tabular-nums\"\n variant=\"outline\"\n >\n 20+\n </Badge>\n );\n};\n"
112
+ },
113
+ {
114
+ "name": "outline",
115
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return <Badge variant=\"outline\">Outline</Badge>;\n};\n"
116
+ },
117
+ {
118
+ "name": "secondary",
119
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return <Badge variant=\"secondary\">Secondary</Badge>;\n};\n"
120
+ },
121
+ {
122
+ "name": "single-digit",
123
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return (\n <Badge className=\"h-5 min-w-5 rounded-full px-1 font-mono tabular-nums\">\n 8\n </Badge>\n );\n};\n"
124
+ },
125
+ {
126
+ "name": "with-icon",
127
+ "code": "import { BadgeCheckIcon } from \"lucide-react\";\nimport { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n return (\n <Badge\n variant=\"secondary\"\n className=\"bg-blue-500 text-white dark:bg-blue-600\"\n >\n <BadgeCheckIcon />\n Verified\n </Badge>\n );\n};\n"
128
+ }
129
+ ]
130
+ },
131
+ {
132
+ "name": "Breadcrumb",
133
+ "slug": "breadcrumb",
134
+ "category": "widget",
135
+ "sourceCode": "import * as React from \"react\";\nimport { ChevronRight, MoreHorizontal } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Slot } from \"@radix-ui/react-slot\";\n\nfunction Breadcrumb({ ...props }: React.ComponentProps<\"nav\">) {\n return <nav aria-label=\"breadcrumb\" data-slot=\"breadcrumb\" {...props} />;\n}\n\nfunction BreadcrumbList({ className, ...props }: React.ComponentProps<\"ol\">) {\n return (\n <ol\n data-slot=\"breadcrumb-list\"\n className={cn(\n \"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbItem({ className, ...props }: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-item\"\n className={cn(\"inline-flex items-center gap-1.5\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbLink({\n asChild,\n className,\n ...props\n}: React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n}) {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n data-slot=\"breadcrumb-link\"\n className={cn(\"hover:text-foreground transition-colors\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbPage({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn(\"text-foreground font-normal\", className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"[&>svg]:size-3.5\", className)}\n {...props}\n >\n {children ?? <ChevronRight />}\n </li>\n );\n}\n\nfunction BreadcrumbEllipsis({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"flex size-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">More</span>\n </span>\n );\n}\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n};\n",
136
+ "demos": [
137
+ {
138
+ "name": "collapsed",
139
+ "code": "import Link from \"next/link\";\n\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@rlx-widgets/breadcrumb\";\n\nexport const Preview = () => {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbEllipsis />\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/docs/components\">Components</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n );\n};\n"
140
+ },
141
+ {
142
+ "name": "custom-separator",
143
+ "code": "import Link from \"next/link\";\nimport { SlashIcon } from \"lucide-react\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@rlx-widgets/breadcrumb\";\n\nexport const Preview = () => {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <SlashIcon />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/components\">Components</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <SlashIcon />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n );\n};\n"
144
+ },
145
+ {
146
+ "name": "default",
147
+ "code": "import Link from \"next/link\";\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@rlx-widgets/breadcrumb\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nexport const Preview = () => {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger className=\"flex items-center gap-1\">\n <BreadcrumbEllipsis className=\"size-4\" />\n <span className=\"sr-only\">Toggle menu</span>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuItem>Documentation</DropdownMenuItem>\n <DropdownMenuItem>Themes</DropdownMenuItem>\n <DropdownMenuItem>GitHub</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/docs/components\">Components</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n );\n};\n"
148
+ },
149
+ {
150
+ "name": "dropdown",
151
+ "code": "import Link from \"next/link\";\nimport { ChevronDownIcon, SlashIcon } from \"lucide-react\";\n\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@rlx-widgets/breadcrumb\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nexport const Preview = () => {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <SlashIcon />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <DropdownMenu>\n <DropdownMenuTrigger className=\"flex items-center gap-1 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5\">\n Components\n <ChevronDownIcon />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n <DropdownMenuItem>Documentation</DropdownMenuItem>\n <DropdownMenuItem>Themes</DropdownMenuItem>\n <DropdownMenuItem>GitHub</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </BreadcrumbItem>\n <BreadcrumbSeparator>\n <SlashIcon />\n </BreadcrumbSeparator>\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n );\n};\n"
152
+ },
153
+ {
154
+ "name": "link-component",
155
+ "code": "import Link from \"next/link\"\n\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@rlx-widgets/breadcrumb\"\n\nexport const Preview = () => {\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/\">Home</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href=\"/components\">Components</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n <BreadcrumbItem>\n <BreadcrumbPage>Breadcrumb</BreadcrumbPage>\n </BreadcrumbItem>\n </BreadcrumbList>\n </Breadcrumb>\n )\n}\n"
156
+ },
157
+ {
158
+ "name": "responsive",
159
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport Link from \"next/link\";\nimport { useMediaQuery } from \"rlx-hooks\";\nimport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@rlx-widgets/breadcrumb\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Drawer,\n DrawerClose,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n DrawerTrigger,\n} from \"@rlx-widgets/drawer\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nconst items = [\n { href: \"#\", label: \"Home\" },\n { href: \"#\", label: \"Documentation\" },\n { href: \"#\", label: \"Building Your Application\" },\n { href: \"#\", label: \"Data Fetching\" },\n { label: \"Caching and Revalidating\" },\n];\n\nconst ITEMS_TO_DISPLAY = 3;\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const isDesktop = useMediaQuery(\"(min-width: 768px)\");\n\n return (\n <Breadcrumb>\n <BreadcrumbList>\n <BreadcrumbItem>\n <BreadcrumbLink asChild>\n <Link href={items[0].href ?? \"/\"}>{items[0].label}</Link>\n </BreadcrumbLink>\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n {items.length > ITEMS_TO_DISPLAY ? (\n <>\n <BreadcrumbItem>\n {isDesktop ? (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger\n className=\"flex items-center gap-1\"\n aria-label=\"Toggle menu\"\n >\n <BreadcrumbEllipsis className=\"size-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {items.slice(1, -2).map((item, index) => (\n <DropdownMenuItem key={index}>\n <Link href={item.href ? item.href : \"#\"}>\n {item.label}\n </Link>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : (\n <Drawer open={open} onOpenChange={setOpen}>\n <DrawerTrigger aria-label=\"Toggle Menu\">\n <BreadcrumbEllipsis className=\"h-4 w-4\" />\n </DrawerTrigger>\n <DrawerContent>\n <DrawerHeader className=\"text-left\">\n <DrawerTitle>Navigate to</DrawerTitle>\n <DrawerDescription>\n Select a page to navigate to.\n </DrawerDescription>\n </DrawerHeader>\n <div className=\"grid gap-1 px-4\">\n {items.slice(1, -2).map((item, index) => (\n <Link\n key={index}\n href={item.href ? item.href : \"#\"}\n className=\"py-1 text-sm\"\n >\n {item.label}\n </Link>\n ))}\n </div>\n <DrawerFooter className=\"pt-4\">\n <DrawerClose asChild>\n <Button variant=\"outline\">Close</Button>\n </DrawerClose>\n </DrawerFooter>\n </DrawerContent>\n </Drawer>\n )}\n </BreadcrumbItem>\n <BreadcrumbSeparator />\n </>\n ) : null}\n {items.slice(-ITEMS_TO_DISPLAY + 1).map((item, index) => (\n <BreadcrumbItem key={index}>\n {item.href ? (\n <>\n <BreadcrumbLink\n asChild\n className=\"max-w-20 truncate md:max-w-none\"\n >\n <Link href={item.href}>{item.label}</Link>\n </BreadcrumbLink>\n <BreadcrumbSeparator />\n </>\n ) : (\n <BreadcrumbPage className=\"max-w-20 truncate md:max-w-none\">\n {item.label}\n </BreadcrumbPage>\n )}\n </BreadcrumbItem>\n ))}\n </BreadcrumbList>\n </Breadcrumb>\n );\n};\n"
160
+ }
161
+ ]
162
+ },
163
+ {
164
+ "name": "Button",
165
+ "slug": "button",
166
+ "category": "widget",
167
+ "sourceCode": "import * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-pointer\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-lg\": \"size-10\",\n \"icon-sm\": \"size-8\",\n \"icon-xs\": \"size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\nexport { Button, buttonVariants };\n",
168
+ "demos": [
169
+ {
170
+ "name": "default",
171
+ "code": "import { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-wrap items-center gap-2 md:flex-row\">\n <Button>Button</Button>\n </div>\n );\n};\n"
172
+ },
173
+ {
174
+ "name": "destructive",
175
+ "code": "import { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return <Button variant=\"destructive\">Destructive</Button>;\n};\n"
176
+ },
177
+ {
178
+ "name": "ghost",
179
+ "code": "import { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return <Button variant=\"ghost\">Ghost</Button>;\n};\n"
180
+ },
181
+ {
182
+ "name": "icon",
183
+ "code": "import { ChevronRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return (\n <Button variant=\"secondary\" size=\"icon\" className=\"size-8\">\n <ChevronRightIcon />\n </Button>\n );\n};\n"
184
+ },
185
+ {
186
+ "name": "icon-with-text",
187
+ "code": "import { ChevronRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return (\n <Button variant=\"outline\" size=\"sm\">\n <ChevronRightIcon /> Go Right\n </Button>\n );\n};\n"
188
+ },
189
+ {
190
+ "name": "link",
191
+ "code": "import { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return <Button variant=\"link\">Link</Button>;\n};\n"
192
+ },
193
+ {
194
+ "name": "link-button",
195
+ "code": "import Link from \"next/link\";\nimport { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return (\n <Button asChild>\n <Link href=\"/login\">Login</Link>\n </Button>\n );\n};\n"
196
+ },
197
+ {
198
+ "name": "loading",
199
+ "code": "import { Loader2Icon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return (\n <Button size=\"sm\" disabled>\n <Loader2Icon className=\"animate-spin\" />\n Please wait\n </Button>\n );\n};\n"
200
+ },
201
+ {
202
+ "name": "outline",
203
+ "code": "import { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return <Button variant=\"outline\">Outline</Button>;\n};\n"
204
+ },
205
+ {
206
+ "name": "secondary",
207
+ "code": "import { Button } from \"@rlx-widgets/button\";\n\nexport const Preview = () => {\n return <Button variant=\"secondary\">Secondary</Button>;\n};\n"
208
+ }
209
+ ]
210
+ },
211
+ {
212
+ "name": "Button Group",
213
+ "slug": "button-group",
214
+ "category": "widget",
215
+ "sourceCode": "import { cn } from \"@rlx-widgets/base\";\nimport { Separator } from \"@rlx-widgets/separator\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nconst buttonGroupVariants = cva(\n \"flex w-fit items-stretch [&>*]:focus-visible:z-10 [&>*]:focus-visible:relative [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md has-[>[data-slot=button-group]]:gap-2\",\n {\n variants: {\n orientation: {\n horizontal:\n \"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none\",\n vertical:\n \"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none\",\n },\n },\n defaultVariants: {\n orientation: \"horizontal\",\n },\n }\n);\n\nfunction ButtonGroup({\n className,\n orientation,\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof buttonGroupVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"button-group\"\n data-orientation={orientation}\n className={cn(buttonGroupVariants({ orientation }), className)}\n {...props}\n />\n );\n}\n\nfunction ButtonGroupText({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n asChild?: boolean;\n}) {\n const Comp = asChild ? Slot : \"div\";\n\n return (\n <Comp\n className={cn(\n \"bg-muted flex items-center gap-2 rounded-md border px-4 text-sm font-medium shadow-xs [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ButtonGroupSeparator({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"button-group-separator\"\n orientation={orientation}\n className={cn(\n \"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n ButtonGroup,\n ButtonGroupSeparator,\n ButtonGroupText,\n buttonGroupVariants,\n};\n",
216
+ "demos": [
217
+ {
218
+ "name": "default",
219
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n ArchiveIcon,\n ArrowLeftIcon,\n CalendarPlusIcon,\n ClockIcon,\n ListFilterPlusIcon,\n MailCheckIcon,\n MoreHorizontalIcon,\n TagIcon,\n Trash2Icon,\n} from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nexport const Preview = () => {\n const [label, setLabel] = React.useState(\"personal\");\n\n return (\n <ButtonGroup>\n <ButtonGroup className=\"hidden sm:flex\">\n <Button variant=\"outline\" size=\"icon\" aria-label=\"Go Back\">\n <ArrowLeftIcon />\n </Button>\n </ButtonGroup>\n <ButtonGroup>\n <Button variant=\"outline\">Archive</Button>\n <Button variant=\"outline\">Report</Button>\n </ButtonGroup>\n <ButtonGroup>\n <Button variant=\"outline\">Snooze</Button>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"icon\" aria-label=\"More Options\">\n <MoreHorizontalIcon />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-52\">\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <MailCheckIcon />\n Mark as Read\n </DropdownMenuItem>\n <DropdownMenuItem>\n <ArchiveIcon />\n Archive\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <ClockIcon />\n Snooze\n </DropdownMenuItem>\n <DropdownMenuItem>\n <CalendarPlusIcon />\n Add to Calendar\n </DropdownMenuItem>\n <DropdownMenuItem>\n <ListFilterPlusIcon />\n Add to List\n </DropdownMenuItem>\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>\n <TagIcon />\n Label As...\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent>\n <DropdownMenuRadioGroup\n value={label}\n onValueChange={setLabel}\n >\n <DropdownMenuRadioItem value=\"personal\">\n Personal\n </DropdownMenuRadioItem>\n <DropdownMenuRadioItem value=\"work\">\n Work\n </DropdownMenuRadioItem>\n <DropdownMenuRadioItem value=\"other\">\n Other\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem variant=\"destructive\">\n <Trash2Icon />\n Trash\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </ButtonGroup>\n </ButtonGroup>\n );\n};\n"
220
+ },
221
+ {
222
+ "name": "dropdown-menu",
223
+ "code": "\"use client\";\n\nimport {\n AlertTriangleIcon,\n CheckIcon,\n ChevronDownIcon,\n CopyIcon,\n ShareIcon,\n TrashIcon,\n UserRoundXIcon,\n VolumeOffIcon,\n} from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup>\n <Button variant=\"outline\">Follow</Button>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" className=\"!pl-2\">\n <ChevronDownIcon />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"[--radius:1rem]\">\n <DropdownMenuGroup>\n <DropdownMenuItem>\n <VolumeOffIcon />\n Mute Conversation\n </DropdownMenuItem>\n <DropdownMenuItem>\n <CheckIcon />\n Mark as Read\n </DropdownMenuItem>\n <DropdownMenuItem>\n <AlertTriangleIcon />\n Report Conversation\n </DropdownMenuItem>\n <DropdownMenuItem>\n <UserRoundXIcon />\n Block User\n </DropdownMenuItem>\n <DropdownMenuItem>\n <ShareIcon />\n Share Conversation\n </DropdownMenuItem>\n <DropdownMenuItem>\n <CopyIcon />\n Copy Conversation\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem variant=\"destructive\">\n <TrashIcon />\n Delete Conversation\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </ButtonGroup>\n );\n};\n"
224
+ },
225
+ {
226
+ "name": "input",
227
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { SearchIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup>\n <Input placeholder=\"Search...\" />\n <Button variant=\"outline\" aria-label=\"Search\">\n <SearchIcon />\n </Button>\n </ButtonGroup>\n );\n};\n"
228
+ },
229
+ {
230
+ "name": "input-group",
231
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { AudioLinesIcon, PlusIcon } from \"lucide-react\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@rlx-widgets/tooltip\";\n\nexport const Preview = () => {\n const [voiceEnabled, setVoiceEnabled] = React.useState(false);\n\n return (\n <ButtonGroup className=\"[--radius:9999rem]\">\n <ButtonGroup>\n <Button variant=\"outline\" size=\"icon\">\n <PlusIcon />\n </Button>\n </ButtonGroup>\n <ButtonGroup>\n <InputGroup>\n <InputGroupInput\n placeholder={\n voiceEnabled ? \"Record and send audio...\" : \"Send a message...\"\n }\n disabled={voiceEnabled}\n />\n <InputGroupAddon align=\"inline-end\">\n <Tooltip>\n <TooltipTrigger asChild>\n <InputGroupButton\n onClick={() => setVoiceEnabled(!voiceEnabled)}\n size=\"icon-xs\"\n data-active={voiceEnabled}\n className=\"data-[active=true]:bg-orange-100 data-[active=true]:text-orange-700 dark:data-[active=true]:bg-orange-800 dark:data-[active=true]:text-orange-100\"\n aria-pressed={voiceEnabled}\n >\n <AudioLinesIcon />\n </InputGroupButton>\n </TooltipTrigger>\n <TooltipContent>Voice Mode</TooltipContent>\n </Tooltip>\n </InputGroupAddon>\n </InputGroup>\n </ButtonGroup>\n </ButtonGroup>\n );\n};\n"
232
+ },
233
+ {
234
+ "name": "nested",
235
+ "code": "\"use client\";\n\nimport { ArrowLeftIcon, ArrowRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup>\n <ButtonGroup>\n <Button variant=\"outline\" size=\"sm\">\n 1\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n 2\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n 3\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n 4\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n 5\n </Button>\n </ButtonGroup>\n <ButtonGroup>\n <Button variant=\"outline\" size=\"icon-sm\" aria-label=\"Previous\">\n <ArrowLeftIcon />\n </Button>\n <Button variant=\"outline\" size=\"icon-sm\" aria-label=\"Next\">\n <ArrowRightIcon />\n </Button>\n </ButtonGroup>\n </ButtonGroup>\n );\n};\n"
236
+ },
237
+ {
238
+ "name": "orientation",
239
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport { MinusIcon, PlusIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup\n orientation=\"vertical\"\n aria-label=\"Media controls\"\n className=\"h-fit\"\n >\n <Button variant=\"outline\" size=\"icon\">\n <PlusIcon />\n </Button>\n <Button variant=\"outline\" size=\"icon\">\n <MinusIcon />\n </Button>\n </ButtonGroup>\n );\n};\n"
240
+ },
241
+ {
242
+ "name": "popover",
243
+ "code": "import { BotIcon, ChevronDownIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport { Separator } from \"@rlx-widgets/separator\";\nimport { Textarea } from \"@rlx-widgets/textarea\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup>\n <Button variant=\"outline\">\n <BotIcon /> Copilot\n </Button>\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" size=\"icon\" aria-label=\"Open Popover\">\n <ChevronDownIcon />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"rounded-xl p-0 text-sm\">\n <div className=\"px-4 py-3\">\n <div className=\"text-sm font-medium\">Agent Tasks</div>\n </div>\n <Separator />\n <div className=\"p-4 text-sm *:[p:not(:last-child)]:mb-2\">\n <Textarea\n placeholder=\"Describe your task in natural language.\"\n className=\"mb-4 resize-none\"\n />\n <p className=\"font-medium\">Start a new task with Copilot</p>\n <p className=\"text-muted-foreground\">\n Describe your task in natural language. Copilot will work in the\n background and open a pull request for your review.\n </p>\n </div>\n </PopoverContent>\n </Popover>\n </ButtonGroup>\n );\n};\n"
244
+ },
245
+ {
246
+ "name": "select",
247
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { ArrowRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Select, SelectContent, SelectItem, SelectTrigger } from \"@rlx-widgets/select\";\n\nconst CURRENCIES = [\n {\n value: \"$\",\n label: \"US Dollar\",\n },\n {\n value: \"€\",\n label: \"Euro\",\n },\n {\n value: \"£\",\n label: \"British Pound\",\n },\n];\n\nexport const Preview = () => {\n const [currency, setCurrency] = React.useState(\"$\");\n\n return (\n <ButtonGroup>\n <ButtonGroup>\n <Select value={currency} onValueChange={setCurrency}>\n <SelectTrigger className=\"font-mono\">{currency}</SelectTrigger>\n <SelectContent className=\"min-w-24\">\n {CURRENCIES.map((currency) => (\n <SelectItem key={currency.value} value={currency.value}>\n {currency.value}{\" \"}\n <span className=\"text-muted-foreground\">{currency.label}</span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Input placeholder=\"10.00\" pattern=\"[0-9]*\" />\n </ButtonGroup>\n <ButtonGroup>\n <Button aria-label=\"Send\" size=\"icon\" variant=\"outline\">\n <ArrowRightIcon />\n </Button>\n </ButtonGroup>\n </ButtonGroup>\n );\n};\n"
248
+ },
249
+ {
250
+ "name": "separator",
251
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup, ButtonGroupSeparator } from \"@rlx-widgets/button-group\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup>\n <Button variant=\"secondary\" size=\"sm\">\n Copy\n </Button>\n <ButtonGroupSeparator />\n <Button variant=\"secondary\" size=\"sm\">\n Paste\n </Button>\n </ButtonGroup>\n );\n};\n"
252
+ },
253
+ {
254
+ "name": "size",
255
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport { PlusIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-col items-start gap-8\">\n <ButtonGroup>\n <Button variant=\"outline\" size=\"sm\">\n Small\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n Button\n </Button>\n <Button variant=\"outline\" size=\"sm\">\n Group\n </Button>\n <Button variant=\"outline\" size=\"icon-sm\">\n <PlusIcon />\n </Button>\n </ButtonGroup>\n <ButtonGroup>\n <Button variant=\"outline\">Default</Button>\n <Button variant=\"outline\">Button</Button>\n <Button variant=\"outline\">Group</Button>\n <Button variant=\"outline\" size=\"icon\">\n <PlusIcon />\n </Button>\n </ButtonGroup>\n <ButtonGroup>\n <Button variant=\"outline\" size=\"lg\">\n Large\n </Button>\n <Button variant=\"outline\" size=\"lg\">\n Button\n </Button>\n <Button variant=\"outline\" size=\"lg\">\n Group\n </Button>\n <Button variant=\"outline\" size=\"icon-lg\">\n <PlusIcon />\n </Button>\n </ButtonGroup>\n </div>\n );\n};\n"
256
+ },
257
+ {
258
+ "name": "split",
259
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Plus } from \"lucide-react\";\nimport { ButtonGroup, ButtonGroupSeparator } from \"@rlx-widgets/button-group\";\n\nexport const Preview = () => {\n return (\n <ButtonGroup>\n <Button variant=\"secondary\">Button</Button>\n <ButtonGroupSeparator />\n <Button size=\"icon\" variant=\"secondary\">\n <Plus />\n </Button>\n </ButtonGroup>\n );\n};\n"
260
+ }
261
+ ]
262
+ },
263
+ {
264
+ "name": "Calendar",
265
+ "slug": "calendar",
266
+ "category": "widget",
267
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n} from \"lucide-react\";\nimport { DayButton, DayPicker, getDefaultClassNames } from \"react-day-picker\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Button, buttonVariants } from \"@rlx-widgets/button\";\n\nfunction Calendar({\n className,\n classNames,\n showOutsideDays = true,\n captionLayout = \"label\",\n buttonVariant = \"ghost\",\n formatters,\n components,\n ...props\n}: React.ComponentProps<typeof DayPicker> & {\n buttonVariant?: React.ComponentProps<typeof Button>[\"variant\"];\n}) {\n const defaultClassNames = getDefaultClassNames();\n\n return (\n <DayPicker\n showOutsideDays={showOutsideDays}\n className={cn(\n \"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent\",\n String.raw`rtl:**:[.rdp-button\\_next>svg]:rotate-180`,\n String.raw`rtl:**:[.rdp-button\\_previous>svg]:rotate-180`,\n className\n )}\n captionLayout={captionLayout}\n formatters={{\n formatMonthDropdown: (date) =>\n date.toLocaleString(\"default\", { month: \"short\" }),\n ...formatters,\n }}\n classNames={{\n root: cn(\"w-fit\", defaultClassNames.root),\n months: cn(\n \"flex gap-4 flex-col md:flex-row relative\",\n defaultClassNames.months\n ),\n month: cn(\"flex flex-col w-full gap-4\", defaultClassNames.month),\n nav: cn(\n \"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between\",\n defaultClassNames.nav\n ),\n button_previous: cn(\n buttonVariants({ variant: buttonVariant }),\n \"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none\",\n defaultClassNames.button_previous\n ),\n button_next: cn(\n buttonVariants({ variant: buttonVariant }),\n \"size-(--cell-size) aria-disabled:opacity-50 p-0 select-none\",\n defaultClassNames.button_next\n ),\n month_caption: cn(\n \"flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)\",\n defaultClassNames.month_caption\n ),\n dropdowns: cn(\n \"w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5\",\n defaultClassNames.dropdowns\n ),\n dropdown_root: cn(\n \"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md\",\n defaultClassNames.dropdown_root\n ),\n dropdown: cn(\n \"absolute bg-popover inset-0 opacity-0\",\n defaultClassNames.dropdown\n ),\n caption_label: cn(\n \"select-none font-medium\",\n captionLayout === \"label\"\n ? \"text-sm\"\n : \"rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5\",\n defaultClassNames.caption_label\n ),\n table: \"w-full border-collapse\",\n weekdays: cn(\"flex\", defaultClassNames.weekdays),\n weekday: cn(\n \"text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none\",\n defaultClassNames.weekday\n ),\n week: cn(\"flex w-full mt-2\", defaultClassNames.week),\n week_number_header: cn(\n \"select-none w-(--cell-size)\",\n defaultClassNames.week_number_header\n ),\n week_number: cn(\n \"text-[0.8rem] select-none text-muted-foreground\",\n defaultClassNames.week_number\n ),\n day: cn(\n \"relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none\",\n defaultClassNames.day\n ),\n range_start: cn(\n \"rounded-l-md bg-accent\",\n defaultClassNames.range_start\n ),\n range_middle: cn(\"rounded-none\", defaultClassNames.range_middle),\n range_end: cn(\"rounded-r-md bg-accent\", defaultClassNames.range_end),\n today: cn(\n \"bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none\",\n defaultClassNames.today\n ),\n outside: cn(\n \"text-muted-foreground aria-selected:text-muted-foreground\",\n defaultClassNames.outside\n ),\n disabled: cn(\n \"text-muted-foreground opacity-50\",\n defaultClassNames.disabled\n ),\n hidden: cn(\"invisible\", defaultClassNames.hidden),\n ...classNames,\n }}\n components={{\n Root: ({ className, rootRef, ...props }) => {\n return (\n <div\n data-slot=\"calendar\"\n ref={rootRef}\n className={cn(className)}\n {...props}\n />\n );\n },\n Chevron: ({ className, orientation, ...props }) => {\n if (orientation === \"left\") {\n return (\n <ChevronLeftIcon className={cn(\"size-4\", className)} {...props} />\n );\n }\n\n if (orientation === \"right\") {\n return (\n <ChevronRightIcon\n className={cn(\"size-4\", className)}\n {...props}\n />\n );\n }\n\n return (\n <ChevronDownIcon className={cn(\"size-4\", className)} {...props} />\n );\n },\n DayButton: CalendarDayButton,\n WeekNumber: ({ children, ...props }) => {\n return (\n <td {...props}>\n <div className=\"flex size-(--cell-size) items-center justify-center text-center\">\n {children}\n </div>\n </td>\n );\n },\n ...components,\n }}\n {...props}\n />\n );\n}\n\nfunction CalendarDayButton({\n className,\n day,\n modifiers,\n ...props\n}: React.ComponentProps<typeof DayButton>) {\n const defaultClassNames = getDefaultClassNames();\n\n const ref = React.useRef<HTMLButtonElement>(null);\n React.useEffect(() => {\n if (modifiers.focused) ref.current?.focus();\n }, [modifiers.focused]);\n\n return (\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"icon\"\n data-day={day.date.toLocaleDateString()}\n data-selected-single={\n modifiers.selected &&\n !modifiers.range_start &&\n !modifiers.range_end &&\n !modifiers.range_middle\n }\n data-range-start={modifiers.range_start}\n data-range-end={modifiers.range_end}\n data-range-middle={modifiers.range_middle}\n className={cn(\n \"data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70\",\n defaultClassNames.day,\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Calendar, CalendarDayButton };\n",
268
+ "demos": [
269
+ {
270
+ "name": "date-and-time-picker",
271
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const [date, setDate] = React.useState<Date | undefined>(undefined);\n\n return (\n <div className=\"flex gap-4\">\n <div className=\"flex flex-col gap-3\">\n <Label htmlFor=\"date-picker\" className=\"px-1\">\n Date\n </Label>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n id=\"date-picker\"\n className=\"w-32 justify-between font-normal\"\n >\n {date ? date.toLocaleDateString() : \"Select date\"}\n <ChevronDownIcon />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto overflow-hidden p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={date}\n captionLayout=\"dropdown\"\n onSelect={(date) => {\n setDate(date);\n setOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n </div>\n <div className=\"flex flex-col gap-3\">\n <Label htmlFor=\"time-picker\" className=\"px-1\">\n Time\n </Label>\n <Input\n type=\"time\"\n id=\"time-picker\"\n step=\"1\"\n defaultValue=\"10:30:00\"\n className=\"bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none\"\n />\n </div>\n </div>\n );\n};\n"
272
+ },
273
+ {
274
+ "name": "date-of-birth",
275
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const [date, setDate] = React.useState<Date | undefined>(undefined);\n\n return (\n <div className=\"flex flex-col gap-3\">\n <Label htmlFor=\"date\" className=\"px-1\">\n Date of birth\n </Label>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n id=\"date\"\n className=\"w-48 justify-between font-normal\"\n >\n {date ? date.toLocaleDateString() : \"Select date\"}\n <ChevronDownIcon />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto overflow-hidden p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={date}\n captionLayout=\"dropdown\"\n onSelect={(date) => {\n setDate(date);\n setOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n </div>\n );\n};\n"
276
+ },
277
+ {
278
+ "name": "default",
279
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\n\nexport function Preview() {\n const [date, setDate] = React.useState<Date | undefined>(new Date());\n\n return (\n <Calendar\n mode=\"single\"\n selected={date}\n onSelect={setDate}\n className=\"rounded-md border shadow-sm\"\n captionLayout=\"dropdown\"\n />\n );\n}\n"
280
+ },
281
+ {
282
+ "name": "form",
283
+ "code": "\"use client\"\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\nimport { CalendarIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { format } from \"date-fns\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\nimport { toast } from \"sonner\";\nimport { useForm } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@rlx-widgets/form\";\n\nconst FormSchema = z.object({\n dob: z.date().refine((val) => val instanceof Date && !isNaN(val.getTime()), {\n message: \"A date of birth is required.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"dob\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Date of birth</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[240px] pl-3 text-left font-normal\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value ? (\n format(field.value, \"PPP\")\n ) : (\n <span>Pick a date</span>\n )}\n <CalendarIcon className=\"ml-auto h-4 w-4 opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"start\">\n <Calendar\n mode=\"single\"\n selected={field.value}\n onSelect={field.onChange}\n disabled={(date) =>\n date > new Date() || date < new Date(\"1900-01-01\")\n }\n captionLayout=\"dropdown\"\n />\n </PopoverContent>\n </Popover>\n <FormDescription>\n Your date of birth is used to calculate your age.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
284
+ },
285
+ {
286
+ "name": "month-year-selector",
287
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\nimport { Label } from \"@rlx-widgets/label\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nexport function Preview() {\n const [dropdown, setDropdown] =\n React.useState<React.ComponentProps<typeof Calendar>[\"captionLayout\"]>(\n \"dropdown\"\n );\n const [date, setDate] = React.useState<Date | undefined>(\n new Date(2025, 5, 12)\n );\n\n return (\n <div className=\"flex flex-col gap-4\">\n <Calendar\n mode=\"single\"\n defaultMonth={date}\n selected={date}\n onSelect={setDate}\n captionLayout={dropdown}\n className=\"rounded-lg border shadow-sm\"\n />\n <div className=\"flex flex-col gap-3\">\n <Label htmlFor=\"dropdown\" className=\"px-1\">\n Dropdown\n </Label>\n <Select\n value={dropdown}\n onValueChange={(value) =>\n setDropdown(\n value as React.ComponentProps<typeof Calendar>[\"captionLayout\"]\n )\n }\n >\n <SelectTrigger\n id=\"dropdown\"\n size=\"sm\"\n className=\"bg-background w-full\"\n >\n <SelectValue placeholder=\"Dropdown\" />\n </SelectTrigger>\n <SelectContent align=\"center\">\n <SelectItem value=\"dropdown\">Month and Year</SelectItem>\n <SelectItem value=\"dropdown-months\">Month Only</SelectItem>\n <SelectItem value=\"dropdown-years\">Year Only</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </div>\n );\n}\n"
288
+ },
289
+ {
290
+ "name": "natural-language-picker",
291
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { parseDate } from \"chrono-node\";\nimport { CalendarIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\nfunction formatDate(date: Date | undefined) {\n if (!date) {\n return \"\";\n }\n\n return date.toLocaleDateString(\"en-US\", {\n day: \"2-digit\",\n month: \"long\",\n year: \"numeric\",\n });\n}\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const [value, setValue] = React.useState(\"In 2 days\");\n const [date, setDate] = React.useState<Date | undefined>(\n parseDate(value) || undefined\n );\n const [month, setMonth] = React.useState<Date | undefined>(date);\n\n return (\n <div className=\"flex flex-col gap-3\">\n <Label htmlFor=\"date\" className=\"px-1\">\n Schedule Date\n </Label>\n <div className=\"relative flex gap-2\">\n <Input\n id=\"date\"\n value={value}\n placeholder=\"Tomorrow or next week\"\n className=\"bg-background pr-10\"\n onChange={(e) => {\n setValue(e.target.value);\n const date = parseDate(e.target.value);\n if (date) {\n setDate(date);\n setMonth(date);\n }\n }}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setOpen(true);\n }\n }}\n />\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n id=\"date-picker\"\n variant=\"ghost\"\n className=\"absolute top-1/2 right-2 size-6 -translate-y-1/2\"\n >\n <CalendarIcon className=\"size-3.5\" />\n <span className=\"sr-only\">Select date</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto overflow-hidden p-0\" align=\"end\">\n <Calendar\n mode=\"single\"\n selected={date}\n captionLayout=\"dropdown\"\n month={month}\n onMonthChange={setMonth}\n onSelect={(date) => {\n setDate(date);\n setValue(formatDate(date));\n setOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n </div>\n <div className=\"text-muted-foreground px-1 text-sm\">\n Your post will be published on{\" \"}\n <span className=\"font-medium\">{formatDate(date)}</span>.\n </div>\n </div>\n );\n};\n"
292
+ },
293
+ {
294
+ "name": "range",
295
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Calendar } from \"@rlx-widgets/calendar\";\n\nexport const Preview = () => {\n const [date, setDate] = React.useState<Date | undefined>(\n new Date(2025, 5, 12)\n );\n\n return (\n <Calendar\n mode=\"single\"\n defaultMonth={date}\n numberOfMonths={2}\n selected={date}\n onSelect={setDate}\n className=\"rounded-lg border shadow-sm\"\n />\n );\n};\n"
296
+ }
297
+ ]
298
+ },
299
+ {
300
+ "name": "Card",
301
+ "slug": "card",
302
+ "category": "widget",
303
+ "sourceCode": "import * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n );\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n};\n",
304
+ "demos": [
305
+ {
306
+ "name": "default",
307
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport {\n Card,\n CardAction,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@rlx-widgets/card\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\n\nexport const Preview = () => {\n return (\n <Card className=\"w-full max-w-sm\">\n <CardHeader>\n <CardTitle>Login to your account</CardTitle>\n <CardDescription>\n Enter your email below to login to your account\n </CardDescription>\n <CardAction>\n <Button variant=\"link\">Sign Up</Button>\n </CardAction>\n </CardHeader>\n <CardContent>\n <form>\n <div className=\"flex flex-col gap-6\">\n <div className=\"grid gap-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"m@example.com\"\n required\n />\n </div>\n <div className=\"grid gap-2\">\n <div className=\"flex items-center\">\n <Label htmlFor=\"password\">Password</Label>\n <a\n href=\"#\"\n className=\"ml-auto inline-block text-sm underline-offset-4 hover:underline\"\n >\n Forgot your password?\n </a>\n </div>\n <Input id=\"password\" type=\"password\" required />\n </div>\n </div>\n </form>\n </CardContent>\n <CardFooter className=\"flex-col gap-2\">\n <Button type=\"submit\" className=\"w-full\">\n Login\n </Button>\n <Button variant=\"outline\" className=\"w-full\">\n Login with Google\n </Button>\n </CardFooter>\n </Card>\n );\n};\n"
308
+ }
309
+ ]
310
+ },
311
+ {
312
+ "name": "Carousel",
313
+ "slug": "carousel",
314
+ "category": "widget",
315
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport useEmblaCarousel, {\n type UseEmblaCarouselType,\n} from \"embla-carousel-react\";\nimport { ArrowLeft, ArrowRight } from \"lucide-react\";\n\nimport { cn } from \"@rlx-widgets/base\";\nimport { Button } from \"@rlx-widgets/button\";\n\ntype CarouselApi = UseEmblaCarouselType[1];\ntype UseCarouselParameters = Parameters<typeof useEmblaCarousel>;\ntype CarouselOptions = UseCarouselParameters[0];\ntype CarouselPlugin = UseCarouselParameters[1];\n\ntype CarouselProps = {\n opts?: CarouselOptions;\n plugins?: CarouselPlugin;\n orientation?: \"horizontal\" | \"vertical\";\n setApi?: (api: CarouselApi) => void;\n};\n\ntype CarouselContextProps = {\n carouselRef: ReturnType<typeof useEmblaCarousel>[0];\n api: ReturnType<typeof useEmblaCarousel>[1];\n scrollPrev: () => void;\n scrollNext: () => void;\n canScrollPrev: boolean;\n canScrollNext: boolean;\n} & CarouselProps;\n\nconst CarouselContext = React.createContext<CarouselContextProps | null>(null);\n\nfunction useCarousel() {\n const context = React.useContext(CarouselContext);\n\n if (!context) {\n throw new Error(\"useCarousel must be used within a <Carousel />\");\n }\n\n return context;\n}\n\nfunction Carousel({\n orientation = \"horizontal\",\n opts,\n setApi,\n plugins,\n className,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & CarouselProps) {\n const [carouselRef, api] = useEmblaCarousel(\n {\n ...opts,\n axis: orientation === \"horizontal\" ? \"x\" : \"y\",\n },\n plugins\n );\n const [canScrollPrev, setCanScrollPrev] = React.useState(false);\n const [canScrollNext, setCanScrollNext] = React.useState(false);\n\n const onSelect = React.useCallback((api: CarouselApi) => {\n if (!api) return;\n setCanScrollPrev(api.canScrollPrev());\n setCanScrollNext(api.canScrollNext());\n }, []);\n\n const scrollPrev = React.useCallback(() => {\n api?.scrollPrev();\n }, [api]);\n\n const scrollNext = React.useCallback(() => {\n api?.scrollNext();\n }, [api]);\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n scrollNext();\n }\n },\n [scrollPrev, scrollNext]\n );\n\n React.useEffect(() => {\n if (!api || !setApi) return;\n setApi(api);\n }, [api, setApi]);\n\n React.useEffect(() => {\n if (!api) return;\n onSelect(api);\n api.on(\"reInit\", onSelect);\n api.on(\"select\", onSelect);\n\n return () => {\n api?.off(\"select\", onSelect);\n };\n }, [api, onSelect]);\n\n return (\n <CarouselContext.Provider\n value={{\n carouselRef,\n api: api,\n opts,\n orientation:\n orientation || (opts?.axis === \"y\" ? \"vertical\" : \"horizontal\"),\n scrollPrev,\n scrollNext,\n canScrollPrev,\n canScrollNext,\n }}\n >\n <div\n onKeyDownCapture={handleKeyDown}\n className={cn(\"relative\", className)}\n role=\"region\"\n aria-roledescription=\"carousel\"\n data-slot=\"carousel\"\n {...props}\n >\n {children}\n </div>\n </CarouselContext.Provider>\n );\n}\n\nfunction CarouselContent({ className, ...props }: React.ComponentProps<\"div\">) {\n const { carouselRef, orientation } = useCarousel();\n\n return (\n <div\n ref={carouselRef}\n className=\"overflow-hidden\"\n data-slot=\"carousel-content\"\n >\n <div\n className={cn(\n \"flex\",\n orientation === \"horizontal\" ? \"-ml-4\" : \"-mt-4 flex-col\",\n className\n )}\n {...props}\n />\n </div>\n );\n}\n\nfunction CarouselItem({ className, ...props }: React.ComponentProps<\"div\">) {\n const { orientation } = useCarousel();\n\n return (\n <div\n role=\"group\"\n aria-roledescription=\"slide\"\n data-slot=\"carousel-item\"\n className={cn(\n \"min-w-0 shrink-0 grow-0 basis-full\",\n orientation === \"horizontal\" ? \"pl-4\" : \"pt-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CarouselPrevious({\n className,\n variant = \"outline\",\n size = \"icon\",\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { orientation, scrollPrev, canScrollPrev } = useCarousel();\n\n return (\n <Button\n data-slot=\"carousel-previous\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -left-12 -translate-y-1/2\"\n : \"-top-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n disabled={!canScrollPrev}\n onClick={scrollPrev}\n {...props}\n >\n <ArrowLeft />\n <span className=\"sr-only\">Previous slide</span>\n </Button>\n );\n}\n\nfunction CarouselNext({\n className,\n variant = \"outline\",\n size = \"icon\",\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { orientation, scrollNext, canScrollNext } = useCarousel();\n\n return (\n <Button\n data-slot=\"carousel-next\"\n variant={variant}\n size={size}\n className={cn(\n \"absolute size-8 rounded-full\",\n orientation === \"horizontal\"\n ? \"top-1/2 -right-12 -translate-y-1/2\"\n : \"-bottom-12 left-1/2 -translate-x-1/2 rotate-90\",\n className\n )}\n disabled={!canScrollNext}\n onClick={scrollNext}\n {...props}\n >\n <ArrowRight />\n <span className=\"sr-only\">Next slide</span>\n </Button>\n );\n}\n\nexport {\n type CarouselApi,\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselPrevious,\n CarouselNext,\n};\n",
316
+ "demos": [
317
+ {
318
+ "name": "api",
319
+ "code": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { Card, CardContent } from \"@rlx-widgets/card\";\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n type CarouselApi,\n} from \"@rlx-widgets/carousel\";\n\nexport const Preview = () => {\n const [api, setApi] = React.useState<CarouselApi>();\n const [current, setCurrent] = React.useState(0);\n const [count, setCount] = React.useState(0);\n\n React.useEffect(() => {\n if (!api) {\n return;\n }\n\n setCount(api.scrollSnapList().length);\n setCurrent(api.selectedScrollSnap() + 1);\n\n api.on(\"select\", () => {\n setCurrent(api.selectedScrollSnap() + 1);\n });\n }, [api]);\n\n return (\n <div className=\"mx-auto max-w-xs\">\n <Carousel setApi={setApi} className=\"w-full max-w-xs\">\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index}>\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-4xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n <div className=\"text-muted-foreground py-2 text-center text-sm\">\n Slide {current} of {count}\n </div>\n </div>\n );\n};\n"
320
+ },
321
+ {
322
+ "name": "default",
323
+ "code": "import * as React from \"react\";\n\nimport { Card, CardContent } from \"@rlx-widgets/card\";\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@rlx-widgets/carousel\";\n\nexport const Preview = () => {\n return (\n <Carousel className=\"w-full max-w-xs\">\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index}>\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-4xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n );\n};\n"
324
+ },
325
+ {
326
+ "name": "orientation",
327
+ "code": "import * as React from \"react\";\n\nimport { Card, CardContent } from \"@rlx-widgets/card\";\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@rlx-widgets/carousel\";\n\nexport const Preview = () => {\n return (\n <Carousel\n opts={{\n align: \"start\",\n }}\n orientation=\"vertical\"\n className=\"w-full max-w-xs\"\n >\n <CarouselContent className=\"-mt-1 h-[200px]\">\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index} className=\"pt-1 md:basis-1/2\">\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex items-center justify-center p-6\">\n <span className=\"text-3xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n );\n};\n"
328
+ },
329
+ {
330
+ "name": "size",
331
+ "code": "import * as React from \"react\";\n\nimport { Card, CardContent } from \"@rlx-widgets/card\";\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@rlx-widgets/carousel\";\n\nexport const Preview = () => {\n return (\n <Carousel\n opts={{\n align: \"start\",\n }}\n className=\"w-full max-w-sm\"\n >\n <CarouselContent>\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index} className=\"md:basis-1/2 lg:basis-1/3\">\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-3xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n );\n};\n"
332
+ },
333
+ {
334
+ "name": "spacing",
335
+ "code": "import * as React from \"react\";\n\nimport { Card, CardContent } from \"@rlx-widgets/card\";\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselNext,\n CarouselPrevious,\n} from \"@rlx-widgets/carousel\";\n\nexport const Preview = () => {\n return (\n <Carousel className=\"w-full max-w-sm\">\n <CarouselContent className=\"-ml-1\">\n {Array.from({ length: 5 }).map((_, index) => (\n <CarouselItem key={index} className=\"pl-1 md:basis-1/2 lg:basis-1/3\">\n <div className=\"p-1\">\n <Card>\n <CardContent className=\"flex aspect-square items-center justify-center p-6\">\n <span className=\"text-2xl font-semibold\">{index + 1}</span>\n </CardContent>\n </Card>\n </div>\n </CarouselItem>\n ))}\n </CarouselContent>\n <CarouselPrevious />\n <CarouselNext />\n </Carousel>\n );\n};\n"
336
+ }
337
+ ]
338
+ },
339
+ {
340
+ "name": "Checkbox",
341
+ "slug": "checkbox",
342
+ "category": "widget",
343
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { CheckIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Checkbox({\n className,\n ...props\n}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {\n return (\n <CheckboxPrimitive.Root\n data-slot=\"checkbox\"\n className={cn(\n \"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n data-slot=\"checkbox-indicator\"\n className=\"flex items-center justify-center text-current transition-none\"\n >\n <CheckIcon className=\"size-3.5\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n );\n}\n\nexport { Checkbox };\n",
344
+ "demos": [
345
+ {
346
+ "name": "default",
347
+ "code": "\"use client\"\n\nimport { Checkbox } from \"@rlx-widgets/checkbox\"\nimport { Label } from \"@rlx-widgets/label\"\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-col gap-6\">\n <div className=\"flex items-center gap-3\">\n <Checkbox id=\"terms\" />\n <Label htmlFor=\"terms\">Accept terms and conditions</Label>\n </div>\n <div className=\"flex items-start gap-3\">\n <Checkbox id=\"terms-2\" defaultChecked />\n <div className=\"grid gap-2\">\n <Label htmlFor=\"terms-2\">Accept terms and conditions</Label>\n <p className=\"text-muted-foreground text-sm\">\n By clicking this checkbox, you agree to the terms and conditions.\n </p>\n </div>\n </div>\n <div className=\"flex items-start gap-3\">\n <Checkbox id=\"toggle\" disabled />\n <Label htmlFor=\"toggle\">Enable notifications</Label>\n </div>\n <Label className=\"hover:bg-accent/50 flex items-start gap-3 rounded-lg border p-3 has-[[aria-checked=true]]:border-blue-600 has-[[aria-checked=true]]:bg-blue-50 dark:has-[[aria-checked=true]]:border-blue-900 dark:has-[[aria-checked=true]]:bg-blue-950\">\n <Checkbox\n id=\"toggle-2\"\n defaultChecked\n className=\"data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white dark:data-[state=checked]:border-blue-700 dark:data-[state=checked]:bg-blue-700\"\n />\n <div className=\"grid gap-1.5 font-normal\">\n <p className=\"text-sm leading-none font-medium\">\n Enable notifications\n </p>\n <p className=\"text-muted-foreground text-sm\">\n You can enable or disable notifications at any time.\n </p>\n </div>\n </Label>\n </div>\n )\n}\n"
348
+ },
349
+ {
350
+ "name": "form",
351
+ "code": "\"use client\";\n\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { z } from \"zod\";\n\nimport { Button } from \"rlx-widgets\";\nimport { Checkbox } from \"rlx-widgets\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"rlx-widgets\";\n\nconst items = [\n {\n id: \"recents\",\n label: \"Recents\",\n },\n {\n id: \"home\",\n label: \"Home\",\n },\n {\n id: \"applications\",\n label: \"Applications\",\n },\n {\n id: \"desktop\",\n label: \"Desktop\",\n },\n {\n id: \"downloads\",\n label: \"Downloads\",\n },\n {\n id: \"documents\",\n label: \"Documents\",\n },\n] as const;\n\nconst FormSchema = z.object({\n items: z.array(z.string()).refine((value) => value.some((item) => item), {\n message: \"You have to select at least one item.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n items: [\"recents\", \"home\"],\n },\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-8\">\n <FormField\n control={form.control}\n name=\"items\"\n render={() => (\n <FormItem>\n <div className=\"mb-4\">\n <FormLabel className=\"text-base\">Sidebar</FormLabel>\n <FormDescription>\n Select the items you want to display in the sidebar.\n </FormDescription>\n </div>\n {items.map((item) => (\n <FormField\n key={item.id}\n control={form.control}\n name=\"items\"\n render={({ field }) => {\n return (\n <FormItem\n key={item.id}\n className=\"flex flex-row items-center gap-2\"\n >\n <FormControl>\n <Checkbox\n checked={field.value?.includes(item.id)}\n onCheckedChange={(checked) => {\n return checked\n ? field.onChange([...field.value, item.id])\n : field.onChange(\n field.value?.filter(\n (value) => value !== item.id\n )\n );\n }}\n />\n </FormControl>\n <FormLabel className=\"text-sm font-normal\">\n {item.label}\n </FormLabel>\n </FormItem>\n );\n }}\n />\n ))}\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
352
+ }
353
+ ]
354
+ },
355
+ {
356
+ "name": "Collapsible",
357
+ "slug": "collapsible",
358
+ "category": "widget",
359
+ "sourceCode": "\"use client\"\n\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\"\n\nfunction Collapsible({\n ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {\n return <CollapsiblePrimitive.Root data-slot=\"collapsible\" {...props} />\n}\n\nfunction CollapsibleTrigger({\n ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {\n return (\n <CollapsiblePrimitive.CollapsibleTrigger\n data-slot=\"collapsible-trigger\"\n {...props}\n />\n )\n}\n\nfunction CollapsibleContent({\n ...props\n}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {\n return (\n <CollapsiblePrimitive.CollapsibleContent\n data-slot=\"collapsible-content\"\n {...props}\n />\n )\n}\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent }\n",
360
+ "demos": [
361
+ {
362
+ "name": "default",
363
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ChevronsUpDown } from \"lucide-react\";\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@rlx-widgets/collapsible\";\n\nexport const Preview = () => {\n const [isOpen, setIsOpen] = React.useState(false);\n\n return (\n <Collapsible\n open={isOpen}\n onOpenChange={setIsOpen}\n className=\"flex w-[350px] flex-col gap-2\"\n >\n <div className=\"flex items-center justify-between gap-4 px-4\">\n <h4 className=\"text-sm font-semibold\">\n @peduarte starred 3 repositories\n </h4>\n <CollapsibleTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"size-8\">\n <ChevronsUpDown />\n <span className=\"sr-only\">Toggle</span>\n </Button>\n </CollapsibleTrigger>\n </div>\n <div className=\"rounded-md border px-4 py-2 font-mono text-sm\">\n @radix-ui/primitives\n </div>\n <CollapsibleContent className=\"flex flex-col gap-2\">\n <div className=\"rounded-md border px-4 py-2 font-mono text-sm\">\n @radix-ui/colors\n </div>\n <div className=\"rounded-md border px-4 py-2 font-mono text-sm\">\n @stitches/react\n </div>\n </CollapsibleContent>\n </Collapsible>\n );\n};\n"
364
+ }
365
+ ]
366
+ },
367
+ {
368
+ "name": "Combobox",
369
+ "slug": "combobox",
370
+ "category": "widget",
371
+ "demos": [
372
+ {
373
+ "name": "default",
374
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Check, ChevronsUpDown } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@rlx-widgets/command\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\nconst frameworks = [\n {\n value: \"next.js\",\n label: \"Next.js\",\n },\n {\n value: \"sveltekit\",\n label: \"SvelteKit\",\n },\n {\n value: \"nuxt.js\",\n label: \"Nuxt.js\",\n },\n {\n value: \"remix\",\n label: \"Remix\",\n },\n {\n value: \"astro\",\n label: \"Astro\",\n },\n];\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const [value, setValue] = React.useState(\"\");\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n className=\"w-[200px] justify-between\"\n >\n {value\n ? frameworks.find((framework) => framework.value === value)?.label\n : \"Select framework...\"}\n <ChevronsUpDown className=\"opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder=\"Search framework...\" className=\"h-9\" />\n <CommandList>\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandGroup>\n {frameworks.map((framework) => (\n <CommandItem\n key={framework.value}\n value={framework.value}\n onSelect={(currentValue) => {\n setValue(currentValue === value ? \"\" : currentValue);\n setOpen(false);\n }}\n >\n {framework.label}\n <Check\n className={cn(\n \"ml-auto\",\n value === framework.value ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n};\n"
375
+ },
376
+ {
377
+ "name": "dropdown-menu",
378
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { MoreHorizontal } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@rlx-widgets/command\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nconst labels = [\n \"feature\",\n \"bug\",\n \"enhancement\",\n \"documentation\",\n \"design\",\n \"question\",\n \"maintenance\",\n];\n\nexport const Preview = () => {\n const [label, setLabel] = React.useState(\"feature\");\n const [open, setOpen] = React.useState(false);\n\n return (\n <div className=\"flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center\">\n <p className=\"text-sm leading-none font-medium\">\n <span className=\"bg-primary text-primary-foreground mr-2 rounded-lg px-2 py-1 text-xs\">\n {label}\n </span>\n <span className=\"text-muted-foreground\">Create a new project</span>\n </p>\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\">\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-[200px]\">\n <DropdownMenuLabel>Actions</DropdownMenuLabel>\n <DropdownMenuGroup>\n <DropdownMenuItem>Assign to...</DropdownMenuItem>\n <DropdownMenuItem>Set due date...</DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>Apply label</DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"p-0\">\n <Command>\n <CommandInput\n placeholder=\"Filter label...\"\n autoFocus={true}\n className=\"h-9\"\n />\n <CommandList>\n <CommandEmpty>No label found.</CommandEmpty>\n <CommandGroup>\n {labels.map((label) => (\n <CommandItem\n key={label}\n value={label}\n onSelect={(value) => {\n setLabel(value);\n setOpen(false);\n }}\n >\n {label}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"text-red-600\">\n Delete\n <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n );\n};\n"
379
+ },
380
+ {
381
+ "name": "form",
382
+ "code": "\"use client\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { Check, ChevronsUpDown } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\nimport { toast } from \"sonner\";\nimport { useForm } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@rlx-widgets/command\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@rlx-widgets/form\";\n\nconst languages = [\n { label: \"English\", value: \"en\" },\n { label: \"French\", value: \"fr\" },\n { label: \"German\", value: \"de\" },\n { label: \"Spanish\", value: \"es\" },\n { label: \"Portuguese\", value: \"pt\" },\n { label: \"Russian\", value: \"ru\" },\n { label: \"Japanese\", value: \"ja\" },\n { label: \"Korean\", value: \"ko\" },\n { label: \"Chinese\", value: \"zh\" },\n] as const;\n\nconst FormSchema = z.object({\n language: z.string({\n error: \"Please select a language.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"space-y-6\">\n <FormField\n control={form.control}\n name=\"language\"\n render={({ field }) => (\n <FormItem className=\"flex flex-col\">\n <FormLabel>Language</FormLabel>\n <Popover>\n <PopoverTrigger asChild>\n <FormControl>\n <Button\n variant=\"outline\"\n role=\"combobox\"\n className={cn(\n \"w-[200px] justify-between\",\n !field.value && \"text-muted-foreground\"\n )}\n >\n {field.value\n ? languages.find(\n (language) => language.value === field.value\n )?.label\n : \"Select language\"}\n <ChevronsUpDown className=\"opacity-50\" />\n </Button>\n </FormControl>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\">\n <Command>\n <CommandInput\n placeholder=\"Search framework...\"\n className=\"h-9\"\n />\n <CommandList>\n <CommandEmpty>No framework found.</CommandEmpty>\n <CommandGroup>\n {languages.map((language) => (\n <CommandItem\n value={language.label}\n key={language.value}\n onSelect={() => {\n form.setValue(\"language\", language.value);\n }}\n >\n {language.label}\n <Check\n className={cn(\n \"ml-auto\",\n language.value === field.value\n ? \"opacity-100\"\n : \"opacity-0\"\n )}\n />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <FormDescription>\n This is the language that will be used in the dashboard.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
383
+ },
384
+ {
385
+ "name": "popover",
386
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@rlx-widgets/command\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\ntype Status = {\n value: string;\n label: string;\n};\n\nconst statuses: Status[] = [\n {\n value: \"backlog\",\n label: \"Backlog\",\n },\n {\n value: \"todo\",\n label: \"Todo\",\n },\n {\n value: \"in progress\",\n label: \"In Progress\",\n },\n {\n value: \"done\",\n label: \"Done\",\n },\n {\n value: \"canceled\",\n label: \"Canceled\",\n },\n];\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const [selectedStatus, setSelectedStatus] = React.useState<Status | null>(\n null\n );\n\n return (\n <div className=\"flex items-center space-x-4\">\n <p className=\"text-muted-foreground text-sm\">Status</p>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className=\"w-[150px] justify-start\">\n {selectedStatus ? <>{selectedStatus.label}</> : <>+ Set status</>}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0\" side=\"right\" align=\"start\">\n <Command>\n <CommandInput placeholder=\"Change status...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n {statuses.map((status) => (\n <CommandItem\n key={status.value}\n value={status.value}\n onSelect={(value) => {\n setSelectedStatus(\n statuses.find((priority) => priority.value === value) ||\n null\n );\n setOpen(false);\n }}\n >\n {status.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </div>\n );\n};\n"
387
+ },
388
+ {
389
+ "name": "responsive",
390
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { useMediaQuery } from \"@rlx-hooks/use-media-query\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n} from \"@rlx-widgets/command\";\nimport { Drawer, DrawerContent, DrawerTrigger } from \"@rlx-widgets/drawer\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\ntype Status = {\n value: string;\n label: string;\n};\n\nconst statuses: Status[] = [\n {\n value: \"backlog\",\n label: \"Backlog\",\n },\n {\n value: \"todo\",\n label: \"Todo\",\n },\n {\n value: \"in progress\",\n label: \"In Progress\",\n },\n {\n value: \"done\",\n label: \"Done\",\n },\n {\n value: \"canceled\",\n label: \"Canceled\",\n },\n];\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const isDesktop = useMediaQuery(\"(min-width: 768px)\");\n const [selectedStatus, setSelectedStatus] = React.useState<Status | null>(\n null\n );\n\n if (isDesktop) {\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className=\"w-[150px] justify-start\">\n {selectedStatus ? <>{selectedStatus.label}</> : <>+ Set status</>}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[200px] p-0\" align=\"start\">\n <StatusList setOpen={setOpen} setSelectedStatus={setSelectedStatus} />\n </PopoverContent>\n </Popover>\n );\n }\n\n return (\n <Drawer open={open} onOpenChange={setOpen}>\n <DrawerTrigger asChild>\n <Button variant=\"outline\" className=\"w-[150px] justify-start\">\n {selectedStatus ? <>{selectedStatus.label}</> : <>+ Set status</>}\n </Button>\n </DrawerTrigger>\n <DrawerContent>\n <div className=\"mt-4 border-t\">\n <StatusList setOpen={setOpen} setSelectedStatus={setSelectedStatus} />\n </div>\n </DrawerContent>\n </Drawer>\n );\n};\n\nfunction StatusList({\n setOpen,\n setSelectedStatus,\n}: {\n setOpen: (open: boolean) => void;\n setSelectedStatus: (status: Status | null) => void;\n}) {\n return (\n <Command>\n <CommandInput placeholder=\"Filter status...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup>\n {statuses.map((status) => (\n <CommandItem\n key={status.value}\n value={status.value}\n onSelect={(value) => {\n setSelectedStatus(\n statuses.find((priority) => priority.value === value) || null\n );\n setOpen(false);\n }}\n >\n {status.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n );\n}\n"
391
+ }
392
+ ]
393
+ },
394
+ {
395
+ "name": "Command",
396
+ "slug": "command",
397
+ "category": "widget",
398
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { SearchIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"@rlx-widgets/dialog\";\n\nfunction Command({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive>) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n \"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CommandDialog({\n title = \"Command Palette\",\n description = \"Search for a command to run...\",\n children,\n className,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof Dialog> & {\n title?: string;\n description?: string;\n className?: string;\n showCloseButton?: boolean;\n}) {\n return (\n <Dialog {...props}>\n <DialogHeader className=\"sr-only\">\n <DialogTitle>{title}</DialogTitle>\n <DialogDescription>{description}</DialogDescription>\n </DialogHeader>\n <DialogContent\n className={cn(\"overflow-hidden p-0\", className)}\n showCloseButton={showCloseButton}\n >\n <Command className=\"[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5\">\n {children}\n </Command>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction CommandInput({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Input>) {\n return (\n <div\n data-slot=\"command-input-wrapper\"\n className=\"flex h-9 items-center gap-2 border-b px-3\"\n >\n <SearchIcon className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n data-slot=\"command-input\"\n className={cn(\n \"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n />\n </div>\n );\n}\n\nfunction CommandList({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.List>) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn(\n \"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CommandEmpty({\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n return (\n <CommandPrimitive.Empty\n data-slot=\"command-empty\"\n className=\"py-6 text-center text-sm\"\n {...props}\n />\n );\n}\n\nfunction CommandGroup({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Group>) {\n return (\n <CommandPrimitive.Group\n data-slot=\"command-group\"\n className={cn(\n \"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CommandSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Separator>) {\n return (\n <CommandPrimitive.Separator\n data-slot=\"command-separator\"\n className={cn(\"bg-border -mx-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction CommandItem({\n className,\n ...props\n}: React.ComponentProps<typeof CommandPrimitive.Item>) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction CommandShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"command-shortcut\"\n className={cn(\n \"text-muted-foreground ml-auto text-xs tracking-widest\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Command,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n CommandShortcut,\n CommandSeparator,\n};\n",
399
+ "demos": [
400
+ {
401
+ "name": "default",
402
+ "code": "import {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from \"lucide-react\";\n\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@rlx-widgets/command\";\n\nexport const Preview = () => {\n return (\n <Command className=\"rounded-lg border shadow-md md:min-w-[450px]\">\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem disabled>\n <Calculator />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </Command>\n );\n};\n"
403
+ },
404
+ {
405
+ "name": "dialog",
406
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n Calculator,\n Calendar,\n CreditCard,\n Settings,\n Smile,\n User,\n} from \"lucide-react\";\nimport {\n CommandDialog,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n CommandShortcut,\n} from \"@rlx-widgets/command\";\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n\n React.useEffect(() => {\n const down = (e: KeyboardEvent) => {\n if (e.key === \"j\" && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n setOpen((open) => !open);\n }\n };\n\n document.addEventListener(\"keydown\", down);\n return () => document.removeEventListener(\"keydown\", down);\n }, []);\n\n return (\n <>\n <p className=\"text-muted-foreground text-sm\">\n Press{\" \"}\n <kbd className=\"bg-muted text-muted-foreground pointer-events-none inline-flex h-5 items-center gap-1 rounded border px-1.5 font-mono text-[10px] font-medium opacity-100 select-none\">\n <span className=\"text-xs\">⌘</span>J\n </kbd>\n </p>\n <CommandDialog open={open} onOpenChange={setOpen}>\n <CommandInput placeholder=\"Type a command or search...\" />\n <CommandList>\n <CommandEmpty>No results found.</CommandEmpty>\n <CommandGroup heading=\"Suggestions\">\n <CommandItem>\n <Calendar />\n <span>Calendar</span>\n </CommandItem>\n <CommandItem>\n <Smile />\n <span>Search Emoji</span>\n </CommandItem>\n <CommandItem>\n <Calculator />\n <span>Calculator</span>\n </CommandItem>\n </CommandGroup>\n <CommandSeparator />\n <CommandGroup heading=\"Settings\">\n <CommandItem>\n <User />\n <span>Profile</span>\n <CommandShortcut>⌘P</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <CreditCard />\n <span>Billing</span>\n <CommandShortcut>⌘B</CommandShortcut>\n </CommandItem>\n <CommandItem>\n <Settings />\n <span>Settings</span>\n <CommandShortcut>⌘S</CommandShortcut>\n </CommandItem>\n </CommandGroup>\n </CommandList>\n </CommandDialog>\n </>\n );\n};\n"
407
+ }
408
+ ]
409
+ },
410
+ {
411
+ "name": "Context Menu",
412
+ "slug": "context-menu",
413
+ "category": "widget",
414
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction ContextMenu({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {\n return <ContextMenuPrimitive.Root data-slot=\"context-menu\" {...props} />;\n}\n\nfunction ContextMenuTrigger({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {\n return (\n <ContextMenuPrimitive.Trigger data-slot=\"context-menu-trigger\" {...props} />\n );\n}\n\nfunction ContextMenuGroup({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {\n return (\n <ContextMenuPrimitive.Group data-slot=\"context-menu-group\" {...props} />\n );\n}\n\nfunction ContextMenuPortal({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {\n return (\n <ContextMenuPrimitive.Portal data-slot=\"context-menu-portal\" {...props} />\n );\n}\n\nfunction ContextMenuSub({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {\n return <ContextMenuPrimitive.Sub data-slot=\"context-menu-sub\" {...props} />;\n}\n\nfunction ContextMenuRadioGroup({\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {\n return (\n <ContextMenuPrimitive.RadioGroup\n data-slot=\"context-menu-radio-group\"\n {...props}\n />\n );\n}\n\nfunction ContextMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}) {\n return (\n <ContextMenuPrimitive.SubTrigger\n data-slot=\"context-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto\" />\n </ContextMenuPrimitive.SubTrigger>\n );\n}\n\nfunction ContextMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {\n return (\n <ContextMenuPrimitive.SubContent\n data-slot=\"context-menu-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuContent({\n className,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {\n return (\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n data-slot=\"context-menu-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md\",\n className\n )}\n {...props}\n />\n </ContextMenuPrimitive.Portal>\n );\n}\n\nfunction ContextMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}) {\n return (\n <ContextMenuPrimitive.Item\n data-slot=\"context-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {\n return (\n <ContextMenuPrimitive.CheckboxItem\n data-slot=\"context-menu-checkbox-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction ContextMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {\n return (\n <ContextMenuPrimitive.RadioItem\n data-slot=\"context-menu-radio-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <CircleIcon className=\"size-2 fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n );\n}\n\nfunction ContextMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean;\n}) {\n return (\n <ContextMenuPrimitive.Label\n data-slot=\"context-menu-label\"\n data-inset={inset}\n className={cn(\n \"text-foreground px-2 py-1.5 text-sm font-medium data-[inset]:pl-8\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ContextMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {\n return (\n <ContextMenuPrimitive.Separator\n data-slot=\"context-menu-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction ContextMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"context-menu-shortcut\"\n className={cn(\n \"text-muted-foreground ml-auto text-xs tracking-widest\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuCheckboxItem,\n ContextMenuRadioItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuGroup,\n ContextMenuPortal,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuRadioGroup,\n};\n",
415
+ "demos": [
416
+ {
417
+ "name": "default",
418
+ "code": "import {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuLabel,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from \"@rlx-widgets/context-menu\";\n\nexport const Preview = () => {\n return (\n <ContextMenu>\n <ContextMenuTrigger className=\"flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed text-sm\">\n Right click here\n </ContextMenuTrigger>\n <ContextMenuContent className=\"w-52\">\n <ContextMenuItem inset>\n Back\n <ContextMenuShortcut>⌘[</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuItem inset disabled>\n Forward\n <ContextMenuShortcut>⌘]</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuItem inset>\n Reload\n <ContextMenuShortcut>⌘R</ContextMenuShortcut>\n </ContextMenuItem>\n <ContextMenuSub>\n <ContextMenuSubTrigger inset>More Tools</ContextMenuSubTrigger>\n <ContextMenuSubContent className=\"w-44\">\n <ContextMenuItem>Save Page...</ContextMenuItem>\n <ContextMenuItem>Create Shortcut...</ContextMenuItem>\n <ContextMenuItem>Name Window...</ContextMenuItem>\n <ContextMenuSeparator />\n <ContextMenuItem>Developer Tools</ContextMenuItem>\n <ContextMenuSeparator />\n <ContextMenuItem variant=\"destructive\">Delete</ContextMenuItem>\n </ContextMenuSubContent>\n </ContextMenuSub>\n <ContextMenuSeparator />\n <ContextMenuCheckboxItem checked>\n Show Bookmarks\n </ContextMenuCheckboxItem>\n <ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem>\n <ContextMenuSeparator />\n <ContextMenuRadioGroup value=\"pedro\">\n <ContextMenuLabel inset>People</ContextMenuLabel>\n <ContextMenuRadioItem value=\"pedro\">\n Pedro Duarte\n </ContextMenuRadioItem>\n <ContextMenuRadioItem value=\"colm\">Colm Tuite</ContextMenuRadioItem>\n </ContextMenuRadioGroup>\n </ContextMenuContent>\n </ContextMenu>\n );\n};\n"
419
+ }
420
+ ]
421
+ },
422
+ {
423
+ "name": "Dialog",
424
+ "slug": "dialog",
425
+ "category": "widget",
426
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { XIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Dialog({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Root>) {\n return <DialogPrimitive.Root data-slot=\"dialog\" {...props} />;\n}\n\nfunction DialogTrigger({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot=\"dialog-trigger\" {...props} />;\n}\n\nfunction DialogPortal({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Portal>) {\n return <DialogPrimitive.Portal data-slot=\"dialog-portal\" {...props} />;\n}\n\nfunction DialogClose({\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot=\"dialog-close\" {...props} />;\n}\n\nfunction DialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal data-slot=\"dialog-portal\">\n <DialogOverlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 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 p-6 shadow-lg duration-200 sm:max-w-lg\",\n className\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close\n data-slot=\"dialog-close\"\n className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\"\n >\n <XIcon />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n )}\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\nfunction DialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-header\"\n className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"dialog-footer\"\n className={cn(\n \"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n className={cn(\"text-lg leading-none font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction DialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n",
427
+ "demos": [
428
+ {
429
+ "name": "custom-close-button",
430
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@rlx-widgets/dialog\";\n\nexport const Preview = () => {\n return (\n <Dialog>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Share</Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Share link</DialogTitle>\n <DialogDescription>\n Anyone who has this link will be able to view this.\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex items-center gap-2\">\n <div className=\"grid flex-1 gap-2\">\n <Label htmlFor=\"link\" className=\"sr-only\">\n Link\n </Label>\n <Input\n id=\"link\"\n defaultValue=\"https://ui.shadcn.com/docs/installation\"\n readOnly\n />\n </div>\n </div>\n <DialogFooter className=\"sm:justify-start\">\n <DialogClose asChild>\n <Button type=\"button\" variant=\"secondary\">\n Close\n </Button>\n </DialogClose>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n};\n"
431
+ },
432
+ {
433
+ "name": "default",
434
+ "code": "import { Button } from \"rlx-widgets\";\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"rlx-widgets\";\nimport { Input } from \"rlx-widgets\";\nimport { Label } from \"rlx-widgets\";\n\nexport const Preview = () => {\n return (\n <Dialog>\n <form>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Open Dialog</Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[425px]\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <div className=\"grid gap-4\">\n <div className=\"grid gap-3\">\n <Label htmlFor=\"name-1\">Name</Label>\n <Input id=\"name-1\" name=\"name\" defaultValue=\"Pedro Duarte\" />\n </div>\n <div className=\"grid gap-3\">\n <Label htmlFor=\"username-1\">Username</Label>\n <Input id=\"username-1\" name=\"username\" defaultValue=\"@peduarte\" />\n </div>\n </div>\n <DialogFooter>\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button type=\"submit\">Save changes</Button>\n </DialogFooter>\n </DialogContent>\n </form>\n </Dialog>\n );\n};\n"
435
+ }
436
+ ]
437
+ },
438
+ {
439
+ "name": "Drawer",
440
+ "slug": "drawer",
441
+ "category": "widget",
442
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Drawer as DrawerPrimitive } from \"vaul\";\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />;\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />;\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />;\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />;\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"group/drawer-content bg-background fixed z-50 flex h-auto flex-col\",\n \"data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b\",\n \"data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t\",\n \"data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm\",\n \"data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm\",\n className\n )}\n {...props}\n >\n <div className=\"bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n );\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\n \"flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n );\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"text-foreground font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n};\n",
443
+ "demos": [
444
+ {
445
+ "name": "custom-height",
446
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { Bar, BarChart, ResponsiveContainer } from \"recharts\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Drawer,\n DrawerClose,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n DrawerTrigger,\n} from \"@rlx-widgets/drawer\";\n\nconst data = [\n {\n goal: 400,\n },\n {\n goal: 300,\n },\n {\n goal: 200,\n },\n {\n goal: 300,\n },\n {\n goal: 200,\n },\n {\n goal: 278,\n },\n {\n goal: 189,\n },\n {\n goal: 239,\n },\n {\n goal: 300,\n },\n {\n goal: 200,\n },\n {\n goal: 278,\n },\n {\n goal: 189,\n },\n {\n goal: 349,\n },\n];\n\nexport const Preview = () => {\n const [goal, setGoal] = React.useState(350);\n\n function onClick(adjustment: number) {\n setGoal(Math.max(200, Math.min(400, goal + adjustment)));\n }\n\n return (\n <Drawer>\n <DrawerTrigger asChild>\n <Button variant=\"outline\">Open Drawer</Button>\n </DrawerTrigger>\n <DrawerContent className=\"h-[100%]\">\n <div className=\"mx-auto w-full max-w-sm\">\n <DrawerHeader>\n <DrawerTitle>Move Goal</DrawerTitle>\n <DrawerDescription>Set your daily activity goal.</DrawerDescription>\n </DrawerHeader>\n <div className=\"p-4 pb-0\">\n <div className=\"flex items-center justify-center space-x-2\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 rounded-full\"\n onClick={() => onClick(-10)}\n disabled={goal <= 200}\n >\n <Minus />\n <span className=\"sr-only\">Decrease</span>\n </Button>\n <div className=\"flex-1 text-center\">\n <div className=\"text-7xl font-bold tracking-tighter\">\n {goal}\n </div>\n <div className=\"text-muted-foreground text-[0.70rem] uppercase\">\n Calories/day\n </div>\n </div>\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 rounded-full\"\n onClick={() => onClick(10)}\n disabled={goal >= 400}\n >\n <Plus />\n <span className=\"sr-only\">Increase</span>\n </Button>\n </div>\n <div className=\"mt-3 h-[120px]\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={data}>\n <Bar\n dataKey=\"goal\"\n style={\n {\n fill: \"hsl(var(--foreground))\",\n opacity: 0.9,\n } as React.CSSProperties\n }\n />\n </BarChart>\n </ResponsiveContainer>\n </div>\n </div>\n <DrawerFooter>\n <Button>Submit</Button>\n <DrawerClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DrawerClose>\n </DrawerFooter>\n </div>\n </DrawerContent>\n </Drawer>\n );\n};\n"
447
+ },
448
+ {
449
+ "name": "default",
450
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { Bar, BarChart, ResponsiveContainer } from \"recharts\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Drawer,\n DrawerClose,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n DrawerTrigger,\n} from \"@rlx-widgets/drawer\";\n\nconst data = [\n {\n goal: 400,\n },\n {\n goal: 300,\n },\n {\n goal: 200,\n },\n {\n goal: 300,\n },\n {\n goal: 200,\n },\n {\n goal: 278,\n },\n {\n goal: 189,\n },\n {\n goal: 239,\n },\n {\n goal: 300,\n },\n {\n goal: 200,\n },\n {\n goal: 278,\n },\n {\n goal: 189,\n },\n {\n goal: 349,\n },\n];\n\nexport const Preview = () => {\n const [goal, setGoal] = React.useState(350);\n\n function onClick(adjustment: number) {\n setGoal(Math.max(200, Math.min(400, goal + adjustment)));\n }\n\n return (\n <Drawer>\n <DrawerTrigger asChild>\n <Button variant=\"outline\">Open Drawer</Button>\n </DrawerTrigger>\n <DrawerContent>\n <div className=\"mx-auto w-full max-w-sm\">\n <DrawerHeader>\n <DrawerTitle>Move Goal</DrawerTitle>\n <DrawerDescription>Set your daily activity goal.</DrawerDescription>\n </DrawerHeader>\n <div className=\"p-4 pb-0\">\n <div className=\"flex items-center justify-center space-x-2\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 rounded-full\"\n onClick={() => onClick(-10)}\n disabled={goal <= 200}\n >\n <Minus />\n <span className=\"sr-only\">Decrease</span>\n </Button>\n <div className=\"flex-1 text-center\">\n <div className=\"text-7xl font-bold tracking-tighter\">\n {goal}\n </div>\n <div className=\"text-muted-foreground text-[0.70rem] uppercase\">\n Calories/day\n </div>\n </div>\n <Button\n variant=\"outline\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 rounded-full\"\n onClick={() => onClick(10)}\n disabled={goal >= 400}\n >\n <Plus />\n <span className=\"sr-only\">Increase</span>\n </Button>\n </div>\n <div className=\"mt-3 h-[120px]\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={data}>\n <Bar\n dataKey=\"goal\"\n style={\n {\n fill: \"hsl(var(--foreground))\",\n opacity: 0.9,\n } as React.CSSProperties\n }\n />\n </BarChart>\n </ResponsiveContainer>\n </div>\n </div>\n <DrawerFooter>\n <Button>Submit</Button>\n <DrawerClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DrawerClose>\n </DrawerFooter>\n </div>\n </DrawerContent>\n </Drawer>\n );\n};\n"
451
+ },
452
+ {
453
+ "name": "responsive",
454
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { useMediaQuery } from \"@rlx-hooks/use-media-query\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"@rlx-widgets/dialog\";\nimport {\n Drawer,\n DrawerClose,\n DrawerContent,\n DrawerDescription,\n DrawerFooter,\n DrawerHeader,\n DrawerTitle,\n DrawerTrigger,\n} from \"@rlx-widgets/drawer\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\n\nexport const Preview = () => {\n const [open, setOpen] = React.useState(false);\n const isDesktop = useMediaQuery(\"(min-width: 768px)\");\n\n if (isDesktop) {\n return (\n <Dialog open={open} onOpenChange={setOpen}>\n <DialogTrigger asChild>\n <Button variant=\"outline\">Edit Profile</Button>\n </DialogTrigger>\n <DialogContent className=\"sm:max-w-[425px]\">\n <DialogHeader>\n <DialogTitle>Edit profile</DialogTitle>\n <DialogDescription>\n Make changes to your profile here. Click save when you&apos;re\n done.\n </DialogDescription>\n </DialogHeader>\n <ProfileForm />\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Drawer open={open} onOpenChange={setOpen}>\n <DrawerTrigger asChild>\n <Button variant=\"outline\">Edit Profile</Button>\n </DrawerTrigger>\n <DrawerContent>\n <DrawerHeader className=\"text-left\">\n <DrawerTitle>Edit profile</DrawerTitle>\n <DrawerDescription>\n Make changes to your profile here. Click save when you&apos;re done.\n </DrawerDescription>\n </DrawerHeader>\n <ProfileForm className=\"px-4\" />\n <DrawerFooter className=\"pt-2\">\n <DrawerClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DrawerClose>\n </DrawerFooter>\n </DrawerContent>\n </Drawer>\n );\n};\n\nfunction ProfileForm({ className }: React.ComponentProps<\"form\">) {\n return (\n <form className={cn(\"grid items-start gap-6\", className)}>\n <div className=\"grid gap-3\">\n <Label htmlFor=\"email\">Email</Label>\n <Input type=\"email\" id=\"email\" defaultValue=\"shadcn@example.com\" />\n </div>\n <div className=\"grid gap-3\">\n <Label htmlFor=\"username\">Username</Label>\n <Input id=\"username\" defaultValue=\"@shadcn\" />\n </div>\n <Button type=\"submit\">Save changes</Button>\n </form>\n );\n}\n"
455
+ }
456
+ ]
457
+ },
458
+ {
459
+ "name": "Dropdown Menu",
460
+ "slug": "dropdown-menu",
461
+ "category": "widget",
462
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction DropdownMenu({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />;\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return (\n <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n );\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n {...props}\n />\n );\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md\",\n className\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return (\n <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n );\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return (\n <DropdownMenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n );\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CircleIcon className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"text-muted-foreground ml-auto text-xs tracking-widest\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub({\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto size-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n};\n",
463
+ "demos": [
464
+ {
465
+ "name": "checkboxes",
466
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { DropdownMenuCheckboxItemProps } from \"@radix-ui/react-dropdown-menu\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\ntype Checked = DropdownMenuCheckboxItemProps[\"checked\"];\n\nexport const Preview = () => {\n const [showStatusBar, setShowStatusBar] = React.useState<Checked>(true);\n const [showActivityBar, setShowActivityBar] = React.useState<Checked>(false);\n const [showPanel, setShowPanel] = React.useState<Checked>(false);\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"w-56\">\n <DropdownMenuLabel>Appearance</DropdownMenuLabel>\n <DropdownMenuSeparator />\n <DropdownMenuCheckboxItem\n checked={showStatusBar}\n onCheckedChange={setShowStatusBar}\n >\n Status Bar\n </DropdownMenuCheckboxItem>\n <DropdownMenuCheckboxItem\n checked={showActivityBar}\n onCheckedChange={setShowActivityBar}\n disabled\n >\n Activity Bar\n </DropdownMenuCheckboxItem>\n <DropdownMenuCheckboxItem\n checked={showPanel}\n onCheckedChange={setShowPanel}\n >\n Panel\n </DropdownMenuCheckboxItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n"
467
+ },
468
+ {
469
+ "name": "default",
470
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\n\nexport const Preview = () => {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"w-56\" align=\"start\">\n <DropdownMenuLabel>My Account</DropdownMenuLabel>\n <DropdownMenuGroup>\n <DropdownMenuItem>\n Profile\n <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n Billing\n <DropdownMenuShortcut>⌘B</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n Settings\n <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem>\n Keyboard shortcuts\n <DropdownMenuShortcut>⌘K</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuGroup>\n <DropdownMenuItem>Team</DropdownMenuItem>\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>\n <DropdownMenuPortal>\n <DropdownMenuSubContent>\n <DropdownMenuItem>Email</DropdownMenuItem>\n <DropdownMenuItem>Message</DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>More...</DropdownMenuItem>\n </DropdownMenuSubContent>\n </DropdownMenuPortal>\n </DropdownMenuSub>\n <DropdownMenuItem>\n New Team\n <DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuGroup>\n <DropdownMenuSeparator />\n <DropdownMenuItem>GitHub</DropdownMenuItem>\n <DropdownMenuItem>Support</DropdownMenuItem>\n <DropdownMenuItem disabled>API</DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem>\n Log out\n <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n};\n"
471
+ }
472
+ ]
473
+ },
474
+ {
475
+ "name": "Empty",
476
+ "slug": "empty",
477
+ "category": "widget",
478
+ "sourceCode": "import { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Empty({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction EmptyHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-header\"\n className={cn(\n \"flex max-w-sm flex-col items-center gap-2 text-center\",\n className\n )}\n {...props}\n />\n );\n}\n\nconst emptyMediaVariants = cva(\n \"flex shrink-0 items-center justify-center mb-2 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction EmptyMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof emptyMediaVariants>) {\n return (\n <div\n data-slot=\"empty-icon\"\n data-variant={variant}\n className={cn(emptyMediaVariants({ variant, className }))}\n {...props}\n />\n );\n}\n\nfunction EmptyTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-title\"\n className={cn(\"text-lg font-medium tracking-tight\", className)}\n {...props}\n />\n );\n}\n\nfunction EmptyDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <div\n data-slot=\"empty-description\"\n className={cn(\n \"text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction EmptyContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-content\"\n className={cn(\n \"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n EmptyDescription,\n EmptyContent,\n EmptyMedia,\n};\n",
479
+ "demos": [
480
+ {
481
+ "name": "avatar",
482
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\n\nexport const Preview = () => {\n return (\n <Empty>\n <EmptyHeader>\n <EmptyMedia variant=\"default\">\n <Avatar className=\"size-12\">\n <AvatarImage\n src=\"https://github.com/shadcn.png\"\n className=\"grayscale\"\n />\n <AvatarFallback>LR</AvatarFallback>\n </Avatar>\n </EmptyMedia>\n <EmptyTitle>User Offline</EmptyTitle>\n <EmptyDescription>\n This user is currently offline. You can leave a message to notify them\n or try again later.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <Button size=\"sm\">Leave Message</Button>\n </EmptyContent>\n </Empty>\n );\n};\n"
483
+ },
484
+ {
485
+ "name": "avatar-group",
486
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { PlusIcon } from \"lucide-react\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\n\nexport const Preview = () => {\n return (\n <Empty>\n <EmptyHeader>\n <EmptyMedia>\n <div className=\"*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:size-12 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale\">\n <Avatar>\n <AvatarImage src=\"https://github.com/shadcn.png\" alt=\"@shadcn\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n <Avatar>\n <AvatarImage\n src=\"https://github.com/maxleiter.png\"\n alt=\"@maxleiter\"\n />\n <AvatarFallback>LR</AvatarFallback>\n </Avatar>\n <Avatar>\n <AvatarImage\n src=\"https://github.com/evilrabbit.png\"\n alt=\"@evilrabbit\"\n />\n <AvatarFallback>ER</AvatarFallback>\n </Avatar>\n </div>\n </EmptyMedia>\n <EmptyTitle>No Team Members</EmptyTitle>\n <EmptyDescription>\n Invite your team to collaborate on this project.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <Button size=\"sm\">\n <PlusIcon />\n Invite Members\n </Button>\n </EmptyContent>\n </Empty>\n );\n};\n"
487
+ },
488
+ {
489
+ "name": "background",
490
+ "code": "import { IconBell } from \"@tabler/icons-react\";\nimport { RefreshCcwIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\n\nexport const Preview = () => {\n return (\n <Empty className=\"from-muted/50 to-background h-full bg-gradient-to-b from-30%\">\n <EmptyHeader>\n <EmptyMedia variant=\"icon\">\n <IconBell />\n </EmptyMedia>\n <EmptyTitle>No Notifications</EmptyTitle>\n <EmptyDescription>\n You&apos;re all caught up. New notifications will appear here.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <Button variant=\"outline\" size=\"sm\">\n <RefreshCcwIcon />\n Refresh\n </Button>\n </EmptyContent>\n </Empty>\n );\n};\n"
491
+ },
492
+ {
493
+ "name": "default",
494
+ "code": "import { IconFolderCode } from \"@tabler/icons-react\";\nimport { ArrowUpRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\n\nexport const Preview = () => {\n return (\n <Empty>\n <EmptyHeader>\n <EmptyMedia variant=\"icon\">\n <IconFolderCode />\n </EmptyMedia>\n <EmptyTitle>No Projects Yet</EmptyTitle>\n <EmptyDescription>\n You haven&apos;t created any projects yet. Get started by creating\n your first project.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <div className=\"flex gap-2\">\n <Button>Create Project</Button>\n <Button variant=\"outline\">Import Project</Button>\n </div>\n </EmptyContent>\n <Button\n variant=\"link\"\n asChild\n className=\"text-muted-foreground\"\n size=\"sm\"\n >\n <a href=\"#\">\n Learn More <ArrowUpRightIcon />\n </a>\n </Button>\n </Empty>\n );\n};\n"
495
+ },
496
+ {
497
+ "name": "input-group",
498
+ "code": "import { Kbd } from \"@rlx-widgets/kbd\";\nimport { SearchIcon } from \"lucide-react\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <Empty>\n <EmptyHeader>\n <EmptyTitle>404 - Not Found</EmptyTitle>\n <EmptyDescription>\n The page you&apos;re looking for doesn&apos;t exist. Try searching for\n what you need below.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <InputGroup className=\"sm:w-3/4\">\n <InputGroupInput placeholder=\"Try searching for pages...\" />\n <InputGroupAddon>\n <SearchIcon />\n </InputGroupAddon>\n <InputGroupAddon align=\"inline-end\">\n <Kbd>/</Kbd>\n </InputGroupAddon>\n </InputGroup>\n <EmptyDescription>\n Need help? <a href=\"#\">Contact support</a>\n </EmptyDescription>\n </EmptyContent>\n </Empty>\n );\n};\n"
499
+ },
500
+ {
501
+ "name": "outline",
502
+ "code": "import { IconCloud } from \"@tabler/icons-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\n\nexport const Preview = () => {\n return (\n <Empty className=\"border border-dashed\">\n <EmptyHeader>\n <EmptyMedia variant=\"icon\">\n <IconCloud />\n </EmptyMedia>\n <EmptyTitle>Cloud Storage Empty</EmptyTitle>\n <EmptyDescription>\n Upload files to your cloud storage to access them anywhere.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <Button variant=\"outline\" size=\"sm\">\n Upload Files\n </Button>\n </EmptyContent>\n </Empty>\n );\n};\n"
503
+ }
504
+ ]
505
+ },
506
+ {
507
+ "name": "Field",
508
+ "slug": "field",
509
+ "category": "widget",
510
+ "sourceCode": "\"use client\";\n\nimport { useMemo } from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Separator } from \"@rlx-widgets/separator\";\n\nfunction FieldSet({ className, ...props }: React.ComponentProps<\"fieldset\">) {\n return (\n <fieldset\n data-slot=\"field-set\"\n className={cn(\n \"flex flex-col gap-6\",\n \"has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction FieldLegend({\n className,\n variant = \"legend\",\n ...props\n}: React.ComponentProps<\"legend\"> & { variant?: \"legend\" | \"label\" }) {\n return (\n <legend\n data-slot=\"field-legend\"\n data-variant={variant}\n className={cn(\n \"mb-3 font-medium\",\n \"data-[variant=legend]:text-base\",\n \"data-[variant=label]:text-sm\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction FieldGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"field-group\"\n className={cn(\n \"group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nconst fieldVariants = cva(\n \"group/field flex w-full gap-3 data-[invalid=true]:text-destructive\",\n {\n variants: {\n orientation: {\n vertical: [\"flex-col [&>*]:w-full [&>.sr-only]:w-auto\"],\n horizontal: [\n \"flex-row items-center\",\n \"[&>[data-slot=field-label]]:flex-auto\",\n \"has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px\",\n ],\n responsive: [\n \"flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto\",\n \"@md/field-group:[&>[data-slot=field-label]]:flex-auto\",\n \"@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px\",\n ],\n },\n },\n defaultVariants: {\n orientation: \"vertical\",\n },\n }\n);\n\nfunction Field({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof fieldVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"field\"\n data-orientation={orientation}\n className={cn(fieldVariants({ orientation }), className)}\n {...props}\n />\n );\n}\n\nfunction FieldContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"field-content\"\n className={cn(\n \"group/field-content flex flex-1 flex-col gap-1.5 leading-snug\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction FieldLabel({\n className,\n ...props\n}: React.ComponentProps<typeof Label>) {\n return (\n <Label\n data-slot=\"field-label\"\n className={cn(\n \"group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50\",\n \"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4\",\n \"has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction FieldTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"field-label\"\n className={cn(\n \"flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction FieldDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"field-description\"\n className={cn(\n \"text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance\",\n \"last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5\",\n \"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction FieldSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<\"div\"> & {\n children?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"field-separator\"\n data-content={!!children}\n className={cn(\n \"relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2\",\n className\n )}\n {...props}\n >\n <Separator className=\"absolute inset-0 top-1/2\" />\n {children && (\n <span\n className=\"bg-background text-muted-foreground relative mx-auto block w-fit px-2\"\n data-slot=\"field-separator-content\"\n >\n {children}\n </span>\n )}\n </div>\n );\n}\n\nfunction FieldError({\n className,\n children,\n errors,\n ...props\n}: React.ComponentProps<\"div\"> & {\n errors?: Array<{ message?: string } | undefined>;\n}) {\n const content = useMemo(() => {\n if (children) {\n return children;\n }\n\n if (!errors) {\n return null;\n }\n\n if (errors?.length === 1 && errors[0]?.message) {\n return errors[0].message;\n }\n\n return (\n <ul className=\"ml-4 flex list-disc flex-col gap-1\">\n {errors.map(\n (error, index) =>\n error?.message && <li key={index}>{error.message}</li>\n )}\n </ul>\n );\n }, [children, errors]);\n\n if (!content) {\n return null;\n }\n\n return (\n <div\n role=\"alert\"\n data-slot=\"field-error\"\n className={cn(\"text-destructive text-sm font-normal\", className)}\n {...props}\n >\n {content}\n </div>\n );\n}\n\nexport {\n Field,\n FieldLabel,\n FieldDescription,\n FieldError,\n FieldGroup,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n FieldContent,\n FieldTitle,\n};\n",
511
+ "demos": [
512
+ {
513
+ "name": "checkbox",
514
+ "code": "import { Checkbox } from \"@rlx-widgets/checkbox\";\nimport {\n Field,\n FieldContent,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n} from \"@rlx-widgets/field\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldGroup>\n <FieldSet>\n <FieldLegend variant=\"label\">\n Show these items on the desktop\n </FieldLegend>\n <FieldDescription>\n Select the items you want to show on the desktop.\n </FieldDescription>\n <FieldGroup className=\"gap-3\">\n <Field orientation=\"horizontal\">\n <Checkbox id=\"finder-pref-9k2-hard-disks-ljj\" />\n <FieldLabel\n htmlFor=\"finder-pref-9k2-hard-disks-ljj\"\n className=\"font-normal\"\n defaultChecked\n >\n Hard disks\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <Checkbox id=\"finder-pref-9k2-external-disks-1yg\" />\n <FieldLabel\n htmlFor=\"finder-pref-9k2-external-disks-1yg\"\n className=\"font-normal\"\n >\n External disks\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <Checkbox id=\"finder-pref-9k2-cds-dvds-fzt\" />\n <FieldLabel\n htmlFor=\"finder-pref-9k2-cds-dvds-fzt\"\n className=\"font-normal\"\n >\n CDs, DVDs, and iPods\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <Checkbox id=\"finder-pref-9k2-connected-servers-6l2\" />\n <FieldLabel\n htmlFor=\"finder-pref-9k2-connected-servers-6l2\"\n className=\"font-normal\"\n >\n Connected servers\n </FieldLabel>\n </Field>\n </FieldGroup>\n </FieldSet>\n <FieldSeparator />\n <Field orientation=\"horizontal\">\n <Checkbox id=\"finder-pref-9k2-sync-folders-nep\" defaultChecked />\n <FieldContent>\n <FieldLabel htmlFor=\"finder-pref-9k2-sync-folders-nep\">\n Sync Desktop & Documents folders\n </FieldLabel>\n <FieldDescription>\n Your Desktop & Documents folders are being synced with iCloud\n Drive. You can access them from other devices.\n </FieldDescription>\n </FieldContent>\n </Field>\n </FieldGroup>\n </div>\n );\n};\n"
515
+ },
516
+ {
517
+ "name": "choice-card",
518
+ "code": "import { RadioGroup, RadioGroupItem } from \"@rlx-widgets/radio-group\";\nimport {\n Field,\n FieldContent,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldSet,\n FieldTitle,\n} from \"@rlx-widgets/field\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldGroup>\n <FieldSet>\n <FieldLabel htmlFor=\"compute-environment-p8w\">\n Compute Environment\n </FieldLabel>\n <FieldDescription>\n Select the compute environment for your cluster.\n </FieldDescription>\n <RadioGroup defaultValue=\"kubernetes\">\n <FieldLabel htmlFor=\"kubernetes-r2h\">\n <Field orientation=\"horizontal\">\n <FieldContent>\n <FieldTitle>Kubernetes</FieldTitle>\n <FieldDescription>\n Run GPU workloads on a K8s configured cluster.\n </FieldDescription>\n </FieldContent>\n <RadioGroupItem value=\"kubernetes\" id=\"kubernetes-r2h\" />\n </Field>\n </FieldLabel>\n <FieldLabel htmlFor=\"vm-z4k\">\n <Field orientation=\"horizontal\">\n <FieldContent>\n <FieldTitle>Virtual Machine</FieldTitle>\n <FieldDescription>\n Access a VM configured cluster to run GPU workloads.\n </FieldDescription>\n </FieldContent>\n <RadioGroupItem value=\"vm\" id=\"vm-z4k\" />\n </Field>\n </FieldLabel>\n </RadioGroup>\n </FieldSet>\n </FieldGroup>\n </div>\n );\n};\n"
519
+ },
520
+ {
521
+ "name": "default",
522
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Checkbox } from \"@rlx-widgets/checkbox\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Textarea } from \"@rlx-widgets/textarea\";\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSeparator,\n FieldSet,\n} from \"@rlx-widgets/field\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <form>\n <FieldGroup>\n <FieldSet>\n <FieldLegend>Payment Method</FieldLegend>\n <FieldDescription>\n All transactions are secure and encrypted\n </FieldDescription>\n <FieldGroup>\n <Field>\n <FieldLabel htmlFor=\"checkout-7j9-card-name-43j\">\n Name on Card\n </FieldLabel>\n <Input\n id=\"checkout-7j9-card-name-43j\"\n placeholder=\"Evil Rabbit\"\n required\n />\n </Field>\n <Field>\n <FieldLabel htmlFor=\"checkout-7j9-card-number-uw1\">\n Card Number\n </FieldLabel>\n <Input\n id=\"checkout-7j9-card-number-uw1\"\n placeholder=\"1234 5678 9012 3456\"\n required\n />\n <FieldDescription>\n Enter your 16-digit card number\n </FieldDescription>\n </Field>\n <div className=\"grid grid-cols-3 gap-4\">\n <Field>\n <FieldLabel htmlFor=\"checkout-exp-month-ts6\">\n Month\n </FieldLabel>\n <Select defaultValue=\"\">\n <SelectTrigger id=\"checkout-exp-month-ts6\">\n <SelectValue placeholder=\"MM\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"01\">01</SelectItem>\n <SelectItem value=\"02\">02</SelectItem>\n <SelectItem value=\"03\">03</SelectItem>\n <SelectItem value=\"04\">04</SelectItem>\n <SelectItem value=\"05\">05</SelectItem>\n <SelectItem value=\"06\">06</SelectItem>\n <SelectItem value=\"07\">07</SelectItem>\n <SelectItem value=\"08\">08</SelectItem>\n <SelectItem value=\"09\">09</SelectItem>\n <SelectItem value=\"10\">10</SelectItem>\n <SelectItem value=\"11\">11</SelectItem>\n <SelectItem value=\"12\">12</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n <Field>\n <FieldLabel htmlFor=\"checkout-7j9-exp-year-f59\">\n Year\n </FieldLabel>\n <Select defaultValue=\"\">\n <SelectTrigger id=\"checkout-7j9-exp-year-f59\">\n <SelectValue placeholder=\"YYYY\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"2024\">2024</SelectItem>\n <SelectItem value=\"2025\">2025</SelectItem>\n <SelectItem value=\"2026\">2026</SelectItem>\n <SelectItem value=\"2027\">2027</SelectItem>\n <SelectItem value=\"2028\">2028</SelectItem>\n <SelectItem value=\"2029\">2029</SelectItem>\n </SelectContent>\n </Select>\n </Field>\n <Field>\n <FieldLabel htmlFor=\"checkout-7j9-cvv\">CVV</FieldLabel>\n <Input id=\"checkout-7j9-cvv\" placeholder=\"123\" required />\n </Field>\n </div>\n </FieldGroup>\n </FieldSet>\n <FieldSeparator />\n <FieldSet>\n <FieldLegend>Billing Address</FieldLegend>\n <FieldDescription>\n The billing address associated with your payment method\n </FieldDescription>\n <FieldGroup>\n <Field orientation=\"horizontal\">\n <Checkbox\n id=\"checkout-7j9-same-as-shipping-wgm\"\n defaultChecked\n />\n <FieldLabel\n htmlFor=\"checkout-7j9-same-as-shipping-wgm\"\n className=\"font-normal\"\n >\n Same as shipping address\n </FieldLabel>\n </Field>\n </FieldGroup>\n </FieldSet>\n <FieldSet>\n <FieldGroup>\n <Field>\n <FieldLabel htmlFor=\"checkout-7j9-optional-comments\">\n Comments\n </FieldLabel>\n <Textarea\n id=\"checkout-7j9-optional-comments\"\n placeholder=\"Add any additional comments\"\n className=\"resize-none\"\n />\n </Field>\n </FieldGroup>\n </FieldSet>\n <Field orientation=\"horizontal\">\n <Button type=\"submit\">Submit</Button>\n <Button variant=\"outline\" type=\"button\">\n Cancel\n </Button>\n </Field>\n </FieldGroup>\n </form>\n </div>\n );\n};\n"
523
+ },
524
+ {
525
+ "name": "field-group",
526
+ "code": "import { Checkbox } from \"@rlx-widgets/checkbox\";\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldSeparator,\n FieldSet,\n} from \"@rlx-widgets/field\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldGroup>\n <FieldSet>\n <FieldLabel>Responses</FieldLabel>\n <FieldDescription>\n Get notified when ChatGPT responds to requests that take time, like\n research or image generation.\n </FieldDescription>\n <FieldGroup data-slot=\"checkbox-group\">\n <Field orientation=\"horizontal\">\n <Checkbox id=\"push\" defaultChecked disabled />\n <FieldLabel htmlFor=\"push\" className=\"font-normal\">\n Push notifications\n </FieldLabel>\n </Field>\n </FieldGroup>\n </FieldSet>\n <FieldSeparator />\n <FieldSet>\n <FieldLabel>Tasks</FieldLabel>\n <FieldDescription>\n Get notified when tasks you&apos;ve created have updates.{\" \"}\n <a href=\"#\">Manage tasks</a>\n </FieldDescription>\n <FieldGroup data-slot=\"checkbox-group\">\n <Field orientation=\"horizontal\">\n <Checkbox id=\"push-tasks\" />\n <FieldLabel htmlFor=\"push-tasks\" className=\"font-normal\">\n Push notifications\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <Checkbox id=\"email-tasks\" />\n <FieldLabel htmlFor=\"email-tasks\" className=\"font-normal\">\n Email notifications\n </FieldLabel>\n </Field>\n </FieldGroup>\n </FieldSet>\n </FieldGroup>\n </div>\n );\n};\n"
527
+ },
528
+ {
529
+ "name": "fieldset",
530
+ "code": "import {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldLegend,\n FieldSet,\n} from \"@rlx-widgets/field\";\nimport { Input } from \"@rlx-widgets/input\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md space-y-6\">\n <FieldSet>\n <FieldLegend>Address Information</FieldLegend>\n <FieldDescription>\n We need your address to deliver your order.\n </FieldDescription>\n <FieldGroup>\n <Field>\n <FieldLabel htmlFor=\"street\">Street Address</FieldLabel>\n <Input id=\"street\" type=\"text\" placeholder=\"123 Main St\" />\n </Field>\n <div className=\"grid grid-cols-2 gap-4\">\n <Field>\n <FieldLabel htmlFor=\"city\">City</FieldLabel>\n <Input id=\"city\" type=\"text\" placeholder=\"New York\" />\n </Field>\n <Field>\n <FieldLabel htmlFor=\"zip\">Postal Code</FieldLabel>\n <Input id=\"zip\" type=\"text\" placeholder=\"90502\" />\n </Field>\n </div>\n </FieldGroup>\n </FieldSet>\n </div>\n );\n};\n"
531
+ },
532
+ {
533
+ "name": "input",
534
+ "code": "import {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldSet,\n} from \"@rlx-widgets/field\";\nimport { Input } from \"@rlx-widgets/input\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldSet>\n <FieldGroup>\n <Field>\n <FieldLabel htmlFor=\"username\">Username</FieldLabel>\n <Input id=\"username\" type=\"text\" placeholder=\"Max Leiter\" />\n <FieldDescription>\n Choose a unique username for your account.\n </FieldDescription>\n </Field>\n <Field>\n <FieldLabel htmlFor=\"password\">Password</FieldLabel>\n <FieldDescription>\n Must be at least 8 characters long.\n </FieldDescription>\n <Input id=\"password\" type=\"password\" placeholder=\"********\" />\n </Field>\n </FieldGroup>\n </FieldSet>\n </div>\n );\n};\n"
535
+ },
536
+ {
537
+ "name": "radio",
538
+ "code": "import {\n Field,\n FieldDescription,\n FieldLabel,\n FieldSet,\n} from \"@rlx-widgets/field\";\nimport { RadioGroup, RadioGroupItem } from \"@rlx-widgets/radio-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldSet>\n <FieldLabel>Subscription Plan</FieldLabel>\n <FieldDescription>\n Yearly and lifetime plans offer significant savings.\n </FieldDescription>\n <RadioGroup defaultValue=\"monthly\">\n <Field orientation=\"horizontal\">\n <RadioGroupItem value=\"monthly\" id=\"plan-monthly\" />\n <FieldLabel htmlFor=\"plan-monthly\" className=\"font-normal\">\n Monthly ($9.99/month)\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <RadioGroupItem value=\"yearly\" id=\"plan-yearly\" />\n <FieldLabel htmlFor=\"plan-yearly\" className=\"font-normal\">\n Yearly ($99.99/year)\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <RadioGroupItem value=\"lifetime\" id=\"plan-lifetime\" />\n <FieldLabel htmlFor=\"plan-lifetime\" className=\"font-normal\">\n Lifetime ($299.99)\n </FieldLabel>\n </Field>\n </RadioGroup>\n </FieldSet>\n </div>\n );\n};\n"
539
+ },
540
+ {
541
+ "name": "responsive-layout",
542
+ "code": "import { Checkbox } from \"@rlx-widgets/checkbox\";\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldSeparator,\n FieldSet,\n} from \"@rlx-widgets/field\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldGroup>\n <FieldSet>\n <FieldLabel>Responses</FieldLabel>\n <FieldDescription>\n Get notified when ChatGPT responds to requests that take time, like\n research or image generation.\n </FieldDescription>\n <FieldGroup data-slot=\"checkbox-group\">\n <Field orientation=\"horizontal\">\n <Checkbox id=\"push\" defaultChecked disabled />\n <FieldLabel htmlFor=\"push\" className=\"font-normal\">\n Push notifications\n </FieldLabel>\n </Field>\n </FieldGroup>\n </FieldSet>\n <FieldSeparator />\n <FieldSet>\n <FieldLabel>Tasks</FieldLabel>\n <FieldDescription>\n Get notified when tasks you&apos;ve created have updates.{\" \"}\n <a href=\"#\">Manage tasks</a>\n </FieldDescription>\n <FieldGroup data-slot=\"checkbox-group\">\n <Field orientation=\"horizontal\">\n <Checkbox id=\"push-tasks\" />\n <FieldLabel htmlFor=\"push-tasks\" className=\"font-normal\">\n Push notifications\n </FieldLabel>\n </Field>\n <Field orientation=\"horizontal\">\n <Checkbox id=\"email-tasks\" />\n <FieldLabel htmlFor=\"email-tasks\" className=\"font-normal\">\n Email notifications\n </FieldLabel>\n </Field>\n </FieldGroup>\n </FieldSet>\n </FieldGroup>\n </div>\n );\n};\n"
543
+ },
544
+ {
545
+ "name": "select",
546
+ "code": "import { Field, FieldDescription, FieldLabel } from \"@rlx-widgets/field\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <Field>\n <FieldLabel>Department</FieldLabel>\n <Select>\n <SelectTrigger>\n <SelectValue placeholder=\"Choose department\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"engineering\">Engineering</SelectItem>\n <SelectItem value=\"design\">Design</SelectItem>\n <SelectItem value=\"marketing\">Marketing</SelectItem>\n <SelectItem value=\"sales\">Sales</SelectItem>\n <SelectItem value=\"support\">Customer Support</SelectItem>\n <SelectItem value=\"hr\">Human Resources</SelectItem>\n <SelectItem value=\"finance\">Finance</SelectItem>\n <SelectItem value=\"operations\">Operations</SelectItem>\n </SelectContent>\n </Select>\n <FieldDescription>\n Select your department or area of work.\n </FieldDescription>\n </Field>\n </div>\n );\n};\n"
547
+ },
548
+ {
549
+ "name": "slider",
550
+ "code": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Field, FieldDescription, FieldTitle } from \"@rlx-widgets/field\";\nimport { Slider } from \"@rlx-widgets/slider\";\n\nexport const Preview = () => {\n const [value, setValue] = useState([200, 800]);\n return (\n <div className=\"w-full max-w-md\">\n <Field>\n <FieldTitle>Price Range</FieldTitle>\n <FieldDescription>\n Set your budget range ($\n <span className=\"font-medium tabular-nums\">{value[0]}</span> -{\" \"}\n <span className=\"font-medium tabular-nums\">{value[1]}</span>).\n </FieldDescription>\n <Slider\n value={value}\n onValueChange={setValue}\n max={1000}\n min={0}\n step={10}\n className=\"mt-2 w-full\"\n aria-label=\"Price Range\"\n />\n </Field>\n </div>\n );\n};\n"
551
+ },
552
+ {
553
+ "name": "switch",
554
+ "code": "import { Switch } from \"@rlx-widgets/switch\";\nimport {\n Field,\n FieldContent,\n FieldDescription,\n FieldLabel,\n} from \"@rlx-widgets/field\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <Field orientation=\"horizontal\">\n <FieldContent>\n <FieldLabel htmlFor=\"2fa\">Multi-factor authentication</FieldLabel>\n <FieldDescription>\n Enable multi-factor authentication. If you do not have a two-factor\n device, you can use a one-time code sent to your email.\n </FieldDescription>\n </FieldContent>\n <Switch id=\"2fa\" />\n </Field>\n </div>\n );\n};\n"
555
+ },
556
+ {
557
+ "name": "textarea",
558
+ "code": "import { Textarea } from \"@rlx-widgets/textarea\";\nimport {\n Field,\n FieldDescription,\n FieldGroup,\n FieldLabel,\n FieldSet,\n} from \"@rlx-widgets/field\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full max-w-md\">\n <FieldSet>\n <FieldGroup>\n <Field>\n <FieldLabel htmlFor=\"feedback\">Feedback</FieldLabel>\n <Textarea\n id=\"feedback\"\n placeholder=\"Your feedback helps us improve...\"\n rows={4}\n />\n <FieldDescription>\n Share your thoughts about our service.\n </FieldDescription>\n </Field>\n </FieldGroup>\n </FieldSet>\n </div>\n );\n};\n"
559
+ }
560
+ ]
561
+ },
562
+ {
563
+ "name": "Hover Card",
564
+ "slug": "hover-card",
565
+ "category": "widget",
566
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as HoverCardPrimitive from \"@radix-ui/react-hover-card\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction HoverCard({\n ...props\n}: React.ComponentProps<typeof HoverCardPrimitive.Root>) {\n return <HoverCardPrimitive.Root data-slot=\"hover-card\" {...props} />;\n}\n\nfunction HoverCardTrigger({\n ...props\n}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {\n return (\n <HoverCardPrimitive.Trigger data-slot=\"hover-card-trigger\" {...props} />\n );\n}\n\nfunction HoverCardContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {\n return (\n <HoverCardPrimitive.Portal data-slot=\"hover-card-portal\">\n <HoverCardPrimitive.Content\n data-slot=\"hover-card-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden\",\n className\n )}\n {...props}\n />\n </HoverCardPrimitive.Portal>\n );\n}\n\nexport { HoverCard, HoverCardTrigger, HoverCardContent };\n",
567
+ "demos": [
568
+ {
569
+ "name": "default",
570
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n HoverCard,\n HoverCardContent,\n HoverCardTrigger,\n} from \"@rlx-widgets/hover-card\";\n\nexport const Preview = () => {\n return (\n <HoverCard>\n <HoverCardTrigger asChild>\n <Button variant=\"link\">@nextjs</Button>\n </HoverCardTrigger>\n <HoverCardContent className=\"w-80\">\n <div className=\"flex justify-between gap-4\">\n <Avatar>\n <AvatarImage src=\"https://github.com/vercel.png\" />\n <AvatarFallback>VC</AvatarFallback>\n </Avatar>\n <div className=\"space-y-1\">\n <h4 className=\"text-sm font-semibold\">@nextjs</h4>\n <p className=\"text-sm\">\n The React Framework – created and maintained by @vercel.\n </p>\n <div className=\"text-muted-foreground text-xs\">\n Joined December 2021\n </div>\n </div>\n </div>\n </HoverCardContent>\n </HoverCard>\n );\n};\n"
571
+ }
572
+ ]
573
+ },
574
+ {
575
+ "name": "Input",
576
+ "slug": "input",
577
+ "category": "widget",
578
+ "sourceCode": "import * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n <input\n type={type}\n data-slot=\"input\"\n className={cn(\n \"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n \"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n \"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Input };\n",
579
+ "demos": [
580
+ {
581
+ "name": "default",
582
+ "code": "import { Input } from \"@rlx-widgets/input\";\n\nexport const Preview = () => {\n return <Input type=\"email\" placeholder=\"Email\" />;\n};\n"
583
+ },
584
+ {
585
+ "name": "disabled",
586
+ "code": "import { Input } from \"@rlx-widgets/input\";\n\nexport const Preview = () => {\n return <Input disabled type=\"email\" placeholder=\"Email\" />;\n};\n"
587
+ },
588
+ {
589
+ "name": "file",
590
+ "code": "import { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm items-center gap-3\">\n <Label htmlFor=\"picture\">Picture</Label>\n <Input id=\"picture\" type=\"file\" />\n </div>\n );\n};\n"
591
+ },
592
+ {
593
+ "name": "form",
594
+ "code": "\"use client\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { toast } from \"sonner\";\nimport { useForm } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@rlx-widgets/form\";\n\nconst FormSchema = z.object({\n username: z.string().min(2, {\n message: \"Username must be at least 2 characters.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n username: \"\",\n },\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"w-2/3 space-y-6\">\n <FormField\n control={form.control}\n name=\"username\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Username</FormLabel>\n <FormControl>\n <Input placeholder=\"shadcn\" {...field} />\n </FormControl>\n <FormDescription>\n This is your public display name.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
595
+ },
596
+ {
597
+ "name": "with-button",
598
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Input } from \"@rlx-widgets/input\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-sm items-center gap-2\">\n <Input type=\"email\" placeholder=\"Email\" />\n <Button type=\"submit\" variant=\"outline\">\n Subscribe\n </Button>\n </div>\n );\n};\n"
599
+ },
600
+ {
601
+ "name": "with-label",
602
+ "code": "import { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm items-center gap-3\">\n <Label htmlFor=\"email\">Email</Label>\n <Input type=\"email\" id=\"email\" placeholder=\"Email\" />\n </div>\n );\n};\n"
603
+ }
604
+ ]
605
+ },
606
+ {
607
+ "name": "Input Group",
608
+ "slug": "input-group",
609
+ "category": "widget",
610
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Textarea } from \"@rlx-widgets/textarea\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nfunction InputGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"input-group\"\n role=\"group\"\n className={cn(\n \"group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none\",\n \"h-9 min-w-0 has-[>textarea]:h-auto\",\n\n // Variants based on alignment.\n \"has-[>[data-align=inline-start]]:[&>input]:pl-2\",\n \"has-[>[data-align=inline-end]]:[&>input]:pr-2\",\n \"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3\",\n \"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3\",\n\n // Focus state.\n \"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]\",\n\n // Error state.\n \"has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40\",\n\n className\n )}\n {...props}\n />\n );\n}\n\nconst inputGroupAddonVariants = cva(\n \"text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50\",\n {\n variants: {\n align: {\n \"inline-start\":\n \"order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]\",\n \"inline-end\":\n \"order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]\",\n \"block-start\":\n \"order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5\",\n \"block-end\":\n \"order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5\",\n },\n },\n defaultVariants: {\n align: \"inline-start\",\n },\n }\n);\n\nfunction InputGroupAddon({\n className,\n align = \"inline-start\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof inputGroupAddonVariants>) {\n return (\n <div\n role=\"group\"\n data-slot=\"input-group-addon\"\n data-align={align}\n className={cn(inputGroupAddonVariants({ align }), className)}\n onClick={(e) => {\n if ((e.target as HTMLElement).closest(\"button\")) {\n return;\n }\n e.currentTarget.parentElement?.querySelector(\"input\")?.focus();\n }}\n {...props}\n />\n );\n}\n\nconst inputGroupButtonVariants = cva(\n \"text-sm shadow-none flex gap-2 items-center\",\n {\n variants: {\n size: {\n xs: \"h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2\",\n sm: \"h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5\",\n \"icon-xs\":\n \"size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0\",\n \"icon-sm\": \"size-8 p-0 has-[>svg]:p-0\",\n },\n },\n defaultVariants: {\n size: \"xs\",\n },\n }\n);\n\nfunction InputGroupButton({\n className,\n type = \"button\",\n variant = \"ghost\",\n size = \"xs\",\n ...props\n}: Omit<React.ComponentProps<typeof Button>, \"size\"> &\n VariantProps<typeof inputGroupButtonVariants>) {\n return (\n <Button\n type={type}\n data-size={size}\n variant={variant}\n className={cn(inputGroupButtonVariants({ size }), className)}\n {...props}\n />\n );\n}\n\nfunction InputGroupText({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n className={cn(\n \"text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction InputGroupInput({\n className,\n ...props\n}: React.ComponentProps<\"input\">) {\n return (\n <Input\n data-slot=\"input-group-control\"\n className={cn(\n \"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction InputGroupTextarea({\n className,\n ...props\n}: React.ComponentProps<\"textarea\">) {\n return (\n <Textarea\n data-slot=\"input-group-control\"\n className={cn(\n \"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupText,\n InputGroupInput,\n InputGroupTextarea,\n};\n",
611
+ "demos": [
612
+ {
613
+ "name": "button",
614
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\nimport { useCopyToClipboard } from \"@rlx-hooks/use-copy-to-clipboard\";\nimport {\n IconCheck,\n IconCopy,\n IconInfoCircle,\n IconStar,\n} from \"@tabler/icons-react\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n const { copyToClipboard, isCopied } = useCopyToClipboard();\n const [isFavorite, setIsFavorite] = React.useState(false);\n\n return (\n <div className=\"grid w-full max-w-sm gap-6\">\n <InputGroup>\n <InputGroupInput placeholder=\"https://x.com/shadcn\" readOnly />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupButton\n aria-label=\"Copy\"\n title=\"Copy\"\n size=\"icon-xs\"\n onClick={() => {\n copyToClipboard(\"https://x.com/shadcn\");\n }}\n >\n {isCopied ? <IconCheck /> : <IconCopy />}\n </InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup className=\"[--radius:9999px]\">\n <Popover>\n <PopoverTrigger asChild>\n <InputGroupAddon>\n <InputGroupButton variant=\"secondary\" size=\"icon-xs\">\n <IconInfoCircle />\n </InputGroupButton>\n </InputGroupAddon>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"flex flex-col gap-1 rounded-xl text-sm\"\n >\n <p className=\"font-medium\">Your connection is not secure.</p>\n <p>You should not enter any sensitive information on this site.</p>\n </PopoverContent>\n </Popover>\n <InputGroupAddon className=\"text-muted-foreground pl-1.5\">\n https://\n </InputGroupAddon>\n <InputGroupInput id=\"input-secure-19\" />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupButton\n onClick={() => setIsFavorite(!isFavorite)}\n size=\"icon-xs\"\n >\n <IconStar\n data-favorite={isFavorite}\n className=\"data-[favorite=true]:fill-blue-600 data-[favorite=true]:stroke-blue-600\"\n />\n </InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"Type to search...\" />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupButton variant=\"secondary\">Search</InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
615
+ },
616
+ {
617
+ "name": "button-group",
618
+ "code": "import { ButtonGroup, ButtonGroupText } from \"@rlx-widgets/button-group\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Link2Icon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-6\">\n <ButtonGroup>\n <ButtonGroupText asChild>\n <Label htmlFor=\"url\">https://</Label>\n </ButtonGroupText>\n <InputGroup>\n <InputGroupInput id=\"url\" />\n <InputGroupAddon align=\"inline-end\">\n <Link2Icon />\n </InputGroupAddon>\n </InputGroup>\n <ButtonGroupText>.com</ButtonGroupText>\n </ButtonGroup>\n </div>\n );\n};\n"
619
+ },
620
+ {
621
+ "name": "custom-input",
622
+ "code": "\"use client\";\n\nimport TextareaAutosize from \"react-textarea-autosize\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-6\">\n <InputGroup>\n <TextareaAutosize\n data-slot=\"input-group-control\"\n className=\"flex field-sizing-content min-h-16 w-full resize-none rounded-md bg-transparent px-3 py-2.5 text-base transition-[color,box-shadow] outline-none md:text-sm\"\n placeholder=\"Autoresize textarea...\"\n />\n <InputGroupAddon align=\"block-end\">\n <InputGroupButton className=\"ml-auto\" size=\"sm\" variant=\"default\">\n Submit\n </InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
623
+ },
624
+ {
625
+ "name": "default",
626
+ "code": "import { ArrowUpIcon, Search } from \"lucide-react\";\nimport { IconCheck, IconInfoCircle, IconPlus } from \"@tabler/icons-react\";\nimport { Separator } from \"@rlx-widgets/separator\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@rlx-widgets/tooltip\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n InputGroupText,\n InputGroupTextarea,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-6\">\n <InputGroup>\n <InputGroupInput placeholder=\"Search...\" />\n <InputGroupAddon>\n <Search />\n </InputGroupAddon>\n <InputGroupAddon align=\"inline-end\">12 results</InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"example.com\" className=\"!pl-1\" />\n <InputGroupAddon>\n <InputGroupText>https://</InputGroupText>\n </InputGroupAddon>\n <InputGroupAddon align=\"inline-end\">\n <Tooltip>\n <TooltipTrigger asChild>\n <InputGroupButton className=\"rounded-full\" size=\"icon-xs\">\n <IconInfoCircle />\n </InputGroupButton>\n </TooltipTrigger>\n <TooltipContent>This is content in a tooltip.</TooltipContent>\n </Tooltip>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupTextarea placeholder=\"Ask, Search or Chat...\" />\n <InputGroupAddon align=\"block-end\">\n <InputGroupButton\n variant=\"outline\"\n className=\"rounded-full\"\n size=\"icon-xs\"\n >\n <IconPlus />\n </InputGroupButton>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <InputGroupButton variant=\"ghost\">Auto</InputGroupButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side=\"top\"\n align=\"start\"\n className=\"[--radius:0.95rem]\"\n >\n <DropdownMenuItem>Auto</DropdownMenuItem>\n <DropdownMenuItem>Agent</DropdownMenuItem>\n <DropdownMenuItem>Manual</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n <InputGroupText className=\"ml-auto\">52% used</InputGroupText>\n <Separator orientation=\"vertical\" className=\"!h-4\" />\n <InputGroupButton\n variant=\"default\"\n className=\"rounded-full\"\n size=\"icon-xs\"\n disabled\n >\n <ArrowUpIcon />\n <span className=\"sr-only\">Send</span>\n </InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"@shadcn\" />\n <InputGroupAddon align=\"inline-end\">\n <div className=\"bg-primary text-primary-foreground flex size-4 items-center justify-center rounded-full\">\n <IconCheck className=\"size-3\" />\n </div>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
627
+ },
628
+ {
629
+ "name": "dropdown",
630
+ "code": "import { ChevronDownIcon, MoreHorizontal } from \"lucide-react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-4\">\n <InputGroup>\n <InputGroupInput placeholder=\"Enter file name\" />\n <InputGroupAddon align=\"inline-end\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <InputGroupButton\n variant=\"ghost\"\n aria-label=\"More\"\n size=\"icon-xs\"\n >\n <MoreHorizontal />\n </InputGroupButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem>Settings</DropdownMenuItem>\n <DropdownMenuItem>Copy path</DropdownMenuItem>\n <DropdownMenuItem>Open location</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup className=\"[--radius:1rem]\">\n <InputGroupInput placeholder=\"Enter search query\" />\n <InputGroupAddon align=\"inline-end\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <InputGroupButton variant=\"ghost\" className=\"!pr-1.5 text-xs\">\n Search In... <ChevronDownIcon className=\"size-3\" />\n </InputGroupButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"[--radius:0.95rem]\">\n <DropdownMenuItem>Documentation</DropdownMenuItem>\n <DropdownMenuItem>Blog Posts</DropdownMenuItem>\n <DropdownMenuItem>Changelog</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
631
+ },
632
+ {
633
+ "name": "icon",
634
+ "code": "import {\n CheckIcon,\n CreditCardIcon,\n InfoIcon,\n MailIcon,\n SearchIcon,\n StarIcon,\n} from \"lucide-react\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-6\">\n <InputGroup>\n <InputGroupInput placeholder=\"Search...\" />\n <InputGroupAddon>\n <SearchIcon />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput type=\"email\" placeholder=\"Enter your email\" />\n <InputGroupAddon>\n <MailIcon />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"Card number\" />\n <InputGroupAddon>\n <CreditCardIcon />\n </InputGroupAddon>\n <InputGroupAddon align=\"inline-end\">\n <CheckIcon />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"Card number\" />\n <InputGroupAddon align=\"inline-end\">\n <StarIcon />\n <InfoIcon />\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
635
+ },
636
+ {
637
+ "name": "label",
638
+ "code": "import { InfoIcon } from \"lucide-react\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@rlx-widgets/tooltip\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-4\">\n <InputGroup>\n <InputGroupInput id=\"email\" placeholder=\"shadcn\" />\n <InputGroupAddon>\n <Label htmlFor=\"email\">@</Label>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput id=\"email-2\" placeholder=\"shadcn@vercel.com\" />\n <InputGroupAddon align=\"block-start\">\n <Label htmlFor=\"email-2\" className=\"text-foreground\">\n Email\n </Label>\n <Tooltip>\n <TooltipTrigger asChild>\n <InputGroupButton\n variant=\"ghost\"\n aria-label=\"Help\"\n className=\"ml-auto rounded-full\"\n size=\"icon-xs\"\n >\n <InfoIcon />\n </InputGroupButton>\n </TooltipTrigger>\n <TooltipContent>\n <p>We&apos;ll use this to send you notifications</p>\n </TooltipContent>\n </Tooltip>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
639
+ },
640
+ {
641
+ "name": "spinner",
642
+ "code": "import { LoaderIcon } from \"lucide-react\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n InputGroupText,\n} from \"@rlx-widgets/input-group\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-4\">\n <InputGroup data-disabled>\n <InputGroupInput placeholder=\"Searching...\" disabled />\n <InputGroupAddon align=\"inline-end\">\n <Spinner />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup data-disabled>\n <InputGroupInput placeholder=\"Processing...\" disabled />\n <InputGroupAddon>\n <Spinner />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup data-disabled>\n <InputGroupInput placeholder=\"Saving changes...\" disabled />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupText>Saving...</InputGroupText>\n <Spinner />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup data-disabled>\n <InputGroupInput placeholder=\"Refreshing data...\" disabled />\n <InputGroupAddon>\n <LoaderIcon className=\"animate-spin\" />\n </InputGroupAddon>\n <InputGroupAddon align=\"inline-end\">\n <InputGroupText className=\"text-muted-foreground\">\n Please wait...\n </InputGroupText>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
643
+ },
644
+ {
645
+ "name": "text",
646
+ "code": "import {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n InputGroupText,\n InputGroupTextarea,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-6\">\n <InputGroup>\n <InputGroupAddon>\n <InputGroupText>$</InputGroupText>\n </InputGroupAddon>\n <InputGroupInput placeholder=\"0.00\" />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupText>USD</InputGroupText>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupAddon>\n <InputGroupText>https://</InputGroupText>\n </InputGroupAddon>\n <InputGroupInput placeholder=\"example.com\" className=\"!pl-0.5\" />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupText>.com</InputGroupText>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"Enter your username\" />\n <InputGroupAddon align=\"inline-end\">\n <InputGroupText>@company.com</InputGroupText>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupTextarea placeholder=\"Enter your message\" />\n <InputGroupAddon align=\"block-end\">\n <InputGroupText className=\"text-muted-foreground text-xs\">\n 120 characters left\n </InputGroupText>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
647
+ },
648
+ {
649
+ "name": "textarea",
650
+ "code": "import {\n IconBrandJavascript,\n IconCopy,\n IconCornerDownLeft,\n IconRefresh,\n} from \"@tabler/icons-react\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupText,\n InputGroupTextarea,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-md gap-4\">\n <InputGroup>\n <InputGroupTextarea\n id=\"textarea-code-32\"\n placeholder=\"console.log('Hello, world!');\"\n className=\"min-h-[200px]\"\n />\n <InputGroupAddon align=\"block-end\" className=\"border-t\">\n <InputGroupText>Line 1, Column 1</InputGroupText>\n <InputGroupButton size=\"sm\" className=\"ml-auto\" variant=\"default\">\n Run <IconCornerDownLeft />\n </InputGroupButton>\n </InputGroupAddon>\n <InputGroupAddon align=\"block-start\" className=\"border-b\">\n <InputGroupText className=\"font-mono font-medium\">\n <IconBrandJavascript />\n script.js\n </InputGroupText>\n <InputGroupButton className=\"ml-auto\" size=\"icon-xs\">\n <IconRefresh />\n </InputGroupButton>\n <InputGroupButton variant=\"ghost\" size=\"icon-xs\">\n <IconCopy />\n </InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
651
+ },
652
+ {
653
+ "name": "tooltip",
654
+ "code": "import { HelpCircle, InfoIcon } from \"lucide-react\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@rlx-widgets/tooltip\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"grid w-full max-w-sm gap-4\">\n <InputGroup>\n <InputGroupInput placeholder=\"Enter password\" type=\"password\" />\n <InputGroupAddon align=\"inline-end\">\n <Tooltip>\n <TooltipTrigger asChild>\n <InputGroupButton\n variant=\"ghost\"\n aria-label=\"Info\"\n size=\"icon-xs\"\n >\n <InfoIcon />\n </InputGroupButton>\n </TooltipTrigger>\n <TooltipContent>\n <p>Password must be at least 8 characters</p>\n </TooltipContent>\n </Tooltip>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"Your email address\" />\n <InputGroupAddon align=\"inline-end\">\n <Tooltip>\n <TooltipTrigger asChild>\n <InputGroupButton\n variant=\"ghost\"\n aria-label=\"Help\"\n size=\"icon-xs\"\n >\n <HelpCircle />\n </InputGroupButton>\n </TooltipTrigger>\n <TooltipContent>\n <p>We&apos;ll use this to send you notifications</p>\n </TooltipContent>\n </Tooltip>\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupInput placeholder=\"Enter API key\" />\n <Tooltip>\n <TooltipTrigger asChild>\n <InputGroupAddon>\n <InputGroupButton\n variant=\"ghost\"\n aria-label=\"Help\"\n size=\"icon-xs\"\n >\n <HelpCircle />\n </InputGroupButton>\n </InputGroupAddon>\n </TooltipTrigger>\n <TooltipContent side=\"left\">\n <p>Click for help with API keys</p>\n </TooltipContent>\n </Tooltip>\n </InputGroup>\n </div>\n );\n};\n"
655
+ }
656
+ ]
657
+ },
658
+ {
659
+ "name": "Input Otp",
660
+ "slug": "input-otp",
661
+ "category": "widget",
662
+ "demos": [
663
+ {
664
+ "name": "controlled",
665
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { InputOTP, InputOTPGroup, InputOTPSlot } from \"@rlx-widgets/input-otp\";\n\nexport const Preview = () => {\n const [value, setValue] = React.useState(\"\");\n\n return (\n <div className=\"space-y-2\">\n <InputOTP\n maxLength={6}\n value={value}\n onChange={(value) => setValue(value)}\n >\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n <InputOTPSlot index={2} />\n <InputOTPSlot index={3} />\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n <div className=\"text-center text-sm\">\n {value === \"\" ? (\n <>Enter your one-time password.</>\n ) : (\n <>You entered: {value}</>\n )}\n </div>\n </div>\n );\n};\n"
666
+ },
667
+ {
668
+ "name": "default",
669
+ "code": "import {\n InputOTP,\n InputOTPGroup,\n InputOTPSeparator,\n InputOTPSlot,\n} from \"@rlx-widgets/input-otp\";\n\nexport const Preview = () => {\n return (\n <InputOTP maxLength={6}>\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n <InputOTPSlot index={2} />\n </InputOTPGroup>\n <InputOTPSeparator />\n <InputOTPGroup>\n <InputOTPSlot index={3} />\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n );\n};\n"
670
+ },
671
+ {
672
+ "name": "form",
673
+ "code": "\"use client\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { InputOTP, InputOTPGroup, InputOTPSlot } from \"@rlx-widgets/input-otp\";\nimport { toast } from \"sonner\";\nimport { useForm } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@rlx-widgets/form\";\n\nconst FormSchema = z.object({\n pin: z.string().min(6, {\n message: \"Your one-time password must be 6 characters.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n pin: \"\",\n },\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"w-2/3 space-y-6\">\n <FormField\n control={form.control}\n name=\"pin\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>One-Time Password</FormLabel>\n <FormControl>\n <InputOTP maxLength={6} {...field}>\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n <InputOTPSlot index={2} />\n <InputOTPSlot index={3} />\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n </FormControl>\n <FormDescription>\n Please enter the one-time password sent to your phone.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
674
+ },
675
+ {
676
+ "name": "pattern",
677
+ "code": "\"use client\";\n\nimport { REGEXP_ONLY_DIGITS_AND_CHARS } from \"input-otp\";\nimport { InputOTP, InputOTPGroup, InputOTPSlot } from \"@rlx-widgets/input-otp\";\n\nexport const Preview = () => {\n return (\n <InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}>\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n <InputOTPSlot index={2} />\n <InputOTPSlot index={3} />\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n );\n};\n"
678
+ },
679
+ {
680
+ "name": "separator",
681
+ "code": "import React from \"react\";\nimport {\n InputOTP,\n InputOTPGroup,\n InputOTPSeparator,\n InputOTPSlot,\n} from \"@rlx-widgets/input-otp\";\n\nexport const Preview = () => {\n return (\n <InputOTP maxLength={6}>\n <InputOTPGroup>\n <InputOTPSlot index={0} />\n <InputOTPSlot index={1} />\n </InputOTPGroup>\n <InputOTPSeparator />\n <InputOTPGroup>\n <InputOTPSlot index={2} />\n <InputOTPSlot index={3} />\n </InputOTPGroup>\n <InputOTPSeparator />\n <InputOTPGroup>\n <InputOTPSlot index={4} />\n <InputOTPSlot index={5} />\n </InputOTPGroup>\n </InputOTP>\n );\n};\n"
682
+ }
683
+ ]
684
+ },
685
+ {
686
+ "name": "Item",
687
+ "slug": "item",
688
+ "category": "widget",
689
+ "sourceCode": "import * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { Separator } from \"@rlx-widgets/separator\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nfunction ItemGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n role=\"list\"\n data-slot=\"item-group\"\n className={cn(\"group/item-group flex flex-col\", className)}\n {...props}\n />\n );\n}\n\nfunction ItemSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"item-separator\"\n orientation=\"horizontal\"\n className={cn(\"my-0\", className)}\n {...props}\n />\n );\n}\n\nconst itemVariants = cva(\n \"group/item flex items-center border border-transparent text-sm rounded-md transition-colors [a]:hover:bg-accent/50 [a]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n outline: \"border-border\",\n muted: \"bg-muted/50\",\n },\n size: {\n default: \"p-4 gap-4 \",\n sm: \"py-3 px-4 gap-2.5\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nfunction Item({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof itemVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"div\";\n return (\n <Comp\n data-slot=\"item\"\n data-variant={variant}\n data-size={size}\n className={cn(itemVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nconst itemMediaVariants = cva(\n \"flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4\",\n image:\n \"size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction ItemMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof itemMediaVariants>) {\n return (\n <div\n data-slot=\"item-media\"\n data-variant={variant}\n className={cn(itemMediaVariants({ variant, className }))}\n {...props}\n />\n );\n}\n\nfunction ItemContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-content\"\n className={cn(\n \"flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ItemTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-title\"\n className={cn(\n \"flex w-fit items-center gap-2 text-sm leading-snug font-medium\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ItemDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return (\n <p\n data-slot=\"item-description\"\n className={cn(\n \"text-muted-foreground line-clamp-2 text-sm leading-normal font-normal text-balance\",\n \"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ItemActions({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-actions\"\n className={cn(\"flex items-center gap-2\", className)}\n {...props}\n />\n );\n}\n\nfunction ItemHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-header\"\n className={cn(\n \"flex basis-full items-center justify-between gap-2\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ItemFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"item-footer\"\n className={cn(\n \"flex basis-full items-center justify-between gap-2\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Item,\n ItemMedia,\n ItemContent,\n ItemActions,\n ItemGroup,\n ItemSeparator,\n ItemTitle,\n ItemDescription,\n ItemHeader,\n ItemFooter,\n};\n",
690
+ "demos": [
691
+ {
692
+ "name": "avatar",
693
+ "code": "import { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { Plus } from \"lucide-react\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-lg flex-col gap-6\">\n <Item variant=\"outline\">\n <ItemMedia>\n <Avatar className=\"size-10\">\n <AvatarImage src=\"https://github.com/evilrabbit.png\" />\n <AvatarFallback>ER</AvatarFallback>\n </Avatar>\n </ItemMedia>\n <ItemContent>\n <ItemTitle>Evil Rabbit</ItemTitle>\n <ItemDescription>Last seen 5 months ago</ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button\n size=\"icon-sm\"\n variant=\"outline\"\n className=\"rounded-full\"\n aria-label=\"Invite\"\n >\n <Plus />\n </Button>\n </ItemActions>\n </Item>\n <Item variant=\"outline\">\n <ItemMedia>\n <div className=\"*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale\">\n <Avatar className=\"hidden sm:flex\">\n <AvatarImage src=\"https://github.com/shadcn.png\" alt=\"@shadcn\" />\n <AvatarFallback>CN</AvatarFallback>\n </Avatar>\n <Avatar className=\"hidden sm:flex\">\n <AvatarImage\n src=\"https://github.com/maxleiter.png\"\n alt=\"@maxleiter\"\n />\n <AvatarFallback>LR</AvatarFallback>\n </Avatar>\n <Avatar>\n <AvatarImage\n src=\"https://github.com/evilrabbit.png\"\n alt=\"@evilrabbit\"\n />\n <AvatarFallback>ER</AvatarFallback>\n </Avatar>\n </div>\n </ItemMedia>\n <ItemContent>\n <ItemTitle>No Team Members</ItemTitle>\n <ItemDescription>\n Invite your team to collaborate on this project.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button size=\"sm\" variant=\"outline\">\n Invite\n </Button>\n </ItemActions>\n </Item>\n </div>\n );\n};\n"
694
+ },
695
+ {
696
+ "name": "default",
697
+ "code": "import { BadgeCheckIcon, ChevronRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-6\">\n <Item variant=\"outline\">\n <ItemContent>\n <ItemTitle>Basic Item</ItemTitle>\n <ItemDescription>\n A simple item with title and description.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"outline\" size=\"sm\">\n Action\n </Button>\n </ItemActions>\n </Item>\n <Item variant=\"outline\" size=\"sm\" asChild>\n <a href=\"#\">\n <ItemMedia>\n <BadgeCheckIcon className=\"size-5\" />\n </ItemMedia>\n <ItemContent>\n <ItemTitle>Your profile has been verified.</ItemTitle>\n </ItemContent>\n <ItemActions>\n <ChevronRightIcon className=\"size-4\" />\n </ItemActions>\n </a>\n </Item>\n </div>\n );\n};\n"
698
+ },
699
+ {
700
+ "name": "dropdown",
701
+ "code": "\"use client\";\n\nimport { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"@rlx-widgets/dropdown-menu\";\nimport {\n Item,\n ItemContent,\n ItemDescription,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nconst people = [\n {\n username: \"shadcn\",\n avatar: \"https://github.com/shadcn.png\",\n email: \"shadcn@vercel.com\",\n },\n {\n username: \"maxleiter\",\n avatar: \"https://github.com/maxleiter.png\",\n email: \"maxleiter@vercel.com\",\n },\n {\n username: \"evilrabbit\",\n avatar: \"https://github.com/evilrabbit.png\",\n email: \"evilrabbit@vercel.com\",\n },\n];\n\nexport const Preview = () => {\n return (\n <div className=\"flex min-h-64 w-full max-w-md flex-col items-center gap-6\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"w-fit\">\n Select <ChevronDownIcon />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"w-72 [--radius:0.65rem]\" align=\"end\">\n {people.map((person) => (\n <DropdownMenuItem key={person.username} className=\"p-0\">\n <Item size=\"sm\" className=\"w-full p-2\">\n <ItemMedia>\n <Avatar className=\"size-8\">\n <AvatarImage src={person.avatar} className=\"grayscale\" />\n <AvatarFallback>{person.username.charAt(0)}</AvatarFallback>\n </Avatar>\n </ItemMedia>\n <ItemContent className=\"gap-0.5\">\n <ItemTitle>{person.username}</ItemTitle>\n <ItemDescription>{person.email}</ItemDescription>\n </ItemContent>\n </Item>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n );\n};\n"
702
+ },
703
+ {
704
+ "name": "group",
705
+ "code": "import * as React from \"react\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"@rlx-widgets/avatar\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { PlusIcon } from \"lucide-react\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemGroup,\n ItemMedia,\n ItemSeparator,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nconst people = [\n {\n username: \"shadcn\",\n avatar: \"https://github.com/shadcn.png\",\n email: \"shadcn@vercel.com\",\n },\n {\n username: \"maxleiter\",\n avatar: \"https://github.com/maxleiter.png\",\n email: \"maxleiter@vercel.com\",\n },\n {\n username: \"evilrabbit\",\n avatar: \"https://github.com/evilrabbit.png\",\n email: \"evilrabbit@vercel.com\",\n },\n];\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-6\">\n <ItemGroup>\n {people.map((person, index) => (\n <React.Fragment key={person.username}>\n <Item>\n <ItemMedia>\n <Avatar>\n <AvatarImage src={person.avatar} className=\"grayscale\" />\n <AvatarFallback>{person.username.charAt(0)}</AvatarFallback>\n </Avatar>\n </ItemMedia>\n <ItemContent className=\"gap-1\">\n <ItemTitle>{person.username}</ItemTitle>\n <ItemDescription>{person.email}</ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"ghost\" size=\"icon\" className=\"rounded-full\">\n <PlusIcon />\n </Button>\n </ItemActions>\n </Item>\n {index !== people.length - 1 && <ItemSeparator />}\n </React.Fragment>\n ))}\n </ItemGroup>\n </div>\n );\n};\n"
706
+ },
707
+ {
708
+ "name": "header",
709
+ "code": "import Image from \"next/image\";\nimport {\n Item,\n ItemContent,\n ItemDescription,\n ItemGroup,\n ItemHeader,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nconst models = [\n {\n name: \"v0-1.5-sm\",\n description: \"Everyday tasks and UI generation.\",\n image:\n \"https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop\",\n credit: \"Valeria Reverdo on Unsplash\",\n },\n {\n name: \"v0-1.5-lg\",\n description: \"Advanced thinking or reasoning.\",\n image:\n \"https://images.unsplash.com/photo-1610280777472-54133d004c8c?q=80&w=640&auto=format&fit=crop\",\n credit: \"Michael Oeser on Unsplash\",\n },\n {\n name: \"v0-2.0-mini\",\n description: \"Open Source model for everyone.\",\n image:\n \"https://images.unsplash.com/photo-1602146057681-08560aee8cde?q=80&w=640&auto=format&fit=crop\",\n credit: \"Cherry Laithang on Unsplash\",\n },\n];\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-xl flex-col gap-6\">\n <ItemGroup className=\"grid grid-cols-3 gap-4\">\n {models.map((model) => (\n <Item key={model.name} variant=\"outline\">\n <ItemHeader>\n <Image\n src={model.image}\n alt={model.name}\n width={128}\n height={128}\n className=\"aspect-square w-full rounded-sm object-cover\"\n />\n </ItemHeader>\n <ItemContent>\n <ItemTitle>{model.name}</ItemTitle>\n <ItemDescription>{model.description}</ItemDescription>\n </ItemContent>\n </Item>\n ))}\n </ItemGroup>\n </div>\n );\n};\n"
710
+ },
711
+ {
712
+ "name": "icon",
713
+ "code": "import { BadgeCheckIcon, ChevronRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-6\">\n <Item variant=\"outline\">\n <ItemContent>\n <ItemTitle>Basic Item</ItemTitle>\n <ItemDescription>\n A simple item with title and description.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"outline\" size=\"sm\">\n Action\n </Button>\n </ItemActions>\n </Item>\n <Item variant=\"outline\" size=\"sm\" asChild>\n <a href=\"#\">\n <ItemMedia>\n <BadgeCheckIcon className=\"size-5\" />\n </ItemMedia>\n <ItemContent>\n <ItemTitle>Your profile has been verified.</ItemTitle>\n </ItemContent>\n <ItemActions>\n <ChevronRightIcon className=\"size-4\" />\n </ItemActions>\n </a>\n </Item>\n </div>\n );\n};\n"
714
+ },
715
+ {
716
+ "name": "image",
717
+ "code": "import Image from \"next/image\";\nimport {\n Item,\n ItemContent,\n ItemDescription,\n ItemGroup,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nconst music = [\n {\n title: \"Midnight City Lights\",\n artist: \"Neon Dreams\",\n album: \"Electric Nights\",\n duration: \"3:45\",\n },\n {\n title: \"Coffee Shop Conversations\",\n artist: \"The Morning Brew\",\n album: \"Urban Stories\",\n duration: \"4:05\",\n },\n {\n title: \"Digital Rain\",\n artist: \"Cyber Symphony\",\n album: \"Binary Beats\",\n duration: \"3:30\",\n },\n];\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-6\">\n <ItemGroup className=\"gap-4\">\n {music.map((song) => (\n <Item key={song.title} variant=\"outline\" asChild role=\"listitem\">\n <a href=\"#\">\n <ItemMedia variant=\"image\">\n <Image\n src={`https://avatar.vercel.sh/${song.title}`}\n alt={song.title}\n width={32}\n height={32}\n className=\"object-cover grayscale\"\n />\n </ItemMedia>\n <ItemContent>\n <ItemTitle className=\"line-clamp-1\">\n {song.title} -{\" \"}\n <span className=\"text-muted-foreground\">{song.album}</span>\n </ItemTitle>\n <ItemDescription>{song.artist}</ItemDescription>\n </ItemContent>\n <ItemContent className=\"flex-none text-center\">\n <ItemDescription>{song.duration}</ItemDescription>\n </ItemContent>\n </a>\n </Item>\n ))}\n </ItemGroup>\n </div>\n );\n};\n"
718
+ },
719
+ {
720
+ "name": "link",
721
+ "code": "import { ChevronRightIcon, ExternalLinkIcon } from \"lucide-react\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-4\">\n <Item asChild>\n <a href=\"#\">\n <ItemContent>\n <ItemTitle>Visit our documentation</ItemTitle>\n <ItemDescription>\n Learn how to get started with our components.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <ChevronRightIcon className=\"size-4\" />\n </ItemActions>\n </a>\n </Item>\n <Item variant=\"outline\" asChild>\n <a href=\"#\" target=\"_blank\" rel=\"noopener noreferrer\">\n <ItemContent>\n <ItemTitle>External resource</ItemTitle>\n <ItemDescription>\n Opens in a new tab with security attributes.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <ExternalLinkIcon className=\"size-4\" />\n </ItemActions>\n </a>\n </Item>\n </div>\n );\n};\n"
722
+ },
723
+ {
724
+ "name": "size",
725
+ "code": "import { BadgeCheckIcon, ChevronRightIcon } from \"lucide-react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-6\">\n <Item variant=\"outline\">\n <ItemContent>\n <ItemTitle>Basic Item</ItemTitle>\n <ItemDescription>\n A simple item with title and description.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"outline\" size=\"sm\">\n Action\n </Button>\n </ItemActions>\n </Item>\n <Item variant=\"outline\" size=\"sm\" asChild>\n <a href=\"#\">\n <ItemMedia>\n <BadgeCheckIcon className=\"size-5\" />\n </ItemMedia>\n <ItemContent>\n <ItemTitle>Your profile has been verified.</ItemTitle>\n </ItemContent>\n <ItemActions>\n <ChevronRightIcon className=\"size-4\" />\n </ItemActions>\n </a>\n </Item>\n </div>\n );\n};\n"
726
+ },
727
+ {
728
+ "name": "variants",
729
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-col gap-6\">\n <Item>\n <ItemContent>\n <ItemTitle>Default Variant</ItemTitle>\n <ItemDescription>\n Standard styling with subtle background and borders.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"outline\" size=\"sm\">\n Open\n </Button>\n </ItemActions>\n </Item>\n <Item variant=\"outline\">\n <ItemContent>\n <ItemTitle>Outline Variant</ItemTitle>\n <ItemDescription>\n Outlined style with clear borders and transparent background.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"outline\" size=\"sm\">\n Open\n </Button>\n </ItemActions>\n </Item>\n <Item variant=\"muted\">\n <ItemContent>\n <ItemTitle>Muted Variant</ItemTitle>\n <ItemDescription>\n Subdued appearance with muted colors for secondary content.\n </ItemDescription>\n </ItemContent>\n <ItemActions>\n <Button variant=\"outline\" size=\"sm\">\n Open\n </Button>\n </ItemActions>\n </Item>\n </div>\n );\n};\n"
730
+ }
731
+ ]
732
+ },
733
+ {
734
+ "name": "Kbd",
735
+ "slug": "kbd",
736
+ "category": "widget",
737
+ "sourceCode": "import { cn } from \"@rlx-widgets/base\";\n\nfunction Kbd({ className, ...props }: React.ComponentProps<\"kbd\">) {\n return (\n <kbd\n data-slot=\"kbd\"\n className={cn(\n \"bg-muted text-muted-foreground pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm px-1 font-sans text-xs font-medium select-none\",\n \"[&_svg:not([class*='size-'])]:size-3\",\n \"[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction KbdGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <kbd\n data-slot=\"kbd-group\"\n className={cn(\"inline-flex items-center gap-1\", className)}\n {...props}\n />\n );\n}\n\nexport { Kbd, KbdGroup };\n",
738
+ "demos": [
739
+ {
740
+ "name": "button",
741
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Kbd } from \"@rlx-widgets/kbd\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-wrap items-center gap-4\">\n <Button variant=\"outline\" size=\"sm\" className=\"pr-2\">\n Accept <Kbd>⏎</Kbd>\n </Button>\n <Button variant=\"outline\" size=\"sm\" className=\"pr-2\">\n Cancel <Kbd>Esc</Kbd>\n </Button>\n </div>\n );\n};\n"
742
+ },
743
+ {
744
+ "name": "default",
745
+ "code": "import { Kbd, KbdGroup } from \"@rlx-widgets/kbd\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <KbdGroup>\n <Kbd>⌘</Kbd>\n <Kbd>⇧</Kbd>\n <Kbd>⌥</Kbd>\n <Kbd>⌃</Kbd>\n </KbdGroup>\n <KbdGroup>\n <Kbd>Ctrl</Kbd>\n <span>+</span>\n <Kbd>B</Kbd>\n </KbdGroup>\n </div>\n );\n};\n"
746
+ },
747
+ {
748
+ "name": "group",
749
+ "code": "import { Kbd, KbdGroup } from \"@rlx-widgets/kbd\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <p className=\"text-muted-foreground text-sm\">\n Use{\" \"}\n <KbdGroup>\n <Kbd>Ctrl + B</Kbd>\n <Kbd>Ctrl + K</Kbd>\n </KbdGroup>{\" \"}\n to open the command palette\n </p>\n </div>\n );\n};\n"
750
+ },
751
+ {
752
+ "name": "input-group",
753
+ "code": "import {\n InputGroup,\n InputGroupAddon,\n InputGroupInput,\n} from \"@rlx-widgets/input-group\";\nimport { Kbd } from \"@rlx-widgets/kbd\";\nimport { SearchIcon } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-xs flex-col gap-6\">\n <InputGroup>\n <InputGroupInput placeholder=\"Search...\" />\n <InputGroupAddon>\n <SearchIcon />\n </InputGroupAddon>\n <InputGroupAddon align=\"inline-end\">\n <Kbd>⌘</Kbd>\n <Kbd>K</Kbd>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
754
+ },
755
+ {
756
+ "name": "tooltip",
757
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { ButtonGroup } from \"@rlx-widgets/button-group\";\nimport { Kbd, KbdGroup } from \"@rlx-widgets/kbd\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@rlx-widgets/tooltip\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-wrap gap-4\">\n <ButtonGroup>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button size=\"sm\" variant=\"outline\">\n Save\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <div className=\"flex items-center gap-2\">\n Save Changes <Kbd>S</Kbd>\n </div>\n </TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button size=\"sm\" variant=\"outline\">\n Print\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <div className=\"flex items-center gap-2\">\n Print Document{\" \"}\n <KbdGroup>\n <Kbd>Ctrl</Kbd>\n <Kbd>P</Kbd>\n </KbdGroup>\n </div>\n </TooltipContent>\n </Tooltip>\n </ButtonGroup>\n </div>\n );\n};\n"
758
+ }
759
+ ]
760
+ },
761
+ {
762
+ "name": "Label",
763
+ "slug": "label",
764
+ "category": "widget",
765
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Label({\n className,\n ...props\n}: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n",
766
+ "demos": [
767
+ {
768
+ "name": "default",
769
+ "code": "import { Checkbox } from \"@rlx-widgets/checkbox\";\nimport { Label } from \"@rlx-widgets/label\";\n\nexport const Preview = () => {\n return (\n <div>\n <div className=\"flex items-center space-x-2\">\n <Checkbox id=\"terms\" />\n <Label htmlFor=\"terms\">Accept terms and conditions</Label>\n </div>\n </div>\n );\n};\n"
770
+ }
771
+ ]
772
+ },
773
+ {
774
+ "name": "Menubar",
775
+ "slug": "menubar",
776
+ "category": "widget",
777
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as MenubarPrimitive from \"@radix-ui/react-menubar\";\nimport { CheckIcon, ChevronRightIcon, CircleIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Menubar({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Root>) {\n return (\n <MenubarPrimitive.Root\n data-slot=\"menubar\"\n className={cn(\n \"bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarMenu({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\n return <MenubarPrimitive.Menu data-slot=\"menubar-menu\" {...props} />;\n}\n\nfunction MenubarGroup({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Group>) {\n return <MenubarPrimitive.Group data-slot=\"menubar-group\" {...props} />;\n}\n\nfunction MenubarPortal({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {\n return <MenubarPrimitive.Portal data-slot=\"menubar-portal\" {...props} />;\n}\n\nfunction MenubarRadioGroup({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\n return (\n <MenubarPrimitive.RadioGroup data-slot=\"menubar-radio-group\" {...props} />\n );\n}\n\nfunction MenubarTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {\n return (\n <MenubarPrimitive.Trigger\n data-slot=\"menubar-trigger\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarContent({\n className,\n align = \"start\",\n alignOffset = -4,\n sideOffset = 8,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Content>) {\n return (\n <MenubarPortal>\n <MenubarPrimitive.Content\n data-slot=\"menubar-content\"\n align={align}\n alignOffset={alignOffset}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md\",\n className\n )}\n {...props}\n />\n </MenubarPortal>\n );\n}\n\nfunction MenubarItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}) {\n return (\n <MenubarPrimitive.Item\n data-slot=\"menubar-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {\n return (\n <MenubarPrimitive.CheckboxItem\n data-slot=\"menubar-checkbox-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.CheckboxItem>\n );\n}\n\nfunction MenubarRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {\n return (\n <MenubarPrimitive.RadioItem\n data-slot=\"menubar-radio-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-xs py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <CircleIcon className=\"size-2 fill-current\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.RadioItem>\n );\n}\n\nfunction MenubarLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Label> & {\n inset?: boolean;\n}) {\n return (\n <MenubarPrimitive.Label\n data-slot=\"menubar-label\"\n data-inset={inset}\n className={cn(\n \"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {\n return (\n <MenubarPrimitive.Separator\n data-slot=\"menubar-separator\"\n className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction MenubarShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"menubar-shortcut\"\n className={cn(\n \"text-muted-foreground ml-auto text-xs tracking-widest\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarSub({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\n}\n\nfunction MenubarSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & {\n inset?: boolean;\n}) {\n return (\n <MenubarPrimitive.SubTrigger\n data-slot=\"menubar-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto h-4 w-4\" />\n </MenubarPrimitive.SubTrigger>\n );\n}\n\nfunction MenubarSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {\n return (\n <MenubarPrimitive.SubContent\n data-slot=\"menubar-sub-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Menubar,\n MenubarPortal,\n MenubarMenu,\n MenubarTrigger,\n MenubarContent,\n MenubarGroup,\n MenubarSeparator,\n MenubarLabel,\n MenubarItem,\n MenubarShortcut,\n MenubarCheckboxItem,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSub,\n MenubarSubTrigger,\n MenubarSubContent,\n};\n",
778
+ "demos": [
779
+ {
780
+ "name": "default",
781
+ "code": "import {\n Menubar,\n MenubarCheckboxItem,\n MenubarContent,\n MenubarItem,\n MenubarMenu,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n} from \"@rlx-widgets/menubar\";\n\nexport const Preview = () => {\n return (\n <Menubar>\n <MenubarMenu>\n <MenubarTrigger>File</MenubarTrigger>\n <MenubarContent>\n <MenubarItem>\n New Tab <MenubarShortcut>⌘T</MenubarShortcut>\n </MenubarItem>\n <MenubarItem>\n New Window <MenubarShortcut>⌘N</MenubarShortcut>\n </MenubarItem>\n <MenubarItem disabled>New Incognito Window</MenubarItem>\n <MenubarSeparator />\n <MenubarSub>\n <MenubarSubTrigger>Share</MenubarSubTrigger>\n <MenubarSubContent>\n <MenubarItem>Email link</MenubarItem>\n <MenubarItem>Messages</MenubarItem>\n <MenubarItem>Notes</MenubarItem>\n </MenubarSubContent>\n </MenubarSub>\n <MenubarSeparator />\n <MenubarItem>\n Print... <MenubarShortcut>⌘P</MenubarShortcut>\n </MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n <MenubarMenu>\n <MenubarTrigger>Edit</MenubarTrigger>\n <MenubarContent>\n <MenubarItem>\n Undo <MenubarShortcut>⌘Z</MenubarShortcut>\n </MenubarItem>\n <MenubarItem>\n Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut>\n </MenubarItem>\n <MenubarSeparator />\n <MenubarSub>\n <MenubarSubTrigger>Find</MenubarSubTrigger>\n <MenubarSubContent>\n <MenubarItem>Search the web</MenubarItem>\n <MenubarSeparator />\n <MenubarItem>Find...</MenubarItem>\n <MenubarItem>Find Next</MenubarItem>\n <MenubarItem>Find Previous</MenubarItem>\n </MenubarSubContent>\n </MenubarSub>\n <MenubarSeparator />\n <MenubarItem>Cut</MenubarItem>\n <MenubarItem>Copy</MenubarItem>\n <MenubarItem>Paste</MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n <MenubarMenu>\n <MenubarTrigger>View</MenubarTrigger>\n <MenubarContent>\n <MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem>\n <MenubarCheckboxItem checked>\n Always Show Full URLs\n </MenubarCheckboxItem>\n <MenubarSeparator />\n <MenubarItem inset>\n Reload <MenubarShortcut>⌘R</MenubarShortcut>\n </MenubarItem>\n <MenubarItem disabled inset>\n Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut>\n </MenubarItem>\n <MenubarSeparator />\n <MenubarItem inset>Toggle Fullscreen</MenubarItem>\n <MenubarSeparator />\n <MenubarItem inset>Hide Sidebar</MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n <MenubarMenu>\n <MenubarTrigger>Profiles</MenubarTrigger>\n <MenubarContent>\n <MenubarRadioGroup value=\"benoit\">\n <MenubarRadioItem value=\"andy\">Andy</MenubarRadioItem>\n <MenubarRadioItem value=\"benoit\">Benoit</MenubarRadioItem>\n <MenubarRadioItem value=\"Luis\">Luis</MenubarRadioItem>\n </MenubarRadioGroup>\n <MenubarSeparator />\n <MenubarItem inset>Edit...</MenubarItem>\n <MenubarSeparator />\n <MenubarItem inset>Add Profile...</MenubarItem>\n </MenubarContent>\n </MenubarMenu>\n </Menubar>\n );\n};\n"
782
+ }
783
+ ]
784
+ },
785
+ {
786
+ "name": "Navigation Menu",
787
+ "slug": "navigation-menu",
788
+ "category": "widget",
789
+ "sourceCode": "import * as NavigationMenuPrimitive from \"@radix-ui/react-navigation-menu\";\nimport * as React from \"react\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { cva } from \"class-variance-authority\";\n\nfunction NavigationMenu({\n className,\n children,\n viewport = true,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {\n viewport?: boolean;\n}) {\n return (\n <NavigationMenuPrimitive.Root\n data-slot=\"navigation-menu\"\n data-viewport={viewport}\n className={cn(\n \"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center\",\n className\n )}\n {...props}\n >\n {children}\n {viewport && <NavigationMenuViewport />}\n </NavigationMenuPrimitive.Root>\n );\n}\n\nfunction NavigationMenuList({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {\n return (\n <NavigationMenuPrimitive.List\n data-slot=\"navigation-menu-list\"\n className={cn(\n \"group flex flex-1 list-none items-center justify-center gap-1\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuItem({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {\n return (\n <NavigationMenuPrimitive.Item\n data-slot=\"navigation-menu-item\"\n className={cn(\"relative\", className)}\n {...props}\n />\n );\n}\n\nconst navigationMenuTriggerStyle = cva(\n \"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1\"\n);\n\nfunction NavigationMenuTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {\n return (\n <NavigationMenuPrimitive.Trigger\n data-slot=\"navigation-menu-trigger\"\n className={cn(navigationMenuTriggerStyle(), \"group\", className)}\n {...props}\n >\n {children}{\" \"}\n <ChevronDownIcon\n className=\"relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180\"\n aria-hidden=\"true\"\n />\n </NavigationMenuPrimitive.Trigger>\n );\n}\n\nfunction NavigationMenuContent({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {\n return (\n <NavigationMenuPrimitive.Content\n data-slot=\"navigation-menu-content\"\n className={cn(\n \"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto\",\n \"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuViewport({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {\n return (\n <div\n className={cn(\n \"absolute top-full left-0 isolate z-50 flex justify-center\"\n )}\n >\n <NavigationMenuPrimitive.Viewport\n data-slot=\"navigation-menu-viewport\"\n className={cn(\n \"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]\",\n className\n )}\n {...props}\n />\n </div>\n );\n}\n\nfunction NavigationMenuLink({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {\n return (\n <NavigationMenuPrimitive.Link\n data-slot=\"navigation-menu-link\"\n className={cn(\n \"data-[active=true]:focus:bg-accent data-[active=true]:hover:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus-visible:ring-ring/50 [&_svg:not([class*='text-'])]:text-muted-foreground flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none focus-visible:ring-[3px] focus-visible:outline-1 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction NavigationMenuIndicator({\n className,\n ...props\n}: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {\n return (\n <NavigationMenuPrimitive.Indicator\n data-slot=\"navigation-menu-indicator\"\n className={cn(\n \"data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden\",\n className\n )}\n {...props}\n >\n <div className=\"bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md\" />\n </NavigationMenuPrimitive.Indicator>\n );\n}\n\nexport {\n NavigationMenu,\n NavigationMenuList,\n NavigationMenuItem,\n NavigationMenuContent,\n NavigationMenuTrigger,\n NavigationMenuLink,\n NavigationMenuIndicator,\n NavigationMenuViewport,\n navigationMenuTriggerStyle,\n};\n",
790
+ "demos": [
791
+ {
792
+ "name": "default",
793
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport Link from \"next/link\";\nimport { CircleCheckIcon, CircleHelpIcon, CircleIcon } from \"lucide-react\";\nimport {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n navigationMenuTriggerStyle,\n} from \"@rlx-widgets/navigation-menu\";\n\nconst components: { title: string; href: string; description: string }[] = [\n {\n title: \"Alert Dialog\",\n href: \"/docs/primitives/alert-dialog\",\n description:\n \"A modal dialog that interrupts the user with important content and expects a response.\",\n },\n {\n title: \"Hover Card\",\n href: \"/docs/primitives/hover-card\",\n description:\n \"For sighted users to preview content available behind a link.\",\n },\n {\n title: \"Progress\",\n href: \"/docs/primitives/progress\",\n description:\n \"Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.\",\n },\n {\n title: \"Scroll-area\",\n href: \"/docs/primitives/scroll-area\",\n description: \"Visually or semantically separates content.\",\n },\n {\n title: \"Tabs\",\n href: \"/docs/primitives/tabs\",\n description:\n \"A set of layered sections of content—known as tab panels—that are displayed one at a time.\",\n },\n {\n title: \"Tooltip\",\n href: \"/docs/primitives/tooltip\",\n description:\n \"A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.\",\n },\n];\n\nexport const Preview = () => {\n return (\n <NavigationMenu viewport={false}>\n <NavigationMenuList>\n <NavigationMenuItem>\n <NavigationMenuTrigger>Home</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul className=\"grid gap-2 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]\">\n <li className=\"row-span-3\">\n <NavigationMenuLink asChild>\n <Link\n className=\"from-muted/50 to-muted flex h-full w-full flex-col justify-end rounded-md bg-linear-to-b p-6 no-underline outline-hidden select-none focus:shadow-md\"\n href=\"/\"\n >\n <div className=\"mt-4 mb-2 text-lg font-medium\">\n shadcn/ui\n </div>\n <p className=\"text-muted-foreground text-sm leading-tight\">\n Beautifully designed components built with Tailwind CSS.\n </p>\n </Link>\n </NavigationMenuLink>\n </li>\n <ListItem href=\"/docs\" title=\"Introduction\">\n Re-usable components built using Radix UI and Tailwind CSS.\n </ListItem>\n <ListItem href=\"/docs/installation\" title=\"Installation\">\n How to install dependencies and structure your app.\n </ListItem>\n <ListItem href=\"/docs/primitives/typography\" title=\"Typography\">\n Styles for headings, paragraphs, lists...etc\n </ListItem>\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuTrigger>Components</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul className=\"grid w-[400px] gap-2 md:w-[500px] md:grid-cols-2 lg:w-[600px]\">\n {components.map((component) => (\n <ListItem\n key={component.title}\n title={component.title}\n href={component.href}\n >\n {component.description}\n </ListItem>\n ))}\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuLink asChild className={navigationMenuTriggerStyle()}>\n <Link href=\"/docs\">Docs</Link>\n </NavigationMenuLink>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuTrigger>List</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul className=\"grid w-[300px] gap-4\">\n <li>\n <NavigationMenuLink asChild>\n <Link href=\"#\">\n <div className=\"font-medium\">Components</div>\n <div className=\"text-muted-foreground\">\n Browse all components in the library.\n </div>\n </Link>\n </NavigationMenuLink>\n <NavigationMenuLink asChild>\n <Link href=\"#\">\n <div className=\"font-medium\">Documentation</div>\n <div className=\"text-muted-foreground\">\n Learn how to use the library.\n </div>\n </Link>\n </NavigationMenuLink>\n <NavigationMenuLink asChild>\n <Link href=\"#\">\n <div className=\"font-medium\">Blog</div>\n <div className=\"text-muted-foreground\">\n Read our latest blog posts.\n </div>\n </Link>\n </NavigationMenuLink>\n </li>\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuTrigger>Simple</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul className=\"grid w-[200px] gap-4\">\n <li>\n <NavigationMenuLink asChild>\n <Link href=\"#\">Components</Link>\n </NavigationMenuLink>\n <NavigationMenuLink asChild>\n <Link href=\"#\">Documentation</Link>\n </NavigationMenuLink>\n <NavigationMenuLink asChild>\n <Link href=\"#\">Blocks</Link>\n </NavigationMenuLink>\n </li>\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n <NavigationMenuItem>\n <NavigationMenuTrigger>With Icon</NavigationMenuTrigger>\n <NavigationMenuContent>\n <ul className=\"grid w-[200px] gap-4\">\n <li>\n <NavigationMenuLink asChild>\n <Link href=\"#\" className=\"flex-row items-center gap-2\">\n <CircleHelpIcon />\n Backlog\n </Link>\n </NavigationMenuLink>\n <NavigationMenuLink asChild>\n <Link href=\"#\" className=\"flex-row items-center gap-2\">\n <CircleIcon />\n To Do\n </Link>\n </NavigationMenuLink>\n <NavigationMenuLink asChild>\n <Link href=\"#\" className=\"flex-row items-center gap-2\">\n <CircleCheckIcon />\n Done\n </Link>\n </NavigationMenuLink>\n </li>\n </ul>\n </NavigationMenuContent>\n </NavigationMenuItem>\n </NavigationMenuList>\n </NavigationMenu>\n );\n};\n\nfunction ListItem({\n title,\n children,\n href,\n ...props\n}: React.ComponentPropsWithoutRef<\"li\"> & { href: string }) {\n return (\n <li {...props}>\n <NavigationMenuLink asChild>\n <Link href={href}>\n <div className=\"text-sm leading-none font-medium\">{title}</div>\n <p className=\"text-muted-foreground line-clamp-2 text-sm leading-snug\">\n {children}\n </p>\n </Link>\n </NavigationMenuLink>\n </li>\n );\n}\n"
794
+ }
795
+ ]
796
+ },
797
+ {
798
+ "name": "Pagination",
799
+ "slug": "pagination",
800
+ "category": "widget",
801
+ "sourceCode": "import * as React from \"react\";\nimport { Button, buttonVariants } from \"@rlx-widgets/button\";\nimport { cn } from \"@rlx-widgets/base\";\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n MoreHorizontalIcon,\n} from \"lucide-react\";\n\nfunction Pagination({ className, ...props }: React.ComponentProps<\"nav\">) {\n return (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n data-slot=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n );\n}\n\nfunction PaginationContent({\n className,\n ...props\n}: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"pagination-content\"\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n );\n}\n\nfunction PaginationItem({ ...props }: React.ComponentProps<\"li\">) {\n return <li data-slot=\"pagination-item\" {...props} />;\n}\n\ntype PaginationLinkProps = {\n isActive?: boolean;\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\n React.ComponentProps<\"a\">;\n\nfunction PaginationLink({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) {\n return (\n <a\n aria-current={isActive ? \"page\" : undefined}\n data-slot=\"pagination-link\"\n data-active={isActive}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n );\n}\n\nfunction PaginationPrevious({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) {\n return (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 px-2.5 sm:pl-2.5\", className)}\n {...props}\n >\n <ChevronLeftIcon />\n <span className=\"hidden sm:block\">Previous</span>\n </PaginationLink>\n );\n}\n\nfunction PaginationNext({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) {\n return (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 px-2.5 sm:pr-2.5\", className)}\n {...props}\n >\n <span className=\"hidden sm:block\">Next</span>\n <ChevronRightIcon />\n </PaginationLink>\n );\n}\n\nfunction PaginationEllipsis({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n aria-hidden\n data-slot=\"pagination-ellipsis\"\n className={cn(\"flex size-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontalIcon className=\"size-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n );\n}\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n};\n",
802
+ "demos": [
803
+ {
804
+ "name": "default",
805
+ "code": "import {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n} from \"@rlx-widgets/pagination\";\n\nexport const Preview = () => {\n return (\n <Pagination>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious href=\"#\" />\n </PaginationItem>\n <PaginationItem>\n <PaginationLink href=\"#\">1</PaginationLink>\n </PaginationItem>\n <PaginationItem>\n <PaginationLink href=\"#\" isActive>\n 2\n </PaginationLink>\n </PaginationItem>\n <PaginationItem>\n <PaginationLink href=\"#\">3</PaginationLink>\n </PaginationItem>\n <PaginationItem>\n <PaginationEllipsis />\n </PaginationItem>\n <PaginationItem>\n <PaginationNext href=\"#\" />\n </PaginationItem>\n </PaginationContent>\n </Pagination>\n );\n};\n"
806
+ }
807
+ ]
808
+ },
809
+ {
810
+ "name": "Popover",
811
+ "slug": "popover",
812
+ "category": "widget",
813
+ "sourceCode": "\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { cn } from \"@rlx-widgets/base\"\n\nfunction Popover({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n )\n}\n\nfunction PopoverAnchor({\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }\n",
814
+ "demos": [
815
+ {
816
+ "name": "default",
817
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@rlx-widgets/popover\";\n\nexport const Preview = () => {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\">Open popover</Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-80\">\n <div className=\"grid gap-4\">\n <div className=\"space-y-2\">\n <h4 className=\"leading-none font-medium\">Dimensions</h4>\n <p className=\"text-muted-foreground text-sm\">\n Set the dimensions for the layer.\n </p>\n </div>\n <div className=\"grid gap-2\">\n <div className=\"grid grid-cols-3 items-center gap-4\">\n <Label htmlFor=\"width\">Width</Label>\n <Input\n id=\"width\"\n defaultValue=\"100%\"\n className=\"col-span-2 h-8\"\n />\n </div>\n <div className=\"grid grid-cols-3 items-center gap-4\">\n <Label htmlFor=\"maxWidth\">Max. width</Label>\n <Input\n id=\"maxWidth\"\n defaultValue=\"300px\"\n className=\"col-span-2 h-8\"\n />\n </div>\n <div className=\"grid grid-cols-3 items-center gap-4\">\n <Label htmlFor=\"height\">Height</Label>\n <Input\n id=\"height\"\n defaultValue=\"25px\"\n className=\"col-span-2 h-8\"\n />\n </div>\n <div className=\"grid grid-cols-3 items-center gap-4\">\n <Label htmlFor=\"maxHeight\">Max. height</Label>\n <Input\n id=\"maxHeight\"\n defaultValue=\"none\"\n className=\"col-span-2 h-8\"\n />\n </div>\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n"
818
+ }
819
+ ]
820
+ },
821
+ {
822
+ "name": "Progress",
823
+ "slug": "progress",
824
+ "category": "widget",
825
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as ProgressPrimitive from \"@radix-ui/react-progress\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Progress({\n className,\n value,\n ...props\n}: React.ComponentProps<typeof ProgressPrimitive.Root>) {\n return (\n <ProgressPrimitive.Root\n data-slot=\"progress\"\n className={cn(\n \"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full\",\n className\n )}\n {...props}\n >\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className=\"bg-primary h-full w-full flex-1 transition-all\"\n style={{ transform: `translateX(-${100 - (value || 0)}%)` }}\n />\n </ProgressPrimitive.Root>\n );\n}\n\nexport { Progress };\n",
826
+ "demos": [
827
+ {
828
+ "name": "default",
829
+ "code": "\"use client\";\n\nimport * as React from \"react\";\nimport { Progress } from \"@rlx-widgets/progress\";\n\nexport const Preview = () => {\n const [progress, setProgress] = React.useState(13);\n\n React.useEffect(() => {\n const timer = setTimeout(() => setProgress(66), 500);\n return () => clearTimeout(timer);\n }, []);\n\n return <Progress value={progress} className=\"w-[60%]\" />;\n};\n"
830
+ }
831
+ ]
832
+ },
833
+ {
834
+ "name": "Radio Group",
835
+ "slug": "radio-group",
836
+ "category": "widget",
837
+ "sourceCode": "\"use client\";\n\nimport * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\nimport * as React from \"react\";\nimport { CircleIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction RadioGroup({\n className,\n ...props\n}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {\n return (\n <RadioGroupPrimitive.Root\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n );\n}\n\nfunction RadioGroupItem({\n className,\n ...props\n}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item\n data-slot=\"radio-group-item\"\n className={cn(\n \"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"relative flex items-center justify-center\"\n >\n <CircleIcon className=\"fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport { RadioGroup, RadioGroupItem };\n",
838
+ "demos": [
839
+ {
840
+ "name": "default",
841
+ "code": "import { Label } from \"@rlx-widgets/label\";\nimport { RadioGroup, RadioGroupItem } from \"@rlx-widgets/radio-group\";\n\nexport const Preview = () => {\n return (\n <RadioGroup defaultValue=\"comfortable\">\n <div className=\"flex items-center gap-3\">\n <RadioGroupItem value=\"default\" id=\"r1\" />\n <Label htmlFor=\"r1\">Default</Label>\n </div>\n <div className=\"flex items-center gap-3\">\n <RadioGroupItem value=\"comfortable\" id=\"r2\" />\n <Label htmlFor=\"r2\">Comfortable</Label>\n </div>\n <div className=\"flex items-center gap-3\">\n <RadioGroupItem value=\"compact\" id=\"r3\" />\n <Label htmlFor=\"r3\">Compact</Label>\n </div>\n </RadioGroup>\n );\n};\n"
842
+ },
843
+ {
844
+ "name": "form",
845
+ "code": "\"use client\";\n\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { z } from \"zod\";\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Form,\n FormControl,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@rlx-widgets/form\";\nimport { RadioGroup, RadioGroupItem } from \"@rlx-widgets/radio-group\";\n\nconst FormSchema = z.object({\n type: z.enum([\"all\", \"mentions\", \"none\"]).refine((val) => !!val, {\n message: \"You need to select a notification type.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"w-2/3 space-y-6\">\n <FormField\n control={form.control}\n name=\"type\"\n render={({ field }) => (\n <FormItem className=\"space-y-3\">\n <FormLabel>Notify me about...</FormLabel>\n <FormControl>\n <RadioGroup\n onValueChange={field.onChange}\n defaultValue={field.value}\n className=\"flex flex-col\"\n >\n <FormItem className=\"flex items-center gap-3\">\n <FormControl>\n <RadioGroupItem value=\"all\" />\n </FormControl>\n <FormLabel className=\"font-normal\">\n All new messages\n </FormLabel>\n </FormItem>\n <FormItem className=\"flex items-center gap-3\">\n <FormControl>\n <RadioGroupItem value=\"mentions\" />\n </FormControl>\n <FormLabel className=\"font-normal\">\n Direct messages and mentions\n </FormLabel>\n </FormItem>\n <FormItem className=\"flex items-center gap-3\">\n <FormControl>\n <RadioGroupItem value=\"none\" />\n </FormControl>\n <FormLabel className=\"font-normal\">Nothing</FormLabel>\n </FormItem>\n </RadioGroup>\n </FormControl>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
846
+ }
847
+ ]
848
+ },
849
+ {
850
+ "name": "Resizable",
851
+ "slug": "resizable",
852
+ "category": "widget",
853
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport { GripVerticalIcon } from \"lucide-react\";\nimport * as ResizablePrimitive from \"react-resizable-panels\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction ResizablePanelGroup({\n className,\n ...props\n}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) {\n return (\n <ResizablePrimitive.PanelGroup\n data-slot=\"resizable-panel-group\"\n className={cn(\n \"flex h-full w-full data-[panel-group-direction=vertical]:flex-col\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction ResizablePanel({\n ...props\n}: React.ComponentProps<typeof ResizablePrimitive.Panel>) {\n return <ResizablePrimitive.Panel data-slot=\"resizable-panel\" {...props} />;\n}\n\nfunction ResizableHandle({\n withHandle,\n className,\n ...props\n}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {\n withHandle?: boolean;\n}) {\n return (\n <ResizablePrimitive.PanelResizeHandle\n data-slot=\"resizable-handle\"\n className={cn(\n \"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90\",\n className\n )}\n {...props}\n >\n {withHandle && (\n <div className=\"bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border\">\n <GripVerticalIcon className=\"size-2.5\" />\n </div>\n )}\n </ResizablePrimitive.PanelResizeHandle>\n );\n}\n\nexport { ResizablePanelGroup, ResizablePanel, ResizableHandle };\n",
854
+ "demos": [
855
+ {
856
+ "name": "default",
857
+ "code": "import {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from \"@rlx-widgets/resizable\";\n\nexport const Preview = () => {\n return (\n <ResizablePanelGroup\n direction=\"horizontal\"\n className=\"max-w-md rounded-lg border md:min-w-[450px]\"\n >\n <ResizablePanel defaultSize={50}>\n <div className=\"flex h-[200px] items-center justify-center p-6\">\n <span className=\"font-semibold\">One</span>\n </div>\n </ResizablePanel>\n <ResizableHandle />\n <ResizablePanel defaultSize={50}>\n <ResizablePanelGroup direction=\"vertical\">\n <ResizablePanel defaultSize={25}>\n <div className=\"flex h-full items-center justify-center p-6\">\n <span className=\"font-semibold\">Two</span>\n </div>\n </ResizablePanel>\n <ResizableHandle />\n <ResizablePanel defaultSize={75}>\n <div className=\"flex h-full items-center justify-center p-6\">\n <span className=\"font-semibold\">Three</span>\n </div>\n </ResizablePanel>\n </ResizablePanelGroup>\n </ResizablePanel>\n </ResizablePanelGroup>\n );\n};\n"
858
+ },
859
+ {
860
+ "name": "handle",
861
+ "code": "import {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from \"@rlx-widgets/resizable\";\n\nexport const Preview = () => {\n return (\n <ResizablePanelGroup\n direction=\"horizontal\"\n className=\"min-h-[200px] max-w-md rounded-lg border md:min-w-[450px]\"\n >\n <ResizablePanel defaultSize={25}>\n <div className=\"flex h-full items-center justify-center p-6\">\n <span className=\"font-semibold\">Sidebar</span>\n </div>\n </ResizablePanel>\n <ResizableHandle withHandle />\n <ResizablePanel defaultSize={75}>\n <div className=\"flex h-full items-center justify-center p-6\">\n <span className=\"font-semibold\">Content</span>\n </div>\n </ResizablePanel>\n </ResizablePanelGroup>\n );\n};\n"
862
+ },
863
+ {
864
+ "name": "vertical",
865
+ "code": "import {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from \"@rlx-widgets/resizable\";\n\nexport const Preview = () => {\n return (\n <ResizablePanelGroup\n direction=\"vertical\"\n className=\"min-h-[200px] max-w-md rounded-lg border md:min-w-[450px]\"\n >\n <ResizablePanel defaultSize={25}>\n <div className=\"flex h-full items-center justify-center p-6\">\n <span className=\"font-semibold\">Header</span>\n </div>\n </ResizablePanel>\n <ResizableHandle />\n <ResizablePanel defaultSize={75}>\n <div className=\"flex h-full items-center justify-center p-6\">\n <span className=\"font-semibold\">Content</span>\n </div>\n </ResizablePanel>\n </ResizablePanelGroup>\n );\n};\n"
866
+ }
867
+ ]
868
+ },
869
+ {
870
+ "name": "Scroll Area",
871
+ "slug": "scroll-area",
872
+ "category": "widget",
873
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as ScrollAreaPrimitive from \"@radix-ui/react-scroll-area\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction ScrollArea({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {\n return (\n <ScrollAreaPrimitive.Root\n data-slot=\"scroll-area\"\n className={cn(\"relative\", className)}\n {...props}\n >\n <ScrollAreaPrimitive.Viewport\n data-slot=\"scroll-area-viewport\"\n className=\"focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1\"\n >\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n );\n}\n\nfunction ScrollBar({\n className,\n orientation = \"vertical\",\n ...props\n}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {\n return (\n <ScrollAreaPrimitive.ScrollAreaScrollbar\n data-slot=\"scroll-area-scrollbar\"\n orientation={orientation}\n className={cn(\n \"flex touch-none p-px transition-colors select-none\",\n orientation === \"vertical\" &&\n \"h-full w-2.5 border-l border-l-transparent\",\n orientation === \"horizontal\" &&\n \"h-2.5 flex-col border-t border-t-transparent\",\n className\n )}\n {...props}\n >\n <ScrollAreaPrimitive.ScrollAreaThumb\n data-slot=\"scroll-area-thumb\"\n className=\"bg-border relative flex-1 rounded-full\"\n />\n </ScrollAreaPrimitive.ScrollAreaScrollbar>\n );\n}\n\nexport { ScrollArea, ScrollBar };\n",
874
+ "demos": [
875
+ {
876
+ "name": "default",
877
+ "code": "import * as React from \"react\";\nimport { ScrollArea } from \"@rlx-widgets/scroll-area\";\nimport { Separator } from \"@rlx-widgets/separator\";\n\nconst tags = Array.from({ length: 50 }).map(\n (_, i, a) => `v1.2.0-beta.${a.length - i}`\n);\n\nexport const Preview = () => {\n return (\n <ScrollArea className=\"h-72 w-48 rounded-md border\">\n <div className=\"p-4\">\n <h4 className=\"mb-4 text-sm leading-none font-medium\">Tags</h4>\n {tags.map((tag) => (\n <React.Fragment key={tag}>\n <div className=\"text-sm\">{tag}</div>\n <Separator className=\"my-2\" />\n </React.Fragment>\n ))}\n </div>\n </ScrollArea>\n );\n};\n"
878
+ },
879
+ {
880
+ "name": "horizontal-scrolling",
881
+ "code": "import * as React from \"react\";\nimport Image from \"next/image\";\nimport { ScrollArea, ScrollBar } from \"@rlx-widgets/scroll-area\";\n\nexport interface Artwork {\n artist: string;\n art: string;\n}\n\nexport const works: Artwork[] = [\n {\n artist: \"Ornella Binni\",\n art: \"https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80\",\n },\n {\n artist: \"Tom Byrom\",\n art: \"https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80\",\n },\n {\n artist: \"Vladimir Malyavko\",\n art: \"https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80\",\n },\n];\n\nexport const Preview = () => {\n return (\n <ScrollArea className=\"w-96 rounded-md border whitespace-nowrap\">\n <div className=\"flex w-max space-x-4 p-4\">\n {works.map((artwork) => (\n <figure key={artwork.artist} className=\"shrink-0\">\n <div className=\"overflow-hidden rounded-md\">\n <Image\n src={artwork.art}\n alt={`Photo by ${artwork.artist}`}\n className=\"aspect-[3/4] h-fit w-fit object-cover\"\n width={300}\n height={400}\n />\n </div>\n <figcaption className=\"text-muted-foreground pt-2 text-xs\">\n Photo by{\" \"}\n <span className=\"text-foreground font-semibold\">\n {artwork.artist}\n </span>\n </figcaption>\n </figure>\n ))}\n </div>\n <ScrollBar orientation=\"horizontal\" />\n </ScrollArea>\n );\n};\n"
882
+ }
883
+ ]
884
+ },
885
+ {
886
+ "name": "Select",
887
+ "slug": "select",
888
+ "category": "widget",
889
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Select({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Root>) {\n return <SelectPrimitive.Root data-slot=\"select\" {...props} />;\n}\n\nfunction SelectGroup({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Group>) {\n return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />;\n}\n\nfunction SelectValue({\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Value>) {\n return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />;\n}\n\nfunction SelectTrigger({\n className,\n size = \"default\",\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n size?: \"sm\" | \"default\";\n}) {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n data-size={size}\n className={cn(\n \"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDownIcon className=\"size-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n}\n\nfunction SelectContent({\n className,\n children,\n position = \"popper\",\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n data-slot=\"select-content\"\n className={cn(\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md\",\n position === \"popper\" &&\n \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n className\n )}\n position={position}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n \"p-1\",\n position === \"popper\" &&\n \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1\"\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n );\n}\n\nfunction SelectLabel({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n data-slot=\"select-label\"\n className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n {...props}\n />\n );\n}\n\nfunction SelectItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2\",\n className\n )}\n {...props}\n >\n <span className=\"absolute right-2 flex size-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n );\n}\n\nfunction SelectSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n {...props}\n />\n );\n}\n\nfunction SelectScrollUpButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n return (\n <SelectPrimitive.ScrollUpButton\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronUpIcon className=\"size-4\" />\n </SelectPrimitive.ScrollUpButton>\n );\n}\n\nfunction SelectScrollDownButton({\n className,\n ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n return (\n <SelectPrimitive.ScrollDownButton\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1\",\n className\n )}\n {...props}\n >\n <ChevronDownIcon className=\"size-4\" />\n </SelectPrimitive.ScrollDownButton>\n );\n}\n\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n};\n",
890
+ "demos": [
891
+ {
892
+ "name": "default",
893
+ "code": "import * as React from \"react\";\n\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nexport const Preview = () => {\n return (\n <Select>\n <SelectTrigger className=\"w-[180px]\">\n <SelectValue placeholder=\"Select a fruit\" />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectLabel>Fruits</SelectLabel>\n <SelectItem value=\"apple\">Apple</SelectItem>\n <SelectItem value=\"banana\">Banana</SelectItem>\n <SelectItem value=\"blueberry\">Blueberry</SelectItem>\n <SelectItem value=\"grapes\">Grapes</SelectItem>\n <SelectItem value=\"pineapple\">Pineapple</SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n );\n};\n"
894
+ },
895
+ {
896
+ "name": "form",
897
+ "code": "\"use client\";\n\nimport Link from \"next/link\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { z } from \"zod\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n} from \"@rlx-widgets/form\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nconst FormSchema = z.object({\n email: z.email({\n error: \"Please select an email to display.\",\n }),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"w-2/3 space-y-6\">\n <FormField\n control={form.control}\n name=\"email\"\n render={({ field }) => (\n <FormItem>\n <FormLabel>Email</FormLabel>\n <Select onValueChange={field.onChange} defaultValue={field.value}>\n <FormControl>\n <SelectTrigger>\n <SelectValue placeholder=\"Select a verified email to display\" />\n </SelectTrigger>\n </FormControl>\n <SelectContent>\n <SelectItem value=\"m@example.com\">m@example.com</SelectItem>\n <SelectItem value=\"m@google.com\">m@google.com</SelectItem>\n <SelectItem value=\"m@support.com\">m@support.com</SelectItem>\n </SelectContent>\n </Select>\n <FormDescription>\n You can manage email addresses in your{\" \"}\n <Link href=\"/examples/forms\">email settings</Link>.\n </FormDescription>\n <FormMessage />\n </FormItem>\n )}\n />\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
898
+ },
899
+ {
900
+ "name": "scrollable",
901
+ "code": "import * as React from \"react\";\n\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nexport const Preview = () => {\n return (\n <Select>\n <SelectTrigger className=\"w-[280px]\">\n <SelectValue placeholder=\"Select a timezone\" />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectLabel>North America</SelectLabel>\n <SelectItem value=\"est\">Eastern Standard Time (EST)</SelectItem>\n <SelectItem value=\"cst\">Central Standard Time (CST)</SelectItem>\n <SelectItem value=\"mst\">Mountain Standard Time (MST)</SelectItem>\n <SelectItem value=\"pst\">Pacific Standard Time (PST)</SelectItem>\n <SelectItem value=\"akst\">Alaska Standard Time (AKST)</SelectItem>\n <SelectItem value=\"hst\">Hawaii Standard Time (HST)</SelectItem>\n </SelectGroup>\n <SelectGroup>\n <SelectLabel>Europe & Africa</SelectLabel>\n <SelectItem value=\"gmt\">Greenwich Mean Time (GMT)</SelectItem>\n <SelectItem value=\"cet\">Central European Time (CET)</SelectItem>\n <SelectItem value=\"eet\">Eastern European Time (EET)</SelectItem>\n <SelectItem value=\"west\">\n Western European Summer Time (WEST)\n </SelectItem>\n <SelectItem value=\"cat\">Central Africa Time (CAT)</SelectItem>\n <SelectItem value=\"eat\">East Africa Time (EAT)</SelectItem>\n </SelectGroup>\n <SelectGroup>\n <SelectLabel>Asia</SelectLabel>\n <SelectItem value=\"msk\">Moscow Time (MSK)</SelectItem>\n <SelectItem value=\"ist\">India Standard Time (IST)</SelectItem>\n <SelectItem value=\"cst_china\">China Standard Time (CST)</SelectItem>\n <SelectItem value=\"jst\">Japan Standard Time (JST)</SelectItem>\n <SelectItem value=\"kst\">Korea Standard Time (KST)</SelectItem>\n <SelectItem value=\"ist_indonesia\">\n Indonesia Central Standard Time (WITA)\n </SelectItem>\n </SelectGroup>\n <SelectGroup>\n <SelectLabel>Australia & Pacific</SelectLabel>\n <SelectItem value=\"awst\">\n Australian Western Standard Time (AWST)\n </SelectItem>\n <SelectItem value=\"acst\">\n Australian Central Standard Time (ACST)\n </SelectItem>\n <SelectItem value=\"aest\">\n Australian Eastern Standard Time (AEST)\n </SelectItem>\n <SelectItem value=\"nzst\">New Zealand Standard Time (NZST)</SelectItem>\n <SelectItem value=\"fjt\">Fiji Time (FJT)</SelectItem>\n </SelectGroup>\n <SelectGroup>\n <SelectLabel>South America</SelectLabel>\n <SelectItem value=\"art\">Argentina Time (ART)</SelectItem>\n <SelectItem value=\"bot\">Bolivia Time (BOT)</SelectItem>\n <SelectItem value=\"brt\">Brasilia Time (BRT)</SelectItem>\n <SelectItem value=\"clt\">Chile Standard Time (CLT)</SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n );\n};\n"
902
+ }
903
+ ]
904
+ },
905
+ {
906
+ "name": "Separator",
907
+ "slug": "separator",
908
+ "category": "widget",
909
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Separator({\n className,\n orientation = \"horizontal\",\n decorative = true,\n ...props\n}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {\n return (\n <SeparatorPrimitive.Root\n data-slot=\"separator\"\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Separator };\n",
910
+ "demos": [
911
+ {
912
+ "name": "default",
913
+ "code": "import { Separator } from \"@rlx-widgets/separator\";\n\nexport const Preview = () => {\n return (\n <div>\n <div className=\"space-y-1\">\n <h4 className=\"text-sm leading-none font-medium\">Radix Primitives</h4>\n <p className=\"text-muted-foreground text-sm\">\n An open-source UI component library.\n </p>\n </div>\n <Separator className=\"my-4\" />\n <div className=\"flex h-5 items-center space-x-4 text-sm\">\n <div>Blog</div>\n <Separator orientation=\"vertical\" />\n <div>Docs</div>\n <Separator orientation=\"vertical\" />\n <div>Source</div>\n </div>\n </div>\n );\n};\n"
914
+ }
915
+ ]
916
+ },
917
+ {
918
+ "name": "Sheet",
919
+ "slug": "sheet",
920
+ "category": "widget",
921
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SheetPrimitive from \"@radix-ui/react-dialog\";\nimport { XIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />;\n}\n\nfunction SheetTrigger({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />;\n}\n\nfunction SheetClose({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />;\n}\n\nfunction SheetPortal({\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />;\n}\n\nfunction SheetOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n return (\n <SheetPrimitive.Overlay\n data-slot=\"sheet-overlay\"\n className={cn(\n \"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SheetContent({\n className,\n children,\n side = \"right\",\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n}) {\n return (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Content\n data-slot=\"sheet-content\"\n className={cn(\n \"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500\",\n side === \"right\" &&\n \"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm\",\n side === \"left\" &&\n \"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm\",\n side === \"top\" &&\n \"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b\",\n side === \"bottom\" &&\n \"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t\",\n className\n )}\n {...props}\n >\n {children}\n <SheetPrimitive.Close className=\"ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none\">\n <XIcon className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n </SheetPrimitive.Content>\n </SheetPortal>\n );\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-header\"\n className={cn(\"flex flex-col gap-1.5 p-4\", className)}\n {...props}\n />\n );\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sheet-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n );\n}\n\nfunction SheetTitle({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn(\"text-foreground font-semibold\", className)}\n {...props}\n />\n );\n}\n\nfunction SheetDescription({\n className,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn(\"text-muted-foreground text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Sheet,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription,\n};\n",
922
+ "demos": [
923
+ {
924
+ "name": "default",
925
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\nimport {\n Sheet,\n SheetClose,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n SheetTrigger,\n} from \"@rlx-widgets/sheet\";\n\nexport const Preview = () => {\n return (\n <Sheet>\n <SheetTrigger asChild>\n <Button variant=\"outline\">Open</Button>\n </SheetTrigger>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>Edit profile</SheetTitle>\n <SheetDescription>\n Make changes to your profile here. Click save when you&apos;re done.\n </SheetDescription>\n </SheetHeader>\n <div className=\"grid flex-1 auto-rows-min gap-6 px-4\">\n <div className=\"grid gap-3\">\n <Label htmlFor=\"sheet-demo-name\">Name</Label>\n <Input id=\"sheet-demo-name\" defaultValue=\"Pedro Duarte\" />\n </div>\n <div className=\"grid gap-3\">\n <Label htmlFor=\"sheet-demo-username\">Username</Label>\n <Input id=\"sheet-demo-username\" defaultValue=\"@peduarte\" />\n </div>\n </div>\n <SheetFooter>\n <Button type=\"submit\">Save changes</Button>\n <SheetClose asChild>\n <Button variant=\"outline\">Close</Button>\n </SheetClose>\n </SheetFooter>\n </SheetContent>\n </Sheet>\n );\n};\n"
926
+ }
927
+ ]
928
+ },
929
+ {
930
+ "name": "Sidebar",
931
+ "slug": "sidebar",
932
+ "category": "widget",
933
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { cva, VariantProps } from \"class-variance-authority\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { PanelLeftIcon } from \"lucide-react\";\nimport { Separator } from \"@rlx-widgets/separator\";\nimport { Skeleton } from \"@rlx-widgets/skeleton\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { useIsMobile } from \"@rlx-hooks/use-is-mobile\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from \"@rlx-widgets/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@rlx-widgets/tooltip\";\n\nconst SIDEBAR_COOKIE_NAME = \"sidebar_state\";\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;\nconst SIDEBAR_WIDTH = \"16rem\";\nconst SIDEBAR_WIDTH_MOBILE = \"18rem\";\nconst SIDEBAR_WIDTH_ICON = \"3rem\";\nconst SIDEBAR_KEYBOARD_SHORTCUT = \"b\";\n\ntype SidebarContextProps = {\n state: \"expanded\" | \"collapsed\";\n open: boolean;\n setOpen: (open: boolean) => void;\n openMobile: boolean;\n setOpenMobile: (open: boolean) => void;\n isMobile: boolean;\n toggleSidebar: () => void;\n};\n\nconst SidebarContext = React.createContext<SidebarContextProps | null>(null);\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext);\n if (!context) {\n throw new Error(\"useSidebar must be used within a SidebarProvider.\");\n }\n\n return context;\n}\n\nfunction SidebarProvider({\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n defaultOpen?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}) {\n const isMobile = useIsMobile();\n const [openMobile, setOpenMobile] = React.useState(false);\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen);\n const open = openProp ?? _open;\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === \"function\" ? value(open) : value;\n if (setOpenProp) {\n setOpenProp(openState);\n } else {\n _setOpen(openState);\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;\n },\n [setOpenProp, open]\n );\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);\n }, [isMobile, setOpen, setOpenMobile]);\n\n // Adds a keyboard shortcut to toggle the sidebar.\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (\n event.key === SIDEBAR_KEYBOARD_SHORTCUT &&\n (event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault();\n toggleSidebar();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [toggleSidebar]);\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? \"expanded\" : \"collapsed\";\n\n const contextValue = React.useMemo<SidebarContextProps>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]\n );\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <TooltipProvider delayDuration={0}>\n <div\n data-slot=\"sidebar-wrapper\"\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH,\n \"--sidebar-width-icon\": SIDEBAR_WIDTH_ICON,\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n \"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n </TooltipProvider>\n </SidebarContext.Provider>\n );\n}\n\n/**\n * tw v4\n */\nfunction Sidebar({\n side = \"left\",\n variant = \"sidebar\",\n collapsible = \"offcanvas\",\n className,\n children,\n ...props\n}: React.ComponentProps<\"div\"> & {\n side?: \"left\" | \"right\";\n variant?: \"sidebar\" | \"floating\" | \"inset\";\n collapsible?: \"offcanvas\" | \"icon\" | \"none\";\n}) {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar();\n\n if (collapsible === \"none\") {\n return (\n <div\n data-slot=\"sidebar\"\n className={cn(\n \"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n );\n }\n\n if (isMobile) {\n return (\n <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar\"\n data-mobile=\"true\"\n className=\"bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden\"\n style={\n {\n \"--sidebar-width\": SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </Sheet>\n );\n }\n\n return (\n <div\n className=\"group peer text-sidebar-foreground hidden md:block\"\n data-state={state}\n data-collapsible={state === \"collapsed\" ? collapsible : \"\"}\n data-variant={variant}\n data-side={side}\n data-slot=\"sidebar\"\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n data-slot=\"sidebar-gap\"\n className={cn(\n \"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear\",\n \"group-data-[collapsible=offcanvas]:w-0\",\n \"group-data-[side=right]:rotate-180\",\n variant === \"floating\" || variant === \"inset\"\n ? \"group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon)\"\n )}\n />\n <div\n data-slot=\"sidebar-container\"\n className={cn(\n \"fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex\",\n side === \"left\"\n ? \"left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]\"\n : \"right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]\",\n // Adjust the padding for floating and inset variants.\n variant === \"floating\" || variant === \"inset\"\n ? \"p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]\"\n : \"group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l\",\n className\n )}\n {...props}\n >\n <div\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar-inner\"\n className=\"bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm\"\n >\n {children}\n </div>\n </div>\n </div>\n );\n}\n\nfunction SidebarTrigger({\n className,\n onClick,\n ...props\n}: React.ComponentProps<typeof Button>) {\n const { toggleSidebar } = useSidebar();\n\n return (\n <Button\n data-sidebar=\"trigger\"\n data-slot=\"sidebar-trigger\"\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\"size-7\", className)}\n onClick={(event) => {\n onClick?.(event);\n toggleSidebar();\n }}\n {...props}\n >\n <PanelLeftIcon />\n <span className=\"sr-only\">Toggle Sidebar</span>\n </Button>\n );\n}\n\nfunction SidebarRail({ className, ...props }: React.ComponentProps<\"button\">) {\n const { toggleSidebar } = useSidebar();\n\n return (\n <button\n data-sidebar=\"rail\"\n data-slot=\"sidebar-rail\"\n aria-label=\"Toggle Sidebar\"\n tabIndex={-1}\n onClick={toggleSidebar}\n title=\"Toggle Sidebar\"\n className={cn(\n \"hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] sm:flex\",\n \"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize\",\n \"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize\",\n \"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full\",\n \"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2\",\n \"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarInset({ className, ...props }: React.ComponentProps<\"main\">) {\n return (\n <main\n data-slot=\"sidebar-inset\"\n className={cn(\n \"bg-background relative flex w-full flex-1 flex-col\",\n \"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarInput({\n className,\n ...props\n}: React.ComponentProps<typeof Input>) {\n return (\n <Input\n data-slot=\"sidebar-input\"\n data-sidebar=\"input\"\n className={cn(\"bg-background h-8 w-full shadow-none\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-header\"\n data-sidebar=\"header\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-footer\"\n data-sidebar=\"footer\"\n className={cn(\"flex flex-col gap-2 p-2\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof Separator>) {\n return (\n <Separator\n data-slot=\"sidebar-separator\"\n data-sidebar=\"separator\"\n className={cn(\"bg-sidebar-border mx-2 w-auto\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-content\"\n data-sidebar=\"content\"\n className={cn(\n \"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-group\"\n data-sidebar=\"group\"\n className={cn(\"relative flex w-full min-w-0 flex-col p-2\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarGroupLabel({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"div\"> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"div\";\n\n return (\n <Comp\n data-slot=\"sidebar-group-label\"\n data-sidebar=\"group-label\"\n className={cn(\n \"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n \"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarGroupAction({\n className,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"sidebar-group-action\"\n data-sidebar=\"group-action\"\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 md:after:hidden\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarGroupContent({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-group-content\"\n data-sidebar=\"group-content\"\n className={cn(\"w-full text-sm\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarMenu({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"sidebar-menu\"\n data-sidebar=\"menu\"\n className={cn(\"flex w-full min-w-0 flex-col gap-1\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarMenuItem({ className, ...props }: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"sidebar-menu-item\"\n data-sidebar=\"menu-item\"\n className={cn(\"group/menu-item relative\", className)}\n {...props}\n />\n );\n}\n\nconst sidebarMenuButtonVariants = cva(\n \"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n outline:\n \"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]\",\n },\n size: {\n default: \"h-8 text-sm\",\n sm: \"h-7 text-xs\",\n lg: \"h-12 text-sm group-data-[collapsible=icon]:p-0!\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nfunction SidebarMenuButton({\n asChild = false,\n isActive = false,\n variant = \"default\",\n size = \"default\",\n tooltip,\n className,\n ...props\n}: React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n isActive?: boolean;\n tooltip?: string | React.ComponentProps<typeof TooltipContent>;\n} & VariantProps<typeof sidebarMenuButtonVariants>) {\n const Comp = asChild ? Slot : \"button\";\n const { isMobile, state } = useSidebar();\n\n const button = (\n <Comp\n data-slot=\"sidebar-menu-button\"\n data-sidebar=\"menu-button\"\n data-size={size}\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n {...props}\n />\n );\n\n if (!tooltip) {\n return button;\n }\n\n if (typeof tooltip === \"string\") {\n tooltip = {\n children: tooltip,\n };\n }\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent\n side=\"right\"\n align=\"center\"\n hidden={state !== \"collapsed\" || isMobile}\n {...tooltip}\n />\n </Tooltip>\n );\n}\n\nfunction SidebarMenuAction({\n className,\n asChild = false,\n showOnHover = false,\n ...props\n}: React.ComponentProps<\"button\"> & {\n asChild?: boolean;\n showOnHover?: boolean;\n}) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"sidebar-menu-action\"\n data-sidebar=\"menu-action\"\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0\",\n // Increases the hit area of the button on mobile.\n \"after:absolute after:-inset-2 md:after:hidden\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n showOnHover &&\n \"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarMenuBadge({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"sidebar-menu-badge\"\n data-sidebar=\"menu-badge\"\n className={cn(\n \"text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none\",\n \"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground\",\n \"peer-data-[size=sm]/menu-button:top-1\",\n \"peer-data-[size=default]/menu-button:top-1.5\",\n \"peer-data-[size=lg]/menu-button:top-2.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarMenuSkeleton({\n className,\n showIcon = false,\n ...props\n}: React.ComponentProps<\"div\"> & {\n showIcon?: boolean;\n}) {\n // Random width between 50 to 90%.\n const width = React.useMemo(() => {\n return `${Math.floor(Math.random() * 40) + 50}%`;\n }, []);\n\n return (\n <div\n data-slot=\"sidebar-menu-skeleton\"\n data-sidebar=\"menu-skeleton\"\n className={cn(\"flex h-8 items-center gap-2 rounded-md px-2\", className)}\n {...props}\n >\n {showIcon && (\n <Skeleton\n className=\"size-4 rounded-md\"\n data-sidebar=\"menu-skeleton-icon\"\n />\n )}\n <Skeleton\n className=\"h-4 max-w-(--skeleton-width) flex-1\"\n data-sidebar=\"menu-skeleton-text\"\n style={\n {\n \"--skeleton-width\": width,\n } as React.CSSProperties\n }\n />\n </div>\n );\n}\n\nfunction SidebarMenuSub({ className, ...props }: React.ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"sidebar-menu-sub\"\n data-sidebar=\"menu-sub\"\n className={cn(\n \"border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction SidebarMenuSubItem({\n className,\n ...props\n}: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"sidebar-menu-sub-item\"\n data-sidebar=\"menu-sub-item\"\n className={cn(\"group/menu-sub-item relative\", className)}\n {...props}\n />\n );\n}\n\nfunction SidebarMenuSubButton({\n asChild = false,\n size = \"md\",\n isActive = false,\n className,\n ...props\n}: React.ComponentProps<\"a\"> & {\n asChild?: boolean;\n size?: \"sm\" | \"md\";\n isActive?: boolean;\n}) {\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n data-slot=\"sidebar-menu-sub-button\"\n data-sidebar=\"menu-sub-button\"\n data-size={size}\n data-active={isActive}\n className={cn(\n \"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0\",\n \"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground\",\n size === \"sm\" && \"text-xs\",\n size === \"md\" && \"text-sm\",\n \"group-data-[collapsible=icon]:hidden\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n useSidebar,\n};\n"
934
+ },
935
+ {
936
+ "name": "Skeleton",
937
+ "slug": "skeleton",
938
+ "category": "widget",
939
+ "sourceCode": "import { cn } from \"@rlx-widgets/base\";\n\nfunction Skeleton({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"skeleton\"\n className={cn(\"bg-accent animate-pulse rounded-md\", className)}\n {...props}\n />\n );\n}\n\nexport { Skeleton };\n",
940
+ "demos": [
941
+ {
942
+ "name": "default",
943
+ "code": "import { Skeleton } from \"@rlx-widgets/skeleton\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex items-center space-x-4\">\n <Skeleton className=\"h-12 w-12 rounded-full\" />\n <div className=\"space-y-2\">\n <Skeleton className=\"h-4 w-[250px]\" />\n <Skeleton className=\"h-4 w-[200px]\" />\n </div>\n </div>\n );\n};\n"
944
+ }
945
+ ]
946
+ },
947
+ {
948
+ "name": "Slider",
949
+ "slug": "slider",
950
+ "category": "widget",
951
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Slider({\n className,\n defaultValue,\n value,\n min = 0,\n max = 100,\n ...props\n}: React.ComponentProps<typeof SliderPrimitive.Root>) {\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 data-slot=\"slider\"\n defaultValue={defaultValue}\n value={value}\n min={min}\n max={max}\n className={cn(\n \"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col\",\n className\n )}\n {...props}\n >\n <SliderPrimitive.Track\n data-slot=\"slider-track\"\n className={cn(\n \"bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5\"\n )}\n >\n <SliderPrimitive.Range\n data-slot=\"slider-range\"\n className={cn(\n \"bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full\"\n )}\n />\n </SliderPrimitive.Track>\n {Array.from({ length: _values.length }, (_, index) => (\n <SliderPrimitive.Thumb\n data-slot=\"slider-thumb\"\n key={index}\n className=\"border-primary bg-background ring-ring/50 block size-4 shrink-0 rounded-full border shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50\"\n />\n ))}\n </SliderPrimitive.Root>\n );\n}\n\nexport { Slider };\n",
952
+ "demos": [
953
+ {
954
+ "name": "default",
955
+ "code": "import { cn } from \"@rlx-widgets/base\";\nimport { Slider } from \"@rlx-widgets/slider\";\n\nexport const Preview = () => {\n return (\n <Slider defaultValue={[50]} max={100} step={1} className={cn(\"w-[60%]\")} />\n );\n};\n"
956
+ }
957
+ ]
958
+ },
959
+ {
960
+ "name": "Sonner",
961
+ "slug": "sonner",
962
+ "category": "widget",
963
+ "demos": [
964
+ {
965
+ "name": "default",
966
+ "code": "\"use client\";\n\nimport { toast, Toaster } from \"sonner\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { useTheme } from \"@rlx-widgets/base\";\n\nexport const Preview = () => {\n const themeContext = useTheme();\n const theme = themeContext.theme;\n return (\n <div>\n <Toaster\n theme={theme}\n toastOptions={{\n style: {\n background: \"var(--color-muted)\",\n border: \"var(--color-border)\",\n },\n }}\n position=\"top-center\"\n />\n <Button\n variant=\"outline\"\n onClick={() =>\n toast(\"Event has been created\", {\n description: \"Sunday, December 03, 2023 at 9:00 AM\",\n action: {\n label: \"Undo\",\n onClick: () => console.log(\"Undo\"),\n },\n })\n }\n >\n Show Toast\n </Button>\n </div>\n );\n};\n"
967
+ }
968
+ ]
969
+ },
970
+ {
971
+ "name": "Spinner",
972
+ "slug": "spinner",
973
+ "category": "widget",
974
+ "sourceCode": "import { cn } from \"@rlx-widgets/base\";\nimport { Loader2Icon } from \"lucide-react\";\n\nexport const Spinner = ({\n className,\n ...props\n}: React.ComponentProps<\"svg\">) => {\n return (\n <Loader2Icon\n role=\"status\"\n aria-label=\"Loading\"\n className={cn(\"size-4 animate-spin\", className)}\n {...props}\n />\n );\n};\n",
975
+ "demos": [
976
+ {
977
+ "name": "badge",
978
+ "code": "import { Badge } from \"@rlx-widgets/badge\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex items-center gap-4 [--radius:1.2rem]\">\n <Badge>\n <Spinner />\n Syncing\n </Badge>\n <Badge variant=\"secondary\">\n <Spinner />\n Updating\n </Badge>\n <Badge variant=\"outline\">\n <Spinner />\n Processing\n </Badge>\n </div>\n );\n};\n"
979
+ },
980
+ {
981
+ "name": "button",
982
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-col items-center gap-4\">\n <Button disabled size=\"sm\">\n <Spinner />\n Loading...\n </Button>\n <Button variant=\"outline\" disabled size=\"sm\">\n <Spinner />\n Please wait\n </Button>\n <Button variant=\"secondary\" disabled size=\"sm\">\n <Spinner />\n Processing\n </Button>\n </div>\n );\n};\n"
983
+ },
984
+ {
985
+ "name": "color",
986
+ "code": "import { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex items-center gap-6\">\n <Spinner className=\"size-6 text-red-500\" />\n <Spinner className=\"size-6 text-green-500\" />\n <Spinner className=\"size-6 text-blue-500\" />\n <Spinner className=\"size-6 text-yellow-500\" />\n <Spinner className=\"size-6 text-purple-500\" />\n </div>\n );\n};\n"
987
+ },
988
+ {
989
+ "name": "customization",
990
+ "code": "import { LoaderIcon } from \"lucide-react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Spinner({ className, ...props }: React.ComponentProps<\"svg\">) {\n return (\n <LoaderIcon\n role=\"status\"\n aria-label=\"Loading\"\n className={cn(\"size-4 animate-spin\", className)}\n {...props}\n />\n );\n}\n\nexport const Preview = () => {\n return (\n <div className=\"flex items-center gap-4\">\n <Spinner />\n </div>\n );\n};\n"
991
+ },
992
+ {
993
+ "name": "default",
994
+ "code": "import { Item, ItemContent, ItemMedia, ItemTitle } from \"@rlx-widgets/item\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-xs flex-col gap-4 [--radius:1rem]\">\n <Item variant=\"muted\">\n <ItemMedia>\n <Spinner />\n </ItemMedia>\n <ItemContent>\n <ItemTitle className=\"line-clamp-1\">Processing payment...</ItemTitle>\n </ItemContent>\n <ItemContent className=\"flex-none justify-end\">\n <span className=\"text-sm tabular-nums\">$100.00</span>\n </ItemContent>\n </Item>\n </div>\n );\n};\n"
995
+ },
996
+ {
997
+ "name": "empty",
998
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport {\n Empty,\n EmptyContent,\n EmptyDescription,\n EmptyHeader,\n EmptyMedia,\n EmptyTitle,\n} from \"@rlx-widgets/empty\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <Empty className=\"w-full\">\n <EmptyHeader>\n <EmptyMedia variant=\"icon\">\n <Spinner />\n </EmptyMedia>\n <EmptyTitle>Processing your request</EmptyTitle>\n <EmptyDescription>\n Please wait while we process your request. Do not refresh the page.\n </EmptyDescription>\n </EmptyHeader>\n <EmptyContent>\n <Button variant=\"outline\" size=\"sm\">\n Cancel\n </Button>\n </EmptyContent>\n </Empty>\n );\n};\n"
999
+ },
1000
+ {
1001
+ "name": "input-group",
1002
+ "code": "import { ArrowUpIcon } from \"lucide-react\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\nimport {\n InputGroup,\n InputGroupAddon,\n InputGroupButton,\n InputGroupInput,\n InputGroupTextarea,\n} from \"@rlx-widgets/input-group\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-4\">\n <InputGroup>\n <InputGroupInput placeholder=\"Send a message...\" disabled />\n <InputGroupAddon align=\"inline-end\">\n <Spinner />\n </InputGroupAddon>\n </InputGroup>\n <InputGroup>\n <InputGroupTextarea placeholder=\"Send a message...\" disabled />\n <InputGroupAddon align=\"block-end\">\n <Spinner /> Validating...\n <InputGroupButton className=\"ml-auto\" variant=\"default\">\n <ArrowUpIcon />\n <span className=\"sr-only\">Send</span>\n </InputGroupButton>\n </InputGroupAddon>\n </InputGroup>\n </div>\n );\n};\n"
1003
+ },
1004
+ {
1005
+ "name": "item",
1006
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Progress } from \"@rlx-widgets/progress\";\nimport { Spinner } from \"@rlx-widgets/spinner\";\nimport {\n Item,\n ItemActions,\n ItemContent,\n ItemDescription,\n ItemFooter,\n ItemMedia,\n ItemTitle,\n} from \"@rlx-widgets/item\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-md flex-col gap-4 [--radius:1rem]\">\n <Item variant=\"outline\">\n <ItemMedia variant=\"icon\">\n <Spinner />\n </ItemMedia>\n <ItemContent>\n <ItemTitle>Downloading...</ItemTitle>\n <ItemDescription>129 MB / 1000 MB</ItemDescription>\n </ItemContent>\n <ItemActions className=\"hidden sm:flex\">\n <Button variant=\"outline\" size=\"sm\">\n Cancel\n </Button>\n </ItemActions>\n <ItemFooter>\n <Progress value={75} />\n </ItemFooter>\n </Item>\n </div>\n );\n};\n"
1007
+ },
1008
+ {
1009
+ "name": "size",
1010
+ "code": "import { Spinner } from \"@rlx-widgets/spinner\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex items-center gap-6\">\n <Spinner className=\"size-3\" />\n <Spinner className=\"size-4\" />\n <Spinner className=\"size-6\" />\n <Spinner className=\"size-8\" />\n </div>\n );\n};\n"
1011
+ }
1012
+ ]
1013
+ },
1014
+ {
1015
+ "name": "Switch",
1016
+ "slug": "switch",
1017
+ "category": "widget",
1018
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Switch({\n className,\n ...props\n}: React.ComponentProps<typeof SwitchPrimitive.Root>) {\n return (\n <SwitchPrimitive.Root\n data-slot=\"switch\"\n className={cn(\n \"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className={cn(\n \"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0\"\n )}\n />\n </SwitchPrimitive.Root>\n );\n}\n\nexport { Switch };\n",
1019
+ "demos": [
1020
+ {
1021
+ "name": "default",
1022
+ "code": "import { Label } from \"@rlx-widgets/label\";\nimport { Switch } from \"@rlx-widgets/switch\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex items-center space-x-2\">\n <Switch id=\"airplane-mode\" />\n <Label htmlFor=\"airplane-mode\">Airplane Mode</Label>\n </div>\n );\n};\n"
1023
+ },
1024
+ {
1025
+ "name": "form",
1026
+ "code": "\"use client\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { Switch } from \"@rlx-widgets/switch\";\nimport { toast } from \"sonner\";\nimport { useForm } from \"react-hook-form\";\nimport { z } from \"zod\";\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n} from \"@rlx-widgets/form\";\n\nconst FormSchema = z.object({\n marketing_emails: z.boolean().default(false).optional(),\n security_emails: z.boolean(),\n});\n\nexport const Preview = () => {\n const form = useForm<z.infer<typeof FormSchema>>({\n resolver: zodResolver(FormSchema),\n defaultValues: {\n security_emails: true,\n },\n });\n\n function onSubmit(data: z.infer<typeof FormSchema>) {\n toast(\"You submitted the following values\", {\n description: (\n <pre className=\"mt-2 w-[320px] rounded-md bg-neutral-950 p-4\">\n <code className=\"text-white\">{JSON.stringify(data, null, 2)}</code>\n </pre>\n ),\n });\n }\n\n return (\n <Form {...form}>\n <form onSubmit={form.handleSubmit(onSubmit)} className=\"w-full space-y-6\">\n <div>\n <h3 className=\"mb-4 text-lg font-medium\">Email Notifications</h3>\n <div className=\"space-y-4\">\n <FormField\n control={form.control}\n name=\"marketing_emails\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm\">\n <div className=\"space-y-0.5\">\n <FormLabel>Marketing emails</FormLabel>\n <FormDescription>\n Receive emails about new products, features, and more.\n </FormDescription>\n </div>\n <FormControl>\n <Switch\n checked={field.value}\n onCheckedChange={field.onChange}\n />\n </FormControl>\n </FormItem>\n )}\n />\n <FormField\n control={form.control}\n name=\"security_emails\"\n render={({ field }) => (\n <FormItem className=\"flex flex-row items-center justify-between rounded-lg border p-3 shadow-sm\">\n <div className=\"space-y-0.5\">\n <FormLabel>Security emails</FormLabel>\n <FormDescription>\n Receive emails about your account security.\n </FormDescription>\n </div>\n <FormControl>\n <Switch\n checked={field.value}\n onCheckedChange={field.onChange}\n disabled\n aria-readonly\n />\n </FormControl>\n </FormItem>\n )}\n />\n </div>\n </div>\n <Button type=\"submit\">Submit</Button>\n </form>\n </Form>\n );\n};\n"
1027
+ }
1028
+ ]
1029
+ },
1030
+ {
1031
+ "name": "Table",
1032
+ "slug": "table",
1033
+ "category": "widget",
1034
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Table({ className, ...props }: React.ComponentProps<\"table\">) {\n return (\n <div\n data-slot=\"table-container\"\n className=\"relative w-full overflow-x-auto\"\n >\n <table\n data-slot=\"table\"\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n </div>\n );\n}\n\nfunction TableHeader({ className, ...props }: React.ComponentProps<\"thead\">) {\n return (\n <thead\n data-slot=\"table-header\"\n className={cn(\"[&_tr]:border-b\", className)}\n {...props}\n />\n );\n}\n\nfunction TableBody({ className, ...props }: React.ComponentProps<\"tbody\">) {\n return (\n <tbody\n data-slot=\"table-body\"\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n );\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<\"tfoot\">) {\n return (\n <tfoot\n data-slot=\"table-footer\"\n className={cn(\n \"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction TableRow({ className, ...props }: React.ComponentProps<\"tr\">) {\n return (\n <tr\n data-slot=\"table-row\"\n className={cn(\n \"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction TableHead({ className, ...props }: React.ComponentProps<\"th\">) {\n return (\n <th\n data-slot=\"table-head\"\n className={cn(\n \"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction TableCell({ className, ...props }: React.ComponentProps<\"td\">) {\n return (\n <td\n data-slot=\"table-cell\"\n className={cn(\n \"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction TableCaption({\n className,\n ...props\n}: React.ComponentProps<\"caption\">) {\n return (\n <caption\n data-slot=\"table-caption\"\n className={cn(\"text-muted-foreground mt-4 text-sm\", className)}\n {...props}\n />\n );\n}\n\nexport {\n Table,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n TableCaption,\n};\n",
1035
+ "demos": [
1036
+ {
1037
+ "name": "default",
1038
+ "code": "import {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableFooter,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@rlx-widgets/table\";\n\nconst invoices = [\n {\n invoice: \"INV001\",\n paymentStatus: \"Paid\",\n totalAmount: \"$250.00\",\n paymentMethod: \"Credit Card\",\n },\n {\n invoice: \"INV002\",\n paymentStatus: \"Pending\",\n totalAmount: \"$150.00\",\n paymentMethod: \"PayPal\",\n },\n {\n invoice: \"INV003\",\n paymentStatus: \"Unpaid\",\n totalAmount: \"$350.00\",\n paymentMethod: \"Bank Transfer\",\n },\n {\n invoice: \"INV004\",\n paymentStatus: \"Paid\",\n totalAmount: \"$450.00\",\n paymentMethod: \"Credit Card\",\n },\n {\n invoice: \"INV005\",\n paymentStatus: \"Paid\",\n totalAmount: \"$550.00\",\n paymentMethod: \"PayPal\",\n },\n {\n invoice: \"INV006\",\n paymentStatus: \"Pending\",\n totalAmount: \"$200.00\",\n paymentMethod: \"Bank Transfer\",\n },\n {\n invoice: \"INV007\",\n paymentStatus: \"Unpaid\",\n totalAmount: \"$300.00\",\n paymentMethod: \"Credit Card\",\n },\n];\n\nexport const Preview = () => {\n return (\n <Table>\n <TableCaption>A list of your recent invoices.</TableCaption>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-[100px]\">Invoice</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Method</TableHead>\n <TableHead className=\"text-right\">Amount</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {invoices.map((invoice) => (\n <TableRow key={invoice.invoice}>\n <TableCell className=\"font-medium\">{invoice.invoice}</TableCell>\n <TableCell>{invoice.paymentStatus}</TableCell>\n <TableCell>{invoice.paymentMethod}</TableCell>\n <TableCell className=\"text-right\">{invoice.totalAmount}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n <TableFooter>\n <TableRow>\n <TableCell colSpan={3}>Total</TableCell>\n <TableCell className=\"text-right\">$2,500.00</TableCell>\n </TableRow>\n </TableFooter>\n </Table>\n );\n};\n"
1039
+ }
1040
+ ]
1041
+ },
1042
+ {
1043
+ "name": "Tabs",
1044
+ "slug": "tabs",
1045
+ "category": "widget",
1046
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Tabs({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Root>) {\n return (\n <TabsPrimitive.Root\n data-slot=\"tabs\"\n className={cn(\"flex flex-col gap-2\", className)}\n {...props}\n />\n );\n}\n\nfunction TabsList({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.List>) {\n return (\n <TabsPrimitive.List\n data-slot=\"tabs-list\"\n className={cn(\n \"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction TabsTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {\n return (\n <TabsPrimitive.Trigger\n data-slot=\"tabs-trigger\"\n className={cn(\n \"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n />\n );\n}\n\nfunction TabsContent({\n className,\n ...props\n}: React.ComponentProps<typeof TabsPrimitive.Content>) {\n return (\n <TabsPrimitive.Content\n data-slot=\"tabs-content\"\n className={cn(\"flex-1 outline-none\", className)}\n {...props}\n />\n );\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n",
1047
+ "demos": [
1048
+ {
1049
+ "name": "default",
1050
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { Label } from \"@rlx-widgets/label\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@rlx-widgets/tabs\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardFooter,\n CardHeader,\n CardTitle,\n} from \"@rlx-widgets/card\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex w-full max-w-sm flex-col gap-6\">\n <Tabs defaultValue=\"account\">\n <TabsList>\n <TabsTrigger value=\"account\">Account</TabsTrigger>\n <TabsTrigger value=\"password\">Password</TabsTrigger>\n </TabsList>\n <TabsContent value=\"account\">\n <Card>\n <CardHeader>\n <CardTitle>Account</CardTitle>\n <CardDescription>\n Make changes to your account here. Click save when you&apos;re\n done.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"grid gap-6\">\n <div className=\"grid gap-3\">\n <Label htmlFor=\"tabs-demo-name\">Name</Label>\n <Input id=\"tabs-demo-name\" defaultValue=\"Pedro Duarte\" />\n </div>\n <div className=\"grid gap-3\">\n <Label htmlFor=\"tabs-demo-username\">Username</Label>\n <Input id=\"tabs-demo-username\" defaultValue=\"@peduarte\" />\n </div>\n </CardContent>\n <CardFooter>\n <Button>Save changes</Button>\n </CardFooter>\n </Card>\n </TabsContent>\n <TabsContent value=\"password\">\n <Card>\n <CardHeader>\n <CardTitle>Password</CardTitle>\n <CardDescription>\n Change your password here. After saving, you&apos;ll be logged\n out.\n </CardDescription>\n </CardHeader>\n <CardContent className=\"grid gap-6\">\n <div className=\"grid gap-3\">\n <Label htmlFor=\"tabs-demo-current\">Current password</Label>\n <Input id=\"tabs-demo-current\" type=\"password\" />\n </div>\n <div className=\"grid gap-3\">\n <Label htmlFor=\"tabs-demo-new\">New password</Label>\n <Input id=\"tabs-demo-new\" type=\"password\" />\n </div>\n </CardContent>\n <CardFooter>\n <Button>Save password</Button>\n </CardFooter>\n </Card>\n </TabsContent>\n </Tabs>\n </div>\n );\n};\n"
1051
+ }
1052
+ ]
1053
+ },
1054
+ {
1055
+ "name": "Textarea",
1056
+ "slug": "textarea",
1057
+ "category": "widget",
1058
+ "sourceCode": "import * as React from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction Textarea({ className, ...props }: React.ComponentProps<\"textarea\">) {\n return (\n <textarea\n data-slot=\"textarea\"\n className={cn(\n \"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Textarea };\n",
1059
+ "demos": [
1060
+ {
1061
+ "name": "default",
1062
+ "code": "import { Textarea } from \"@rlx-widgets/textarea\";\n\nexport const Preview = () => {\n return <Textarea placeholder=\"Type your message here.\" />;\n};\n"
1063
+ }
1064
+ ]
1065
+ },
1066
+ {
1067
+ "name": "Toggle",
1068
+ "slug": "toggle",
1069
+ "category": "widget",
1070
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@rlx-widgets/base\";\n\nconst toggleVariants = cva(\n \"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n outline:\n \"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-2 min-w-9\",\n sm: \"h-8 px-1.5 min-w-8\",\n lg: \"h-10 px-2.5 min-w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nfunction Toggle({\n className,\n variant,\n size,\n ...props\n}: React.ComponentProps<typeof TogglePrimitive.Root> &\n VariantProps<typeof toggleVariants>) {\n return (\n <TogglePrimitive.Root\n data-slot=\"toggle\"\n className={cn(toggleVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Toggle, toggleVariants };\n",
1071
+ "demos": [
1072
+ {
1073
+ "name": "default",
1074
+ "code": "import { Bold } from \"lucide-react\";\nimport { Toggle } from \"@rlx-widgets/toggle\";\n\nexport const Preview = () => {\n return (\n <Toggle aria-label=\"Toggle italic\">\n <Bold className=\"h-4 w-4\" />\n </Toggle>\n );\n};\n"
1075
+ },
1076
+ {
1077
+ "name": "disabled",
1078
+ "code": "import { Toggle } from \"@rlx-widgets/toggle\";\nimport { Underline } from \"lucide-react\";\n\nexport const Preview = () => {\n return (\n <Toggle aria-label=\"Toggle italic\" disabled>\n <Underline className=\"h-4 w-4\" />\n </Toggle>\n );\n};\n"
1079
+ },
1080
+ {
1081
+ "name": "large",
1082
+ "code": "import { Italic } from \"lucide-react\";\nimport { Toggle } from \"@rlx-widgets/toggle\";\n\nexport const Preview = () => {\n return (\n <Toggle size=\"lg\" variant=\"outline\" aria-label=\"Toggle italic\">\n <Italic />\n </Toggle>\n );\n};\n"
1083
+ },
1084
+ {
1085
+ "name": "outline",
1086
+ "code": "import { Italic } from \"lucide-react\";\nimport { Toggle } from \"@rlx-widgets/toggle\";\n\nexport const Preview = () => {\n return (\n <Toggle variant=\"outline\" aria-label=\"Toggle italic\">\n <Italic />\n </Toggle>\n );\n};\n"
1087
+ },
1088
+ {
1089
+ "name": "small",
1090
+ "code": "import { Italic } from \"lucide-react\";\nimport { Toggle } from \"@rlx-widgets/toggle\";\n\nexport const Preview = () => {\n return (\n <Toggle size=\"sm\" variant=\"outline\" aria-label=\"Toggle italic\">\n <Italic />\n </Toggle>\n );\n};\n"
1091
+ },
1092
+ {
1093
+ "name": "with-text",
1094
+ "code": "import { Italic } from \"lucide-react\";\nimport { Toggle } from \"@rlx-widgets/toggle\";\n\nexport const Preview = () => {\n return (\n <Toggle aria-label=\"Toggle italic\">\n <Italic />\n Italic\n </Toggle>\n );\n};\n"
1095
+ }
1096
+ ]
1097
+ },
1098
+ {
1099
+ "name": "Toggle Group",
1100
+ "slug": "toggle-group",
1101
+ "category": "widget",
1102
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as ToggleGroupPrimitive from \"@radix-ui/react-toggle-group\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { toggleVariants } from \"@rlx-widgets/toggle\";\nimport { type VariantProps } from \"class-variance-authority\";\n\nconst ToggleGroupContext = React.createContext<\n VariantProps<typeof toggleVariants>\n>({\n size: \"default\",\n variant: \"default\",\n});\n\nfunction ToggleGroup({\n className,\n variant,\n size,\n children,\n ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &\n VariantProps<typeof toggleVariants>) {\n return (\n <ToggleGroupPrimitive.Root\n data-slot=\"toggle-group\"\n data-variant={variant}\n data-size={size}\n className={cn(\n \"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs\",\n className\n )}\n {...props}\n >\n <ToggleGroupContext.Provider value={{ variant, size }}>\n {children}\n </ToggleGroupContext.Provider>\n </ToggleGroupPrimitive.Root>\n );\n}\n\nfunction ToggleGroupItem({\n className,\n children,\n variant,\n size,\n ...props\n}: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &\n VariantProps<typeof toggleVariants>) {\n const context = React.useContext(ToggleGroupContext);\n\n return (\n <ToggleGroupPrimitive.Item\n data-slot=\"toggle-group-item\"\n data-variant={context.variant || variant}\n data-size={context.size || size}\n className={cn(\n toggleVariants({\n variant: context.variant || variant,\n size: context.size || size,\n }),\n \"min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[variant=outline]:border-l-0 data-[variant=outline]:first:border-l\",\n className\n )}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Item>\n );\n}\n\nexport { ToggleGroup, ToggleGroupItem };\n",
1103
+ "demos": [
1104
+ {
1105
+ "name": "default",
1106
+ "code": "import { Bold, Italic, Underline } from \"lucide-react\";\nimport { ToggleGroup, ToggleGroupItem } from \"@rlx-widgets/toggle-group\";\n\nexport const Preview = () => {\n return (\n <ToggleGroup variant=\"outline\" type=\"multiple\">\n <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n <Bold className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n <Italic className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"strikethrough\" aria-label=\"Toggle strikethrough\">\n <Underline className=\"h-4 w-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n};\n"
1107
+ },
1108
+ {
1109
+ "name": "disabled",
1110
+ "code": "import { Bold, Italic, Underline } from \"lucide-react\";\nimport { ToggleGroup, ToggleGroupItem } from \"@rlx-widgets/toggle-group\";\n\nexport const Preview = () => {\n return (\n <ToggleGroup type=\"multiple\" disabled>\n <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n <Bold className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n <Italic className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"strikethrough\" aria-label=\"Toggle strikethrough\">\n <Underline className=\"h-4 w-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n};\n"
1111
+ },
1112
+ {
1113
+ "name": "large",
1114
+ "code": "import { Bold, Italic, Underline } from \"lucide-react\";\nimport { ToggleGroup, ToggleGroupItem } from \"@rlx-widgets/toggle-group\";\n\nexport const Preview = () => {\n return (\n <ToggleGroup type=\"multiple\" size=\"lg\">\n <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n <Bold className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n <Italic className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"strikethrough\" aria-label=\"Toggle strikethrough\">\n <Underline className=\"h-4 w-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n};\n"
1115
+ },
1116
+ {
1117
+ "name": "outline",
1118
+ "code": "import { Bold, Italic, Underline } from \"lucide-react\";\nimport { ToggleGroup, ToggleGroupItem } from \"@rlx-widgets/toggle-group\";\n\nexport const Preview = () => {\n return (\n <ToggleGroup type=\"multiple\" variant=\"outline\">\n <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n <Bold className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n <Italic className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"strikethrough\" aria-label=\"Toggle strikethrough\">\n <Underline className=\"h-4 w-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n};\n"
1119
+ },
1120
+ {
1121
+ "name": "single",
1122
+ "code": "import { Bold, Italic, Underline } from \"lucide-react\";\nimport { ToggleGroup, ToggleGroupItem } from \"@rlx-widgets/toggle-group\";\n\nexport const Preview = () => {\n return (\n <ToggleGroup type=\"single\">\n <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n <Bold className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n <Italic className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"strikethrough\" aria-label=\"Toggle strikethrough\">\n <Underline className=\"h-4 w-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n};\n"
1123
+ },
1124
+ {
1125
+ "name": "small",
1126
+ "code": "import { Bold, Italic, Underline } from \"lucide-react\";\nimport { ToggleGroup, ToggleGroupItem } from \"@rlx-widgets/toggle-group\";\n\nexport const Preview = () => {\n return (\n <ToggleGroup type=\"single\" size=\"sm\">\n <ToggleGroupItem value=\"bold\" aria-label=\"Toggle bold\">\n <Bold className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"italic\" aria-label=\"Toggle italic\">\n <Italic className=\"h-4 w-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"strikethrough\" aria-label=\"Toggle strikethrough\">\n <Underline className=\"h-4 w-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n};\n"
1127
+ }
1128
+ ]
1129
+ },
1130
+ {
1131
+ "name": "Tooltip",
1132
+ "slug": "tooltip",
1133
+ "category": "widget",
1134
+ "sourceCode": "\"use client\";\n\nimport * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"@rlx-widgets/base\";\n\nfunction TooltipProvider({\n delayDuration = 0,\n ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {\n return (\n <TooltipPrimitive.Provider\n data-slot=\"tooltip-provider\"\n delayDuration={delayDuration}\n {...props}\n />\n );\n}\n\nfunction Tooltip({\n ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Root>) {\n return (\n <TooltipProvider>\n <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n </TooltipProvider>\n );\n}\n\nfunction TooltipTrigger({\n ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />;\n}\n\nfunction TooltipContent({\n className,\n sideOffset = 0,\n children,\n ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n data-slot=\"tooltip-content\"\n sideOffset={sideOffset}\n className={cn(\n \"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance\",\n className\n )}\n {...props}\n >\n {children}\n <TooltipPrimitive.Arrow className=\"bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]\" />\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n );\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n",
1135
+ "demos": [
1136
+ {
1137
+ "name": "default",
1138
+ "code": "import { Button } from \"@rlx-widgets/button\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@rlx-widgets/tooltip\";\n\nexport const Preview = () => {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"outline\">Hover</Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>Add to library</p>\n </TooltipContent>\n </Tooltip>\n );\n};\n"
1139
+ }
1140
+ ]
1141
+ },
1142
+ {
1143
+ "name": "Typography",
1144
+ "slug": "typography",
1145
+ "category": "widget",
1146
+ "sourceCode": "import { cn } from \"@rlx-widgets/base\";\nimport { FC, HTMLAttributes } from \"react\";\n\nexport function Heading1({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <h1\n className={cn(\n \"scroll-m-20 text-4xl font-extrabold text-balance\",\n className\n )}\n >\n {children}\n </h1>\n );\n}\n\nexport function Heading2({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <h2\n className={cn(\"scroll-m-20 text-3xl font-semibold first:mt-0\", className)}\n >\n {children}\n </h2>\n );\n}\n\nexport function Heading3({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <h3 className={cn(\"scroll-m-20 text-2xl font-semibold\", className)}>\n {children}\n </h3>\n );\n}\n\nexport function Heading4({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <h4 className={cn(\"scroll-m-20 text-xl font-semibold\", className)}>\n {children}\n </h4>\n );\n}\n\nexport function Heading5({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <h4 className={cn(\"scroll-m-20 text-lg font-semibold\", className)}>\n {children}\n </h4>\n );\n}\n\nexport function Heading6({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return (\n <h4 className={cn(\"scroll-m-20 text-base font-semibold\", className)}>\n {children}\n </h4>\n );\n}\n\nexport function Paragraph({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) {\n return <p className={cn(\"leading-7\", className)}>{children}</p>;\n}\n\nexport const Blockquote: FC<HTMLAttributes<HTMLQuoteElement>> = ({\n children,\n className,\n ...props\n}) => {\n return (\n <blockquote\n className={cn(\"mt-6 border-l-2 pl-6 italic\", className)}\n {...props}\n >\n {children}\n </blockquote>\n );\n};\n",
1147
+ "demos": [
1148
+ {
1149
+ "name": "default",
1150
+ "code": "import {\n Blockquote,\n Heading1,\n Heading2,\n Heading3,\n Heading4,\n Heading5,\n Heading6,\n Paragraph,\n} from \"@rlx-widgets/typography\";\n\nexport const Preview = () => {\n return (\n <div>\n <Heading1>Heading 1</Heading1>\n <Heading2>Heading 2</Heading2>\n <Heading3>Heading 3</Heading3>\n <Heading4>Heading 4</Heading4>\n <Heading5>Heading 5</Heading5>\n <Heading6>Heading 6</Heading6>\n <Paragraph>Paragraph</Paragraph>\n <Blockquote>Blockquote</Blockquote>\n </div>\n );\n};\n"
1151
+ }
1152
+ ]
1153
+ }
1154
+ ],
1155
+ "components": [
1156
+ {
1157
+ "name": "Blur Reveal",
1158
+ "slug": "blur-reveal",
1159
+ "category": "component",
1160
+ "sourceCode": "\"use client\";\n\nimport { cva, VariantProps } from \"class-variance-authority\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { useState, MouseEvent, useEffect } from \"react\";\nimport { cn } from \"@rlx-widgets/base\";\n\nconst blurRevealVariants = cva(\n \"transition-all duration-100 cursor-pointer select-none\",\n {\n variants: {\n blur: {\n extraSmall: \"blur-xs\",\n small: \"blur-sm\",\n medium: \"blur-md\",\n large: \"blur-lg\",\n extraLarge: \"blur-2xl\",\n },\n },\n defaultVariants: {\n blur: \"extraSmall\",\n },\n }\n);\n\nconst BlurReveal = ({\n blur,\n children,\n className,\n asChild,\n onClick,\n reveal = false,\n ...props\n}: React.ComponentProps<\"div\"> &\n VariantProps<typeof blurRevealVariants> & {\n asChild?: boolean;\n reveal?: boolean;\n }) => {\n const [showBlur, setShowBlur] = useState(!reveal);\n const Comp = asChild ? Slot : \"div\";\n\n useEffect(() => {\n setShowBlur(!reveal);\n }, [reveal]);\n\n const handleClick = (e: MouseEvent<HTMLDivElement>) => {\n if (onClick) {\n onClick?.(e);\n return;\n }\n setShowBlur(false);\n };\n\n return (\n <Comp\n className={cn(\n blurRevealVariants({ blur, className }),\n !showBlur && \"blur-none cursor-auto select-auto\"\n )}\n onClick={handleClick}\n {...props}\n >\n {children}\n </Comp>\n );\n};\n\nexport { BlurReveal, blurRevealVariants };\n",
1161
+ "demos": [
1162
+ {
1163
+ "name": "blur",
1164
+ "code": "\"use client\";\n\nimport { BlurReveal } from \"@rlx-components/blur-reveal\";\nimport { Card, CardContent, CardTitle } from \"@rlx-widgets/card\";\n\nexport const Preview = () => {\n return (\n <div className=\"flex flex-wrap gap-4\">\n <Card>\n <CardTitle className=\"text-center\">Extra Small</CardTitle>\n <CardContent>\n <BlurReveal blur=\"extraSmall\">\n <p>Hello, world!</p>\n </BlurReveal>\n </CardContent>\n </Card>\n <Card>\n <CardTitle className=\"text-center\">Small</CardTitle>\n <CardContent>\n <BlurReveal blur=\"small\">\n <p>Hello, world!</p>\n </BlurReveal>\n </CardContent>\n </Card>\n <Card>\n <CardTitle className=\"text-center\">Medium</CardTitle>\n <CardContent>\n <BlurReveal blur=\"medium\">\n <p>Hello, world!</p>\n </BlurReveal>\n </CardContent>\n </Card>\n <Card>\n <CardTitle className=\"text-center\">Large</CardTitle>\n <CardContent>\n <BlurReveal blur=\"large\">\n <p>Hello, world!</p>\n </BlurReveal>\n </CardContent>\n </Card>\n <Card>\n <CardTitle className=\"text-center\">Extra Large</CardTitle>\n <CardContent>\n <BlurReveal blur=\"extraLarge\">\n <p>Hello, world!</p>\n </BlurReveal>\n </CardContent>\n </Card>\n </div>\n );\n};\n"
1165
+ },
1166
+ {
1167
+ "name": "controlled",
1168
+ "code": "\"use client\";\n\nimport { BlurReveal } from \"@rlx-components/blur-reveal\";\nimport { useState } from \"react\";\n\nexport const Preview = () => {\n const [reveal, setReveal] = useState(false);\n return (\n <BlurReveal reveal={reveal} onClick={() => setReveal(true)}>\n <p>Hello, world!</p>\n </BlurReveal>\n );\n};\n"
1169
+ },
1170
+ {
1171
+ "name": "default",
1172
+ "code": "\"use client\";\n\nimport { BlurReveal } from \"@rlx-components/blur-reveal\";\n\nexport const Preview = () => {\n return (\n <BlurReveal>\n <p>Hello, world!</p>\n </BlurReveal>\n );\n};\n"
1173
+ }
1174
+ ]
1175
+ },
1176
+ {
1177
+ "name": "Code Preview Tabs",
1178
+ "slug": "code-preview-tabs",
1179
+ "category": "component",
1180
+ "sourceCode": "\"use client\";\n\nimport { cn } from \"@rlx-widgets/base\";\nimport { CodePreviewTabsProps, PreviewVariants, TabType } from \"./types\";\nimport { ShikiCodeBlock } from \"@rlx-components/shiki-code-block\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@rlx-widgets/tabs\";\nimport { TabTypeEnum } from \"./enums\";\nimport { useMemo, useState } from \"react\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@rlx-widgets/select\";\n\nconst defaultClassNames = {};\n\nexport const CodePreviewTabs = ({\n variants: variantsProp,\n preview,\n code,\n classNames = defaultClassNames,\n lang = \"tsx\",\n}: CodePreviewTabsProps) => {\n const variants = useMemo(() => {\n return variantsProp || { Default: { preview, code } };\n }, [variantsProp, preview, code]);\n\n const [value, setValue] = useState<TabType>(\"preview\");\n const [variant, setVariant] = useState<string>(Object.keys(variants)[0]);\n\n const handleValueChange = (newValue: string) => {\n setValue(newValue as TabType);\n };\n\n return (\n <Tabs\n value={value}\n onValueChange={handleValueChange}\n className=\"relative mt-6 w-full\"\n >\n <div className=\"flex items-center justify-between\">\n <TabsList>\n <TabsTrigger value={TabTypeEnum.PREVIEW}>Preview</TabsTrigger>\n <TabsTrigger value={TabTypeEnum.CODE}>Code</TabsTrigger>\n </TabsList>\n {Object.keys(variants).length > 1 && (\n <Select\n onValueChange={setVariant}\n defaultValue={Object.keys(variants)[0]}\n value={variant}\n >\n <SelectTrigger>\n <SelectValue placeholder=\"Default\" />\n </SelectTrigger>\n <SelectContent>\n {Object.keys(variants).map((variant) => (\n <SelectItem key={variant} value={variant}>\n {variant}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n </div>\n\n <TabsContent value={TabTypeEnum.PREVIEW}>\n <div\n className={cn(\"rounded-md border p-14 h-[400px]\", classNames.preview)}\n >\n <Preview variant={variant} variants={variants} />\n </div>\n </TabsContent>\n\n <TabsContent value={TabTypeEnum.CODE}>\n <ShikiCodeBlock\n code={variants[variant].code}\n lang={lang}\n className={classNames.code}\n />\n </TabsContent>\n </Tabs>\n );\n};\n\nconst Preview = ({\n variant,\n variants,\n}: {\n variant: string;\n variants: PreviewVariants;\n}) => {\n if (typeof variants[variant].preview !== \"function\") {\n return <>{variants[variant].preview}</>;\n }\n\n const Component = variants[variant].preview;\n\n return <Component />;\n};\n",
1181
+ "demos": [
1182
+ {
1183
+ "name": "default",
1184
+ "code": "\"use client\";\n\nimport { CodePreviewTabs } from \"@rlx-components/code-preview-tabs\";\n\nconst preview = <div>Hello, world!</div>;\nconst code = `<div>Hello, world!</div>`;\n\nexport const Preview = () => {\n return (\n <div className=\"w-full\">\n <CodePreviewTabs\n preview={preview}\n code={code}\n lang=\"tsx\"\n classNames={{ preview: \"h-[200px]\", code: \"h-[200px]\" }}\n />\n </div>\n );\n};\n"
1185
+ },
1186
+ {
1187
+ "name": "variants",
1188
+ "code": "\"use client\";\n\nimport { CodePreviewTabs } from \"@rlx-components/code-preview-tabs\";\n\nconst variants = {\n Default: {\n preview: <div>Hello, world!</div>,\n code: `<div>Hello, world!</div>`,\n },\n Variant2: {\n preview: <div>Goodbye, world!</div>,\n code: `<div>Goodbye, world!</div>`,\n },\n};\n\nexport const Preview = () => {\n return (\n <div className=\"w-full\">\n <CodePreviewTabs\n variants={variants}\n lang=\"tsx\"\n classNames={{ preview: \"h-[200px]\", code: \"h-[200px]\" }}\n />\n </div>\n );\n};\n"
1189
+ }
1190
+ ],
1191
+ "sourceFiles": {
1192
+ "enums/TabTypeEnum.ts": "export enum TabTypeEnum {\n PREVIEW = \"preview\",\n CODE = \"code\",\n}\n",
1193
+ "types/CodePreview.t.ts": "import { JSX, ReactNode } from \"react\";\n\nexport type CodePreview = {\n preview: ReactNode | (() => JSX.Element);\n code: string;\n};\n",
1194
+ "types/CodePreviewTabsProps.t.ts": "import { BundledLanguage } from \"shiki/bundle/web\";\nimport { CodePreview } from \"./CodePreview.t\";\nimport { PreviewVariants } from \"./PreviewVariants.t\";\n\nexport type CodePreviewTabsProps =\n | (CodePreview &\n CommonProps & {\n variants?: undefined;\n })\n | (CommonProps & {\n preview?: undefined;\n code?: undefined;\n variants: PreviewVariants;\n });\n\ntype CommonProps = {\n classNames?: {\n preview?: string;\n code?: string;\n };\n /**\n * @default tsx\n */\n lang?: BundledLanguage;\n};\n",
1195
+ "types/PreviewVariants.t.ts": "import { CodePreview } from \"./CodePreview.t\";\n\nexport type PreviewVariants = {\n [variant: string]: CodePreview;\n};\n",
1196
+ "types/TabType.t.ts": "import { TabTypeEnum } from \"../enums\";\n\nexport type TabType = `${TabTypeEnum}`;\n"
1197
+ }
1198
+ },
1199
+ {
1200
+ "name": "Shiki Code Block",
1201
+ "slug": "shiki-code-block",
1202
+ "category": "component",
1203
+ "sourceCode": "\"use client\";\n\nimport { JSX, useLayoutEffect, useState } from \"react\";\nimport { highlight } from \"./utils\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { BundledLanguage } from \"shiki/bundle/web\";\nimport { Copy } from \"lucide-react\";\n\nexport const ShikiCodeBlock = ({\n code,\n lang,\n className,\n}: {\n code: string;\n lang: BundledLanguage;\n className?: string;\n}) => {\n const [onHover, setOnHover] = useState(false);\n const [highlightedCode, setHighlightedCode] = useState<JSX.Element>();\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n useLayoutEffect(() => {\n void highlight({\n code,\n lang,\n className: cn(\"h-[400px]\", className),\n }).then(setHighlightedCode);\n }, [className, code, lang]);\n\n return (\n <div\n onMouseEnter={() => setOnHover(true)}\n onMouseLeave={() => setOnHover(false)}\n >\n <div className=\"relative\">\n <div>{highlightedCode ?? <p>Loading...</p>}</div>\n <span\n className={cn(\n \"absolute top-[8px] right-[16px]\",\n \"text-xs\",\n onHover && \"hidden\"\n )}\n >\n {lang}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleCopy}\n className={cn(\n \"absolute top-[8px] right-[16px]\",\n \"cursor-pointer\",\n !onHover && \"hidden\"\n )}\n >\n <Copy /> {copied ? \"Copied!\" : \"Copy\"}\n </Button>\n </div>\n </div>\n );\n};\n",
1204
+ "demos": [
1205
+ {
1206
+ "name": "default",
1207
+ "code": "\"use client\";\n\nimport { ShikiCodeBlock } from \"@rlx-components/shiki-code-block\";\n\nconst code = `console.log('Hello, world!');`;\n\nexport const Preview = () => {\n return (\n <div className=\"w-full\">\n <ShikiCodeBlock code={code} lang=\"tsx\" className=\"h-fit\" />\n </div>\n );\n};\n"
1208
+ }
1209
+ ],
1210
+ "sourceFiles": {
1211
+ "utils/highlight.tsx": "import { codeToHast } from \"shiki/bundle/web\";\nimport { Fragment } from \"react\";\nimport { jsx, jsxs } from \"react/jsx-runtime\";\nimport { toJsxRuntime } from \"hast-util-to-jsx-runtime\";\nimport type { JSX } from \"react\";\nimport type { BundledLanguage } from \"shiki/bundle/web\";\nimport { cn } from \"@rlx-widgets/base\";\n\nexport async function highlight({\n code,\n lang,\n className,\n}: {\n code: string;\n lang: BundledLanguage;\n className?: string;\n}) {\n const out = await codeToHast(code, {\n lang,\n theme: \"ayu-dark\",\n });\n\n return toJsxRuntime(out, {\n Fragment,\n jsx,\n jsxs,\n components: {\n pre: (props) => (\n <pre\n {...props}\n className={cn(\"rounded p-4 overflow-x-auto\", className)}\n />\n ),\n },\n }) as JSX.Element;\n}\n"
1212
+ }
1213
+ },
1214
+ {
1215
+ "name": "Stacked Cards",
1216
+ "slug": "stacked-cards",
1217
+ "category": "component",
1218
+ "sourceCode": "\"use client\";\n\nimport { cn } from \"@rlx-widgets/base\";\nimport StackedCard from \"./StackedCard\";\nimport { Code } from \"lucide-react\";\nimport {\n MouseEventHandler,\n ReactNode,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { parseTranslate } from \"../../utils\";\n\nconst DEFAULT_TRANSFORM = \"rotateX(60deg) rotateY(0deg) rotateZ(-30deg)\";\nconst HOVERED_TRANSFORM = \"rotateX(0deg) rotateY(0deg) rotateZ(0deg)\";\n\nconst HOVERED_TRANSLATE = \"calc(-50% - 20px) 0px 50px\";\nconst getDefaultTranslate = (index: number) => {\n return `-50% ${index * 4}px -200px`;\n};\n\nconst parseRotationValues = (transform: string): [number, number, number] => {\n const xMatch = transform.match(/rotateX\\(([-\\d.]+)deg\\)/);\n const yMatch = transform.match(/rotateY\\(([-\\d.]+)deg\\)/);\n const zMatch = transform.match(/rotateZ\\(([-\\d.]+)deg\\)/);\n\n return [\n xMatch ? parseFloat(xMatch[1]) : 0,\n yMatch ? parseFloat(yMatch[1]) : 0,\n zMatch ? parseFloat(zMatch[1]) : 0,\n ];\n};\n\nconst mDown = (translate: string, distance: number) => {\n const { x, y: _y, z } = parseTranslate(translate);\n const y = _y.replace(\"px\", \"\");\n\n return `${x} ${+y + distance}px ${z}`;\n};\n\nconst rX = (transform: string, angle: number) => {\n const [x, y, z] = parseRotationValues(transform);\n return `rotateX(${x + angle}deg) rotateY(${y}deg) rotateZ(${z}deg)`;\n};\n\nexport const StackedCards = ({\n items: _items,\n onAnimationEnd,\n classNames: _classNames,\n}: {\n items: Array<{\n id?: string;\n icon: ReactNode;\n text: string;\n }>;\n onAnimationEnd?: (id: string) => void;\n classNames?: {\n root?: string;\n card?: string;\n };\n}) => {\n const [items, setItems] = useState(_items);\n const [isHovered, setIsHovered] = useState(false);\n const [isHoveredOnCard, setIsHoveredOnCard] = useState(false);\n const [isAnimating, setIsAnimating] = useState(false);\n const cardRefs = useRef<Array<HTMLDivElement | null>>([]);\n\n const handleClick: MouseEventHandler<HTMLDivElement> = async (e) => {\n e.stopPropagation();\n const $card = cardRefs.current[0];\n if (!$card) {\n return;\n }\n const cardId = $card.getAttribute(\"data-id\") || \"\";\n if (isAnimating) {\n $card.getAnimations().forEach((animation) => animation.finish());\n onAnimationEnd?.(cardId);\n } else {\n setIsAnimating(true);\n const animation = await $card.animate(\n [\n {\n translate: $card.style.translate,\n transform: $card.style.transform,\n },\n {\n translate: mDown($card.style.translate, 100),\n },\n {\n translate: mDown(mDown($card.style.translate, 100), 50),\n transform: rX($card.style.transform, 80),\n },\n {\n translate: getDefaultTranslate(items.length),\n transform: DEFAULT_TRANSFORM,\n },\n ],\n { duration: 1100, easing: \"ease-out\", fill: \"both\" }\n ).finished;\n onAnimationEnd?.(cardId);\n\n animation.commitStyles();\n animation.cancel();\n }\n\n cardRefs.current = [...cardRefs.current.slice(1), cardRefs.current[0]];\n setItems([...items.slice(1), items[0]]);\n setIsAnimating(false);\n };\n\n useLayoutEffect(() => {\n cardRefs.current.forEach((card, index) => {\n if (card) {\n card.style.transform = DEFAULT_TRANSFORM;\n card.style.translate = getDefaultTranslate(index);\n }\n });\n\n setItems((prev) => [...prev].reverse());\n }, []);\n\n const isAnimatingRef = useRef(isAnimating);\n const isHoveredRef = useRef(isHovered);\n const isHoveredOnCardRef = useRef(isHoveredOnCard);\n useEffect(() => {\n isHoveredRef.current = isHovered;\n isHoveredOnCardRef.current = isHoveredOnCard;\n\n if (isAnimating) {\n isAnimatingRef.current = isAnimating;\n return;\n }\n\n if (isAnimatingRef.current !== isAnimating) {\n isAnimatingRef.current = isAnimating;\n return;\n }\n\n if (cardRefs.current?.[0]) {\n if (isHovered || isHoveredOnCard) {\n cardRefs.current[0].style.transform = HOVERED_TRANSFORM;\n cardRefs.current[0].style.translate = HOVERED_TRANSLATE;\n } else {\n cardRefs.current[0].style.transform = DEFAULT_TRANSFORM;\n cardRefs.current[0].style.translate = getDefaultTranslate(0);\n }\n }\n }, [isHovered, isHoveredOnCard, isAnimating]);\n\n useEffect(() => {\n cardRefs.current.forEach((card, index) => {\n if (!card) {\n return;\n }\n if (index === 0 && (isHoveredRef.current || isHoveredOnCardRef.current)) {\n card.style.transform = HOVERED_TRANSFORM;\n card.style.translate = HOVERED_TRANSLATE;\n return;\n }\n card.style.transform = DEFAULT_TRANSFORM;\n card.style.translate = getDefaultTranslate(index);\n });\n }, [items]);\n\n return (\n <div\n className={cn(\"transform-3d hover:cursor-pointer\", _classNames?.root)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n onClick={handleClick}\n >\n {items.map((item, index) => (\n <StackedCard\n ref={(el) => {\n cardRefs.current[index] = el;\n }}\n key={item.id || item.text}\n className={cn(\"absolute select-none left-1/2\", _classNames?.card)}\n onMouseEnter={() => {\n if (index === 0) {\n setIsHoveredOnCard(true);\n }\n }}\n onMouseLeave={() => {\n if (index === 0) {\n setIsHoveredOnCard(false);\n }\n }}\n onClick={handleClick}\n data-id={item.id || item.text}\n style={{\n transform: `translateX(-50%)`, // To ensure the card is centered as soon as it is rendered\n }}\n >\n {item.icon || <Code className=\"size-8 text-primary\" />}\n <p className=\"text-2xl text-center\">{item.text}</p>\n </StackedCard>\n ))}\n </div>\n );\n};\n\nexport default StackedCards;\n",
1219
+ "demos": [
1220
+ {
1221
+ "name": "default",
1222
+ "code": "\"use client\";\n\nimport { StackedCards } from \"@rlx-components/stacked-cards\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { ReactNode } from \"react\";\nimport { RiTailwindCssFill } from \"react-icons/ri\";\nimport { SiRedux, SiShadcnui } from \"react-icons/si\";\n\nexport const Preview = () => {\n return (\n <div className=\"h-1/2\">\n <StackedCards\n items={items}\n classNames={{\n card: \"bg-secondary\",\n }}\n />\n </div>\n );\n};\n\nconst Icon = ({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) => {\n return (\n <div\n className={cn(\n \"bg-primary/10 rounded-full w-14 h-14 flex items-center justify-center mx-auto\",\n className\n )}\n >\n {children}\n </div>\n );\n};\n\nconst items: Array<{\n icon: ReactNode;\n text: string;\n}> = [\n {\n icon: (\n <Icon className=\"bg-[#030712]\">\n <RiTailwindCssFill className=\"size-8 text-[#00BCFF]\" />\n </Icon>\n ),\n text: \"Tailwind CSS\",\n },\n {\n icon: (\n <Icon className=\"bg-[#764abc]\">\n <SiRedux className=\"size-8 text-[white]\" />\n </Icon>\n ),\n text: \"Redux Toolkit\",\n },\n {\n icon: (\n <Icon className=\"bg-[black]\">\n <SiShadcnui className=\"size-8 text-white\" />\n </Icon>\n ),\n text: \"Shadcn UI\",\n },\n].reverse();\n"
1223
+ },
1224
+ {
1225
+ "name": "on-animation-end",
1226
+ "code": "\"use client\";\n\nimport { StackedCards } from \"@rlx-components/stacked-cards\";\nimport { cn } from \"@rlx-widgets/base\";\nimport { ReactNode, useState } from \"react\";\nimport { RiTailwindCssFill } from \"react-icons/ri\";\nimport { SiRedux, SiShadcnui } from \"react-icons/si\";\n\nexport const Preview = () => {\n const [flippedCards, setFlippedCards] = useState<Array<string>>([]);\n\n const handleAnimationEnd = (id: string) => {\n setFlippedCards((prev) => Array.from(new Set([...prev, id])));\n };\n return (\n <div className=\"h-1/2\">\n <StackedCards\n items={items}\n classNames={{\n card: \"bg-secondary\",\n }}\n onAnimationEnd={handleAnimationEnd}\n />\n <div className=\"absolute bottom-[5%] left-1/2 -translate-x-1/2 flex flex-wrap gap-2\">\n {flippedCards.map((text) => (\n <div key={text} className=\"bg-secondary p-2 rounded-md\">\n {text}\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nconst Icon = ({\n children,\n className,\n}: {\n children: React.ReactNode;\n className?: string;\n}) => {\n return (\n <div\n className={cn(\n \"bg-primary/10 rounded-full w-14 h-14 flex items-center justify-center mx-auto\",\n className\n )}\n >\n {children}\n </div>\n );\n};\n\nconst items: Array<{\n icon: ReactNode;\n text: string;\n}> = [\n {\n icon: (\n <Icon className=\"bg-[#030712]\">\n <RiTailwindCssFill className=\"size-8 text-[#00BCFF]\" />\n </Icon>\n ),\n text: \"Tailwind CSS\",\n },\n {\n icon: (\n <Icon className=\"bg-[#764abc]\">\n <SiRedux className=\"size-8 text-[white]\" />\n </Icon>\n ),\n text: \"Redux Toolkit\",\n },\n {\n icon: (\n <Icon className=\"bg-[black]\">\n <SiShadcnui className=\"size-8 text-white\" />\n </Icon>\n ),\n text: \"Shadcn UI\",\n },\n].reverse();\n"
1227
+ }
1228
+ ],
1229
+ "sourceFiles": {
1230
+ "StackedCard.tsx": "import { cn } from \"@rlx-widgets/base\";\nimport { Card } from \"@rlx-widgets/card\";\nimport { forwardRef, MouseEventHandler } from \"react\";\n\nconst boxShadow =\n\t\"[box-shadow:0px_5px_10px_0px_#22215140,1px_1px_1px_1px_#75757526]\";\n\ntype StackedCardProps = {\n\tchildren: React.ReactNode;\n\tclassName?: string;\n\tstyle?: React.CSSProperties;\n\tonMouseEnter?: () => void;\n\tonMouseLeave?: () => void;\n\tonClick?: MouseEventHandler<HTMLDivElement> | undefined;\n};\n\nexport const StackedCard = forwardRef<HTMLDivElement, StackedCardProps>(\n\t({ children, className, style, ...props }, ref) => {\n\t\treturn (\n\t\t\t<Card\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"transition-transform duration-200 ease-in-out\",\n\t\t\t\t\t\"h-[175px] w-[260px]\",\n\t\t\t\t\t\"inline-flex gap-4\",\n\t\t\t\t\tboxShadow,\n\t\t\t\t\t\"border-0\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tstyle={style}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Card>\n\t\t);\n\t}\n);\n\nStackedCard.displayName = \"StackedCard\";\n\nexport default StackedCard;\n"
1231
+ }
1232
+ },
1233
+ {
1234
+ "name": "Theme Toggle",
1235
+ "slug": "theme-toggle",
1236
+ "category": "component",
1237
+ "sourceCode": "\"use client\";\n\nimport { Button } from \"@rlx-widgets/button\";\nimport { Moon, Sun } from \"lucide-react\";\nimport { useTheme } from \"@rlx-widgets/base\";\n\nexport const ThemeToggle = () => {\n const { setTheme, theme } = useTheme();\n\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTheme(theme === \"light\" ? \"dark\" : \"light\")}\n >\n <Sun className=\"h-6 w-[1.3rem] dark:hidden\" />\n <Moon className=\"hidden h-5 w-5 dark:block\" />\n <span className=\"sr-only\">Toggle theme</span>\n </Button>\n );\n};\n",
1238
+ "demos": [
1239
+ {
1240
+ "name": "default",
1241
+ "code": "\"use client\";\n\nimport { ThemeToggle } from \"@rlx-components/theme-toggle\";\n\nexport const Preview = () => {\n return <ThemeToggle />;\n};\n"
1242
+ }
1243
+ ]
1244
+ },
1245
+ {
1246
+ "name": "Timeline",
1247
+ "slug": "timeline",
1248
+ "category": "component",
1249
+ "sourceCode": "import { cn } from \"@rlx-widgets/base\";\nimport { StatusIndicator } from \"./components\";\nimport { TimelineProps } from \"./types\";\n\nconst Timeline = ({\n items,\n orientation = \"vertical\",\n className,\n connectorColor = \"bg-border\",\n connectorVerticalPosition = \"center\",\n}: TimelineProps) => {\n if (orientation === \"horizontal\") {\n return (\n <div className={cn(\"overflow-x-auto\", className)}>\n <div className=\"inline-flex items-center gap-4 pb-4 relative\">\n <div\n className={cn(\"absolute top-0 left-0 h-px right-0\", connectorColor)}\n />\n {items.map((item, index) => (\n <div key={index} className=\"relative\">\n <div className=\"absolute top-0 left-1/2 -translate-x-1/2\">\n <StatusIndicator statusColor={item.statusColor} />\n </div>\n {item.content}\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n if (connectorVerticalPosition === \"left\") {\n return (\n <div className={cn(\"overflow-y-auto\", className)}>\n <div className=\"space-y-6 relative\">\n {items.map((item, index) => {\n return (\n <div key={index} className={cn(\"grid grid-cols-[auto_1fr]\")}>\n <StatusIndicator statusColor={item.statusColor} />\n <div className={cn(\"mb-6 ml-6\")}>{item.content}</div>\n </div>\n );\n })}\n <div\n className={cn(\n \"absolute left-1 top-0 bottom-0 w-px\",\n connectorColor\n )}\n />\n </div>\n </div>\n );\n }\n\n if (connectorVerticalPosition === \"right\") {\n return (\n <div className={cn(\"overflow-y-auto\", className)}>\n <div className=\"space-y-6 relative\">\n {items.map((item, index) => {\n return (\n <div key={index} className={cn(\"grid grid-cols-[1fr_auto]\")}>\n <div className={cn(\"mb-6 mr-6\")}>{item.content}</div>\n <StatusIndicator statusColor={item.statusColor} />\n </div>\n );\n })}\n <div\n className={cn(\n \"absolute right-1 top-0 bottom-0 w-px\",\n connectorColor\n )}\n />\n </div>\n </div>\n );\n }\n\n /**\n * connectorVerticalPosition === \"center\"\n * orientation === \"vertical\"\n */\n return (\n <div className={cn(\"overflow-y-auto\", className)}>\n <div className=\"space-y-6 relative\">\n {items.map((item, index) => {\n const isLeft = item.position === \"left\";\n\n return (\n <div key={index} className=\"grid grid-cols-[1fr_auto_1fr]\">\n {isLeft ? (\n <>\n <div className=\"mb-6 mr-6\">{item.content}</div>\n <StatusIndicator statusColor={item.statusColor} />\n <div></div>\n </>\n ) : (\n <>\n <div></div>\n <StatusIndicator statusColor={item.statusColor} />\n <div className=\"mb-6 ml-6\">{item.content}</div>\n </>\n )}\n </div>\n );\n })}\n <div\n className={cn(\n \"absolute left-1/2 top-0 bottom-0 w-px -translate-x-1/2\",\n connectorColor\n )}\n />\n </div>\n </div>\n );\n};\n\nexport { Timeline };\n",
1250
+ "demos": [
1251
+ {
1252
+ "name": "horizontal",
1253
+ "code": "\"use client\";\n\nimport { Timeline, TimelineItem } from \"@rlx-components/timeline\";\nimport { Badge } from \"@rlx-widgets/badge\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@rlx-widgets/card\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full\">\n <Timeline items={horizontalItems} orientation=\"horizontal\" />\n </div>\n );\n};\n\nconst horizontalItems: Array<TimelineItem> = [\n {\n content: (\n <Card className=\"w-full h-[150px] mt-5 min-w-[200px]\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n\n <CardContent className=\"pt-0\">\n <p className=\"text-xs text-muted-foreground\">Initial setup</p>\n </CardContent>\n </Card>\n ),\n statusColor: \"bg-red-500\",\n },\n {\n content: (\n <Card className=\"w-full h-[150px] mt-5 min-w-[200px]\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-yellow-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full h-[150px] mt-5 min-w-[200px]\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-green-500\",\n },\n {\n content: (\n <Card className=\"w-full h-[150px] mt-5 min-w-[200px]\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-blue-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full h-[150px] mt-5 min-w-[200px]\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-purple-500\",\n },\n];\n"
1254
+ },
1255
+ {
1256
+ "name": "vertical",
1257
+ "code": "\"use client\";\n\nimport { Badge } from \"@rlx-widgets/badge\";\nimport { Timeline, TimelineItem } from \"@rlx-components/timeline\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@rlx-widgets/card\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full h-full\">\n <div className=\"h-full\">\n <Timeline\n items={verticalItems}\n orientation=\"vertical\"\n className=\"h-full\"\n />\n </div>\n </div>\n );\n};\n\nconst verticalItems: TimelineItem[] = [\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n\n <CardContent className=\"pt-0\">\n <p className=\"text-xs text-muted-foreground\">Initial setup</p>\n </CardContent>\n </Card>\n ),\n statusColor: \"bg-red-500\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-yellow-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-green-500\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-blue-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-purple-500\",\n },\n];\n"
1258
+ },
1259
+ {
1260
+ "name": "vertical-left",
1261
+ "code": "\"use client\";\n\nimport { Badge } from \"@rlx-widgets/badge\";\nimport { Timeline, TimelineItem } from \"@rlx-components/timeline\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@rlx-widgets/card\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full h-full\">\n <div className=\"h-full\">\n <Timeline\n items={verticalItems}\n orientation=\"vertical\"\n className=\"h-full\"\n connectorVerticalPosition=\"left\"\n />\n </div>\n </div>\n );\n};\n\nconst verticalItems: TimelineItem[] = [\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n\n <CardContent className=\"pt-0\">\n <p className=\"text-xs text-muted-foreground\">Initial setup</p>\n </CardContent>\n </Card>\n ),\n statusColor: \"bg-red-500\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-yellow-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-green-500\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-blue-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-purple-500\",\n },\n];\n"
1262
+ },
1263
+ {
1264
+ "name": "vertical-right",
1265
+ "code": "\"use client\";\n\nimport { Badge } from \"@rlx-widgets/badge\";\nimport { Timeline, TimelineItem } from \"@rlx-components/timeline\";\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from \"@rlx-widgets/card\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full h-full\">\n <div className=\"h-full\">\n <Timeline\n items={verticalItems}\n orientation=\"vertical\"\n className=\"h-full\"\n connectorVerticalPosition=\"right\"\n />\n </div>\n </div>\n );\n};\n\nconst verticalItems: TimelineItem[] = [\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n\n <CardContent className=\"pt-0\">\n <p className=\"text-xs text-muted-foreground\">Initial setup</p>\n </CardContent>\n </Card>\n ),\n statusColor: \"bg-red-500\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-yellow-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-sm\">Project Started</CardTitle>\n <CardDescription className=\"text-xs\">Jan 2024</CardDescription>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-green-500\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-blue-500\",\n position: \"left\",\n },\n {\n content: (\n <Card className=\"w-full\">\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <CardTitle className=\"text-base\">Project Started</CardTitle>\n <CardDescription className=\"text-sm mt-1\">\n Jan 2024\n </CardDescription>\n </div>\n\n <Badge variant=\"default\">Completed</Badge>\n </div>\n </CardHeader>\n </Card>\n ),\n statusColor: \"bg-purple-500\",\n },\n];\n"
1266
+ }
1267
+ ],
1268
+ "sourceFiles": {
1269
+ "components/StatusIndicator.tsx": "import { cn } from \"@rlx-widgets/base\";\n\nconst DEFAULT_STATUS_COLOR = \"bg-blue-500\";\n\nexport const StatusIndicator = ({\n statusColor = DEFAULT_STATUS_COLOR,\n}: {\n statusColor?: string;\n}) => {\n return (\n <div\n className={cn(\n \"w-2 h-2 rounded-full z-10\",\n statusColor\n )}\n />\n );\n};\n",
1270
+ "types/TimelineItem.t.ts": "export type TimelineItem = {\n /**\n * The color of the status badge (Tailwind CSS class).\n * @default \"bg-blue-500\"\n */\n statusColor?: string;\n content: React.ReactNode;\n /**\n * @default \"right\"\n */\n position?: \"left\" | \"right\";\n};\n",
1271
+ "types/TimelineProps.t.ts": "import { TimelineItem } from \"./TimelineItem.t\";\n\nexport type TimelineProps = {\n items: Array<TimelineItem>;\n /**\n * @default \"vertical\"\n */\n orientation?: \"vertical\" | \"horizontal\";\n className?: string;\n /**\n * The color of the connector (Tailwind CSS class).\n *\n * @default \"bg-border\"\n */\n connectorColor?: string;\n connectorVerticalPosition?: \"left\" | \"center\" | \"right\";\n};\n"
1272
+ }
1273
+ },
1274
+ {
1275
+ "name": "Wave Text",
1276
+ "slug": "wave-text",
1277
+ "category": "component",
1278
+ "sourceCode": "export const WaveText = ({ children }: { children: string }) => {\n\tconst chars = children.split(\"\");\n\tconst waveSpeed = 0.15; // seconds between each letter starting the wave\n\tconst waveDuration = 0.6; // duration of each letter's wave motion\n\tconst pauseDuration = 1.5; // seconds pause after all letters finish\n\n\t// Count only non-space characters for timing calculations\n\tconst nonSpaceCount = chars.filter((char) => char !== \" \").length;\n\t// Total cycle: time for wave to pass through all letters + pause\n\tconst totalCycleDuration =\n\t\tnonSpaceCount * waveSpeed + waveDuration + pauseDuration;\n\n\t// Build individual keyframes for each letter (skip spaces)\n\tlet allKeyframes = \"\";\n\tlet nonSpaceIndex = 0; // Track which non-space character this is\n\n\tchars.forEach((char, index) => {\n\t\t// Skip creating keyframes for spaces\n\t\tif (char === \" \") return;\n\n\t\tconst animationName = `waveLetter${index}`;\n\t\t// Calculate when this letter's wave starts (staggered by waveSpeed)\n\t\tconst waveStart =\n\t\t\t((nonSpaceIndex * waveSpeed) / totalCycleDuration) * 100;\n\t\tconst wavePeak =\n\t\t\t((nonSpaceIndex * waveSpeed + waveDuration * 0.3) /\n\t\t\t\ttotalCycleDuration) *\n\t\t\t100;\n\t\tconst waveMid =\n\t\t\t((nonSpaceIndex * waveSpeed + waveDuration * 0.5) /\n\t\t\t\ttotalCycleDuration) *\n\t\t\t100;\n\t\tconst waveEnd =\n\t\t\t((nonSpaceIndex * waveSpeed + waveDuration) / totalCycleDuration) *\n\t\t\t100;\n\n\t\t// Create smooth arm wave motion - rise up and come back down\n\t\t// Alternate rotation for wave effect (left-right pattern)\n\t\tconst rotationAmount = nonSpaceIndex % 2 === 0 ? -12 : 12;\n\n\t\tallKeyframes += `@keyframes ${animationName} {\\n`;\n\t\tallKeyframes += ` 0% { transform: translateY(0) rotate(0deg); }\\n`;\n\t\tallKeyframes += ` ${waveStart.toFixed(\n\t\t\t2\n\t\t)}% { transform: translateY(0) rotate(0deg); }\\n`;\n\t\tallKeyframes += ` ${wavePeak.toFixed(\n\t\t\t2\n\t\t)}% { transform: translateY(-0.7em) rotate(${\n\t\t\trotationAmount * 0.7\n\t\t}deg); }\\n`;\n\t\tallKeyframes += ` ${waveMid.toFixed(\n\t\t\t2\n\t\t)}% { transform: translateY(-0.8em) rotate(${rotationAmount}deg); }\\n`;\n\t\tallKeyframes += ` ${waveEnd.toFixed(\n\t\t\t2\n\t\t)}% { transform: translateY(0) rotate(0deg); }\\n`;\n\t\tallKeyframes += ` 100% { transform: translateY(0) rotate(0deg); }\\n`;\n\t\tallKeyframes += `}\\n`;\n\n\t\tnonSpaceIndex++; // Increment for next non-space character\n\t});\n\n\treturn (\n\t\t<>\n\t\t\t<style>{allKeyframes}</style>\n\t\t\t<span className=\"inline-block\">\n\t\t\t\t{chars.map((char, index) => {\n\t\t\t\t\tconst isSpace = char === \" \";\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\tclassName=\"inline-block\"\n\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\tisSpace\n\t\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\tanimation: `waveLetter${index} ${totalCycleDuration}s ease-in-out infinite`,\n\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{isSpace ? \"\\u00A0\" : char}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</span>\n\t\t</>\n\t);\n};\n",
1279
+ "demos": [
1280
+ {
1281
+ "name": "default",
1282
+ "code": "\"use client\";\n\nimport { WaveText } from \"@rlx-components/wave-text\";\n\nexport const Preview = () => {\n return (\n <div className=\"w-full text-center\">\n <WaveText>Hello, world!</WaveText>\n </div>\n );\n};\n"
1283
+ }
1284
+ ]
1285
+ }
1286
+ ],
1287
+ "animates": [
1288
+ {
1289
+ "name": "Circular Swing",
1290
+ "slug": "circular-swing",
1291
+ "category": "animate",
1292
+ "demos": [
1293
+ {
1294
+ "name": "default",
1295
+ "code": "import { MessageCircleMore } from \"lucide-react\";\n\nexport const Preview = () => {\n return <MessageCircleMore className=\"animate-rlx-circular-swing\" />;\n};\n"
1296
+ }
1297
+ ]
1298
+ }
1299
+ ],
1300
+ "hooks": [
1301
+ {
1302
+ "name": "UseCopyToClipboard",
1303
+ "slug": "useCopyToClipboard",
1304
+ "category": "hook",
1305
+ "demos": [
1306
+ {
1307
+ "name": "default",
1308
+ "code": "\"use client\";\n\nimport { useCopyToClipboard } from \"@rlx-hooks/use-copy-to-clipboard\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { Check } from \"lucide-react\";\n\nexport const Preview = () => {\n const { isCopied, copyToClipboard } = useCopyToClipboard();\n\n return (\n <Button onClick={() => copyToClipboard(\"Hello World!\")} variant=\"outline\">\n {isCopied ? <Check className=\"w-4 h-4\" /> : \"Copy Text\"}\n </Button>\n );\n};\n"
1309
+ },
1310
+ {
1311
+ "name": "params",
1312
+ "code": "\"use client\";\n\nimport { useCopyToClipboard } from \"@rlx-hooks/use-copy-to-clipboard\";\nimport { Button } from \"@rlx-widgets/button\";\nimport { Check } from \"lucide-react\";\nimport { toast, Toaster } from \"sonner\";\nimport { useTheme } from \"@rlx-widgets/base\";\n\nexport const Preview = () => {\n const themeContext = useTheme();\n const theme = themeContext.theme;\n\n const handleCopy = () => {\n toast(\"Copied to clipboard\");\n };\n\n const { isCopied, copyToClipboard } = useCopyToClipboard({\n timeout: 2000,\n onCopy: handleCopy,\n });\n\n return (\n <div>\n <Toaster\n theme={theme}\n toastOptions={{\n style: {\n background: \"var(--color-muted)\",\n border: \"var(--color-border)\",\n },\n }}\n position=\"top-center\"\n />\n <Button onClick={() => copyToClipboard(\"Hello World!\")} variant=\"outline\">\n {isCopied ? <Check className=\"w-4 h-4\" /> : \"Copy Text\"}\n </Button>\n </div>\n );\n};\n"
1313
+ }
1314
+ ]
1315
+ },
1316
+ {
1317
+ "name": "UseIsMobile",
1318
+ "slug": "useIsMobile",
1319
+ "category": "hook",
1320
+ "demos": [
1321
+ {
1322
+ "name": "default",
1323
+ "code": "\"use client\";\n\nimport { useState, useEffect } from \"react\";\nimport { useIsMobile } from \"@rlx-hooks/use-is-mobile\";\n\nexport const Preview = () => {\n const isMobile = useIsMobile();\n const [windowWidth, setWindowWidth] = useState(0);\n\n useEffect(() => {\n setWindowWidth(window.innerWidth);\n const handleResize = () => {\n setWindowWidth(window.innerWidth);\n };\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }, []);\n\n return (\n <div>\n <div>Window width: {windowWidth}px</div>\n <div>Is mobile: {isMobile ? \"Yes\" : \"No\"}</div>\n </div>\n );\n};\n"
1324
+ }
1325
+ ]
1326
+ },
1327
+ {
1328
+ "name": "UseMediaQuery",
1329
+ "slug": "useMediaQuery",
1330
+ "category": "hook",
1331
+ "demos": [
1332
+ {
1333
+ "name": "default",
1334
+ "code": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { useMediaQuery } from \"@rlx-hooks/use-media-query\";\nimport { Badge } from \"@rlx-widgets/badge\";\n\nexport const Preview = () => {\n const [query, setQuery] = useState(\"(min-width: 768px)\");\n const isMatch = useMediaQuery(query);\n\n return (\n <div>\n <Input\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Enter media query\"\n />\n <div>\n Screen size matches:{\" \"}\n {isMatch ? (\n <Badge variant=\"default\">Yes</Badge>\n ) : (\n <Badge variant=\"destructive\">No</Badge>\n )}\n </div>\n </div>\n );\n};\n"
1335
+ }
1336
+ ]
1337
+ }
1338
+ ],
1339
+ "utils": [
1340
+ {
1341
+ "name": "IsValidDate",
1342
+ "slug": "isValidDate",
1343
+ "category": "util",
1344
+ "demos": [
1345
+ {
1346
+ "name": "default",
1347
+ "code": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Input } from \"@rlx-widgets/input\";\nimport { isValidDate } from \"@rlx-utils/is-valid-date\";\nimport { ShikiCodeBlock } from \"@rlx-components/shiki-code-block\";\nimport { InlineCode } from \"../../../../../../_components\";\nimport { ArrowRight } from \"lucide-react\";\n\nexport const Preview = () => {\n const [date, setDate] = useState<string>(\"2025-10-18\");\n const [isValid, setIsValid] = useState(false);\n\n useEffect(() => {\n setIsValid(isValidDate(new Date(date)));\n }, [date]);\n\n return (\n <div>\n <ShikiCodeBlock\n code={`isValidDate(new Date(\"${date}\"))`}\n lang=\"tsx\"\n className=\"h-fit\"\n />\n <Input\n type=\"text\"\n value={date}\n onChange={(e) => setDate(e.target.value)}\n className=\"mt-4\"\n />\n <p className=\"text-center mt-2\">\n {isValid ? \"Valid Date ✅\" : \"Invalid Date ❌\"}\n </p>\n {isValid && (\n <div className=\"flex items-center justify-center gap-2 mt-2\">\n <InlineCode>{`new Date(date).toLocaleDateString()`}</InlineCode>\n <ArrowRight className=\"w-4 h-4\" />\n <InlineCode>{new Date(date).toLocaleDateString()}</InlineCode>\n </div>\n )}\n </div>\n );\n};\n"
1348
+ }
1349
+ ]
1350
+ }
1351
+ ],
1352
+ "extractedAt": "2025-11-19T06:44:13.628Z"
1353
+ }