@avenue-ticketing/ui 0.4.0 → 0.6.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 (73) 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 +129 -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.js +1 -1
  23. package/dist/react/dialog.js.map +1 -1
  24. package/dist/react/dropdown.d.ts +34 -9
  25. package/dist/react/dropdown.js +295 -144
  26. package/dist/react/dropdown.js.map +1 -1
  27. package/dist/react/input.d.ts +7 -0
  28. package/dist/react/input.js +15 -2
  29. package/dist/react/input.js.map +1 -1
  30. package/dist/react/pagination.d.ts +28 -0
  31. package/dist/react/pagination.js +262 -0
  32. package/dist/react/pagination.js.map +1 -0
  33. package/dist/react/popover.d.ts +76 -0
  34. package/dist/react/popover.js +564 -0
  35. package/dist/react/popover.js.map +1 -0
  36. package/dist/react/scroll-header.js +13 -1
  37. package/dist/react/scroll-header.js.map +1 -1
  38. package/dist/react/scroll-wheel.d.ts +45 -0
  39. package/dist/react/scroll-wheel.js +557 -0
  40. package/dist/react/scroll-wheel.js.map +1 -0
  41. package/dist/react/select.d.ts +62 -0
  42. package/dist/react/select.js +889 -0
  43. package/dist/react/select.js.map +1 -0
  44. package/dist/react/sheet.js +1 -1
  45. package/dist/react/sheet.js.map +1 -1
  46. package/dist/react/switch.d.ts +38 -0
  47. package/dist/react/switch.js +117 -0
  48. package/dist/react/switch.js.map +1 -0
  49. package/dist/react/table-pagination.d.ts +15 -0
  50. package/dist/react/table-pagination.js +1153 -0
  51. package/dist/react/table-pagination.js.map +1 -0
  52. package/dist/react/table-view/column-menu.d.ts +15 -0
  53. package/dist/react/table-view/column-menu.js +955 -0
  54. package/dist/react/table-view/column-menu.js.map +1 -0
  55. package/dist/react/table-view/index.d.ts +70 -0
  56. package/dist/react/table-view/index.js +2190 -0
  57. package/dist/react/table-view/index.js.map +1 -0
  58. package/dist/react/table.d.ts +86 -0
  59. package/dist/react/table.js +414 -0
  60. package/dist/react/table.js.map +1 -0
  61. package/dist/react/tabs.d.ts +9 -3
  62. package/dist/react/tabs.js +204 -48
  63. package/dist/react/tabs.js.map +1 -1
  64. package/dist/react/textarea.d.ts +6 -0
  65. package/dist/react/textarea.js +33 -0
  66. package/dist/react/textarea.js.map +1 -0
  67. package/dist/react/time-picker.d.ts +22 -0
  68. package/dist/react/time-picker.js +856 -0
  69. package/dist/react/time-picker.js.map +1 -0
  70. package/dist/react/tooltip.d.ts +45 -0
  71. package/dist/react/tooltip.js +540 -0
  72. package/dist/react/tooltip.js.map +1 -0
  73. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import * as React2 from 'react';
2
- import React2__default, { useCallback, useState, useRef, useMemo, useEffect, useLayoutEffect } from 'react';
1
+ import * as React3 from 'react';
2
+ import React3__default, { useState, useCallback, useRef, useLayoutEffect, useMemo, useEffect } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { X, ChevronDown, Check, ChevronRight } from 'lucide-react';
5
5
  import { clsx } from 'clsx';
@@ -10,7 +10,7 @@ function cn(...inputs) {
10
10
  return twMerge(clsx(inputs));
11
11
  }
12
12
  var sizeClass = {
13
- xs: "h-8 min-h-8 gap-2 px-4 text-xs has-[>svg]:px-3 [&_svg:not([class*='size-'])]:size-3",
13
+ xs: "h-8 min-h-8 gap-2 px-4 text-sm has-[>svg]:px-3 [&_svg:not([class*='size-'])]:size-3",
14
14
  default: "h-10 min-h-10 gap-2 px-5 text-sm has-[>svg]:px-4 [&_svg:not([class*='size-'])]:size-4",
15
15
  lg: "h-11 min-h-11 gap-2 px-6 text-base has-[>svg]:px-5 [&_svg:not([class*='size-'])]:size-5"
16
16
  };
@@ -30,7 +30,7 @@ var variantClass = {
30
30
  destructive: "bg-background text-red-500 border border-red-500/25 hover:bg-red-500/5",
31
31
  success: "bg-background text-green-500 border border-green-500/25 hover:bg-green-500/5"
32
32
  };
33
- var Button = React2.forwardRef(
33
+ var Button = React3.forwardRef(
34
34
  ({
35
35
  className,
36
36
  type = "button",
@@ -50,9 +50,9 @@ var Button = React2.forwardRef(
50
50
  "data-slot": "button",
51
51
  "data-icon-only": iconOnly ? "" : void 0,
52
52
  className: cn(
53
- "inline-flex shrink-0 cursor-pointer items-center justify-center whitespace-nowrap outline-none transition-[color,background-color,box-shadow,transform] duration-150 ease-out active:scale-[0.98] [&_svg]:pointer-events-none [&_svg]:shrink-0",
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
54
  "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
55
- "focus-visible:border-ring font-bold tracking-wide focus-visible:ring-ring/50 focus-visible:ring-[3px]",
55
+ "focus-visible:border-ring font-medium lg:tracking-wide focus-visible:ring-ring/50 focus-visible:ring-[3px]",
56
56
  iconOnly ? iconOnlySizeClass[size] : sizeClass[size],
57
57
  roundedClass[rounded],
58
58
  variantClass[variant],
@@ -65,6 +65,122 @@ var Button = React2.forwardRef(
65
65
  }
66
66
  );
67
67
  Button.displayName = "Button";
68
+ var CHECKBOX_TICK_DELAY_MS = 60;
69
+ var CHECKBOX_TICK_DRAW_MS = 100;
70
+ function CheckboxAnimatedCheckMark() {
71
+ const lineRef = useRef(null);
72
+ useLayoutEffect(() => {
73
+ const poly = lineRef.current;
74
+ if (!poly || typeof poly.getTotalLength !== "function") return;
75
+ const len = poly.getTotalLength();
76
+ if (len <= 0) return;
77
+ poly.style.strokeDasharray = `${len}`;
78
+ poly.style.strokeDashoffset = `${len}`;
79
+ if (typeof poly.animate !== "function") {
80
+ poly.style.strokeDashoffset = "0";
81
+ return;
82
+ }
83
+ const anim = poly.animate(
84
+ [{ strokeDashoffset: len }, { strokeDashoffset: 0 }],
85
+ {
86
+ duration: CHECKBOX_TICK_DRAW_MS,
87
+ delay: CHECKBOX_TICK_DELAY_MS,
88
+ easing: "cubic-bezier(0.45, 0, 0.2, 1)",
89
+ fill: "forwards"
90
+ }
91
+ );
92
+ return () => anim.cancel();
93
+ }, []);
94
+ return /* @__PURE__ */ jsx(
95
+ "svg",
96
+ {
97
+ className: "size-4 shrink-0 overflow-visible",
98
+ viewBox: "0 0 24 24",
99
+ "aria-hidden": true,
100
+ children: /* @__PURE__ */ jsx(
101
+ "polyline",
102
+ {
103
+ ref: lineRef,
104
+ points: "4 12 9 17 20 6",
105
+ fill: "none",
106
+ stroke: "currentColor",
107
+ strokeWidth: "3",
108
+ strokeLinecap: "round",
109
+ strokeLinejoin: "round"
110
+ }
111
+ )
112
+ }
113
+ );
114
+ }
115
+ var Checkbox = React3.forwardRef(
116
+ ({
117
+ checked: checkedProp,
118
+ defaultChecked = false,
119
+ onCheckedChange,
120
+ indeterminate = false,
121
+ disabled = false,
122
+ className,
123
+ onClick,
124
+ ...rest
125
+ }, ref) => {
126
+ const isControlled = checkedProp !== void 0;
127
+ const [uncontrolledChecked, setUncontrolledChecked] = useState(defaultChecked);
128
+ const checked = isControlled ? checkedProp : uncontrolledChecked;
129
+ const ariaChecked = indeterminate ? "mixed" : checked ? true : false;
130
+ return /* @__PURE__ */ jsx(
131
+ "button",
132
+ {
133
+ ref,
134
+ type: "button",
135
+ role: "checkbox",
136
+ "data-slot": "checkbox",
137
+ "data-state": indeterminate ? "indeterminate" : checked ? "checked" : "unchecked",
138
+ disabled,
139
+ "aria-checked": ariaChecked,
140
+ className: cn(
141
+ "ring-offset-background focus-visible:ring-primary/40 inline-flex shrink-0 items-center justify-center rounded-md border border-transparent p-0 outline-none select-none",
142
+ "focus-visible:ring-2 focus-visible:ring-offset-2",
143
+ "disabled:cursor-not-allowed",
144
+ className
145
+ ),
146
+ onClick: (e) => {
147
+ onClick?.(e);
148
+ if (e.defaultPrevented) return;
149
+ if (disabled) return;
150
+ if (isControlled) {
151
+ onCheckedChange?.(!checked);
152
+ return;
153
+ }
154
+ setUncontrolledChecked((prev) => {
155
+ const next = !prev;
156
+ onCheckedChange?.(next);
157
+ return next;
158
+ });
159
+ },
160
+ ...rest,
161
+ children: /* @__PURE__ */ jsx("span", { className: "pointer-events-none", children: /* @__PURE__ */ jsx(
162
+ "span",
163
+ {
164
+ "aria-hidden": true,
165
+ className: cn(
166
+ "flex size-5 shrink-0 items-center justify-center rounded-[4px] border",
167
+ !disabled && (indeterminate ? "border-primary bg-primary text-background" : checked ? "border-primary bg-primary text-background" : "border-primary/20 bg-background"),
168
+ disabled && (indeterminate ? "border-transparent bg-primary/45 text-primary-foreground" : checked ? "border-transparent bg-primary/45 text-primary-foreground" : "border-primary/10 bg-muted/25")
169
+ ),
170
+ children: indeterminate ? /* @__PURE__ */ jsx(
171
+ "span",
172
+ {
173
+ className: "size-2.5 shrink-0 rounded-[2px] border border-primary/20 bg-background",
174
+ "aria-hidden": true
175
+ }
176
+ ) : checked ? /* @__PURE__ */ jsx(CheckboxAnimatedCheckMark, {}) : null
177
+ }
178
+ ) })
179
+ }
180
+ );
181
+ }
182
+ );
183
+ Checkbox.displayName = "Checkbox";
68
184
  var DROPDOWN_PANEL_OPEN_EASING = "cubic-bezier(0,0.55,0.45,1)";
69
185
  var DROPDOWN_PANEL_CLOSE_EASING = "cubic-bezier(0.55,0,1,0.45)";
70
186
  var DROPDOWN_MENU_MIN_WIDTH_PX = 192;
@@ -73,7 +189,31 @@ var DROPDOWN_MOBILE_SHEET_MOTION_MS = 175;
73
189
  var DROPDOWN_MOBILE_SHEET_ENTRY_EASING = "cubic-bezier(0.85, 0, 0.15, 1)";
74
190
  var DROPDOWN_MOBILE_SHEET_EXIT_EASING = "cubic-bezier(0.85, 0, 1, 0.15)";
75
191
  var DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX = 120;
192
+ function resolveDropdownMobileSheet(mobileOptions) {
193
+ return {
194
+ sheet: mobileOptions?.sheet ?? true,
195
+ title: mobileOptions?.title,
196
+ sheetExtraClassName: mobileOptions?.className,
197
+ contentClassName: mobileOptions?.contentClassName
198
+ };
199
+ }
76
200
  var DROPDOWN_SUB_CONTENT_ATTR = "data-dropdown-sub-content";
201
+ var DROPDOWN_PANEL_SHADOW = "shadow-[0_12px_32px_-8px_rgba(0,0,0,0.18),0_2px_6px_-2px_rgba(0,0,0,0.06)] dark:shadow-[0_12px_32px_-8px_rgba(0,0,0,0.55),0_2px_6px_-2px_rgba(0,0,0,0.35)]";
202
+ var DROPDOWN_PANEL_SCROLL = "[&_*]:[scrollbar-width:none] [&_*::-webkit-scrollbar]:hidden [&_*]:overscroll-contain";
203
+ function preventMenuWheelChain(menu, e) {
204
+ let el = e.target;
205
+ while (el && menu.contains(el)) {
206
+ const oy = getComputedStyle(el).overflowY;
207
+ if ((oy === "auto" || oy === "scroll") && el.scrollHeight > el.clientHeight) {
208
+ const atTop = el.scrollTop <= 0;
209
+ const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight;
210
+ if (e.deltaY < 0 && !atTop || e.deltaY > 0 && !atBottom) return;
211
+ break;
212
+ }
213
+ el = el.parentElement;
214
+ }
215
+ e.preventDefault();
216
+ }
77
217
  var DROPDOWN_SHEET_MENU_TEXT = "max-[1024px]:text-base";
78
218
  var DROPDOWN_SHEET_MENU_SHORTCUT = "max-[1024px]:text-sm";
79
219
  var DROPDOWN_SHEET_MENU_LABEL_TEXT = "max-[1024px]:text-sm";
@@ -164,24 +304,26 @@ function computePos(trigger, menu, side, align, offset, pad) {
164
304
  return { top, left, side: effectiveSide };
165
305
  }
166
306
  function useIsMobile(breakpoint = 1025) {
167
- const [isMobile, setIsMobile] = useState(false);
307
+ const [isMobile, setIsMobile] = useState(() => {
308
+ if (typeof window === "undefined") return false;
309
+ return window.matchMedia(`(max-width: ${breakpoint - 1}px)`).matches;
310
+ });
168
311
  useEffect(() => {
169
312
  const mq = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);
170
- setIsMobile(mq.matches);
171
313
  const handler = (e) => setIsMobile(e.matches);
172
314
  mq.addEventListener("change", handler);
173
315
  return () => mq.removeEventListener("change", handler);
174
316
  }, [breakpoint]);
175
317
  return isMobile;
176
318
  }
177
- var DropdownContext = React2__default.createContext(void 0);
319
+ var DropdownContext = React3__default.createContext(void 0);
178
320
  function useDropdown() {
179
- const ctx = React2__default.useContext(DropdownContext);
321
+ const ctx = React3__default.useContext(DropdownContext);
180
322
  if (!ctx)
181
323
  throw new Error("Dropdown components must be used within <Dropdown />");
182
324
  return ctx;
183
325
  }
184
- var SubContext = React2__default.createContext(void 0);
326
+ var SubContext = React3__default.createContext(void 0);
185
327
  var Dropdown = ({
186
328
  children,
187
329
  open: controlledOpen,
@@ -214,7 +356,7 @@ function mergeTriggerRef(triggerRef, node, childRef) {
214
356
  else if (childRef && typeof childRef === "object")
215
357
  childRef.current = node;
216
358
  }
217
- var DropdownTrigger = React2__default.forwardRef(
359
+ var DropdownTrigger = React3__default.forwardRef(
218
360
  ({
219
361
  children,
220
362
  asChild,
@@ -241,9 +383,9 @@ var DropdownTrigger = React2__default.forwardRef(
241
383
  },
242
384
  [ref, triggerRef]
243
385
  );
244
- if (asChild && React2__default.isValidElement(children)) {
386
+ if (asChild && React3__default.isValidElement(children)) {
245
387
  const child = children;
246
- return React2__default.cloneElement(child, {
388
+ return React3__default.cloneElement(child, {
247
389
  ref: (node) => {
248
390
  mergeTriggerRef(
249
391
  triggerRef,
@@ -296,7 +438,7 @@ function DropdownChevron({
296
438
  }
297
439
  );
298
440
  }
299
- var DropdownMobileClose = React2__default.forwardRef(({ className, type = "button", ...props }, ref) => {
441
+ var DropdownMobileClose = React3__default.forwardRef(({ className, type = "button", ...props }, ref) => {
300
442
  return /* @__PURE__ */ jsxs(
301
443
  "button",
302
444
  {
@@ -320,10 +462,13 @@ function DropdownMobileBottomSheetPortal({
320
462
  isAnimating,
321
463
  slideEntrance,
322
464
  slideOffsetPx,
323
- mobileTitle,
465
+ sheetTitle,
466
+ sheetExtraClassName,
467
+ contentClassName,
324
468
  onRequestClose,
325
469
  menuRef,
326
470
  portalZClassName = "z-50",
471
+ isSubPortal = false,
327
472
  children,
328
473
  className,
329
474
  style,
@@ -335,6 +480,7 @@ function DropdownMobileBottomSheetPortal({
335
480
  /* @__PURE__ */ jsxs(
336
481
  "div",
337
482
  {
483
+ ...isSubPortal ? { [DROPDOWN_SUB_CONTENT_ATTR]: "" } : {},
338
484
  className: cn(
339
485
  "fixed inset-0 flex items-end justify-center p-0",
340
486
  portalZClassName
@@ -361,8 +507,10 @@ function DropdownMobileBottomSheetPortal({
361
507
  ...panelProps,
362
508
  ref: menuRef,
363
509
  className: cn(
364
- "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",
510
+ "bg-background border-primary/8 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",
365
511
  "rounded-t-2xl rounded-b-none border-x-0 border-b-0 border-t",
512
+ DROPDOWN_PANEL_SCROLL,
513
+ sheetExtraClassName,
366
514
  className
367
515
  ),
368
516
  style: {
@@ -379,10 +527,10 @@ function DropdownMobileBottomSheetPortal({
379
527
  {
380
528
  className: cn(
381
529
  "flex w-full shrink-0 items-center py-2 pl-4 pr-2",
382
- mobileTitle ? "justify-between gap-3" : "justify-end"
530
+ sheetTitle ? "justify-between gap-3" : "justify-end"
383
531
  ),
384
532
  children: [
385
- mobileTitle ? /* @__PURE__ */ jsx("p", { className: "text-foreground min-w-0 flex-1 truncate text-base font-semibold", children: mobileTitle }) : null,
533
+ sheetTitle ? /* @__PURE__ */ jsx("p", { className: "text-foreground min-w-0 flex-1 truncate text-base font-semibold", children: sheetTitle }) : null,
386
534
  /* @__PURE__ */ jsx(
387
535
  DropdownMobileClose,
388
536
  {
@@ -395,7 +543,16 @@ function DropdownMobileBottomSheetPortal({
395
543
  ]
396
544
  }
397
545
  ),
398
- /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pb-[max(0.375rem,env(safe-area-inset-bottom,0px))]", children: /* @__PURE__ */ jsx("div", { className: "pb-1", children }) })
546
+ /* @__PURE__ */ jsx(
547
+ "div",
548
+ {
549
+ className: cn(
550
+ "min-h-0 flex-1 overflow-y-auto pb-[calc(5rem+env(safe-area-inset-bottom,0px))]",
551
+ contentClassName
552
+ ),
553
+ children
554
+ }
555
+ )
399
556
  ]
400
557
  }
401
558
  )
@@ -415,8 +572,7 @@ var DropdownContent = ({
415
572
  closeOnEscape = true,
416
573
  minWidth = "trigger",
417
574
  loop = true,
418
- mobileSheet = true,
419
- mobileTitle,
575
+ mobileOptions,
420
576
  slideEntrance = true,
421
577
  slideEntranceOffsetPx: slideEntranceOffsetPxProp,
422
578
  className,
@@ -430,21 +586,25 @@ var DropdownContent = ({
430
586
  const [pos, setPos] = useState({ top: -9999, left: -9999, side });
431
587
  const [triggerW, setTriggerW] = useState(0);
432
588
  const menuRef = useRef(null);
433
- const slideOffsetPx = useMemo(
434
- () => slideEntranceOffsetPxProp ?? DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX,
435
- [slideEntranceOffsetPxProp]
436
- );
437
- const closeDuration = isMobile && mobileSheet ? DROPDOWN_MOBILE_SHEET_MOTION_MS : duration;
438
- const closeMenu = useCallback(() => setOpen(false), [setOpen]);
589
+ const resolvedMobile = resolveDropdownMobileSheet(mobileOptions);
590
+ const isMobileSheet = isMobile && resolvedMobile.sheet;
591
+ const slideOffsetPx = slideEntranceOffsetPxProp ?? DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX;
439
592
  useEffect(() => {
440
593
  if (open) {
441
594
  setShouldRender(true);
442
- } else {
443
- setIsAnimating(false);
444
- const timer = setTimeout(() => setShouldRender(false), closeDuration);
445
- return () => clearTimeout(timer);
595
+ return;
596
+ }
597
+ if (!isMobileSheet) {
598
+ setShouldRender(false);
599
+ return;
446
600
  }
447
- }, [open, closeDuration]);
601
+ setIsAnimating(false);
602
+ const t = setTimeout(
603
+ () => setShouldRender(false),
604
+ DROPDOWN_MOBILE_SHEET_MOTION_MS
605
+ );
606
+ return () => clearTimeout(t);
607
+ }, [open, isMobileSheet]);
448
608
  useEffect(() => {
449
609
  if (!shouldRender || !open) return;
450
610
  let raf2 = 0;
@@ -474,12 +634,27 @@ var DropdownContent = ({
474
634
  };
475
635
  update();
476
636
  window.addEventListener("resize", update);
477
- window.addEventListener("scroll", update, true);
478
637
  return () => {
479
638
  window.removeEventListener("resize", update);
480
- window.removeEventListener("scroll", update, true);
481
639
  };
482
640
  }, [shouldRender, side, align, offset, viewportPadding]);
641
+ useEffect(() => {
642
+ if (!open || isMobileSheet) return;
643
+ const isInsideMenu = (t) => t instanceof Node && (!!menuRef.current?.contains(t) || !!triggerRef.current?.contains(t) || t instanceof Element && !!t.closest(`[${DROPDOWN_SUB_CONTENT_ATTR}]`));
644
+ const onScroll = (e) => {
645
+ if (!isInsideMenu(e.target)) setOpen(false);
646
+ };
647
+ window.addEventListener("scroll", onScroll, true);
648
+ return () => window.removeEventListener("scroll", onScroll, true);
649
+ }, [open, isMobileSheet, setOpen, triggerRef]);
650
+ useEffect(() => {
651
+ if (!shouldRender || isMobileSheet) return;
652
+ const menu = menuRef.current;
653
+ if (!menu) return;
654
+ const onWheel = (e) => preventMenuWheelChain(menu, e);
655
+ menu.addEventListener("wheel", onWheel, { passive: false });
656
+ return () => menu.removeEventListener("wheel", onWheel);
657
+ }, [shouldRender, isMobileSheet]);
483
658
  useEffect(() => {
484
659
  if (isAnimating && menuRef.current) {
485
660
  menuRef.current.focus();
@@ -545,15 +720,14 @@ var DropdownContent = ({
545
720
  return () => window.removeEventListener("keydown", handler);
546
721
  }, [open, closeOnEscape, loop, setOpen, triggerRef]);
547
722
  useEffect(() => {
548
- if (open && isMobile && mobileSheet) {
549
- document.body.style.overflow = "hidden";
550
- }
723
+ if (!open || !isMobileSheet) return;
724
+ document.body.style.overflow = "hidden";
551
725
  return () => {
552
726
  document.body.style.overflow = "";
553
727
  };
554
- }, [open, isMobile, mobileSheet]);
728
+ }, [open, isMobileSheet]);
555
729
  if (!shouldRender || typeof document === "undefined") return null;
556
- if (isMobile && mobileSheet) {
730
+ if (isMobileSheet) {
557
731
  return /* @__PURE__ */ jsx(
558
732
  DropdownMobileBottomSheetPortal,
559
733
  {
@@ -562,8 +736,10 @@ var DropdownContent = ({
562
736
  isAnimating,
563
737
  slideEntrance,
564
738
  slideOffsetPx,
565
- mobileTitle,
566
- onRequestClose: closeMenu,
739
+ sheetTitle: resolvedMobile.title,
740
+ sheetExtraClassName: resolvedMobile.sheetExtraClassName,
741
+ contentClassName: resolvedMobile.contentClassName,
742
+ onRequestClose: () => setOpen(false),
567
743
  menuRef,
568
744
  portalZClassName: "z-50",
569
745
  className,
@@ -586,7 +762,9 @@ var DropdownContent = ({
586
762
  "aria-orientation": "vertical",
587
763
  tabIndex: -1,
588
764
  className: cn(
589
- "bg-background border-primary/10 absolute z-50 overflow-hidden rounded-xl border py-1.5 shadow-xl outline-none",
765
+ "bg-background border-primary/8 absolute z-50 overflow-hidden rounded-xl border py-1.5 outline-none",
766
+ DROPDOWN_PANEL_SHADOW,
767
+ DROPDOWN_PANEL_SCROLL,
590
768
  className
591
769
  ),
592
770
  style: {
@@ -649,7 +827,7 @@ var DropdownItem = ({
649
827
  onClick: handleClick,
650
828
  onKeyDown: handleKeyDown,
651
829
  className: cn(
652
- "relative mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors outline-none select-none",
830
+ "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",
653
831
  DROPDOWN_SHEET_MENU_TEXT,
654
832
  inset && "pl-9",
655
833
  !disabled && "cursor-pointer",
@@ -662,7 +840,7 @@ var DropdownItem = ({
662
840
  ),
663
841
  children: [
664
842
  icon && /* @__PURE__ */ jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: icon }),
665
- /* @__PURE__ */ jsx("span", { className: "flex-1", children }),
843
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children }),
666
844
  shortcut ? /* @__PURE__ */ jsx(
667
845
  "span",
668
846
  {
@@ -698,53 +876,6 @@ var DropdownLabel = ({ className, inset, ...props }) => /* @__PURE__ */ jsx(
698
876
  ...props
699
877
  }
700
878
  );
701
- var DROPDOWN_CHECKBOX_TICK_DELAY_MS = 60;
702
- var DROPDOWN_CHECKBOX_TICK_DRAW_MS = 200;
703
- function DropdownCheckboxItemCheckMark() {
704
- const lineRef = useRef(null);
705
- useLayoutEffect(() => {
706
- const poly = lineRef.current;
707
- if (!poly || typeof poly.getTotalLength !== "function") return;
708
- const len = poly.getTotalLength();
709
- if (len <= 0) return;
710
- poly.style.strokeDasharray = `${len}`;
711
- poly.style.strokeDashoffset = `${len}`;
712
- if (typeof poly.animate !== "function") {
713
- poly.style.strokeDashoffset = "0";
714
- return;
715
- }
716
- const anim = poly.animate(
717
- [{ strokeDashoffset: len }, { strokeDashoffset: 0 }],
718
- {
719
- duration: DROPDOWN_CHECKBOX_TICK_DRAW_MS,
720
- delay: DROPDOWN_CHECKBOX_TICK_DELAY_MS,
721
- easing: "cubic-bezier(0.45, 0, 0.2, 1)",
722
- fill: "forwards"
723
- }
724
- );
725
- return () => anim.cancel();
726
- }, []);
727
- return /* @__PURE__ */ jsx(
728
- "svg",
729
- {
730
- className: "size-4 shrink-0 overflow-visible",
731
- viewBox: "0 0 24 24",
732
- "aria-hidden": true,
733
- children: /* @__PURE__ */ jsx(
734
- "polyline",
735
- {
736
- ref: lineRef,
737
- points: "4 12 9 17 20 6",
738
- fill: "none",
739
- stroke: "currentColor",
740
- strokeWidth: "3",
741
- strokeLinecap: "round",
742
- strokeLinejoin: "round"
743
- }
744
- )
745
- }
746
- );
747
- }
748
879
  var DropdownCheckboxItem = ({
749
880
  children,
750
881
  checked = false,
@@ -780,25 +911,22 @@ var DropdownCheckboxItem = ({
780
911
  onClick: handleClick,
781
912
  onKeyDown: handleKeyDown,
782
913
  className: cn(
783
- "mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors outline-none select-none",
914
+ "mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors duration-0 outline-none select-none",
784
915
  DROPDOWN_SHEET_MENU_TEXT,
785
916
  !disabled && "cursor-pointer text-foreground hover:bg-primary/8 focus-visible:bg-primary/8 dark:hover:bg-primary/4 dark:focus-visible:bg-primary/4",
786
917
  disabled && "lg:cursor-not-allowed text-foreground/45 dark:text-foreground/50",
787
918
  className
788
919
  ),
789
920
  children: [
790
- /* @__PURE__ */ jsx(
791
- "span",
921
+ /* @__PURE__ */ jsx("span", { className: "mr-1 inline-flex shrink-0", "aria-hidden": true, children: /* @__PURE__ */ jsx(
922
+ Checkbox,
792
923
  {
793
- "aria-hidden": true,
794
- className: cn(
795
- "pointer-events-none flex size-5 shrink-0 items-center justify-center rounded-[4px] border mr-1",
796
- !disabled && (checked ? "border-primary bg-primary text-background" : "border-primary/20 bg-background"),
797
- disabled && (checked ? "border-primary/40 bg-primary/45 text-primary-foreground" : "border-primary/10 bg-muted/25")
798
- ),
799
- children: checked ? /* @__PURE__ */ jsx(DropdownCheckboxItemCheckMark, {}) : null
924
+ checked,
925
+ disabled,
926
+ tabIndex: -1,
927
+ className: "pointer-events-none"
800
928
  }
801
- ),
929
+ ) }),
802
930
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children }),
803
931
  shortcut && /* @__PURE__ */ jsx(
804
932
  "span",
@@ -834,11 +962,11 @@ var DropdownRadioGroup = ({ children, value, onValueChange, group }) => {
834
962
  );
835
963
  return /* @__PURE__ */ jsx(RadioGroupContext.Provider, { value: radioCtx, children });
836
964
  };
837
- var RadioGroupContext = React2__default.createContext(
965
+ var RadioGroupContext = React3__default.createContext(
838
966
  void 0
839
967
  );
840
968
  function useRadioGroup() {
841
- const ctx = React2__default.useContext(RadioGroupContext);
969
+ const ctx = React3__default.useContext(RadioGroupContext);
842
970
  if (!ctx)
843
971
  throw new Error("DropdownRadioItem must be inside DropdownRadioGroup");
844
972
  return ctx;
@@ -879,7 +1007,7 @@ var DropdownRadioItem = ({
879
1007
  onClick: handleClick,
880
1008
  onKeyDown: handleKeyDown,
881
1009
  className: cn(
882
- "relative mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors outline-none select-none",
1010
+ "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",
883
1011
  DROPDOWN_SHEET_MENU_TEXT,
884
1012
  !disabled && "cursor-pointer text-foreground hover:bg-primary/8 focus-visible:bg-primary/8 dark:hover:bg-primary/4 dark:focus-visible:bg-primary/4",
885
1013
  disabled && "lg:cursor-not-allowed text-foreground/45 dark:text-foreground/50",
@@ -909,21 +1037,19 @@ var DropdownRadioItem = ({
909
1037
  }
910
1038
  );
911
1039
  };
912
- var DropdownSub = ({
913
- children
914
- }) => {
1040
+ var DropdownSub = ({ children, openOnHover = true }) => {
915
1041
  const [open, setOpen] = useState(false);
916
1042
  const triggerRef = useRef(null);
917
1043
  const subCtx = useMemo(
918
- () => ({ open, setOpen, triggerRef }),
919
- [open, setOpen]
1044
+ () => ({ open, setOpen, triggerRef, openOnHover }),
1045
+ [open, setOpen, openOnHover]
920
1046
  );
921
1047
  return /* @__PURE__ */ jsx(SubContext.Provider, { value: subCtx, children });
922
1048
  };
923
1049
  var DropdownSubTrigger = ({ children, icon, inset, disabled = false, className, ...props }) => {
924
- const sub = React2__default.useContext(SubContext);
1050
+ const sub = React3__default.useContext(SubContext);
925
1051
  if (!sub) throw new Error("DropdownSubTrigger must be inside DropdownSub");
926
- const { open, setOpen, triggerRef } = sub;
1052
+ const { open, setOpen, triggerRef, openOnHover } = sub;
927
1053
  const isMobile = useIsMobile(DROPDOWN_MOBILE_SHEET_MAX_PX + 1);
928
1054
  return /* @__PURE__ */ jsxs(
929
1055
  "div",
@@ -938,11 +1064,11 @@ var DropdownSubTrigger = ({ children, icon, inset, disabled = false, className,
938
1064
  tabIndex: disabled ? void 0 : -1,
939
1065
  "aria-disabled": disabled,
940
1066
  onMouseEnter: () => {
941
- if (disabled || isMobile) return;
1067
+ if (disabled || isMobile || !openOnHover) return;
942
1068
  setOpen(true);
943
1069
  },
944
1070
  onMouseLeave: () => {
945
- if (isMobile) return;
1071
+ if (isMobile || !openOnHover) return;
946
1072
  setOpen(false);
947
1073
  },
948
1074
  onKeyDown: (e) => {
@@ -957,7 +1083,7 @@ var DropdownSubTrigger = ({ children, icon, inset, disabled = false, className,
957
1083
  setOpen(!open);
958
1084
  },
959
1085
  className: cn(
960
- "relative mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors outline-none select-none",
1086
+ "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",
961
1087
  DROPDOWN_SHEET_MENU_TEXT,
962
1088
  inset && "pl-9",
963
1089
  !disabled && "cursor-pointer text-foreground hover:bg-primary/8 focus-visible:bg-primary/8 dark:hover:bg-primary/4 dark:focus-visible:bg-primary/4",
@@ -966,8 +1092,8 @@ var DropdownSubTrigger = ({ children, icon, inset, disabled = false, className,
966
1092
  ),
967
1093
  children: [
968
1094
  icon && /* @__PURE__ */ jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: icon }),
969
- /* @__PURE__ */ jsx("span", { className: "flex-1", children }),
970
- /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto size-4 opacity-50" })
1095
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children }),
1096
+ /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto size-4 shrink-0 opacity-50" })
971
1097
  ]
972
1098
  }
973
1099
  );
@@ -976,8 +1102,7 @@ var DropdownSubContent = ({
976
1102
  children,
977
1103
  duration = 80,
978
1104
  viewportPadding = 8,
979
- mobileSheet = true,
980
- mobileTitle,
1105
+ mobileOptions,
981
1106
  slideEntrance = true,
982
1107
  slideEntranceOffsetPx: slideEntranceOffsetPxProp,
983
1108
  className,
@@ -985,14 +1110,13 @@ var DropdownSubContent = ({
985
1110
  onKeyDown: onKeyDownProp,
986
1111
  ...props
987
1112
  }) => {
988
- const sub = React2__default.useContext(SubContext);
1113
+ const sub = React3__default.useContext(SubContext);
989
1114
  if (!sub) throw new Error("DropdownSubContent must be inside DropdownSub");
990
- const { open, setOpen, triggerRef } = sub;
1115
+ const { open, setOpen, triggerRef, openOnHover } = sub;
991
1116
  const isMobile = useIsMobile(DROPDOWN_MOBILE_SHEET_MAX_PX + 1);
992
- const slideOffsetPx = useMemo(
993
- () => slideEntranceOffsetPxProp ?? DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX,
994
- [slideEntranceOffsetPxProp]
995
- );
1117
+ const resolvedMobile = resolveDropdownMobileSheet(mobileOptions);
1118
+ const isMobileSheet = isMobile && resolvedMobile.sheet;
1119
+ const slideOffsetPx = slideEntranceOffsetPxProp ?? DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX;
996
1120
  const [shouldRender, setShouldRender] = useState(false);
997
1121
  const [isAnimating, setIsAnimating] = useState(false);
998
1122
  const [pos, setPos] = useState({
@@ -1001,17 +1125,22 @@ var DropdownSubContent = ({
1001
1125
  side: "right"
1002
1126
  });
1003
1127
  const menuRef = useRef(null);
1004
- const closeDuration = isMobile && mobileSheet ? DROPDOWN_MOBILE_SHEET_MOTION_MS : duration;
1005
- const closeSub = useCallback(() => setOpen(false), [setOpen]);
1006
1128
  useEffect(() => {
1007
1129
  if (open) {
1008
1130
  setShouldRender(true);
1009
- } else {
1010
- setIsAnimating(false);
1011
- const timer = setTimeout(() => setShouldRender(false), closeDuration);
1012
- return () => clearTimeout(timer);
1131
+ return;
1132
+ }
1133
+ if (!isMobileSheet) {
1134
+ setShouldRender(false);
1135
+ return;
1013
1136
  }
1014
- }, [open, closeDuration]);
1137
+ setIsAnimating(false);
1138
+ const t = setTimeout(
1139
+ () => setShouldRender(false),
1140
+ DROPDOWN_MOBILE_SHEET_MOTION_MS
1141
+ );
1142
+ return () => clearTimeout(t);
1143
+ }, [open, isMobileSheet]);
1015
1144
  useEffect(() => {
1016
1145
  if (!shouldRender || !open) return;
1017
1146
  let raf2 = 0;
@@ -1024,8 +1153,8 @@ var DropdownSubContent = ({
1024
1153
  };
1025
1154
  }, [shouldRender, open]);
1026
1155
  useLayoutEffect(() => {
1027
- if (!shouldRender || !triggerRef.current || !menuRef.current) return;
1028
- if (isMobile && mobileSheet) return;
1156
+ if (!shouldRender || isMobileSheet) return;
1157
+ if (!triggerRef.current || !menuRef.current) return;
1029
1158
  const update = () => {
1030
1159
  if (!triggerRef.current || !menuRef.current) return;
1031
1160
  setPos(
@@ -1041,12 +1170,29 @@ var DropdownSubContent = ({
1041
1170
  };
1042
1171
  update();
1043
1172
  window.addEventListener("resize", update);
1044
- window.addEventListener("scroll", update, true);
1045
1173
  return () => {
1046
1174
  window.removeEventListener("resize", update);
1047
- window.removeEventListener("scroll", update, true);
1048
1175
  };
1049
- }, [shouldRender, viewportPadding, isMobile, mobileSheet]);
1176
+ }, [shouldRender, viewportPadding, isMobileSheet]);
1177
+ useEffect(() => {
1178
+ if (!open || isMobileSheet) return;
1179
+ const onScroll = (e) => {
1180
+ const t = e.target;
1181
+ if (!(t instanceof Node) || menuRef.current?.contains(t)) return;
1182
+ const trigger = triggerRef.current;
1183
+ if (trigger && (t === trigger || t.contains(trigger))) setOpen(false);
1184
+ };
1185
+ window.addEventListener("scroll", onScroll, true);
1186
+ return () => window.removeEventListener("scroll", onScroll, true);
1187
+ }, [open, isMobileSheet, setOpen, triggerRef]);
1188
+ useEffect(() => {
1189
+ if (!shouldRender || isMobileSheet) return;
1190
+ const menu = menuRef.current;
1191
+ if (!menu) return;
1192
+ const onWheel = (e) => preventMenuWheelChain(menu, e);
1193
+ menu.addEventListener("wheel", onWheel, { passive: false });
1194
+ return () => menu.removeEventListener("wheel", onWheel);
1195
+ }, [shouldRender, isMobileSheet]);
1050
1196
  useEffect(() => {
1051
1197
  if (isAnimating && menuRef.current) {
1052
1198
  menuRef.current.focus();
@@ -1107,7 +1253,7 @@ var DropdownSubContent = ({
1107
1253
  [onKeyDownProp, setOpen, triggerRef]
1108
1254
  );
1109
1255
  if (!shouldRender || typeof document === "undefined") return null;
1110
- if (isMobile && mobileSheet) {
1256
+ if (isMobileSheet) {
1111
1257
  return /* @__PURE__ */ jsx(
1112
1258
  DropdownMobileBottomSheetPortal,
1113
1259
  {
@@ -1116,10 +1262,13 @@ var DropdownSubContent = ({
1116
1262
  isAnimating,
1117
1263
  slideEntrance,
1118
1264
  slideOffsetPx,
1119
- mobileTitle,
1120
- onRequestClose: closeSub,
1265
+ sheetTitle: resolvedMobile.title,
1266
+ sheetExtraClassName: resolvedMobile.sheetExtraClassName,
1267
+ contentClassName: resolvedMobile.contentClassName,
1268
+ onRequestClose: () => setOpen(false),
1121
1269
  menuRef,
1122
1270
  portalZClassName: "z-[70]",
1271
+ isSubPortal: true,
1123
1272
  className,
1124
1273
  style,
1125
1274
  role: "menu",
@@ -1138,12 +1287,14 @@ var DropdownSubContent = ({
1138
1287
  ref: menuRef,
1139
1288
  role: "menu",
1140
1289
  tabIndex: -1,
1141
- onMouseEnter: () => setOpen(true),
1142
- onMouseLeave: () => setOpen(false),
1290
+ onMouseEnter: openOnHover ? () => setOpen(true) : void 0,
1291
+ onMouseLeave: openOnHover ? () => setOpen(false) : void 0,
1143
1292
  onKeyDown: handleSubMenuKeyDown,
1144
1293
  "data-dropdown-sub-content": "",
1145
1294
  className: cn(
1146
- "bg-background border-primary/10 absolute z-60 overflow-hidden rounded-xl border py-1.5 shadow-xl outline-none",
1295
+ "bg-background border-primary/8 absolute z-60 overflow-hidden rounded-xl border py-1.5 outline-none",
1296
+ DROPDOWN_PANEL_SHADOW,
1297
+ DROPDOWN_PANEL_SCROLL,
1147
1298
  className
1148
1299
  ),
1149
1300
  style: {