@underverse-ui/underverse 0.2.64 → 0.2.65
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 +25 -1
- package/dist/Input-umeHzPJL.d.cts +110 -0
- package/dist/Input-umeHzPJL.d.ts +110 -0
- package/dist/chunk-A5NZI37V.js +1149 -0
- package/dist/chunk-A5NZI37V.js.map +1 -0
- package/dist/form.cjs +1287 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.d.cts +47 -0
- package/dist/form.d.ts +47 -0
- package/dist/form.js +167 -0
- package/dist/form.js.map +1 -0
- package/dist/index.cjs +117 -240
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -150
- package/dist/index.d.ts +5 -150
- package/dist/index.js +1587 -2815
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,1149 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// ../../lib/constants/constants-ui/button.ts
|
|
14
|
+
var VARIANT_STYLES_BTN = {
|
|
15
|
+
// Mặc định: tối giản, rõ ràng, dùng tokens hệ màu
|
|
16
|
+
default: "bg-background/80 backdrop-blur-sm text-foreground border border-border hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
17
|
+
// Viền: trong suốt, viền tinh tế, hover nhẹ
|
|
18
|
+
outline: "bg-transparent backdrop-blur-sm border border-input hover:bg-accent/40 hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
19
|
+
// Primary: dùng brand, bỏ hiệu ứng scale/shadow mạnh
|
|
20
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm border border-primary/20 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
21
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/90 shadow-sm border border-secondary/20 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
22
|
+
success: "bg-success text-success-foreground hover:bg-success/90 shadow-sm border border-success/20 focus-visible:ring-2 focus-visible:ring-success/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
23
|
+
danger: "bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm border border-destructive/20 focus-visible:ring-2 focus-visible:ring-destructive/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
24
|
+
// Alias for shadcn-style prop naming used in some components
|
|
25
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm border border-destructive/20 focus-visible:ring-2 focus-visible:ring-destructive/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
26
|
+
warning: "bg-warning text-warning-foreground hover:bg-warning/90 shadow-sm border border-warning/20 focus-visible:ring-2 focus-visible:ring-warning/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
27
|
+
info: "bg-info text-info-foreground hover:bg-info/90 shadow-sm border border-info/20 focus-visible:ring-2 focus-visible:ring-info/60 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
28
|
+
// Ghost: minimal
|
|
29
|
+
ghost: "bg-transparent hover:bg-accent/20 hover:text-accent-foreground backdrop-blur-sm transition-colors",
|
|
30
|
+
// Link: chỉ văn bản
|
|
31
|
+
link: "text-primary bg-transparent underline-offset-4 hover:underline hover:text-primary/85 transition-colors",
|
|
32
|
+
// Gradient: smooth gradient từ primary → secondary (cùng tone)
|
|
33
|
+
gradient: "bg-linear-to-r from-primary via-primary/80 to-secondary text-primary-foreground hover:opacity-90 shadow-md border-0"
|
|
34
|
+
};
|
|
35
|
+
var SIZE_STYLES_BTN = {
|
|
36
|
+
sm: "px-3 py-1.5 text-sm h-8 min-w-8 md:px-2.5 md:py-1 md:h-7 md:text-xs",
|
|
37
|
+
md: "px-4 py-2 text-sm h-10 min-w-10 md:px-3 md:py-1.5 md:h-9",
|
|
38
|
+
lg: "px-6 py-3 text-base h-12 min-w-12 md:px-4 md:py-2 md:h-10 md:text-sm",
|
|
39
|
+
smx: "px-3.5 py-1.5 text-[13px] h-9 min-w-9 md:px-3 md:py-1 md:h-8 md:text-xs",
|
|
40
|
+
icon: "w-11 h-11 p-0 rounded-full flex items-center justify-center md:w-10 md:h-10"
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ../../lib/utils/cn.ts
|
|
44
|
+
import { clsx } from "clsx";
|
|
45
|
+
import { twMerge } from "tailwind-merge";
|
|
46
|
+
function cn(...inputs) {
|
|
47
|
+
return twMerge(clsx(...inputs));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ../../components/ui/Button.tsx
|
|
51
|
+
import { forwardRef, useCallback, useRef, useState } from "react";
|
|
52
|
+
import { Activity } from "lucide-react";
|
|
53
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
54
|
+
var Button = forwardRef(
|
|
55
|
+
({
|
|
56
|
+
onClick,
|
|
57
|
+
children,
|
|
58
|
+
type = "button",
|
|
59
|
+
icon: Icon,
|
|
60
|
+
iconRight: IconRight,
|
|
61
|
+
variant = "default",
|
|
62
|
+
size = "md",
|
|
63
|
+
className = "",
|
|
64
|
+
iConClassName = "",
|
|
65
|
+
disabled = false,
|
|
66
|
+
loading = false,
|
|
67
|
+
fullWidth = false,
|
|
68
|
+
title,
|
|
69
|
+
spinner: Spinner,
|
|
70
|
+
loadingText,
|
|
71
|
+
preserveChildrenOnLoading = false,
|
|
72
|
+
// custom behavior props (do not forward to DOM)
|
|
73
|
+
preventDoubleClick = false,
|
|
74
|
+
lockMs = 600,
|
|
75
|
+
asContainer = false,
|
|
76
|
+
noWrap = true,
|
|
77
|
+
noHoverOverlay = false,
|
|
78
|
+
gradient = false,
|
|
79
|
+
...rest
|
|
80
|
+
}, ref) => {
|
|
81
|
+
const baseStyles = asContainer ? "relative inline-flex justify-center rounded-full font-medium transition-colors duration-150 ease-soft outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background active:translate-y-px" : "relative inline-flex items-center justify-center gap-2 rounded-full font-medium overflow-hidden transition-colors duration-150 ease-soft outline-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background active:translate-y-px";
|
|
82
|
+
const finalVariant = gradient ? "gradient" : variant;
|
|
83
|
+
const variantStyle = VARIANT_STYLES_BTN[finalVariant] || VARIANT_STYLES_BTN.default;
|
|
84
|
+
const sizeStyle = SIZE_STYLES_BTN[size] || SIZE_STYLES_BTN.md;
|
|
85
|
+
const SpinnerIcon = Spinner ?? Activity;
|
|
86
|
+
const [locked, setLocked] = useState(false);
|
|
87
|
+
const lockTimer = useRef(null);
|
|
88
|
+
const handleClick = useCallback(
|
|
89
|
+
async (e) => {
|
|
90
|
+
if (disabled || loading) return;
|
|
91
|
+
if (preventDoubleClick) {
|
|
92
|
+
if (locked) return;
|
|
93
|
+
setLocked(true);
|
|
94
|
+
try {
|
|
95
|
+
const result = onClick?.(e);
|
|
96
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
97
|
+
await result;
|
|
98
|
+
setLocked(false);
|
|
99
|
+
} else {
|
|
100
|
+
const ms = lockMs ?? 600;
|
|
101
|
+
if (lockTimer.current) clearTimeout(lockTimer.current);
|
|
102
|
+
lockTimer.current = setTimeout(() => setLocked(false), ms);
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
setLocked(false);
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
onClick?.(e);
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
[disabled, loading, onClick, locked, preventDoubleClick, lockMs]
|
|
113
|
+
);
|
|
114
|
+
const computedDisabled = disabled || loading || (preventDoubleClick ? locked : false);
|
|
115
|
+
return /* @__PURE__ */ jsxs(
|
|
116
|
+
"button",
|
|
117
|
+
{
|
|
118
|
+
ref,
|
|
119
|
+
type,
|
|
120
|
+
onClick: handleClick,
|
|
121
|
+
title,
|
|
122
|
+
className: cn(
|
|
123
|
+
baseStyles,
|
|
124
|
+
variantStyle,
|
|
125
|
+
sizeStyle,
|
|
126
|
+
"group",
|
|
127
|
+
noWrap && "whitespace-nowrap",
|
|
128
|
+
{
|
|
129
|
+
"cursor-pointer hover:opacity-95": !computedDisabled,
|
|
130
|
+
"opacity-50 cursor-not-allowed": computedDisabled,
|
|
131
|
+
"w-full": fullWidth
|
|
132
|
+
},
|
|
133
|
+
className
|
|
134
|
+
),
|
|
135
|
+
disabled: computedDisabled,
|
|
136
|
+
"aria-disabled": computedDisabled,
|
|
137
|
+
"aria-busy": loading,
|
|
138
|
+
"data-variant": variant,
|
|
139
|
+
"data-size": size,
|
|
140
|
+
"data-locked": preventDoubleClick ? locked ? "true" : "false" : void 0,
|
|
141
|
+
"aria-label": rest["aria-label"] || title,
|
|
142
|
+
...rest,
|
|
143
|
+
children: [
|
|
144
|
+
!noHoverOverlay ? /* @__PURE__ */ jsx("span", { className: "absolute inset-0 bg-linear-to-r from-primary-foreground/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-200 dark:hidden" }) : null,
|
|
145
|
+
loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
146
|
+
/* @__PURE__ */ jsx(SpinnerIcon, { className: "w-4 h-4 animate-spin", "aria-hidden": "true" }),
|
|
147
|
+
loadingText ? /* @__PURE__ */ jsx("span", { className: "ml-2", "aria-live": "polite", children: loadingText }) : null,
|
|
148
|
+
preserveChildrenOnLoading && !loadingText ? /* @__PURE__ */ jsx("span", { className: "ml-2 opacity-70", "aria-hidden": true, children }) : null
|
|
149
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
150
|
+
Icon ? /* @__PURE__ */ jsx(Icon, { className: cn("transition-transform duration-200", iConClassName ? iConClassName : "w-5 h-5") }) : null,
|
|
151
|
+
children,
|
|
152
|
+
IconRight ? /* @__PURE__ */ jsx(IconRight, { className: "w-4 h-4 transition-transform duration-200" }) : null
|
|
153
|
+
] })
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
Button.displayName = "Button";
|
|
160
|
+
var Button_default = Button;
|
|
161
|
+
|
|
162
|
+
// ../../components/ui/CheckBox.tsx
|
|
163
|
+
import * as React2 from "react";
|
|
164
|
+
import { Check } from "lucide-react";
|
|
165
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
166
|
+
var Checkbox = React2.forwardRef(
|
|
167
|
+
({ className, label, labelClassName, containerClassName, checked, defaultChecked, onChange, ...props }, ref) => {
|
|
168
|
+
const [internalChecked, setInternalChecked] = React2.useState(defaultChecked ?? false);
|
|
169
|
+
const isControlled = checked !== void 0;
|
|
170
|
+
const isChecked = isControlled ? checked : internalChecked;
|
|
171
|
+
const handleChange = (e) => {
|
|
172
|
+
if (!isControlled) {
|
|
173
|
+
setInternalChecked(e.target.checked);
|
|
174
|
+
}
|
|
175
|
+
onChange?.(e);
|
|
176
|
+
};
|
|
177
|
+
return /* @__PURE__ */ jsxs2("label", { className: cn("inline-flex items-center gap-2 cursor-pointer select-none", containerClassName), children: [
|
|
178
|
+
/* @__PURE__ */ jsx2("input", { type: "checkbox", ref, checked: isChecked, onChange: handleChange, className: "hidden", ...props }),
|
|
179
|
+
/* @__PURE__ */ jsx2(
|
|
180
|
+
"div",
|
|
181
|
+
{
|
|
182
|
+
className: cn(
|
|
183
|
+
"w-5 h-5 border rounded-md flex items-center justify-center transition-all duration-200 ease-soft",
|
|
184
|
+
"hover:shadow-sm active:scale-95",
|
|
185
|
+
isChecked ? "bg-primary border-primary shadow-md text-primary-foreground" : "bg-background border-input hover:border-accent-foreground/30 hover:bg-accent/10"
|
|
186
|
+
),
|
|
187
|
+
children: isChecked && /* @__PURE__ */ jsx2(Check, { className: "w-4 h-4" })
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
label && /* @__PURE__ */ jsx2("span", { className: cn("text-sm text-foreground", labelClassName), children: label })
|
|
191
|
+
] });
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
Checkbox.displayName = "Checkbox";
|
|
195
|
+
|
|
196
|
+
// ../../lib/i18n/translation-adapter.tsx
|
|
197
|
+
import * as React3 from "react";
|
|
198
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
199
|
+
var defaultTranslations = {
|
|
200
|
+
en: {
|
|
201
|
+
Common: {
|
|
202
|
+
close: "Close",
|
|
203
|
+
closeAlert: "Close alert",
|
|
204
|
+
notifications: "Notifications",
|
|
205
|
+
newNotification: "New",
|
|
206
|
+
readStatus: "Read",
|
|
207
|
+
openLink: "Open link",
|
|
208
|
+
theme: "Theme",
|
|
209
|
+
lightTheme: "Light",
|
|
210
|
+
darkTheme: "Dark",
|
|
211
|
+
systemTheme: "System",
|
|
212
|
+
density: "Density",
|
|
213
|
+
compact: "Compact",
|
|
214
|
+
normal: "Normal",
|
|
215
|
+
comfortable: "Comfortable",
|
|
216
|
+
columns: "Columns"
|
|
217
|
+
},
|
|
218
|
+
ValidationInput: {
|
|
219
|
+
required: "This field is required",
|
|
220
|
+
typeMismatch: "Invalid format",
|
|
221
|
+
pattern: "Invalid pattern",
|
|
222
|
+
tooShort: "Too short",
|
|
223
|
+
tooLong: "Too long",
|
|
224
|
+
rangeUnderflow: "Below minimum",
|
|
225
|
+
rangeOverflow: "Above maximum",
|
|
226
|
+
stepMismatch: "Step mismatch",
|
|
227
|
+
badInput: "Bad input",
|
|
228
|
+
invalid: "Invalid value"
|
|
229
|
+
},
|
|
230
|
+
Loading: {
|
|
231
|
+
loadingPage: "Loading page",
|
|
232
|
+
pleaseWait: "Please wait"
|
|
233
|
+
},
|
|
234
|
+
DatePicker: {
|
|
235
|
+
placeholder: "Select date",
|
|
236
|
+
today: "Today",
|
|
237
|
+
clear: "Clear"
|
|
238
|
+
},
|
|
239
|
+
Pagination: {
|
|
240
|
+
navigationLabel: "Pagination navigation",
|
|
241
|
+
showingResults: "Showing {startItem}\u2013{endItem} of {totalItems}",
|
|
242
|
+
firstPage: "First page",
|
|
243
|
+
previousPage: "Previous page",
|
|
244
|
+
previous: "Previous",
|
|
245
|
+
nextPage: "Next page",
|
|
246
|
+
next: "Next",
|
|
247
|
+
lastPage: "Last page",
|
|
248
|
+
pageNumber: "Page {page}",
|
|
249
|
+
itemsPerPage: "Items per page",
|
|
250
|
+
search: "Search",
|
|
251
|
+
noOptions: "No options"
|
|
252
|
+
},
|
|
253
|
+
Form: {
|
|
254
|
+
required: "This field is required"
|
|
255
|
+
},
|
|
256
|
+
OCR: {
|
|
257
|
+
imageUpload: {
|
|
258
|
+
dragDropText: "Drag & drop files here",
|
|
259
|
+
browseFiles: "Browse files",
|
|
260
|
+
supportedFormats: "Supported formats: images"
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
vi: {
|
|
265
|
+
Common: {
|
|
266
|
+
close: "\u0110\xF3ng",
|
|
267
|
+
closeAlert: "\u0110\xF3ng c\u1EA3nh b\xE1o",
|
|
268
|
+
notifications: "Th\xF4ng b\xE1o",
|
|
269
|
+
newNotification: "M\u1EDBi",
|
|
270
|
+
readStatus: "\u0110\xE3 \u0111\u1ECDc",
|
|
271
|
+
openLink: "M\u1EDF li\xEAn k\u1EBFt",
|
|
272
|
+
theme: "Ch\u1EE7 \u0111\u1EC1",
|
|
273
|
+
lightTheme: "Giao di\u1EC7n s\xE1ng",
|
|
274
|
+
darkTheme: "Giao di\u1EC7n t\u1ED1i",
|
|
275
|
+
systemTheme: "Theo h\u1EC7 th\u1ED1ng",
|
|
276
|
+
density: "M\u1EADt \u0111\u1ED9",
|
|
277
|
+
compact: "G\u1ECDn",
|
|
278
|
+
normal: "Th\u01B0\u1EDDng",
|
|
279
|
+
comfortable: "Tho\u1EA3i m\xE1i",
|
|
280
|
+
columns: "C\u1ED9t"
|
|
281
|
+
},
|
|
282
|
+
ValidationInput: {
|
|
283
|
+
required: "Tr\u01B0\u1EDDng n\xE0y l\xE0 b\u1EAFt bu\u1ED9c",
|
|
284
|
+
typeMismatch: "\u0110\u1ECBnh d\u1EA1ng kh\xF4ng h\u1EE3p l\u1EC7",
|
|
285
|
+
pattern: "Sai m\u1EABu",
|
|
286
|
+
tooShort: "Qu\xE1 ng\u1EAFn",
|
|
287
|
+
tooLong: "Qu\xE1 d\xE0i",
|
|
288
|
+
rangeUnderflow: "Nh\u1ECF h\u01A1n gi\xE1 tr\u1ECB t\u1ED1i thi\u1EC3u",
|
|
289
|
+
rangeOverflow: "L\u1EDBn h\u01A1n gi\xE1 tr\u1ECB t\u1ED1i \u0111a",
|
|
290
|
+
stepMismatch: "Sai b\u01B0\u1EDBc",
|
|
291
|
+
badInput: "Gi\xE1 tr\u1ECB kh\xF4ng h\u1EE3p l\u1EC7",
|
|
292
|
+
invalid: "Gi\xE1 tr\u1ECB kh\xF4ng h\u1EE3p l\u1EC7"
|
|
293
|
+
},
|
|
294
|
+
Loading: {
|
|
295
|
+
loadingPage: "\u0110ang t\u1EA3i trang",
|
|
296
|
+
pleaseWait: "Vui l\xF2ng ch\u1EDD"
|
|
297
|
+
},
|
|
298
|
+
DatePicker: {
|
|
299
|
+
placeholder: "Ch\u1ECDn ng\xE0y",
|
|
300
|
+
today: "H\xF4m nay",
|
|
301
|
+
clear: "X\xF3a"
|
|
302
|
+
},
|
|
303
|
+
Pagination: {
|
|
304
|
+
navigationLabel: "\u0110i\u1EC1u h\u01B0\u1EDBng ph\xE2n trang",
|
|
305
|
+
showingResults: "Hi\u1EC3n th\u1ECB {startItem}\u2013{endItem} trong t\u1ED5ng {totalItems}",
|
|
306
|
+
firstPage: "Trang \u0111\u1EA7u",
|
|
307
|
+
previousPage: "Trang tr\u01B0\u1EDBc",
|
|
308
|
+
previous: "Tr\u01B0\u1EDBc",
|
|
309
|
+
nextPage: "Trang sau",
|
|
310
|
+
next: "Sau",
|
|
311
|
+
lastPage: "Trang cu\u1ED1i",
|
|
312
|
+
pageNumber: "Trang {page}",
|
|
313
|
+
itemsPerPage: "S\u1ED1 m\u1EE5c/trang",
|
|
314
|
+
search: "T\xECm ki\u1EBFm",
|
|
315
|
+
noOptions: "Kh\xF4ng c\xF3 l\u1EF1a ch\u1ECDn"
|
|
316
|
+
},
|
|
317
|
+
Form: {
|
|
318
|
+
required: "Tr\u01B0\u1EDDng n\xE0y l\xE0 b\u1EAFt bu\u1ED9c"
|
|
319
|
+
},
|
|
320
|
+
OCR: {
|
|
321
|
+
imageUpload: {
|
|
322
|
+
dragDropText: "K\xE9o & th\u1EA3 \u1EA3nh v\xE0o \u0111\xE2y",
|
|
323
|
+
browseFiles: "Ch\u1ECDn t\u1EC7p",
|
|
324
|
+
supportedFormats: "H\u1ED7 tr\u1EE3 c\xE1c \u0111\u1ECBnh d\u1EA1ng \u1EA3nh"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
ko: {
|
|
329
|
+
Common: {
|
|
330
|
+
close: "\uB2EB\uAE30",
|
|
331
|
+
closeAlert: "\uC54C\uB9BC \uB2EB\uAE30",
|
|
332
|
+
notifications: "\uC54C\uB9BC",
|
|
333
|
+
newNotification: "\uC0C8\uB85C\uC6B4",
|
|
334
|
+
readStatus: "\uC77D\uC74C",
|
|
335
|
+
openLink: "\uB9C1\uD06C \uC5F4\uAE30",
|
|
336
|
+
theme: "\uD14C\uB9C8",
|
|
337
|
+
lightTheme: "\uB77C\uC774\uD2B8",
|
|
338
|
+
darkTheme: "\uB2E4\uD06C",
|
|
339
|
+
systemTheme: "\uC2DC\uC2A4\uD15C",
|
|
340
|
+
density: "\uBC00\uB3C4",
|
|
341
|
+
compact: "\uCEF4\uD329\uD2B8",
|
|
342
|
+
normal: "\uBCF4\uD1B5",
|
|
343
|
+
comfortable: "\uC5EC\uC720",
|
|
344
|
+
columns: "\uC5F4"
|
|
345
|
+
},
|
|
346
|
+
ValidationInput: {
|
|
347
|
+
required: "\uD544\uC218 \uC785\uB825 \uD56D\uBAA9\uC785\uB2C8\uB2E4",
|
|
348
|
+
typeMismatch: "\uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
349
|
+
pattern: "\uD328\uD134\uC774 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
350
|
+
tooShort: "\uB108\uBB34 \uC9E7\uC2B5\uB2C8\uB2E4",
|
|
351
|
+
tooLong: "\uB108\uBB34 \uAE41\uB2C8\uB2E4",
|
|
352
|
+
rangeUnderflow: "\uCD5C\uC19F\uAC12\uBCF4\uB2E4 \uC791\uC2B5\uB2C8\uB2E4",
|
|
353
|
+
rangeOverflow: "\uCD5C\uB313\uAC12\uC744 \uCD08\uACFC\uD588\uC2B5\uB2C8\uB2E4",
|
|
354
|
+
stepMismatch: "\uB2E8\uACC4\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
355
|
+
badInput: "\uC798\uBABB\uB41C \uC785\uB825\uC785\uB2C8\uB2E4",
|
|
356
|
+
invalid: "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC12\uC785\uB2C8\uB2E4"
|
|
357
|
+
},
|
|
358
|
+
Loading: {
|
|
359
|
+
loadingPage: "\uD398\uC774\uC9C0 \uB85C\uB529 \uC911",
|
|
360
|
+
pleaseWait: "\uC7A0\uC2DC\uB9CC \uAE30\uB2E4\uB824 \uC8FC\uC138\uC694"
|
|
361
|
+
},
|
|
362
|
+
DatePicker: {
|
|
363
|
+
placeholder: "\uB0A0\uC9DC \uC120\uD0DD",
|
|
364
|
+
today: "\uC624\uB298",
|
|
365
|
+
clear: "\uC9C0\uC6B0\uAE30"
|
|
366
|
+
},
|
|
367
|
+
Pagination: {
|
|
368
|
+
navigationLabel: "\uD398\uC774\uC9C0 \uB124\uBE44\uAC8C\uC774\uC158",
|
|
369
|
+
showingResults: "{startItem}\u2013{endItem} / \uCD1D {totalItems}\uAC1C",
|
|
370
|
+
firstPage: "\uCCAB \uD398\uC774\uC9C0",
|
|
371
|
+
previousPage: "\uC774\uC804 \uD398\uC774\uC9C0",
|
|
372
|
+
previous: "\uC774\uC804",
|
|
373
|
+
nextPage: "\uB2E4\uC74C \uD398\uC774\uC9C0",
|
|
374
|
+
next: "\uB2E4\uC74C",
|
|
375
|
+
lastPage: "\uB9C8\uC9C0\uB9C9 \uD398\uC774\uC9C0",
|
|
376
|
+
pageNumber: "{page}\uD398\uC774\uC9C0",
|
|
377
|
+
itemsPerPage: "\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218",
|
|
378
|
+
search: "\uAC80\uC0C9",
|
|
379
|
+
noOptions: "\uC635\uC158 \uC5C6\uC74C"
|
|
380
|
+
},
|
|
381
|
+
Form: {
|
|
382
|
+
required: "\uD544\uC218 \uC785\uB825 \uD56D\uBAA9\uC785\uB2C8\uB2E4"
|
|
383
|
+
},
|
|
384
|
+
OCR: {
|
|
385
|
+
imageUpload: {
|
|
386
|
+
dragDropText: "\uC5EC\uAE30\uC5D0 \uD30C\uC77C\uC744 \uB4DC\uB798\uADF8 \uC564 \uB4DC\uB86D\uD558\uC138\uC694",
|
|
387
|
+
browseFiles: "\uD30C\uC77C \uCC3E\uC544\uBCF4\uAE30",
|
|
388
|
+
supportedFormats: "\uC9C0\uC6D0 \uD615\uC2DD: \uC774\uBBF8\uC9C0"
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
ja: {
|
|
393
|
+
Common: {
|
|
394
|
+
close: "\u9589\u3058\u308B",
|
|
395
|
+
closeAlert: "\u30A2\u30E9\u30FC\u30C8\u3092\u9589\u3058\u308B",
|
|
396
|
+
notifications: "\u901A\u77E5",
|
|
397
|
+
newNotification: "\u65B0\u898F",
|
|
398
|
+
readStatus: "\u65E2\u8AAD",
|
|
399
|
+
openLink: "\u30EA\u30F3\u30AF\u3092\u958B\u304F",
|
|
400
|
+
theme: "\u30C6\u30FC\u30DE",
|
|
401
|
+
lightTheme: "\u30E9\u30A4\u30C8",
|
|
402
|
+
darkTheme: "\u30C0\u30FC\u30AF",
|
|
403
|
+
systemTheme: "\u30B7\u30B9\u30C6\u30E0",
|
|
404
|
+
density: "\u5BC6\u5EA6",
|
|
405
|
+
compact: "\u30B3\u30F3\u30D1\u30AF\u30C8",
|
|
406
|
+
normal: "\u901A\u5E38",
|
|
407
|
+
comfortable: "\u3086\u3063\u305F\u308A",
|
|
408
|
+
columns: "\u5217"
|
|
409
|
+
},
|
|
410
|
+
ValidationInput: {
|
|
411
|
+
required: "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059",
|
|
412
|
+
typeMismatch: "\u5F62\u5F0F\u304C\u6B63\u3057\u304F\u3042\u308A\u307E\u305B\u3093",
|
|
413
|
+
pattern: "\u30D1\u30BF\u30FC\u30F3\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093",
|
|
414
|
+
tooShort: "\u77ED\u3059\u304E\u307E\u3059",
|
|
415
|
+
tooLong: "\u9577\u3059\u304E\u307E\u3059",
|
|
416
|
+
rangeUnderflow: "\u6700\u5C0F\u5024\u3088\u308A\u5C0F\u3055\u3044\u3067\u3059",
|
|
417
|
+
rangeOverflow: "\u6700\u5927\u5024\u3092\u8D85\u3048\u3066\u3044\u307E\u3059",
|
|
418
|
+
stepMismatch: "\u30B9\u30C6\u30C3\u30D7\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093",
|
|
419
|
+
badInput: "\u5165\u529B\u304C\u7121\u52B9\u3067\u3059",
|
|
420
|
+
invalid: "\u7121\u52B9\u306A\u5024\u3067\u3059"
|
|
421
|
+
},
|
|
422
|
+
Loading: {
|
|
423
|
+
loadingPage: "\u30DA\u30FC\u30B8\u3092\u8AAD\u307F\u8FBC\u307F\u4E2D",
|
|
424
|
+
pleaseWait: "\u3057\u3070\u3089\u304F\u304A\u5F85\u3061\u304F\u3060\u3055\u3044"
|
|
425
|
+
},
|
|
426
|
+
DatePicker: {
|
|
427
|
+
placeholder: "\u65E5\u4ED8\u3092\u9078\u629E",
|
|
428
|
+
today: "\u4ECA\u65E5",
|
|
429
|
+
clear: "\u30AF\u30EA\u30A2"
|
|
430
|
+
},
|
|
431
|
+
Pagination: {
|
|
432
|
+
navigationLabel: "\u30DA\u30FC\u30B8\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3",
|
|
433
|
+
showingResults: "{startItem}\u2013{endItem} / \u5168{totalItems}\u4EF6",
|
|
434
|
+
firstPage: "\u6700\u521D\u306E\u30DA\u30FC\u30B8",
|
|
435
|
+
previousPage: "\u524D\u306E\u30DA\u30FC\u30B8",
|
|
436
|
+
previous: "\u524D\u3078",
|
|
437
|
+
nextPage: "\u6B21\u306E\u30DA\u30FC\u30B8",
|
|
438
|
+
next: "\u6B21\u3078",
|
|
439
|
+
lastPage: "\u6700\u5F8C\u306E\u30DA\u30FC\u30B8",
|
|
440
|
+
pageNumber: "{page}\u30DA\u30FC\u30B8",
|
|
441
|
+
itemsPerPage: "1\u30DA\u30FC\u30B8\u3042\u305F\u308A\u306E\u9805\u76EE\u6570",
|
|
442
|
+
search: "\u691C\u7D22",
|
|
443
|
+
noOptions: "\u30AA\u30D7\u30B7\u30E7\u30F3\u306A\u3057"
|
|
444
|
+
},
|
|
445
|
+
Form: {
|
|
446
|
+
required: "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059"
|
|
447
|
+
},
|
|
448
|
+
OCR: {
|
|
449
|
+
imageUpload: {
|
|
450
|
+
dragDropText: "\u3053\u3053\u306B\u30D5\u30A1\u30A4\u30EB\u3092\u30C9\u30E9\u30C3\u30B0\uFF06\u30C9\u30ED\u30C3\u30D7",
|
|
451
|
+
browseFiles: "\u30D5\u30A1\u30A4\u30EB\u3092\u53C2\u7167",
|
|
452
|
+
supportedFormats: "\u5BFE\u5FDC\u5F62\u5F0F\uFF1A\u753B\u50CF"
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var TranslationContext = React3.createContext(null);
|
|
458
|
+
var UnderverseProvider = ({ children, locale = "en", translations }) => {
|
|
459
|
+
const t = React3.useCallback(
|
|
460
|
+
(namespace) => {
|
|
461
|
+
return (key) => {
|
|
462
|
+
const mergedTranslations = {
|
|
463
|
+
...defaultTranslations[locale],
|
|
464
|
+
...translations
|
|
465
|
+
};
|
|
466
|
+
const parts = namespace.split(".");
|
|
467
|
+
let current = mergedTranslations;
|
|
468
|
+
for (const part of parts) {
|
|
469
|
+
if (current && typeof current === "object" && part in current) {
|
|
470
|
+
current = current[part];
|
|
471
|
+
} else {
|
|
472
|
+
return key;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (current && typeof current === "object" && key in current) {
|
|
476
|
+
const value = current[key];
|
|
477
|
+
return typeof value === "string" ? value : key;
|
|
478
|
+
}
|
|
479
|
+
return key;
|
|
480
|
+
};
|
|
481
|
+
},
|
|
482
|
+
[locale, translations]
|
|
483
|
+
);
|
|
484
|
+
return /* @__PURE__ */ jsx3(TranslationContext.Provider, { value: { locale, t }, children });
|
|
485
|
+
};
|
|
486
|
+
var nextIntlAvailable = false;
|
|
487
|
+
var nextIntlUseTranslations = null;
|
|
488
|
+
var nextIntlUseLocale = null;
|
|
489
|
+
try {
|
|
490
|
+
const nextIntl = __require("next-intl");
|
|
491
|
+
if (nextIntl && typeof nextIntl.useTranslations === "function") {
|
|
492
|
+
nextIntlAvailable = true;
|
|
493
|
+
nextIntlUseTranslations = nextIntl.useTranslations;
|
|
494
|
+
nextIntlUseLocale = nextIntl.useLocale;
|
|
495
|
+
}
|
|
496
|
+
} catch {
|
|
497
|
+
}
|
|
498
|
+
function interpolate(template, params) {
|
|
499
|
+
if (!params) return template;
|
|
500
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
501
|
+
const value = params[key];
|
|
502
|
+
return value !== void 0 ? String(value) : `{${key}}`;
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
function getInternalTranslation(namespace, locale) {
|
|
506
|
+
return (key, params) => {
|
|
507
|
+
const localeTranslations = defaultTranslations[locale] || defaultTranslations.en;
|
|
508
|
+
const parts = namespace.split(".");
|
|
509
|
+
let current = localeTranslations;
|
|
510
|
+
for (const part of parts) {
|
|
511
|
+
if (current && typeof current === "object" && part in current) {
|
|
512
|
+
current = current[part];
|
|
513
|
+
} else {
|
|
514
|
+
return interpolate(key, params);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (current && typeof current === "object" && key in current) {
|
|
518
|
+
const value = current[key];
|
|
519
|
+
return typeof value === "string" ? interpolate(value, params) : interpolate(key, params);
|
|
520
|
+
}
|
|
521
|
+
return interpolate(key, params);
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function useTranslations(namespace) {
|
|
525
|
+
const underverseContext = React3.useContext(TranslationContext);
|
|
526
|
+
if (underverseContext) {
|
|
527
|
+
return (key, params) => {
|
|
528
|
+
const result = underverseContext.t(namespace)(key);
|
|
529
|
+
return interpolate(result, params);
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
if (nextIntlAvailable && nextIntlUseTranslations) {
|
|
533
|
+
try {
|
|
534
|
+
const nextIntlT = nextIntlUseTranslations(namespace);
|
|
535
|
+
return nextIntlT;
|
|
536
|
+
} catch {
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return getInternalTranslation(namespace, "en");
|
|
540
|
+
}
|
|
541
|
+
function useLocale() {
|
|
542
|
+
const underverseContext = React3.useContext(TranslationContext);
|
|
543
|
+
if (underverseContext) {
|
|
544
|
+
return underverseContext.locale;
|
|
545
|
+
}
|
|
546
|
+
if (nextIntlAvailable && nextIntlUseLocale) {
|
|
547
|
+
try {
|
|
548
|
+
const locale = nextIntlUseLocale();
|
|
549
|
+
return locale === "vi" ? "vi" : "en";
|
|
550
|
+
} catch {
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return "en";
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// ../../components/ui/Input.tsx
|
|
557
|
+
import React4, { forwardRef as forwardRef3, useId, useState as useState3 } from "react";
|
|
558
|
+
import { Eye, EyeOff, Search, X, AlertCircle, CheckCircle, Loader2 } from "lucide-react";
|
|
559
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
560
|
+
var Input = forwardRef3(
|
|
561
|
+
({
|
|
562
|
+
label,
|
|
563
|
+
error,
|
|
564
|
+
description,
|
|
565
|
+
className,
|
|
566
|
+
required,
|
|
567
|
+
variant = "default",
|
|
568
|
+
size = "md",
|
|
569
|
+
leftIcon: LeftIcon,
|
|
570
|
+
rightIcon: RightIcon,
|
|
571
|
+
clearable = false,
|
|
572
|
+
loading = false,
|
|
573
|
+
success = false,
|
|
574
|
+
onClear,
|
|
575
|
+
hint,
|
|
576
|
+
counter = false,
|
|
577
|
+
type = "text",
|
|
578
|
+
value,
|
|
579
|
+
maxLength,
|
|
580
|
+
...rest
|
|
581
|
+
}, ref) => {
|
|
582
|
+
const [localError, setLocalError] = useState3(error);
|
|
583
|
+
const [showPassword, setShowPassword] = useState3(false);
|
|
584
|
+
const [isFocused, setIsFocused] = useState3(false);
|
|
585
|
+
const tv = useTranslations("ValidationInput");
|
|
586
|
+
const autoId = useId();
|
|
587
|
+
const needsId = !!(label || description || hint || error);
|
|
588
|
+
const resolvedId = rest.id || (needsId ? `input-${autoId}` : void 0);
|
|
589
|
+
const errMsg = error || localError;
|
|
590
|
+
const hasValue = value !== void 0 && value !== null && value !== "";
|
|
591
|
+
const charCount = typeof value === "string" ? value.length : 0;
|
|
592
|
+
const errorId = errMsg && resolvedId ? `${resolvedId}-error` : void 0;
|
|
593
|
+
const descId = !errMsg && (description || hint) && resolvedId ? `${resolvedId}-desc` : void 0;
|
|
594
|
+
const containerSpacing = size === "sm" ? "space-y-1.5" : "space-y-2";
|
|
595
|
+
const variantStyles = {
|
|
596
|
+
default: {
|
|
597
|
+
container: "bg-background border border-input hover:border-accent-foreground/20",
|
|
598
|
+
focus: "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
599
|
+
error: "border-destructive focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-destructive focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent"
|
|
600
|
+
},
|
|
601
|
+
filled: {
|
|
602
|
+
container: "bg-muted/50 border border-transparent hover:bg-muted/70",
|
|
603
|
+
focus: "focus-visible:outline-none focus-visible:bg-background focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
604
|
+
error: "bg-destructive/10 border-destructive focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-destructive focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent"
|
|
605
|
+
},
|
|
606
|
+
outlined: {
|
|
607
|
+
container: "bg-transparent border border-border hover:border-accent-foreground/30",
|
|
608
|
+
focus: "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
609
|
+
error: "border-destructive focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-destructive focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent"
|
|
610
|
+
},
|
|
611
|
+
minimal: {
|
|
612
|
+
container: "bg-transparent border-0 border-b border-border hover:border-accent-foreground/30",
|
|
613
|
+
focus: "focus-visible:outline-none focus-visible:border-ring focus-visible:ring-0 rounded-none",
|
|
614
|
+
error: "border-destructive focus-visible:outline-none focus-visible:border-destructive"
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
const sizeStyles = {
|
|
618
|
+
sm: {
|
|
619
|
+
input: "px-3 py-1.5 text-sm h-8 md:h-7 md:py-1 md:text-xs",
|
|
620
|
+
icon: "w-4 h-4",
|
|
621
|
+
button: "h-7 w-7"
|
|
622
|
+
},
|
|
623
|
+
md: {
|
|
624
|
+
input: "px-4 py-2 text-sm h-10",
|
|
625
|
+
icon: "w-5 h-5",
|
|
626
|
+
button: "h-8 w-8"
|
|
627
|
+
},
|
|
628
|
+
lg: {
|
|
629
|
+
input: "px-5 py-4 text-base h-12",
|
|
630
|
+
icon: "w-6 h-6",
|
|
631
|
+
button: "h-10 w-10"
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
const getErrorKey = (v) => {
|
|
635
|
+
if (v.valueMissing) return "required";
|
|
636
|
+
if (v.typeMismatch) return "typeMismatch";
|
|
637
|
+
if (v.patternMismatch) return "pattern";
|
|
638
|
+
if (v.tooShort) return "tooShort";
|
|
639
|
+
if (v.tooLong) return "tooLong";
|
|
640
|
+
if (v.rangeUnderflow) return "rangeUnderflow";
|
|
641
|
+
if (v.rangeOverflow) return "rangeOverflow";
|
|
642
|
+
if (v.stepMismatch) return "stepMismatch";
|
|
643
|
+
if (v.badInput) return "badInput";
|
|
644
|
+
return "invalid";
|
|
645
|
+
};
|
|
646
|
+
const getStatusIcon = () => {
|
|
647
|
+
if (loading) return /* @__PURE__ */ jsx4(Loader2, { className: cn("animate-spin text-muted-foreground", sizeStyles[size].icon) });
|
|
648
|
+
if (success) return /* @__PURE__ */ jsx4(CheckCircle, { className: cn("text-success", sizeStyles[size].icon) });
|
|
649
|
+
if (errMsg) return /* @__PURE__ */ jsx4(AlertCircle, { className: cn("text-destructive", sizeStyles[size].icon) });
|
|
650
|
+
return null;
|
|
651
|
+
};
|
|
652
|
+
const showPasswordToggle = type === "password";
|
|
653
|
+
const actualType = showPasswordToggle && showPassword ? "text" : type;
|
|
654
|
+
const { onFocus: onFocusProp, onBlur: onBlurProp, disabled } = rest;
|
|
655
|
+
const {
|
|
656
|
+
label: _label,
|
|
657
|
+
error: _error,
|
|
658
|
+
description: _description,
|
|
659
|
+
variant: _variant,
|
|
660
|
+
size: _size,
|
|
661
|
+
leftIcon: _leftIcon,
|
|
662
|
+
rightIcon: _rightIcon,
|
|
663
|
+
clearable: _clearable,
|
|
664
|
+
loading: _loading,
|
|
665
|
+
success: _success,
|
|
666
|
+
onClear: _onClear,
|
|
667
|
+
hint: _hint,
|
|
668
|
+
counter: _counter,
|
|
669
|
+
...restInput
|
|
670
|
+
} = rest;
|
|
671
|
+
const handleFocus = (e) => {
|
|
672
|
+
setIsFocused(true);
|
|
673
|
+
onFocusProp?.(e);
|
|
674
|
+
};
|
|
675
|
+
const handleBlur = (e) => {
|
|
676
|
+
setIsFocused(false);
|
|
677
|
+
onBlurProp?.(e);
|
|
678
|
+
};
|
|
679
|
+
const radiusClass = size === "sm" ? "rounded-full" : "rounded-full";
|
|
680
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("w-full group", containerSpacing), children: [
|
|
681
|
+
label && /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between", children: [
|
|
682
|
+
/* @__PURE__ */ jsxs3(
|
|
683
|
+
"label",
|
|
684
|
+
{
|
|
685
|
+
htmlFor: resolvedId,
|
|
686
|
+
className: cn(
|
|
687
|
+
// Label size follows input size
|
|
688
|
+
size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm",
|
|
689
|
+
"font-medium transition-colors duration-200",
|
|
690
|
+
// default color and highlight while any descendant focused
|
|
691
|
+
disabled ? "text-muted-foreground" : cn("text-foreground group-focus-within:text-primary", success && "text-primary"),
|
|
692
|
+
errMsg && "text-destructive"
|
|
693
|
+
),
|
|
694
|
+
children: [
|
|
695
|
+
label,
|
|
696
|
+
required && /* @__PURE__ */ jsx4("span", { className: "text-destructive ml-1", children: "*" })
|
|
697
|
+
]
|
|
698
|
+
}
|
|
699
|
+
),
|
|
700
|
+
counter && maxLength && /* @__PURE__ */ jsxs3(
|
|
701
|
+
"span",
|
|
702
|
+
{
|
|
703
|
+
className: cn(
|
|
704
|
+
"text-xs transition-colors duration-200",
|
|
705
|
+
charCount > maxLength * 0.9 ? "text-warning" : "text-muted-foreground",
|
|
706
|
+
charCount >= maxLength && "text-destructive"
|
|
707
|
+
),
|
|
708
|
+
children: [
|
|
709
|
+
charCount,
|
|
710
|
+
"/",
|
|
711
|
+
maxLength
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
] }),
|
|
716
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative group", children: [
|
|
717
|
+
LeftIcon && /* @__PURE__ */ jsx4(
|
|
718
|
+
"div",
|
|
719
|
+
{
|
|
720
|
+
className: cn(
|
|
721
|
+
"absolute left-3 top-1/2 -translate-y-1/2 z-10",
|
|
722
|
+
"text-muted-foreground transition-colors duration-200",
|
|
723
|
+
// highlight icon when input (or controls) focused
|
|
724
|
+
"group-focus-within:text-primary"
|
|
725
|
+
),
|
|
726
|
+
children: /* @__PURE__ */ jsx4(LeftIcon, { className: sizeStyles[size].icon })
|
|
727
|
+
}
|
|
728
|
+
),
|
|
729
|
+
/* @__PURE__ */ jsx4(
|
|
730
|
+
"input",
|
|
731
|
+
{
|
|
732
|
+
ref,
|
|
733
|
+
type: actualType,
|
|
734
|
+
...value !== void 0 ? { value } : {},
|
|
735
|
+
maxLength,
|
|
736
|
+
required,
|
|
737
|
+
id: resolvedId,
|
|
738
|
+
autoComplete: type === "password" ? "current-password" : type === "email" ? "email" : rest.autoComplete,
|
|
739
|
+
onFocus: handleFocus,
|
|
740
|
+
onBlur: handleBlur,
|
|
741
|
+
onInvalid: (e) => {
|
|
742
|
+
e.preventDefault();
|
|
743
|
+
const key = getErrorKey(e.currentTarget.validity);
|
|
744
|
+
setLocalError(tv(key));
|
|
745
|
+
},
|
|
746
|
+
onInput: () => setLocalError(void 0),
|
|
747
|
+
"aria-invalid": !!errMsg,
|
|
748
|
+
"aria-describedby": [errorId, descId].filter(Boolean).join(" ") || void 0,
|
|
749
|
+
className: cn(
|
|
750
|
+
"w-full text-foreground transition-all duration-200 ease-out",
|
|
751
|
+
"placeholder:text-muted-foreground focus:outline-none focus-visible:outline-none",
|
|
752
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
753
|
+
// Size styles
|
|
754
|
+
sizeStyles[size].input,
|
|
755
|
+
radiusClass,
|
|
756
|
+
// Icon padding adjustments
|
|
757
|
+
LeftIcon && "pl-10",
|
|
758
|
+
(RightIcon || showPasswordToggle || clearable || loading || success || errMsg) && "pr-10",
|
|
759
|
+
// Variant styles
|
|
760
|
+
variantStyles[variant].container,
|
|
761
|
+
errMsg ? variantStyles[variant].error : variantStyles[variant].focus,
|
|
762
|
+
// Reduce visual weight for sm: no default drop shadows
|
|
763
|
+
size !== "sm" && variant !== "minimal" && "shadow-sm",
|
|
764
|
+
size !== "sm" && isFocused && "shadow-md",
|
|
765
|
+
className
|
|
766
|
+
),
|
|
767
|
+
disabled,
|
|
768
|
+
...restInput
|
|
769
|
+
}
|
|
770
|
+
),
|
|
771
|
+
/* @__PURE__ */ jsxs3("div", { className: "absolute right-3 top-1/2 -translate-y-1/2 flex items-center gap-1", children: [
|
|
772
|
+
getStatusIcon(),
|
|
773
|
+
RightIcon && !loading && !success && !errMsg && /* @__PURE__ */ jsx4(RightIcon, { className: cn("text-muted-foreground", sizeStyles[size].icon) }),
|
|
774
|
+
clearable && hasValue && !loading && /* @__PURE__ */ jsx4(
|
|
775
|
+
"button",
|
|
776
|
+
{
|
|
777
|
+
type: "button",
|
|
778
|
+
onClick: () => {
|
|
779
|
+
if (onClear) return onClear();
|
|
780
|
+
rest.onChange?.({ target: { value: "" } });
|
|
781
|
+
},
|
|
782
|
+
className: cn(
|
|
783
|
+
"flex items-center justify-center text-muted-foreground hover:text-foreground transition-colors rounded-md",
|
|
784
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
|
|
785
|
+
"active:bg-accent active:text-accent-foreground",
|
|
786
|
+
sizeStyles[size].button
|
|
787
|
+
),
|
|
788
|
+
tabIndex: 0,
|
|
789
|
+
"aria-label": "Clear input",
|
|
790
|
+
children: /* @__PURE__ */ jsx4(X, { className: sizeStyles[size].icon })
|
|
791
|
+
}
|
|
792
|
+
),
|
|
793
|
+
showPasswordToggle && /* @__PURE__ */ jsx4(
|
|
794
|
+
"button",
|
|
795
|
+
{
|
|
796
|
+
type: "button",
|
|
797
|
+
onClick: () => setShowPassword(!showPassword),
|
|
798
|
+
className: cn(
|
|
799
|
+
"flex items-center justify-center text-muted-foreground hover:text-foreground transition-colors rounded-full",
|
|
800
|
+
"focus:outline-none focus-visible:ring-1 focus-visible:ring-ring/40",
|
|
801
|
+
"active:bg-accent/50 active:text-accent-foreground",
|
|
802
|
+
sizeStyles[size].button
|
|
803
|
+
),
|
|
804
|
+
tabIndex: 0,
|
|
805
|
+
"aria-label": showPassword ? "Hide password" : "Show password",
|
|
806
|
+
children: showPassword ? /* @__PURE__ */ jsx4(EyeOff, { className: sizeStyles[size].icon }) : /* @__PURE__ */ jsx4(Eye, { className: sizeStyles[size].icon })
|
|
807
|
+
}
|
|
808
|
+
)
|
|
809
|
+
] }),
|
|
810
|
+
variant === "minimal" && /* @__PURE__ */ jsx4(
|
|
811
|
+
"div",
|
|
812
|
+
{
|
|
813
|
+
className: cn(
|
|
814
|
+
"absolute bottom-0 left-0 h-0.5 bg-linear-to-r from-primary to-primary/60 transition-all duration-300",
|
|
815
|
+
// default hidden
|
|
816
|
+
"w-0 opacity-0",
|
|
817
|
+
// expand underline when focused within input container
|
|
818
|
+
"group-focus-within:w-full group-focus-within:opacity-100"
|
|
819
|
+
)
|
|
820
|
+
}
|
|
821
|
+
)
|
|
822
|
+
] }),
|
|
823
|
+
errMsg ? /* @__PURE__ */ jsxs3("div", { id: errorId, className: "flex items-center gap-2 text-sm text-destructive animate-in slide-in-from-top-1 duration-200", children: [
|
|
824
|
+
/* @__PURE__ */ jsx4(AlertCircle, { className: "w-4 h-4 shrink-0" }),
|
|
825
|
+
/* @__PURE__ */ jsx4("span", { children: errMsg })
|
|
826
|
+
] }) : null,
|
|
827
|
+
(description || hint) && !errMsg && /* @__PURE__ */ jsx4(
|
|
828
|
+
"p",
|
|
829
|
+
{
|
|
830
|
+
id: descId,
|
|
831
|
+
className: cn(
|
|
832
|
+
"text-xs transition-colors duration-200",
|
|
833
|
+
// follow focus state of the whole field area
|
|
834
|
+
"text-muted-foreground group-focus-within:text-primary/70"
|
|
835
|
+
),
|
|
836
|
+
children: hint || description
|
|
837
|
+
}
|
|
838
|
+
)
|
|
839
|
+
] });
|
|
840
|
+
}
|
|
841
|
+
);
|
|
842
|
+
Input.displayName = "Input";
|
|
843
|
+
var SearchInput = forwardRef3(
|
|
844
|
+
({ onSearch, searchDelay = 300, placeholder = "Search\u2026", ...props }, ref) => {
|
|
845
|
+
const [searchValue, setSearchValue] = useState3(props.value || "");
|
|
846
|
+
React4.useEffect(() => {
|
|
847
|
+
if (!onSearch) return;
|
|
848
|
+
const timer = setTimeout(() => {
|
|
849
|
+
onSearch(searchValue);
|
|
850
|
+
}, searchDelay);
|
|
851
|
+
return () => clearTimeout(timer);
|
|
852
|
+
}, [searchValue, onSearch, searchDelay]);
|
|
853
|
+
return /* @__PURE__ */ jsx4(
|
|
854
|
+
Input,
|
|
855
|
+
{
|
|
856
|
+
ref,
|
|
857
|
+
type: "search",
|
|
858
|
+
leftIcon: Search,
|
|
859
|
+
placeholder,
|
|
860
|
+
clearable: true,
|
|
861
|
+
value: searchValue,
|
|
862
|
+
onChange: (e) => setSearchValue(e.target.value),
|
|
863
|
+
onClear: () => setSearchValue(""),
|
|
864
|
+
...props
|
|
865
|
+
}
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
);
|
|
869
|
+
SearchInput.displayName = "SearchInput";
|
|
870
|
+
var PasswordInput = forwardRef3(
|
|
871
|
+
({ showStrength = false, strengthLabels = ["Weak", "Fair", "Good", "Strong"], ...props }, ref) => {
|
|
872
|
+
const getPasswordStrength = (password) => {
|
|
873
|
+
let score = 0;
|
|
874
|
+
if (password.length >= 8) score++;
|
|
875
|
+
if (/[a-z]/.test(password)) score++;
|
|
876
|
+
if (/[A-Z]/.test(password)) score++;
|
|
877
|
+
if (/[0-9]/.test(password)) score++;
|
|
878
|
+
if (/[^A-Za-z0-9]/.test(password)) score++;
|
|
879
|
+
return Math.min(score, 4);
|
|
880
|
+
};
|
|
881
|
+
const strength = showStrength && typeof props.value === "string" ? getPasswordStrength(props.value) : 0;
|
|
882
|
+
const strengthColors = ["bg-destructive", "bg-warning", "bg-warning", "bg-success"];
|
|
883
|
+
const strengthLabel = strengthLabels[strength - 1];
|
|
884
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
|
|
885
|
+
/* @__PURE__ */ jsx4(Input, { ref, type: "password", ...props }),
|
|
886
|
+
showStrength && props.value && /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
|
|
887
|
+
/* @__PURE__ */ jsx4("div", { className: "flex gap-1", children: [1, 2, 3, 4].map((level) => /* @__PURE__ */ jsx4(
|
|
888
|
+
"div",
|
|
889
|
+
{
|
|
890
|
+
className: cn(
|
|
891
|
+
"h-1 flex-1 rounded-full transition-colors duration-300",
|
|
892
|
+
level <= strength ? strengthColors[strength - 1] : "bg-muted"
|
|
893
|
+
)
|
|
894
|
+
},
|
|
895
|
+
level
|
|
896
|
+
)) }),
|
|
897
|
+
strengthLabel && /* @__PURE__ */ jsx4(
|
|
898
|
+
"p",
|
|
899
|
+
{
|
|
900
|
+
className: cn(
|
|
901
|
+
"text-xs font-medium",
|
|
902
|
+
strength <= 1 ? "text-destructive" : strength <= 2 ? "text-warning" : strength <= 3 ? "text-warning" : "text-success"
|
|
903
|
+
),
|
|
904
|
+
children: strengthLabel
|
|
905
|
+
}
|
|
906
|
+
)
|
|
907
|
+
] })
|
|
908
|
+
] });
|
|
909
|
+
}
|
|
910
|
+
);
|
|
911
|
+
PasswordInput.displayName = "PasswordInput";
|
|
912
|
+
var NumberInput = forwardRef3(
|
|
913
|
+
({ min, max, step = 1, showSteppers = true, onIncrement, onDecrement, formatThousands = false, locale = "vi-VN", value, onChange, ...props }, ref) => {
|
|
914
|
+
const toNumber = (v) => {
|
|
915
|
+
if (v === "" || v === void 0 || v === null) return 0;
|
|
916
|
+
const n = Number(v);
|
|
917
|
+
return Number.isFinite(n) ? n : 0;
|
|
918
|
+
};
|
|
919
|
+
const format = React4.useCallback((n) => new Intl.NumberFormat(locale, { maximumFractionDigits: 0 }).format(n), [locale]);
|
|
920
|
+
const parse = (s) => {
|
|
921
|
+
const digits = (s || "").replace(/\D+/g, "");
|
|
922
|
+
return digits ? Number(digits) : NaN;
|
|
923
|
+
};
|
|
924
|
+
const [displayValue, setDisplayValue] = React4.useState(
|
|
925
|
+
formatThousands ? value !== void 0 && value !== null && value !== "" ? format(toNumber(value)) : "" : String(value ?? "")
|
|
926
|
+
);
|
|
927
|
+
const currentValue = toNumber(value);
|
|
928
|
+
React4.useEffect(() => {
|
|
929
|
+
if (formatThousands) {
|
|
930
|
+
const next = value === "" || value === void 0 || value === null ? "" : format(toNumber(value));
|
|
931
|
+
setDisplayValue((prev) => prev === next ? prev : next);
|
|
932
|
+
} else {
|
|
933
|
+
const next = String(value ?? "");
|
|
934
|
+
setDisplayValue((prev) => prev === next ? prev : next);
|
|
935
|
+
}
|
|
936
|
+
}, [value, formatThousands, locale, format]);
|
|
937
|
+
const handleIncrement = () => {
|
|
938
|
+
if (onIncrement) {
|
|
939
|
+
onIncrement();
|
|
940
|
+
} else if (onChange) {
|
|
941
|
+
const newValue = Math.min(currentValue + step, max ?? Infinity);
|
|
942
|
+
if (formatThousands) setDisplayValue(format(newValue));
|
|
943
|
+
onChange({ target: { value: newValue.toString() } });
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
const handleDecrement = () => {
|
|
947
|
+
if (onDecrement) {
|
|
948
|
+
onDecrement();
|
|
949
|
+
} else if (onChange) {
|
|
950
|
+
const newValue = Math.max(currentValue - step, min ?? -Infinity);
|
|
951
|
+
if (formatThousands) setDisplayValue(format(newValue));
|
|
952
|
+
onChange({ target: { value: newValue.toString() } });
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
return /* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
956
|
+
/* @__PURE__ */ jsx4(
|
|
957
|
+
Input,
|
|
958
|
+
{
|
|
959
|
+
ref,
|
|
960
|
+
type: formatThousands ? "text" : "number",
|
|
961
|
+
min,
|
|
962
|
+
max,
|
|
963
|
+
step,
|
|
964
|
+
rightIcon: showSteppers ? void 0 : props.rightIcon,
|
|
965
|
+
value: displayValue,
|
|
966
|
+
onChange: (e) => {
|
|
967
|
+
if (!onChange) return;
|
|
968
|
+
if (!formatThousands) return onChange(e);
|
|
969
|
+
const raw = e.target.value;
|
|
970
|
+
const parsed = parse(raw);
|
|
971
|
+
if (Number.isNaN(parsed)) {
|
|
972
|
+
setDisplayValue("");
|
|
973
|
+
onChange({ target: { value: "" } });
|
|
974
|
+
} else {
|
|
975
|
+
const bounded = Math.min(Math.max(parsed, min ?? -Infinity), max ?? Infinity);
|
|
976
|
+
setDisplayValue(format(bounded));
|
|
977
|
+
onChange({ target: { value: bounded.toString() } });
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
...props,
|
|
981
|
+
className: cn(
|
|
982
|
+
showSteppers && [
|
|
983
|
+
"pr-12",
|
|
984
|
+
// Hide native browser steppers
|
|
985
|
+
"[&::-webkit-outer-spin-button]:appearance-none",
|
|
986
|
+
"[&::-webkit-inner-spin-button]:appearance-none",
|
|
987
|
+
"[&::-webkit-inner-spin-button]:m-0",
|
|
988
|
+
"appearance-none"
|
|
989
|
+
],
|
|
990
|
+
props.className
|
|
991
|
+
)
|
|
992
|
+
}
|
|
993
|
+
),
|
|
994
|
+
showSteppers && /* @__PURE__ */ jsxs3("div", { className: "absolute right-2 top-1/2 -translate-y-1/2 flex flex-col gap-0.5", children: [
|
|
995
|
+
/* @__PURE__ */ jsx4(
|
|
996
|
+
"button",
|
|
997
|
+
{
|
|
998
|
+
type: "button",
|
|
999
|
+
onClick: handleIncrement,
|
|
1000
|
+
disabled: max !== void 0 && currentValue >= max,
|
|
1001
|
+
className: cn(
|
|
1002
|
+
"flex items-center justify-center w-4 h-4 rounded-md transition-colors",
|
|
1003
|
+
"hover:bg-accent focus:outline-none focus:bg-accent",
|
|
1004
|
+
"disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent",
|
|
1005
|
+
"text-muted-foreground hover:text-foreground"
|
|
1006
|
+
),
|
|
1007
|
+
"aria-label": "Increase value",
|
|
1008
|
+
children: /* @__PURE__ */ jsx4("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", className: "shrink-0", children: /* @__PURE__ */ jsx4("path", { d: "M4 2L6 6H2L4 2Z", fill: "currentColor" }) })
|
|
1009
|
+
}
|
|
1010
|
+
),
|
|
1011
|
+
/* @__PURE__ */ jsx4(
|
|
1012
|
+
"button",
|
|
1013
|
+
{
|
|
1014
|
+
type: "button",
|
|
1015
|
+
onClick: handleDecrement,
|
|
1016
|
+
disabled: min !== void 0 && currentValue <= min,
|
|
1017
|
+
className: cn(
|
|
1018
|
+
"flex items-center justify-center w-4 h-4 rounded-md transition-colors",
|
|
1019
|
+
"hover:bg-accent focus:outline-none focus:bg-accent",
|
|
1020
|
+
"disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent",
|
|
1021
|
+
"text-muted-foreground hover:text-foreground"
|
|
1022
|
+
),
|
|
1023
|
+
"aria-label": "Decrease value",
|
|
1024
|
+
children: /* @__PURE__ */ jsx4("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", className: "shrink-0", children: /* @__PURE__ */ jsx4("path", { d: "M4 6L2 2H6L4 6Z", fill: "currentColor" }) })
|
|
1025
|
+
}
|
|
1026
|
+
)
|
|
1027
|
+
] })
|
|
1028
|
+
] });
|
|
1029
|
+
}
|
|
1030
|
+
);
|
|
1031
|
+
NumberInput.displayName = "NumberInput";
|
|
1032
|
+
var Textarea = forwardRef3(
|
|
1033
|
+
({ label, error, description, variant = "default", resize = "vertical", counter = false, className, required, value, maxLength, ...props }, ref) => {
|
|
1034
|
+
const [isFocused, setIsFocused] = useState3(false);
|
|
1035
|
+
const charCount = typeof value === "string" ? value.length : 0;
|
|
1036
|
+
const variantStyles = {
|
|
1037
|
+
default: "bg-background border border-input hover:border-accent-foreground/20 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
1038
|
+
filled: "bg-muted/50 border border-transparent hover:bg-muted/70 focus-visible:outline-none focus-visible:bg-background focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
1039
|
+
outlined: "bg-transparent border border-border hover:border-accent-foreground/30 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
1040
|
+
minimal: "bg-transparent border-0 border-b border-border hover:border-accent-foreground/30 focus-visible:outline-none focus-visible:border-ring focus-visible:ring-0 rounded-none"
|
|
1041
|
+
};
|
|
1042
|
+
const resizeClasses = {
|
|
1043
|
+
none: "resize-none",
|
|
1044
|
+
vertical: "resize-y",
|
|
1045
|
+
horizontal: "resize-x",
|
|
1046
|
+
both: "resize"
|
|
1047
|
+
};
|
|
1048
|
+
return /* @__PURE__ */ jsxs3("div", { className: "w-full space-y-2", children: [
|
|
1049
|
+
label && /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between", children: [
|
|
1050
|
+
/* @__PURE__ */ jsxs3(
|
|
1051
|
+
"label",
|
|
1052
|
+
{
|
|
1053
|
+
className: cn(
|
|
1054
|
+
"text-sm font-medium transition-colors duration-200",
|
|
1055
|
+
isFocused ? "text-primary" : "text-foreground",
|
|
1056
|
+
error && "text-destructive"
|
|
1057
|
+
),
|
|
1058
|
+
children: [
|
|
1059
|
+
label,
|
|
1060
|
+
required && /* @__PURE__ */ jsx4("span", { className: "text-destructive ml-1", children: "*" })
|
|
1061
|
+
]
|
|
1062
|
+
}
|
|
1063
|
+
),
|
|
1064
|
+
counter && maxLength && /* @__PURE__ */ jsxs3(
|
|
1065
|
+
"span",
|
|
1066
|
+
{
|
|
1067
|
+
className: cn(
|
|
1068
|
+
"text-xs transition-colors duration-200",
|
|
1069
|
+
charCount > maxLength * 0.9 ? "text-warning" : "text-muted-foreground",
|
|
1070
|
+
charCount >= maxLength && "text-destructive"
|
|
1071
|
+
),
|
|
1072
|
+
children: [
|
|
1073
|
+
charCount,
|
|
1074
|
+
"/",
|
|
1075
|
+
maxLength
|
|
1076
|
+
]
|
|
1077
|
+
}
|
|
1078
|
+
)
|
|
1079
|
+
] }),
|
|
1080
|
+
/* @__PURE__ */ jsx4(
|
|
1081
|
+
"textarea",
|
|
1082
|
+
{
|
|
1083
|
+
ref,
|
|
1084
|
+
value,
|
|
1085
|
+
maxLength,
|
|
1086
|
+
required,
|
|
1087
|
+
onFocus: () => setIsFocused(true),
|
|
1088
|
+
onBlur: () => setIsFocused(false),
|
|
1089
|
+
className: cn(
|
|
1090
|
+
"w-full rounded-full px-4 py-3 text-sm text-foreground transition-all duration-200",
|
|
1091
|
+
"placeholder:text-muted-foreground focus:outline-none min-h-20",
|
|
1092
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
1093
|
+
variantStyles[variant],
|
|
1094
|
+
// DÒNG NÀY ĐÃ ĐƯỢC CẬP NHẬT:
|
|
1095
|
+
error && "border-destructive focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-destructive focus-visible:ring-offset-1 focus-visible:ring-offset-background focus-visible:border-transparent",
|
|
1096
|
+
resizeClasses[resize],
|
|
1097
|
+
isFocused && "shadow-md",
|
|
1098
|
+
variant !== "minimal" && "shadow-sm",
|
|
1099
|
+
className
|
|
1100
|
+
),
|
|
1101
|
+
...props
|
|
1102
|
+
}
|
|
1103
|
+
),
|
|
1104
|
+
error && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 text-sm text-destructive animate-in slide-in-from-top-1 duration-200", children: [
|
|
1105
|
+
/* @__PURE__ */ jsx4(AlertCircle, { className: "w-4 h-4 shrink-0" }),
|
|
1106
|
+
/* @__PURE__ */ jsx4("span", { children: error })
|
|
1107
|
+
] }),
|
|
1108
|
+
description && !error && /* @__PURE__ */ jsx4("p", { className: cn("text-xs transition-colors duration-200", isFocused ? "text-primary/70" : "text-muted-foreground"), children: description })
|
|
1109
|
+
] });
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
1112
|
+
Textarea.displayName = "Textarea";
|
|
1113
|
+
var Input_default = Input;
|
|
1114
|
+
|
|
1115
|
+
// ../../components/ui/label.tsx
|
|
1116
|
+
import * as React5 from "react";
|
|
1117
|
+
import { cva } from "class-variance-authority";
|
|
1118
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1119
|
+
var labelVariants = cva(
|
|
1120
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
1121
|
+
);
|
|
1122
|
+
var Label = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
|
|
1123
|
+
"label",
|
|
1124
|
+
{
|
|
1125
|
+
ref,
|
|
1126
|
+
className: cn(labelVariants(), className),
|
|
1127
|
+
...props
|
|
1128
|
+
}
|
|
1129
|
+
));
|
|
1130
|
+
Label.displayName = "Label";
|
|
1131
|
+
|
|
1132
|
+
export {
|
|
1133
|
+
__require,
|
|
1134
|
+
__export,
|
|
1135
|
+
VARIANT_STYLES_BTN,
|
|
1136
|
+
SIZE_STYLES_BTN,
|
|
1137
|
+
cn,
|
|
1138
|
+
Button_default,
|
|
1139
|
+
Checkbox,
|
|
1140
|
+
UnderverseProvider,
|
|
1141
|
+
useTranslations,
|
|
1142
|
+
useLocale,
|
|
1143
|
+
SearchInput,
|
|
1144
|
+
PasswordInput,
|
|
1145
|
+
NumberInput,
|
|
1146
|
+
Input_default,
|
|
1147
|
+
Label
|
|
1148
|
+
};
|
|
1149
|
+
//# sourceMappingURL=chunk-A5NZI37V.js.map
|