@c-rex/ui 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-rex/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src"
@@ -93,6 +93,34 @@
93
93
  "./pagination": {
94
94
  "types": "./src/pagination.tsx",
95
95
  "import": "./src/pagination.tsx"
96
+ },
97
+ "./radio-group": {
98
+ "types": "./src/radio-group.tsx",
99
+ "import": "./src/radio-group.tsx"
100
+ },
101
+ "./switch": {
102
+ "types": "./src/switch.tsx",
103
+ "import": "./src/switch.tsx"
104
+ },
105
+ "./toggle": {
106
+ "types": "./src/toggle.tsx",
107
+ "import": "./src/toggle.tsx"
108
+ },
109
+ "./toggle-group": {
110
+ "types": "./src/toggle-group.tsx",
111
+ "import": "./src/toggle-group.tsx"
112
+ },
113
+ "./tabs": {
114
+ "types": "./src/tabs.tsx",
115
+ "import": "./src/tabs.tsx"
116
+ },
117
+ "./context-menu": {
118
+ "types": "./src/context-menu.tsx",
119
+ "import": "./src/context-menu.tsx"
120
+ },
121
+ "./badge": {
122
+ "types": "./src/badge.tsx",
123
+ "import": "./src/badge.tsx"
96
124
  }
97
125
  },
98
126
  "scripts": {
@@ -114,13 +142,19 @@
114
142
  "@c-rex/utils": "*",
115
143
  "@radix-ui/react-avatar": "^1.1.9",
116
144
  "@radix-ui/react-checkbox": "^1.3.2",
145
+ "@radix-ui/react-context-menu": "^2.2.15",
117
146
  "@radix-ui/react-dialog": "^1.1.6",
118
147
  "@radix-ui/react-dropdown-menu": "^2.1.15",
119
148
  "@radix-ui/react-label": "^2.1.7",
120
149
  "@radix-ui/react-popover": "^1.1.6",
150
+ "@radix-ui/react-radio-group": "^1.3.7",
121
151
  "@radix-ui/react-select": "^2.1.6",
122
152
  "@radix-ui/react-separator": "^1.1.2",
123
153
  "@radix-ui/react-slot": "^1.2.3",
154
+ "@radix-ui/react-switch": "^1.2.5",
155
+ "@radix-ui/react-tabs": "^1.1.12",
156
+ "@radix-ui/react-toggle": "^1.1.9",
157
+ "@radix-ui/react-toggle-group": "^1.1.10",
124
158
  "@radix-ui/react-tooltip": "^1.1.8",
125
159
  "class-variance-authority": "^0.7.1",
126
160
  "clsx": "^2.1.1",
package/src/badge.tsx ADDED
@@ -0,0 +1,46 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@c-rex/utils"
6
+
7
+ const badgeVariants = cva(
8
+ "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",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
14
+ secondary:
15
+ "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
16
+ destructive:
17
+ "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",
18
+ outline:
19
+ "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ },
25
+ }
26
+ )
27
+
28
+ function Badge({
29
+ className,
30
+ variant,
31
+ asChild = false,
32
+ ...props
33
+ }: React.ComponentProps<"span"> &
34
+ VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35
+ const Comp = asChild ? Slot : "span"
36
+
37
+ return (
38
+ <Comp
39
+ data-slot="badge"
40
+ className={cn(badgeVariants({ variant }), className)}
41
+ {...props}
42
+ />
43
+ )
44
+ }
45
+
46
+ export { Badge, badgeVariants }
package/src/button.tsx CHANGED
@@ -12,7 +12,7 @@ const buttonVariants = cva(
12
12
  default:
13
13
  "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14
14
  destructive:
15
- "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
15
+ "border border-destructive text-destructive shadow-sm hover:bg-destructive/90 hover:text-destructive-foreground",
16
16
  outline:
17
17
  "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18
18
  secondary:
@@ -23,6 +23,7 @@ const buttonVariants = cva(
23
23
  size: {
24
24
  default: "h-9 px-4 py-2",
25
25
  sm: "h-8 rounded-md px-3 text-xs",
26
+ xs: "h-5 w-5 rounded text-xs",
26
27
  lg: "h-10 rounded-md px-8",
27
28
  icon: "h-9 w-9",
28
29
  },
@@ -0,0 +1,250 @@
1
+ import * as React from "react"
2
+ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
3
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
4
+
5
+ import { cn } from "@c-rex/utils"
6
+
7
+ function ContextMenu({
8
+ ...props
9
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
10
+ return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
11
+ }
12
+
13
+ function ContextMenuTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
16
+ return (
17
+ <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />
18
+ )
19
+ }
20
+
21
+ function ContextMenuGroup({
22
+ ...props
23
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
24
+ return (
25
+ <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
26
+ )
27
+ }
28
+
29
+ function ContextMenuPortal({
30
+ ...props
31
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
32
+ return (
33
+ <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
34
+ )
35
+ }
36
+
37
+ function ContextMenuSub({
38
+ ...props
39
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
40
+ return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />
41
+ }
42
+
43
+ function ContextMenuRadioGroup({
44
+ ...props
45
+ }: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
46
+ return (
47
+ <ContextMenuPrimitive.RadioGroup
48
+ data-slot="context-menu-radio-group"
49
+ {...props}
50
+ />
51
+ )
52
+ }
53
+
54
+ function ContextMenuSubTrigger({
55
+ className,
56
+ inset,
57
+ children,
58
+ ...props
59
+ }: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
60
+ inset?: boolean
61
+ }) {
62
+ return (
63
+ <ContextMenuPrimitive.SubTrigger
64
+ data-slot="context-menu-sub-trigger"
65
+ data-inset={inset}
66
+ className={cn(
67
+ "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",
68
+ className
69
+ )}
70
+ {...props}
71
+ >
72
+ {children}
73
+ <ChevronRightIcon className="ml-auto" />
74
+ </ContextMenuPrimitive.SubTrigger>
75
+ )
76
+ }
77
+
78
+ function ContextMenuSubContent({
79
+ className,
80
+ ...props
81
+ }: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
82
+ return (
83
+ <ContextMenuPrimitive.SubContent
84
+ data-slot="context-menu-sub-content"
85
+ className={cn(
86
+ "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",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ )
92
+ }
93
+
94
+ function ContextMenuContent({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
98
+ return (
99
+ <ContextMenuPrimitive.Portal>
100
+ <ContextMenuPrimitive.Content
101
+ data-slot="context-menu-content"
102
+ className={cn(
103
+ "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",
104
+ className
105
+ )}
106
+ {...props}
107
+ />
108
+ </ContextMenuPrimitive.Portal>
109
+ )
110
+ }
111
+
112
+ function ContextMenuItem({
113
+ className,
114
+ inset,
115
+ variant = "default",
116
+ ...props
117
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
118
+ inset?: boolean
119
+ variant?: "default" | "destructive"
120
+ }) {
121
+ return (
122
+ <ContextMenuPrimitive.Item
123
+ data-slot="context-menu-item"
124
+ data-inset={inset}
125
+ data-variant={variant}
126
+ className={cn(
127
+ "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",
128
+ className
129
+ )}
130
+ {...props}
131
+ />
132
+ )
133
+ }
134
+
135
+ function ContextMenuCheckboxItem({
136
+ className,
137
+ children,
138
+ checked,
139
+ ...props
140
+ }: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {
141
+ return (
142
+ <ContextMenuPrimitive.CheckboxItem
143
+ data-slot="context-menu-checkbox-item"
144
+ className={cn(
145
+ "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",
146
+ className
147
+ )}
148
+ checked={checked}
149
+ {...props}
150
+ >
151
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
152
+ <ContextMenuPrimitive.ItemIndicator>
153
+ <CheckIcon className="size-4" />
154
+ </ContextMenuPrimitive.ItemIndicator>
155
+ </span>
156
+ {children}
157
+ </ContextMenuPrimitive.CheckboxItem>
158
+ )
159
+ }
160
+
161
+ function ContextMenuRadioItem({
162
+ className,
163
+ children,
164
+ ...props
165
+ }: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {
166
+ return (
167
+ <ContextMenuPrimitive.RadioItem
168
+ data-slot="context-menu-radio-item"
169
+ className={cn(
170
+ "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",
171
+ className
172
+ )}
173
+ {...props}
174
+ >
175
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
176
+ <ContextMenuPrimitive.ItemIndicator>
177
+ <CircleIcon className="size-2 fill-current" />
178
+ </ContextMenuPrimitive.ItemIndicator>
179
+ </span>
180
+ {children}
181
+ </ContextMenuPrimitive.RadioItem>
182
+ )
183
+ }
184
+
185
+ function ContextMenuLabel({
186
+ className,
187
+ inset,
188
+ ...props
189
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
190
+ inset?: boolean
191
+ }) {
192
+ return (
193
+ <ContextMenuPrimitive.Label
194
+ data-slot="context-menu-label"
195
+ data-inset={inset}
196
+ className={cn(
197
+ "text-foreground px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
198
+ className
199
+ )}
200
+ {...props}
201
+ />
202
+ )
203
+ }
204
+
205
+ function ContextMenuSeparator({
206
+ className,
207
+ ...props
208
+ }: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
209
+ return (
210
+ <ContextMenuPrimitive.Separator
211
+ data-slot="context-menu-separator"
212
+ className={cn("bg-border -mx-1 my-1 h-px", className)}
213
+ {...props}
214
+ />
215
+ )
216
+ }
217
+
218
+ function ContextMenuShortcut({
219
+ className,
220
+ ...props
221
+ }: React.ComponentProps<"span">) {
222
+ return (
223
+ <span
224
+ data-slot="context-menu-shortcut"
225
+ className={cn(
226
+ "text-muted-foreground ml-auto text-xs tracking-widest",
227
+ className
228
+ )}
229
+ {...props}
230
+ />
231
+ )
232
+ }
233
+
234
+ export {
235
+ ContextMenu,
236
+ ContextMenuTrigger,
237
+ ContextMenuContent,
238
+ ContextMenuItem,
239
+ ContextMenuCheckboxItem,
240
+ ContextMenuRadioItem,
241
+ ContextMenuLabel,
242
+ ContextMenuSeparator,
243
+ ContextMenuShortcut,
244
+ ContextMenuGroup,
245
+ ContextMenuPortal,
246
+ ContextMenuSub,
247
+ ContextMenuSubContent,
248
+ ContextMenuSubTrigger,
249
+ ContextMenuRadioGroup,
250
+ }
package/src/input.tsx CHANGED
@@ -8,7 +8,7 @@ const inputVariants = cva(
8
8
  {
9
9
  variants: {
10
10
  variant: {
11
- default: "shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
11
+ default: "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
12
12
  file: "file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground",
13
13
  embedded: "border-0 outline-none focus:border-0 focus:outline-none focus:ring20",
14
14
  }
@@ -0,0 +1,43 @@
1
+ import * as React from "react"
2
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
3
+ import { CircleIcon } from "lucide-react"
4
+
5
+ import { cn } from "@c-rex/utils"
6
+
7
+ function RadioGroup({
8
+ className,
9
+ ...props
10
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
11
+ return (
12
+ <RadioGroupPrimitive.Root
13
+ data-slot="radio-group"
14
+ className={cn("grid gap-3", className)}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function RadioGroupItem({
21
+ className,
22
+ ...props
23
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
24
+ return (
25
+ <RadioGroupPrimitive.Item
26
+ data-slot="radio-group-item"
27
+ className={cn(
28
+ "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",
29
+ className
30
+ )}
31
+ {...props}
32
+ >
33
+ <RadioGroupPrimitive.Indicator
34
+ data-slot="radio-group-indicator"
35
+ className="relative flex items-center justify-center"
36
+ >
37
+ <CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
38
+ </RadioGroupPrimitive.Indicator>
39
+ </RadioGroupPrimitive.Item>
40
+ )
41
+ }
42
+
43
+ export { RadioGroup, RadioGroupItem }
package/src/sidebar.tsx CHANGED
@@ -713,7 +713,7 @@ const SidebarMenuSub = React.forwardRef<
713
713
  ref={ref}
714
714
  data-sidebar="menu-sub"
715
715
  className={cn(
716
- "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
716
+ "ml-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border pl-2.5 py-0.5",
717
717
  "group-data-[collapsible=icon]:hidden",
718
718
  className,
719
719
  )}
package/src/switch.tsx ADDED
@@ -0,0 +1,29 @@
1
+ import * as React from "react"
2
+ import * as SwitchPrimitive from "@radix-ui/react-switch"
3
+
4
+ import { cn } from "@c-rex/utils"
5
+
6
+ function Switch({
7
+ className,
8
+ ...props
9
+ }: React.ComponentProps<typeof SwitchPrimitive.Root>) {
10
+ return (
11
+ <SwitchPrimitive.Root
12
+ data-slot="switch"
13
+ className={cn(
14
+ "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",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <SwitchPrimitive.Thumb
20
+ data-slot="switch-thumb"
21
+ className={cn(
22
+ "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"
23
+ )}
24
+ />
25
+ </SwitchPrimitive.Root>
26
+ )
27
+ }
28
+
29
+ export { Switch }
package/src/tabs.tsx ADDED
@@ -0,0 +1,64 @@
1
+ import * as React from "react"
2
+ import * as TabsPrimitive from "@radix-ui/react-tabs"
3
+
4
+ import { cn } from "@c-rex/utils"
5
+
6
+ function Tabs({
7
+ className,
8
+ ...props
9
+ }: React.ComponentProps<typeof TabsPrimitive.Root>) {
10
+ return (
11
+ <TabsPrimitive.Root
12
+ data-slot="tabs"
13
+ className={cn("flex flex-col gap-2", className)}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ function TabsList({
20
+ className,
21
+ ...props
22
+ }: React.ComponentProps<typeof TabsPrimitive.List>) {
23
+ return (
24
+ <TabsPrimitive.List
25
+ data-slot="tabs-list"
26
+ className={cn(
27
+ "bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
28
+ className
29
+ )}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function TabsTrigger({
36
+ className,
37
+ ...props
38
+ }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
39
+ return (
40
+ <TabsPrimitive.Trigger
41
+ data-slot="tabs-trigger"
42
+ className={cn(
43
+ "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",
44
+ className
45
+ )}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function TabsContent({
52
+ className,
53
+ ...props
54
+ }: React.ComponentProps<typeof TabsPrimitive.Content>) {
55
+ return (
56
+ <TabsPrimitive.Content
57
+ data-slot="tabs-content"
58
+ className={cn("flex-1 outline-none", className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ export { Tabs, TabsList, TabsTrigger, TabsContent }
@@ -0,0 +1,71 @@
1
+ import * as React from "react"
2
+ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
3
+ import { type VariantProps } from "class-variance-authority"
4
+
5
+ import { cn } from "@c-rex/utils"
6
+ import { toggleVariants } from "./toggle"
7
+
8
+ const ToggleGroupContext = React.createContext<
9
+ VariantProps<typeof toggleVariants>
10
+ >({
11
+ size: "default",
12
+ variant: "default",
13
+ })
14
+
15
+ function ToggleGroup({
16
+ className,
17
+ variant,
18
+ size,
19
+ children,
20
+ ...props
21
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
22
+ VariantProps<typeof toggleVariants>) {
23
+ return (
24
+ <ToggleGroupPrimitive.Root
25
+ data-slot="toggle-group"
26
+ data-variant={variant}
27
+ data-size={size}
28
+ className={cn(
29
+ "group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
30
+ className
31
+ )}
32
+ {...props}
33
+ >
34
+ <ToggleGroupContext.Provider value={{ variant, size }}>
35
+ {children}
36
+ </ToggleGroupContext.Provider>
37
+ </ToggleGroupPrimitive.Root>
38
+ )
39
+ }
40
+
41
+ function ToggleGroupItem({
42
+ className,
43
+ children,
44
+ variant,
45
+ size,
46
+ ...props
47
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
48
+ VariantProps<typeof toggleVariants>) {
49
+ const context = React.useContext(ToggleGroupContext)
50
+
51
+ return (
52
+ <ToggleGroupPrimitive.Item
53
+ data-slot="toggle-group-item"
54
+ data-variant={context.variant || variant}
55
+ data-size={context.size || size}
56
+ className={cn(
57
+ toggleVariants({
58
+ variant: context.variant || variant,
59
+ size: context.size || size,
60
+ }),
61
+ "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",
62
+ className
63
+ )}
64
+ {...props}
65
+ >
66
+ {children}
67
+ </ToggleGroupPrimitive.Item>
68
+ )
69
+ }
70
+
71
+ export { ToggleGroup, ToggleGroupItem }
package/src/toggle.tsx ADDED
@@ -0,0 +1,47 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as TogglePrimitive from "@radix-ui/react-toggle"
5
+ import { cva, type VariantProps } from "class-variance-authority"
6
+
7
+ import { cn } from "@c-rex/utils"
8
+
9
+ const toggleVariants = cva(
10
+ "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",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: "bg-transparent",
15
+ outline:
16
+ "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
17
+ },
18
+ size: {
19
+ default: "h-9 px-2 min-w-9",
20
+ sm: "h-8 px-1.5 min-w-8",
21
+ lg: "h-10 px-2.5 min-w-10",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: "default",
26
+ size: "default",
27
+ },
28
+ }
29
+ )
30
+
31
+ function Toggle({
32
+ className,
33
+ variant,
34
+ size,
35
+ ...props
36
+ }: React.ComponentProps<typeof TogglePrimitive.Root> &
37
+ VariantProps<typeof toggleVariants>) {
38
+ return (
39
+ <TogglePrimitive.Root
40
+ data-slot="toggle"
41
+ className={cn(toggleVariants({ variant, size, className }))}
42
+ {...props}
43
+ />
44
+ )
45
+ }
46
+
47
+ export { Toggle, toggleVariants }