@avenue-ticketing/ui 0.3.0 → 0.5.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 (74) hide show
  1. package/dist/react/avatar.d.ts +42 -0
  2. package/dist/react/avatar.js +159 -0
  3. package/dist/react/avatar.js.map +1 -0
  4. package/dist/react/badge.d.ts +12 -0
  5. package/dist/react/badge.js +35 -1
  6. package/dist/react/badge.js.map +1 -1
  7. package/dist/react/button.d.ts +1 -1
  8. package/dist/react/button.js +3 -3
  9. package/dist/react/button.js.map +1 -1
  10. package/dist/react/calendar.d.ts +13 -0
  11. package/dist/react/calendar.js +4639 -0
  12. package/dist/react/calendar.js.map +1 -0
  13. package/dist/react/card.d.ts +11 -0
  14. package/dist/react/card.js +113 -0
  15. package/dist/react/card.js.map +1 -0
  16. package/dist/react/checkbox.d.ts +11 -0
  17. package/dist/react/checkbox.js +131 -0
  18. package/dist/react/checkbox.js.map +1 -0
  19. package/dist/react/datetime-picker.d.ts +21 -0
  20. package/dist/react/datetime-picker.js +6124 -0
  21. package/dist/react/datetime-picker.js.map +1 -0
  22. package/dist/react/dialog.d.ts +7 -0
  23. package/dist/react/dialog.js +211 -90
  24. package/dist/react/dialog.js.map +1 -1
  25. package/dist/react/dropdown.d.ts +126 -0
  26. package/dist/react/dropdown.js +1269 -0
  27. package/dist/react/dropdown.js.map +1 -0
  28. package/dist/react/input.d.ts +7 -0
  29. package/dist/react/input.js +15 -2
  30. package/dist/react/input.js.map +1 -1
  31. package/dist/react/pagination.d.ts +28 -0
  32. package/dist/react/pagination.js +262 -0
  33. package/dist/react/pagination.js.map +1 -0
  34. package/dist/react/popover.d.ts +76 -0
  35. package/dist/react/popover.js +564 -0
  36. package/dist/react/popover.js.map +1 -0
  37. package/dist/react/scroll-header.js +13 -1
  38. package/dist/react/scroll-header.js.map +1 -1
  39. package/dist/react/scroll-wheel.d.ts +45 -0
  40. package/dist/react/scroll-wheel.js +557 -0
  41. package/dist/react/scroll-wheel.js.map +1 -0
  42. package/dist/react/select.d.ts +62 -0
  43. package/dist/react/select.js +889 -0
  44. package/dist/react/select.js.map +1 -0
  45. package/dist/react/sheet.js +1 -1
  46. package/dist/react/sheet.js.map +1 -1
  47. package/dist/react/switch.d.ts +38 -0
  48. package/dist/react/switch.js +117 -0
  49. package/dist/react/switch.js.map +1 -0
  50. package/dist/react/table-pagination.d.ts +15 -0
  51. package/dist/react/table-pagination.js +1153 -0
  52. package/dist/react/table-pagination.js.map +1 -0
  53. package/dist/react/table-view/column-menu.d.ts +15 -0
  54. package/dist/react/table-view/column-menu.js +918 -0
  55. package/dist/react/table-view/column-menu.js.map +1 -0
  56. package/dist/react/table-view/index.d.ts +70 -0
  57. package/dist/react/table-view/index.js +2155 -0
  58. package/dist/react/table-view/index.js.map +1 -0
  59. package/dist/react/table.d.ts +86 -0
  60. package/dist/react/table.js +414 -0
  61. package/dist/react/table.js.map +1 -0
  62. package/dist/react/tabs.d.ts +9 -3
  63. package/dist/react/tabs.js +217 -57
  64. package/dist/react/tabs.js.map +1 -1
  65. package/dist/react/textarea.d.ts +6 -0
  66. package/dist/react/textarea.js +33 -0
  67. package/dist/react/textarea.js.map +1 -0
  68. package/dist/react/time-picker.d.ts +22 -0
  69. package/dist/react/time-picker.js +856 -0
  70. package/dist/react/time-picker.js.map +1 -0
  71. package/dist/react/tooltip.d.ts +45 -0
  72. package/dist/react/tooltip.js +540 -0
  73. package/dist/react/tooltip.js.map +1 -0
  74. package/package.json +1 -1
@@ -0,0 +1,889 @@
1
+ import * as React2 from 'react';
2
+ import { useCallback, useState, useRef, useMemo, useLayoutEffect, useEffect } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { X, ChevronDown, Check } from 'lucide-react';
5
+ import { clsx } from 'clsx';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ function cn(...inputs) {
10
+ return twMerge(clsx(inputs));
11
+ }
12
+ var sizeClass = {
13
+ xs: "h-8 min-h-8 gap-2 px-4 text-sm has-[>svg]:px-3 [&_svg:not([class*='size-'])]:size-3",
14
+ default: "h-10 min-h-10 gap-2 px-5 text-sm has-[>svg]:px-4 [&_svg:not([class*='size-'])]:size-4",
15
+ lg: "h-11 min-h-11 gap-2 px-6 text-base has-[>svg]:px-5 [&_svg:not([class*='size-'])]:size-5"
16
+ };
17
+ var iconOnlySizeClass = {
18
+ xs: "size-8 min-h-8 min-w-8 gap-0 p-0 [&_svg:not([class*='size-'])]:size-3",
19
+ default: "size-10 min-h-10 min-w-10 gap-0 p-0 [&_svg:not([class*='size-'])]:size-4",
20
+ lg: "size-11 min-h-11 min-w-11 gap-0 p-0 [&_svg:not([class*='size-'])]:size-5"
21
+ };
22
+ var roundedClass = {
23
+ full: "rounded-full",
24
+ lg: "rounded-lg",
25
+ md: "rounded-md"
26
+ };
27
+ var variantClass = {
28
+ primary: "bg-primary text-background border border-transparent hover:bg-primary/90 active:bg-primary/85",
29
+ secondary: "bg-background text-primary border border-primary/10 hover:bg-primary/5",
30
+ destructive: "bg-background text-red-500 border border-red-500/25 hover:bg-red-500/5",
31
+ success: "bg-background text-green-500 border border-green-500/25 hover:bg-green-500/5"
32
+ };
33
+ var Button = React2.forwardRef(
34
+ ({
35
+ className,
36
+ type = "button",
37
+ variant = "secondary",
38
+ rounded: roundedProp,
39
+ size = "default",
40
+ iconOnly = false,
41
+ disabled,
42
+ ...props
43
+ }, ref) => {
44
+ const rounded = roundedProp ?? (iconOnly ? "md" : "full");
45
+ return /* @__PURE__ */ jsx(
46
+ "button",
47
+ {
48
+ type,
49
+ disabled,
50
+ "data-slot": "button",
51
+ "data-icon-only": iconOnly ? "" : void 0,
52
+ className: cn(
53
+ "inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap outline-none scale-100 transition-[color,background-color,box-shadow,transform] duration-150 ease-out active:scale-[0.98] active:duration-100 active:ease-linear [&_svg]:pointer-events-none [&_svg]:shrink-0",
54
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
55
+ "focus-visible:border-ring font-medium lg:tracking-wide focus-visible:ring-ring/50 focus-visible:ring-[3px]",
56
+ iconOnly ? iconOnlySizeClass[size] : sizeClass[size],
57
+ roundedClass[rounded],
58
+ variantClass[variant],
59
+ className
60
+ ),
61
+ ref,
62
+ ...props
63
+ }
64
+ );
65
+ }
66
+ );
67
+ Button.displayName = "Button";
68
+ var PANEL_OPEN_EASING = "cubic-bezier(0,0.55,0.45,1)";
69
+ var PANEL_CLOSE_EASING = "cubic-bezier(0.55,0,1,0.45)";
70
+ var MOBILE_SHEET_MAX_PX = 1024;
71
+ var MOBILE_SHEET_MS = 175;
72
+ var MOBILE_SHEET_IN = "cubic-bezier(0.85, 0, 0.15, 1)";
73
+ var MOBILE_SHEET_OUT = "cubic-bezier(0.85, 0, 1, 0.15)";
74
+ var SLIDE_DEFAULT_PX = 120;
75
+ var SHEET_MENU_TEXT = "max-[1024px]:text-base";
76
+ var SHEET_MENU_SHORTCUT = "max-[1024px]:text-sm";
77
+ var CONTENT_ORIGIN = {
78
+ bottom: "top center",
79
+ top: "bottom center",
80
+ left: "right center",
81
+ right: "left center"
82
+ };
83
+ var CONTENT_HIDDEN = {
84
+ bottom: "translateY(-4px) scale(0.97)",
85
+ top: "translateY(4px) scale(0.97)",
86
+ left: "translateX(4px) scale(0.97)",
87
+ right: "translateX(-4px) scale(0.97)"
88
+ };
89
+ function computeMenuPosition(trigger, menu, side, align, offset, pad) {
90
+ const tr = trigger.getBoundingClientRect();
91
+ const mr = menu.getBoundingClientRect();
92
+ const vh = window.innerHeight;
93
+ const vw = window.innerWidth;
94
+ const sx = window.scrollX;
95
+ const sy = window.scrollY;
96
+ let top = 0;
97
+ let left = 0;
98
+ let effectiveSide = side;
99
+ const place = (s) => {
100
+ switch (s) {
101
+ case "bottom":
102
+ top = tr.bottom + sy + offset;
103
+ if (align === "start") left = tr.left + sx;
104
+ else if (align === "end") left = tr.right + sx - mr.width;
105
+ else left = tr.left + sx + tr.width / 2 - mr.width / 2;
106
+ break;
107
+ case "top":
108
+ top = tr.top + sy - mr.height - offset;
109
+ if (align === "start") left = tr.left + sx;
110
+ else if (align === "end") left = tr.right + sx - mr.width;
111
+ else left = tr.left + sx + tr.width / 2 - mr.width / 2;
112
+ break;
113
+ case "right":
114
+ left = tr.right + sx + offset;
115
+ if (align === "start") top = tr.top + sy;
116
+ else if (align === "end") top = tr.bottom + sy - mr.height;
117
+ else top = tr.top + sy + tr.height / 2 - mr.height / 2;
118
+ break;
119
+ case "left":
120
+ left = tr.left + sx - mr.width - offset;
121
+ if (align === "start") top = tr.top + sy;
122
+ else if (align === "end") top = tr.bottom + sy - mr.height;
123
+ else top = tr.top + sy + tr.height / 2 - mr.height / 2;
124
+ break;
125
+ }
126
+ };
127
+ place(side);
128
+ if (side === "bottom" && top + mr.height > vh + sy - pad) {
129
+ const flip = tr.top + sy - mr.height - offset;
130
+ if (flip >= sy + pad) {
131
+ effectiveSide = "top";
132
+ top = flip;
133
+ }
134
+ } else if (side === "top" && top < sy + pad) {
135
+ const flip = tr.bottom + sy + offset;
136
+ if (flip + mr.height <= vh + sy - pad) {
137
+ effectiveSide = "bottom";
138
+ top = flip;
139
+ }
140
+ } else if (side === "right" && left + mr.width > vw + sx - pad) {
141
+ const flip = tr.left + sx - mr.width - offset;
142
+ if (flip >= sx + pad) {
143
+ effectiveSide = "left";
144
+ left = flip;
145
+ }
146
+ } else if (side === "left" && left < sx + pad) {
147
+ const flip = tr.right + sx + offset;
148
+ if (flip + mr.width <= vw + sx - pad) {
149
+ effectiveSide = "right";
150
+ left = flip;
151
+ }
152
+ }
153
+ left = Math.max(sx + pad, Math.min(left, vw + sx - mr.width - pad));
154
+ top = Math.max(sy + pad, Math.min(top, vh + sy - mr.height - pad));
155
+ return { top, left, side: effectiveSide };
156
+ }
157
+ function useNarrowSheetViewport(breakpoint = 1025) {
158
+ const [narrow, setNarrow] = useState(false);
159
+ useEffect(() => {
160
+ const mq = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);
161
+ setNarrow(mq.matches);
162
+ const h = (e) => setNarrow(e.matches);
163
+ mq.addEventListener("change", h);
164
+ return () => mq.removeEventListener("change", h);
165
+ }, [breakpoint]);
166
+ return narrow;
167
+ }
168
+ function plainTextFromNode(node) {
169
+ if (node == null || node === false || node === true) return "";
170
+ if (typeof node === "string" || typeof node === "number")
171
+ return String(node);
172
+ if (Array.isArray(node)) return node.map(plainTextFromNode).join("");
173
+ if (React2.isValidElement(node)) {
174
+ return plainTextFromNode(
175
+ node.props.children
176
+ );
177
+ }
178
+ return "";
179
+ }
180
+ var ValueContext = React2.createContext(null);
181
+ function useSelectValue() {
182
+ const c = React2.useContext(ValueContext);
183
+ if (!c) throw new Error("Select subcomponents must be used within <Select>");
184
+ return c;
185
+ }
186
+ var OpenContext = React2.createContext(null);
187
+ function useSelectOpen() {
188
+ const c = React2.useContext(OpenContext);
189
+ if (!c)
190
+ throw new Error(
191
+ "Select.Trigger, SelectContent, and SelectItem need <Select> without native"
192
+ );
193
+ return c;
194
+ }
195
+ var Select = ({
196
+ children,
197
+ className,
198
+ value: valueProp,
199
+ defaultValue = "",
200
+ onValueChange,
201
+ native: nativeProp = false,
202
+ disabled = false,
203
+ name,
204
+ id: idAttr,
205
+ placeholder = "Select",
206
+ open: openProp,
207
+ onOpenChange
208
+ }) => {
209
+ const isValueControlled = valueProp !== void 0;
210
+ const [internalValue, setInternalValue] = useState(defaultValue);
211
+ const value = isValueControlled ? valueProp : internalValue;
212
+ const [labels, setLabels] = useState({});
213
+ const [nativeMeta, setNativeMeta] = useState({});
214
+ const [nativeOrder, setNativeOrder] = useState([]);
215
+ const setValue = useCallback(
216
+ (v) => {
217
+ if (!isValueControlled) setInternalValue(v);
218
+ onValueChange?.(v);
219
+ },
220
+ [isValueControlled, onValueChange]
221
+ );
222
+ const setLabel = useCallback((v, n) => {
223
+ setLabels((p) => p[v] === n ? p : { ...p, [v]: n });
224
+ }, []);
225
+ const clearLabel = useCallback((v) => {
226
+ setLabels((p) => {
227
+ if (!(v in p)) return p;
228
+ const n = { ...p };
229
+ delete n[v];
230
+ return n;
231
+ });
232
+ }, []);
233
+ const labelsRef = useRef(labels);
234
+ labelsRef.current = labels;
235
+ const labelFor = useCallback(
236
+ (v) => labelsRef.current[v],
237
+ []
238
+ );
239
+ const registerNativeItem = useCallback(
240
+ (e) => {
241
+ setLabel(e.value, e.label);
242
+ setNativeMeta((p) => ({ ...p, [e.value]: { label: e.label, disabled: e.disabled } }));
243
+ setNativeOrder((o) => o.includes(e.value) ? o : [...o, e.value]);
244
+ },
245
+ [setLabel]
246
+ );
247
+ const unregisterNativeItem = useCallback(
248
+ (v) => {
249
+ setNativeMeta((p) => {
250
+ if (!(v in p)) return p;
251
+ const n = { ...p };
252
+ delete n[v];
253
+ return n;
254
+ });
255
+ setNativeOrder((o) => o.filter((x) => x !== v));
256
+ clearLabel(v);
257
+ },
258
+ [clearLabel]
259
+ );
260
+ const valueCtx = useMemo(
261
+ () => ({
262
+ native: nativeProp,
263
+ value,
264
+ setValue,
265
+ disabled,
266
+ setLabel,
267
+ clearLabel,
268
+ registerNativeItem,
269
+ unregisterNativeItem,
270
+ labelFor,
271
+ placeholder
272
+ }),
273
+ [
274
+ nativeProp,
275
+ value,
276
+ setValue,
277
+ disabled,
278
+ labels,
279
+ setLabel,
280
+ clearLabel,
281
+ registerNativeItem,
282
+ unregisterNativeItem,
283
+ labelFor,
284
+ placeholder
285
+ ]
286
+ );
287
+ if (nativeProp) {
288
+ return /* @__PURE__ */ jsxs(ValueContext.Provider, { value: valueCtx, children: [
289
+ /* @__PURE__ */ jsxs(
290
+ "div",
291
+ {
292
+ className: cn(
293
+ "group relative inline-block w-max min-w-0 max-w-full",
294
+ className
295
+ ),
296
+ children: [
297
+ /* @__PURE__ */ jsxs(
298
+ "select",
299
+ {
300
+ id: idAttr,
301
+ name,
302
+ className: cn(
303
+ "peer",
304
+ "border-primary/10 bg-background text-primary w-full min-w-0 max-w-full cursor-pointer appearance-none border pr-9 pl-3 outline-none",
305
+ "h-10 min-h-10 text-sm font-medium",
306
+ "rounded-full transition-[color,background-color,box-shadow,transform] duration-150",
307
+ "focus-visible:ring-ring/50 focus-visible:ring-[3px]",
308
+ "active:scale-[0.99]",
309
+ "disabled:cursor-not-allowed disabled:opacity-50"
310
+ ),
311
+ value,
312
+ disabled,
313
+ onChange: (ev) => setValue(ev.target.value),
314
+ children: [
315
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
316
+ nativeOrder.map((key) => {
317
+ const m = nativeMeta[key];
318
+ if (!m) return null;
319
+ return /* @__PURE__ */ jsx("option", { value: key, disabled: m.disabled, children: plainTextFromNode(m.label) }, key);
320
+ })
321
+ ]
322
+ }
323
+ ),
324
+ /* @__PURE__ */ jsx(
325
+ ChevronDown,
326
+ {
327
+ "aria-hidden": true,
328
+ className: "text-primary/50 pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 peer-disabled:opacity-50"
329
+ }
330
+ )
331
+ ]
332
+ }
333
+ ),
334
+ children
335
+ ] });
336
+ }
337
+ return /* @__PURE__ */ jsx(ValueContext.Provider, { value: valueCtx, children: /* @__PURE__ */ jsx(SelectOpenBridge, { open: openProp, onOpenChange, children: /* @__PURE__ */ jsx("div", { className: cn("inline-block min-w-0 max-w-full", className), children }) }) });
338
+ };
339
+ function SelectOpenBridge({
340
+ children,
341
+ open: controlled,
342
+ onOpenChange
343
+ }) {
344
+ const [inner, setInner] = useState(false);
345
+ const isControlled = controlled !== void 0;
346
+ const open = isControlled ? controlled : inner;
347
+ const setOpen = useCallback(
348
+ (o) => {
349
+ if (!isControlled) setInner(o);
350
+ onOpenChange?.(o);
351
+ },
352
+ [isControlled, onOpenChange]
353
+ );
354
+ const triggerRef = useRef(null);
355
+ const ctx = useMemo(
356
+ () => ({ open, setOpen, triggerRef }),
357
+ [open, setOpen]
358
+ );
359
+ return /* @__PURE__ */ jsx(OpenContext.Provider, { value: ctx, children });
360
+ }
361
+ var SheetClose = React2.forwardRef(({ className, type = "button", ...p }, ref) => /* @__PURE__ */ jsxs(
362
+ "button",
363
+ {
364
+ ref,
365
+ type,
366
+ className: cn(
367
+ "z-100 flex size-12 shrink-0 cursor-pointer items-center justify-center rounded-full transition-all hover:bg-secondary-background active:scale-[0.96]",
368
+ className
369
+ ),
370
+ ...p,
371
+ children: [
372
+ /* @__PURE__ */ jsx(X, { className: "size-5.5" }),
373
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
374
+ ]
375
+ }
376
+ ));
377
+ SheetClose.displayName = "SelectSheetClose";
378
+ function resolveSheetOpts(o) {
379
+ return {
380
+ sheet: o?.sheet ?? true,
381
+ title: o?.title,
382
+ panelClass: o?.className,
383
+ bodyClass: o?.contentClassName
384
+ };
385
+ }
386
+ function MobileSheetPortal({
387
+ open,
388
+ isAnimating,
389
+ slideEntrance,
390
+ slideOffsetPx,
391
+ sheetTitle,
392
+ sheetPanelClassName,
393
+ contentClassName,
394
+ onRequestClose,
395
+ menuRef,
396
+ children,
397
+ className,
398
+ style,
399
+ ...rest
400
+ }) {
401
+ const ease = open ? MOBILE_SHEET_IN : MOBILE_SHEET_OUT;
402
+ const hiddenY = slideEntrance ? `translateY(${slideOffsetPx}px)` : "translateY(100%)";
403
+ return createPortal(
404
+ /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-end justify-center p-0", children: [
405
+ /* @__PURE__ */ jsx(
406
+ "div",
407
+ {
408
+ className: cn(
409
+ "fixed inset-0 bg-black/40 dark:bg-black/60",
410
+ isAnimating ? "opacity-100" : "opacity-0"
411
+ ),
412
+ style: {
413
+ transition: `opacity ${MOBILE_SHEET_MS}ms ${ease}`
414
+ },
415
+ onClick: onRequestClose
416
+ }
417
+ ),
418
+ /* @__PURE__ */ jsxs(
419
+ "div",
420
+ {
421
+ ...rest,
422
+ ref: menuRef,
423
+ className: cn(
424
+ "bg-background border-primary/10 relative z-10 flex w-full max-h-[min(90dvh,calc(100dvh-env(safe-area-inset-bottom,0px)))] flex-col overflow-hidden shadow-2xl outline-none",
425
+ "rounded-t-2xl rounded-b-none border-x-0 border-b-0 border-t",
426
+ sheetPanelClassName,
427
+ className
428
+ ),
429
+ style: {
430
+ transform: isAnimating ? "translateY(0)" : hiddenY,
431
+ opacity: isAnimating ? 1 : 0,
432
+ transition: `transform ${MOBILE_SHEET_MS}ms ${ease}, opacity ${MOBILE_SHEET_MS}ms ${ease}`,
433
+ ...style
434
+ },
435
+ children: [
436
+ /* @__PURE__ */ jsxs(
437
+ "div",
438
+ {
439
+ className: cn(
440
+ "flex w-full shrink-0 items-center py-2 pl-4 pr-2",
441
+ sheetTitle ? "justify-between gap-3" : "justify-end"
442
+ ),
443
+ children: [
444
+ sheetTitle ? /* @__PURE__ */ jsx("p", { className: "text-foreground min-w-0 flex-1 truncate text-base font-semibold", children: sheetTitle }) : null,
445
+ /* @__PURE__ */ jsx(
446
+ SheetClose,
447
+ {
448
+ onClick: (e) => {
449
+ e.stopPropagation();
450
+ onRequestClose();
451
+ }
452
+ }
453
+ )
454
+ ]
455
+ }
456
+ ),
457
+ /* @__PURE__ */ jsx(
458
+ "div",
459
+ {
460
+ className: cn(
461
+ "min-h-0 flex-1 overflow-y-auto pb-[calc(5rem+env(safe-area-inset-bottom,0px))]",
462
+ contentClassName
463
+ ),
464
+ children
465
+ }
466
+ )
467
+ ]
468
+ }
469
+ )
470
+ ] }),
471
+ document.body
472
+ );
473
+ }
474
+ function listFocusableItems(host) {
475
+ return Array.from(
476
+ host.querySelectorAll(
477
+ '[data-select-item="true"]:not([aria-disabled="true"])'
478
+ )
479
+ );
480
+ }
481
+ var SelectContent = ({
482
+ children,
483
+ side = "bottom",
484
+ align = "start",
485
+ offset = 10,
486
+ duration = 80,
487
+ viewportPadding = 8,
488
+ closeOnEscape = true,
489
+ minWidth = "trigger",
490
+ loop = true,
491
+ mobileOptions,
492
+ slideEntrance = true,
493
+ slideEntranceOffsetPx: slidePxProp,
494
+ className,
495
+ style,
496
+ ...rest
497
+ }) => {
498
+ const narrow = useNarrowSheetViewport(MOBILE_SHEET_MAX_PX + 1);
499
+ const { open, setOpen, triggerRef } = useSelectOpen();
500
+ const [show, setShow] = useState(false);
501
+ const [anim, setAnim] = useState(false);
502
+ const [pos, setPos] = useState({ top: -9999, left: -9999, side });
503
+ const [triggerW, setTriggerW] = useState(0);
504
+ const menuRef = useRef(null);
505
+ const sheet = useMemo(() => resolveSheetOpts(mobileOptions), [mobileOptions]);
506
+ const slidePx = slidePxProp ?? SLIDE_DEFAULT_PX;
507
+ const closeMs = narrow && sheet.sheet ? MOBILE_SHEET_MS : duration;
508
+ const close = useCallback(() => setOpen(false), [setOpen]);
509
+ const [portalReady, setPortalReady] = useState(false);
510
+ useLayoutEffect(() => {
511
+ setPortalReady(true);
512
+ }, []);
513
+ useEffect(() => {
514
+ if (open) {
515
+ setShow(true);
516
+ } else {
517
+ setAnim(false);
518
+ const t = setTimeout(() => setShow(false), closeMs);
519
+ return () => clearTimeout(t);
520
+ }
521
+ }, [open, closeMs]);
522
+ useEffect(() => {
523
+ if (!show || !open) return;
524
+ let r2 = 0;
525
+ const r1 = requestAnimationFrame(() => {
526
+ r2 = requestAnimationFrame(() => setAnim(true));
527
+ });
528
+ return () => {
529
+ cancelAnimationFrame(r1);
530
+ if (r2) cancelAnimationFrame(r2);
531
+ };
532
+ }, [show, open]);
533
+ useLayoutEffect(() => {
534
+ if (!triggerRef.current || !menuRef.current) return;
535
+ if (!open && !show) return;
536
+ const run = () => {
537
+ if (!triggerRef.current || !menuRef.current) return;
538
+ setTriggerW(triggerRef.current.getBoundingClientRect().width);
539
+ setPos(
540
+ computeMenuPosition(
541
+ triggerRef.current,
542
+ menuRef.current,
543
+ side,
544
+ align,
545
+ offset,
546
+ viewportPadding
547
+ )
548
+ );
549
+ };
550
+ run();
551
+ window.addEventListener("resize", run);
552
+ window.addEventListener("scroll", run, true);
553
+ return () => {
554
+ window.removeEventListener("resize", run);
555
+ window.removeEventListener("scroll", run, true);
556
+ };
557
+ }, [open, show, side, align, offset, viewportPadding, triggerRef]);
558
+ useEffect(() => {
559
+ if (anim && menuRef.current) menuRef.current.focus();
560
+ }, [anim]);
561
+ useEffect(() => {
562
+ if (!open) return;
563
+ const onDoc = (e) => {
564
+ const t = e.target;
565
+ if (menuRef.current?.contains(t) || triggerRef.current?.contains(t)) return;
566
+ setOpen(false);
567
+ };
568
+ document.addEventListener("mousedown", onDoc);
569
+ return () => document.removeEventListener("mousedown", onDoc);
570
+ }, [open, setOpen, triggerRef]);
571
+ useEffect(() => {
572
+ if (!open) return;
573
+ const onKey = (e) => {
574
+ const m = menuRef.current;
575
+ if (!m) return;
576
+ const active = document.activeElement;
577
+ if (active && !m.contains(active) && !triggerRef.current?.contains(active))
578
+ return;
579
+ const items = listFocusableItems(m);
580
+ const i = items.indexOf(active);
581
+ switch (e.key) {
582
+ case "Escape":
583
+ if (closeOnEscape) {
584
+ e.preventDefault();
585
+ setOpen(false);
586
+ triggerRef.current?.focus();
587
+ }
588
+ break;
589
+ case "ArrowDown":
590
+ e.preventDefault();
591
+ if (!items.length) break;
592
+ if (i === -1 || i === items.length - 1 && loop) items[0]?.focus();
593
+ else if (i < items.length - 1) items[i + 1]?.focus();
594
+ break;
595
+ case "ArrowUp":
596
+ e.preventDefault();
597
+ if (!items.length) break;
598
+ if (i <= 0 && loop) items[items.length - 1]?.focus();
599
+ else if (i > 0) items[i - 1]?.focus();
600
+ break;
601
+ case "Home":
602
+ e.preventDefault();
603
+ items[0]?.focus();
604
+ break;
605
+ case "End":
606
+ e.preventDefault();
607
+ items[items.length - 1]?.focus();
608
+ break;
609
+ case "Tab":
610
+ setOpen(false);
611
+ break;
612
+ }
613
+ };
614
+ window.addEventListener("keydown", onKey);
615
+ return () => window.removeEventListener("keydown", onKey);
616
+ }, [open, closeOnEscape, loop, setOpen, triggerRef]);
617
+ const lockBodyScroll = (open || show) && narrow && sheet.sheet;
618
+ useEffect(() => {
619
+ if (!lockBodyScroll) return;
620
+ const prev = document.body.style.overflow;
621
+ document.body.style.overflow = "hidden";
622
+ return () => {
623
+ document.body.style.overflow = prev;
624
+ };
625
+ }, [lockBodyScroll]);
626
+ if (narrow && sheet.sheet) {
627
+ if (!open && !show) {
628
+ const registrationSlot = /* @__PURE__ */ jsx("div", { className: "sr-only pointer-events-none", "aria-hidden": true, children });
629
+ if (!portalReady) return registrationSlot;
630
+ return createPortal(registrationSlot, document.body);
631
+ }
632
+ return /* @__PURE__ */ jsx(
633
+ MobileSheetPortal,
634
+ {
635
+ ...rest,
636
+ open,
637
+ isAnimating: anim,
638
+ slideEntrance,
639
+ slideOffsetPx: slidePx,
640
+ sheetTitle: sheet.title,
641
+ sheetPanelClassName: sheet.panelClass,
642
+ contentClassName: sheet.bodyClass,
643
+ onRequestClose: close,
644
+ menuRef,
645
+ className,
646
+ style,
647
+ role: "listbox",
648
+ tabIndex: -1,
649
+ "aria-label": sheet.title,
650
+ children
651
+ }
652
+ );
653
+ }
654
+ const resolvedMin = minWidth === "trigger" ? triggerW > 0 ? triggerW : void 0 : minWidth;
655
+ const listbox = /* @__PURE__ */ jsx(
656
+ "div",
657
+ {
658
+ ...rest,
659
+ ref: menuRef,
660
+ role: "listbox",
661
+ tabIndex: -1,
662
+ "aria-hidden": !open,
663
+ className: cn(
664
+ "bg-background border-primary/10 absolute z-50 overflow-hidden rounded-xl border py-1.5 shadow-xl outline-none",
665
+ className
666
+ ),
667
+ style: {
668
+ position: "absolute",
669
+ top: pos.top,
670
+ left: pos.left,
671
+ ...typeof resolvedMin === "number" ? { minWidth: resolvedMin } : {},
672
+ transformOrigin: CONTENT_ORIGIN[pos.side],
673
+ transform: anim ? "none" : CONTENT_HIDDEN[pos.side],
674
+ opacity: anim ? 1 : 0,
675
+ pointerEvents: !open ? "none" : "auto",
676
+ transitionProperty: "opacity, transform",
677
+ transitionDuration: `${duration}ms`,
678
+ transitionTimingFunction: anim ? PANEL_OPEN_EASING : PANEL_CLOSE_EASING,
679
+ ...style
680
+ },
681
+ children
682
+ }
683
+ );
684
+ if (!portalReady) {
685
+ return listbox;
686
+ }
687
+ return createPortal(listbox, document.body);
688
+ };
689
+ function mergeRef(store, node, fromChild) {
690
+ store.current = node;
691
+ if (typeof fromChild === "function") fromChild(node);
692
+ else if (fromChild && typeof fromChild === "object")
693
+ fromChild.current = node;
694
+ }
695
+ var SelectTrigger = React2.forwardRef(
696
+ function SelectTrigger2({ children, asChild, className, onClick, disabled, ...buttonProps }, ref) {
697
+ const { open, setOpen, triggerRef } = useSelectOpen();
698
+ const triggerVariant = buttonProps.variant ?? "secondary";
699
+ const onPress = useCallback(
700
+ (e) => {
701
+ onClick?.(
702
+ e
703
+ );
704
+ e.stopPropagation();
705
+ if (disabled) return;
706
+ setOpen(!open);
707
+ },
708
+ [onClick, disabled, open, setOpen]
709
+ );
710
+ const setBtnRef = useCallback(
711
+ (el) => {
712
+ mergeRef(triggerRef, el, null);
713
+ if (typeof ref === "function") ref(el);
714
+ else if (ref) ref.current = el;
715
+ },
716
+ [ref, triggerRef]
717
+ );
718
+ if (asChild && React2.isValidElement(children)) {
719
+ const ch = children;
720
+ const childRef = ch.ref;
721
+ return React2.cloneElement(ch, {
722
+ ref: (n) => mergeRef(triggerRef, n, childRef),
723
+ className: cn("group w-fit max-w-full min-w-0 justify-start gap-2", ch.props.className),
724
+ onClick: (e) => {
725
+ ch.props.onClick?.(e);
726
+ onPress(e);
727
+ },
728
+ "aria-expanded": open,
729
+ "aria-haspopup": "listbox",
730
+ "data-state": open ? "open" : "closed",
731
+ "data-variant": triggerVariant,
732
+ ...disabled !== void 0 ? { "aria-disabled": disabled } : {}
733
+ });
734
+ }
735
+ return /* @__PURE__ */ jsx(
736
+ Button,
737
+ {
738
+ ref: setBtnRef,
739
+ type: "button",
740
+ ...buttonProps,
741
+ disabled,
742
+ className: cn("group w-fit max-w-full min-w-0 justify-start gap-2", className),
743
+ "aria-expanded": open,
744
+ "aria-haspopup": "listbox",
745
+ "data-state": open ? "open" : "closed",
746
+ "data-variant": triggerVariant,
747
+ onClick: onPress,
748
+ children
749
+ }
750
+ );
751
+ }
752
+ );
753
+ SelectTrigger.displayName = "SelectTrigger";
754
+ var SelectChevron = ({
755
+ className,
756
+ ...props
757
+ }) => {
758
+ const { open } = useSelectOpen();
759
+ return /* @__PURE__ */ jsx(
760
+ ChevronDown,
761
+ {
762
+ "aria-hidden": true,
763
+ className: cn("size-4 shrink-0", open && "rotate-180", className),
764
+ ...props
765
+ }
766
+ );
767
+ };
768
+ var SelectValue = ({ placeholder, className }) => {
769
+ const c = useSelectValue();
770
+ if (c.native) return null;
771
+ const ph = placeholder ?? c.placeholder;
772
+ const text = c.value ? c.labelFor(c.value) : void 0;
773
+ const isEmpty = !c.value;
774
+ return /* @__PURE__ */ jsx(
775
+ "span",
776
+ {
777
+ "data-slot": "select-value",
778
+ className: cn(
779
+ "min-w-0 flex-1 truncate text-left",
780
+ isEmpty && cn(
781
+ "group-data-[variant=primary]:!text-background/50",
782
+ "group-data-[variant=secondary]:!text-primary/50",
783
+ "group-data-[variant=destructive]:!text-red-500/50",
784
+ "group-data-[variant=success]:!text-green-500/50"
785
+ ),
786
+ className
787
+ ),
788
+ children: text != null ? text : ph
789
+ }
790
+ );
791
+ };
792
+ var SelectItemRow = ({
793
+ value: v,
794
+ children,
795
+ disabled,
796
+ shortcut,
797
+ className,
798
+ onClick: userClick,
799
+ ...divProps
800
+ }) => {
801
+ const c = useSelectValue();
802
+ const { setOpen } = useSelectOpen();
803
+ const selected = c.value === v;
804
+ const click = (e) => {
805
+ if (disabled) return;
806
+ c.setValue(v);
807
+ userClick?.(e);
808
+ setOpen(false);
809
+ };
810
+ const keyDown = (e) => {
811
+ if (e.key === "Enter" || e.key === " ") {
812
+ e.preventDefault();
813
+ click(e);
814
+ }
815
+ };
816
+ return /* @__PURE__ */ jsxs(
817
+ "div",
818
+ {
819
+ ...divProps,
820
+ "data-select-item": "true",
821
+ role: "option",
822
+ "aria-selected": selected,
823
+ tabIndex: disabled ? void 0 : -1,
824
+ "aria-disabled": disabled,
825
+ onClick: click,
826
+ onKeyDown: keyDown,
827
+ className: cn(
828
+ "relative mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors duration-0 outline-none select-none",
829
+ SHEET_MENU_TEXT,
830
+ !disabled && "text-foreground hover:bg-primary/8 focus-visible:bg-primary/8 dark:hover:bg-primary/4 dark:focus-visible:bg-primary/4",
831
+ disabled && "lg:cursor-not-allowed text-foreground/45 dark:text-foreground/50",
832
+ !disabled && "cursor-pointer",
833
+ className
834
+ ),
835
+ children: [
836
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children }),
837
+ shortcut ? /* @__PURE__ */ jsx(
838
+ "span",
839
+ {
840
+ className: cn(
841
+ "shrink-0 text-xs tracking-widest opacity-40",
842
+ SHEET_MENU_SHORTCUT
843
+ ),
844
+ children: shortcut
845
+ }
846
+ ) : null,
847
+ /* @__PURE__ */ jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", "aria-hidden": true, children: selected ? /* @__PURE__ */ jsx(Check, { className: "size-3.5", strokeWidth: 2.5 }) : null })
848
+ ]
849
+ }
850
+ );
851
+ };
852
+ var SelectItem = ({
853
+ value: v,
854
+ children,
855
+ disabled,
856
+ ...rest
857
+ }) => {
858
+ const {
859
+ native,
860
+ setLabel,
861
+ clearLabel,
862
+ registerNativeItem,
863
+ unregisterNativeItem
864
+ } = useSelectValue();
865
+ useLayoutEffect(() => {
866
+ setLabel(v, children);
867
+ if (native) registerNativeItem({ value: v, label: children, disabled });
868
+ return () => {
869
+ clearLabel(v);
870
+ if (native) unregisterNativeItem(v);
871
+ };
872
+ }, [
873
+ v,
874
+ children,
875
+ disabled,
876
+ native,
877
+ setLabel,
878
+ clearLabel,
879
+ registerNativeItem,
880
+ unregisterNativeItem
881
+ ]);
882
+ if (native) return null;
883
+ return /* @__PURE__ */ jsx(SelectItemRow, { value: v, disabled, ...rest, children });
884
+ };
885
+ SelectItem.displayName = "SelectItem";
886
+
887
+ export { Select, SelectChevron, SelectContent, SelectItem, SelectTrigger, SelectValue };
888
+ //# sourceMappingURL=select.js.map
889
+ //# sourceMappingURL=select.js.map