@sarunyu/system-one 1.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.
- package/README.md +11 -0
- package/dist/index.cjs +3672 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +3655 -0
- package/dist/index.js.map +1 -0
- package/dist/src/components/button.d.ts +16 -0
- package/dist/src/components/button.d.ts.map +1 -0
- package/dist/src/components/card.d.ts +18 -0
- package/dist/src/components/card.d.ts.map +1 -0
- package/dist/src/components/date-input.d.ts +33 -0
- package/dist/src/components/date-input.d.ts.map +1 -0
- package/dist/src/components/dropdown-multiple.d.ts +28 -0
- package/dist/src/components/dropdown-multiple.d.ts.map +1 -0
- package/dist/src/components/dropdown.d.ts +29 -0
- package/dist/src/components/dropdown.d.ts.map +1 -0
- package/dist/src/components/input.d.ts +15 -0
- package/dist/src/components/input.d.ts.map +1 -0
- package/dist/src/components/option-list.d.ts +19 -0
- package/dist/src/components/option-list.d.ts.map +1 -0
- package/dist/src/components/search-input.d.ts +11 -0
- package/dist/src/components/search-input.d.ts.map +1 -0
- package/dist/src/components/tab.d.ts +24 -0
- package/dist/src/components/tab.d.ts.map +1 -0
- package/dist/src/components/textarea.d.ts +14 -0
- package/dist/src/components/textarea.d.ts.map +1 -0
- package/dist/src/components/time-input.d.ts +36 -0
- package/dist/src/components/time-input.d.ts.map +1 -0
- package/dist/src/components/ui/drawer.d.ts +14 -0
- package/dist/src/components/ui/drawer.d.ts.map +1 -0
- package/dist/src/components/ui/use-mobile.d.ts +2 -0
- package/dist/src/components/ui/use-mobile.d.ts.map +1 -0
- package/dist/src/index.d.ts +25 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/lib/utils.d.ts +3 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/style.css +2 -0
- package/package.json +120 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3672 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const clsx = require("clsx");
|
|
6
|
+
const tailwindMerge = require("tailwind-merge");
|
|
7
|
+
const react = require("@phosphor-icons/react");
|
|
8
|
+
const reactDayPicker = require("react-day-picker");
|
|
9
|
+
const Popover = require("@radix-ui/react-popover");
|
|
10
|
+
const lucideReact = require("lucide-react");
|
|
11
|
+
const vaul = require("vaul");
|
|
12
|
+
function _interopNamespaceDefault(e) {
|
|
13
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
14
|
+
if (e) {
|
|
15
|
+
for (const k in e) {
|
|
16
|
+
if (k !== "default") {
|
|
17
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
18
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: () => e[k]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
n.default = e;
|
|
26
|
+
return Object.freeze(n);
|
|
27
|
+
}
|
|
28
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
29
|
+
const Popover__namespace = /* @__PURE__ */ _interopNamespaceDefault(Popover);
|
|
30
|
+
function cn(...inputs) {
|
|
31
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
32
|
+
}
|
|
33
|
+
const labelIconSizeClass = {
|
|
34
|
+
xs: "size-[13px]",
|
|
35
|
+
sm: "size-[15px]",
|
|
36
|
+
md: "size-[15px]",
|
|
37
|
+
lg: "size-[16px]",
|
|
38
|
+
xl: "size-[16px]"
|
|
39
|
+
};
|
|
40
|
+
const gapClass = {
|
|
41
|
+
xs: "gap-[4px]",
|
|
42
|
+
sm: "gap-[4px]",
|
|
43
|
+
md: "gap-[4px]",
|
|
44
|
+
lg: "gap-[4px]",
|
|
45
|
+
xl: "gap-[4px]"
|
|
46
|
+
};
|
|
47
|
+
const textSizeClass = {
|
|
48
|
+
xs: "text-[12px] leading-[18px]",
|
|
49
|
+
sm: "text-[14px] leading-[20px]",
|
|
50
|
+
md: "text-[14px] leading-[20px]",
|
|
51
|
+
lg: "text-[14px] leading-[20px]",
|
|
52
|
+
xl: "text-[14px] leading-[20px]"
|
|
53
|
+
};
|
|
54
|
+
const roundedLabelClass = {
|
|
55
|
+
xs: "rounded-[4px]",
|
|
56
|
+
sm: "rounded-[6px]",
|
|
57
|
+
md: "rounded-[6px]",
|
|
58
|
+
lg: "rounded-[8px]",
|
|
59
|
+
xl: "rounded-[8px]"
|
|
60
|
+
};
|
|
61
|
+
function getPaddingClasses(size, hasLeft, hasRight) {
|
|
62
|
+
const pyMap = {
|
|
63
|
+
xs: "py-[4px]",
|
|
64
|
+
sm: "py-[4px]",
|
|
65
|
+
md: "py-[6px]",
|
|
66
|
+
lg: "py-[8px]",
|
|
67
|
+
xl: "py-[10px]"
|
|
68
|
+
};
|
|
69
|
+
const pxMap = {
|
|
70
|
+
xs: { l: "pl-[6px]", r: "pr-[6px]" },
|
|
71
|
+
sm: { l: "pl-[8px]", r: "pr-[8px]" },
|
|
72
|
+
md: { l: "pl-[10px]", r: "pr-[10px]" },
|
|
73
|
+
lg: { l: "pl-[14px]", r: "pr-[14px]" },
|
|
74
|
+
xl: { l: "pl-[16px]", r: "pr-[16px]" }
|
|
75
|
+
};
|
|
76
|
+
const reducedMap = {
|
|
77
|
+
xs: { l: "pl-[6px]", r: "pr-[6px]" },
|
|
78
|
+
sm: { l: "pl-[6px]", r: "pr-[6px]" },
|
|
79
|
+
md: { l: "pl-[8px]", r: "pr-[8px]" },
|
|
80
|
+
lg: { l: "pl-[10px]", r: "pr-[10px]" },
|
|
81
|
+
xl: { l: "pl-[12px]", r: "pr-[12px]" }
|
|
82
|
+
};
|
|
83
|
+
return [
|
|
84
|
+
hasLeft ? reducedMap[size].l : pxMap[size].l,
|
|
85
|
+
hasRight ? reducedMap[size].r : pxMap[size].r,
|
|
86
|
+
pyMap[size]
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
const iconSizeSpec = {
|
|
90
|
+
"icon-xs": { btn: "size-[26px]", icon: 16, rounded: "rounded-[4px]" },
|
|
91
|
+
"icon-sm": { btn: "size-[28px]", icon: 18, rounded: "rounded-[6px]" },
|
|
92
|
+
"icon-md": { btn: "size-[32px]", icon: 18, rounded: "rounded-[6px]" },
|
|
93
|
+
"icon-lg": { btn: "size-[36px]", icon: 20, rounded: "rounded-[8px]" },
|
|
94
|
+
"icon-xl": { btn: "size-[40px]", icon: 20, rounded: "rounded-[8px]" }
|
|
95
|
+
};
|
|
96
|
+
function getVariantClasses(variant, isDisabled) {
|
|
97
|
+
if (isDisabled) {
|
|
98
|
+
if (variant === "outline" || variant === "outline-black")
|
|
99
|
+
return "bg-disabled-bg text-disabled border border-border-disabled cursor-not-allowed";
|
|
100
|
+
return "bg-disabled-bg text-disabled cursor-not-allowed";
|
|
101
|
+
}
|
|
102
|
+
if (variant === "outline")
|
|
103
|
+
return "bg-white text-primary-action border border-border hover:bg-hover-bg active:bg-disabled-bg";
|
|
104
|
+
if (variant === "plain")
|
|
105
|
+
return "bg-transparent text-primary-action hover:bg-hover-bg active:bg-disabled-bg";
|
|
106
|
+
if (variant === "outline-black")
|
|
107
|
+
return "bg-white text-foreground border border-border hover:bg-hover-bg";
|
|
108
|
+
if (variant === "plain-black")
|
|
109
|
+
return "bg-transparent text-foreground hover:bg-hover-bg";
|
|
110
|
+
return "bg-primary-action text-white hover:bg-primary-action-hover active:bg-primary-action-active";
|
|
111
|
+
}
|
|
112
|
+
const Button = React.forwardRef(function Button2({
|
|
113
|
+
size = "md",
|
|
114
|
+
variant = "primary",
|
|
115
|
+
children,
|
|
116
|
+
leftIcon,
|
|
117
|
+
rightIcon,
|
|
118
|
+
disabled,
|
|
119
|
+
className = "",
|
|
120
|
+
// Destructure pointer events so we can merge with ghost-icon active handlers
|
|
121
|
+
onPointerDown,
|
|
122
|
+
onPointerUp,
|
|
123
|
+
onPointerLeave,
|
|
124
|
+
...props
|
|
125
|
+
}, ref) {
|
|
126
|
+
const isDisabled = variant === "disabled" || !!disabled;
|
|
127
|
+
const isGhost = variant === "outline-black" || variant === "plain-black";
|
|
128
|
+
const isIconOnly = size.startsWith("icon-");
|
|
129
|
+
const [ghostPressed, setGhostPressed] = React.useState(false);
|
|
130
|
+
const needsGhostPress = isGhost && isIconOnly && !isDisabled;
|
|
131
|
+
const ghostPressStyle = needsGhostPress && ghostPressed ? { backgroundColor: "var(--disabled-bg)", color: "var(--disabled)" } : void 0;
|
|
132
|
+
const handlePointerDown = needsGhostPress ? (e) => {
|
|
133
|
+
setGhostPressed(true);
|
|
134
|
+
onPointerDown == null ? void 0 : onPointerDown(e);
|
|
135
|
+
} : onPointerDown;
|
|
136
|
+
const handlePointerUp = needsGhostPress ? (e) => {
|
|
137
|
+
setGhostPressed(false);
|
|
138
|
+
onPointerUp == null ? void 0 : onPointerUp(e);
|
|
139
|
+
} : onPointerUp;
|
|
140
|
+
const handlePointerLeave = needsGhostPress ? (e) => {
|
|
141
|
+
setGhostPressed(false);
|
|
142
|
+
onPointerLeave == null ? void 0 : onPointerLeave(e);
|
|
143
|
+
} : onPointerLeave;
|
|
144
|
+
const variantClasses = getVariantClasses(variant, isDisabled);
|
|
145
|
+
const cursorClass = isDisabled ? "cursor-not-allowed" : "cursor-pointer";
|
|
146
|
+
const baseClasses = "inline-flex items-center justify-center font-semibold whitespace-nowrap transition-colors duration-150 select-none";
|
|
147
|
+
if (isIconOnly) {
|
|
148
|
+
const spec = iconSizeSpec[size];
|
|
149
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
150
|
+
"button",
|
|
151
|
+
{
|
|
152
|
+
ref,
|
|
153
|
+
className: cn(
|
|
154
|
+
baseClasses,
|
|
155
|
+
spec.rounded,
|
|
156
|
+
spec.btn,
|
|
157
|
+
"shrink-0",
|
|
158
|
+
variantClasses,
|
|
159
|
+
cursorClass,
|
|
160
|
+
className
|
|
161
|
+
),
|
|
162
|
+
style: ghostPressStyle,
|
|
163
|
+
disabled: isDisabled,
|
|
164
|
+
"aria-label": "icon button",
|
|
165
|
+
onPointerDown: handlePointerDown,
|
|
166
|
+
onPointerUp: handlePointerUp,
|
|
167
|
+
onPointerLeave: handlePointerLeave,
|
|
168
|
+
...props,
|
|
169
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
170
|
+
"span",
|
|
171
|
+
{
|
|
172
|
+
className: cn("flex items-center justify-center"),
|
|
173
|
+
"aria-hidden": "true",
|
|
174
|
+
style: { width: spec.icon, height: spec.icon },
|
|
175
|
+
children
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const labelSize = size;
|
|
182
|
+
const hasLeft = Boolean(leftIcon);
|
|
183
|
+
const hasRight = Boolean(rightIcon);
|
|
184
|
+
const paddingParts = getPaddingClasses(labelSize, hasLeft, hasRight);
|
|
185
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
186
|
+
"button",
|
|
187
|
+
{
|
|
188
|
+
ref,
|
|
189
|
+
className: cn(
|
|
190
|
+
baseClasses,
|
|
191
|
+
roundedLabelClass[labelSize],
|
|
192
|
+
paddingParts[0],
|
|
193
|
+
paddingParts[1],
|
|
194
|
+
paddingParts[2],
|
|
195
|
+
hasLeft || hasRight ? gapClass[labelSize] : void 0,
|
|
196
|
+
variantClasses,
|
|
197
|
+
cursorClass,
|
|
198
|
+
textSizeClass[labelSize],
|
|
199
|
+
className
|
|
200
|
+
),
|
|
201
|
+
disabled: isDisabled,
|
|
202
|
+
onPointerDown,
|
|
203
|
+
onPointerUp,
|
|
204
|
+
onPointerLeave,
|
|
205
|
+
...props,
|
|
206
|
+
children: [
|
|
207
|
+
hasLeft && /* @__PURE__ */ jsxRuntime.jsx(
|
|
208
|
+
"span",
|
|
209
|
+
{
|
|
210
|
+
className: cn(
|
|
211
|
+
"flex items-center justify-center shrink-0 overflow-hidden",
|
|
212
|
+
labelIconSizeClass[labelSize]
|
|
213
|
+
),
|
|
214
|
+
"aria-hidden": "true",
|
|
215
|
+
children: leftIcon
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
children ?? "Button",
|
|
219
|
+
hasRight && /* @__PURE__ */ jsxRuntime.jsx(
|
|
220
|
+
"span",
|
|
221
|
+
{
|
|
222
|
+
className: cn(
|
|
223
|
+
"flex items-center justify-center shrink-0 overflow-hidden",
|
|
224
|
+
labelIconSizeClass[labelSize]
|
|
225
|
+
),
|
|
226
|
+
"aria-hidden": "true",
|
|
227
|
+
children: rightIcon
|
|
228
|
+
}
|
|
229
|
+
)
|
|
230
|
+
]
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
Button.displayName = "Button";
|
|
235
|
+
const imgBanner = "";
|
|
236
|
+
function LockIcon() {
|
|
237
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.Lock, { size: 16, weight: "regular", color: "var(--subtle-text)" });
|
|
238
|
+
}
|
|
239
|
+
function CalendarIcon() {
|
|
240
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.CalendarBlank, { size: 16, weight: "regular", color: "var(--accent-orange)" });
|
|
241
|
+
}
|
|
242
|
+
function LocationIcon() {
|
|
243
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.MapPin, { size: 16, weight: "regular", color: "var(--subtle-text)" });
|
|
244
|
+
}
|
|
245
|
+
function AudienceIcon() {
|
|
246
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.Users, { size: 16, weight: "regular", color: "var(--subtle-text)" });
|
|
247
|
+
}
|
|
248
|
+
const tagConfig = {
|
|
249
|
+
"not-registered": {
|
|
250
|
+
bg: "var(--disabled-bg)",
|
|
251
|
+
text: "var(--disabled)",
|
|
252
|
+
label: "ยังไม่ลงทะเบียน"
|
|
253
|
+
},
|
|
254
|
+
registered: {
|
|
255
|
+
bg: "var(--success-bg)",
|
|
256
|
+
text: "var(--success)",
|
|
257
|
+
label: "ลงทะเบียนแล้ว"
|
|
258
|
+
},
|
|
259
|
+
full: {
|
|
260
|
+
bg: "var(--error-bg)",
|
|
261
|
+
text: "var(--destructive)",
|
|
262
|
+
label: "เต็มแล้ว"
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const Card = React.forwardRef(function Card2({
|
|
266
|
+
variant = "desktop",
|
|
267
|
+
title = "Lorem ipsum dolor sit amet consectetur. Lectus viverraasdasd",
|
|
268
|
+
date = "23 มิ.ย. 2567",
|
|
269
|
+
time = "08.30 - 12.00",
|
|
270
|
+
location = "ณ หอประชุมศาสตราจารย์สังเวียน อินทรวิชัย ชั้น 7 ตลาดหลักทรัพย์แห่งประเทศไทย",
|
|
271
|
+
showLocation = true,
|
|
272
|
+
showAudience = true,
|
|
273
|
+
count = "200/200",
|
|
274
|
+
locked = true,
|
|
275
|
+
tagStatus = "not-registered",
|
|
276
|
+
image,
|
|
277
|
+
className
|
|
278
|
+
}, ref) {
|
|
279
|
+
const widthClass = variant === "desktop" ? "w-[308px]" : variant === "tablet" ? "w-[224px]" : "w-[163px]";
|
|
280
|
+
const padding = variant === "desktop" ? "p-[16px]" : variant === "tablet" ? "p-[12px]" : "p-[10px]";
|
|
281
|
+
const titleGap = variant === "desktop" ? "gap-[6px]" : "gap-[4px]";
|
|
282
|
+
const bannerClass = variant === "desktop" ? "h-[173px]" : "aspect-video w-full";
|
|
283
|
+
const tag = tagConfig[tagStatus];
|
|
284
|
+
const bannerSrc = image ?? imgBanner;
|
|
285
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
286
|
+
"div",
|
|
287
|
+
{
|
|
288
|
+
ref,
|
|
289
|
+
className: cn(
|
|
290
|
+
"flex min-h-[120px] flex-col items-start overflow-clip rounded-[8px]",
|
|
291
|
+
"shadow-[0px_0px_2px_0px_rgba(102,102,102,0.16),0px_4px_8px_0px_rgba(102,102,102,0.12)]",
|
|
292
|
+
widthClass,
|
|
293
|
+
className
|
|
294
|
+
),
|
|
295
|
+
children: [
|
|
296
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative w-full shrink-0 overflow-clip", bannerClass), children: [
|
|
297
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
298
|
+
"img",
|
|
299
|
+
{
|
|
300
|
+
alt: "event banner",
|
|
301
|
+
className: "pointer-events-none absolute inset-0 size-full object-cover",
|
|
302
|
+
src: bannerSrc
|
|
303
|
+
}
|
|
304
|
+
),
|
|
305
|
+
locked && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
306
|
+
"div",
|
|
307
|
+
{
|
|
308
|
+
className: cn(
|
|
309
|
+
"absolute left-[8px] top-[8px] flex items-center gap-[4px] rounded-[4px] bg-hover-bg px-[6px] py-[4px]"
|
|
310
|
+
),
|
|
311
|
+
children: [
|
|
312
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
313
|
+
"div",
|
|
314
|
+
{
|
|
315
|
+
"aria-hidden": "true",
|
|
316
|
+
className: "pointer-events-none absolute inset-0 rounded-[4px] border border-solid border-border"
|
|
317
|
+
}
|
|
318
|
+
),
|
|
319
|
+
/* @__PURE__ */ jsxRuntime.jsx(LockIcon, {}),
|
|
320
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-nowrap text-[12px] leading-[18px] text-subtle-text", children: "Lock" })
|
|
321
|
+
]
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
] }),
|
|
325
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full shrink-0 bg-white", padding), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex w-full flex-col items-start", titleGap), children: [
|
|
326
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full flex-col items-start gap-[4px]", children: [
|
|
327
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
328
|
+
"p",
|
|
329
|
+
{
|
|
330
|
+
className: cn(
|
|
331
|
+
"line-clamp-2 w-full overflow-hidden text-ellipsis text-[14px] leading-[20px] text-foreground"
|
|
332
|
+
),
|
|
333
|
+
children: title
|
|
334
|
+
}
|
|
335
|
+
),
|
|
336
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-[8px]", children: [
|
|
337
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-[22px] shrink-0 items-center gap-[4px]", children: [
|
|
338
|
+
/* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, {}),
|
|
339
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-nowrap text-[12px] leading-[16px] text-accent-orange", children: date })
|
|
340
|
+
] }),
|
|
341
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[14px] w-px shrink-0 bg-border" }),
|
|
342
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
343
|
+
"p",
|
|
344
|
+
{
|
|
345
|
+
className: cn(
|
|
346
|
+
"min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-[12px] leading-[16px] text-subtle-text"
|
|
347
|
+
),
|
|
348
|
+
children: time
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
] }),
|
|
352
|
+
showLocation && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-[22px] w-full items-center gap-[4px]", children: [
|
|
353
|
+
/* @__PURE__ */ jsxRuntime.jsx(LocationIcon, {}),
|
|
354
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
355
|
+
"p",
|
|
356
|
+
{
|
|
357
|
+
className: cn(
|
|
358
|
+
"min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-[12px] leading-[16px] text-subtle-text"
|
|
359
|
+
),
|
|
360
|
+
children: location
|
|
361
|
+
}
|
|
362
|
+
)
|
|
363
|
+
] }),
|
|
364
|
+
showAudience && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-[22px] w-full items-center gap-[4px]", children: [
|
|
365
|
+
/* @__PURE__ */ jsxRuntime.jsx(AudienceIcon, {}),
|
|
366
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 whitespace-nowrap text-[12px] leading-[16px] text-subtle-text", children: "ผู้เข้าร่วม" }),
|
|
367
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "shrink-0 whitespace-nowrap text-[12px] leading-[16px] text-primary-action", children: count })
|
|
368
|
+
] })
|
|
369
|
+
] }),
|
|
370
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-start", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
371
|
+
"div",
|
|
372
|
+
{
|
|
373
|
+
className: "flex items-center justify-center gap-[2px] overflow-clip rounded-[4px] px-[8px] py-[4px]",
|
|
374
|
+
style: { backgroundColor: tag.bg },
|
|
375
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-nowrap text-[12px] leading-[16px]", style: { color: tag.text }, children: tag.label })
|
|
376
|
+
}
|
|
377
|
+
) })
|
|
378
|
+
] }) })
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
});
|
|
383
|
+
Card.displayName = "Card";
|
|
384
|
+
const MOBILE_BREAKPOINT = 768;
|
|
385
|
+
function useIsMobile() {
|
|
386
|
+
const [isMobile, setIsMobile] = React__namespace.useState(
|
|
387
|
+
void 0
|
|
388
|
+
);
|
|
389
|
+
React__namespace.useEffect(() => {
|
|
390
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
391
|
+
const onChange = () => {
|
|
392
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
393
|
+
};
|
|
394
|
+
mql.addEventListener("change", onChange);
|
|
395
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
396
|
+
return () => mql.removeEventListener("change", onChange);
|
|
397
|
+
}, []);
|
|
398
|
+
return !!isMobile;
|
|
399
|
+
}
|
|
400
|
+
function Drawer({
|
|
401
|
+
...props
|
|
402
|
+
}) {
|
|
403
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Root, { "data-slot": "drawer", ...props });
|
|
404
|
+
}
|
|
405
|
+
function DrawerTrigger({
|
|
406
|
+
...props
|
|
407
|
+
}) {
|
|
408
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Trigger, { "data-slot": "drawer-trigger", ...props });
|
|
409
|
+
}
|
|
410
|
+
function DrawerPortal({
|
|
411
|
+
...props
|
|
412
|
+
}) {
|
|
413
|
+
return /* @__PURE__ */ jsxRuntime.jsx(vaul.Drawer.Portal, { "data-slot": "drawer-portal", ...props });
|
|
414
|
+
}
|
|
415
|
+
function DrawerOverlay({
|
|
416
|
+
className,
|
|
417
|
+
...props
|
|
418
|
+
}) {
|
|
419
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
420
|
+
vaul.Drawer.Overlay,
|
|
421
|
+
{
|
|
422
|
+
"data-slot": "drawer-overlay",
|
|
423
|
+
className: cn(
|
|
424
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
425
|
+
className
|
|
426
|
+
),
|
|
427
|
+
...props
|
|
428
|
+
}
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
function DrawerContent({
|
|
432
|
+
className,
|
|
433
|
+
children,
|
|
434
|
+
...props
|
|
435
|
+
}) {
|
|
436
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DrawerPortal, { "data-slot": "drawer-portal", children: [
|
|
437
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerOverlay, {}),
|
|
438
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
439
|
+
vaul.Drawer.Content,
|
|
440
|
+
{
|
|
441
|
+
"data-slot": "drawer-content",
|
|
442
|
+
className: cn(
|
|
443
|
+
"group/drawer-content bg-background fixed z-50 flex h-auto flex-col",
|
|
444
|
+
"data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b",
|
|
445
|
+
"data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t",
|
|
446
|
+
"data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm",
|
|
447
|
+
"data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm",
|
|
448
|
+
className
|
|
449
|
+
),
|
|
450
|
+
...props,
|
|
451
|
+
children: [
|
|
452
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" }),
|
|
453
|
+
children
|
|
454
|
+
]
|
|
455
|
+
}
|
|
456
|
+
)
|
|
457
|
+
] });
|
|
458
|
+
}
|
|
459
|
+
function DrawerTitle({
|
|
460
|
+
className,
|
|
461
|
+
...props
|
|
462
|
+
}) {
|
|
463
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
464
|
+
vaul.Drawer.Title,
|
|
465
|
+
{
|
|
466
|
+
"data-slot": "drawer-title",
|
|
467
|
+
className: cn("text-foreground font-semibold", className),
|
|
468
|
+
...props
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
const THAI_MONTHS_SHORT = [
|
|
473
|
+
"ม.ค.",
|
|
474
|
+
"ก.พ.",
|
|
475
|
+
"มี.ค.",
|
|
476
|
+
"เม.ย.",
|
|
477
|
+
"พ.ค.",
|
|
478
|
+
"มิ.ย.",
|
|
479
|
+
"ก.ค.",
|
|
480
|
+
"ส.ค.",
|
|
481
|
+
"ก.ย.",
|
|
482
|
+
"ต.ค.",
|
|
483
|
+
"พ.ย.",
|
|
484
|
+
"ธ.ค."
|
|
485
|
+
];
|
|
486
|
+
const THAI_MONTHS_FULL = [
|
|
487
|
+
"มกราคม",
|
|
488
|
+
"กุมภาพันธ์",
|
|
489
|
+
"มีนาคม",
|
|
490
|
+
"เมษายน",
|
|
491
|
+
"พฤษภาคม",
|
|
492
|
+
"มิถุนายน",
|
|
493
|
+
"กรกฎาคม",
|
|
494
|
+
"สิงหาคม",
|
|
495
|
+
"กันยายน",
|
|
496
|
+
"ตุลาคม",
|
|
497
|
+
"พฤศจิกายน",
|
|
498
|
+
"ธันวาคม"
|
|
499
|
+
];
|
|
500
|
+
const THAI_WEEKDAYS = ["อา", "จ", "อ", "พ", "พฤ", "ศ", "ส"];
|
|
501
|
+
function formatThaiDate(date) {
|
|
502
|
+
return `${date.getDate()} ${THAI_MONTHS_SHORT[date.getMonth()]} ${date.getFullYear() + 543}`;
|
|
503
|
+
}
|
|
504
|
+
const DrawerRangeCtx = React.createContext(false);
|
|
505
|
+
const DisabledDatesCtx = React.createContext({});
|
|
506
|
+
const NAV_BTN_CLASS = cn(
|
|
507
|
+
"h-[28px] w-[28px] inline-flex items-center justify-center",
|
|
508
|
+
"rounded-[6px] bg-transparent border border-border cursor-pointer",
|
|
509
|
+
"text-muted-foreground hover:bg-disabled-bg transition-colors duration-100",
|
|
510
|
+
"p-0 outline-none"
|
|
511
|
+
);
|
|
512
|
+
function CustomCaption({
|
|
513
|
+
displayMonth,
|
|
514
|
+
displayIndex
|
|
515
|
+
}) {
|
|
516
|
+
const { goToMonth, previousMonth, nextMonth, displayMonths } = reactDayPicker.useNavigation();
|
|
517
|
+
const isDrawerRange = React.useContext(DrawerRangeCtx);
|
|
518
|
+
const { disabledYears = [] } = React.useContext(DisabledDatesCtx);
|
|
519
|
+
const [view, setView] = React.useState("days");
|
|
520
|
+
const [pickerYear, setPickerYear] = React.useState(
|
|
521
|
+
displayMonth.getFullYear()
|
|
522
|
+
);
|
|
523
|
+
const [yearRangeStart, setYearRangeStart] = React.useState(
|
|
524
|
+
Math.floor(displayMonth.getFullYear() / 12) * 12
|
|
525
|
+
);
|
|
526
|
+
const isFirst = displayMonths[0].getTime() === displayMonth.getTime();
|
|
527
|
+
const isLast = displayMonths[displayMonths.length - 1].getTime() === displayMonth.getTime();
|
|
528
|
+
const idx = displayIndex ?? 0;
|
|
529
|
+
const handlePrevYear = () => {
|
|
530
|
+
const d = new Date(displayMonth);
|
|
531
|
+
d.setFullYear(d.getFullYear() - 1);
|
|
532
|
+
goToMonth(d);
|
|
533
|
+
};
|
|
534
|
+
const handleNextYear = () => {
|
|
535
|
+
const d = new Date(displayMonth);
|
|
536
|
+
d.setFullYear(d.getFullYear() + 1);
|
|
537
|
+
goToMonth(d);
|
|
538
|
+
};
|
|
539
|
+
if (isDrawerRange && !isFirst) {
|
|
540
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center pt-3 mb-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
541
|
+
"button",
|
|
542
|
+
{
|
|
543
|
+
type: "button",
|
|
544
|
+
className: "text-[14px] leading-[20px] text-foreground font-medium hover:text-primary-action cursor-pointer bg-transparent border-0 outline-none transition-colors",
|
|
545
|
+
onClick: () => {
|
|
546
|
+
setPickerYear(displayMonth.getFullYear());
|
|
547
|
+
setView("months");
|
|
548
|
+
},
|
|
549
|
+
children: [
|
|
550
|
+
THAI_MONTHS_FULL[displayMonth.getMonth()],
|
|
551
|
+
" ",
|
|
552
|
+
displayMonth.getFullYear() + 543
|
|
553
|
+
]
|
|
554
|
+
}
|
|
555
|
+
) });
|
|
556
|
+
}
|
|
557
|
+
let headerText;
|
|
558
|
+
let onHeaderClick;
|
|
559
|
+
if (view === "years") {
|
|
560
|
+
headerText = `${yearRangeStart + 543} - ${yearRangeStart + 11 + 543}`;
|
|
561
|
+
onHeaderClick = () => setView("months");
|
|
562
|
+
} else if (view === "months") {
|
|
563
|
+
headerText = `${pickerYear + 543}`;
|
|
564
|
+
onHeaderClick = () => {
|
|
565
|
+
setYearRangeStart(Math.floor(pickerYear / 12) * 12);
|
|
566
|
+
setView("years");
|
|
567
|
+
};
|
|
568
|
+
} else {
|
|
569
|
+
headerText = `${THAI_MONTHS_FULL[displayMonth.getMonth()]} ${displayMonth.getFullYear() + 543}`;
|
|
570
|
+
onHeaderClick = () => {
|
|
571
|
+
setPickerYear(displayMonth.getFullYear());
|
|
572
|
+
setView("months");
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
let leftNav = null;
|
|
576
|
+
let rightNav = null;
|
|
577
|
+
if (view === "years") {
|
|
578
|
+
leftNav = /* @__PURE__ */ jsxRuntime.jsx(
|
|
579
|
+
"button",
|
|
580
|
+
{
|
|
581
|
+
type: "button",
|
|
582
|
+
className: NAV_BTN_CLASS,
|
|
583
|
+
onClick: () => setYearRangeStart((s) => s - 12),
|
|
584
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16, className: "text-primary-action" })
|
|
585
|
+
}
|
|
586
|
+
);
|
|
587
|
+
rightNav = /* @__PURE__ */ jsxRuntime.jsx(
|
|
588
|
+
"button",
|
|
589
|
+
{
|
|
590
|
+
type: "button",
|
|
591
|
+
className: NAV_BTN_CLASS,
|
|
592
|
+
onClick: () => setYearRangeStart((s) => s + 12),
|
|
593
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 16, className: "text-primary-action" })
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
} else if (view === "months") {
|
|
597
|
+
leftNav = /* @__PURE__ */ jsxRuntime.jsx(
|
|
598
|
+
"button",
|
|
599
|
+
{
|
|
600
|
+
type: "button",
|
|
601
|
+
className: NAV_BTN_CLASS,
|
|
602
|
+
onClick: () => setPickerYear((y) => y - 1),
|
|
603
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16, className: "text-primary-action" })
|
|
604
|
+
}
|
|
605
|
+
);
|
|
606
|
+
rightNav = /* @__PURE__ */ jsxRuntime.jsx(
|
|
607
|
+
"button",
|
|
608
|
+
{
|
|
609
|
+
type: "button",
|
|
610
|
+
className: NAV_BTN_CLASS,
|
|
611
|
+
onClick: () => setPickerYear((y) => y + 1),
|
|
612
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 16, className: "text-primary-action" })
|
|
613
|
+
}
|
|
614
|
+
);
|
|
615
|
+
} else if (isDrawerRange) {
|
|
616
|
+
leftNav = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
617
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
618
|
+
"button",
|
|
619
|
+
{
|
|
620
|
+
type: "button",
|
|
621
|
+
className: NAV_BTN_CLASS,
|
|
622
|
+
onClick: handlePrevYear,
|
|
623
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsLeft, { size: 16, className: "text-primary-action" })
|
|
624
|
+
}
|
|
625
|
+
),
|
|
626
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
627
|
+
"button",
|
|
628
|
+
{
|
|
629
|
+
type: "button",
|
|
630
|
+
className: NAV_BTN_CLASS,
|
|
631
|
+
onClick: () => previousMonth && goToMonth(previousMonth),
|
|
632
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16, className: "text-primary-action" })
|
|
633
|
+
}
|
|
634
|
+
)
|
|
635
|
+
] });
|
|
636
|
+
rightNav = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
637
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
638
|
+
"button",
|
|
639
|
+
{
|
|
640
|
+
type: "button",
|
|
641
|
+
className: NAV_BTN_CLASS,
|
|
642
|
+
onClick: () => nextMonth && goToMonth(nextMonth),
|
|
643
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 16, className: "text-primary-action" })
|
|
644
|
+
}
|
|
645
|
+
),
|
|
646
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
647
|
+
"button",
|
|
648
|
+
{
|
|
649
|
+
type: "button",
|
|
650
|
+
className: NAV_BTN_CLASS,
|
|
651
|
+
onClick: handleNextYear,
|
|
652
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsRight, { size: 16, className: "text-primary-action" })
|
|
653
|
+
}
|
|
654
|
+
)
|
|
655
|
+
] });
|
|
656
|
+
} else {
|
|
657
|
+
if (isFirst) {
|
|
658
|
+
leftNav = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
659
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
660
|
+
"button",
|
|
661
|
+
{
|
|
662
|
+
type: "button",
|
|
663
|
+
className: NAV_BTN_CLASS,
|
|
664
|
+
onClick: handlePrevYear,
|
|
665
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
666
|
+
lucideReact.ChevronsLeft,
|
|
667
|
+
{
|
|
668
|
+
size: 16,
|
|
669
|
+
className: "text-primary-action"
|
|
670
|
+
}
|
|
671
|
+
)
|
|
672
|
+
}
|
|
673
|
+
),
|
|
674
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
675
|
+
"button",
|
|
676
|
+
{
|
|
677
|
+
type: "button",
|
|
678
|
+
className: NAV_BTN_CLASS,
|
|
679
|
+
onClick: () => previousMonth && goToMonth(previousMonth),
|
|
680
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16, className: "text-primary-action" })
|
|
681
|
+
}
|
|
682
|
+
)
|
|
683
|
+
] });
|
|
684
|
+
}
|
|
685
|
+
if (isLast) {
|
|
686
|
+
rightNav = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
687
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
688
|
+
"button",
|
|
689
|
+
{
|
|
690
|
+
type: "button",
|
|
691
|
+
className: NAV_BTN_CLASS,
|
|
692
|
+
onClick: () => nextMonth && goToMonth(nextMonth),
|
|
693
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
694
|
+
lucideReact.ChevronRight,
|
|
695
|
+
{
|
|
696
|
+
size: 16,
|
|
697
|
+
className: "text-primary-action"
|
|
698
|
+
}
|
|
699
|
+
)
|
|
700
|
+
}
|
|
701
|
+
),
|
|
702
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
703
|
+
"button",
|
|
704
|
+
{
|
|
705
|
+
type: "button",
|
|
706
|
+
className: NAV_BTN_CLASS,
|
|
707
|
+
onClick: handleNextYear,
|
|
708
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
709
|
+
lucideReact.ChevronsRight,
|
|
710
|
+
{
|
|
711
|
+
size: 16,
|
|
712
|
+
className: "text-primary-action"
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
}
|
|
716
|
+
)
|
|
717
|
+
] });
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
const now = /* @__PURE__ */ new Date();
|
|
721
|
+
const gridBtnClass = (active, isToday, isItemDisabled = false) => cn(
|
|
722
|
+
"py-[10px] text-[13px] rounded-[6px] border-0 outline-none transition-colors",
|
|
723
|
+
isItemDisabled ? "bg-disabled-bg text-disabled cursor-not-allowed" : active ? "bg-primary-action text-white cursor-pointer" : isToday ? "bg-primary-action-muted text-primary-action cursor-pointer" : "bg-transparent text-foreground hover:bg-disabled-bg cursor-pointer"
|
|
724
|
+
);
|
|
725
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
726
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pt-1 mb-2", children: [
|
|
727
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1", children: leftNav }),
|
|
728
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
729
|
+
"button",
|
|
730
|
+
{
|
|
731
|
+
type: "button",
|
|
732
|
+
className: "text-[14px] leading-[20px] text-foreground font-medium hover:text-primary-action cursor-pointer bg-transparent border-0 outline-none transition-colors",
|
|
733
|
+
onClick: onHeaderClick,
|
|
734
|
+
children: headerText
|
|
735
|
+
}
|
|
736
|
+
),
|
|
737
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1", children: rightNav })
|
|
738
|
+
] }),
|
|
739
|
+
view === "months" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
740
|
+
"div",
|
|
741
|
+
{
|
|
742
|
+
className: "absolute left-0 right-0 z-10 bg-white grid grid-cols-3 gap-1 p-2 content-center",
|
|
743
|
+
style: { top: "42px", bottom: "0" },
|
|
744
|
+
children: THAI_MONTHS_SHORT.map((name, i) => {
|
|
745
|
+
const isCurrent = pickerYear === displayMonth.getFullYear() && i === displayMonth.getMonth();
|
|
746
|
+
const isToday = pickerYear === now.getFullYear() && i === now.getMonth();
|
|
747
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
748
|
+
"button",
|
|
749
|
+
{
|
|
750
|
+
type: "button",
|
|
751
|
+
onClick: () => {
|
|
752
|
+
goToMonth(new Date(pickerYear, i - idx));
|
|
753
|
+
setView("days");
|
|
754
|
+
},
|
|
755
|
+
className: gridBtnClass(isCurrent, isToday),
|
|
756
|
+
children: name
|
|
757
|
+
},
|
|
758
|
+
i
|
|
759
|
+
);
|
|
760
|
+
})
|
|
761
|
+
}
|
|
762
|
+
),
|
|
763
|
+
view === "years" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
764
|
+
"div",
|
|
765
|
+
{
|
|
766
|
+
className: "absolute left-0 right-0 z-10 bg-white grid grid-cols-3 gap-1 p-2 content-center",
|
|
767
|
+
style: { top: "42px", bottom: "0" },
|
|
768
|
+
children: Array.from({ length: 12 }, (_, i) => {
|
|
769
|
+
const year = yearRangeStart + i;
|
|
770
|
+
const isCurrent = year === displayMonth.getFullYear();
|
|
771
|
+
const isToday = year === now.getFullYear();
|
|
772
|
+
const isYearDisabled = disabledYears.includes(year);
|
|
773
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
774
|
+
"button",
|
|
775
|
+
{
|
|
776
|
+
type: "button",
|
|
777
|
+
disabled: isYearDisabled,
|
|
778
|
+
onClick: () => {
|
|
779
|
+
if (isYearDisabled) return;
|
|
780
|
+
setPickerYear(year);
|
|
781
|
+
setView("months");
|
|
782
|
+
},
|
|
783
|
+
className: gridBtnClass(isCurrent, isToday, isYearDisabled),
|
|
784
|
+
children: year + 543
|
|
785
|
+
},
|
|
786
|
+
year
|
|
787
|
+
);
|
|
788
|
+
})
|
|
789
|
+
}
|
|
790
|
+
)
|
|
791
|
+
] });
|
|
792
|
+
}
|
|
793
|
+
const DAY_PICKER_CLASSES = {
|
|
794
|
+
months: "flex flex-col sm:flex-row sm:gap-6",
|
|
795
|
+
month: "space-y-2 relative",
|
|
796
|
+
caption: "flex justify-center pt-1 relative items-center mb-2",
|
|
797
|
+
caption_label: "text-[14px] leading-[20px] text-foreground",
|
|
798
|
+
nav: "hidden",
|
|
799
|
+
nav_button: cn(
|
|
800
|
+
"h-[28px] w-[28px] inline-flex items-center justify-center",
|
|
801
|
+
"rounded-[6px] bg-transparent border border-border cursor-pointer",
|
|
802
|
+
"text-muted-foreground hover:bg-disabled-bg transition-colors duration-100",
|
|
803
|
+
"p-0 outline-none"
|
|
804
|
+
),
|
|
805
|
+
nav_button_previous: "absolute left-1",
|
|
806
|
+
nav_button_next: "absolute right-1",
|
|
807
|
+
table: "w-full border-collapse",
|
|
808
|
+
head_row: "flex",
|
|
809
|
+
head_cell: "w-[36px] h-[32px] inline-flex items-center justify-center text-[12px] text-disabled font-normal",
|
|
810
|
+
row: "flex w-full mt-1",
|
|
811
|
+
cell: cn(
|
|
812
|
+
"h-[36px] w-[36px] text-center p-0 relative overflow-hidden",
|
|
813
|
+
"[&:has(.day-range-middle)]:bg-range-bg",
|
|
814
|
+
"[&:has(.day-range-start)]:bg-range-bg",
|
|
815
|
+
"[&:has(.day-range-end)]:bg-range-bg",
|
|
816
|
+
"[&:has(.day-range-start)]:rounded-l-[6px]",
|
|
817
|
+
"[&:has(.day-range-end)]:rounded-r-[6px]",
|
|
818
|
+
"[&:first-child:has(.day-range-middle)]:rounded-l-[6px]",
|
|
819
|
+
"[&:last-child:has(.day-range-middle)]:rounded-r-[6px]",
|
|
820
|
+
"[&:first-child:has(.day-range-end)]:rounded-l-[6px]",
|
|
821
|
+
"[&:last-child:has(.day-range-start)]:rounded-r-[6px]",
|
|
822
|
+
"focus-within:relative focus-within:z-20"
|
|
823
|
+
),
|
|
824
|
+
day: cn(
|
|
825
|
+
"h-[36px] w-[36px] inline-flex items-center justify-center",
|
|
826
|
+
"text-[14px] text-foreground rounded-[6px]",
|
|
827
|
+
"border-0 bg-transparent cursor-pointer",
|
|
828
|
+
"hover:bg-disabled-bg transition-colors duration-100",
|
|
829
|
+
"outline-none aria-selected:opacity-100 p-0"
|
|
830
|
+
),
|
|
831
|
+
day_range_start: "day-range-start !bg-primary-action !text-white !rounded-l-[6px] !rounded-r-none",
|
|
832
|
+
day_range_end: "day-range-end !bg-primary-action !text-white !rounded-r-[6px] !rounded-l-none",
|
|
833
|
+
day_selected: "!bg-primary-action text-white hover:!bg-primary-action focus:!bg-primary-action rounded-[6px]",
|
|
834
|
+
day_today: "[&:not([aria-selected=true])]:!bg-primary-action-light [&:not([aria-selected=true])]:text-foreground rounded-[6px]",
|
|
835
|
+
day_outside: "day-outside text-disabled opacity-50 aria-selected:bg-transparent aria-selected:opacity-30",
|
|
836
|
+
day_disabled: "text-disabled opacity-50 cursor-not-allowed",
|
|
837
|
+
day_range_middle: "day-range-middle !bg-range-bg !text-range-text !rounded-none",
|
|
838
|
+
day_hidden: "invisible"
|
|
839
|
+
};
|
|
840
|
+
const DRAWER_DAY_PICKER_CLASSES = {
|
|
841
|
+
...DAY_PICKER_CLASSES,
|
|
842
|
+
months: "flex flex-col gap-6 w-full",
|
|
843
|
+
month: "space-y-2 relative w-full",
|
|
844
|
+
table: "w-full border-collapse table-fixed",
|
|
845
|
+
head_row: "flex w-full",
|
|
846
|
+
head_cell: "flex-1 h-[40px] inline-flex items-center justify-center text-[13px] text-disabled font-normal",
|
|
847
|
+
row: "flex w-full mt-1",
|
|
848
|
+
cell: cn(
|
|
849
|
+
"h-[44px] flex-1 text-center p-0 relative overflow-hidden",
|
|
850
|
+
"[&:has(.day-range-middle)]:bg-range-bg",
|
|
851
|
+
"[&:has(.day-range-start)]:bg-range-bg",
|
|
852
|
+
"[&:has(.day-range-end)]:bg-range-bg",
|
|
853
|
+
"[&:has(.day-range-start)]:rounded-l-[8px]",
|
|
854
|
+
"[&:has(.day-range-end)]:rounded-r-[8px]",
|
|
855
|
+
"[&:first-child:has(.day-range-middle)]:rounded-l-[8px]",
|
|
856
|
+
"[&:last-child:has(.day-range-middle)]:rounded-r-[8px]",
|
|
857
|
+
"[&:first-child:has(.day-range-end)]:rounded-l-[8px]",
|
|
858
|
+
"[&:last-child:has(.day-range-start)]:rounded-r-[8px]",
|
|
859
|
+
"focus-within:relative focus-within:z-20"
|
|
860
|
+
),
|
|
861
|
+
day: cn(
|
|
862
|
+
"h-[44px] w-full inline-flex items-center justify-center",
|
|
863
|
+
"text-[16px] text-foreground rounded-[8px]",
|
|
864
|
+
"border-0 bg-transparent cursor-pointer",
|
|
865
|
+
"hover:bg-disabled-bg transition-colors duration-100",
|
|
866
|
+
"outline-none aria-selected:opacity-100 p-0"
|
|
867
|
+
)
|
|
868
|
+
};
|
|
869
|
+
const DATE_ITEM_H = 40;
|
|
870
|
+
const DATE_DRUM_H = 200;
|
|
871
|
+
const DATE_SPACER = (DATE_DRUM_H - DATE_ITEM_H) / 2;
|
|
872
|
+
const SCROLL_YEAR_START = 1950;
|
|
873
|
+
const SCROLL_YEAR_END = 2060;
|
|
874
|
+
const YEAR_ITEMS = Array.from(
|
|
875
|
+
{ length: SCROLL_YEAR_END - SCROLL_YEAR_START + 1 },
|
|
876
|
+
(_, i) => String(SCROLL_YEAR_START + i)
|
|
877
|
+
);
|
|
878
|
+
function getDaysInMonth(year, month) {
|
|
879
|
+
return new Date(year, month, 0).getDate();
|
|
880
|
+
}
|
|
881
|
+
function dateToScrollValue(date) {
|
|
882
|
+
const d = date ?? /* @__PURE__ */ new Date();
|
|
883
|
+
return {
|
|
884
|
+
year: d.getFullYear(),
|
|
885
|
+
month: d.getMonth() + 1,
|
|
886
|
+
day: d.getDate()
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
function scrollValueToDate(v) {
|
|
890
|
+
return new Date(v.year, v.month - 1, v.day);
|
|
891
|
+
}
|
|
892
|
+
function DateScrollColumn({
|
|
893
|
+
items,
|
|
894
|
+
selectedIndex,
|
|
895
|
+
onChange,
|
|
896
|
+
flex = 1
|
|
897
|
+
}) {
|
|
898
|
+
const containerRef = React.useRef(null);
|
|
899
|
+
const debounceRef = React.useRef(void 0);
|
|
900
|
+
const [localIndex, setLocalIndex] = React.useState(selectedIndex);
|
|
901
|
+
const isUserScrolling = React.useRef(false);
|
|
902
|
+
React.useEffect(() => {
|
|
903
|
+
const el = containerRef.current;
|
|
904
|
+
if (el) {
|
|
905
|
+
el.scrollTop = selectedIndex * DATE_ITEM_H;
|
|
906
|
+
setLocalIndex(selectedIndex);
|
|
907
|
+
}
|
|
908
|
+
}, []);
|
|
909
|
+
React.useEffect(() => {
|
|
910
|
+
if (isUserScrolling.current) return;
|
|
911
|
+
const el = containerRef.current;
|
|
912
|
+
if (el) {
|
|
913
|
+
el.scrollTo({
|
|
914
|
+
top: selectedIndex * DATE_ITEM_H,
|
|
915
|
+
behavior: "smooth"
|
|
916
|
+
});
|
|
917
|
+
setLocalIndex(selectedIndex);
|
|
918
|
+
}
|
|
919
|
+
}, [selectedIndex]);
|
|
920
|
+
const handleScroll = React.useCallback(() => {
|
|
921
|
+
isUserScrolling.current = true;
|
|
922
|
+
const el = containerRef.current;
|
|
923
|
+
if (!el) return;
|
|
924
|
+
const rawIdx = el.scrollTop / DATE_ITEM_H;
|
|
925
|
+
const idx = Math.max(
|
|
926
|
+
0,
|
|
927
|
+
Math.min(Math.round(rawIdx), items.length - 1)
|
|
928
|
+
);
|
|
929
|
+
setLocalIndex(idx);
|
|
930
|
+
clearTimeout(debounceRef.current);
|
|
931
|
+
debounceRef.current = setTimeout(() => {
|
|
932
|
+
isUserScrolling.current = false;
|
|
933
|
+
const finalIdx = Math.max(
|
|
934
|
+
0,
|
|
935
|
+
Math.min(
|
|
936
|
+
Math.round(el.scrollTop / DATE_ITEM_H),
|
|
937
|
+
items.length - 1
|
|
938
|
+
)
|
|
939
|
+
);
|
|
940
|
+
el.scrollTo({
|
|
941
|
+
top: finalIdx * DATE_ITEM_H,
|
|
942
|
+
behavior: "smooth"
|
|
943
|
+
});
|
|
944
|
+
onChange(finalIdx);
|
|
945
|
+
setLocalIndex(finalIdx);
|
|
946
|
+
}, 120);
|
|
947
|
+
}, [items.length, onChange]);
|
|
948
|
+
const handleItemClick = React.useCallback(
|
|
949
|
+
(idx) => {
|
|
950
|
+
var _a;
|
|
951
|
+
setLocalIndex(idx);
|
|
952
|
+
onChange(idx);
|
|
953
|
+
(_a = containerRef.current) == null ? void 0 : _a.scrollTo({
|
|
954
|
+
top: idx * DATE_ITEM_H,
|
|
955
|
+
behavior: "smooth"
|
|
956
|
+
});
|
|
957
|
+
},
|
|
958
|
+
[onChange]
|
|
959
|
+
);
|
|
960
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
961
|
+
"div",
|
|
962
|
+
{
|
|
963
|
+
ref: containerRef,
|
|
964
|
+
className: "relative [&::-webkit-scrollbar]:hidden min-w-0",
|
|
965
|
+
style: {
|
|
966
|
+
flex,
|
|
967
|
+
height: DATE_DRUM_H,
|
|
968
|
+
overflowY: "scroll",
|
|
969
|
+
scrollSnapType: "y mandatory",
|
|
970
|
+
scrollbarWidth: "none"
|
|
971
|
+
},
|
|
972
|
+
onScroll: handleScroll,
|
|
973
|
+
children: [
|
|
974
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: DATE_SPACER, flexShrink: 0 } }),
|
|
975
|
+
items.map((label, idx) => {
|
|
976
|
+
const isSel = idx === localIndex;
|
|
977
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
978
|
+
"div",
|
|
979
|
+
{
|
|
980
|
+
style: {
|
|
981
|
+
height: DATE_ITEM_H,
|
|
982
|
+
scrollSnapAlign: "center"
|
|
983
|
+
},
|
|
984
|
+
className: "flex items-center justify-center cursor-pointer select-none",
|
|
985
|
+
onClick: () => handleItemClick(idx),
|
|
986
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
987
|
+
"span",
|
|
988
|
+
{
|
|
989
|
+
style: {
|
|
990
|
+
fontSize: isSel ? 32 : 14,
|
|
991
|
+
lineHeight: 1,
|
|
992
|
+
color: isSel ? "var(--foreground)" : "var(--disabled)",
|
|
993
|
+
transition: "font-size 0.1s, color 0.1s",
|
|
994
|
+
whiteSpace: "nowrap"
|
|
995
|
+
},
|
|
996
|
+
children: label
|
|
997
|
+
}
|
|
998
|
+
)
|
|
999
|
+
},
|
|
1000
|
+
idx
|
|
1001
|
+
);
|
|
1002
|
+
}),
|
|
1003
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: DATE_SPACER, flexShrink: 0 } })
|
|
1004
|
+
]
|
|
1005
|
+
}
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
function ScrollDatePickerContent({
|
|
1009
|
+
value,
|
|
1010
|
+
onChange
|
|
1011
|
+
}) {
|
|
1012
|
+
const daysInMonth = getDaysInMonth(value.year, value.month);
|
|
1013
|
+
const dayItems = Array.from(
|
|
1014
|
+
{ length: daysInMonth },
|
|
1015
|
+
(_, i) => String(i + 1).padStart(2, "0")
|
|
1016
|
+
);
|
|
1017
|
+
const monthIndex = value.month - 1;
|
|
1018
|
+
const dayIndex = Math.min(value.day, daysInMonth) - 1;
|
|
1019
|
+
const yearIndex = value.year - SCROLL_YEAR_START;
|
|
1020
|
+
const handleMonthChange = React.useCallback(
|
|
1021
|
+
(idx) => {
|
|
1022
|
+
const newMonth = idx + 1;
|
|
1023
|
+
const maxDay = getDaysInMonth(value.year, newMonth);
|
|
1024
|
+
onChange({
|
|
1025
|
+
...value,
|
|
1026
|
+
month: newMonth,
|
|
1027
|
+
day: Math.min(value.day, maxDay)
|
|
1028
|
+
});
|
|
1029
|
+
},
|
|
1030
|
+
[value, onChange]
|
|
1031
|
+
);
|
|
1032
|
+
const handleDayChange = React.useCallback(
|
|
1033
|
+
(idx) => {
|
|
1034
|
+
onChange({ ...value, day: idx + 1 });
|
|
1035
|
+
},
|
|
1036
|
+
[value, onChange]
|
|
1037
|
+
);
|
|
1038
|
+
const handleYearChange = React.useCallback(
|
|
1039
|
+
(idx) => {
|
|
1040
|
+
const newYear = SCROLL_YEAR_START + idx;
|
|
1041
|
+
const maxDay = getDaysInMonth(newYear, value.month);
|
|
1042
|
+
onChange({
|
|
1043
|
+
...value,
|
|
1044
|
+
year: newYear,
|
|
1045
|
+
day: Math.min(value.day, maxDay)
|
|
1046
|
+
});
|
|
1047
|
+
},
|
|
1048
|
+
[value, onChange]
|
|
1049
|
+
);
|
|
1050
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
|
|
1051
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1052
|
+
"div",
|
|
1053
|
+
{
|
|
1054
|
+
className: "absolute left-0 right-0 rounded-[4px] bg-selected-light-bg pointer-events-none",
|
|
1055
|
+
style: {
|
|
1056
|
+
top: "50%",
|
|
1057
|
+
transform: "translateY(-50%)",
|
|
1058
|
+
height: DATE_ITEM_H,
|
|
1059
|
+
zIndex: 0
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
),
|
|
1063
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1064
|
+
"div",
|
|
1065
|
+
{
|
|
1066
|
+
className: "relative flex gap-[8px] items-center w-full min-w-[340px] px-4",
|
|
1067
|
+
style: { zIndex: 1 },
|
|
1068
|
+
children: [
|
|
1069
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1070
|
+
DateScrollColumn,
|
|
1071
|
+
{
|
|
1072
|
+
items: THAI_MONTHS_FULL,
|
|
1073
|
+
selectedIndex: monthIndex,
|
|
1074
|
+
onChange: handleMonthChange,
|
|
1075
|
+
flex: 108
|
|
1076
|
+
}
|
|
1077
|
+
),
|
|
1078
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1079
|
+
DateScrollColumn,
|
|
1080
|
+
{
|
|
1081
|
+
items: dayItems,
|
|
1082
|
+
selectedIndex: dayIndex,
|
|
1083
|
+
onChange: handleDayChange,
|
|
1084
|
+
flex: 38
|
|
1085
|
+
}
|
|
1086
|
+
),
|
|
1087
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
|
+
DateScrollColumn,
|
|
1089
|
+
{
|
|
1090
|
+
items: YEAR_ITEMS,
|
|
1091
|
+
selectedIndex: yearIndex,
|
|
1092
|
+
onChange: handleYearChange,
|
|
1093
|
+
flex: 85
|
|
1094
|
+
}
|
|
1095
|
+
)
|
|
1096
|
+
]
|
|
1097
|
+
}
|
|
1098
|
+
)
|
|
1099
|
+
] });
|
|
1100
|
+
}
|
|
1101
|
+
const DateInput = React.forwardRef(
|
|
1102
|
+
function DateInput2({
|
|
1103
|
+
mode = "single",
|
|
1104
|
+
placeholder = "Text label",
|
|
1105
|
+
required = false,
|
|
1106
|
+
forceState,
|
|
1107
|
+
errorMessage = "Error message",
|
|
1108
|
+
helperText,
|
|
1109
|
+
pickerVariant = "calendar",
|
|
1110
|
+
value,
|
|
1111
|
+
onChange,
|
|
1112
|
+
dateRange,
|
|
1113
|
+
onRangeChange,
|
|
1114
|
+
disabledYears,
|
|
1115
|
+
className
|
|
1116
|
+
}, ref) {
|
|
1117
|
+
const [open, setOpen] = React.useState(false);
|
|
1118
|
+
const [internalDate, setInternalDate] = React.useState(void 0);
|
|
1119
|
+
const [internalRange, setInternalRange] = React.useState(void 0);
|
|
1120
|
+
const isMobile = useIsMobile();
|
|
1121
|
+
const [draftDate, setDraftDate] = React.useState(
|
|
1122
|
+
void 0
|
|
1123
|
+
);
|
|
1124
|
+
const [draftRange, setDraftRange] = React.useState(void 0);
|
|
1125
|
+
const [draftScrollValue, setDraftScrollValue] = React.useState(dateToScrollValue(void 0));
|
|
1126
|
+
const isStatic = Boolean(forceState);
|
|
1127
|
+
const isDisabled = forceState === "disabled";
|
|
1128
|
+
const currentDate = value !== void 0 ? value : internalDate;
|
|
1129
|
+
const currentRange = dateRange !== void 0 ? dateRange : internalRange;
|
|
1130
|
+
const state = forceState ?? (open ? "focus" : "default");
|
|
1131
|
+
const isError = state === "error";
|
|
1132
|
+
const isFocus = state === "focus";
|
|
1133
|
+
const isFilled = mode === "single" ? Boolean(currentDate) : Boolean(currentRange == null ? void 0 : currentRange.from);
|
|
1134
|
+
const bgClass = isDisabled ? "bg-disabled-bg" : "bg-white";
|
|
1135
|
+
const labelColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
1136
|
+
const valueColor = isDisabled ? "var(--disabled)" : "var(--foreground)";
|
|
1137
|
+
const iconColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
1138
|
+
const minusColor = isDisabled ? "var(--disabled)" : "var(--foreground)";
|
|
1139
|
+
const asteriskColorEmpty = isDisabled ? "var(--disabled)" : "var(--error-dark)";
|
|
1140
|
+
const asteriskColorFilled = isDisabled ? "var(--disabled)" : "var(--error-dark)";
|
|
1141
|
+
const borderInset = isFocus || isError ? "-1px" : "0px";
|
|
1142
|
+
const borderRad = isFocus || isError ? "9px" : "8px";
|
|
1143
|
+
const borderColor = isDisabled ? "var(--border-disabled)" : isError ? "var(--destructive)" : isFocus ? "var(--primary-action)" : "var(--border)";
|
|
1144
|
+
const showBelow = isError || Boolean(helperText);
|
|
1145
|
+
const leftText = isError ? errorMessage : helperText ?? "";
|
|
1146
|
+
const leftColor = isError ? "var(--error-dark)" : "var(--muted-foreground)";
|
|
1147
|
+
const handleDateSelect = (date) => {
|
|
1148
|
+
setDraftDate(date);
|
|
1149
|
+
};
|
|
1150
|
+
const handleRangeSelect = (range) => {
|
|
1151
|
+
setDraftRange(range);
|
|
1152
|
+
};
|
|
1153
|
+
const handleCancel = () => setOpen(false);
|
|
1154
|
+
const handleConfirm = () => {
|
|
1155
|
+
if (pickerVariant === "scroll") {
|
|
1156
|
+
const d = scrollValueToDate(draftScrollValue);
|
|
1157
|
+
if (value === void 0) setInternalDate(d);
|
|
1158
|
+
onChange == null ? void 0 : onChange(d);
|
|
1159
|
+
} else if (mode === "single") {
|
|
1160
|
+
if (value === void 0) setInternalDate(draftDate);
|
|
1161
|
+
onChange == null ? void 0 : onChange(draftDate);
|
|
1162
|
+
} else {
|
|
1163
|
+
if (dateRange === void 0) setInternalRange(draftRange);
|
|
1164
|
+
onRangeChange == null ? void 0 : onRangeChange(draftRange);
|
|
1165
|
+
}
|
|
1166
|
+
setOpen(false);
|
|
1167
|
+
};
|
|
1168
|
+
const renderContent = () => {
|
|
1169
|
+
if (isFilled) {
|
|
1170
|
+
const floatingLabel = required ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[2px] items-center relative shrink-0 w-full", children: [
|
|
1171
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1172
|
+
"p",
|
|
1173
|
+
{
|
|
1174
|
+
className: "leading-[16px] not-italic relative shrink-0 text-[12px] whitespace-nowrap",
|
|
1175
|
+
style: { color: labelColor },
|
|
1176
|
+
children: placeholder
|
|
1177
|
+
}
|
|
1178
|
+
),
|
|
1179
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1180
|
+
"p",
|
|
1181
|
+
{
|
|
1182
|
+
className: "leading-[1.5] not-italic relative shrink-0 text-[9px] w-[7px]",
|
|
1183
|
+
style: { color: asteriskColorFilled },
|
|
1184
|
+
children: "*"
|
|
1185
|
+
}
|
|
1186
|
+
)
|
|
1187
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1188
|
+
"p",
|
|
1189
|
+
{
|
|
1190
|
+
className: "leading-[16px] not-italic relative shrink-0 text-[12px] w-full",
|
|
1191
|
+
style: { color: labelColor },
|
|
1192
|
+
children: placeholder
|
|
1193
|
+
}
|
|
1194
|
+
);
|
|
1195
|
+
const valueRow = mode === "single" && currentDate ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1196
|
+
"p",
|
|
1197
|
+
{
|
|
1198
|
+
className: "leading-[20px] not-italic relative shrink-0 text-[16px] w-full",
|
|
1199
|
+
style: { color: valueColor },
|
|
1200
|
+
children: formatThaiDate(currentDate)
|
|
1201
|
+
}
|
|
1202
|
+
) : mode === "range" && (currentRange == null ? void 0 : currentRange.from) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[8px] items-center relative shrink-0 w-full", children: [
|
|
1203
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1204
|
+
"p",
|
|
1205
|
+
{
|
|
1206
|
+
className: "leading-[20px] not-italic relative shrink-0 text-[16px] whitespace-nowrap",
|
|
1207
|
+
style: { color: valueColor },
|
|
1208
|
+
children: formatThaiDate(currentRange.from)
|
|
1209
|
+
}
|
|
1210
|
+
),
|
|
1211
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Minus, { size: 20, weight: "bold", color: minusColor }),
|
|
1212
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1213
|
+
"p",
|
|
1214
|
+
{
|
|
1215
|
+
className: "leading-[20px] not-italic relative shrink-0 text-[16px] whitespace-nowrap",
|
|
1216
|
+
style: { color: valueColor },
|
|
1217
|
+
children: currentRange.to ? formatThaiDate(currentRange.to) : "..."
|
|
1218
|
+
}
|
|
1219
|
+
)
|
|
1220
|
+
] }) : null;
|
|
1221
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "content-stretch flex flex-1 flex-col items-center justify-center min-h-px min-w-px relative", children: [
|
|
1222
|
+
floatingLabel,
|
|
1223
|
+
valueRow
|
|
1224
|
+
] });
|
|
1225
|
+
}
|
|
1226
|
+
if (required) {
|
|
1227
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "content-stretch flex flex-1 min-w-px min-h-px gap-[2px] items-center relative", children: [
|
|
1228
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1229
|
+
"p",
|
|
1230
|
+
{
|
|
1231
|
+
className: "leading-[20px] not-italic relative shrink-0 text-[16px] whitespace-nowrap",
|
|
1232
|
+
style: { color: labelColor },
|
|
1233
|
+
children: placeholder
|
|
1234
|
+
}
|
|
1235
|
+
),
|
|
1236
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1237
|
+
"p",
|
|
1238
|
+
{
|
|
1239
|
+
className: "font-normal h-full leading-[1.5] not-italic relative shrink-0 text-[12px] w-[7px]",
|
|
1240
|
+
style: { color: asteriskColorEmpty },
|
|
1241
|
+
children: "*"
|
|
1242
|
+
}
|
|
1243
|
+
)
|
|
1244
|
+
] });
|
|
1245
|
+
}
|
|
1246
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1247
|
+
"p",
|
|
1248
|
+
{
|
|
1249
|
+
className: "flex-1 min-w-0 min-h-px text-[16px] leading-[20px] not-italic overflow-hidden text-ellipsis whitespace-nowrap relative",
|
|
1250
|
+
style: { color: labelColor },
|
|
1251
|
+
children: placeholder
|
|
1252
|
+
}
|
|
1253
|
+
);
|
|
1254
|
+
};
|
|
1255
|
+
const triggerInner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1256
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1257
|
+
"div",
|
|
1258
|
+
{
|
|
1259
|
+
"aria-hidden": "true",
|
|
1260
|
+
className: "absolute pointer-events-none border border-solid",
|
|
1261
|
+
style: {
|
|
1262
|
+
inset: borderInset,
|
|
1263
|
+
borderRadius: borderRad,
|
|
1264
|
+
borderColor
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
),
|
|
1268
|
+
renderContent(),
|
|
1269
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1270
|
+
"div",
|
|
1271
|
+
{
|
|
1272
|
+
className: cn(
|
|
1273
|
+
"flex flex-row items-center shrink-0",
|
|
1274
|
+
isFilled && "self-stretch"
|
|
1275
|
+
),
|
|
1276
|
+
children: isFilled ? /* @__PURE__ */ jsxRuntime.jsx(react.CalendarBlank, { size: 22, weight: "regular", color: iconColor }) : /* @__PURE__ */ jsxRuntime.jsx(react.CalendarBlank, { size: 24, weight: "regular", color: iconColor })
|
|
1277
|
+
}
|
|
1278
|
+
)
|
|
1279
|
+
] });
|
|
1280
|
+
const triggerBaseClasses = cn(
|
|
1281
|
+
"relative flex gap-[8px] items-center rounded-[8px]",
|
|
1282
|
+
bgClass,
|
|
1283
|
+
"px-[14px]",
|
|
1284
|
+
isFilled ? "py-[6px]" : "py-[12px]",
|
|
1285
|
+
"w-full"
|
|
1286
|
+
);
|
|
1287
|
+
const belowMessage = showBelow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start px-[4px] text-[12px] leading-[16px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1288
|
+
"span",
|
|
1289
|
+
{
|
|
1290
|
+
className: "flex-1 min-w-0",
|
|
1291
|
+
style: { color: leftColor },
|
|
1292
|
+
children: leftText
|
|
1293
|
+
}
|
|
1294
|
+
) });
|
|
1295
|
+
if (isStatic) {
|
|
1296
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1297
|
+
"div",
|
|
1298
|
+
{
|
|
1299
|
+
ref,
|
|
1300
|
+
className: cn("flex flex-col gap-[4px] w-full", className),
|
|
1301
|
+
children: [
|
|
1302
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: triggerBaseClasses, children: triggerInner }),
|
|
1303
|
+
belowMessage
|
|
1304
|
+
]
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
const isScrollVariant = pickerVariant === "scroll" && mode === "single";
|
|
1309
|
+
const pickerClasses = isMobile ? DRAWER_DAY_PICKER_CLASSES : DAY_PICKER_CLASSES;
|
|
1310
|
+
const pickerInner = isScrollVariant ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1311
|
+
ScrollDatePickerContent,
|
|
1312
|
+
{
|
|
1313
|
+
value: draftScrollValue,
|
|
1314
|
+
onChange: setDraftScrollValue
|
|
1315
|
+
}
|
|
1316
|
+
) : mode === "single" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1317
|
+
reactDayPicker.DayPicker,
|
|
1318
|
+
{
|
|
1319
|
+
mode: "single",
|
|
1320
|
+
selected: draftDate,
|
|
1321
|
+
onSelect: handleDateSelect,
|
|
1322
|
+
showOutsideDays: true,
|
|
1323
|
+
classNames: pickerClasses,
|
|
1324
|
+
formatters: {
|
|
1325
|
+
formatWeekdayName: (date) => THAI_WEEKDAYS[date.getDay()]
|
|
1326
|
+
},
|
|
1327
|
+
components: { Caption: CustomCaption }
|
|
1328
|
+
}
|
|
1329
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1330
|
+
reactDayPicker.DayPicker,
|
|
1331
|
+
{
|
|
1332
|
+
mode: "range",
|
|
1333
|
+
selected: draftRange,
|
|
1334
|
+
onSelect: handleRangeSelect,
|
|
1335
|
+
numberOfMonths: 2,
|
|
1336
|
+
showOutsideDays: true,
|
|
1337
|
+
classNames: pickerClasses,
|
|
1338
|
+
formatters: {
|
|
1339
|
+
formatWeekdayName: (date) => THAI_WEEKDAYS[date.getDay()]
|
|
1340
|
+
},
|
|
1341
|
+
components: { Caption: CustomCaption }
|
|
1342
|
+
}
|
|
1343
|
+
);
|
|
1344
|
+
const calendarContent = /* @__PURE__ */ jsxRuntime.jsx(DisabledDatesCtx.Provider, { value: { disabledYears }, children: pickerInner });
|
|
1345
|
+
const actionButtons = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[12px] items-center pt-[12px]", children: [
|
|
1346
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1347
|
+
Button,
|
|
1348
|
+
{
|
|
1349
|
+
variant: "outline",
|
|
1350
|
+
size: "lg",
|
|
1351
|
+
className: "flex-1",
|
|
1352
|
+
onClick: handleCancel,
|
|
1353
|
+
children: "ยกเลิก"
|
|
1354
|
+
}
|
|
1355
|
+
),
|
|
1356
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1357
|
+
Button,
|
|
1358
|
+
{
|
|
1359
|
+
variant: "primary",
|
|
1360
|
+
size: "lg",
|
|
1361
|
+
className: "flex-1",
|
|
1362
|
+
onClick: handleConfirm,
|
|
1363
|
+
children: "ตกลง"
|
|
1364
|
+
}
|
|
1365
|
+
)
|
|
1366
|
+
] });
|
|
1367
|
+
const triggerButton = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1368
|
+
"button",
|
|
1369
|
+
{
|
|
1370
|
+
type: "button",
|
|
1371
|
+
disabled: isDisabled,
|
|
1372
|
+
className: cn(triggerBaseClasses, "text-left cursor-pointer disabled:cursor-default"),
|
|
1373
|
+
children: triggerInner
|
|
1374
|
+
}
|
|
1375
|
+
);
|
|
1376
|
+
const handleOpenChange = (o) => {
|
|
1377
|
+
if (!isDisabled) {
|
|
1378
|
+
if (o) {
|
|
1379
|
+
setDraftDate(currentDate);
|
|
1380
|
+
setDraftRange(currentRange);
|
|
1381
|
+
setDraftScrollValue(dateToScrollValue(currentDate));
|
|
1382
|
+
}
|
|
1383
|
+
setOpen(o);
|
|
1384
|
+
}
|
|
1385
|
+
};
|
|
1386
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1387
|
+
"div",
|
|
1388
|
+
{
|
|
1389
|
+
ref,
|
|
1390
|
+
className: cn("flex flex-col gap-[4px] w-full", className),
|
|
1391
|
+
children: [
|
|
1392
|
+
isMobile ? /* @__PURE__ */ jsxRuntime.jsxs(Drawer, { open, onOpenChange: handleOpenChange, children: [
|
|
1393
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerTrigger, { asChild: true, children: triggerButton }),
|
|
1394
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DrawerContent, { children: [
|
|
1395
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerTitle, { className: "sr-only", children: "เลือกวันที่" }),
|
|
1396
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-auto px-4 pt-2 pb-8 w-full", children: [
|
|
1397
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerRangeCtx.Provider, { value: mode === "range", children: calendarContent }),
|
|
1398
|
+
actionButtons
|
|
1399
|
+
] })
|
|
1400
|
+
] })
|
|
1401
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1402
|
+
Popover__namespace.Root,
|
|
1403
|
+
{
|
|
1404
|
+
open,
|
|
1405
|
+
onOpenChange: handleOpenChange,
|
|
1406
|
+
children: [
|
|
1407
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: triggerButton }),
|
|
1408
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1409
|
+
Popover__namespace.Content,
|
|
1410
|
+
{
|
|
1411
|
+
align: "start",
|
|
1412
|
+
sideOffset: 4,
|
|
1413
|
+
className: "z-50 rounded-[8px] bg-white p-3 outline-none",
|
|
1414
|
+
style: {
|
|
1415
|
+
boxShadow: "0px 20px 25px -5px rgba(0,0,0,0.1), 0px 8px 10px -6px rgba(0,0,0,0.1)",
|
|
1416
|
+
border: "1px solid var(--border)"
|
|
1417
|
+
},
|
|
1418
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
1419
|
+
children: [
|
|
1420
|
+
calendarContent,
|
|
1421
|
+
actionButtons
|
|
1422
|
+
]
|
|
1423
|
+
}
|
|
1424
|
+
) })
|
|
1425
|
+
]
|
|
1426
|
+
}
|
|
1427
|
+
),
|
|
1428
|
+
belowMessage
|
|
1429
|
+
]
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
);
|
|
1434
|
+
DateInput.displayName = "DateInput";
|
|
1435
|
+
function ChevronDownIcon$1({ className }) {
|
|
1436
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", className, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 9L11 13L15 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1437
|
+
}
|
|
1438
|
+
function ChevronUpIcon$1({ className }) {
|
|
1439
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", className, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 13L11 9L15 13", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1440
|
+
}
|
|
1441
|
+
const Dropdown = React.forwardRef(
|
|
1442
|
+
({
|
|
1443
|
+
placeholder = "Text label",
|
|
1444
|
+
label,
|
|
1445
|
+
required = false,
|
|
1446
|
+
forceState,
|
|
1447
|
+
errorMessage = "Error message",
|
|
1448
|
+
helperText,
|
|
1449
|
+
value,
|
|
1450
|
+
onChange,
|
|
1451
|
+
options = [],
|
|
1452
|
+
className
|
|
1453
|
+
}, ref) => {
|
|
1454
|
+
var _a;
|
|
1455
|
+
const [open, setOpen] = React.useState(false);
|
|
1456
|
+
const [internalValue, setInternalValue] = React.useState("");
|
|
1457
|
+
const [search, setSearch] = React.useState("");
|
|
1458
|
+
const containerRef = React.useRef(null);
|
|
1459
|
+
const inputRef = React.useRef(null);
|
|
1460
|
+
const controlled = value !== void 0;
|
|
1461
|
+
const currentValue = controlled ? value : internalValue;
|
|
1462
|
+
const isDisabled = forceState === "disabled";
|
|
1463
|
+
const selectedLabel = (_a = options.find((o) => o.value === currentValue)) == null ? void 0 : _a.label;
|
|
1464
|
+
const isFilled = Boolean(selectedLabel);
|
|
1465
|
+
const state = forceState ?? (open ? "focus" : "default");
|
|
1466
|
+
const isError = state === "error";
|
|
1467
|
+
const isFocus = state === "focus";
|
|
1468
|
+
const bg = isDisabled ? "bg-disabled-bg" : "bg-white";
|
|
1469
|
+
const labelColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
1470
|
+
const filledColor = isDisabled ? "var(--disabled)" : "var(--foreground)";
|
|
1471
|
+
const caretClassName = isDisabled ? "text-disabled" : "text-muted-foreground";
|
|
1472
|
+
const hasExternalLabel = Boolean(label);
|
|
1473
|
+
const borderInset = isFocus || isError ? "-1px" : "0px";
|
|
1474
|
+
const borderRad = isFocus || isError ? "9px" : "8px";
|
|
1475
|
+
const borderColor = isDisabled ? "var(--border-disabled)" : isError ? "var(--destructive)" : isFocus ? "var(--primary-action)" : "var(--border)";
|
|
1476
|
+
const showBelow = isError || Boolean(helperText);
|
|
1477
|
+
const leftText = isError ? errorMessage : helperText ?? "";
|
|
1478
|
+
const leftColor = isError ? "var(--destructive)" : "var(--muted-foreground)";
|
|
1479
|
+
const filteredOptions = search.trim() ? options.filter(
|
|
1480
|
+
(o) => o.label.toLowerCase().includes(search.trim().toLowerCase())
|
|
1481
|
+
) : options;
|
|
1482
|
+
React.useEffect(() => {
|
|
1483
|
+
if (open && inputRef.current) {
|
|
1484
|
+
inputRef.current.focus();
|
|
1485
|
+
}
|
|
1486
|
+
}, [open]);
|
|
1487
|
+
React.useEffect(() => {
|
|
1488
|
+
if (!open) setSearch("");
|
|
1489
|
+
}, [open]);
|
|
1490
|
+
React.useEffect(() => {
|
|
1491
|
+
if (!open) return;
|
|
1492
|
+
const handler = (e) => {
|
|
1493
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
1494
|
+
setOpen(false);
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
document.addEventListener("mousedown", handler);
|
|
1498
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
1499
|
+
}, [open]);
|
|
1500
|
+
const handleSelect = (val) => {
|
|
1501
|
+
if (!controlled) setInternalValue(val);
|
|
1502
|
+
onChange == null ? void 0 : onChange(val);
|
|
1503
|
+
setOpen(false);
|
|
1504
|
+
};
|
|
1505
|
+
const handleToggle = () => {
|
|
1506
|
+
if (isDisabled) return;
|
|
1507
|
+
if (forceState) return;
|
|
1508
|
+
setOpen((prev) => !prev);
|
|
1509
|
+
};
|
|
1510
|
+
const handleInputKeyDown = (e) => {
|
|
1511
|
+
if (e.key === "Escape") {
|
|
1512
|
+
setOpen(false);
|
|
1513
|
+
} else if (e.key === "Enter" && filteredOptions.length === 1) {
|
|
1514
|
+
handleSelect(filteredOptions[0].value);
|
|
1515
|
+
}
|
|
1516
|
+
};
|
|
1517
|
+
const Asterisk = ({ color }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "leading-[16px] not-italic text-[12px]", style: { color }, children: [
|
|
1518
|
+
" ",
|
|
1519
|
+
"*"
|
|
1520
|
+
] });
|
|
1521
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1522
|
+
"div",
|
|
1523
|
+
{
|
|
1524
|
+
ref: (node) => {
|
|
1525
|
+
containerRef.current = node;
|
|
1526
|
+
if (typeof ref === "function") ref(node);
|
|
1527
|
+
else if (ref) ref.current = node;
|
|
1528
|
+
},
|
|
1529
|
+
className: cn("flex flex-col gap-[4px] w-full", className),
|
|
1530
|
+
children: [
|
|
1531
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative shrink-0 w-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start px-[4px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "leading-[20px] not-italic relative shrink-0 text-foreground text-[14px] font-bold whitespace-nowrap", children: label }) }) }),
|
|
1532
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1533
|
+
"div",
|
|
1534
|
+
{
|
|
1535
|
+
onClick: handleToggle,
|
|
1536
|
+
className: cn(
|
|
1537
|
+
"relative flex gap-[8px] items-center rounded-[8px] px-[14px]",
|
|
1538
|
+
bg,
|
|
1539
|
+
hasExternalLabel ? "h-[38px]" : isFilled && !open ? "py-[6px]" : "p-[14px]",
|
|
1540
|
+
!isDisabled && !forceState && "cursor-pointer"
|
|
1541
|
+
),
|
|
1542
|
+
children: [
|
|
1543
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1544
|
+
"div",
|
|
1545
|
+
{
|
|
1546
|
+
"aria-hidden": "true",
|
|
1547
|
+
className: "absolute pointer-events-none border border-solid",
|
|
1548
|
+
style: { inset: borderInset, borderRadius: borderRad, borderColor }
|
|
1549
|
+
}
|
|
1550
|
+
),
|
|
1551
|
+
open && !forceState ? (
|
|
1552
|
+
/* ─── Open: search input ─── */
|
|
1553
|
+
hasExternalLabel ? (
|
|
1554
|
+
/* External label + open → single-line search input */
|
|
1555
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1556
|
+
"input",
|
|
1557
|
+
{
|
|
1558
|
+
ref: inputRef,
|
|
1559
|
+
type: "text",
|
|
1560
|
+
value: search,
|
|
1561
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1562
|
+
onKeyDown: handleInputKeyDown,
|
|
1563
|
+
placeholder: isFilled ? selectedLabel : placeholder + (required ? " *" : ""),
|
|
1564
|
+
className: "flex-1 min-w-0 min-h-[1px] text-[14px] leading-[20px] not-italic bg-transparent outline-none border-none p-0 m-0 placeholder:text-disabled",
|
|
1565
|
+
style: {
|
|
1566
|
+
color: filledColor,
|
|
1567
|
+
caretColor: "var(--caret-color)"
|
|
1568
|
+
},
|
|
1569
|
+
onClick: (e) => e.stopPropagation()
|
|
1570
|
+
}
|
|
1571
|
+
)
|
|
1572
|
+
) : isFilled ? (
|
|
1573
|
+
/* Filled + open → floating label + search input */
|
|
1574
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start justify-center flex-1 min-w-0 min-h-[1px]", children: [
|
|
1575
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1576
|
+
"p",
|
|
1577
|
+
{
|
|
1578
|
+
className: "shrink-0 w-full leading-[16px] not-italic text-[12px]",
|
|
1579
|
+
style: { color: labelColor },
|
|
1580
|
+
children: [
|
|
1581
|
+
placeholder,
|
|
1582
|
+
required && /* @__PURE__ */ jsxRuntime.jsx(Asterisk, { color: isDisabled ? "var(--disabled)" : "var(--error-dark)" })
|
|
1583
|
+
]
|
|
1584
|
+
}
|
|
1585
|
+
),
|
|
1586
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1587
|
+
"input",
|
|
1588
|
+
{
|
|
1589
|
+
ref: inputRef,
|
|
1590
|
+
type: "text",
|
|
1591
|
+
value: search,
|
|
1592
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1593
|
+
onKeyDown: handleInputKeyDown,
|
|
1594
|
+
placeholder: selectedLabel,
|
|
1595
|
+
className: "w-full leading-[20px] not-italic text-[14px] min-w-0 bg-transparent outline-none border-none p-0 m-0 placeholder:text-disabled",
|
|
1596
|
+
style: {
|
|
1597
|
+
color: filledColor,
|
|
1598
|
+
caretColor: "var(--caret-color)"
|
|
1599
|
+
},
|
|
1600
|
+
onClick: (e) => e.stopPropagation()
|
|
1601
|
+
}
|
|
1602
|
+
)
|
|
1603
|
+
] })
|
|
1604
|
+
) : (
|
|
1605
|
+
/* Empty + open → inline search input */
|
|
1606
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1607
|
+
"input",
|
|
1608
|
+
{
|
|
1609
|
+
ref: inputRef,
|
|
1610
|
+
type: "text",
|
|
1611
|
+
value: search,
|
|
1612
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1613
|
+
onKeyDown: handleInputKeyDown,
|
|
1614
|
+
placeholder: placeholder + (required ? " *" : ""),
|
|
1615
|
+
className: "flex-1 min-w-0 min-h-[1px] text-[16px] leading-[20px] not-italic bg-transparent outline-none border-none p-0 m-0 placeholder:text-muted-foreground",
|
|
1616
|
+
style: {
|
|
1617
|
+
color: "var(--foreground)",
|
|
1618
|
+
caretColor: "var(--caret-color)"
|
|
1619
|
+
},
|
|
1620
|
+
onClick: (e) => e.stopPropagation()
|
|
1621
|
+
}
|
|
1622
|
+
)
|
|
1623
|
+
)
|
|
1624
|
+
) : isFilled ? (
|
|
1625
|
+
/* ─── Closed + Filled ─── */
|
|
1626
|
+
hasExternalLabel ? (
|
|
1627
|
+
/* External label → single-line selected value */
|
|
1628
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1629
|
+
"p",
|
|
1630
|
+
{
|
|
1631
|
+
className: "flex-1 min-w-0 min-h-[1px] leading-[20px] not-italic text-[14px] overflow-hidden text-ellipsis whitespace-nowrap",
|
|
1632
|
+
style: { color: filledColor },
|
|
1633
|
+
children: [
|
|
1634
|
+
selectedLabel,
|
|
1635
|
+
required && /* @__PURE__ */ jsxRuntime.jsx(Asterisk, { color: isDisabled ? "var(--disabled)" : "var(--error-dark)" })
|
|
1636
|
+
]
|
|
1637
|
+
}
|
|
1638
|
+
)
|
|
1639
|
+
) : (
|
|
1640
|
+
/* Default → floating label + selected value */
|
|
1641
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start justify-center flex-1 min-w-0 min-h-[1px]", children: [
|
|
1642
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1643
|
+
"p",
|
|
1644
|
+
{
|
|
1645
|
+
className: "shrink-0 w-full leading-[16px] not-italic text-[12px]",
|
|
1646
|
+
style: { color: labelColor },
|
|
1647
|
+
children: [
|
|
1648
|
+
placeholder,
|
|
1649
|
+
required && /* @__PURE__ */ jsxRuntime.jsx(Asterisk, { color: isDisabled ? "var(--disabled)" : "var(--error-dark)" })
|
|
1650
|
+
]
|
|
1651
|
+
}
|
|
1652
|
+
),
|
|
1653
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1654
|
+
"p",
|
|
1655
|
+
{
|
|
1656
|
+
className: "w-full leading-[20px] not-italic text-[14px] min-w-0 min-h-[1px]",
|
|
1657
|
+
style: { color: filledColor },
|
|
1658
|
+
children: selectedLabel
|
|
1659
|
+
}
|
|
1660
|
+
)
|
|
1661
|
+
] })
|
|
1662
|
+
)
|
|
1663
|
+
) : (
|
|
1664
|
+
/* ─── Closed + Empty: placeholder ─── */
|
|
1665
|
+
required ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 min-w-0 min-h-[1px] gap-[2px] items-center", children: [
|
|
1666
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1667
|
+
"p",
|
|
1668
|
+
{
|
|
1669
|
+
className: "leading-[20px] not-italic text-[16px] whitespace-nowrap",
|
|
1670
|
+
style: { color: labelColor },
|
|
1671
|
+
children: placeholder
|
|
1672
|
+
}
|
|
1673
|
+
),
|
|
1674
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1675
|
+
"p",
|
|
1676
|
+
{
|
|
1677
|
+
className: "leading-[16px] not-italic text-[12px] w-[7px]",
|
|
1678
|
+
style: { color: isDisabled ? "var(--disabled)" : "var(--error-dark)" },
|
|
1679
|
+
children: "*"
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1682
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1683
|
+
"p",
|
|
1684
|
+
{
|
|
1685
|
+
className: "flex-1 min-w-0 min-h-[1px] text-[16px] leading-[20px] not-italic overflow-hidden text-ellipsis whitespace-nowrap",
|
|
1686
|
+
style: { color: labelColor },
|
|
1687
|
+
children: placeholder
|
|
1688
|
+
}
|
|
1689
|
+
)
|
|
1690
|
+
),
|
|
1691
|
+
isFocus ? /* @__PURE__ */ jsxRuntime.jsx(ChevronUpIcon$1, { className: cn("shrink-0", caretClassName) }) : /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon$1, { className: cn("shrink-0", caretClassName) })
|
|
1692
|
+
]
|
|
1693
|
+
}
|
|
1694
|
+
),
|
|
1695
|
+
open && !forceState && options.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1696
|
+
"div",
|
|
1697
|
+
{
|
|
1698
|
+
className: cn(
|
|
1699
|
+
"relative bg-white rounded-[8px] overflow-clip p-[8px] z-20 flex flex-col items-start",
|
|
1700
|
+
filteredOptions.length > 10 && "overflow-y-auto"
|
|
1701
|
+
),
|
|
1702
|
+
style: {
|
|
1703
|
+
boxShadow: "0px 20px 25px -5px rgba(0,0,0,0.1), 0px 8px 10px -6px rgba(0,0,0,0.1)",
|
|
1704
|
+
...filteredOptions.length > 10 ? { maxHeight: 10 * 48 + 16 } : {}
|
|
1705
|
+
},
|
|
1706
|
+
children: filteredOptions.length > 0 ? filteredOptions.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1707
|
+
"div",
|
|
1708
|
+
{
|
|
1709
|
+
onClick: () => handleSelect(opt.value),
|
|
1710
|
+
className: cn(
|
|
1711
|
+
"w-full shrink-0 rounded-[4px] cursor-pointer transition-colors duration-100",
|
|
1712
|
+
opt.value === currentValue ? "bg-primary-action-light" : "bg-white hover:bg-disabled-bg"
|
|
1713
|
+
),
|
|
1714
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center p-[14px] relative w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1715
|
+
"p",
|
|
1716
|
+
{
|
|
1717
|
+
className: cn(
|
|
1718
|
+
"flex-1 min-w-0 min-h-[1px] leading-[20px] not-italic overflow-hidden text-[14px] text-ellipsis whitespace-nowrap",
|
|
1719
|
+
opt.value === currentValue ? "text-primary-action" : "text-foreground"
|
|
1720
|
+
),
|
|
1721
|
+
children: opt.label
|
|
1722
|
+
}
|
|
1723
|
+
) }) })
|
|
1724
|
+
},
|
|
1725
|
+
opt.value
|
|
1726
|
+
)) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full shrink-0 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center p-[14px] relative w-full", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "flex-1 min-w-0 min-h-[1px] leading-[20px] not-italic text-[14px] text-disabled", children: "No results found" }) }) }) })
|
|
1727
|
+
}
|
|
1728
|
+
),
|
|
1729
|
+
showBelow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start px-[4px] text-[12px] leading-[16px]", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0", style: { color: leftColor }, children: leftText }) })
|
|
1730
|
+
]
|
|
1731
|
+
}
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
);
|
|
1735
|
+
Dropdown.displayName = "Dropdown";
|
|
1736
|
+
const TAG_GAP = 4;
|
|
1737
|
+
const MAX_COMPONENT_WIDTH = 343;
|
|
1738
|
+
function ChevronDownIcon({ className }) {
|
|
1739
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", className, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 9L11 13L15 9", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1740
|
+
}
|
|
1741
|
+
function ChevronUpIcon({ className }) {
|
|
1742
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "22", height: "22", viewBox: "0 0 22 22", fill: "none", className, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 13L11 9L15 13", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
1743
|
+
}
|
|
1744
|
+
function XIcon({ color = "var(--muted-foreground)" }) {
|
|
1745
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1746
|
+
"svg",
|
|
1747
|
+
{
|
|
1748
|
+
width: "12",
|
|
1749
|
+
height: "12",
|
|
1750
|
+
viewBox: "0 0 12 12",
|
|
1751
|
+
fill: "none",
|
|
1752
|
+
className: "shrink-0",
|
|
1753
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1754
|
+
"path",
|
|
1755
|
+
{
|
|
1756
|
+
d: "M9 3L3 9M3 3L9 9",
|
|
1757
|
+
stroke: color,
|
|
1758
|
+
strokeWidth: "1.5",
|
|
1759
|
+
strokeLinecap: "round",
|
|
1760
|
+
strokeLinejoin: "round"
|
|
1761
|
+
}
|
|
1762
|
+
)
|
|
1763
|
+
}
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
function RemovableTag({
|
|
1767
|
+
label,
|
|
1768
|
+
disabled,
|
|
1769
|
+
onRemove,
|
|
1770
|
+
maxWidth
|
|
1771
|
+
}) {
|
|
1772
|
+
const textColor = disabled ? "var(--disabled)" : "var(--subtle-text)";
|
|
1773
|
+
const iconColor = disabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
1774
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1775
|
+
"div",
|
|
1776
|
+
{
|
|
1777
|
+
className: "bg-disabled-bg flex items-center overflow-hidden pl-[8px] pr-[8px] py-[4px] rounded-[4px] shrink-0 relative group",
|
|
1778
|
+
style: maxWidth !== void 0 ? { maxWidth, flexShrink: 1 } : void 0,
|
|
1779
|
+
children: [
|
|
1780
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1781
|
+
"p",
|
|
1782
|
+
{
|
|
1783
|
+
className: "leading-[16px] not-italic text-[12px] whitespace-nowrap overflow-hidden text-ellipsis pr-[4px]",
|
|
1784
|
+
style: { color: textColor },
|
|
1785
|
+
children: [
|
|
1786
|
+
label,
|
|
1787
|
+
" "
|
|
1788
|
+
]
|
|
1789
|
+
}
|
|
1790
|
+
),
|
|
1791
|
+
!disabled && onRemove && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1792
|
+
"button",
|
|
1793
|
+
{
|
|
1794
|
+
type: "button",
|
|
1795
|
+
onClick: (e) => {
|
|
1796
|
+
e.stopPropagation();
|
|
1797
|
+
onRemove();
|
|
1798
|
+
},
|
|
1799
|
+
className: "absolute right-[4px] top-1/2 -translate-y-1/2 flex items-center justify-center rounded-[2px] p-[1px] cursor-pointer opacity-0 group-hover:opacity-100 transition-all duration-150 bg-[#e5e7eb]",
|
|
1800
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(XIcon, { color: iconColor })
|
|
1801
|
+
}
|
|
1802
|
+
)
|
|
1803
|
+
]
|
|
1804
|
+
}
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
function StaticTag({
|
|
1808
|
+
label,
|
|
1809
|
+
disabled,
|
|
1810
|
+
maxWidth
|
|
1811
|
+
}) {
|
|
1812
|
+
const textColor = disabled ? "var(--disabled)" : "var(--subtle-text)";
|
|
1813
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1814
|
+
"div",
|
|
1815
|
+
{
|
|
1816
|
+
className: "bg-disabled-bg flex items-center justify-center overflow-clip px-[8px] py-[4px] rounded-[4px] shrink-0",
|
|
1817
|
+
style: maxWidth !== void 0 ? { maxWidth, flexShrink: 1 } : void 0,
|
|
1818
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1819
|
+
"p",
|
|
1820
|
+
{
|
|
1821
|
+
className: "leading-[16px] not-italic text-[12px] whitespace-nowrap overflow-hidden text-ellipsis",
|
|
1822
|
+
style: { color: textColor },
|
|
1823
|
+
children: label
|
|
1824
|
+
}
|
|
1825
|
+
)
|
|
1826
|
+
}
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
function OverflowBadge({
|
|
1830
|
+
count,
|
|
1831
|
+
disabled
|
|
1832
|
+
}) {
|
|
1833
|
+
const bg = disabled ? "bg-[#fafafa]" : "bg-selected-bg";
|
|
1834
|
+
const textColor = disabled ? "var(--disabled)" : "var(--primary-action)";
|
|
1835
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1836
|
+
"div",
|
|
1837
|
+
{
|
|
1838
|
+
className: cn(
|
|
1839
|
+
bg,
|
|
1840
|
+
"flex items-center justify-center overflow-clip px-[8px] py-[4px] rounded-[4px] shrink-0"
|
|
1841
|
+
),
|
|
1842
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1843
|
+
"p",
|
|
1844
|
+
{
|
|
1845
|
+
className: "leading-[16px] not-italic text-[12px] whitespace-nowrap",
|
|
1846
|
+
style: { color: textColor },
|
|
1847
|
+
children: [
|
|
1848
|
+
"+",
|
|
1849
|
+
count
|
|
1850
|
+
]
|
|
1851
|
+
}
|
|
1852
|
+
)
|
|
1853
|
+
}
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
function CheckIcon$1(props) {
|
|
1857
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1858
|
+
"svg",
|
|
1859
|
+
{
|
|
1860
|
+
width: "10",
|
|
1861
|
+
height: "8",
|
|
1862
|
+
viewBox: "0 0 10 8",
|
|
1863
|
+
fill: "none",
|
|
1864
|
+
...props,
|
|
1865
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1866
|
+
"path",
|
|
1867
|
+
{
|
|
1868
|
+
d: "M1 4L3.5 6.5L9 1",
|
|
1869
|
+
stroke: "currentColor",
|
|
1870
|
+
strokeWidth: "1.5",
|
|
1871
|
+
strokeLinecap: "round",
|
|
1872
|
+
strokeLinejoin: "round"
|
|
1873
|
+
}
|
|
1874
|
+
)
|
|
1875
|
+
}
|
|
1876
|
+
);
|
|
1877
|
+
}
|
|
1878
|
+
function useChipLayout(selectedOptions, measureRef, containerRef) {
|
|
1879
|
+
const [layout, setLayout] = React.useState({
|
|
1880
|
+
visibleCount: selectedOptions.length,
|
|
1881
|
+
lastTagMaxWidth: void 0
|
|
1882
|
+
});
|
|
1883
|
+
React.useLayoutEffect(() => {
|
|
1884
|
+
var _a, _b;
|
|
1885
|
+
const calculate = () => {
|
|
1886
|
+
var _a2, _b2;
|
|
1887
|
+
const total = selectedOptions.length;
|
|
1888
|
+
if (!measureRef.current || total === 0) {
|
|
1889
|
+
setLayout({
|
|
1890
|
+
visibleCount: total,
|
|
1891
|
+
lastTagMaxWidth: void 0
|
|
1892
|
+
});
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
const tagEls = Array.from(
|
|
1896
|
+
measureRef.current.children
|
|
1897
|
+
);
|
|
1898
|
+
const containerWidth = ((_a2 = containerRef.current) == null ? void 0 : _a2.offsetWidth) ?? MAX_COMPONENT_WIDTH;
|
|
1899
|
+
const RIGHT_SECTION_WIDTH = 60;
|
|
1900
|
+
const budget = containerWidth * 0.72 - RIGHT_SECTION_WIDTH;
|
|
1901
|
+
let used = 0;
|
|
1902
|
+
let count = 0;
|
|
1903
|
+
for (let i = 0; i < tagEls.length; i++) {
|
|
1904
|
+
const w = tagEls[i].offsetWidth;
|
|
1905
|
+
const gap = count > 0 ? TAG_GAP : 0;
|
|
1906
|
+
const nextUsed = used + gap + w;
|
|
1907
|
+
if (nextUsed <= budget) {
|
|
1908
|
+
used = nextUsed;
|
|
1909
|
+
count++;
|
|
1910
|
+
} else {
|
|
1911
|
+
count++;
|
|
1912
|
+
break;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
count = Math.max(1, count);
|
|
1916
|
+
const overflowCount = total - count;
|
|
1917
|
+
const isFullWidth = used >= budget * 0.98;
|
|
1918
|
+
let lastTagMaxWidth;
|
|
1919
|
+
if (overflowCount > 0 || isFullWidth) {
|
|
1920
|
+
const prevTagsWidth = tagEls.slice(0, count - 1).reduce(
|
|
1921
|
+
(sum, el, i) => sum + el.offsetWidth + (i > 0 ? TAG_GAP : 0),
|
|
1922
|
+
0
|
|
1923
|
+
);
|
|
1924
|
+
const gapBeforeLast = count > 1 ? TAG_GAP : 0;
|
|
1925
|
+
const remaining = budget - prevTagsWidth - gapBeforeLast;
|
|
1926
|
+
((_b2 = tagEls[count - 1]) == null ? void 0 : _b2.offsetWidth) ?? 0;
|
|
1927
|
+
if (remaining > 0) {
|
|
1928
|
+
lastTagMaxWidth = remaining;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
setLayout({ visibleCount: count, lastTagMaxWidth });
|
|
1932
|
+
};
|
|
1933
|
+
calculate();
|
|
1934
|
+
(_b = (_a = document.fonts) == null ? void 0 : _a.ready) == null ? void 0 : _b.then(calculate);
|
|
1935
|
+
}, [selectedOptions, measureRef, containerRef]);
|
|
1936
|
+
return layout;
|
|
1937
|
+
}
|
|
1938
|
+
const DropdownMultiple = React.forwardRef(
|
|
1939
|
+
function DropdownMultiple2({
|
|
1940
|
+
placeholder = "Placeholder",
|
|
1941
|
+
label,
|
|
1942
|
+
required = false,
|
|
1943
|
+
forceState,
|
|
1944
|
+
errorMessage = "Error message",
|
|
1945
|
+
helperText,
|
|
1946
|
+
value,
|
|
1947
|
+
onChange,
|
|
1948
|
+
options = [],
|
|
1949
|
+
className = ""
|
|
1950
|
+
}, ref) {
|
|
1951
|
+
const [open, setOpen] = React.useState(false);
|
|
1952
|
+
const [internalValue, setInternalValue] = React.useState([]);
|
|
1953
|
+
const [search, setSearch] = React.useState("");
|
|
1954
|
+
const containerRef = React.useRef(null);
|
|
1955
|
+
const inputRef = React.useRef(null);
|
|
1956
|
+
const measureRef = React.useRef(null);
|
|
1957
|
+
React.useImperativeHandle(ref, () => containerRef.current);
|
|
1958
|
+
const controlled = value !== void 0;
|
|
1959
|
+
const currentValue = controlled ? value : internalValue;
|
|
1960
|
+
const isDisabled = forceState === "disabled";
|
|
1961
|
+
const isStatic = Boolean(forceState);
|
|
1962
|
+
const isFilled = currentValue.length > 0;
|
|
1963
|
+
const state = forceState ?? (open ? "focus" : "default");
|
|
1964
|
+
const isError = state === "error";
|
|
1965
|
+
const isFocus = state === "focus";
|
|
1966
|
+
const bg = isDisabled ? "bg-disabled-bg" : "bg-white";
|
|
1967
|
+
const labelColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
1968
|
+
const caretColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
1969
|
+
const borderInset = isFocus || isError ? "-1px" : "0px";
|
|
1970
|
+
const borderRad = isFocus || isError ? "9px" : "8px";
|
|
1971
|
+
const borderColor = isDisabled ? "var(--border-disabled)" : isError ? "var(--destructive)" : isFocus ? "var(--primary-action)" : "var(--border)";
|
|
1972
|
+
const showBelow = isError || Boolean(helperText);
|
|
1973
|
+
const leftText = isError ? errorMessage : helperText ?? "";
|
|
1974
|
+
const leftColor = isError ? "var(--destructive)" : "var(--muted-foreground)";
|
|
1975
|
+
const selectedOptions = React.useMemo(
|
|
1976
|
+
() => currentValue.map((v) => options.find((o) => o.value === v)).filter(Boolean),
|
|
1977
|
+
[currentValue, options]
|
|
1978
|
+
);
|
|
1979
|
+
const { visibleCount, lastTagMaxWidth } = useChipLayout(
|
|
1980
|
+
selectedOptions,
|
|
1981
|
+
measureRef,
|
|
1982
|
+
containerRef
|
|
1983
|
+
);
|
|
1984
|
+
const visibleTags = selectedOptions.slice(0, visibleCount);
|
|
1985
|
+
const overflowCount = Math.max(
|
|
1986
|
+
0,
|
|
1987
|
+
selectedOptions.length - visibleCount
|
|
1988
|
+
);
|
|
1989
|
+
const filteredOptions = React.useMemo(() => {
|
|
1990
|
+
if (!search.trim()) return options;
|
|
1991
|
+
const q = search.trim().toLowerCase();
|
|
1992
|
+
return options.filter(
|
|
1993
|
+
(o) => o.label.toLowerCase().includes(q)
|
|
1994
|
+
);
|
|
1995
|
+
}, [search, options]);
|
|
1996
|
+
React.useEffect(() => {
|
|
1997
|
+
if (open && inputRef.current) inputRef.current.focus();
|
|
1998
|
+
}, [open]);
|
|
1999
|
+
React.useEffect(() => {
|
|
2000
|
+
if (!open) setSearch("");
|
|
2001
|
+
}, [open]);
|
|
2002
|
+
React.useEffect(() => {
|
|
2003
|
+
if (!open) return;
|
|
2004
|
+
const handler = (e) => {
|
|
2005
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
2006
|
+
setOpen(false);
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
document.addEventListener("mousedown", handler);
|
|
2010
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
2011
|
+
}, [open]);
|
|
2012
|
+
const updateValue = React.useCallback(
|
|
2013
|
+
(next) => {
|
|
2014
|
+
if (!controlled) setInternalValue(next);
|
|
2015
|
+
onChange == null ? void 0 : onChange(next);
|
|
2016
|
+
},
|
|
2017
|
+
[controlled, onChange]
|
|
2018
|
+
);
|
|
2019
|
+
const handleToggleOption = React.useCallback(
|
|
2020
|
+
(val) => {
|
|
2021
|
+
const next = currentValue.includes(val) ? currentValue.filter((v) => v !== val) : [...currentValue, val];
|
|
2022
|
+
updateValue(next);
|
|
2023
|
+
},
|
|
2024
|
+
[currentValue, updateValue]
|
|
2025
|
+
);
|
|
2026
|
+
const handleRemoveTag = React.useCallback(
|
|
2027
|
+
(val) => {
|
|
2028
|
+
updateValue(currentValue.filter((v) => v !== val));
|
|
2029
|
+
},
|
|
2030
|
+
[currentValue, updateValue]
|
|
2031
|
+
);
|
|
2032
|
+
const handleTriggerClick = () => {
|
|
2033
|
+
var _a;
|
|
2034
|
+
if (isDisabled || isStatic) return;
|
|
2035
|
+
if (!open) setOpen(true);
|
|
2036
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
2037
|
+
};
|
|
2038
|
+
const handleInputKeyDown = (e) => {
|
|
2039
|
+
if (e.key === "Escape") setOpen(false);
|
|
2040
|
+
if (e.key === "Backspace" && search === "" && currentValue.length > 0) {
|
|
2041
|
+
updateValue(currentValue.slice(0, -1));
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
const FloatingLabel = () => required ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[2px] items-center shrink-0 w-full", children: [
|
|
2045
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2046
|
+
"p",
|
|
2047
|
+
{
|
|
2048
|
+
className: "shrink-0 leading-[16px] not-italic text-[12px]",
|
|
2049
|
+
style: { color: labelColor },
|
|
2050
|
+
children: placeholder
|
|
2051
|
+
}
|
|
2052
|
+
),
|
|
2053
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2054
|
+
"p",
|
|
2055
|
+
{
|
|
2056
|
+
className: "leading-[1.5] not-italic text-[9px] w-[7px]",
|
|
2057
|
+
style: {
|
|
2058
|
+
color: isDisabled ? "var(--disabled)" : "var(--error-dark)"
|
|
2059
|
+
},
|
|
2060
|
+
children: "*"
|
|
2061
|
+
}
|
|
2062
|
+
)
|
|
2063
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2064
|
+
"p",
|
|
2065
|
+
{
|
|
2066
|
+
className: "shrink-0 w-full leading-[16px] not-italic text-[12px]",
|
|
2067
|
+
style: { color: labelColor },
|
|
2068
|
+
children: placeholder
|
|
2069
|
+
}
|
|
2070
|
+
);
|
|
2071
|
+
const Placeholder = () => required ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 min-w-0 min-h-[1px] gap-[2px] items-center", children: [
|
|
2072
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2073
|
+
"p",
|
|
2074
|
+
{
|
|
2075
|
+
className: "leading-[20px] not-italic text-[16px] whitespace-nowrap",
|
|
2076
|
+
style: { color: labelColor },
|
|
2077
|
+
children: placeholder
|
|
2078
|
+
}
|
|
2079
|
+
),
|
|
2080
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2081
|
+
"p",
|
|
2082
|
+
{
|
|
2083
|
+
className: "leading-[16px] not-italic text-[12px] w-[7px]",
|
|
2084
|
+
style: { color: isDisabled ? "var(--disabled)" : "var(--error-dark)" },
|
|
2085
|
+
children: "*"
|
|
2086
|
+
}
|
|
2087
|
+
)
|
|
2088
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2089
|
+
"p",
|
|
2090
|
+
{
|
|
2091
|
+
className: "flex-1 min-w-0 min-h-[1px] text-[16px] leading-[20px] not-italic overflow-hidden text-ellipsis whitespace-nowrap py-[7px]",
|
|
2092
|
+
style: { color: labelColor },
|
|
2093
|
+
children: placeholder
|
|
2094
|
+
}
|
|
2095
|
+
);
|
|
2096
|
+
const MeasurementLayer = () => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2097
|
+
"div",
|
|
2098
|
+
{
|
|
2099
|
+
ref: measureRef,
|
|
2100
|
+
"aria-hidden": true,
|
|
2101
|
+
className: "absolute flex gap-[4px] items-center pointer-events-none",
|
|
2102
|
+
style: {
|
|
2103
|
+
visibility: "hidden",
|
|
2104
|
+
top: 0,
|
|
2105
|
+
left: 0,
|
|
2106
|
+
height: 0,
|
|
2107
|
+
overflow: "hidden"
|
|
2108
|
+
},
|
|
2109
|
+
children: selectedOptions.map(
|
|
2110
|
+
(opt) => isStatic ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2111
|
+
StaticTag,
|
|
2112
|
+
{
|
|
2113
|
+
label: opt.label,
|
|
2114
|
+
disabled: isDisabled
|
|
2115
|
+
},
|
|
2116
|
+
opt.value
|
|
2117
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2118
|
+
RemovableTag,
|
|
2119
|
+
{
|
|
2120
|
+
label: opt.label,
|
|
2121
|
+
disabled: isDisabled
|
|
2122
|
+
},
|
|
2123
|
+
opt.value
|
|
2124
|
+
)
|
|
2125
|
+
)
|
|
2126
|
+
}
|
|
2127
|
+
);
|
|
2128
|
+
const renderTriggerContent = () => {
|
|
2129
|
+
const hasExternalLabel2 = Boolean(label);
|
|
2130
|
+
if (isStatic) {
|
|
2131
|
+
if (isFilled) {
|
|
2132
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start flex-1 min-w-0 min-h-[1px] relative", children: [
|
|
2133
|
+
/* @__PURE__ */ jsxRuntime.jsx(MeasurementLayer, {}),
|
|
2134
|
+
" ",
|
|
2135
|
+
!hasExternalLabel2 && /* @__PURE__ */ jsxRuntime.jsx(FloatingLabel, {}),
|
|
2136
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2137
|
+
"div",
|
|
2138
|
+
{
|
|
2139
|
+
className: "flex gap-[4px] items-center shrink-0 overflow-hidden",
|
|
2140
|
+
style: { maxWidth: "100%" },
|
|
2141
|
+
children: visibleTags.map((opt, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2142
|
+
StaticTag,
|
|
2143
|
+
{
|
|
2144
|
+
label: opt.label,
|
|
2145
|
+
disabled: isDisabled,
|
|
2146
|
+
maxWidth: i === visibleTags.length - 1 ? lastTagMaxWidth : void 0
|
|
2147
|
+
},
|
|
2148
|
+
opt.value
|
|
2149
|
+
))
|
|
2150
|
+
}
|
|
2151
|
+
)
|
|
2152
|
+
] });
|
|
2153
|
+
}
|
|
2154
|
+
if (!isFilled) {
|
|
2155
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Placeholder, {});
|
|
2156
|
+
}
|
|
2157
|
+
return null;
|
|
2158
|
+
}
|
|
2159
|
+
if (isFilled) {
|
|
2160
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start flex-1 min-w-0 min-h-[1px] relative", children: [
|
|
2161
|
+
/* @__PURE__ */ jsxRuntime.jsx(MeasurementLayer, {}),
|
|
2162
|
+
!hasExternalLabel2 && /* @__PURE__ */ jsxRuntime.jsx(FloatingLabel, {}),
|
|
2163
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2164
|
+
"div",
|
|
2165
|
+
{
|
|
2166
|
+
className: "flex gap-[4px] items-center overflow-hidden",
|
|
2167
|
+
style: { maxWidth: "100%" },
|
|
2168
|
+
children: [
|
|
2169
|
+
visibleTags.map((opt, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2170
|
+
RemovableTag,
|
|
2171
|
+
{
|
|
2172
|
+
label: opt.label,
|
|
2173
|
+
onRemove: () => handleRemoveTag(opt.value),
|
|
2174
|
+
maxWidth: i === visibleTags.length - 1 ? lastTagMaxWidth : void 0
|
|
2175
|
+
},
|
|
2176
|
+
opt.value
|
|
2177
|
+
)),
|
|
2178
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2179
|
+
"input",
|
|
2180
|
+
{
|
|
2181
|
+
ref: inputRef,
|
|
2182
|
+
type: "text",
|
|
2183
|
+
value: search,
|
|
2184
|
+
onChange: (e) => setSearch(e.target.value),
|
|
2185
|
+
onKeyDown: handleInputKeyDown,
|
|
2186
|
+
className: "flex-1 min-w-[40px] outline-none border-none bg-transparent text-[14px] leading-[20px]",
|
|
2187
|
+
style: {
|
|
2188
|
+
color: "var(--foreground)",
|
|
2189
|
+
caretColor: "var(--caret-color)"
|
|
2190
|
+
},
|
|
2191
|
+
onClick: (e) => e.stopPropagation()
|
|
2192
|
+
}
|
|
2193
|
+
)
|
|
2194
|
+
]
|
|
2195
|
+
}
|
|
2196
|
+
)
|
|
2197
|
+
] });
|
|
2198
|
+
}
|
|
2199
|
+
if (open) {
|
|
2200
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2201
|
+
"input",
|
|
2202
|
+
{
|
|
2203
|
+
ref: inputRef,
|
|
2204
|
+
type: "text",
|
|
2205
|
+
value: search,
|
|
2206
|
+
onChange: (e) => setSearch(e.target.value),
|
|
2207
|
+
onKeyDown: handleInputKeyDown,
|
|
2208
|
+
className: "flex-1 min-w-[40px] outline-none border-none bg-transparent text-[14px] leading-[20px]",
|
|
2209
|
+
style: {
|
|
2210
|
+
color: "var(--foreground)",
|
|
2211
|
+
caretColor: "var(--caret-color)"
|
|
2212
|
+
},
|
|
2213
|
+
onClick: (e) => e.stopPropagation()
|
|
2214
|
+
}
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
if (!isFilled) {
|
|
2218
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Placeholder, {});
|
|
2219
|
+
}
|
|
2220
|
+
return null;
|
|
2221
|
+
};
|
|
2222
|
+
const hasExternalLabel = Boolean(label);
|
|
2223
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2224
|
+
"div",
|
|
2225
|
+
{
|
|
2226
|
+
ref: containerRef,
|
|
2227
|
+
className: cn("flex flex-col gap-[4px] w-full max-w-[343px]", className),
|
|
2228
|
+
children: [
|
|
2229
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative shrink-0 w-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start px-[4px] w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2230
|
+
"p",
|
|
2231
|
+
{
|
|
2232
|
+
className: "leading-[20px] not-italic relative shrink-0 text-foreground text-[14px] whitespace-nowrap",
|
|
2233
|
+
style: { fontWeight: 700 },
|
|
2234
|
+
children: label
|
|
2235
|
+
}
|
|
2236
|
+
) }) }),
|
|
2237
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2238
|
+
"div",
|
|
2239
|
+
{
|
|
2240
|
+
onClick: handleTriggerClick,
|
|
2241
|
+
className: cn(
|
|
2242
|
+
"relative flex gap-[8px] items-center rounded-[8px]",
|
|
2243
|
+
bg,
|
|
2244
|
+
"px-[14px]",
|
|
2245
|
+
hasExternalLabel ? "h-[40px]" : "py-[4px] min-h-[48px]",
|
|
2246
|
+
!isDisabled && !isStatic && "cursor-pointer"
|
|
2247
|
+
),
|
|
2248
|
+
children: [
|
|
2249
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2250
|
+
"div",
|
|
2251
|
+
{
|
|
2252
|
+
"aria-hidden": "true",
|
|
2253
|
+
className: "absolute pointer-events-none border border-solid",
|
|
2254
|
+
style: {
|
|
2255
|
+
inset: borderInset,
|
|
2256
|
+
borderRadius: borderRad,
|
|
2257
|
+
borderColor
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
),
|
|
2261
|
+
renderTriggerContent(),
|
|
2262
|
+
isFilled && overflowCount > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2263
|
+
"div",
|
|
2264
|
+
{
|
|
2265
|
+
className: hasExternalLabel ? "self-center" : "self-end",
|
|
2266
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2267
|
+
OverflowBadge,
|
|
2268
|
+
{
|
|
2269
|
+
count: overflowCount,
|
|
2270
|
+
disabled: isDisabled
|
|
2271
|
+
}
|
|
2272
|
+
)
|
|
2273
|
+
}
|
|
2274
|
+
),
|
|
2275
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", style: { color: caretColor }, children: isFocus ? /* @__PURE__ */ jsxRuntime.jsx(ChevronUpIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, {}) })
|
|
2276
|
+
]
|
|
2277
|
+
}
|
|
2278
|
+
),
|
|
2279
|
+
open && !isStatic && options.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2280
|
+
"div",
|
|
2281
|
+
{
|
|
2282
|
+
className: "relative bg-white rounded-[8px] overflow-clip p-[8px] z-20 flex flex-col items-start",
|
|
2283
|
+
style: {
|
|
2284
|
+
boxShadow: "0px 20px 25px -5px rgba(0,0,0,0.1), 0px 8px 10px -6px rgba(0,0,0,0.1)"
|
|
2285
|
+
},
|
|
2286
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2287
|
+
"div",
|
|
2288
|
+
{
|
|
2289
|
+
className: cn(
|
|
2290
|
+
"w-full flex flex-col",
|
|
2291
|
+
filteredOptions.length > 10 && "overflow-y-auto"
|
|
2292
|
+
),
|
|
2293
|
+
style: filteredOptions.length > 10 ? { maxHeight: 10 * 48 } : void 0,
|
|
2294
|
+
children: filteredOptions.length > 0 ? filteredOptions.map((opt) => {
|
|
2295
|
+
const isSelected = currentValue.includes(opt.value);
|
|
2296
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2297
|
+
"div",
|
|
2298
|
+
{
|
|
2299
|
+
onClick: (e) => {
|
|
2300
|
+
var _a;
|
|
2301
|
+
e.stopPropagation();
|
|
2302
|
+
handleToggleOption(opt.value);
|
|
2303
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
2304
|
+
},
|
|
2305
|
+
className: cn(
|
|
2306
|
+
"w-full shrink-0 rounded-[4px] cursor-pointer transition-colors duration-100",
|
|
2307
|
+
isSelected ? "bg-primary-action-light" : "bg-white hover:bg-disabled-bg"
|
|
2308
|
+
),
|
|
2309
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[8px] p-[14px] relative w-full", children: [
|
|
2310
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2311
|
+
"p",
|
|
2312
|
+
{
|
|
2313
|
+
className: cn(
|
|
2314
|
+
"flex-1 min-w-0 min-h-[1px] leading-[20px] not-italic overflow-hidden text-[14px] text-ellipsis whitespace-nowrap",
|
|
2315
|
+
isSelected ? "text-primary-action" : "text-foreground"
|
|
2316
|
+
),
|
|
2317
|
+
children: opt.label
|
|
2318
|
+
}
|
|
2319
|
+
),
|
|
2320
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2321
|
+
"div",
|
|
2322
|
+
{
|
|
2323
|
+
className: cn(
|
|
2324
|
+
"shrink-0 w-[16px] h-[16px] rounded-[3px] flex items-center justify-center transition-colors duration-100",
|
|
2325
|
+
"bg-transparent"
|
|
2326
|
+
),
|
|
2327
|
+
children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon$1, { className: "text-primary-action" })
|
|
2328
|
+
}
|
|
2329
|
+
)
|
|
2330
|
+
] }) })
|
|
2331
|
+
},
|
|
2332
|
+
opt.value
|
|
2333
|
+
);
|
|
2334
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full shrink-0 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-row items-center size-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center p-[14px] relative w-full", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "flex-1 min-w-0 min-h-[1px] leading-[20px] not-italic text-[14px] text-disabled", children: "No results found" }) }) }) })
|
|
2335
|
+
}
|
|
2336
|
+
)
|
|
2337
|
+
}
|
|
2338
|
+
),
|
|
2339
|
+
showBelow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start px-[4px] text-[12px] leading-[16px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2340
|
+
"span",
|
|
2341
|
+
{
|
|
2342
|
+
className: "flex-1 min-w-0",
|
|
2343
|
+
style: { color: leftColor },
|
|
2344
|
+
children: leftText
|
|
2345
|
+
}
|
|
2346
|
+
) })
|
|
2347
|
+
]
|
|
2348
|
+
}
|
|
2349
|
+
);
|
|
2350
|
+
}
|
|
2351
|
+
);
|
|
2352
|
+
DropdownMultiple.displayName = "DropdownMultiple";
|
|
2353
|
+
const Input = React.forwardRef(function Input2({
|
|
2354
|
+
placeholder = "Text label",
|
|
2355
|
+
required = false,
|
|
2356
|
+
forceState,
|
|
2357
|
+
errorMessage = "Error message",
|
|
2358
|
+
value,
|
|
2359
|
+
onChange,
|
|
2360
|
+
rightIcon,
|
|
2361
|
+
unit,
|
|
2362
|
+
helperText,
|
|
2363
|
+
showCount = false,
|
|
2364
|
+
maxCount = 100,
|
|
2365
|
+
className = "",
|
|
2366
|
+
type = "text",
|
|
2367
|
+
style: inputStyleProp,
|
|
2368
|
+
onFocus: onFocusProp,
|
|
2369
|
+
onBlur: onBlurProp,
|
|
2370
|
+
disabled: _disabledProp,
|
|
2371
|
+
...inputRest
|
|
2372
|
+
}, ref) {
|
|
2373
|
+
const [focused, setFocused] = React.useState(false);
|
|
2374
|
+
const [internalValue, setInternalValue] = React.useState("");
|
|
2375
|
+
const controlled = value !== void 0;
|
|
2376
|
+
const currentValue = controlled ? value : internalValue;
|
|
2377
|
+
const isDisabled = forceState === "disabled";
|
|
2378
|
+
const state = forceState ?? (focused ? "focus" : "default");
|
|
2379
|
+
const isError = state === "error";
|
|
2380
|
+
const isFocus = state === "focus";
|
|
2381
|
+
const isFilled = currentValue.length > 0;
|
|
2382
|
+
const bg = isDisabled ? "bg-disabled-bg" : "bg-white";
|
|
2383
|
+
const floatLabel = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
2384
|
+
const filledValue = isDisabled ? "var(--disabled)" : "var(--foreground)";
|
|
2385
|
+
const unitColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
2386
|
+
const borderInset = isFocus || isError ? "-1px" : "0px";
|
|
2387
|
+
const borderRad = isFocus || isError ? "9px" : "8px";
|
|
2388
|
+
const borderColor = isDisabled ? "var(--border-disabled)" : isError ? "var(--destructive)" : isFocus ? "var(--primary-action)" : "var(--border)";
|
|
2389
|
+
const hasRight = Boolean(rightIcon) || Boolean(unit);
|
|
2390
|
+
const padding = isFilled ? "px-[14px] py-[6px]" : hasRight ? "px-[14px] py-[12px]" : "p-[14px]";
|
|
2391
|
+
const charCount = currentValue.length;
|
|
2392
|
+
const showBelow = isError || Boolean(helperText) || showCount;
|
|
2393
|
+
const leftText = isError ? errorMessage : helperText ?? "";
|
|
2394
|
+
const leftColor = isError ? "var(--destructive)" : "var(--muted-foreground)";
|
|
2395
|
+
const handleChange = (e) => {
|
|
2396
|
+
if (!controlled) setInternalValue(e.target.value);
|
|
2397
|
+
onChange == null ? void 0 : onChange(e.target.value);
|
|
2398
|
+
};
|
|
2399
|
+
const handleFocus = (e) => {
|
|
2400
|
+
onFocusProp == null ? void 0 : onFocusProp(e);
|
|
2401
|
+
setFocused(true);
|
|
2402
|
+
};
|
|
2403
|
+
const handleBlur = (e) => {
|
|
2404
|
+
onBlurProp == null ? void 0 : onBlurProp(e);
|
|
2405
|
+
setFocused(false);
|
|
2406
|
+
};
|
|
2407
|
+
const containerFlex = isFilled ? !hasRight ? "flex-col items-start justify-center" : rightIcon ? "flex items-center gap-[8px]" : "flex items-end gap-[8px]" : cn("flex items-center", hasRight && "gap-[8px]");
|
|
2408
|
+
const inputCaretStyle = {
|
|
2409
|
+
caretColor: "var(--caret-color)"
|
|
2410
|
+
};
|
|
2411
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex flex-col gap-[4px] w-full", className), children: [
|
|
2412
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2413
|
+
"div",
|
|
2414
|
+
{
|
|
2415
|
+
className: cn(
|
|
2416
|
+
"relative rounded-[8px]",
|
|
2417
|
+
padding,
|
|
2418
|
+
bg,
|
|
2419
|
+
containerFlex
|
|
2420
|
+
),
|
|
2421
|
+
children: [
|
|
2422
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2423
|
+
"div",
|
|
2424
|
+
{
|
|
2425
|
+
"aria-hidden": "true",
|
|
2426
|
+
className: "absolute pointer-events-none border border-solid",
|
|
2427
|
+
style: {
|
|
2428
|
+
inset: borderInset,
|
|
2429
|
+
borderRadius: borderRad,
|
|
2430
|
+
borderColor
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
),
|
|
2434
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2435
|
+
"div",
|
|
2436
|
+
{
|
|
2437
|
+
className: cn(
|
|
2438
|
+
"flex flex-col min-w-0 min-h-[1px]",
|
|
2439
|
+
hasRight ? "flex-1 justify-center" : "w-full justify-center"
|
|
2440
|
+
),
|
|
2441
|
+
children: [
|
|
2442
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2443
|
+
"p",
|
|
2444
|
+
{
|
|
2445
|
+
className: cn(
|
|
2446
|
+
"shrink-0 w-full not-italic",
|
|
2447
|
+
isFilled ? "leading-[16px] text-[12px]" : "text-[16px] leading-[20px] pointer-events-none"
|
|
2448
|
+
),
|
|
2449
|
+
style: { color: floatLabel },
|
|
2450
|
+
children: [
|
|
2451
|
+
placeholder,
|
|
2452
|
+
required && !isFilled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2453
|
+
"span",
|
|
2454
|
+
{
|
|
2455
|
+
style: {
|
|
2456
|
+
color: isDisabled ? "var(--disabled)" : "var(--error-dark)"
|
|
2457
|
+
},
|
|
2458
|
+
children: " *"
|
|
2459
|
+
}
|
|
2460
|
+
)
|
|
2461
|
+
]
|
|
2462
|
+
}
|
|
2463
|
+
),
|
|
2464
|
+
!isDisabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2465
|
+
"input",
|
|
2466
|
+
{
|
|
2467
|
+
...inputRest,
|
|
2468
|
+
type,
|
|
2469
|
+
value: currentValue,
|
|
2470
|
+
onChange: handleChange,
|
|
2471
|
+
onFocus: handleFocus,
|
|
2472
|
+
onBlur: handleBlur,
|
|
2473
|
+
disabled: isDisabled,
|
|
2474
|
+
"aria-label": placeholder,
|
|
2475
|
+
className: cn(
|
|
2476
|
+
"w-full bg-transparent outline-none border-none min-w-0",
|
|
2477
|
+
isFilled ? "leading-[20px] not-italic text-[14px] p-0 m-0" : "absolute inset-0 h-full cursor-text text-[16px]"
|
|
2478
|
+
),
|
|
2479
|
+
style: isFilled ? { ...inputStyleProp, color: filledValue, ...inputCaretStyle } : {
|
|
2480
|
+
...inputStyleProp,
|
|
2481
|
+
color: "transparent",
|
|
2482
|
+
caretColor: isFocus ? "var(--caret-color)" : "transparent",
|
|
2483
|
+
padding: hasRight ? "12px 14px" : "14px"
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
)
|
|
2487
|
+
]
|
|
2488
|
+
}
|
|
2489
|
+
),
|
|
2490
|
+
rightIcon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2491
|
+
"div",
|
|
2492
|
+
{
|
|
2493
|
+
className: cn(
|
|
2494
|
+
"shrink-0 flex items-center",
|
|
2495
|
+
isFilled && "self-stretch",
|
|
2496
|
+
!isFilled && "relative"
|
|
2497
|
+
),
|
|
2498
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center size-[24px] overflow-hidden", children: rightIcon })
|
|
2499
|
+
}
|
|
2500
|
+
),
|
|
2501
|
+
unit && !rightIcon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2502
|
+
"p",
|
|
2503
|
+
{
|
|
2504
|
+
className: cn(
|
|
2505
|
+
"shrink-0 whitespace-nowrap text-[16px]",
|
|
2506
|
+
!isFilled && "relative"
|
|
2507
|
+
),
|
|
2508
|
+
style: {
|
|
2509
|
+
color: unitColor,
|
|
2510
|
+
lineHeight: "1.5",
|
|
2511
|
+
fontVariationSettings: "'wdth' 100"
|
|
2512
|
+
},
|
|
2513
|
+
children: unit
|
|
2514
|
+
}
|
|
2515
|
+
)
|
|
2516
|
+
]
|
|
2517
|
+
}
|
|
2518
|
+
),
|
|
2519
|
+
showBelow && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[8px] px-[4px] text-[12px] leading-[16px]", children: [
|
|
2520
|
+
leftText ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0", style: { color: leftColor }, children: leftText }) : showCount && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
|
|
2521
|
+
showCount && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2522
|
+
"span",
|
|
2523
|
+
{
|
|
2524
|
+
className: "shrink-0 text-right whitespace-nowrap",
|
|
2525
|
+
style: { color: "var(--muted-foreground)" },
|
|
2526
|
+
children: [
|
|
2527
|
+
charCount,
|
|
2528
|
+
"/",
|
|
2529
|
+
maxCount
|
|
2530
|
+
]
|
|
2531
|
+
}
|
|
2532
|
+
)
|
|
2533
|
+
] })
|
|
2534
|
+
] });
|
|
2535
|
+
});
|
|
2536
|
+
Input.displayName = "Input";
|
|
2537
|
+
function CheckIcon(props) {
|
|
2538
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2539
|
+
"svg",
|
|
2540
|
+
{
|
|
2541
|
+
width: "16",
|
|
2542
|
+
height: "11",
|
|
2543
|
+
viewBox: "0 0 16 11",
|
|
2544
|
+
fill: "none",
|
|
2545
|
+
...props,
|
|
2546
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2547
|
+
"path",
|
|
2548
|
+
{
|
|
2549
|
+
d: "M1 5.5L5.5 10L15 1",
|
|
2550
|
+
stroke: "currentColor",
|
|
2551
|
+
strokeWidth: "1.5",
|
|
2552
|
+
strokeLinecap: "round",
|
|
2553
|
+
strokeLinejoin: "round"
|
|
2554
|
+
}
|
|
2555
|
+
)
|
|
2556
|
+
}
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
const OptionList = React.forwardRef(
|
|
2560
|
+
function OptionList2({
|
|
2561
|
+
options,
|
|
2562
|
+
selectedValue,
|
|
2563
|
+
selectedValues,
|
|
2564
|
+
onSelect,
|
|
2565
|
+
onToggle,
|
|
2566
|
+
maxVisible = 10,
|
|
2567
|
+
emptyText = "No results found",
|
|
2568
|
+
className
|
|
2569
|
+
}, ref) {
|
|
2570
|
+
const isMulti = selectedValues !== void 0 || onToggle !== void 0;
|
|
2571
|
+
const isScrollable = options.length > maxVisible;
|
|
2572
|
+
const maxHeight = isScrollable ? maxVisible * 48 + 16 : void 0;
|
|
2573
|
+
const isSelected = (val) => isMulti ? (selectedValues ?? []).includes(val) : val === selectedValue;
|
|
2574
|
+
const handleClick = (opt) => {
|
|
2575
|
+
if (opt.disabled) return;
|
|
2576
|
+
if (isMulti) {
|
|
2577
|
+
onToggle == null ? void 0 : onToggle(opt.value);
|
|
2578
|
+
} else {
|
|
2579
|
+
onSelect == null ? void 0 : onSelect(opt.value);
|
|
2580
|
+
}
|
|
2581
|
+
};
|
|
2582
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2583
|
+
"div",
|
|
2584
|
+
{
|
|
2585
|
+
ref,
|
|
2586
|
+
className: cn(
|
|
2587
|
+
"flex flex-col items-start overflow-clip rounded-[8px] bg-white px-[8px] py-[8px]",
|
|
2588
|
+
className
|
|
2589
|
+
),
|
|
2590
|
+
style: {
|
|
2591
|
+
boxShadow: "0px 20px 25px -5px rgba(0,0,0,0.1), 0px 8px 10px -6px rgba(0,0,0,0.1)",
|
|
2592
|
+
...isScrollable ? { maxHeight, overflowY: "auto" } : {}
|
|
2593
|
+
},
|
|
2594
|
+
children: options.length > 0 ? options.map((opt) => {
|
|
2595
|
+
const selected = isSelected(opt.value);
|
|
2596
|
+
const disabled = opt.disabled === true;
|
|
2597
|
+
const rowBg = disabled ? "bg-disabled-bg" : selected ? "bg-selected-bg" : "bg-white hover:bg-selected-bg";
|
|
2598
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2599
|
+
"div",
|
|
2600
|
+
{
|
|
2601
|
+
onClick: () => handleClick(opt),
|
|
2602
|
+
className: cn(
|
|
2603
|
+
"w-full shrink-0 rounded-[4px] transition-colors duration-100",
|
|
2604
|
+
rowBg,
|
|
2605
|
+
disabled ? "cursor-default" : "cursor-pointer"
|
|
2606
|
+
),
|
|
2607
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-[8px] p-[14px]", children: [
|
|
2608
|
+
opt.icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2609
|
+
"span",
|
|
2610
|
+
{
|
|
2611
|
+
className: "flex size-[20px] shrink-0 items-center justify-center overflow-clip",
|
|
2612
|
+
style: {
|
|
2613
|
+
color: disabled ? "var(--disabled)" : "var(--muted-foreground)"
|
|
2614
|
+
},
|
|
2615
|
+
children: opt.icon
|
|
2616
|
+
}
|
|
2617
|
+
),
|
|
2618
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2619
|
+
"p",
|
|
2620
|
+
{
|
|
2621
|
+
className: "min-h-[1px] min-w-0 flex-1 overflow-hidden text-[14px] leading-[20px] text-ellipsis whitespace-nowrap not-italic",
|
|
2622
|
+
style: {
|
|
2623
|
+
color: disabled ? "var(--disabled)" : "var(--foreground)"
|
|
2624
|
+
},
|
|
2625
|
+
children: opt.label
|
|
2626
|
+
}
|
|
2627
|
+
),
|
|
2628
|
+
selected && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-[20px] shrink-0 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "text-primary-action" }) })
|
|
2629
|
+
] })
|
|
2630
|
+
},
|
|
2631
|
+
opt.value
|
|
2632
|
+
);
|
|
2633
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full shrink-0 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full items-center p-[14px]", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "min-h-[1px] min-w-0 flex-1 text-[14px] leading-[20px] not-italic text-disabled", children: emptyText }) }) })
|
|
2634
|
+
}
|
|
2635
|
+
);
|
|
2636
|
+
}
|
|
2637
|
+
);
|
|
2638
|
+
OptionList.displayName = "OptionList";
|
|
2639
|
+
const SearchInput = React.forwardRef(
|
|
2640
|
+
function SearchInput2({
|
|
2641
|
+
placeholder = "Placeholder",
|
|
2642
|
+
value,
|
|
2643
|
+
onChange,
|
|
2644
|
+
size = "lg",
|
|
2645
|
+
className,
|
|
2646
|
+
onClear
|
|
2647
|
+
}, ref) {
|
|
2648
|
+
const [focused, setFocused] = React.useState(false);
|
|
2649
|
+
const [internalValue, setInternalValue] = React.useState("");
|
|
2650
|
+
const inputRef = React.useRef(null);
|
|
2651
|
+
const controlled = value !== void 0;
|
|
2652
|
+
const currentValue = controlled ? value : internalValue;
|
|
2653
|
+
const isFilled = currentValue.length > 0;
|
|
2654
|
+
const iconSize = size === "lg" ? 24 : 22;
|
|
2655
|
+
const minHeight = size === "sm" ? "min-h-[32px]" : "";
|
|
2656
|
+
const padding = size === "sm" ? "px-[14px] py-[8px]" : "px-[14px] py-[12px]";
|
|
2657
|
+
const borderInset = focused ? "-1px" : "0px";
|
|
2658
|
+
const borderRad = focused ? "9px" : "8px";
|
|
2659
|
+
const borderColor = focused ? "var(--primary-action)" : "var(--border)";
|
|
2660
|
+
const handleChange = (next) => {
|
|
2661
|
+
if (!controlled) setInternalValue(next);
|
|
2662
|
+
onChange == null ? void 0 : onChange(next);
|
|
2663
|
+
};
|
|
2664
|
+
const handleClear = () => {
|
|
2665
|
+
var _a;
|
|
2666
|
+
if (!controlled) setInternalValue("");
|
|
2667
|
+
onChange == null ? void 0 : onChange("");
|
|
2668
|
+
onClear == null ? void 0 : onClear();
|
|
2669
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
2670
|
+
};
|
|
2671
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2672
|
+
"div",
|
|
2673
|
+
{
|
|
2674
|
+
ref,
|
|
2675
|
+
className: cn(
|
|
2676
|
+
"relative flex cursor-text items-center gap-[8px] rounded-[8px] bg-white",
|
|
2677
|
+
padding,
|
|
2678
|
+
minHeight,
|
|
2679
|
+
className
|
|
2680
|
+
),
|
|
2681
|
+
onClick: () => {
|
|
2682
|
+
var _a;
|
|
2683
|
+
return (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
2684
|
+
},
|
|
2685
|
+
children: [
|
|
2686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2687
|
+
"div",
|
|
2688
|
+
{
|
|
2689
|
+
"aria-hidden": "true",
|
|
2690
|
+
className: "pointer-events-none absolute border border-solid",
|
|
2691
|
+
style: {
|
|
2692
|
+
inset: borderInset,
|
|
2693
|
+
borderRadius: borderRad,
|
|
2694
|
+
borderColor
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
),
|
|
2698
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2699
|
+
react.MagnifyingGlass,
|
|
2700
|
+
{
|
|
2701
|
+
size: iconSize,
|
|
2702
|
+
color: "var(--muted-foreground)",
|
|
2703
|
+
weight: "regular"
|
|
2704
|
+
}
|
|
2705
|
+
) }),
|
|
2706
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative min-w-0 flex-1", children: [
|
|
2707
|
+
!isFilled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2708
|
+
"p",
|
|
2709
|
+
{
|
|
2710
|
+
className: "pointer-events-none absolute inset-0 flex items-center text-[16px] leading-[20px] not-italic",
|
|
2711
|
+
style: { color: "var(--muted-foreground)" },
|
|
2712
|
+
children: placeholder
|
|
2713
|
+
}
|
|
2714
|
+
),
|
|
2715
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2716
|
+
"input",
|
|
2717
|
+
{
|
|
2718
|
+
ref: inputRef,
|
|
2719
|
+
type: "text",
|
|
2720
|
+
"aria-label": placeholder,
|
|
2721
|
+
value: currentValue,
|
|
2722
|
+
onChange: (e) => handleChange(e.target.value),
|
|
2723
|
+
onFocus: () => setFocused(true),
|
|
2724
|
+
onBlur: () => setFocused(false),
|
|
2725
|
+
className: "m-0 w-full border-none bg-transparent p-0 text-[16px] leading-[20px] outline-none",
|
|
2726
|
+
style: {
|
|
2727
|
+
color: isFilled ? "var(--foreground)" : "transparent",
|
|
2728
|
+
caretColor: "var(--caret-color)"
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
)
|
|
2732
|
+
] }),
|
|
2733
|
+
focused && isFilled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2734
|
+
"button",
|
|
2735
|
+
{
|
|
2736
|
+
type: "button",
|
|
2737
|
+
"aria-label": "Clear search",
|
|
2738
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
2739
|
+
onClick: handleClear,
|
|
2740
|
+
className: "m-0 flex shrink-0 cursor-pointer items-center justify-center border-none bg-transparent p-0",
|
|
2741
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2742
|
+
react.X,
|
|
2743
|
+
{
|
|
2744
|
+
size: iconSize,
|
|
2745
|
+
color: "var(--muted-foreground)",
|
|
2746
|
+
weight: "regular"
|
|
2747
|
+
}
|
|
2748
|
+
)
|
|
2749
|
+
}
|
|
2750
|
+
)
|
|
2751
|
+
]
|
|
2752
|
+
}
|
|
2753
|
+
);
|
|
2754
|
+
}
|
|
2755
|
+
);
|
|
2756
|
+
SearchInput.displayName = "SearchInput";
|
|
2757
|
+
const sizeClasses = {
|
|
2758
|
+
lg: {
|
|
2759
|
+
pad: "px-[12px] py-[10px]",
|
|
2760
|
+
text: "text-[14px]",
|
|
2761
|
+
leading: "leading-[20px]",
|
|
2762
|
+
font: "font-bold"
|
|
2763
|
+
},
|
|
2764
|
+
md: {
|
|
2765
|
+
pad: "px-[10px] py-[8px]",
|
|
2766
|
+
text: "text-[14px]",
|
|
2767
|
+
leading: "leading-[20px]",
|
|
2768
|
+
font: "font-bold"
|
|
2769
|
+
},
|
|
2770
|
+
sm: {
|
|
2771
|
+
pad: "px-[8px] py-[6px]",
|
|
2772
|
+
text: "text-[12px]",
|
|
2773
|
+
leading: "leading-[16px]",
|
|
2774
|
+
font: "font-semibold"
|
|
2775
|
+
}
|
|
2776
|
+
};
|
|
2777
|
+
const Tab = React.forwardRef(function Tab2({
|
|
2778
|
+
title = "Tab",
|
|
2779
|
+
size = "md",
|
|
2780
|
+
active = false,
|
|
2781
|
+
disabled = false,
|
|
2782
|
+
onClick,
|
|
2783
|
+
className
|
|
2784
|
+
}, ref) {
|
|
2785
|
+
const s = sizeClasses[size];
|
|
2786
|
+
const textColor = disabled ? "text-disabled" : active ? "text-primary-action" : "text-muted-foreground";
|
|
2787
|
+
const borderColor = active && !disabled ? "border-primary-action" : "border-border";
|
|
2788
|
+
const cursor = disabled ? "cursor-not-allowed" : "cursor-pointer";
|
|
2789
|
+
const hoverBg = !disabled && !active ? "hover:bg-hover-bg" : "";
|
|
2790
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2791
|
+
"div",
|
|
2792
|
+
{
|
|
2793
|
+
ref,
|
|
2794
|
+
role: "tab",
|
|
2795
|
+
"aria-selected": active,
|
|
2796
|
+
"aria-disabled": disabled,
|
|
2797
|
+
onClick: !disabled ? onClick : void 0,
|
|
2798
|
+
className: cn(
|
|
2799
|
+
"relative flex min-w-[80px] select-none items-center justify-center bg-white transition-colors duration-150",
|
|
2800
|
+
s.pad,
|
|
2801
|
+
cursor,
|
|
2802
|
+
hoverBg,
|
|
2803
|
+
className
|
|
2804
|
+
),
|
|
2805
|
+
children: [
|
|
2806
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2807
|
+
"div",
|
|
2808
|
+
{
|
|
2809
|
+
"aria-hidden": "true",
|
|
2810
|
+
className: cn(
|
|
2811
|
+
"pointer-events-none absolute inset-0 border-b-[1.5px] border-solid",
|
|
2812
|
+
borderColor
|
|
2813
|
+
)
|
|
2814
|
+
}
|
|
2815
|
+
),
|
|
2816
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2817
|
+
"span",
|
|
2818
|
+
{
|
|
2819
|
+
className: cn(
|
|
2820
|
+
"relative overflow-hidden text-ellipsis whitespace-nowrap text-center",
|
|
2821
|
+
s.text,
|
|
2822
|
+
s.leading,
|
|
2823
|
+
s.font,
|
|
2824
|
+
textColor
|
|
2825
|
+
),
|
|
2826
|
+
children: title
|
|
2827
|
+
}
|
|
2828
|
+
)
|
|
2829
|
+
]
|
|
2830
|
+
}
|
|
2831
|
+
);
|
|
2832
|
+
});
|
|
2833
|
+
Tab.displayName = "Tab";
|
|
2834
|
+
const TabGroup = React.forwardRef(
|
|
2835
|
+
function TabGroup2({ items, activeId, size = "md", onChange, className }, ref) {
|
|
2836
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, role: "tablist", className: cn("flex", className), children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2837
|
+
Tab,
|
|
2838
|
+
{
|
|
2839
|
+
title: item.title,
|
|
2840
|
+
size,
|
|
2841
|
+
active: item.id === activeId,
|
|
2842
|
+
disabled: item.disabled,
|
|
2843
|
+
onClick: () => onChange == null ? void 0 : onChange(item.id)
|
|
2844
|
+
},
|
|
2845
|
+
item.id
|
|
2846
|
+
)) });
|
|
2847
|
+
}
|
|
2848
|
+
);
|
|
2849
|
+
TabGroup.displayName = "TabGroup";
|
|
2850
|
+
const TextArea = React.forwardRef(
|
|
2851
|
+
function TextArea2({
|
|
2852
|
+
placeholder = "Text label",
|
|
2853
|
+
required = false,
|
|
2854
|
+
forceState,
|
|
2855
|
+
errorMessage = "Error message",
|
|
2856
|
+
value,
|
|
2857
|
+
onChange,
|
|
2858
|
+
helperText,
|
|
2859
|
+
showCount = false,
|
|
2860
|
+
maxCount = 100,
|
|
2861
|
+
rows = 4,
|
|
2862
|
+
className,
|
|
2863
|
+
...textareaProps
|
|
2864
|
+
}, ref) {
|
|
2865
|
+
const [focused, setFocused] = React.useState(false);
|
|
2866
|
+
const [internalValue, setInternalValue] = React.useState("");
|
|
2867
|
+
const controlled = value !== void 0;
|
|
2868
|
+
const currentValue = controlled ? value : internalValue;
|
|
2869
|
+
const isDisabled = forceState === "disabled";
|
|
2870
|
+
const state = forceState ?? (focused ? "focus" : "default");
|
|
2871
|
+
const isError = state === "error";
|
|
2872
|
+
const isFocus = state === "focus";
|
|
2873
|
+
const isFilled = currentValue.length > 0;
|
|
2874
|
+
const floatLabel = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
2875
|
+
const filledValue = isDisabled ? "var(--disabled)" : "var(--foreground)";
|
|
2876
|
+
const borderInset = isFocus || isError ? "-1px" : "0px";
|
|
2877
|
+
const borderRad = isFocus || isError ? "9px" : "8px";
|
|
2878
|
+
const borderColor = isDisabled ? "var(--border-disabled)" : isError ? "var(--destructive)" : isFocus ? "var(--primary-action)" : "var(--border)";
|
|
2879
|
+
const charCount = currentValue.length;
|
|
2880
|
+
const showBelow = isError || Boolean(helperText) || showCount;
|
|
2881
|
+
const leftText = isError ? errorMessage : helperText ?? "";
|
|
2882
|
+
const leftColor = isError ? "var(--destructive)" : "var(--muted-foreground)";
|
|
2883
|
+
const countColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
2884
|
+
const handleChange = (e) => {
|
|
2885
|
+
let newValue = e.target.value;
|
|
2886
|
+
if (showCount && newValue.length > maxCount) {
|
|
2887
|
+
newValue = newValue.slice(0, maxCount);
|
|
2888
|
+
}
|
|
2889
|
+
if (!controlled) setInternalValue(newValue);
|
|
2890
|
+
onChange == null ? void 0 : onChange(newValue);
|
|
2891
|
+
};
|
|
2892
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: cn("flex w-full flex-col gap-[4px]", className), children: [
|
|
2893
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2894
|
+
"div",
|
|
2895
|
+
{
|
|
2896
|
+
className: cn(
|
|
2897
|
+
"relative h-[116px] rounded-[8px]",
|
|
2898
|
+
isDisabled ? "bg-disabled-bg" : "bg-white"
|
|
2899
|
+
),
|
|
2900
|
+
children: [
|
|
2901
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2902
|
+
"div",
|
|
2903
|
+
{
|
|
2904
|
+
"aria-hidden": "true",
|
|
2905
|
+
className: "pointer-events-none absolute border border-solid",
|
|
2906
|
+
style: { inset: borderInset, borderRadius: borderRad, borderColor }
|
|
2907
|
+
}
|
|
2908
|
+
),
|
|
2909
|
+
isFilled ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full flex-col items-start p-[14px] pb-[6px]", children: [
|
|
2910
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2911
|
+
"p",
|
|
2912
|
+
{
|
|
2913
|
+
className: "w-full shrink-0 text-[12px] leading-[16px] not-italic",
|
|
2914
|
+
style: { color: floatLabel },
|
|
2915
|
+
children: placeholder
|
|
2916
|
+
}
|
|
2917
|
+
),
|
|
2918
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2919
|
+
"textarea",
|
|
2920
|
+
{
|
|
2921
|
+
...textareaProps,
|
|
2922
|
+
value: currentValue,
|
|
2923
|
+
onChange: handleChange,
|
|
2924
|
+
onFocus: (e) => {
|
|
2925
|
+
var _a;
|
|
2926
|
+
(_a = textareaProps.onFocus) == null ? void 0 : _a.call(textareaProps, e);
|
|
2927
|
+
setFocused(true);
|
|
2928
|
+
},
|
|
2929
|
+
onBlur: (e) => {
|
|
2930
|
+
var _a;
|
|
2931
|
+
(_a = textareaProps.onBlur) == null ? void 0 : _a.call(textareaProps, e);
|
|
2932
|
+
setFocused(false);
|
|
2933
|
+
},
|
|
2934
|
+
disabled: isDisabled,
|
|
2935
|
+
rows,
|
|
2936
|
+
"aria-label": placeholder,
|
|
2937
|
+
className: cn(
|
|
2938
|
+
"m-0 min-w-0 flex-1 resize-none border-none bg-transparent p-0 text-[14px] leading-[20px] not-italic outline-none"
|
|
2939
|
+
),
|
|
2940
|
+
style: {
|
|
2941
|
+
...textareaProps.style,
|
|
2942
|
+
color: filledValue,
|
|
2943
|
+
caretColor: "var(--caret-color)"
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
)
|
|
2947
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex size-full items-start p-[14px]", children: [
|
|
2948
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2949
|
+
"p",
|
|
2950
|
+
{
|
|
2951
|
+
className: "pointer-events-none relative h-full min-h-[1px] min-w-0 flex-1 text-[16px] leading-[20px] not-italic",
|
|
2952
|
+
style: { color: floatLabel },
|
|
2953
|
+
children: [
|
|
2954
|
+
placeholder,
|
|
2955
|
+
required && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2956
|
+
"span",
|
|
2957
|
+
{
|
|
2958
|
+
style: {
|
|
2959
|
+
color: isDisabled ? "var(--disabled)" : "var(--error-dark)"
|
|
2960
|
+
},
|
|
2961
|
+
children: [
|
|
2962
|
+
" ",
|
|
2963
|
+
"*"
|
|
2964
|
+
]
|
|
2965
|
+
}
|
|
2966
|
+
)
|
|
2967
|
+
]
|
|
2968
|
+
}
|
|
2969
|
+
),
|
|
2970
|
+
!isDisabled && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2971
|
+
"textarea",
|
|
2972
|
+
{
|
|
2973
|
+
...textareaProps,
|
|
2974
|
+
value: currentValue,
|
|
2975
|
+
onChange: handleChange,
|
|
2976
|
+
onFocus: (e) => {
|
|
2977
|
+
var _a;
|
|
2978
|
+
(_a = textareaProps.onFocus) == null ? void 0 : _a.call(textareaProps, e);
|
|
2979
|
+
setFocused(true);
|
|
2980
|
+
},
|
|
2981
|
+
onBlur: (e) => {
|
|
2982
|
+
var _a;
|
|
2983
|
+
(_a = textareaProps.onBlur) == null ? void 0 : _a.call(textareaProps, e);
|
|
2984
|
+
setFocused(false);
|
|
2985
|
+
},
|
|
2986
|
+
rows,
|
|
2987
|
+
className: cn(
|
|
2988
|
+
"absolute inset-0 h-full w-full cursor-text resize-none border-none bg-transparent text-[16px] outline-none"
|
|
2989
|
+
),
|
|
2990
|
+
style: {
|
|
2991
|
+
...textareaProps.style,
|
|
2992
|
+
color: "transparent",
|
|
2993
|
+
caretColor: isFocus ? "var(--caret-color)" : "transparent",
|
|
2994
|
+
padding: "14px"
|
|
2995
|
+
},
|
|
2996
|
+
"aria-label": placeholder
|
|
2997
|
+
}
|
|
2998
|
+
)
|
|
2999
|
+
] })
|
|
3000
|
+
]
|
|
3001
|
+
}
|
|
3002
|
+
),
|
|
3003
|
+
showBelow && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3004
|
+
"div",
|
|
3005
|
+
{
|
|
3006
|
+
className: "flex items-start gap-[8px] px-[4px] text-[12px] leading-[16px]",
|
|
3007
|
+
children: [
|
|
3008
|
+
leftText ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", style: { color: leftColor }, children: leftText }) : showCount && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1" }),
|
|
3009
|
+
showCount && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3010
|
+
"span",
|
|
3011
|
+
{
|
|
3012
|
+
className: "shrink-0 whitespace-nowrap text-right",
|
|
3013
|
+
style: { color: countColor },
|
|
3014
|
+
children: [
|
|
3015
|
+
charCount,
|
|
3016
|
+
"/",
|
|
3017
|
+
maxCount
|
|
3018
|
+
]
|
|
3019
|
+
}
|
|
3020
|
+
)
|
|
3021
|
+
]
|
|
3022
|
+
}
|
|
3023
|
+
)
|
|
3024
|
+
] });
|
|
3025
|
+
}
|
|
3026
|
+
);
|
|
3027
|
+
TextArea.displayName = "TextArea";
|
|
3028
|
+
const HOURS = Array.from({ length: 24 }, (_, i) => i);
|
|
3029
|
+
const MINUTES = Array.from({ length: 60 }, (_, i) => i);
|
|
3030
|
+
const ITEM_H = 40;
|
|
3031
|
+
const DRUM_H = 248;
|
|
3032
|
+
const SPACER = (DRUM_H - ITEM_H) / 2;
|
|
3033
|
+
function generateHourlySlots() {
|
|
3034
|
+
return Array.from({ length: 24 }, (_, i) => ({
|
|
3035
|
+
start: { hour: i, minute: 0 },
|
|
3036
|
+
end: { hour: (i + 1) % 24, minute: 0 },
|
|
3037
|
+
label: `${pad2(i)}:00 - ${pad2((i + 1) % 24)}:00`
|
|
3038
|
+
}));
|
|
3039
|
+
}
|
|
3040
|
+
function slotMatches(slot, start, end) {
|
|
3041
|
+
return slot.start.hour === start.hour && slot.start.minute === start.minute && slot.end.hour === end.hour && slot.end.minute === end.minute;
|
|
3042
|
+
}
|
|
3043
|
+
function pad2(n) {
|
|
3044
|
+
return n.toString().padStart(2, "0");
|
|
3045
|
+
}
|
|
3046
|
+
function formatTime(v) {
|
|
3047
|
+
return `${pad2(v.hour)}:${pad2(v.minute)}`;
|
|
3048
|
+
}
|
|
3049
|
+
function ScrollColumn({
|
|
3050
|
+
items,
|
|
3051
|
+
value,
|
|
3052
|
+
onChange
|
|
3053
|
+
}) {
|
|
3054
|
+
const containerRef = React.useRef(null);
|
|
3055
|
+
const debounceRef = React.useRef(void 0);
|
|
3056
|
+
const [localValue, setLocalValue] = React.useState(value);
|
|
3057
|
+
const isUserScrolling = React.useRef(false);
|
|
3058
|
+
React.useEffect(() => {
|
|
3059
|
+
const el = containerRef.current;
|
|
3060
|
+
if (el) {
|
|
3061
|
+
el.scrollTop = items.indexOf(value) * ITEM_H;
|
|
3062
|
+
setLocalValue(value);
|
|
3063
|
+
}
|
|
3064
|
+
}, []);
|
|
3065
|
+
React.useEffect(() => {
|
|
3066
|
+
if (isUserScrolling.current) return;
|
|
3067
|
+
const el = containerRef.current;
|
|
3068
|
+
if (el) {
|
|
3069
|
+
const idx = items.indexOf(value);
|
|
3070
|
+
if (idx >= 0) {
|
|
3071
|
+
el.scrollTo({ top: idx * ITEM_H, behavior: "smooth" });
|
|
3072
|
+
setLocalValue(value);
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
}, [value, items]);
|
|
3076
|
+
const handleScroll = React.useCallback(() => {
|
|
3077
|
+
isUserScrolling.current = true;
|
|
3078
|
+
const el = containerRef.current;
|
|
3079
|
+
if (!el) return;
|
|
3080
|
+
const rawIdx = el.scrollTop / ITEM_H;
|
|
3081
|
+
const idx = Math.max(
|
|
3082
|
+
0,
|
|
3083
|
+
Math.min(Math.round(rawIdx), items.length - 1)
|
|
3084
|
+
);
|
|
3085
|
+
setLocalValue(items[idx]);
|
|
3086
|
+
clearTimeout(debounceRef.current);
|
|
3087
|
+
debounceRef.current = setTimeout(() => {
|
|
3088
|
+
isUserScrolling.current = false;
|
|
3089
|
+
const finalIdx = Math.max(
|
|
3090
|
+
0,
|
|
3091
|
+
Math.min(
|
|
3092
|
+
Math.round(el.scrollTop / ITEM_H),
|
|
3093
|
+
items.length - 1
|
|
3094
|
+
)
|
|
3095
|
+
);
|
|
3096
|
+
const finalValue = items[finalIdx];
|
|
3097
|
+
el.scrollTo({
|
|
3098
|
+
top: finalIdx * ITEM_H,
|
|
3099
|
+
behavior: "smooth"
|
|
3100
|
+
});
|
|
3101
|
+
onChange(finalValue);
|
|
3102
|
+
setLocalValue(finalValue);
|
|
3103
|
+
}, 120);
|
|
3104
|
+
}, [items, onChange]);
|
|
3105
|
+
const handleItemClick = React.useCallback(
|
|
3106
|
+
(item) => {
|
|
3107
|
+
var _a;
|
|
3108
|
+
const idx = items.indexOf(item);
|
|
3109
|
+
setLocalValue(item);
|
|
3110
|
+
onChange(item);
|
|
3111
|
+
(_a = containerRef.current) == null ? void 0 : _a.scrollTo({
|
|
3112
|
+
top: idx * ITEM_H,
|
|
3113
|
+
behavior: "smooth"
|
|
3114
|
+
});
|
|
3115
|
+
},
|
|
3116
|
+
[items, onChange]
|
|
3117
|
+
);
|
|
3118
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3119
|
+
"div",
|
|
3120
|
+
{
|
|
3121
|
+
ref: containerRef,
|
|
3122
|
+
className: "relative [&::-webkit-scrollbar]:hidden",
|
|
3123
|
+
style: {
|
|
3124
|
+
width: 39,
|
|
3125
|
+
height: DRUM_H,
|
|
3126
|
+
overflowY: "scroll",
|
|
3127
|
+
scrollSnapType: "y mandatory",
|
|
3128
|
+
scrollbarWidth: "none"
|
|
3129
|
+
},
|
|
3130
|
+
onScroll: handleScroll,
|
|
3131
|
+
children: [
|
|
3132
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: SPACER, flexShrink: 0 } }),
|
|
3133
|
+
items.map((item) => {
|
|
3134
|
+
const isSel = item === localValue;
|
|
3135
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3136
|
+
"div",
|
|
3137
|
+
{
|
|
3138
|
+
style: {
|
|
3139
|
+
height: ITEM_H,
|
|
3140
|
+
scrollSnapAlign: "center"
|
|
3141
|
+
},
|
|
3142
|
+
className: "flex items-center justify-center cursor-pointer select-none",
|
|
3143
|
+
onClick: () => handleItemClick(item),
|
|
3144
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3145
|
+
"span",
|
|
3146
|
+
{
|
|
3147
|
+
style: {
|
|
3148
|
+
fontSize: isSel ? 32 : 14,
|
|
3149
|
+
lineHeight: 1,
|
|
3150
|
+
color: isSel ? "var(--foreground)" : "var(--disabled)",
|
|
3151
|
+
transition: "font-size 0.1s, color 0.1s"
|
|
3152
|
+
},
|
|
3153
|
+
children: pad2(item)
|
|
3154
|
+
}
|
|
3155
|
+
)
|
|
3156
|
+
},
|
|
3157
|
+
item
|
|
3158
|
+
);
|
|
3159
|
+
}),
|
|
3160
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: SPACER, flexShrink: 0 } })
|
|
3161
|
+
]
|
|
3162
|
+
}
|
|
3163
|
+
);
|
|
3164
|
+
}
|
|
3165
|
+
const DEFAULT_SLOTS = generateHourlySlots();
|
|
3166
|
+
function RangeSlotPicker({
|
|
3167
|
+
slots = DEFAULT_SLOTS,
|
|
3168
|
+
startValue,
|
|
3169
|
+
endValue,
|
|
3170
|
+
onSelect
|
|
3171
|
+
}) {
|
|
3172
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3173
|
+
"div",
|
|
3174
|
+
{
|
|
3175
|
+
className: "overflow-y-auto [&::-webkit-scrollbar]:hidden",
|
|
3176
|
+
style: { maxHeight: 320, scrollbarWidth: "none", minWidth: 300 },
|
|
3177
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3178
|
+
"div",
|
|
3179
|
+
{
|
|
3180
|
+
className: "content-center grid grid-cols-2 gap-x-[20px] gap-y-[32px] items-center justify-between overflow-clip relative",
|
|
3181
|
+
style: { padding: "24px 40px" },
|
|
3182
|
+
children: slots.map((slot, idx) => {
|
|
3183
|
+
const isSelected = slotMatches(
|
|
3184
|
+
slot,
|
|
3185
|
+
startValue,
|
|
3186
|
+
endValue
|
|
3187
|
+
);
|
|
3188
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3189
|
+
"div",
|
|
3190
|
+
{
|
|
3191
|
+
onClick: () => onSelect(slot),
|
|
3192
|
+
className: cn(
|
|
3193
|
+
"content-stretch flex h-[25px] items-center justify-center relative rounded-[4px] shrink-0 cursor-pointer select-none transition-colors duration-100",
|
|
3194
|
+
isSelected ? "bg-primary-action" : "hover:bg-primary-action-light"
|
|
3195
|
+
),
|
|
3196
|
+
style: { padding: "2px 8px" },
|
|
3197
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3198
|
+
"p",
|
|
3199
|
+
{
|
|
3200
|
+
className: "leading-[22px] relative shrink-0 text-[14px] text-center whitespace-nowrap",
|
|
3201
|
+
style: {
|
|
3202
|
+
fontVariationSettings: "'wdth' 100",
|
|
3203
|
+
color: isSelected ? "#ffffff" : "var(--foreground)"
|
|
3204
|
+
},
|
|
3205
|
+
children: slot.label
|
|
3206
|
+
}
|
|
3207
|
+
)
|
|
3208
|
+
},
|
|
3209
|
+
idx
|
|
3210
|
+
);
|
|
3211
|
+
})
|
|
3212
|
+
}
|
|
3213
|
+
)
|
|
3214
|
+
}
|
|
3215
|
+
);
|
|
3216
|
+
}
|
|
3217
|
+
function TimePickerContent({
|
|
3218
|
+
mode,
|
|
3219
|
+
singleValue,
|
|
3220
|
+
onSingleChange,
|
|
3221
|
+
startValue,
|
|
3222
|
+
endValue,
|
|
3223
|
+
onStartChange,
|
|
3224
|
+
onEndChange
|
|
3225
|
+
}) {
|
|
3226
|
+
if (mode === "range") {
|
|
3227
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3228
|
+
RangeSlotPicker,
|
|
3229
|
+
{
|
|
3230
|
+
startValue,
|
|
3231
|
+
endValue,
|
|
3232
|
+
onSelect: (slot) => {
|
|
3233
|
+
onStartChange(slot.start);
|
|
3234
|
+
onEndChange(slot.end);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
);
|
|
3238
|
+
}
|
|
3239
|
+
const handleHour = (h) => onSingleChange({ ...singleValue, hour: h });
|
|
3240
|
+
const handleMinute = (m) => onSingleChange({ ...singleValue, minute: m });
|
|
3241
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
|
|
3242
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3243
|
+
"div",
|
|
3244
|
+
{
|
|
3245
|
+
className: "absolute left-0 right-0 rounded-[4px] bg-selected-light-bg pointer-events-none",
|
|
3246
|
+
style: {
|
|
3247
|
+
top: "50%",
|
|
3248
|
+
transform: "translateY(-50%)",
|
|
3249
|
+
height: ITEM_H,
|
|
3250
|
+
zIndex: 0
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
),
|
|
3254
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3255
|
+
"div",
|
|
3256
|
+
{
|
|
3257
|
+
className: "relative flex gap-[8px] items-center justify-center",
|
|
3258
|
+
style: { zIndex: 1 },
|
|
3259
|
+
children: [
|
|
3260
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3261
|
+
ScrollColumn,
|
|
3262
|
+
{
|
|
3263
|
+
items: HOURS,
|
|
3264
|
+
value: singleValue.hour,
|
|
3265
|
+
onChange: handleHour
|
|
3266
|
+
}
|
|
3267
|
+
),
|
|
3268
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3269
|
+
"div",
|
|
3270
|
+
{
|
|
3271
|
+
className: "flex items-center justify-center shrink-0",
|
|
3272
|
+
style: { height: ITEM_H, width: 8 },
|
|
3273
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3274
|
+
"span",
|
|
3275
|
+
{
|
|
3276
|
+
style: {
|
|
3277
|
+
fontSize: 32,
|
|
3278
|
+
lineHeight: 1,
|
|
3279
|
+
color: "var(--foreground)"
|
|
3280
|
+
},
|
|
3281
|
+
children: ":"
|
|
3282
|
+
}
|
|
3283
|
+
)
|
|
3284
|
+
}
|
|
3285
|
+
),
|
|
3286
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3287
|
+
ScrollColumn,
|
|
3288
|
+
{
|
|
3289
|
+
items: MINUTES,
|
|
3290
|
+
value: singleValue.minute,
|
|
3291
|
+
onChange: handleMinute
|
|
3292
|
+
}
|
|
3293
|
+
)
|
|
3294
|
+
]
|
|
3295
|
+
}
|
|
3296
|
+
)
|
|
3297
|
+
] });
|
|
3298
|
+
}
|
|
3299
|
+
const TimeInput = React.forwardRef(
|
|
3300
|
+
({
|
|
3301
|
+
mode = "single",
|
|
3302
|
+
placeholder = "Text label",
|
|
3303
|
+
required = false,
|
|
3304
|
+
forceState,
|
|
3305
|
+
errorMessage = "Error message",
|
|
3306
|
+
helperText,
|
|
3307
|
+
value,
|
|
3308
|
+
onChange,
|
|
3309
|
+
startTime,
|
|
3310
|
+
endTime,
|
|
3311
|
+
onStartChange,
|
|
3312
|
+
onEndChange,
|
|
3313
|
+
className
|
|
3314
|
+
}, ref) => {
|
|
3315
|
+
const [open, setOpen] = React.useState(false);
|
|
3316
|
+
const isMobile = useIsMobile();
|
|
3317
|
+
const [internalSingle, setInternalSingle] = React.useState(void 0);
|
|
3318
|
+
const [internalStart, setInternalStart] = React.useState({
|
|
3319
|
+
hour: 0,
|
|
3320
|
+
minute: 0
|
|
3321
|
+
});
|
|
3322
|
+
const [internalEnd, setInternalEnd] = React.useState({
|
|
3323
|
+
hour: 0,
|
|
3324
|
+
minute: 0
|
|
3325
|
+
});
|
|
3326
|
+
const [draftSingle, setDraftSingle] = React.useState({
|
|
3327
|
+
hour: 0,
|
|
3328
|
+
minute: 0
|
|
3329
|
+
});
|
|
3330
|
+
const [draftStart, setDraftStart] = React.useState({
|
|
3331
|
+
hour: 0,
|
|
3332
|
+
minute: 0
|
|
3333
|
+
});
|
|
3334
|
+
const [draftEnd, setDraftEnd] = React.useState({
|
|
3335
|
+
hour: 0,
|
|
3336
|
+
minute: 0
|
|
3337
|
+
});
|
|
3338
|
+
const isStatic = Boolean(forceState);
|
|
3339
|
+
const isDisabled = forceState === "disabled";
|
|
3340
|
+
const currentValue = value !== void 0 ? value : internalSingle;
|
|
3341
|
+
const currentStart = startTime !== void 0 ? startTime : internalStart;
|
|
3342
|
+
const currentEnd = endTime !== void 0 ? endTime : internalEnd;
|
|
3343
|
+
const state = forceState ?? (open ? "focus" : "default");
|
|
3344
|
+
const isError = state === "error";
|
|
3345
|
+
const isFocus = state === "focus";
|
|
3346
|
+
const isFilled = mode === "single" ? Boolean(currentValue) : true;
|
|
3347
|
+
const bgClass = isDisabled ? "bg-disabled-bg" : "bg-white";
|
|
3348
|
+
const labelColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
3349
|
+
const valueColor = isDisabled ? "var(--disabled)" : "var(--foreground)";
|
|
3350
|
+
const iconColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
3351
|
+
const minusColor = isDisabled ? "var(--disabled)" : "var(--muted-foreground)";
|
|
3352
|
+
const asteriskColor = isDisabled ? "var(--disabled)" : "var(--error-dark)";
|
|
3353
|
+
const asteriskSmall = isDisabled ? "var(--disabled)" : "var(--error-dark)";
|
|
3354
|
+
const borderInset = isFocus || isError ? "-1px" : "0px";
|
|
3355
|
+
const borderRad = isFocus || isError ? "9px" : "8px";
|
|
3356
|
+
const borderColor = isDisabled ? "var(--border-disabled)" : isError ? "var(--destructive)" : isFocus ? "var(--primary-action)" : "var(--border)";
|
|
3357
|
+
const showBelow = isError || Boolean(helperText);
|
|
3358
|
+
const leftText = isError ? errorMessage : helperText ?? "";
|
|
3359
|
+
const leftColor = isError ? "var(--error-dark)" : "var(--muted-foreground)";
|
|
3360
|
+
const commitSingle = React.useCallback(
|
|
3361
|
+
(v) => {
|
|
3362
|
+
if (value === void 0) setInternalSingle(v);
|
|
3363
|
+
onChange == null ? void 0 : onChange(v);
|
|
3364
|
+
},
|
|
3365
|
+
[value, onChange]
|
|
3366
|
+
);
|
|
3367
|
+
const commitStart = React.useCallback(
|
|
3368
|
+
(v) => {
|
|
3369
|
+
if (startTime === void 0) setInternalStart(v);
|
|
3370
|
+
onStartChange == null ? void 0 : onStartChange(v);
|
|
3371
|
+
},
|
|
3372
|
+
[startTime, onStartChange]
|
|
3373
|
+
);
|
|
3374
|
+
const commitEnd = React.useCallback(
|
|
3375
|
+
(v) => {
|
|
3376
|
+
if (endTime === void 0) setInternalEnd(v);
|
|
3377
|
+
onEndChange == null ? void 0 : onEndChange(v);
|
|
3378
|
+
},
|
|
3379
|
+
[endTime, onEndChange]
|
|
3380
|
+
);
|
|
3381
|
+
const renderContent = () => {
|
|
3382
|
+
if (isFilled && (mode === "range" || currentValue)) {
|
|
3383
|
+
const floatLabel = required ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[2px] items-center shrink-0 w-full", children: [
|
|
3384
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3385
|
+
"p",
|
|
3386
|
+
{
|
|
3387
|
+
className: "leading-[16px] not-italic shrink-0 text-[12px] whitespace-nowrap",
|
|
3388
|
+
style: { color: labelColor },
|
|
3389
|
+
children: placeholder
|
|
3390
|
+
}
|
|
3391
|
+
),
|
|
3392
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3393
|
+
"p",
|
|
3394
|
+
{
|
|
3395
|
+
className: "leading-[1.5] not-italic shrink-0 text-[9px] w-[7px]",
|
|
3396
|
+
style: { color: asteriskSmall },
|
|
3397
|
+
children: "*"
|
|
3398
|
+
}
|
|
3399
|
+
)
|
|
3400
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3401
|
+
"p",
|
|
3402
|
+
{
|
|
3403
|
+
className: "leading-[16px] not-italic shrink-0 text-[12px] w-full",
|
|
3404
|
+
style: { color: labelColor },
|
|
3405
|
+
children: placeholder
|
|
3406
|
+
}
|
|
3407
|
+
);
|
|
3408
|
+
const valueRow = mode === "single" && currentValue ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3409
|
+
"p",
|
|
3410
|
+
{
|
|
3411
|
+
className: "leading-[20px] not-italic shrink-0 text-[16px] w-full",
|
|
3412
|
+
style: { color: valueColor },
|
|
3413
|
+
children: formatTime(currentValue)
|
|
3414
|
+
}
|
|
3415
|
+
) : mode === "range" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[8px] items-center shrink-0 w-full", children: [
|
|
3416
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3417
|
+
"p",
|
|
3418
|
+
{
|
|
3419
|
+
className: "leading-[20px] not-italic shrink-0 text-[16px] whitespace-nowrap",
|
|
3420
|
+
style: { color: valueColor },
|
|
3421
|
+
children: formatTime(currentStart)
|
|
3422
|
+
}
|
|
3423
|
+
),
|
|
3424
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3425
|
+
react.Minus,
|
|
3426
|
+
{
|
|
3427
|
+
size: 20,
|
|
3428
|
+
color: minusColor,
|
|
3429
|
+
weight: "bold"
|
|
3430
|
+
}
|
|
3431
|
+
),
|
|
3432
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3433
|
+
"p",
|
|
3434
|
+
{
|
|
3435
|
+
className: "leading-[20px] not-italic shrink-0 text-[16px] whitespace-nowrap",
|
|
3436
|
+
style: { color: valueColor },
|
|
3437
|
+
children: formatTime(currentEnd)
|
|
3438
|
+
}
|
|
3439
|
+
)
|
|
3440
|
+
] }) : null;
|
|
3441
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "content-stretch flex flex-1 flex-col items-center justify-center min-h-px min-w-px relative", children: [
|
|
3442
|
+
floatLabel,
|
|
3443
|
+
valueRow
|
|
3444
|
+
] });
|
|
3445
|
+
}
|
|
3446
|
+
if (required) {
|
|
3447
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "content-stretch flex flex-1 min-w-px min-h-px gap-[2px] items-center relative", children: [
|
|
3448
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3449
|
+
"p",
|
|
3450
|
+
{
|
|
3451
|
+
className: "leading-[20px] not-italic shrink-0 text-[16px] whitespace-nowrap",
|
|
3452
|
+
style: { color: labelColor },
|
|
3453
|
+
children: placeholder
|
|
3454
|
+
}
|
|
3455
|
+
),
|
|
3456
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3457
|
+
"p",
|
|
3458
|
+
{
|
|
3459
|
+
className: "font-normal h-full leading-[1.5] not-italic shrink-0 text-[12px] w-[7px]",
|
|
3460
|
+
style: { color: asteriskColor },
|
|
3461
|
+
children: "*"
|
|
3462
|
+
}
|
|
3463
|
+
)
|
|
3464
|
+
] });
|
|
3465
|
+
}
|
|
3466
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3467
|
+
"p",
|
|
3468
|
+
{
|
|
3469
|
+
className: "flex-1 min-w-0 min-h-px text-[16px] leading-[20px] not-italic overflow-hidden text-ellipsis whitespace-nowrap relative",
|
|
3470
|
+
style: { color: labelColor },
|
|
3471
|
+
children: placeholder
|
|
3472
|
+
}
|
|
3473
|
+
);
|
|
3474
|
+
};
|
|
3475
|
+
const isTriggerFilled = isFilled && (mode === "range" || currentValue);
|
|
3476
|
+
const triggerPadding = isTriggerFilled ? "py-[6px]" : "py-[12px]";
|
|
3477
|
+
const triggerBase = cn(
|
|
3478
|
+
"relative flex gap-[8px] items-center rounded-[8px] px-[14px] w-full",
|
|
3479
|
+
bgClass,
|
|
3480
|
+
triggerPadding
|
|
3481
|
+
);
|
|
3482
|
+
const triggerInner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3483
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3484
|
+
"div",
|
|
3485
|
+
{
|
|
3486
|
+
"aria-hidden": "true",
|
|
3487
|
+
className: "absolute pointer-events-none border border-solid",
|
|
3488
|
+
style: {
|
|
3489
|
+
inset: borderInset,
|
|
3490
|
+
borderRadius: borderRad,
|
|
3491
|
+
borderColor
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
),
|
|
3495
|
+
renderContent(),
|
|
3496
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3497
|
+
"div",
|
|
3498
|
+
{
|
|
3499
|
+
className: cn(
|
|
3500
|
+
"flex flex-row items-center shrink-0",
|
|
3501
|
+
isTriggerFilled && "self-stretch"
|
|
3502
|
+
),
|
|
3503
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3504
|
+
react.Clock,
|
|
3505
|
+
{
|
|
3506
|
+
size: isTriggerFilled ? 22 : 24,
|
|
3507
|
+
color: iconColor,
|
|
3508
|
+
weight: "regular"
|
|
3509
|
+
}
|
|
3510
|
+
)
|
|
3511
|
+
}
|
|
3512
|
+
)
|
|
3513
|
+
] });
|
|
3514
|
+
const belowMsg = showBelow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start px-[4px] text-[12px] leading-[16px]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3515
|
+
"span",
|
|
3516
|
+
{
|
|
3517
|
+
className: "flex-1 min-w-0",
|
|
3518
|
+
style: { color: leftColor },
|
|
3519
|
+
children: leftText
|
|
3520
|
+
}
|
|
3521
|
+
) });
|
|
3522
|
+
if (isStatic) {
|
|
3523
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3524
|
+
"div",
|
|
3525
|
+
{
|
|
3526
|
+
ref,
|
|
3527
|
+
className: cn(
|
|
3528
|
+
"flex flex-col gap-[4px] w-full",
|
|
3529
|
+
className
|
|
3530
|
+
),
|
|
3531
|
+
children: [
|
|
3532
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: triggerBase, children: triggerInner }),
|
|
3533
|
+
belowMsg
|
|
3534
|
+
]
|
|
3535
|
+
}
|
|
3536
|
+
);
|
|
3537
|
+
}
|
|
3538
|
+
const handleOpenChange = (o) => {
|
|
3539
|
+
if (!isDisabled) {
|
|
3540
|
+
if (o) {
|
|
3541
|
+
setDraftSingle(
|
|
3542
|
+
currentValue ?? { hour: 0, minute: 0 }
|
|
3543
|
+
);
|
|
3544
|
+
setDraftStart(currentStart);
|
|
3545
|
+
setDraftEnd(currentEnd);
|
|
3546
|
+
}
|
|
3547
|
+
setOpen(o);
|
|
3548
|
+
}
|
|
3549
|
+
};
|
|
3550
|
+
const handleCancel = () => setOpen(false);
|
|
3551
|
+
const handleConfirm = () => {
|
|
3552
|
+
if (mode === "single") {
|
|
3553
|
+
commitSingle(draftSingle);
|
|
3554
|
+
} else {
|
|
3555
|
+
commitStart(draftStart);
|
|
3556
|
+
commitEnd(draftEnd);
|
|
3557
|
+
}
|
|
3558
|
+
setOpen(false);
|
|
3559
|
+
};
|
|
3560
|
+
const triggerButton = /* @__PURE__ */ jsxRuntime.jsx(
|
|
3561
|
+
"button",
|
|
3562
|
+
{
|
|
3563
|
+
type: "button",
|
|
3564
|
+
disabled: isDisabled,
|
|
3565
|
+
className: cn(
|
|
3566
|
+
triggerBase,
|
|
3567
|
+
"text-left cursor-pointer disabled:cursor-default"
|
|
3568
|
+
),
|
|
3569
|
+
children: triggerInner
|
|
3570
|
+
}
|
|
3571
|
+
);
|
|
3572
|
+
const pickerContent = /* @__PURE__ */ jsxRuntime.jsx(
|
|
3573
|
+
TimePickerContent,
|
|
3574
|
+
{
|
|
3575
|
+
mode,
|
|
3576
|
+
singleValue: draftSingle,
|
|
3577
|
+
onSingleChange: setDraftSingle,
|
|
3578
|
+
startValue: draftStart,
|
|
3579
|
+
endValue: draftEnd,
|
|
3580
|
+
onStartChange: setDraftStart,
|
|
3581
|
+
onEndChange: setDraftEnd
|
|
3582
|
+
}
|
|
3583
|
+
);
|
|
3584
|
+
const actionButtons = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-[12px] items-center pt-[12px]", children: [
|
|
3585
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3586
|
+
Button,
|
|
3587
|
+
{
|
|
3588
|
+
variant: "outline",
|
|
3589
|
+
size: "lg",
|
|
3590
|
+
className: "flex-1",
|
|
3591
|
+
onClick: handleCancel,
|
|
3592
|
+
children: "ยกเลิก"
|
|
3593
|
+
}
|
|
3594
|
+
),
|
|
3595
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3596
|
+
Button,
|
|
3597
|
+
{
|
|
3598
|
+
variant: "primary",
|
|
3599
|
+
size: "lg",
|
|
3600
|
+
className: "flex-1",
|
|
3601
|
+
onClick: handleConfirm,
|
|
3602
|
+
children: "ตกลง"
|
|
3603
|
+
}
|
|
3604
|
+
)
|
|
3605
|
+
] });
|
|
3606
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3607
|
+
"div",
|
|
3608
|
+
{
|
|
3609
|
+
ref,
|
|
3610
|
+
className: cn(
|
|
3611
|
+
"flex flex-col gap-[4px] w-full",
|
|
3612
|
+
className
|
|
3613
|
+
),
|
|
3614
|
+
children: [
|
|
3615
|
+
isMobile ? /* @__PURE__ */ jsxRuntime.jsxs(Drawer, { open, onOpenChange: handleOpenChange, children: [
|
|
3616
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerTrigger, { asChild: true, children: triggerButton }),
|
|
3617
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DrawerContent, { children: [
|
|
3618
|
+
/* @__PURE__ */ jsxRuntime.jsx(DrawerTitle, { className: "sr-only", children: "เลือกเวลา" }),
|
|
3619
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-auto px-4 pt-2 pb-8 w-full", children: [
|
|
3620
|
+
pickerContent,
|
|
3621
|
+
actionButtons
|
|
3622
|
+
] })
|
|
3623
|
+
] })
|
|
3624
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3625
|
+
Popover__namespace.Root,
|
|
3626
|
+
{
|
|
3627
|
+
open,
|
|
3628
|
+
onOpenChange: handleOpenChange,
|
|
3629
|
+
children: [
|
|
3630
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: triggerButton }),
|
|
3631
|
+
/* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3632
|
+
Popover__namespace.Content,
|
|
3633
|
+
{
|
|
3634
|
+
align: "start",
|
|
3635
|
+
sideOffset: 4,
|
|
3636
|
+
className: "z-50 rounded-[8px] bg-white p-3 outline-none max-w-[340px]",
|
|
3637
|
+
style: {
|
|
3638
|
+
boxShadow: "0px 20px 25px -5px rgba(0,0,0,0.1), 0px 8px 10px -6px rgba(0,0,0,0.1)",
|
|
3639
|
+
border: "1px solid rgba(0,0,0,0.08)",
|
|
3640
|
+
minWidth: mode === "single" ? 327 : void 0
|
|
3641
|
+
},
|
|
3642
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
3643
|
+
children: [
|
|
3644
|
+
pickerContent,
|
|
3645
|
+
actionButtons
|
|
3646
|
+
]
|
|
3647
|
+
}
|
|
3648
|
+
) })
|
|
3649
|
+
]
|
|
3650
|
+
}
|
|
3651
|
+
),
|
|
3652
|
+
belowMsg
|
|
3653
|
+
]
|
|
3654
|
+
}
|
|
3655
|
+
);
|
|
3656
|
+
}
|
|
3657
|
+
);
|
|
3658
|
+
TimeInput.displayName = "TimeInput";
|
|
3659
|
+
exports.Button = Button;
|
|
3660
|
+
exports.Card = Card;
|
|
3661
|
+
exports.DateInput = DateInput;
|
|
3662
|
+
exports.Dropdown = Dropdown;
|
|
3663
|
+
exports.DropdownMultiple = DropdownMultiple;
|
|
3664
|
+
exports.Input = Input;
|
|
3665
|
+
exports.OptionList = OptionList;
|
|
3666
|
+
exports.SearchInput = SearchInput;
|
|
3667
|
+
exports.Tab = Tab;
|
|
3668
|
+
exports.TabGroup = TabGroup;
|
|
3669
|
+
exports.TextArea = TextArea;
|
|
3670
|
+
exports.TimeInput = TimeInput;
|
|
3671
|
+
exports.cn = cn;
|
|
3672
|
+
//# sourceMappingURL=index.cjs.map
|