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