@srcroot/ui 0.0.55 → 0.0.58
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/README.md +151 -151
- package/dist/index.d.ts +0 -0
- package/dist/index.js +120 -93
- package/package.json +7 -2
- package/src/registry/analytics/google-analytics.tsx +36 -39
- package/src/registry/analytics/google-tag-manager.tsx +62 -65
- package/src/registry/analytics/meta-pixel.tsx +44 -47
- package/src/registry/analytics/microsoft-clarity.tsx +31 -34
- package/src/registry/analytics/tiktok-pixel.tsx +34 -37
- package/src/registry/lib/utils.ts +0 -0
- package/src/registry/themes/v3/blue.css +157 -157
- package/src/registry/themes/v3/glass.css +153 -153
- package/src/registry/themes/v3/gray.css +157 -157
- package/src/registry/themes/v3/green.css +157 -157
- package/src/registry/themes/v3/neutral.css +157 -157
- package/src/registry/themes/v3/orange.css +157 -157
- package/src/registry/themes/v3/rose.css +157 -157
- package/src/registry/themes/v3/slate.css +157 -157
- package/src/registry/themes/v3/stone.css +157 -157
- package/src/registry/themes/v3/violet.css +186 -186
- package/src/registry/themes/v3/zinc.css +157 -157
- package/src/registry/themes/v4/blue.css +184 -184
- package/src/registry/themes/v4/glass.css +180 -180
- package/src/registry/themes/v4/gray.css +184 -184
- package/src/registry/themes/v4/green.css +184 -184
- package/src/registry/themes/v4/neutral.css +184 -184
- package/src/registry/themes/v4/orange.css +184 -184
- package/src/registry/themes/v4/rose.css +184 -184
- package/src/registry/themes/v4/slate.css +184 -184
- package/src/registry/themes/v4/stone.css +184 -184
- package/src/registry/themes/v4/violet.css +184 -184
- package/src/registry/themes/v4/zinc.css +184 -184
- package/src/registry/ui/accordion.tsx +164 -165
- package/src/registry/ui/alert-dialog.tsx +213 -214
- package/src/registry/ui/alert.tsx +73 -76
- package/src/registry/ui/aspect-ratio.tsx +44 -47
- package/src/registry/ui/avatar.tsx +96 -97
- package/src/registry/ui/badge.tsx +52 -55
- package/src/registry/ui/breadcrumb.tsx +147 -150
- package/src/registry/ui/button-group.tsx +64 -67
- package/src/registry/ui/button.tsx +71 -72
- package/src/registry/ui/calendar.tsx +514 -515
- package/src/registry/ui/card.tsx +88 -91
- package/src/registry/ui/carousel.tsx +214 -214
- package/src/registry/ui/chart.tsx +373 -373
- package/src/registry/ui/chatbot.tsx +86 -13
- package/src/registry/ui/checkbox.tsx +93 -94
- package/src/registry/ui/collapsible.tsx +107 -108
- package/src/registry/ui/combobox.tsx +171 -171
- package/src/registry/ui/command.tsx +300 -300
- package/src/registry/ui/container.tsx +44 -47
- package/src/registry/ui/context-menu.tsx +221 -221
- package/src/registry/ui/date-picker.tsx +228 -228
- package/src/registry/ui/dialog.tsx +269 -270
- package/src/registry/ui/drawer.tsx +10 -4
- package/src/registry/ui/dropdown-menu.tsx +529 -530
- package/src/registry/ui/empty-state.tsx +0 -2
- package/src/registry/ui/file-upload.tsx +0 -0
- package/src/registry/ui/floating-dock.tsx +0 -0
- package/src/registry/ui/form-field.tsx +91 -94
- package/src/registry/ui/google-analytics.tsx +38 -0
- package/src/registry/ui/google-tag-manager.tsx +64 -0
- package/src/registry/ui/hover-card.tsx +223 -223
- package/src/registry/ui/image.tsx +144 -147
- package/src/registry/ui/input-group.tsx +82 -85
- package/src/registry/ui/input.tsx +125 -125
- package/src/registry/ui/kbd.tsx +60 -63
- package/src/registry/ui/label.tsx +36 -37
- package/src/registry/ui/loading-spinner.tsx +108 -111
- package/src/registry/ui/map.tsx +0 -0
- package/src/registry/ui/marquee.tsx +2 -0
- package/src/registry/ui/menubar.tsx +246 -246
- package/src/registry/ui/meta-pixel.tsx +46 -0
- package/src/registry/ui/microsoft-clarity.tsx +33 -0
- package/src/registry/ui/native-select.tsx +49 -52
- package/src/registry/ui/otp-input.tsx +163 -155
- package/src/registry/ui/pagination.tsx +149 -152
- package/src/registry/ui/patterns.tsx +28 -0
- package/src/registry/ui/popover.tsx +226 -227
- package/src/registry/ui/progress.tsx +51 -52
- package/src/registry/ui/radio.tsx +99 -102
- package/src/registry/ui/resizable.tsx +314 -314
- package/src/registry/ui/scroll-animation.tsx +45 -0
- package/src/registry/ui/scroll-area.tsx +121 -122
- package/src/registry/ui/scroll-to-top.tsx +0 -0
- package/src/registry/ui/search.tsx +162 -150
- package/src/registry/ui/select.tsx +292 -293
- package/src/registry/ui/separator.tsx +46 -47
- package/src/registry/ui/sheet.tsx +6 -3
- package/src/registry/ui/sidebar.tsx +628 -628
- package/src/registry/ui/skeleton.tsx +26 -29
- package/src/registry/ui/slider.tsx +196 -197
- package/src/registry/ui/slot.tsx +69 -72
- package/src/registry/ui/star-rating.tsx +146 -134
- package/src/registry/ui/switch.tsx +72 -73
- package/src/registry/ui/table-of-contents.tsx +96 -96
- package/src/registry/ui/table.tsx +138 -139
- package/src/registry/ui/tabs.tsx +124 -125
- package/src/registry/ui/text.tsx +61 -64
- package/src/registry/ui/textarea.tsx +41 -42
- package/src/registry/ui/theme-switcher.tsx +66 -66
- package/src/registry/ui/tiktok-pixel.tsx +36 -0
- package/src/registry/ui/toast.tsx +97 -98
- package/src/registry/ui/toggle-group.tsx +129 -129
- package/src/registry/ui/toggle.tsx +72 -72
- package/src/registry/ui/tooltip.tsx +143 -144
- package/src/registry/ui/whatsapp.tsx +0 -0
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import { FiEye, FiEyeOff, FiSearch, FiX } from "react-icons/fi"
|
|
5
|
-
|
|
6
|
-
import { cn } from "@/lib/utils"
|
|
7
|
-
|
|
8
|
-
export interface InputProps
|
|
9
|
-
extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
10
|
-
/**
|
|
11
|
-
* Whether the input is in an error state
|
|
12
|
-
*/
|
|
13
|
-
error?: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Input component with focus states and error styling
|
|
18
|
-
*
|
|
19
|
-
* Supports special handling for:
|
|
20
|
-
* - type="password": Adds show/hide toggle
|
|
21
|
-
* - type="search": Adds search icon and clear button
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* // Basic usage
|
|
25
|
-
* <Input placeholder="Enter your email" />
|
|
26
|
-
*
|
|
27
|
-
* // Password with toggle
|
|
28
|
-
* <Input type="password" placeholder="Password" />
|
|
29
|
-
*
|
|
30
|
-
* // Search with icon and clear
|
|
31
|
-
* <Input type="search" placeholder="Search..." />
|
|
32
|
-
*/
|
|
33
|
-
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
34
|
-
({ className, type, error, ...props }, ref) => {
|
|
35
|
-
const [isVisible, setIsVisible] = React.useState(false)
|
|
36
|
-
const [value, setValue] = React.useState(props.value || props.defaultValue || "")
|
|
37
|
-
const isPassword = type === "password"
|
|
38
|
-
const isSearch = type === "search"
|
|
39
|
-
|
|
40
|
-
// Handle value changes for search clear functionality
|
|
41
|
-
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
42
|
-
setValue(e.target.value)
|
|
43
|
-
props.onChange?.(e)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handleClear = () => {
|
|
47
|
-
setValue("")
|
|
48
|
-
// Create a synthetic event to notify parent
|
|
49
|
-
const event = {
|
|
50
|
-
target: { value: "" },
|
|
51
|
-
currentTarget: { value: "" },
|
|
52
|
-
} as React.ChangeEvent<HTMLInputElement>
|
|
53
|
-
props.onChange?.(event)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Base input styles
|
|
57
|
-
const baseStyles = cn(
|
|
58
|
-
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
|
59
|
-
error && "border-destructive focus-visible:ring-destructive",
|
|
60
|
-
isSearch && "pl-9", // Add padding for search icon
|
|
61
|
-
(isPassword || (isSearch && value)) && "pr-9", // Add padding for toggle/clear button
|
|
62
|
-
"[&::-webkit-search-cancel-button]:appearance-none", // Hide native search cancel button
|
|
63
|
-
className
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
// For regular inputs, render normally
|
|
67
|
-
if (!isPassword && !isSearch) {
|
|
68
|
-
return (
|
|
69
|
-
<input
|
|
70
|
-
type={type}
|
|
71
|
-
className={baseStyles}
|
|
72
|
-
ref={ref}
|
|
73
|
-
aria-invalid={error ? "true" : undefined}
|
|
74
|
-
{...props}
|
|
75
|
-
/>
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<div className="relative">
|
|
81
|
-
{isSearch && (
|
|
82
|
-
<FiSearch className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground pointer-events-none" />
|
|
83
|
-
)}
|
|
84
|
-
<input
|
|
85
|
-
type={isPassword ? (isVisible ? "text" : "password") : type}
|
|
86
|
-
className={baseStyles}
|
|
87
|
-
ref={ref}
|
|
88
|
-
aria-invalid={error ? "true" : undefined}
|
|
89
|
-
{...props}
|
|
90
|
-
onChange={handleChange}
|
|
91
|
-
value={props.value !== undefined ? props.value : value}
|
|
92
|
-
/>
|
|
93
|
-
{isPassword && (
|
|
94
|
-
<button
|
|
95
|
-
type="button"
|
|
96
|
-
onClick={() => setIsVisible(!isVisible)}
|
|
97
|
-
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground focus:outline-none"
|
|
98
|
-
>
|
|
99
|
-
{isVisible ? (
|
|
100
|
-
<FiEyeOff className="h-4 w-4" aria-hidden="true" />
|
|
101
|
-
) : (
|
|
102
|
-
<FiEye className="h-4 w-4" aria-hidden="true" />
|
|
103
|
-
)}
|
|
104
|
-
<span className="sr-only">
|
|
105
|
-
{isVisible ? "Hide password" : "Show password"}
|
|
106
|
-
</span>
|
|
107
|
-
</button>
|
|
108
|
-
)}
|
|
109
|
-
{isSearch && value && (
|
|
110
|
-
<button
|
|
111
|
-
type="button"
|
|
112
|
-
onClick={handleClear}
|
|
113
|
-
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground focus:outline-none"
|
|
114
|
-
>
|
|
115
|
-
<FiX className="h-4 w-4" aria-hidden="true" />
|
|
116
|
-
<span className="sr-only">Clear search</span>
|
|
117
|
-
</button>
|
|
118
|
-
)}
|
|
119
|
-
</div>
|
|
120
|
-
)
|
|
121
|
-
}
|
|
122
|
-
)
|
|
123
|
-
Input.displayName = "Input"
|
|
124
|
-
|
|
125
|
-
export { Input }
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { FiEye, FiEyeOff, FiSearch, FiX } from "react-icons/fi"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
export interface InputProps
|
|
9
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
10
|
+
/**
|
|
11
|
+
* Whether the input is in an error state
|
|
12
|
+
*/
|
|
13
|
+
error?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Input component with focus states and error styling
|
|
18
|
+
*
|
|
19
|
+
* Supports special handling for:
|
|
20
|
+
* - type="password": Adds show/hide toggle
|
|
21
|
+
* - type="search": Adds search icon and clear button
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Basic usage
|
|
25
|
+
* <Input placeholder="Enter your email" />
|
|
26
|
+
*
|
|
27
|
+
* // Password with toggle
|
|
28
|
+
* <Input type="password" placeholder="Password" />
|
|
29
|
+
*
|
|
30
|
+
* // Search with icon and clear
|
|
31
|
+
* <Input type="search" placeholder="Search..." />
|
|
32
|
+
*/
|
|
33
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
34
|
+
({ className, type, error, ...props }, ref) => {
|
|
35
|
+
const [isVisible, setIsVisible] = React.useState(false)
|
|
36
|
+
const [value, setValue] = React.useState(props.value || props.defaultValue || "")
|
|
37
|
+
const isPassword = type === "password"
|
|
38
|
+
const isSearch = type === "search"
|
|
39
|
+
|
|
40
|
+
// Handle value changes for search clear functionality
|
|
41
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
42
|
+
setValue(e.target.value)
|
|
43
|
+
props.onChange?.(e)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const handleClear = () => {
|
|
47
|
+
setValue("")
|
|
48
|
+
// Create a synthetic event to notify parent
|
|
49
|
+
const event = {
|
|
50
|
+
target: { value: "" },
|
|
51
|
+
currentTarget: { value: "" },
|
|
52
|
+
} as React.ChangeEvent<HTMLInputElement>
|
|
53
|
+
props.onChange?.(event)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Base input styles
|
|
57
|
+
const baseStyles = cn(
|
|
58
|
+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
|
59
|
+
error && "border-destructive focus-visible:ring-destructive",
|
|
60
|
+
isSearch && "pl-9", // Add padding for search icon
|
|
61
|
+
(isPassword || (isSearch && value)) && "pr-9", // Add padding for toggle/clear button
|
|
62
|
+
"[&::-webkit-search-cancel-button]:appearance-none", // Hide native search cancel button
|
|
63
|
+
className
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
// For regular inputs, render normally
|
|
67
|
+
if (!isPassword && !isSearch) {
|
|
68
|
+
return (
|
|
69
|
+
<input
|
|
70
|
+
type={type}
|
|
71
|
+
className={baseStyles}
|
|
72
|
+
ref={ref}
|
|
73
|
+
aria-invalid={error ? "true" : undefined}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<div className="relative">
|
|
81
|
+
{isSearch && (
|
|
82
|
+
<FiSearch className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground pointer-events-none" />
|
|
83
|
+
)}
|
|
84
|
+
<input
|
|
85
|
+
type={isPassword ? (isVisible ? "text" : "password") : type}
|
|
86
|
+
className={baseStyles}
|
|
87
|
+
ref={ref}
|
|
88
|
+
aria-invalid={error ? "true" : undefined}
|
|
89
|
+
{...props}
|
|
90
|
+
onChange={handleChange}
|
|
91
|
+
value={props.value !== undefined ? props.value : value}
|
|
92
|
+
/>
|
|
93
|
+
{isPassword && (
|
|
94
|
+
<button
|
|
95
|
+
type="button"
|
|
96
|
+
onClick={() => setIsVisible(!isVisible)}
|
|
97
|
+
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground focus:outline-none"
|
|
98
|
+
>
|
|
99
|
+
{isVisible ? (
|
|
100
|
+
<FiEyeOff className="h-4 w-4" aria-hidden="true" />
|
|
101
|
+
) : (
|
|
102
|
+
<FiEye className="h-4 w-4" aria-hidden="true" />
|
|
103
|
+
)}
|
|
104
|
+
<span className="sr-only">
|
|
105
|
+
{isVisible ? "Hide password" : "Show password"}
|
|
106
|
+
</span>
|
|
107
|
+
</button>
|
|
108
|
+
)}
|
|
109
|
+
{isSearch && value && (
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
onClick={handleClear}
|
|
113
|
+
className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground focus:outline-none"
|
|
114
|
+
>
|
|
115
|
+
<FiX className="h-4 w-4" aria-hidden="true" />
|
|
116
|
+
<span className="sr-only">Clear search</span>
|
|
117
|
+
</button>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
Input.displayName = "Input"
|
|
124
|
+
|
|
125
|
+
export { Input }
|
package/src/registry/ui/kbd.tsx
CHANGED
|
@@ -1,63 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
export { Kbd }
|
|
63
|
-
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cn } from "@/lib/utils"
|
|
3
|
+
|
|
4
|
+
interface KbdProps extends React.HTMLAttributes<HTMLElement> {
|
|
5
|
+
/** Array of keys to display (e.g., ["Ctrl", "K"]) */
|
|
6
|
+
keys?: string[]
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Kbd - Keyboard key display component
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* <Kbd>⌘</Kbd>
|
|
14
|
+
* <Kbd keys={["Ctrl", "Shift", "P"]} />
|
|
15
|
+
*/
|
|
16
|
+
const Kbd = React.forwardRef<HTMLElement, KbdProps>(
|
|
17
|
+
({ className, children, keys, ...props }, ref) => {
|
|
18
|
+
// If keys array is provided, render each key
|
|
19
|
+
if (keys && keys.length > 0) {
|
|
20
|
+
return (
|
|
21
|
+
<span className="inline-flex items-center gap-1">
|
|
22
|
+
{keys.map((key, index) => (
|
|
23
|
+
<React.Fragment key={index}>
|
|
24
|
+
<kbd
|
|
25
|
+
ref={index === 0 ? ref : undefined}
|
|
26
|
+
className={cn(
|
|
27
|
+
"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground",
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
{key}
|
|
33
|
+
</kbd>
|
|
34
|
+
{index < keys.length - 1 && (
|
|
35
|
+
<span className="text-muted-foreground text-xs">+</span>
|
|
36
|
+
)}
|
|
37
|
+
</React.Fragment>
|
|
38
|
+
))}
|
|
39
|
+
</span>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Single key rendering
|
|
44
|
+
return (
|
|
45
|
+
<kbd
|
|
46
|
+
ref={ref}
|
|
47
|
+
className={cn(
|
|
48
|
+
"pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground",
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
</kbd>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
Kbd.displayName = "Kbd"
|
|
59
|
+
|
|
60
|
+
export { Kbd }
|
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import * as React from "react"
|
|
4
|
-
import { cn } from "@/lib/utils"
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Label component for form inputs
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* <Label htmlFor="email">Email</Label>
|
|
11
|
-
* <Input id="email" type="email" />
|
|
12
|
-
*/
|
|
13
|
-
const Label = React.forwardRef<
|
|
14
|
-
HTMLLabelElement,
|
|
15
|
-
React.LabelHTMLAttributes<HTMLLabelElement> & {
|
|
16
|
-
/**
|
|
17
|
-
* Whether the associated input is required
|
|
18
|
-
*/
|
|
19
|
-
required?: boolean
|
|
20
|
-
}
|
|
21
|
-
>(({ className, required, children, ...props }, ref) => (
|
|
22
|
-
<label
|
|
23
|
-
ref={ref}
|
|
24
|
-
className={cn(
|
|
25
|
-
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
26
|
-
className
|
|
27
|
-
)}
|
|
28
|
-
{...props}
|
|
29
|
-
>
|
|
30
|
-
{children}
|
|
31
|
-
{required && <span className="text-destructive ml-1">*</span>}
|
|
32
|
-
</label>
|
|
33
|
-
))
|
|
34
|
-
Label.displayName = "Label"
|
|
35
|
-
|
|
36
|
-
export { Label }
|
|
37
|
-
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Label component for form inputs
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <Label htmlFor="email">Email</Label>
|
|
11
|
+
* <Input id="email" type="email" />
|
|
12
|
+
*/
|
|
13
|
+
const Label = React.forwardRef<
|
|
14
|
+
HTMLLabelElement,
|
|
15
|
+
React.LabelHTMLAttributes<HTMLLabelElement> & {
|
|
16
|
+
/**
|
|
17
|
+
* Whether the associated input is required
|
|
18
|
+
*/
|
|
19
|
+
required?: boolean
|
|
20
|
+
}
|
|
21
|
+
>(({ className, required, children, ...props }, ref) => (
|
|
22
|
+
<label
|
|
23
|
+
ref={ref}
|
|
24
|
+
className={cn(
|
|
25
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
{required && <span className="text-destructive ml-1">*</span>}
|
|
32
|
+
</label>
|
|
33
|
+
))
|
|
34
|
+
Label.displayName = "Label"
|
|
35
|
+
|
|
36
|
+
export { Label }
|