@djangocfg/ui-core 1.0.1

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.
Files changed (88) hide show
  1. package/README.md +135 -0
  2. package/package.json +111 -0
  3. package/src/components/accordion.tsx +56 -0
  4. package/src/components/alert-dialog.tsx +142 -0
  5. package/src/components/alert.tsx +59 -0
  6. package/src/components/aspect-ratio.tsx +7 -0
  7. package/src/components/avatar.tsx +50 -0
  8. package/src/components/badge.tsx +36 -0
  9. package/src/components/button-group.tsx +85 -0
  10. package/src/components/button.tsx +111 -0
  11. package/src/components/calendar.tsx +213 -0
  12. package/src/components/card.tsx +76 -0
  13. package/src/components/carousel.tsx +261 -0
  14. package/src/components/chart.tsx +369 -0
  15. package/src/components/checkbox.tsx +29 -0
  16. package/src/components/collapsible.tsx +11 -0
  17. package/src/components/combobox.tsx +182 -0
  18. package/src/components/command.tsx +170 -0
  19. package/src/components/context-menu.tsx +200 -0
  20. package/src/components/copy.tsx +144 -0
  21. package/src/components/dialog.tsx +122 -0
  22. package/src/components/drawer.tsx +137 -0
  23. package/src/components/empty.tsx +104 -0
  24. package/src/components/field.tsx +244 -0
  25. package/src/components/form.tsx +178 -0
  26. package/src/components/hover-card.tsx +29 -0
  27. package/src/components/image-with-fallback.tsx +170 -0
  28. package/src/components/index.ts +86 -0
  29. package/src/components/input-group.tsx +170 -0
  30. package/src/components/input-otp.tsx +81 -0
  31. package/src/components/input.tsx +22 -0
  32. package/src/components/item.tsx +195 -0
  33. package/src/components/kbd.tsx +28 -0
  34. package/src/components/label.tsx +26 -0
  35. package/src/components/multi-select.tsx +222 -0
  36. package/src/components/og-image.tsx +47 -0
  37. package/src/components/popover.tsx +33 -0
  38. package/src/components/portal.tsx +106 -0
  39. package/src/components/preloader.tsx +250 -0
  40. package/src/components/progress.tsx +28 -0
  41. package/src/components/radio-group.tsx +43 -0
  42. package/src/components/resizable.tsx +111 -0
  43. package/src/components/scroll-area.tsx +102 -0
  44. package/src/components/section.tsx +58 -0
  45. package/src/components/select.tsx +158 -0
  46. package/src/components/separator.tsx +31 -0
  47. package/src/components/sheet.tsx +140 -0
  48. package/src/components/skeleton.tsx +15 -0
  49. package/src/components/slider.tsx +28 -0
  50. package/src/components/spinner.tsx +16 -0
  51. package/src/components/sticky.tsx +117 -0
  52. package/src/components/switch.tsx +29 -0
  53. package/src/components/table.tsx +120 -0
  54. package/src/components/tabs.tsx +238 -0
  55. package/src/components/textarea.tsx +22 -0
  56. package/src/components/toast.tsx +129 -0
  57. package/src/components/toaster.tsx +41 -0
  58. package/src/components/toggle-group.tsx +61 -0
  59. package/src/components/toggle.tsx +45 -0
  60. package/src/components/token-icon.tsx +156 -0
  61. package/src/components/tooltip-provider-safe.tsx +43 -0
  62. package/src/components/tooltip.tsx +32 -0
  63. package/src/hooks/index.ts +15 -0
  64. package/src/hooks/useCopy.ts +41 -0
  65. package/src/hooks/useCountdown.ts +73 -0
  66. package/src/hooks/useDebounce.ts +25 -0
  67. package/src/hooks/useDebouncedCallback.ts +58 -0
  68. package/src/hooks/useDebugTools.ts +52 -0
  69. package/src/hooks/useEventsBus.ts +53 -0
  70. package/src/hooks/useImageLoader.ts +95 -0
  71. package/src/hooks/useMediaQuery.ts +40 -0
  72. package/src/hooks/useMobile.tsx +22 -0
  73. package/src/hooks/useToast.ts +194 -0
  74. package/src/index.ts +14 -0
  75. package/src/lib/index.ts +2 -0
  76. package/src/lib/og-image.ts +151 -0
  77. package/src/lib/utils.ts +6 -0
  78. package/src/styles/base.css +20 -0
  79. package/src/styles/globals.css +12 -0
  80. package/src/styles/index.css +25 -0
  81. package/src/styles/sources.css +11 -0
  82. package/src/styles/theme/animations.css +65 -0
  83. package/src/styles/theme/dark.css +49 -0
  84. package/src/styles/theme/light.css +50 -0
  85. package/src/styles/theme/tokens.css +134 -0
  86. package/src/styles/theme.css +22 -0
  87. package/src/styles/utilities.css +187 -0
  88. package/src/types/index.ts +0 -0
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # @djangocfg/ui-core
2
+
3
+ Pure React UI library with 60+ components built on Radix UI + Tailwind CSS v4.
4
+
5
+ **No Next.js dependencies** — works with Electron, Vite, CRA, and any React environment.
6
+
7
+ **Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @djangocfg/ui-core
13
+ ```
14
+
15
+ ## Why ui-core?
16
+
17
+ | Package | Use Case |
18
+ |---------|----------|
19
+ | `@djangocfg/ui-core` | Electron, Vite, CRA, any React app |
20
+ | `@djangocfg/ui-nextjs` | Next.js apps (extends ui-core) |
21
+
22
+ ## Components (61)
23
+
24
+ ### Forms (16)
25
+ `Label` `Button` `ButtonLink` `Input` `Checkbox` `RadioGroup` `Select` `Textarea` `Switch` `Slider` `Combobox` `MultiSelect` `InputOTP` `PhoneInput` `Form` `Field`
26
+
27
+ ### Layout (8)
28
+ `Card` `Separator` `Skeleton` `AspectRatio` `Sticky` `ScrollArea` `Resizable` `Section`
29
+
30
+ ### Overlay (7)
31
+ `Dialog` `AlertDialog` `Sheet` `Drawer` `Popover` `HoverCard` `Tooltip`
32
+
33
+ ### Feedback (6)
34
+ `Toast` `Toaster` `Alert` `Progress` `Badge` `Avatar`
35
+
36
+ ### Data (8)
37
+ `Table` `Tabs` `Accordion` `Collapsible` `Toggle` `ToggleGroup` `Calendar` `Carousel`
38
+
39
+ ### Interactive (3)
40
+ `Command` `ContextMenu` `Chart`
41
+
42
+ ### Specialized (13)
43
+ `ButtonGroup` `Empty` `Spinner` `Preloader` `Kbd` `TokenIcon` `InputGroup` `Item` `ImageWithFallback` `OgImage` `CopyButton` `CopyField` `StaticPagination`
44
+
45
+ ## Hooks (10)
46
+
47
+ | Hook | Description |
48
+ |------|-------------|
49
+ | `useMediaQuery` | Responsive breakpoints |
50
+ | `useIsMobile` | Mobile detection |
51
+ | `useCopy` | Copy to clipboard |
52
+ | `useCountdown` | Countdown timer |
53
+ | `useDebounce` | Debounce values |
54
+ | `useDebouncedCallback` | Debounced callbacks |
55
+ | `useImageLoader` | Image loading state |
56
+ | `useToast` | Toast notifications |
57
+ | `useEventListener` | Event bus |
58
+ | `useDebugTools` | Debug utilities |
59
+
60
+ ## Usage
61
+
62
+ ```tsx
63
+ import { Button, Card, Input, useToast } from '@djangocfg/ui-core';
64
+
65
+ function Example() {
66
+ const { toast } = useToast();
67
+
68
+ return (
69
+ <Card>
70
+ <Input placeholder="Email" />
71
+ <Button onClick={() => toast({ title: 'Saved!' })}>
72
+ Submit
73
+ </Button>
74
+ </Card>
75
+ );
76
+ }
77
+ ```
78
+
79
+ ## Electron Usage
80
+
81
+ ```tsx
82
+ // In Electron renderer process
83
+ import { Button, Dialog, useMediaQuery } from '@djangocfg/ui-core';
84
+ import '@djangocfg/ui-core/styles/globals';
85
+
86
+ function App() {
87
+ const isMobile = useMediaQuery('(max-width: 768px)');
88
+
89
+ return (
90
+ <Dialog>
91
+ <Button>Open Dialog</Button>
92
+ </Dialog>
93
+ );
94
+ }
95
+ ```
96
+
97
+ ## Styling
98
+
99
+ ```tsx
100
+ // Import global styles
101
+ import '@djangocfg/ui-core/styles/globals';
102
+ ```
103
+
104
+ ## Exports
105
+
106
+ | Path | Content |
107
+ |------|---------|
108
+ | `@djangocfg/ui-core` | All components & hooks |
109
+ | `@djangocfg/ui-core/components` | Components only |
110
+ | `@djangocfg/ui-core/hooks` | Hooks only |
111
+ | `@djangocfg/ui-core/lib` | Utilities (cn, etc.) |
112
+ | `@djangocfg/ui-core/styles` | CSS |
113
+
114
+ ## What's NOT included (use ui-nextjs)
115
+
116
+ These features require Next.js or browser storage APIs:
117
+
118
+ - `Sidebar` — uses next/link
119
+ - `Breadcrumb`, `BreadcrumbNavigation` — uses next/link
120
+ - `NavigationMenu`, `Menubar` — uses next/link
121
+ - `Pagination`, `SSRPagination` — uses next/link
122
+ - `DropdownMenu` — uses next/link
123
+ - `DownloadButton` — uses localStorage
124
+ - `useLocalStorage`, `useSessionStorage` — browser storage
125
+ - `useTheme` — uses next-themes
126
+ - `useQueryParams`, `useCfgRouter` — uses next/router
127
+
128
+ ## Requirements
129
+
130
+ - React >= 18 or >= 19
131
+ - Tailwind CSS >= 4
132
+
133
+ ---
134
+
135
+ **[Full documentation & examples](https://djangocfg.com/demo/ui/)**
package/package.json ADDED
@@ -0,0 +1,111 @@
1
+ {
2
+ "name": "@djangocfg/ui-core",
3
+ "version": "1.0.1",
4
+ "description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
5
+ "keywords": [
6
+ "ui-components",
7
+ "react",
8
+ "radix-ui",
9
+ "tailwindcss",
10
+ "design-system",
11
+ "component-library",
12
+ "typescript",
13
+ "electron",
14
+ "vite"
15
+ ],
16
+ "author": {
17
+ "name": "DjangoCFG",
18
+ "url": "https://djangocfg.com"
19
+ },
20
+ "homepage": "https://djangocfg.com",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/markolofsen/django-cfg.git",
24
+ "directory": "packages/ui-core"
25
+ },
26
+ "license": "MIT",
27
+ "main": "./src/index.ts",
28
+ "types": "./src/index.ts",
29
+ "exports": {
30
+ ".": "./src/index.ts",
31
+ "./components": "./src/components/index.ts",
32
+ "./hooks": "./src/hooks/index.ts",
33
+ "./lib": "./src/lib/index.ts",
34
+ "./styles": "./src/styles/index.css",
35
+ "./styles/globals": "./src/styles/globals.css",
36
+ "./styles/theme": "./src/styles/theme.css",
37
+ "./styles/base": "./src/styles/base.css",
38
+ "./styles/utilities": "./src/styles/utilities.css"
39
+ },
40
+ "files": [
41
+ "src",
42
+ "README.md",
43
+ "LICENSE"
44
+ ],
45
+ "scripts": {
46
+ "lint": "eslint .",
47
+ "check": "tsc --noEmit"
48
+ },
49
+ "peerDependencies": {
50
+ "lucide-react": "^0.545.0",
51
+ "moment": "^2.30.1",
52
+ "react": "^18.0.0 || ^19.0.0",
53
+ "react-dom": "^18.0.0 || ^19.0.0",
54
+ "react-hook-form": "^7.0.0",
55
+ "tailwindcss": "^4.0.0",
56
+ "zod": "^4.0.0"
57
+ },
58
+ "dependencies": {
59
+ "@hookform/resolvers": "^5.2.2",
60
+ "@radix-ui/react-accordion": "^1.2.12",
61
+ "@radix-ui/react-alert-dialog": "^1.1.15",
62
+ "@radix-ui/react-aspect-ratio": "^1.1.7",
63
+ "@radix-ui/react-avatar": "^1.1.10",
64
+ "@radix-ui/react-checkbox": "^1.3.3",
65
+ "@radix-ui/react-collapsible": "^1.1.12",
66
+ "@radix-ui/react-context-menu": "^2.2.16",
67
+ "@radix-ui/react-dialog": "^1.1.15",
68
+ "@radix-ui/react-hover-card": "^1.1.15",
69
+ "@radix-ui/react-icons": "^1.3.2",
70
+ "@radix-ui/react-label": "^2.1.7",
71
+ "@radix-ui/react-popover": "^1.1.15",
72
+ "@radix-ui/react-progress": "^1.1.7",
73
+ "@radix-ui/react-radio-group": "^1.3.8",
74
+ "@radix-ui/react-scroll-area": "^1.2.10",
75
+ "@radix-ui/react-select": "^2.2.6",
76
+ "@radix-ui/react-separator": "^1.1.7",
77
+ "@radix-ui/react-slider": "^1.3.6",
78
+ "@radix-ui/react-slot": "^1.2.4",
79
+ "@radix-ui/react-switch": "^1.2.6",
80
+ "@radix-ui/react-tabs": "^1.1.13",
81
+ "@radix-ui/react-toast": "^1.2.15",
82
+ "@radix-ui/react-toggle": "^1.1.10",
83
+ "@radix-ui/react-toggle-group": "^1.1.11",
84
+ "@radix-ui/react-tooltip": "^1.2.8",
85
+ "class-variance-authority": "^0.7.1",
86
+ "clsx": "^2.1.1",
87
+ "cmdk": "1.1.1",
88
+ "date-fns": "^4.1.0",
89
+ "embla-carousel-react": "8.6.0",
90
+ "input-otp": "1.4.2",
91
+ "libphonenumber-js": "^1.12.24",
92
+ "react-day-picker": "9.11.1",
93
+ "react-resizable-panels": "3.0.6",
94
+ "react-sticky-box": "^2.0.5",
95
+ "recharts": "2.15.4",
96
+ "sonner": "2.0.7",
97
+ "tailwind-merge": "^3.3.1",
98
+ "vaul": "1.1.2",
99
+ "@web3icons/react": "^4.0.26"
100
+ },
101
+ "devDependencies": {
102
+ "@djangocfg/typescript-config": "^1.4.45",
103
+ "@types/node": "^24.7.2",
104
+ "@types/react": "19.2.2",
105
+ "@types/react-dom": "19.2.1",
106
+ "typescript": "^5.9.3"
107
+ },
108
+ "publishConfig": {
109
+ "access": "public"
110
+ }
111
+ }
@@ -0,0 +1,56 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AccordionPrimitive from "@radix-ui/react-accordion"
5
+ import { cn } from "../lib/utils"
6
+ import { ChevronDownIcon } from "@radix-ui/react-icons"
7
+
8
+ const Accordion = AccordionPrimitive.Root
9
+
10
+ const AccordionItem = React.forwardRef<
11
+ React.ElementRef<typeof AccordionPrimitive.Item>,
12
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> & { key?: React.Key }
13
+ >(({ className, ...props }, ref) => (
14
+ <AccordionPrimitive.Item
15
+ ref={ref}
16
+ className={cn("border-b", className)}
17
+ {...props}
18
+ />
19
+ ))
20
+ AccordionItem.displayName = "AccordionItem"
21
+
22
+ const AccordionTrigger = React.forwardRef<
23
+ React.ElementRef<typeof AccordionPrimitive.Trigger>,
24
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
25
+ >(({ className, children, ...props }, ref) => (
26
+ <AccordionPrimitive.Header className="flex">
27
+ <AccordionPrimitive.Trigger
28
+ ref={ref}
29
+ className={cn(
30
+ "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
31
+ className
32
+ )}
33
+ {...props}
34
+ >
35
+ {children}
36
+ <ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
37
+ </AccordionPrimitive.Trigger>
38
+ </AccordionPrimitive.Header>
39
+ ))
40
+ AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
41
+
42
+ const AccordionContent = React.forwardRef<
43
+ React.ElementRef<typeof AccordionPrimitive.Content>,
44
+ React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
45
+ >(({ className, children, ...props }, ref) => (
46
+ <AccordionPrimitive.Content
47
+ ref={ref}
48
+ className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
49
+ {...props}
50
+ >
51
+ <div className={cn("pb-4 pt-0", className)}>{children}</div>
52
+ </AccordionPrimitive.Content>
53
+ ))
54
+ AccordionContent.displayName = AccordionPrimitive.Content.displayName
55
+
56
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
@@ -0,0 +1,142 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
5
+
6
+ import { cn } from "../lib/utils"
7
+ import { buttonVariants } from "./button"
8
+
9
+ const AlertDialog = AlertDialogPrimitive.Root
10
+
11
+ const AlertDialogTrigger = AlertDialogPrimitive.Trigger
12
+
13
+ const AlertDialogPortal = AlertDialogPrimitive.Portal
14
+
15
+ const AlertDialogOverlay = React.forwardRef<
16
+ React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
17
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
18
+ >(({ className, style, ...props }, ref) => (
19
+ <AlertDialogPrimitive.Overlay
20
+ className={cn(
21
+ "fixed inset-0 z-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
22
+ className
23
+ )}
24
+ style={{ backgroundColor: 'rgb(0 0 0 / 0.8)', ...style }}
25
+ {...props}
26
+ ref={ref}
27
+ />
28
+ ))
29
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
30
+
31
+ const AlertDialogContent = React.forwardRef<
32
+ React.ElementRef<typeof AlertDialogPrimitive.Content>,
33
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
34
+ >(({ className, ...props }, ref) => (
35
+ <AlertDialogPortal>
36
+ <AlertDialogOverlay />
37
+ <AlertDialogPrimitive.Content
38
+ ref={ref}
39
+ className={cn(
40
+ "fixed left-1/2 top-1/2 z-200 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 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 sm:rounded-lg",
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ </AlertDialogPortal>
46
+ ))
47
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
48
+
49
+ const AlertDialogHeader = ({
50
+ className,
51
+ ...props
52
+ }: React.HTMLAttributes<HTMLDivElement>) => (
53
+ <div
54
+ className={cn(
55
+ "flex flex-col space-y-2 text-center sm:text-left",
56
+ className
57
+ )}
58
+ {...props}
59
+ />
60
+ )
61
+ AlertDialogHeader.displayName = "AlertDialogHeader"
62
+
63
+ const AlertDialogFooter = ({
64
+ className,
65
+ ...props
66
+ }: React.HTMLAttributes<HTMLDivElement>) => (
67
+ <div
68
+ className={cn(
69
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
70
+ className
71
+ )}
72
+ {...props}
73
+ />
74
+ )
75
+ AlertDialogFooter.displayName = "AlertDialogFooter"
76
+
77
+ const AlertDialogTitle = React.forwardRef<
78
+ React.ElementRef<typeof AlertDialogPrimitive.Title>,
79
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
80
+ >(({ className, ...props }, ref) => (
81
+ <AlertDialogPrimitive.Title
82
+ ref={ref}
83
+ className={cn("text-lg font-semibold", className)}
84
+ {...props}
85
+ />
86
+ ))
87
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
88
+
89
+ const AlertDialogDescription = React.forwardRef<
90
+ React.ElementRef<typeof AlertDialogPrimitive.Description>,
91
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
92
+ >(({ className, ...props }, ref) => (
93
+ <AlertDialogPrimitive.Description
94
+ ref={ref}
95
+ className={cn("text-sm text-muted-foreground", className)}
96
+ {...props}
97
+ />
98
+ ))
99
+ AlertDialogDescription.displayName =
100
+ AlertDialogPrimitive.Description.displayName
101
+
102
+ const AlertDialogAction = React.forwardRef<
103
+ React.ElementRef<typeof AlertDialogPrimitive.Action>,
104
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
105
+ >(({ className, ...props }, ref) => (
106
+ <AlertDialogPrimitive.Action
107
+ ref={ref}
108
+ className={cn(buttonVariants(), className)}
109
+ {...props}
110
+ />
111
+ ))
112
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
113
+
114
+ const AlertDialogCancel = React.forwardRef<
115
+ React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
116
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
117
+ >(({ className, ...props }, ref) => (
118
+ <AlertDialogPrimitive.Cancel
119
+ ref={ref}
120
+ className={cn(
121
+ buttonVariants({ variant: "outline" }),
122
+ "mt-2 sm:mt-0",
123
+ className
124
+ )}
125
+ {...props}
126
+ />
127
+ ))
128
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
129
+
130
+ export {
131
+ AlertDialog,
132
+ AlertDialogPortal,
133
+ AlertDialogOverlay,
134
+ AlertDialogTrigger,
135
+ AlertDialogContent,
136
+ AlertDialogHeader,
137
+ AlertDialogFooter,
138
+ AlertDialogTitle,
139
+ AlertDialogDescription,
140
+ AlertDialogAction,
141
+ AlertDialogCancel,
142
+ }
@@ -0,0 +1,59 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+
4
+ import { cn } from "../lib/utils"
5
+
6
+ const alertVariants = cva(
7
+ "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: "bg-background text-foreground",
12
+ destructive:
13
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: "default",
18
+ },
19
+ }
20
+ )
21
+
22
+ const Alert = React.forwardRef<
23
+ HTMLDivElement,
24
+ React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
25
+ >(({ className, variant, ...props }, ref) => (
26
+ <div
27
+ ref={ref}
28
+ role="alert"
29
+ className={cn(alertVariants({ variant }), className)}
30
+ {...props}
31
+ />
32
+ ))
33
+ Alert.displayName = "Alert"
34
+
35
+ const AlertTitle = React.forwardRef<
36
+ HTMLParagraphElement,
37
+ React.HTMLAttributes<HTMLHeadingElement>
38
+ >(({ className, ...props }, ref) => (
39
+ <h5
40
+ ref={ref}
41
+ className={cn("mb-1 font-medium leading-none tracking-tight", className)}
42
+ {...props}
43
+ />
44
+ ))
45
+ AlertTitle.displayName = "AlertTitle"
46
+
47
+ const AlertDescription = React.forwardRef<
48
+ HTMLParagraphElement,
49
+ React.HTMLAttributes<HTMLParagraphElement>
50
+ >(({ className, ...props }, ref) => (
51
+ <div
52
+ ref={ref}
53
+ className={cn("text-sm [&_p]:leading-relaxed", className)}
54
+ {...props}
55
+ />
56
+ ))
57
+ AlertDescription.displayName = "AlertDescription"
58
+
59
+ export { Alert, AlertTitle, AlertDescription }
@@ -0,0 +1,7 @@
1
+ "use client"
2
+
3
+ import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
4
+
5
+ const AspectRatio = AspectRatioPrimitive.Root
6
+
7
+ export { AspectRatio }
@@ -0,0 +1,50 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AvatarPrimitive from "@radix-ui/react-avatar"
5
+
6
+ import { cn } from "../lib/utils"
7
+
8
+ const Avatar = React.forwardRef<
9
+ React.ElementRef<typeof AvatarPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
11
+ >(({ className, ...props }, ref) => (
12
+ <AvatarPrimitive.Root
13
+ ref={ref}
14
+ className={cn(
15
+ "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ ))
21
+ Avatar.displayName = AvatarPrimitive.Root.displayName
22
+
23
+ const AvatarImage = React.forwardRef<
24
+ React.ElementRef<typeof AvatarPrimitive.Image>,
25
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
26
+ >(({ className, ...props }, ref) => (
27
+ <AvatarPrimitive.Image
28
+ ref={ref}
29
+ className={cn("aspect-square h-full w-full", className)}
30
+ {...props}
31
+ />
32
+ ))
33
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName
34
+
35
+ const AvatarFallback = React.forwardRef<
36
+ React.ElementRef<typeof AvatarPrimitive.Fallback>,
37
+ React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
38
+ >(({ className, ...props }, ref) => (
39
+ <AvatarPrimitive.Fallback
40
+ ref={ref}
41
+ className={cn(
42
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ ))
48
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
49
+
50
+ export { Avatar, AvatarImage, AvatarFallback }
@@ -0,0 +1,36 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+
4
+ import { cn } from "../lib/utils"
5
+
6
+ const badgeVariants = cva(
7
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
13
+ secondary:
14
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15
+ destructive:
16
+ "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
17
+ outline: "text-foreground",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "default",
22
+ },
23
+ }
24
+ )
25
+
26
+ export interface BadgeProps
27
+ extends React.HTMLAttributes<HTMLDivElement>,
28
+ VariantProps<typeof badgeVariants> {}
29
+
30
+ function Badge({ className, variant, ...props }: BadgeProps) {
31
+ return (
32
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
33
+ )
34
+ }
35
+
36
+ export { Badge, badgeVariants }
@@ -0,0 +1,85 @@
1
+ "use client"
2
+
3
+ import { Slot } from "@radix-ui/react-slot"
4
+ import { cva, type VariantProps } from "class-variance-authority"
5
+
6
+ import { cn } from "../lib/utils"
7
+ import { Separator } from "./separator"
8
+
9
+ const buttonGroupVariants = cva(
10
+ "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
11
+ {
12
+ variants: {
13
+ orientation: {
14
+ horizontal:
15
+ "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
16
+ vertical:
17
+ "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ orientation: "horizontal",
22
+ },
23
+ }
24
+ )
25
+
26
+ function ButtonGroup({
27
+ className,
28
+ orientation,
29
+ ...props
30
+ }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
31
+ return (
32
+ <div
33
+ role="group"
34
+ data-slot="button-group"
35
+ data-orientation={orientation}
36
+ className={cn(buttonGroupVariants({ orientation }), className)}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+
42
+ function ButtonGroupText({
43
+ className,
44
+ asChild = false,
45
+ ...props
46
+ }: React.ComponentProps<"div"> & {
47
+ asChild?: boolean
48
+ }) {
49
+ const Comp = asChild ? Slot : "div"
50
+
51
+ return (
52
+ <Comp
53
+ className={cn(
54
+ "bg-muted shadow-xs flex items-center gap-2 rounded-md border px-4 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
55
+ className
56
+ )}
57
+ {...props}
58
+ />
59
+ )
60
+ }
61
+
62
+ function ButtonGroupSeparator({
63
+ className,
64
+ orientation = "vertical",
65
+ ...props
66
+ }: React.ComponentProps<typeof Separator>) {
67
+ return (
68
+ <Separator
69
+ data-slot="button-group-separator"
70
+ orientation={orientation}
71
+ className={cn(
72
+ "bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto",
73
+ className
74
+ )}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ export {
81
+ ButtonGroup,
82
+ ButtonGroupSeparator,
83
+ ButtonGroupText,
84
+ buttonGroupVariants,
85
+ }