cooterlabs 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,177 @@
1
+ import * as React from "react"
2
+ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
3
+ import { Check, ChevronRight } from "lucide-react"
4
+ import { clsx, type ClassValue } from "clsx"
5
+ import { twMerge } from "tailwind-merge"
6
+
7
+ export function cn(...inputs: ClassValue[]) {
8
+ return twMerge(clsx(inputs))
9
+ }
10
+
11
+ const surfaceClasses =
12
+ "z-50 min-w-48 overflow-hidden bg-popover text-popover-foreground rounded-xs shadow-400 border border-grey-100 p-1"
13
+
14
+ const itemClasses =
15
+ "relative flex h-10 cursor-default select-none items-center gap-2 px-3 rounded-xxs text-b3 outline-none transition-colors data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0"
16
+
17
+ const ContextMenu = ContextMenuPrimitive.Root
18
+
19
+ const ContextMenuTrigger = ContextMenuPrimitive.Trigger
20
+
21
+ const ContextMenuGroup = ContextMenuPrimitive.Group
22
+
23
+ const ContextMenuPortal = ContextMenuPrimitive.Portal
24
+
25
+ const ContextMenuSub = ContextMenuPrimitive.Sub
26
+
27
+ const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
28
+
29
+ const ContextMenuContent = React.forwardRef<
30
+ React.ElementRef<typeof ContextMenuPrimitive.Content>,
31
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
32
+ >(({ className, ...props }, ref) => (
33
+ <ContextMenuPrimitive.Portal>
34
+ <ContextMenuPrimitive.Content
35
+ ref={ref}
36
+ className={cn(surfaceClasses, className)}
37
+ {...props}
38
+ />
39
+ </ContextMenuPrimitive.Portal>
40
+ ))
41
+ ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
42
+
43
+ export interface ContextMenuItemProps
44
+ extends React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> {
45
+ variant?: "default" | "destructive"
46
+ }
47
+
48
+ const ContextMenuItem = React.forwardRef<
49
+ React.ElementRef<typeof ContextMenuPrimitive.Item>,
50
+ ContextMenuItemProps
51
+ >(({ className, variant = "default", ...props }, ref) => (
52
+ <ContextMenuPrimitive.Item
53
+ ref={ref}
54
+ className={cn(
55
+ itemClasses,
56
+ variant === "destructive" &&
57
+ "text-error data-[highlighted]:bg-error-50 data-[highlighted]:text-error",
58
+ className
59
+ )}
60
+ {...props}
61
+ />
62
+ ))
63
+ ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
64
+
65
+ const ContextMenuCheckboxItem = React.forwardRef<
66
+ React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
67
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
68
+ >(({ className, children, checked, ...props }, ref) => (
69
+ <ContextMenuPrimitive.CheckboxItem
70
+ ref={ref}
71
+ className={cn(itemClasses, "pl-8", className)}
72
+ checked={checked}
73
+ {...props}
74
+ >
75
+ <span className="absolute left-2 flex size-4 items-center justify-center">
76
+ <ContextMenuPrimitive.ItemIndicator>
77
+ <Check className="size-4" />
78
+ </ContextMenuPrimitive.ItemIndicator>
79
+ </span>
80
+ {children}
81
+ </ContextMenuPrimitive.CheckboxItem>
82
+ ))
83
+ ContextMenuCheckboxItem.displayName =
84
+ ContextMenuPrimitive.CheckboxItem.displayName
85
+
86
+ const ContextMenuRadioItem = React.forwardRef<
87
+ React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
88
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
89
+ >(({ className, children, ...props }, ref) => (
90
+ <ContextMenuPrimitive.RadioItem
91
+ ref={ref}
92
+ className={cn(itemClasses, "pl-8", className)}
93
+ {...props}
94
+ >
95
+ <span className="absolute left-2 flex size-4 items-center justify-center">
96
+ <ContextMenuPrimitive.ItemIndicator>
97
+ <span className="block size-2 rounded-full bg-current" />
98
+ </ContextMenuPrimitive.ItemIndicator>
99
+ </span>
100
+ {children}
101
+ </ContextMenuPrimitive.RadioItem>
102
+ ))
103
+ ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
104
+
105
+ const ContextMenuLabel = React.forwardRef<
106
+ React.ElementRef<typeof ContextMenuPrimitive.Label>,
107
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label>
108
+ >(({ className, ...props }, ref) => (
109
+ <ContextMenuPrimitive.Label
110
+ ref={ref}
111
+ className={cn("px-3 py-2 text-label text-muted-foreground", className)}
112
+ {...props}
113
+ />
114
+ ))
115
+ ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
116
+
117
+ const ContextMenuSeparator = React.forwardRef<
118
+ React.ElementRef<typeof ContextMenuPrimitive.Separator>,
119
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
120
+ >(({ className, ...props }, ref) => (
121
+ <ContextMenuPrimitive.Separator
122
+ ref={ref}
123
+ className={cn("-mx-1 my-1 h-px bg-grey-100", className)}
124
+ {...props}
125
+ />
126
+ ))
127
+ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
128
+
129
+ const ContextMenuSubTrigger = React.forwardRef<
130
+ React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
131
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger>
132
+ >(({ className, children, ...props }, ref) => (
133
+ <ContextMenuPrimitive.SubTrigger
134
+ ref={ref}
135
+ className={cn(
136
+ itemClasses,
137
+ "data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
138
+ className
139
+ )}
140
+ {...props}
141
+ >
142
+ {children}
143
+ <ChevronRight className="ml-auto size-4" />
144
+ </ContextMenuPrimitive.SubTrigger>
145
+ ))
146
+ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
147
+
148
+ const ContextMenuSubContent = React.forwardRef<
149
+ React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
150
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
151
+ >(({ className, ...props }, ref) => (
152
+ <ContextMenuPrimitive.Portal>
153
+ <ContextMenuPrimitive.SubContent
154
+ ref={ref}
155
+ className={cn(surfaceClasses, className)}
156
+ {...props}
157
+ />
158
+ </ContextMenuPrimitive.Portal>
159
+ ))
160
+ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
161
+
162
+ export {
163
+ ContextMenu,
164
+ ContextMenuTrigger,
165
+ ContextMenuContent,
166
+ ContextMenuItem,
167
+ ContextMenuCheckboxItem,
168
+ ContextMenuRadioGroup,
169
+ ContextMenuRadioItem,
170
+ ContextMenuLabel,
171
+ ContextMenuSeparator,
172
+ ContextMenuGroup,
173
+ ContextMenuPortal,
174
+ ContextMenuSub,
175
+ ContextMenuSubTrigger,
176
+ ContextMenuSubContent,
177
+ }
@@ -0,0 +1,127 @@
1
+ import * as React from "react"
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
3
+ import { X } from "lucide-react"
4
+ import { clsx, type ClassValue } from "clsx"
5
+ import { twMerge } from "tailwind-merge"
6
+
7
+ export function cn(...inputs: ClassValue[]) {
8
+ return twMerge(clsx(inputs))
9
+ }
10
+
11
+ const Dialog = DialogPrimitive.Root
12
+
13
+ const DialogTrigger = DialogPrimitive.Trigger
14
+
15
+ const DialogPortal = DialogPrimitive.Portal
16
+
17
+ const DialogClose = DialogPrimitive.Close
18
+
19
+ const DialogOverlay = React.forwardRef<
20
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
21
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
22
+ >(({ className, ...props }, ref) => (
23
+ <DialogPrimitive.Overlay
24
+ ref={ref}
25
+ className={cn(
26
+ "fixed inset-0 z-50 bg-black/50 transition-opacity data-[state=closed]:opacity-0",
27
+ className
28
+ )}
29
+ {...props}
30
+ />
31
+ ))
32
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
33
+
34
+ const DialogContent = React.forwardRef<
35
+ React.ElementRef<typeof DialogPrimitive.Content>,
36
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
37
+ >(({ className, children, ...props }, ref) => (
38
+ <DialogPortal>
39
+ <DialogOverlay />
40
+ <DialogPrimitive.Content
41
+ ref={ref}
42
+ className={cn(
43
+ "fixed left-1/2 top-1/2 z-50 grid w-full max-w-md -translate-x-1/2 -translate-y-1/2 gap-4 bg-background p-6 rounded-md shadow-600 transition-opacity data-[state=closed]:opacity-0",
44
+ className
45
+ )}
46
+ {...props}
47
+ >
48
+ {children}
49
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-xxs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none">
50
+ <X className="size-5" />
51
+ <span className="sr-only">Close</span>
52
+ </DialogPrimitive.Close>
53
+ </DialogPrimitive.Content>
54
+ </DialogPortal>
55
+ ))
56
+ DialogContent.displayName = DialogPrimitive.Content.displayName
57
+
58
+ const DialogHeader = ({
59
+ className,
60
+ ...props
61
+ }: React.HTMLAttributes<HTMLDivElement>) => (
62
+ <div
63
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
64
+ {...props}
65
+ />
66
+ )
67
+ DialogHeader.displayName = "DialogHeader"
68
+
69
+ export interface DialogFooterProps
70
+ extends React.HTMLAttributes<HTMLDivElement> {
71
+ orientation?: "horizontal" | "vertical"
72
+ }
73
+
74
+ const DialogFooter = ({
75
+ className,
76
+ orientation = "horizontal",
77
+ ...props
78
+ }: DialogFooterProps) => (
79
+ <div
80
+ className={cn(
81
+ "flex gap-2",
82
+ orientation === "vertical"
83
+ ? "flex-col"
84
+ : "flex-row justify-end [&>*]:flex-1 sm:[&>*]:flex-none",
85
+ className
86
+ )}
87
+ {...props}
88
+ />
89
+ )
90
+ DialogFooter.displayName = "DialogFooter"
91
+
92
+ const DialogTitle = React.forwardRef<
93
+ React.ElementRef<typeof DialogPrimitive.Title>,
94
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
95
+ >(({ className, ...props }, ref) => (
96
+ <DialogPrimitive.Title
97
+ ref={ref}
98
+ className={cn("text-s1 text-foreground", className)}
99
+ {...props}
100
+ />
101
+ ))
102
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
103
+
104
+ const DialogDescription = React.forwardRef<
105
+ React.ElementRef<typeof DialogPrimitive.Description>,
106
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
107
+ >(({ className, ...props }, ref) => (
108
+ <DialogPrimitive.Description
109
+ ref={ref}
110
+ className={cn("text-b3 text-muted-foreground", className)}
111
+ {...props}
112
+ />
113
+ ))
114
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
115
+
116
+ export {
117
+ Dialog,
118
+ DialogTrigger,
119
+ DialogPortal,
120
+ DialogOverlay,
121
+ DialogContent,
122
+ DialogHeader,
123
+ DialogFooter,
124
+ DialogTitle,
125
+ DialogDescription,
126
+ DialogClose,
127
+ }
@@ -0,0 +1,180 @@
1
+ import * as React from "react"
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
3
+ import { Check, ChevronRight } from "lucide-react"
4
+ import { clsx, type ClassValue } from "clsx"
5
+ import { twMerge } from "tailwind-merge"
6
+
7
+ export function cn(...inputs: ClassValue[]) {
8
+ return twMerge(clsx(inputs))
9
+ }
10
+
11
+ const surfaceClasses =
12
+ "z-50 min-w-48 overflow-hidden bg-popover text-popover-foreground rounded-xs shadow-400 border border-grey-100 p-1"
13
+
14
+ const itemClasses =
15
+ "relative flex h-10 cursor-default select-none items-center gap-2 px-3 rounded-xxs text-b3 outline-none transition-colors data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0"
16
+
17
+ const DropdownMenu = DropdownMenuPrimitive.Root
18
+
19
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
20
+
21
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
22
+
23
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
24
+
25
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
26
+
27
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
28
+
29
+ const DropdownMenuContent = React.forwardRef<
30
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
31
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
32
+ >(({ className, sideOffset = 4, ...props }, ref) => (
33
+ <DropdownMenuPrimitive.Portal>
34
+ <DropdownMenuPrimitive.Content
35
+ ref={ref}
36
+ sideOffset={sideOffset}
37
+ className={cn(surfaceClasses, className)}
38
+ {...props}
39
+ />
40
+ </DropdownMenuPrimitive.Portal>
41
+ ))
42
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
43
+
44
+ export interface DropdownMenuItemProps
45
+ extends React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {
46
+ variant?: "default" | "destructive"
47
+ }
48
+
49
+ const DropdownMenuItem = React.forwardRef<
50
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
51
+ DropdownMenuItemProps
52
+ >(({ className, variant = "default", ...props }, ref) => (
53
+ <DropdownMenuPrimitive.Item
54
+ ref={ref}
55
+ className={cn(
56
+ itemClasses,
57
+ variant === "destructive" &&
58
+ "text-error data-[highlighted]:bg-error-50 data-[highlighted]:text-error",
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ ))
64
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
65
+
66
+ const DropdownMenuCheckboxItem = React.forwardRef<
67
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
68
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
69
+ >(({ className, children, checked, ...props }, ref) => (
70
+ <DropdownMenuPrimitive.CheckboxItem
71
+ ref={ref}
72
+ className={cn(itemClasses, "pl-8", className)}
73
+ checked={checked}
74
+ {...props}
75
+ >
76
+ <span className="absolute left-2 flex size-4 items-center justify-center">
77
+ <DropdownMenuPrimitive.ItemIndicator>
78
+ <Check className="size-4" />
79
+ </DropdownMenuPrimitive.ItemIndicator>
80
+ </span>
81
+ {children}
82
+ </DropdownMenuPrimitive.CheckboxItem>
83
+ ))
84
+ DropdownMenuCheckboxItem.displayName =
85
+ DropdownMenuPrimitive.CheckboxItem.displayName
86
+
87
+ const DropdownMenuRadioItem = React.forwardRef<
88
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
89
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
90
+ >(({ className, children, ...props }, ref) => (
91
+ <DropdownMenuPrimitive.RadioItem
92
+ ref={ref}
93
+ className={cn(itemClasses, "pl-8", className)}
94
+ {...props}
95
+ >
96
+ <span className="absolute left-2 flex size-4 items-center justify-center">
97
+ <DropdownMenuPrimitive.ItemIndicator>
98
+ <span className="block size-2 rounded-full bg-current" />
99
+ </DropdownMenuPrimitive.ItemIndicator>
100
+ </span>
101
+ {children}
102
+ </DropdownMenuPrimitive.RadioItem>
103
+ ))
104
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
105
+
106
+ const DropdownMenuLabel = React.forwardRef<
107
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
108
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label>
109
+ >(({ className, ...props }, ref) => (
110
+ <DropdownMenuPrimitive.Label
111
+ ref={ref}
112
+ className={cn("px-3 py-2 text-label text-muted-foreground", className)}
113
+ {...props}
114
+ />
115
+ ))
116
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
117
+
118
+ const DropdownMenuSeparator = React.forwardRef<
119
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
120
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
121
+ >(({ className, ...props }, ref) => (
122
+ <DropdownMenuPrimitive.Separator
123
+ ref={ref}
124
+ className={cn("-mx-1 my-1 h-px bg-grey-100", className)}
125
+ {...props}
126
+ />
127
+ ))
128
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
129
+
130
+ const DropdownMenuSubTrigger = React.forwardRef<
131
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
132
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger>
133
+ >(({ className, children, ...props }, ref) => (
134
+ <DropdownMenuPrimitive.SubTrigger
135
+ ref={ref}
136
+ className={cn(
137
+ itemClasses,
138
+ "data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
139
+ className
140
+ )}
141
+ {...props}
142
+ >
143
+ {children}
144
+ <ChevronRight className="ml-auto size-4" />
145
+ </DropdownMenuPrimitive.SubTrigger>
146
+ ))
147
+ DropdownMenuSubTrigger.displayName =
148
+ DropdownMenuPrimitive.SubTrigger.displayName
149
+
150
+ const DropdownMenuSubContent = React.forwardRef<
151
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
152
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
153
+ >(({ className, ...props }, ref) => (
154
+ <DropdownMenuPrimitive.Portal>
155
+ <DropdownMenuPrimitive.SubContent
156
+ ref={ref}
157
+ className={cn(surfaceClasses, className)}
158
+ {...props}
159
+ />
160
+ </DropdownMenuPrimitive.Portal>
161
+ ))
162
+ DropdownMenuSubContent.displayName =
163
+ DropdownMenuPrimitive.SubContent.displayName
164
+
165
+ export {
166
+ DropdownMenu,
167
+ DropdownMenuTrigger,
168
+ DropdownMenuContent,
169
+ DropdownMenuItem,
170
+ DropdownMenuCheckboxItem,
171
+ DropdownMenuRadioGroup,
172
+ DropdownMenuRadioItem,
173
+ DropdownMenuLabel,
174
+ DropdownMenuSeparator,
175
+ DropdownMenuGroup,
176
+ DropdownMenuPortal,
177
+ DropdownMenuSub,
178
+ DropdownMenuSubTrigger,
179
+ DropdownMenuSubContent,
180
+ }
@@ -6,16 +6,43 @@ export function cn(...inputs: ClassValue[]) {
6
6
  return twMerge(clsx(inputs))
7
7
  }
8
8
 
9
+ const inputVariants = {
10
+ outline: "border-input bg-background hover:border-grey-300",
11
+ filled: "border-transparent bg-secondary hover:bg-muted",
12
+ }
13
+
14
+ const inputSizes = {
15
+ large: "h-12 px-4 text-b1",
16
+ medium: "h-10 px-3 text-b3",
17
+ }
18
+
19
+ const inputStatuses = {
20
+ success: "border-success",
21
+ info: "border-info",
22
+ warning: "border-warning",
23
+ error: "border-error",
24
+ }
25
+
9
26
  export interface InputProps
10
- extends React.InputHTMLAttributes<HTMLInputElement> { }
27
+ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"> {
28
+ variant?: keyof typeof inputVariants
29
+ size?: keyof typeof inputSizes
30
+ status?: keyof typeof inputStatuses
31
+ }
11
32
 
12
33
  const Input = React.forwardRef<HTMLInputElement, InputProps>(
13
- ({ className, type, ...props }, ref) => {
34
+ (
35
+ { className, type, variant = "outline", size = "large", status, ...props },
36
+ ref
37
+ ) => {
14
38
  return (
15
39
  <input
16
40
  type={type}
17
41
  className={cn(
18
- "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
42
+ "flex w-full rounded-xs border text-foreground ring-offset-background transition-colors file:border-0 file:bg-transparent file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 aria-invalid:border-error disabled:pointer-events-none disabled:border-grey-200 disabled:bg-secondary disabled:text-grey-400",
43
+ inputVariants[variant],
44
+ inputSizes[size],
45
+ status && inputStatuses[status],
19
46
  className
20
47
  )}
21
48
  ref={ref}
@@ -3,7 +3,7 @@ import * as LabelPrimitive from "@radix-ui/react-label"
3
3
  import { clsx, type ClassValue } from "clsx"
4
4
  import { twMerge } from "tailwind-merge"
5
5
 
6
- function cn(...inputs: ClassValue[]) {
6
+ export function cn(...inputs: ClassValue[]) {
7
7
  return twMerge(clsx(inputs))
8
8
  }
9
9
 
@@ -14,7 +14,7 @@ const Label = React.forwardRef<
14
14
  <LabelPrimitive.Root
15
15
  ref={ref}
16
16
  className={cn(
17
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
17
+ "text-label text-foreground peer-disabled:pointer-events-none peer-disabled:text-grey-400",
18
18
  className
19
19
  )}
20
20
  {...props}
@@ -0,0 +1,96 @@
1
+ import * as React from "react"
2
+ import { clsx, type ClassValue } from "clsx"
3
+ import { twMerge } from "tailwind-merge"
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs))
7
+ }
8
+
9
+ const List = React.forwardRef<
10
+ HTMLDivElement,
11
+ React.HTMLAttributes<HTMLDivElement>
12
+ >(({ className, ...props }, ref) => (
13
+ <div
14
+ ref={ref}
15
+ role="list"
16
+ className={cn("w-full divide-y divide-grey-100", className)}
17
+ {...props}
18
+ />
19
+ ))
20
+ List.displayName = "List"
21
+
22
+ const ListHeader = React.forwardRef<
23
+ HTMLDivElement,
24
+ React.HTMLAttributes<HTMLDivElement>
25
+ >(({ className, ...props }, ref) => (
26
+ <div
27
+ ref={ref}
28
+ className={cn("px-4 py-2 text-label text-muted-foreground", className)}
29
+ {...props}
30
+ />
31
+ ))
32
+ ListHeader.displayName = "ListHeader"
33
+
34
+ export interface ListItemProps
35
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
36
+ leading?: React.ReactNode
37
+ title?: React.ReactNode
38
+ subtitle?: React.ReactNode
39
+ trailing?: React.ReactNode
40
+ interactive?: boolean
41
+ }
42
+
43
+ const ListItem = React.forwardRef<HTMLDivElement, ListItemProps>(
44
+ (
45
+ {
46
+ className,
47
+ leading,
48
+ title,
49
+ subtitle,
50
+ trailing,
51
+ interactive = false,
52
+ children,
53
+ ...props
54
+ },
55
+ ref
56
+ ) => (
57
+ <div
58
+ ref={ref}
59
+ role="listitem"
60
+ className={cn(
61
+ "flex min-h-12 items-center gap-3 px-4 py-2",
62
+ interactive &&
63
+ "cursor-pointer transition-colors hover:bg-secondary active:bg-muted",
64
+ className
65
+ )}
66
+ {...props}
67
+ >
68
+ {leading && (
69
+ <span className="flex shrink-0 items-center justify-center text-muted-foreground [&_svg]:size-5">
70
+ {leading}
71
+ </span>
72
+ )}
73
+ <span className="flex min-w-0 flex-1 flex-col">
74
+ {title && (
75
+ <span className="truncate text-b2 text-foreground">
76
+ {title}
77
+ </span>
78
+ )}
79
+ {subtitle && (
80
+ <span className="truncate text-c1 text-muted-foreground">
81
+ {subtitle}
82
+ </span>
83
+ )}
84
+ {children}
85
+ </span>
86
+ {trailing && (
87
+ <span className="flex shrink-0 items-center gap-2 text-c1 text-muted-foreground [&_svg]:size-5">
88
+ {trailing}
89
+ </span>
90
+ )}
91
+ </div>
92
+ )
93
+ )
94
+ ListItem.displayName = "ListItem"
95
+
96
+ export { List, ListHeader, ListItem }
@@ -0,0 +1,38 @@
1
+ import * as React from "react"
2
+ import { clsx, type ClassValue } from "clsx"
3
+ import { twMerge } from "tailwind-merge"
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs))
7
+ }
8
+
9
+ const loaderSizes = {
10
+ tiny: "h-6 w-6 border-2",
11
+ small: "h-8 w-8 border-2",
12
+ medium: "h-10 w-10 border-4",
13
+ large: "h-12 w-12 border-4",
14
+ giant: "h-14 w-14 border-4",
15
+ }
16
+
17
+ export interface LoaderProps extends React.HTMLAttributes<HTMLDivElement> {
18
+ size?: keyof typeof loaderSizes
19
+ }
20
+
21
+ const Loader = React.forwardRef<HTMLDivElement, LoaderProps>(
22
+ ({ className, size = "medium", ...props }, ref) => (
23
+ <div
24
+ ref={ref}
25
+ role="status"
26
+ aria-label="Loading"
27
+ className={cn(
28
+ "inline-block animate-spin rounded-full border-grey-200 border-t-primary",
29
+ loaderSizes[size],
30
+ className
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ )
36
+ Loader.displayName = "Loader"
37
+
38
+ export { Loader }