@avenue-ticketing/ui 0.11.0 → 0.12.0-beta.2

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 (226) hide show
  1. package/README.md +47 -0
  2. package/dist/badge-types-B67wcd4m.d.ts +22 -0
  3. package/dist/react/app-store-buttons-outline.d.ts +17 -0
  4. package/dist/react/app-store-buttons-outline.js +582 -0
  5. package/dist/react/app-store-buttons-outline.js.map +1 -0
  6. package/dist/react/app-store-buttons.d.ts +20 -0
  7. package/dist/react/app-store-buttons.js +817 -0
  8. package/dist/react/app-store-buttons.js.map +1 -0
  9. package/dist/react/avatar-label-group.d.ts +14 -0
  10. package/dist/react/avatar-label-group.js +183 -0
  11. package/dist/react/avatar-label-group.js.map +1 -0
  12. package/dist/react/avatar-profile-photo.d.ts +9 -0
  13. package/dist/react/avatar-profile-photo.js +202 -0
  14. package/dist/react/avatar-profile-photo.js.map +1 -0
  15. package/dist/react/avatar.d.ts +66 -40
  16. package/dist/react/avatar.js +159 -149
  17. package/dist/react/avatar.js.map +1 -1
  18. package/dist/react/badge-groups.d.ts +25 -0
  19. package/dist/react/badge-groups.js +162 -0
  20. package/dist/react/badge-groups.js.map +1 -0
  21. package/dist/react/badge.d.ts +123 -59
  22. package/dist/react/badge.js +314 -86
  23. package/dist/react/badge.js.map +1 -1
  24. package/dist/react/button-group.d.ts +43 -0
  25. package/dist/react/button-group.js +108 -0
  26. package/dist/react/button-group.js.map +1 -0
  27. package/dist/react/button-utility.d.ts +47 -0
  28. package/dist/react/button-utility.js +158 -0
  29. package/dist/react/button-utility.js.map +1 -0
  30. package/dist/react/button.d.ts +112 -37
  31. package/dist/react/button.js +270 -55
  32. package/dist/react/button.js.map +1 -1
  33. package/dist/react/checkbox.d.ts +25 -8
  34. package/dist/react/checkbox.js +115 -110
  35. package/dist/react/checkbox.js.map +1 -1
  36. package/dist/react/close-button.d.ts +25 -0
  37. package/dist/react/close-button.js +54 -0
  38. package/dist/react/close-button.js.map +1 -0
  39. package/dist/react/combobox.d.ts +18 -0
  40. package/dist/react/combobox.js +574 -0
  41. package/dist/react/combobox.js.map +1 -0
  42. package/dist/react/dialog.d.ts +15 -15
  43. package/dist/react/dialog.js +43 -108
  44. package/dist/react/dialog.js.map +1 -1
  45. package/dist/react/dropdown-account-breadcrumb.d.ts +5 -0
  46. package/dist/react/dropdown-account-breadcrumb.js +481 -0
  47. package/dist/react/dropdown-account-breadcrumb.js.map +1 -0
  48. package/dist/react/dropdown-account-button.d.ts +5 -0
  49. package/dist/react/dropdown-account-button.js +938 -0
  50. package/dist/react/dropdown-account-button.js.map +1 -0
  51. package/dist/react/dropdown-account-card-md.d.ts +5 -0
  52. package/dist/react/dropdown-account-card-md.js +714 -0
  53. package/dist/react/dropdown-account-card-md.js.map +1 -0
  54. package/dist/react/dropdown-account-card-sm.d.ts +5 -0
  55. package/dist/react/dropdown-account-card-sm.js +692 -0
  56. package/dist/react/dropdown-account-card-sm.js.map +1 -0
  57. package/dist/react/dropdown-account-card-xs.d.ts +5 -0
  58. package/dist/react/dropdown-account-card-xs.js +672 -0
  59. package/dist/react/dropdown-account-card-xs.js.map +1 -0
  60. package/dist/react/dropdown-avatar.d.ts +5 -0
  61. package/dist/react/dropdown-avatar.js +955 -0
  62. package/dist/react/dropdown-avatar.js.map +1 -0
  63. package/dist/react/dropdown-button-advanced.d.ts +5 -0
  64. package/dist/react/dropdown-button-advanced.js +964 -0
  65. package/dist/react/dropdown-button-advanced.js.map +1 -0
  66. package/dist/react/dropdown-button-link.d.ts +5 -0
  67. package/dist/react/dropdown-button-link.js +666 -0
  68. package/dist/react/dropdown-button-link.js.map +1 -0
  69. package/dist/react/dropdown-button-simple.d.ts +5 -0
  70. package/dist/react/dropdown-button-simple.js +919 -0
  71. package/dist/react/dropdown-button-simple.js.map +1 -0
  72. package/dist/react/dropdown-icon-advanced.d.ts +5 -0
  73. package/dist/react/dropdown-icon-advanced.js +708 -0
  74. package/dist/react/dropdown-icon-advanced.js.map +1 -0
  75. package/dist/react/dropdown-icon-simple.d.ts +5 -0
  76. package/dist/react/dropdown-icon-simple.js +670 -0
  77. package/dist/react/dropdown-icon-simple.js.map +1 -0
  78. package/dist/react/dropdown-integration.d.ts +5 -0
  79. package/dist/react/dropdown-integration.js +1490 -0
  80. package/dist/react/dropdown-integration.js.map +1 -0
  81. package/dist/react/dropdown-search-advanced.d.ts +5 -0
  82. package/dist/react/dropdown-search-advanced.js +1163 -0
  83. package/dist/react/dropdown-search-advanced.js.map +1 -0
  84. package/dist/react/dropdown-search-simple.d.ts +5 -0
  85. package/dist/react/dropdown-search-simple.js +1125 -0
  86. package/dist/react/dropdown-search-simple.js.map +1 -0
  87. package/dist/react/dropdown.d.ts +35 -133
  88. package/dist/react/dropdown.js +536 -1318
  89. package/dist/react/dropdown.js.map +1 -1
  90. package/dist/react/file-upload-trigger.d.ts +34 -0
  91. package/dist/react/file-upload-trigger.js +39 -0
  92. package/dist/react/file-upload-trigger.js.map +1 -0
  93. package/dist/react/form.d.ts +10 -0
  94. package/dist/react/form.js +11 -0
  95. package/dist/react/form.js.map +1 -0
  96. package/dist/react/hint-text.d.ts +17 -0
  97. package/dist/react/hint-text.js +36 -0
  98. package/dist/react/hint-text.js.map +1 -0
  99. package/dist/react/hook-form.d.ts +35 -0
  100. package/dist/react/hook-form.js +50 -0
  101. package/dist/react/hook-form.js.map +1 -0
  102. package/dist/react/input-date.d.ts +43 -0
  103. package/dist/react/input-date.js +306 -0
  104. package/dist/react/input-date.js.map +1 -0
  105. package/dist/react/input-file.d.ts +45 -0
  106. package/dist/react/input-file.js +748 -0
  107. package/dist/react/input-file.js.map +1 -0
  108. package/dist/react/input-group.d.ts +37 -0
  109. package/dist/react/input-group.js +251 -0
  110. package/dist/react/input-group.js.map +1 -0
  111. package/dist/react/input-number.d.ts +32 -0
  112. package/dist/react/input-number.js +553 -0
  113. package/dist/react/input-number.js.map +1 -0
  114. package/dist/react/input-payment.d.ts +16 -0
  115. package/dist/react/input-payment.js +593 -0
  116. package/dist/react/input-payment.js.map +1 -0
  117. package/dist/react/input-tags-outer.d.ts +53 -0
  118. package/dist/react/input-tags-outer.js +607 -0
  119. package/dist/react/input-tags-outer.js.map +1 -0
  120. package/dist/react/input-tags.d.ts +53 -0
  121. package/dist/react/input-tags.js +565 -0
  122. package/dist/react/input-tags.js.map +1 -0
  123. package/dist/react/input.d.ts +71 -22
  124. package/dist/react/input.js +332 -45
  125. package/dist/react/input.js.map +1 -1
  126. package/dist/react/label.d.ts +18 -0
  127. package/dist/react/label.js +112 -0
  128. package/dist/react/label.js.map +1 -0
  129. package/dist/react/multi-select.d.ts +90 -0
  130. package/dist/react/multi-select.js +1237 -0
  131. package/dist/react/multi-select.js.map +1 -0
  132. package/dist/react/pin-input.d.ts +59 -0
  133. package/dist/react/pin-input.js +229 -0
  134. package/dist/react/pin-input.js.map +1 -0
  135. package/dist/react/popover.d.ts +14 -71
  136. package/dist/react/popover.js +171 -540
  137. package/dist/react/popover.js.map +1 -1
  138. package/dist/react/progress-circle.d.ts +9 -0
  139. package/dist/react/progress-circle.js +36 -0
  140. package/dist/react/progress-circle.js.map +1 -0
  141. package/dist/react/progress-circles.d.ts +14 -0
  142. package/dist/react/progress-circles.js +160 -0
  143. package/dist/react/progress-circles.js.map +1 -0
  144. package/dist/react/progress-indicators.d.ts +52 -0
  145. package/dist/react/progress-indicators.js +78 -0
  146. package/dist/react/progress-indicators.js.map +1 -0
  147. package/dist/react/radio-buttons.d.ts +35 -0
  148. package/dist/react/radio-buttons.js +117 -0
  149. package/dist/react/radio-buttons.js.map +1 -0
  150. package/dist/react/scroll-header.d.ts +6 -0
  151. package/dist/react/scroll-header.js +42 -61
  152. package/dist/react/scroll-header.js.map +1 -1
  153. package/dist/react/scroll-wheel.d.ts +4 -5
  154. package/dist/react/scroll-wheel.js +19 -15
  155. package/dist/react/scroll-wheel.js.map +1 -1
  156. package/dist/react/select-item.d.ts +14 -0
  157. package/dist/react/select-item.js +340 -0
  158. package/dist/react/select-item.js.map +1 -0
  159. package/dist/react/select-native.d.ts +17 -0
  160. package/dist/react/select-native.js +203 -0
  161. package/dist/react/select-native.js.map +1 -0
  162. package/dist/react/select.d.ts +19 -61
  163. package/dist/react/select.js +866 -908
  164. package/dist/react/select.js.map +1 -1
  165. package/dist/react/sheet.d.ts +19 -19
  166. package/dist/react/sheet.js +97 -219
  167. package/dist/react/sheet.js.map +1 -1
  168. package/dist/react/slider.d.ts +15 -0
  169. package/dist/react/slider.js +66 -0
  170. package/dist/react/slider.js.map +1 -0
  171. package/dist/react/social-button.d.ts +55 -0
  172. package/dist/react/social-button.js +263 -0
  173. package/dist/react/social-button.js.map +1 -0
  174. package/dist/react/social-logos.d.ts +20 -0
  175. package/dist/react/social-logos.js +131 -0
  176. package/dist/react/social-logos.js.map +1 -0
  177. package/dist/react/switch.d.ts +21 -36
  178. package/dist/react/switch.js +121 -109
  179. package/dist/react/switch.js.map +1 -1
  180. package/dist/react/tag-select.d.ts +47 -0
  181. package/dist/react/tag-select.js +1252 -0
  182. package/dist/react/tag-select.js.map +1 -0
  183. package/dist/react/tags.d.ts +30 -0
  184. package/dist/react/tags.js +228 -0
  185. package/dist/react/tags.js.map +1 -0
  186. package/dist/react/textarea.d.ts +40 -4
  187. package/dist/react/textarea.js +193 -27
  188. package/dist/react/textarea.js.map +1 -1
  189. package/dist/react/tooltip.d.ts +30 -43
  190. package/dist/react/tooltip.js +65 -521
  191. package/dist/react/tooltip.js.map +1 -1
  192. package/dist/select-mobile-sheet-CB2ptDTJ.d.ts +12 -0
  193. package/dist/select-shared-oJEeJxeB.d.ts +68 -0
  194. package/package.json +28 -21
  195. package/source.css +2 -13
  196. package/theme.css +883 -79
  197. package/dist/react/calendar.d.ts +0 -13
  198. package/dist/react/calendar.js +0 -4639
  199. package/dist/react/calendar.js.map +0 -1
  200. package/dist/react/card.d.ts +0 -11
  201. package/dist/react/card.js +0 -113
  202. package/dist/react/card.js.map +0 -1
  203. package/dist/react/datetime-picker.d.ts +0 -21
  204. package/dist/react/datetime-picker.js +0 -6142
  205. package/dist/react/datetime-picker.js.map +0 -1
  206. package/dist/react/pagination.d.ts +0 -28
  207. package/dist/react/pagination.js +0 -262
  208. package/dist/react/pagination.js.map +0 -1
  209. package/dist/react/table-pagination.d.ts +0 -15
  210. package/dist/react/table-pagination.js +0 -1247
  211. package/dist/react/table-pagination.js.map +0 -1
  212. package/dist/react/table-view/column-menu.d.ts +0 -15
  213. package/dist/react/table-view/column-menu.js +0 -1049
  214. package/dist/react/table-view/column-menu.js.map +0 -1
  215. package/dist/react/table-view/index.d.ts +0 -70
  216. package/dist/react/table-view/index.js +0 -2284
  217. package/dist/react/table-view/index.js.map +0 -1
  218. package/dist/react/table.d.ts +0 -86
  219. package/dist/react/table.js +0 -414
  220. package/dist/react/table.js.map +0 -1
  221. package/dist/react/tabs.d.ts +0 -34
  222. package/dist/react/tabs.js +0 -423
  223. package/dist/react/tabs.js.map +0 -1
  224. package/dist/react/time-picker.d.ts +0 -22
  225. package/dist/react/time-picker.js +0 -856
  226. package/dist/react/time-picker.js.map +0 -1
@@ -1,391 +1,78 @@
1
- import * as React3 from 'react';
2
- import React3__default, { useState, useCallback, useRef, useLayoutEffect, useMemo, useEffect } from 'react';
1
+ import { createContext, useCallback, useMemo, useContext, useEffect, useState, useLayoutEffect, useRef } from 'react';
3
2
  import { createPortal } from 'react-dom';
4
- import { X, ChevronDown, Check, ChevronRight } from 'lucide-react';
5
- import { clsx } from 'clsx';
6
- import { twMerge } from 'tailwind-merge';
7
- import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { CheckIcon } from '@phosphor-icons/react/dist/csr/Check';
4
+ import { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';
5
+ import { DotsThreeVerticalIcon } from '@phosphor-icons/react/dist/csr/DotsThreeVertical';
6
+ import { XIcon } from '@phosphor-icons/react/dist/csr/X';
7
+ import { Header, MenuSection, MenuTrigger, MenuItem, Menu, OverlayTriggerStateContext, Popover, Separator, Button } from 'react-aria-components';
8
+ import { extendTailwindMerge } from 'tailwind-merge';
9
+ import { UserIcon } from '@phosphor-icons/react/dist/csr/User';
10
+ import '@phosphor-icons/react/dist/csr/Plus';
11
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
12
 
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 = React3.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 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";
184
-
185
- // src/lib/typeahead.ts
186
- var TYPEAHEAD_TIMEOUT_MS = 500;
187
- function createTypeaheadState() {
188
- return { search: "", timer: null };
189
- }
190
- function resetTypeahead(state) {
191
- state.search = "";
192
- if (state.timer) {
193
- clearTimeout(state.timer);
194
- state.timer = null;
195
- }
196
- }
197
- function getItemLabel(item) {
198
- const aria = item.getAttribute("aria-label")?.trim();
199
- if (aria) return aria;
200
- const marked = item.querySelector("[data-menu-label]");
201
- if (marked?.textContent) return marked.textContent.replace(/\s+/g, " ").trim();
202
- return (item.textContent ?? "").replace(/\s+/g, " ").trim();
203
- }
204
- function normalizeSearch(value) {
205
- return value.trim().toLocaleLowerCase();
206
- }
207
- function isTypeaheadTarget(target) {
208
- if (!(target instanceof HTMLElement)) return true;
209
- if (target.isContentEditable) return false;
210
- const tag = target.tagName;
211
- return tag !== "INPUT" && tag !== "TEXTAREA" && tag !== "SELECT";
212
- }
213
- function handleTypeaheadKeyDown(event, items, state, options) {
214
- if (options?.enabled === false || items.length === 0) return false;
215
- if (event.ctrlKey || event.metaKey || event.altKey) return false;
216
- if (event.key.length !== 1 || !isTypeaheadTarget(event.target)) return false;
217
- event.preventDefault();
218
- const timeoutMs = options?.timeoutMs ?? TYPEAHEAD_TIMEOUT_MS;
219
- const char = event.key;
220
- const prevSearch = state.search;
221
- const repeatSingleChar = prevSearch.length === 1 && prevSearch === char;
222
- if (repeatSingleChar) {
223
- state.search = prevSearch;
224
- } else {
225
- state.search = prevSearch + char;
226
- }
227
- if (state.timer) clearTimeout(state.timer);
228
- state.timer = setTimeout(() => {
229
- state.search = "";
230
- state.timer = null;
231
- }, timeoutMs);
232
- const labels = items.map((item) => normalizeSearch(getItemLabel(item)));
233
- let needle = normalizeSearch(state.search);
234
- let matches = items.map((item, index) => ({ item, index, label: labels[index] })).filter(({ label }) => label.startsWith(needle));
235
- if (matches.length === 0 && state.search.length > 1) {
236
- state.search = char;
237
- needle = normalizeSearch(char);
238
- matches = items.map((item, index) => ({ item, index, label: labels[index] })).filter(({ label }) => label.startsWith(needle));
239
- }
240
- if (matches.length === 0) return true;
241
- const focused = document.activeElement;
242
- const focusedIndex = focused ? items.indexOf(focused) : -1;
243
- if (repeatSingleChar && focusedIndex !== -1) {
244
- const currentMatch = matches.findIndex(
245
- ({ index }) => index === focusedIndex
246
- );
247
- if (currentMatch !== -1) {
248
- const next = matches[(currentMatch + 1) % matches.length];
249
- next?.item.focus();
250
- return true;
251
- }
252
- }
253
- if (focusedIndex !== -1) {
254
- const nextAfterFocus = matches.find(({ index }) => index > focusedIndex);
255
- if (nextAfterFocus) {
256
- nextAfterFocus.item.focus();
257
- return true;
258
- }
259
- }
260
- matches[0]?.item.focus();
261
- return true;
262
- }
263
- var DROPDOWN_PANEL_OPEN_EASING = "cubic-bezier(0,0.55,0.45,1)";
264
- var DROPDOWN_PANEL_CLOSE_EASING = "cubic-bezier(0.55,0,1,0.45)";
265
- var DROPDOWN_MENU_MIN_WIDTH_PX = 192;
266
- var DROPDOWN_FLIP_MIN_SPACE_PX = 100;
267
- var DROPDOWN_MOBILE_SHEET_MAX_PX = 1024;
268
- var DROPDOWN_MOBILE_SHEET_MOTION_MS = 175;
269
- var DROPDOWN_MOBILE_SHEET_ENTRY_EASING = "cubic-bezier(0.85, 0, 0.15, 1)";
270
- var DROPDOWN_MOBILE_SHEET_EXIT_EASING = "cubic-bezier(0.85, 0, 1, 0.15)";
271
- var DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX = 120;
272
- function resolveDropdownMobileSheet(mobileOptions) {
13
+ var MOBILE_SHEET_MOTION_MS = 175;
14
+ var MOBILE_SHEET_ENTRY_EASING = "cubic-bezier(0.85, 0, 0.15, 1)";
15
+ var MOBILE_SHEET_EXIT_EASING = "cubic-bezier(0.85, 0, 1, 0.15)";
16
+ var MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_PX = 120;
17
+ function resolveSelectMobileOptions(mobileOptions) {
273
18
  return {
274
19
  sheet: mobileOptions?.sheet ?? true,
275
20
  title: mobileOptions?.title,
276
- sheetExtraClassName: mobileOptions?.className,
21
+ sheetClassName: mobileOptions?.className,
277
22
  contentClassName: mobileOptions?.contentClassName
278
23
  };
279
24
  }
280
- var DROPDOWN_SUB_CONTENT_ATTR = "data-dropdown-sub-content";
281
- 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)]";
282
- var DROPDOWN_PANEL_SCROLL = "[&_*]:[scrollbar-width:none] [&_*::-webkit-scrollbar]:hidden [&_*]:overscroll-contain";
283
- function preventMenuWheelChain(menu, e) {
284
- let el = e.target;
285
- while (el && menu.contains(el)) {
286
- const oy = getComputedStyle(el).overflowY;
287
- if ((oy === "auto" || oy === "scroll") && el.scrollHeight > el.clientHeight) {
288
- const atTop = el.scrollTop <= 0;
289
- const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight;
290
- if (e.deltaY < 0 && !atTop || e.deltaY > 0 && !atBottom) return;
291
- break;
292
- }
293
- el = el.parentElement;
294
- }
295
- e.preventDefault();
296
- }
297
- var DROPDOWN_SHEET_MENU_TEXT = "max-[1024px]:text-base";
298
- var DROPDOWN_SHEET_MENU_SHORTCUT = "max-[1024px]:text-sm";
299
- var DROPDOWN_SHEET_MENU_LABEL_TEXT = "max-[1024px]:text-sm";
300
- var DROPDOWN_CONTENT_ORIGIN = {
301
- bottom: "top center",
302
- top: "bottom center",
303
- left: "right center",
304
- right: "left center"
305
- };
306
- var DROPDOWN_CONTENT_HIDDEN = {
307
- bottom: "translateY(-4px) scale(0.97)",
308
- top: "translateY(4px) scale(0.97)",
309
- left: "translateX(4px) scale(0.97)",
310
- right: "translateX(-4px) scale(0.97)"
311
- };
312
- var SUB_CONTENT_ORIGIN = {
313
- bottom: "top center",
314
- top: "bottom center",
315
- left: "right top",
316
- right: "left top"
317
- };
318
- function computePos(trigger, menu, side, align, offset, pad) {
319
- const tr = trigger.getBoundingClientRect();
320
- const mr = menu.getBoundingClientRect();
321
- const contentHeight = menu.scrollHeight;
322
- const vw = window.innerWidth;
323
- const vh = window.innerHeight;
324
- const sx = window.scrollX;
325
- const sy = window.scrollY;
326
- let top = 0;
327
- let left = 0;
328
- let effectiveSide = side;
329
- let maxHeight;
330
- const placeVertical = (s, height) => {
331
- if (s === "bottom") top = tr.bottom + sy + offset;
332
- else top = tr.top + sy - height - offset;
333
- if (align === "start") left = tr.left + sx;
334
- else if (align === "end") left = tr.right + sx - mr.width;
335
- else left = tr.left + sx + tr.width / 2 - mr.width / 2;
336
- };
337
- const calc = (s, height = contentHeight) => {
338
- switch (s) {
339
- case "bottom":
340
- case "top":
341
- placeVertical(s, height);
342
- break;
343
- case "right":
344
- left = tr.right + sx + offset;
345
- if (align === "start") top = tr.top + sy;
346
- else if (align === "end") top = tr.bottom + sy - mr.height;
347
- else top = tr.top + sy + tr.height / 2 - mr.height / 2;
348
- break;
349
- case "left":
350
- left = tr.left + sx - mr.width - offset;
351
- if (align === "start") top = tr.top + sy;
352
- else if (align === "end") top = tr.bottom + sy - mr.height;
353
- else top = tr.top + sy + tr.height / 2 - mr.height / 2;
354
- break;
355
- }
356
- };
357
- calc(side);
358
- const spaceBelow = Math.max(0, vh - pad - tr.bottom - offset);
359
- const spaceAbove = Math.max(0, tr.top - offset - pad);
360
- if (side === "bottom" || side === "top") {
361
- const primarySpace = side === "bottom" ? spaceBelow : spaceAbove;
362
- const alternateSpace = side === "bottom" ? spaceAbove : spaceBelow;
363
- const alternateSide = side === "bottom" ? "top" : "bottom";
364
- if (contentHeight > primarySpace) {
365
- maxHeight = Math.min(contentHeight, primarySpace);
366
- calc(side, maxHeight);
367
- }
368
- if (contentHeight > primarySpace && primarySpace < DROPDOWN_FLIP_MIN_SPACE_PX && alternateSpace > primarySpace) {
369
- effectiveSide = alternateSide;
370
- maxHeight = Math.min(contentHeight, alternateSpace);
371
- calc(alternateSide, maxHeight);
372
- }
373
- } else if (side === "right" && left + mr.width > vw + sx - pad) {
374
- const fl = tr.left + sx - mr.width - offset;
375
- if (fl >= sx + pad) {
376
- effectiveSide = "left";
377
- left = fl;
25
+ function useMobileSheetAnimation(open, enabled, slideEntrance = true, slideOffsetPx = MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_PX) {
26
+ const [shouldRender, setShouldRender] = useState(open);
27
+ const [isAnimating, setIsAnimating] = useState(false);
28
+ useLayoutEffect(() => {
29
+ if (!enabled) {
30
+ setShouldRender(open);
31
+ return;
378
32
  }
379
- } else if (side === "left" && left < sx + pad) {
380
- const fl = tr.right + sx + offset;
381
- if (fl + mr.width <= vw + sx - pad) {
382
- effectiveSide = "right";
383
- left = fl;
33
+ if (open) {
34
+ setShouldRender(true);
384
35
  }
385
- }
386
- return { top, left, side: effectiveSide, maxHeight };
36
+ }, [open, enabled]);
37
+ useEffect(() => {
38
+ if (!enabled || open) return;
39
+ const timer = setTimeout(() => setShouldRender(false), MOBILE_SHEET_MOTION_MS);
40
+ return () => clearTimeout(timer);
41
+ }, [open, enabled]);
42
+ useLayoutEffect(() => {
43
+ if (!enabled || open || !shouldRender) return;
44
+ setIsAnimating(false);
45
+ }, [enabled, open, shouldRender]);
46
+ useEffect(() => {
47
+ if (!enabled || !shouldRender || !open) return;
48
+ let raf2 = 0;
49
+ const raf1 = requestAnimationFrame(() => {
50
+ raf2 = requestAnimationFrame(() => setIsAnimating(true));
51
+ });
52
+ return () => {
53
+ cancelAnimationFrame(raf1);
54
+ if (raf2) cancelAnimationFrame(raf2);
55
+ };
56
+ }, [shouldRender, open, enabled]);
57
+ const motionEasing = open ? MOBILE_SHEET_ENTRY_EASING : MOBILE_SHEET_EXIT_EASING;
58
+ const hiddenTransform = slideEntrance ? `translateY(${slideOffsetPx}px)` : "translateY(100%)";
59
+ const panelStyle = enabled ? {
60
+ transform: isAnimating ? "translateY(0)" : hiddenTransform,
61
+ opacity: isAnimating ? 1 : 0,
62
+ transitionProperty: "transform, opacity",
63
+ transitionDuration: `${MOBILE_SHEET_MOTION_MS}ms`,
64
+ transitionTimingFunction: motionEasing
65
+ } : void 0;
66
+ const backdropStyle = enabled ? {
67
+ opacity: isAnimating ? 1 : 0,
68
+ transitionProperty: "opacity",
69
+ transitionDuration: `${MOBILE_SHEET_MOTION_MS}ms`,
70
+ transitionTimingFunction: motionEasing
71
+ } : void 0;
72
+ return { shouldRender, isAnimating, panelStyle, backdropStyle };
387
73
  }
388
- function useIsMobile(breakpoint = 1025) {
74
+ var MOBILE_SHEET_MAX_PX = 1024;
75
+ function useIsMobile(breakpoint = MOBILE_SHEET_MAX_PX + 1) {
389
76
  const [isMobile, setIsMobile] = useState(() => {
390
77
  if (typeof window === "undefined") return false;
391
78
  return window.matchMedia(`(max-width: ${breakpoint - 1}px)`).matches;
@@ -398,1031 +85,562 @@ function useIsMobile(breakpoint = 1025) {
398
85
  }, [breakpoint]);
399
86
  return isMobile;
400
87
  }
401
- var DropdownContext = React3__default.createContext(void 0);
402
- function useDropdown() {
403
- const ctx = React3__default.useContext(DropdownContext);
404
- if (!ctx)
405
- throw new Error("Dropdown components must be used within <Dropdown />");
406
- return ctx;
407
- }
408
- var SubContext = React3__default.createContext(void 0);
409
- var Dropdown = ({
410
- children,
411
- open: controlledOpen,
412
- onOpenChange
413
- }) => {
414
- const [internalOpen, setInternalOpen] = useState(false);
415
- const isControlled = controlledOpen !== void 0;
416
- const open = isControlled ? controlledOpen : internalOpen;
417
- const triggerRef = useRef(null);
418
- const [radioValues, setRadioValues] = useState({});
419
- const setOpen = useCallback(
420
- (v) => {
421
- if (!isControlled) setInternalOpen(v);
422
- onOpenChange?.(v);
423
- },
424
- [isControlled, onOpenChange]
425
- );
426
- const setRadioValue = useCallback((group, value) => {
427
- setRadioValues((prev) => ({ ...prev, [group]: value }));
428
- }, []);
429
- const ctx = useMemo(
430
- () => ({ open, setOpen, triggerRef, radioValues, setRadioValue }),
431
- [open, setOpen, radioValues, setRadioValue]
432
- );
433
- return /* @__PURE__ */ jsx(DropdownContext.Provider, { value: ctx, children });
434
- };
435
- function mergeTriggerRef(triggerRef, node, childRef) {
436
- triggerRef.current = node;
437
- if (typeof childRef === "function") childRef(node);
438
- else if (childRef && typeof childRef === "object")
439
- childRef.current = node;
440
- }
441
- var DropdownTrigger = React3__default.forwardRef(
442
- ({
443
- children,
444
- asChild,
445
- className,
446
- onClick: onClickProp,
447
- disabled,
448
- ...buttonProps
449
- }, ref) => {
450
- const { open, setOpen, triggerRef } = useDropdown();
451
- const handleClick = useCallback(
452
- (e) => {
453
- onClickProp?.(e);
454
- e.stopPropagation();
455
- if (disabled) return;
456
- setOpen(!open);
457
- },
458
- [disabled, onClickProp, open, setOpen]
459
- );
460
- const setButtonRef = useCallback(
461
- (el) => {
462
- triggerRef.current = el;
463
- if (typeof ref === "function") ref(el);
464
- else if (ref) ref.current = el;
465
- },
466
- [ref, triggerRef]
467
- );
468
- if (asChild && React3__default.isValidElement(children)) {
469
- const child = children;
470
- return React3__default.cloneElement(child, {
471
- ref: (node) => {
472
- mergeTriggerRef(
473
- triggerRef,
474
- node,
475
- child.ref
476
- );
477
- },
478
- className: cn("group", child.props.className),
479
- onClick: (e) => {
480
- child.props.onClick?.(e);
481
- handleClick(e);
482
- },
483
- "aria-expanded": open,
484
- "aria-haspopup": "menu",
485
- "data-state": open ? "open" : "closed",
486
- ...disabled !== void 0 ? {
487
- disabled
488
- } : {}
489
- });
88
+ var twMerge = extendTailwindMerge({
89
+ extend: {
90
+ theme: {
91
+ text: ["display-xs", "display-sm", "display-md", "display-lg", "display-xl", "display-2xl"]
490
92
  }
491
- return /* @__PURE__ */ jsx(
492
- Button,
493
- {
494
- ref: setButtonRef,
495
- type: "button",
496
- ...buttonProps,
497
- disabled,
498
- className: cn("group", className),
499
- "aria-expanded": open,
500
- "aria-haspopup": "menu",
501
- "data-state": open ? "open" : "closed",
502
- onClick: handleClick,
503
- children
504
- }
505
- );
93
+ }
94
+ });
95
+ var cx = twMerge;
96
+ var sizes = {
97
+ xs: "size-1.5",
98
+ sm: "size-2",
99
+ md: "size-2.5",
100
+ lg: "size-3",
101
+ xl: "size-3.5",
102
+ "2xl": "size-4",
103
+ "3xl": "size-4.5",
104
+ "4xl": "size-5"
105
+ };
106
+ var AvatarOnlineIndicator = ({ size, status, className }) => /* @__PURE__ */ jsx(
107
+ "span",
108
+ {
109
+ className: cx(
110
+ "absolute right-0 bottom-0 flex justify-center rounded-full ring-[1.5px] ring-bg-primary",
111
+ status === "online" ? "bg-fg-success-secondary" : "bg-utility-neutral-300",
112
+ sizes[size],
113
+ className
114
+ ),
115
+ style: {
116
+ backgroundImage: "radial-gradient(43.75% 43.75% at 50% 28.75%, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.00) 100%), radial-gradient(50% 50% at 50% 50%, rgba(255, 255, 255, 0.00) 74.66%, rgba(255, 255, 255, 0.18) 100%), radial-gradient(75% 75% at 50% 0%, rgba(255, 255, 255, 0.00) 0%, rgba(255, 255, 255, 0.00) 50%, rgba(255, 255, 255, 0.08) 99%, rgba(255, 255, 255, 0.00) 100%)"
117
+ },
118
+ children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 7.2 2.85", fill: "none", className: "mt-[10%] h-[20%] w-[60%]", children: [
119
+ /* @__PURE__ */ jsx(
120
+ "path",
121
+ {
122
+ d: "M7.2 1.83107C7.2 2.84235 5.58823 2.19729 3.6 2.19729C1.61177 2.19729 0 2.84235 0 1.83107C0 0.8198 1.61177 0 3.6 0C5.58823 0 7.2 0.8198 7.2 1.83107Z",
123
+ fill: "url(#reflection-gradient)",
124
+ fillOpacity: "0.4"
125
+ }
126
+ ),
127
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: "reflection-gradient", x1: "3.6", y1: "0", x2: "3.6", y2: "2.4", gradientUnits: "userSpaceOnUse", children: [
128
+ /* @__PURE__ */ jsx("stop", { stopColor: "white" }),
129
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "white", stopOpacity: "0.1" })
130
+ ] }) })
131
+ ] })
506
132
  }
507
133
  );
508
- DropdownTrigger.displayName = "DropdownTrigger";
509
- function DropdownChevron({
510
- className,
511
- ...props
512
- }) {
513
- const { open } = useDropdown();
514
- return /* @__PURE__ */ jsx(
515
- ChevronDown,
134
+ var sizes2 = {
135
+ xs: "size-2.5",
136
+ sm: "size-3",
137
+ md: "size-3.5",
138
+ lg: "size-4",
139
+ xl: "size-4.5",
140
+ "2xl": "size-5",
141
+ "3xl": "size-6",
142
+ "4xl": "size-8"
143
+ };
144
+ var VerifiedTick = ({ size, className }) => /* @__PURE__ */ jsxs("svg", { className: cx("z-10 text-utility-blue-500", sizes2[size], className), viewBox: "0 0 10 10", fill: "none", children: [
145
+ /* @__PURE__ */ jsx(
146
+ "path",
516
147
  {
517
- "aria-hidden": true,
518
- className: cn("size-4 shrink-0", open && "rotate-180", className),
519
- ...props
148
+ d: "M7.72237 1.77098C7.81734 2.00068 7.99965 2.18326 8.2292 2.27858L9.03413 2.61199C9.26384 2.70714 9.44635 2.88965 9.5415 3.11936C9.63665 3.34908 9.63665 3.60718 9.5415 3.83689L9.20833 4.64125C9.11313 4.87106 9.113 5.12943 9.20863 5.35913L9.54122 6.16325C9.58839 6.27702 9.61268 6.39897 9.6127 6.52214C9.61272 6.6453 9.58847 6.76726 9.54134 6.88105C9.4942 6.99484 9.42511 7.09823 9.33801 7.18531C9.2509 7.27238 9.14749 7.34144 9.03369 7.38854L8.22934 7.72171C7.99964 7.81669 7.81706 7.99899 7.72174 8.22855L7.38833 9.03348C7.29318 9.26319 7.11067 9.4457 6.88096 9.54085C6.65124 9.636 6.39314 9.636 6.16343 9.54085L5.35907 9.20767C5.12935 9.11276 4.87134 9.11295 4.64177 9.20821L3.83684 9.54115C3.60725 9.63608 3.34937 9.636 3.11984 9.54092C2.89032 9.44585 2.70791 9.26356 2.6127 9.03409L2.27918 8.22892C2.18421 7.99923 2.0019 7.81665 1.77235 7.72133L0.967421 7.38792C0.737807 7.29281 0.555355 7.11041 0.460169 6.88083C0.364983 6.65125 0.364854 6.39327 0.45981 6.16359L0.792984 5.35924C0.8879 5.12952 0.887707 4.87151 0.792445 4.64193L0.459749 3.83642C0.41258 3.72265 0.388291 3.60069 0.388272 3.47753C0.388252 3.35436 0.412501 3.2324 0.459634 3.11861C0.506767 3.00482 0.57586 2.90144 0.662965 2.81436C0.75007 2.72728 0.853479 2.65822 0.967283 2.61113L1.77164 2.27795C2.00113 2.18306 2.1836 2.00099 2.27899 1.7717L2.6124 0.966768C2.70755 0.737054 2.89006 0.554547 3.11978 0.459397C3.34949 0.364246 3.60759 0.364246 3.83731 0.459397L4.64166 0.792571C4.87138 0.887487 5.12939 0.887293 5.35897 0.792031L6.16424 0.459913C6.39392 0.364816 6.65197 0.364836 6.88164 0.459968C7.11131 0.555099 7.29379 0.737554 7.38895 0.967208L7.72247 1.77238L7.72237 1.77098Z",
149
+ className: "fill-current"
520
150
  }
521
- );
522
- }
523
- var DropdownMobileClose = React3__default.forwardRef(({ className, type = "button", ...props }, ref) => {
524
- return /* @__PURE__ */ jsxs(
525
- "button",
151
+ ),
152
+ /* @__PURE__ */ jsx(
153
+ "path",
526
154
  {
527
- ref,
528
- type,
529
- className: cn(
530
- "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]",
531
- className
532
- ),
533
- ...props,
534
- children: [
535
- /* @__PURE__ */ jsx(X, { className: "size-5.5" }),
536
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
537
- ]
155
+ fillRule: "evenodd",
156
+ clipRule: "evenodd",
157
+ d: "M6.95829 3.68932C7.02509 3.58439 7.04747 3.45723 7.02051 3.3358C6.99356 3.21437 6.91946 3.10862 6.81454 3.04182C6.70961 2.97502 6.58245 2.95264 6.46102 2.97959C6.33959 3.00655 6.23384 3.08064 6.16704 3.18557L4.33141 6.06995L3.49141 5.01995C3.41375 4.92281 3.30069 4.8605 3.17709 4.84673C3.05349 4.83296 2.92949 4.86885 2.83235 4.94651C2.73522 5.02417 2.67291 5.13723 2.65914 5.26083C2.64536 5.38443 2.68125 5.50843 2.75891 5.60557L4.00891 7.16807C4.0555 7.22638 4.11533 7.27271 4.18344 7.30323C4.25154 7.33375 4.32595 7.34757 4.40047 7.34353C4.47499 7.3395 4.54747 7.31773 4.61188 7.28004C4.67629 7.24234 4.73077 7.18981 4.77079 7.12682L6.95829 3.68932Z",
158
+ fill: "white"
538
159
  }
539
- );
540
- });
541
- DropdownMobileClose.displayName = "DropdownMobileClose";
542
- function DropdownMobileBottomSheetPortal({
543
- open,
544
- isAnimating,
545
- slideEntrance,
546
- slideOffsetPx,
547
- sheetTitle,
548
- sheetExtraClassName,
549
- contentClassName,
550
- onRequestClose,
551
- menuRef,
552
- portalZClassName = "z-50",
553
- isSubPortal = false,
554
- children,
555
- className,
556
- style,
557
- ...panelProps
558
- }) {
559
- const sheetMotion = open ? DROPDOWN_MOBILE_SHEET_ENTRY_EASING : DROPDOWN_MOBILE_SHEET_EXIT_EASING;
560
- const sheetHiddenTransform = slideEntrance ? `translateY(${slideOffsetPx}px)` : "translateY(100%)";
561
- return createPortal(
562
- /* @__PURE__ */ jsxs(
563
- "div",
564
- {
565
- ...isSubPortal ? { [DROPDOWN_SUB_CONTENT_ATTR]: "" } : {},
566
- className: cn(
567
- "fixed inset-0 flex items-end justify-center p-0",
568
- portalZClassName
569
- ),
570
- children: [
571
- /* @__PURE__ */ jsx(
572
- "div",
573
- {
574
- className: cn(
575
- "fixed inset-0 bg-black/40 dark:bg-primary/4",
576
- isAnimating ? "opacity-100" : "opacity-0"
577
- ),
578
- style: {
579
- transitionProperty: "opacity",
580
- transitionDuration: `${DROPDOWN_MOBILE_SHEET_MOTION_MS}ms`,
581
- transitionTimingFunction: sheetMotion
582
- },
583
- onClick: onRequestClose
584
- }
585
- ),
586
- /* @__PURE__ */ jsxs(
587
- "div",
588
- {
589
- ...panelProps,
590
- ref: menuRef,
591
- className: cn(
592
- "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",
593
- "rounded-t-2xl rounded-b-none border-x-0 border-b-0 border-t",
594
- DROPDOWN_PANEL_SCROLL,
595
- sheetExtraClassName,
596
- className
597
- ),
598
- style: {
599
- transform: isAnimating ? "translateY(0)" : sheetHiddenTransform,
600
- opacity: isAnimating ? 1 : 0,
601
- transitionProperty: "transform, opacity",
602
- transitionDuration: `${DROPDOWN_MOBILE_SHEET_MOTION_MS}ms`,
603
- transitionTimingFunction: sheetMotion,
604
- ...style
605
- },
606
- children: [
607
- /* @__PURE__ */ jsxs(
608
- "div",
609
- {
610
- className: cn(
611
- "flex w-full shrink-0 items-center py-2 pl-4 pr-2",
612
- sheetTitle ? "justify-between gap-3" : "justify-end"
613
- ),
614
- children: [
615
- sheetTitle ? /* @__PURE__ */ jsx("p", { className: "text-foreground min-w-0 flex-1 truncate text-base font-semibold", children: sheetTitle }) : null,
616
- /* @__PURE__ */ jsx(
617
- DropdownMobileClose,
618
- {
619
- onClick: (e) => {
620
- e.stopPropagation();
621
- onRequestClose();
622
- }
623
- }
624
- )
625
- ]
626
- }
627
- ),
628
- /* @__PURE__ */ jsx(
629
- "div",
630
- {
631
- className: cn(
632
- "min-h-0 flex-1 overflow-y-auto pb-[calc(5rem+env(safe-area-inset-bottom,0px))]",
633
- contentClassName
634
- ),
635
- children
636
- }
637
- )
638
- ]
639
- }
640
- )
641
- ]
642
- }
643
- ),
644
- document.body
645
- );
646
- }
647
- var DropdownContent = ({
648
- children,
649
- side = "bottom",
650
- align = "start",
651
- offset = 10,
652
- duration = 80,
653
- viewportPadding = 8,
654
- closeOnEscape = true,
655
- minWidth = "trigger",
656
- loop = true,
657
- typeahead = true,
658
- mobileOptions,
659
- slideEntrance = true,
660
- slideEntranceOffsetPx: slideEntranceOffsetPxProp,
160
+ )
161
+ ] });
162
+ var AvatarCount = ({ count, className }) => /* @__PURE__ */ jsx("div", { className: cx("absolute right-0 bottom-0 p-px", className), children: /* @__PURE__ */ jsx("div", { className: "flex size-3.5 items-center justify-center rounded-full bg-fg-error-primary text-center text-[10px] leading-[13px] font-bold text-white", children: count }) });
163
+ var styles = {
164
+ xs: { root: "size-6", rootWithBorder: "p-px", initials: "text-xs font-semibold", icon: "size-4" },
165
+ sm: { root: "size-8", rootWithBorder: "p-px", initials: "text-sm font-semibold", icon: "size-5" },
166
+ md: { root: "size-10", rootWithBorder: "p-px", initials: "text-md font-semibold", icon: "size-6" },
167
+ lg: { root: "size-12", rootWithBorder: "p-[1.5px]", initials: "text-lg font-semibold", icon: "size-7" },
168
+ xl: { root: "size-14", rootWithBorder: "p-0.5", initials: "text-xl font-semibold", icon: "size-8" },
169
+ "2xl": { root: "size-16", rootWithBorder: "p-0.5", initials: "text-display-xs font-semibold", icon: "size-8" }
170
+ };
171
+ var Avatar = ({
172
+ size = "md",
173
+ src,
174
+ alt,
175
+ initials,
176
+ placeholder,
177
+ placeholderIcon: PlaceholderIcon,
178
+ border,
179
+ badge,
180
+ status,
181
+ verified,
182
+ count,
183
+ focusable = false,
184
+ rounded = true,
661
185
  className,
662
- style,
663
- ...props
186
+ contentClassName
664
187
  }) => {
665
- const isMobile = useIsMobile(DROPDOWN_MOBILE_SHEET_MAX_PX + 1);
666
- const { open, setOpen, triggerRef } = useDropdown();
667
- const [shouldRender, setShouldRender] = useState(false);
668
- const [isAnimating, setIsAnimating] = useState(false);
669
- const [pos, setPos] = useState({ top: -9999, left: -9999, side });
670
- const [triggerW, setTriggerW] = useState(0);
671
- const menuRef = useRef(null);
672
- const typeaheadStateRef = useRef(createTypeaheadState());
673
- const resolvedMobile = resolveDropdownMobileSheet(mobileOptions);
674
- const isMobileSheet = isMobile && resolvedMobile.sheet;
675
- const slideOffsetPx = slideEntranceOffsetPxProp ?? DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX;
676
- useEffect(() => {
677
- if (open) {
678
- setShouldRender(true);
679
- return;
188
+ const [isFailed, setIsFailed] = useState(false);
189
+ const canShowImage = src && !isFailed;
190
+ const renderMainContent = () => {
191
+ if (canShowImage) {
192
+ return /* @__PURE__ */ jsx("img", { "data-avatar-img": true, className: "size-full object-cover", src, alt, onError: () => setIsFailed(true) });
680
193
  }
681
- if (!isMobileSheet) {
682
- setShouldRender(false);
683
- return;
194
+ if (initials) {
195
+ return /* @__PURE__ */ jsx("span", { className: cx("text-quaternary", styles[size].initials), children: initials });
684
196
  }
685
- setIsAnimating(false);
686
- const t = setTimeout(
687
- () => setShouldRender(false),
688
- DROPDOWN_MOBILE_SHEET_MOTION_MS
689
- );
690
- return () => clearTimeout(t);
691
- }, [open, isMobileSheet]);
692
- useEffect(() => {
693
- if (!shouldRender || !open) return;
694
- let raf2 = 0;
695
- const raf1 = requestAnimationFrame(() => {
696
- raf2 = requestAnimationFrame(() => setIsAnimating(true));
697
- });
698
- return () => {
699
- cancelAnimationFrame(raf1);
700
- if (raf2) cancelAnimationFrame(raf2);
701
- };
702
- }, [shouldRender, open]);
703
- useLayoutEffect(() => {
704
- if (!shouldRender || !triggerRef.current || !menuRef.current) return;
705
- const update = () => {
706
- if (!triggerRef.current || !menuRef.current) return;
707
- setTriggerW(triggerRef.current.getBoundingClientRect().width);
708
- setPos(
709
- computePos(
710
- triggerRef.current,
711
- menuRef.current,
712
- side,
713
- align,
714
- offset,
715
- viewportPadding
716
- )
717
- );
718
- };
719
- update();
720
- window.addEventListener("resize", update);
721
- return () => {
722
- window.removeEventListener("resize", update);
723
- };
724
- }, [shouldRender, side, align, offset, viewportPadding]);
725
- useEffect(() => {
726
- if (!open || isMobileSheet) return;
727
- const isInsideMenu = (t) => t instanceof Node && (!!menuRef.current?.contains(t) || !!triggerRef.current?.contains(t) || t instanceof Element && !!t.closest(`[${DROPDOWN_SUB_CONTENT_ATTR}]`));
728
- const onScroll = (e) => {
729
- if (!isInsideMenu(e.target)) setOpen(false);
730
- };
731
- window.addEventListener("scroll", onScroll, true);
732
- return () => window.removeEventListener("scroll", onScroll, true);
733
- }, [open, isMobileSheet, setOpen, triggerRef]);
734
- useEffect(() => {
735
- if (!shouldRender || isMobileSheet) return;
736
- const menu = menuRef.current;
737
- if (!menu) return;
738
- const onWheel = (e) => preventMenuWheelChain(menu, e);
739
- menu.addEventListener("wheel", onWheel, { passive: false });
740
- return () => menu.removeEventListener("wheel", onWheel);
741
- }, [shouldRender, isMobileSheet]);
742
- useEffect(() => {
743
- if (isAnimating && menuRef.current) {
744
- menuRef.current.focus();
197
+ if (PlaceholderIcon) {
198
+ return /* @__PURE__ */ jsx(PlaceholderIcon, { className: cx("text-fg-quaternary", styles[size].icon) });
745
199
  }
746
- }, [isAnimating]);
747
- useEffect(() => {
748
- if (!open) resetTypeahead(typeaheadStateRef.current);
749
- }, [open]);
750
- useEffect(() => {
751
- if (!open) return;
752
- const handler = (e) => {
753
- const t = e.target;
754
- if (menuRef.current?.contains(t) || triggerRef.current?.contains(t))
755
- return;
756
- const el = e.target instanceof Element ? e.target : null;
757
- if (el?.closest?.(`[${DROPDOWN_SUB_CONTENT_ATTR}]`)) return;
758
- setOpen(false);
759
- };
760
- document.addEventListener("mousedown", handler);
761
- return () => document.removeEventListener("mousedown", handler);
762
- }, [open, setOpen, triggerRef]);
763
- useEffect(() => {
764
- if (!open) return;
765
- const handler = (e) => {
766
- const menu = menuRef.current;
767
- if (!menu) return;
768
- const focusedEl = document.activeElement;
769
- if (focusedEl && !menu.contains(focusedEl)) return;
770
- const items = getItems(menu);
771
- const idx = items.indexOf(focusedEl);
772
- switch (e.key) {
773
- case "Escape":
774
- if (closeOnEscape) {
775
- e.preventDefault();
776
- setOpen(false);
777
- triggerRef.current?.focus();
778
- }
779
- break;
780
- case "ArrowDown":
781
- e.preventDefault();
782
- if (items.length === 0) break;
783
- if (idx === -1 || idx === items.length - 1 && loop)
784
- items[0]?.focus();
785
- else if (idx < items.length - 1) items[idx + 1]?.focus();
786
- break;
787
- case "ArrowUp":
788
- e.preventDefault();
789
- if (items.length === 0) break;
790
- if (idx <= 0 && loop) items[items.length - 1]?.focus();
791
- else if (idx > 0) items[idx - 1]?.focus();
792
- break;
793
- case "Home":
794
- e.preventDefault();
795
- items[0]?.focus();
796
- break;
797
- case "End":
798
- e.preventDefault();
799
- items[items.length - 1]?.focus();
800
- break;
801
- case "Tab":
802
- setOpen(false);
803
- break;
804
- default:
805
- handleTypeaheadKeyDown(e, items, typeaheadStateRef.current, {
806
- enabled: typeahead
807
- });
808
- break;
809
- }
810
- };
811
- window.addEventListener("keydown", handler);
812
- return () => window.removeEventListener("keydown", handler);
813
- }, [open, closeOnEscape, loop, typeahead, setOpen, triggerRef]);
814
- useEffect(() => {
815
- if (!open || !isMobileSheet) return;
816
- document.body.style.overflow = "hidden";
817
- return () => {
818
- document.body.style.overflow = "";
819
- };
820
- }, [open, isMobileSheet]);
821
- if (!shouldRender || typeof document === "undefined") return null;
822
- if (isMobileSheet) {
823
- return /* @__PURE__ */ jsx(
824
- DropdownMobileBottomSheetPortal,
825
- {
826
- ...props,
827
- open,
828
- isAnimating,
829
- slideEntrance,
830
- slideOffsetPx,
831
- sheetTitle: resolvedMobile.title,
832
- sheetExtraClassName: resolvedMobile.sheetExtraClassName,
833
- contentClassName: resolvedMobile.contentClassName,
834
- onRequestClose: () => setOpen(false),
835
- menuRef,
836
- portalZClassName: "z-50",
837
- className,
838
- style,
839
- role: "menu",
840
- "aria-orientation": "vertical",
841
- tabIndex: -1,
842
- children
843
- }
844
- );
845
- }
846
- const resolvedMinW = minWidth === "trigger" ? Math.max(triggerW, DROPDOWN_MENU_MIN_WIDTH_PX) : minWidth;
847
- return createPortal(
848
- /* @__PURE__ */ jsx(
849
- "div",
850
- {
851
- ...props,
852
- ref: menuRef,
853
- role: "menu",
854
- "aria-orientation": "vertical",
855
- tabIndex: -1,
856
- className: cn(
857
- "bg-background border-primary/8 absolute z-50 rounded-xl border py-1.5 outline-none",
858
- DROPDOWN_PANEL_SHADOW,
859
- DROPDOWN_PANEL_SCROLL,
860
- className,
861
- pos.maxHeight != null ? "overflow-y-auto" : "overflow-hidden"
862
- ),
863
- style: {
864
- position: "absolute",
865
- top: pos.top,
866
- left: pos.left,
867
- minWidth: resolvedMinW,
868
- maxHeight: pos.maxHeight,
869
- transformOrigin: DROPDOWN_CONTENT_ORIGIN[pos.side],
870
- transform: isAnimating ? "none" : DROPDOWN_CONTENT_HIDDEN[pos.side],
871
- opacity: isAnimating ? 1 : 0,
872
- transitionProperty: "opacity, transform",
873
- transitionDuration: `${duration}ms`,
874
- transitionTimingFunction: isAnimating ? DROPDOWN_PANEL_OPEN_EASING : DROPDOWN_PANEL_CLOSE_EASING,
875
- ...style
876
- },
877
- children
878
- }
879
- ),
880
- document.body
881
- );
882
- };
883
- function getItems(menu) {
884
- return Array.from(
885
- menu.querySelectorAll(
886
- '[role="menuitem"]:not([aria-disabled="true"]),[role="menuitemcheckbox"]:not([aria-disabled="true"]),[role="menuitemradio"]:not([aria-disabled="true"])'
887
- )
888
- );
889
- }
890
- var DropdownItem = ({
891
- children,
892
- disabled = false,
893
- destructive = false,
894
- icon,
895
- shortcut,
896
- closeOnSelect = true,
897
- inset = false,
898
- className,
899
- onClick,
900
- ...props
901
- }) => {
902
- const { setOpen } = useDropdown();
903
- const handleClick = (e) => {
904
- if (disabled) return;
905
- onClick?.(e);
906
- if (closeOnSelect) setOpen(false);
200
+ return placeholder || /* @__PURE__ */ jsx(UserIcon, { className: cx("text-fg-quaternary", styles[size].icon) });
907
201
  };
908
- const handleKeyDown = (e) => {
909
- if (e.key === "Enter" || e.key === " ") {
910
- e.preventDefault();
911
- handleClick(e);
202
+ const renderBadgeContent = () => {
203
+ if (status) {
204
+ return /* @__PURE__ */ jsx(AvatarOnlineIndicator, { status, size });
205
+ }
206
+ if (verified) {
207
+ return /* @__PURE__ */ jsx(VerifiedTick, { size, className: cx("absolute right-0 bottom-0", size === "xs" && "-right-px -bottom-px") });
912
208
  }
209
+ if (count) {
210
+ return /* @__PURE__ */ jsx(AvatarCount, { count });
211
+ }
212
+ return badge;
913
213
  };
914
214
  return /* @__PURE__ */ jsxs(
915
215
  "div",
916
216
  {
917
- ...props,
918
- role: "menuitem",
919
- tabIndex: disabled ? void 0 : -1,
920
- "aria-disabled": disabled,
921
- onClick: handleClick,
922
- onKeyDown: handleKeyDown,
923
- className: cn(
924
- "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",
925
- DROPDOWN_SHEET_MENU_TEXT,
926
- inset && "pl-9",
927
- !disabled && "cursor-pointer",
928
- disabled && "lg:cursor-not-allowed",
929
- !disabled && !destructive && "text-foreground hover:bg-primary/8 focus-visible:bg-primary/8 dark:hover:bg-primary/4 dark:focus-visible:bg-primary/4",
930
- !disabled && destructive && "text-destructive hover:bg-destructive/10 focus-visible:bg-destructive/10 dark:text-destructive-foreground dark:hover:bg-destructive-foreground/18 dark:focus-visible:bg-destructive-foreground/18",
931
- disabled && !destructive && "text-foreground/45 dark:text-foreground/50",
932
- disabled && destructive && "bg-destructive/5 text-destructive/75 dark:bg-destructive-foreground/12 dark:text-destructive-foreground/78",
217
+ "data-avatar": true,
218
+ className: cx(
219
+ "relative inline-flex shrink-0 rounded-[7px]",
220
+ rounded && "rounded-full",
221
+ // Focus styles
222
+ focusable && "outline-none group-focus-visible:[box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]",
223
+ border && "ring-1 ring-secondary_alt",
224
+ border && styles[size].rootWithBorder,
225
+ styles[size].root,
933
226
  className
934
227
  ),
935
228
  children: [
936
- icon && /* @__PURE__ */ jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: icon }),
937
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", "data-menu-label": true, children }),
938
- shortcut ? /* @__PURE__ */ jsx(
939
- "span",
229
+ /* @__PURE__ */ jsx(
230
+ "div",
940
231
  {
941
- className: cn(
942
- "ml-auto text-xs tracking-widest",
943
- DROPDOWN_SHEET_MENU_SHORTCUT,
944
- destructive ? "text-destructive/70 dark:text-destructive-foreground/80" : "opacity-40"
232
+ className: cx(
233
+ "relative inline-flex size-full shrink-0 items-center justify-center overflow-hidden rounded-md bg-tertiary outline-[0.5px] -outline-offset-[0.5px] outline-black/16 before:inset-[0.5px]",
234
+ rounded && "rounded-full",
235
+ canShowImage && size !== "xs" && "before:absolute before:inset-0 before:rounded-[inherit] before:border before:border-white/32 before:mask-[linear-gradient(to_bottom,black_0%,transparent_25%,transparent_75%,black_100%)]",
236
+ contentClassName
945
237
  ),
946
- children: shortcut
238
+ children: renderMainContent()
947
239
  }
948
- ) : null
240
+ ),
241
+ renderBadgeContent()
949
242
  ]
950
243
  }
951
244
  );
952
245
  };
953
- var DropdownSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx(
954
- "div",
955
- {
956
- role: "separator",
957
- className: cn("border-primary/10 my-1.5 border-t", className),
958
- ...props
959
- }
960
- );
961
- var DropdownLabel = ({ className, inset, ...props }) => /* @__PURE__ */ jsx(
962
- "div",
963
- {
964
- className: cn(
965
- "text-primary/50 px-4 py-2 text-xs font-medium",
966
- DROPDOWN_SHEET_MENU_LABEL_TEXT,
967
- inset && "pl-9",
968
- className
969
- ),
970
- ...props
971
- }
972
- );
973
- var DropdownCheckboxItem = ({
974
- children,
975
- checked = false,
976
- onCheckedChange,
977
- disabled = false,
978
- shortcut,
979
- closeOnSelect = false,
980
- className,
981
- onClick,
982
- ...props
983
- }) => {
984
- const { setOpen } = useDropdown();
985
- const handleClick = (e) => {
986
- if (disabled) return;
987
- onCheckedChange?.(!checked);
988
- onClick?.(e);
989
- if (closeOnSelect) setOpen(false);
990
- };
991
- const handleKeyDown = (e) => {
992
- if (e.key === "Enter" || e.key === " ") {
993
- e.preventDefault();
994
- handleClick(e);
246
+ var CHECKBOX_TICK_DELAY_MS = 60;
247
+ var CHECKBOX_TICK_DRAW_MS = 100;
248
+ function CheckboxAnimatedCheckMark({ pixelSize, className }) {
249
+ const pathRef = useRef(null);
250
+ useLayoutEffect(() => {
251
+ const path = pathRef.current;
252
+ if (!path || typeof path.getTotalLength !== "function") return;
253
+ const len = path.getTotalLength();
254
+ if (len <= 0) return;
255
+ path.style.strokeDasharray = `${len}`;
256
+ path.style.strokeDashoffset = `${len}`;
257
+ if (typeof path.animate !== "function") {
258
+ path.style.strokeDashoffset = "0";
259
+ return;
995
260
  }
996
- };
261
+ const anim = path.animate([{ strokeDashoffset: len }, { strokeDashoffset: 0 }], {
262
+ duration: CHECKBOX_TICK_DRAW_MS,
263
+ delay: CHECKBOX_TICK_DELAY_MS,
264
+ easing: "cubic-bezier(0.45, 0, 0.2, 1)",
265
+ fill: "forwards"
266
+ });
267
+ return () => anim.cancel();
268
+ }, []);
269
+ return /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", width: pixelSize, height: pixelSize, viewBox: "0 0 14 14", fill: "none", className: cx("block", className), children: /* @__PURE__ */ jsx(
270
+ "path",
271
+ {
272
+ ref: pathRef,
273
+ d: "M2.33325 7L5.24992 9.91667L11.6666 3.5",
274
+ stroke: "currentColor",
275
+ strokeWidth: "2",
276
+ strokeLinecap: "round",
277
+ strokeLinejoin: "round"
278
+ }
279
+ ) });
280
+ }
281
+ var focusRingShadow = "outline-none [box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]";
282
+ var CheckboxBase = ({ className, isSelected, isDisabled, isIndeterminate, size = "sm", isFocusVisible = false }) => {
283
+ const isChecked = isSelected || isIndeterminate;
284
+ const iconPixelSize = size === "sm" ? 10 : 14;
997
285
  return /* @__PURE__ */ jsxs(
998
286
  "div",
999
287
  {
1000
- ...props,
1001
- role: "menuitemcheckbox",
1002
- "aria-checked": checked,
1003
- tabIndex: disabled ? void 0 : -1,
1004
- "aria-disabled": disabled,
1005
- onClick: handleClick,
1006
- onKeyDown: handleKeyDown,
1007
- className: cn(
1008
- "mx-1.5 flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors duration-0 outline-none select-none",
1009
- DROPDOWN_SHEET_MENU_TEXT,
1010
- !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",
1011
- disabled && "lg:cursor-not-allowed text-foreground/45 dark:text-foreground/50",
288
+ className: cx(
289
+ "relative flex shrink-0 cursor-pointer appearance-none items-center justify-center overflow-clip border border-solid border-primary",
290
+ size === "sm" ? "size-4 rounded-xs" : "size-5 rounded-sm",
291
+ isChecked ? "border-transparent bg-brand-solid" : "bg-primary",
292
+ !isChecked && !isDisabled && "group-hover:bg-primary_hover",
293
+ isDisabled && "cursor-not-allowed opacity-50",
294
+ isDisabled && !isChecked && "bg-tertiary",
295
+ isFocusVisible && !isDisabled && focusRingShadow,
1012
296
  className
1013
297
  ),
1014
298
  children: [
1015
- /* @__PURE__ */ jsx("span", { className: "mr-1 inline-flex shrink-0", "aria-hidden": true, children: /* @__PURE__ */ jsx(
1016
- Checkbox,
299
+ isIndeterminate && /* @__PURE__ */ jsx(
300
+ "svg",
1017
301
  {
1018
- checked,
1019
- disabled,
1020
- tabIndex: -1,
1021
- className: "pointer-events-none"
1022
- }
1023
- ) }),
1024
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", "data-menu-label": true, children }),
1025
- shortcut && /* @__PURE__ */ jsx(
1026
- "span",
1027
- {
1028
- className: cn(
1029
- "ml-auto text-xs tracking-widest opacity-40",
1030
- DROPDOWN_SHEET_MENU_SHORTCUT
1031
- ),
1032
- children: shortcut
302
+ "aria-hidden": "true",
303
+ width: iconPixelSize,
304
+ height: iconPixelSize,
305
+ viewBox: "0 0 14 14",
306
+ fill: "none",
307
+ className: "pointer-events-none block text-fg-white",
308
+ children: /* @__PURE__ */ jsx("path", { d: "M2.91675 7H11.0834", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
1033
309
  }
1034
- )
310
+ ),
311
+ isSelected && !isIndeterminate && /* @__PURE__ */ jsx(CheckboxAnimatedCheckMark, { pixelSize: iconPixelSize, className: "pointer-events-none text-fg-white" })
1035
312
  ]
1036
313
  }
1037
314
  );
1038
315
  };
1039
- var DropdownRadioGroup = ({ children, value, onValueChange, group }) => {
1040
- const { setRadioValue, radioValues } = useDropdown();
1041
- const resolvedValue = value ?? radioValues[group] ?? "";
1042
- const handleValueChange = useCallback(
1043
- (v) => {
1044
- setRadioValue(group, v);
1045
- onValueChange?.(v);
1046
- },
1047
- [group, onValueChange, setRadioValue]
1048
- );
1049
- const radioCtx = useMemo(
1050
- () => ({
1051
- group,
1052
- value: resolvedValue,
1053
- onValueChange: handleValueChange
1054
- }),
1055
- [group, resolvedValue, handleValueChange]
316
+ CheckboxBase.displayName = "CheckboxBase";
317
+ var RADIO_DOT_DELAY_MS = 60;
318
+ var RADIO_DOT_POP_MS = 100;
319
+ function RadioAnimatedDot({ className }) {
320
+ const dotRef = useRef(null);
321
+ useLayoutEffect(() => {
322
+ const dot = dotRef.current;
323
+ if (!dot) return;
324
+ if (typeof dot.animate !== "function") {
325
+ dot.style.opacity = "1";
326
+ dot.style.transform = "scale(1)";
327
+ return;
328
+ }
329
+ const anim = dot.animate(
330
+ [
331
+ { opacity: 0, transform: "scale(0)" },
332
+ { opacity: 1, transform: "scale(1)" }
333
+ ],
334
+ {
335
+ duration: RADIO_DOT_POP_MS,
336
+ delay: RADIO_DOT_DELAY_MS,
337
+ easing: "cubic-bezier(0.45, 0, 0.2, 1)",
338
+ fill: "forwards"
339
+ }
340
+ );
341
+ return () => anim.cancel();
342
+ }, []);
343
+ return /* @__PURE__ */ jsx("div", { ref: dotRef, "aria-hidden": "true", className: cx("rounded-full bg-fg-white", className), style: { opacity: 0, transform: "scale(0)" } });
344
+ }
345
+ var focusRingShadow2 = "outline-none [box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]";
346
+ createContext(null);
347
+ var RadioButtonBase = ({ className, isFocusVisible, isSelected, isDisabled, size = "sm" }) => {
348
+ const dotClassName = size === "sm" ? "size-1.5" : "size-2";
349
+ return /* @__PURE__ */ jsx(
350
+ "div",
351
+ {
352
+ className: cx(
353
+ "relative flex shrink-0 cursor-pointer appearance-none items-center justify-center overflow-clip rounded-full border border-solid border-primary bg-primary",
354
+ size === "sm" ? "size-4" : "size-5",
355
+ isSelected && "border-transparent bg-brand-solid",
356
+ !isSelected && !isDisabled && "group-hover:bg-primary_hover",
357
+ isDisabled && "cursor-not-allowed opacity-50",
358
+ isDisabled && !isSelected && "bg-tertiary",
359
+ isFocusVisible && !isDisabled && focusRingShadow2,
360
+ className
361
+ ),
362
+ children: isSelected && /* @__PURE__ */ jsx(RadioAnimatedDot, { className: cx("pointer-events-none", dotClassName) })
363
+ }
1056
364
  );
1057
- return /* @__PURE__ */ jsx(RadioGroupContext.Provider, { value: radioCtx, children });
1058
365
  };
1059
- var RadioGroupContext = React3__default.createContext(
1060
- void 0
1061
- );
1062
- function useRadioGroup() {
1063
- const ctx = React3__default.useContext(RadioGroupContext);
1064
- if (!ctx)
1065
- throw new Error("DropdownRadioItem must be inside DropdownRadioGroup");
1066
- return ctx;
1067
- }
1068
- var DropdownRadioItem = ({
1069
- children,
1070
- value,
1071
- disabled = false,
1072
- shortcut,
1073
- closeOnSelect = false,
1074
- className,
1075
- onClick,
1076
- ...props
1077
- }) => {
1078
- const { setOpen } = useDropdown();
1079
- const { value: groupValue, onValueChange } = useRadioGroup();
1080
- const checked = groupValue === value;
1081
- const handleClick = (e) => {
1082
- if (disabled) return;
1083
- onValueChange(value);
1084
- onClick?.(e);
1085
- if (closeOnSelect) setOpen(false);
1086
- };
1087
- const handleKeyDown = (e) => {
1088
- if (e.key === "Enter" || e.key === " ") {
1089
- e.preventDefault();
1090
- handleClick(e);
366
+ RadioButtonBase.displayName = "RadioButtonBase";
367
+ var focusRingShadow3 = "outline-none [box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]";
368
+ var ToggleBase = ({ className, isHovered, isDisabled, isFocusVisible, isSelected, slim, size = "sm" }) => {
369
+ const styles2 = {
370
+ default: {
371
+ sm: {
372
+ track: "h-5 w-9 p-0.5",
373
+ thumb: "size-4",
374
+ thumbPosition: isSelected ? "left-[calc(100%-1rem-0.125rem)]" : "left-0.5"
375
+ },
376
+ md: {
377
+ track: "h-6 w-11 p-0.5",
378
+ thumb: "size-5",
379
+ thumbPosition: isSelected ? "left-[calc(100%-1.25rem-0.125rem)]" : "left-0.5"
380
+ }
381
+ },
382
+ slim: {
383
+ sm: {
384
+ track: "h-4 w-8",
385
+ thumb: "size-4",
386
+ thumbPosition: isSelected ? "left-4" : "left-0"
387
+ },
388
+ md: {
389
+ track: "h-5 w-10",
390
+ thumb: "size-5",
391
+ thumbPosition: isSelected ? "left-5" : "left-0"
392
+ }
1091
393
  }
1092
394
  };
1093
- return /* @__PURE__ */ jsxs(
395
+ const classes = slim ? styles2.slim[size] : styles2.default[size];
396
+ const offTrackBackground = (() => {
397
+ if (isDisabled) return "bg-tertiary";
398
+ if (isHovered) return "bg-secondary_hover";
399
+ return "bg-quaternary";
400
+ })();
401
+ return /* @__PURE__ */ jsx(
1094
402
  "div",
1095
403
  {
1096
- ...props,
1097
- role: "menuitemradio",
1098
- "aria-checked": checked,
1099
- tabIndex: disabled ? void 0 : -1,
1100
- "aria-disabled": disabled,
1101
- onClick: handleClick,
1102
- onKeyDown: handleKeyDown,
1103
- className: cn(
1104
- "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",
1105
- DROPDOWN_SHEET_MENU_TEXT,
1106
- !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",
1107
- disabled && "lg:cursor-not-allowed text-foreground/45 dark:text-foreground/50",
404
+ className: cx(
405
+ "relative inline-flex shrink-0 cursor-pointer overflow-clip rounded-full outline-none transition duration-150 ease-linear",
406
+ !isSelected && offTrackBackground,
407
+ !slim && "ring-[0.5px] ring-secondary ring-inset",
408
+ slim && "ring-1 ring-secondary ring-inset",
409
+ isSelected && "bg-brand-solid",
410
+ isSelected && isHovered && "bg-brand-solid_hover",
411
+ isSelected && "ring-transparent",
412
+ isDisabled && "cursor-not-allowed opacity-50",
413
+ isFocusVisible && !isDisabled && focusRingShadow3,
414
+ classes.track,
1108
415
  className
1109
416
  ),
1110
- children: [
1111
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", "data-menu-label": true, children }),
1112
- shortcut ? /* @__PURE__ */ jsx(
1113
- "span",
417
+ children: /* @__PURE__ */ jsx(
418
+ "div",
419
+ {
420
+ className: cx(
421
+ "absolute rounded-full bg-fg-white shadow-sm transition-[left] duration-150 ease-in-out",
422
+ slim ? "top-0 shadow-xs" : "top-0.5",
423
+ slim && "border border-toggle-border",
424
+ slim && isSelected && "border-toggle-slim-border_pressed",
425
+ slim && isSelected && isHovered && "border-toggle-slim-border_pressed-hover",
426
+ classes.thumb,
427
+ classes.thumbPosition
428
+ )
429
+ }
430
+ )
431
+ }
432
+ );
433
+ };
434
+ var focusShadowPlain = "focus-visible:outline-none focus-visible:[box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]";
435
+ var focusShadowInset = "[box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]";
436
+ var DropdownItem = ({ label, children, addon, icon: Icon, avatarUrl, unstyled, selectionIndicator = "checkmark", ...props }) => {
437
+ const SelectionIndicator = useCallback(
438
+ (state) => {
439
+ if (selectionIndicator === "checkmark") {
440
+ return /* @__PURE__ */ jsx(
441
+ CheckIcon,
1114
442
  {
1115
- className: cn(
1116
- "shrink-0 text-xs tracking-widest opacity-40",
1117
- DROPDOWN_SHEET_MENU_SHORTCUT
1118
- ),
1119
- children: shortcut
443
+ "aria-hidden": "true",
444
+ className: cx("size-4 shrink-0 stroke-[2.25px] text-fg-brand-primary", !state.isSelected && "invisible", state.className)
1120
445
  }
1121
- ) : null,
1122
- /* @__PURE__ */ jsx(
1123
- "span",
446
+ );
447
+ }
448
+ if (selectionIndicator === "checkbox") {
449
+ return /* @__PURE__ */ jsx(
450
+ CheckboxBase,
1124
451
  {
1125
- className: "flex size-4 shrink-0 items-center justify-center",
1126
- "aria-hidden": true,
1127
- children: checked ? /* @__PURE__ */ jsx(Check, { className: "size-3.5", strokeWidth: 2.5 }) : null
452
+ isSelected: state.isSelected && !state.hasSubmenu,
453
+ isIndeterminate: state.isSelected && state.hasSubmenu,
454
+ size: "sm",
455
+ className: cx("shrink-0", state.className)
1128
456
  }
1129
- )
1130
- ]
457
+ );
458
+ }
459
+ if (selectionIndicator === "radio") {
460
+ return /* @__PURE__ */ jsx(RadioButtonBase, { isSelected: state.isSelected, className: cx("shrink-0", state.className) });
461
+ }
462
+ if (selectionIndicator === "toggle") {
463
+ return /* @__PURE__ */ jsx(ToggleBase, { slim: true, size: "sm", isSelected: state.isSelected, className: cx("shrink-0", state.className) });
464
+ }
465
+ return null;
466
+ },
467
+ [selectionIndicator]
468
+ );
469
+ if (unstyled) {
470
+ return /* @__PURE__ */ jsx(MenuItem, { id: label, textValue: label, ...props });
471
+ }
472
+ return /* @__PURE__ */ jsx(
473
+ MenuItem,
474
+ {
475
+ ...props,
476
+ className: (state) => cx(
477
+ "group block cursor-pointer px-1.5 py-px outline-hidden",
478
+ state.isDisabled && "cursor-not-allowed opacity-50",
479
+ typeof props.className === "function" ? props.className(state) : props.className
480
+ ),
481
+ children: (state) => /* @__PURE__ */ jsxs(
482
+ "div",
483
+ {
484
+ className: cx(
485
+ "relative flex items-center rounded-md px-2.5 py-2 transition duration-100 ease-linear",
486
+ !state.isDisabled && "group-hover:bg-primary_hover",
487
+ state.isFocused && "bg-primary_hover",
488
+ state.isFocusVisible && focusShadowInset,
489
+ state.hasSubmenu && "pr-1.5"
490
+ ),
491
+ children: [
492
+ state.selectionMode !== "none" && !avatarUrl && !Icon && /* @__PURE__ */ jsx(SelectionIndicator, { ...state, className: "mr-2" }),
493
+ avatarUrl && /* @__PURE__ */ jsx("div", { className: "mr-2 flex size-4 items-center justify-center", children: /* @__PURE__ */ jsx(Avatar, { "aria-hidden": "true", size: "xs", src: avatarUrl, alt: label, className: "size-5" }) }),
494
+ Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true", className: "mr-2 size-4 shrink-0 stroke-[2.25px] text-fg-quaternary" }),
495
+ /* @__PURE__ */ jsx("span", { className: cx("grow truncate text-sm font-semibold text-secondary", state.isFocused && "text-secondary_hover"), children: label || (typeof children === "function" ? children(state) : children) }),
496
+ addon && /* @__PURE__ */ jsx("span", { className: "ml-1 shrink-0 pr-1 text-xs font-medium text-quaternary", children: addon }),
497
+ state.selectionMode !== "none" && (avatarUrl || Icon) && /* @__PURE__ */ jsx(SelectionIndicator, { ...state, className: "ml-1" }),
498
+ state.hasSubmenu && /* @__PURE__ */ jsx(CaretRightIcon, { "aria-hidden": "true", className: "ml-auto size-4 shrink-0 stroke-[2.25px] text-fg-quaternary" })
499
+ ]
500
+ }
501
+ )
1131
502
  }
1132
503
  );
1133
504
  };
1134
- var DropdownSub = ({ children, openOnHover = true }) => {
1135
- const [open, setOpen] = useState(false);
1136
- const triggerRef = useRef(null);
1137
- const subCtx = useMemo(
1138
- () => ({ open, setOpen, triggerRef, openOnHover }),
1139
- [open, setOpen, openOnHover]
505
+ var DropdownMenu = (props) => {
506
+ return /* @__PURE__ */ jsx(
507
+ Menu,
508
+ {
509
+ ...props,
510
+ className: (state) => cx("h-min overflow-y-auto py-1 outline-hidden select-none", typeof props.className === "function" ? props.className(state) : props.className)
511
+ }
1140
512
  );
1141
- return /* @__PURE__ */ jsx(SubContext.Provider, { value: subCtx, children });
1142
513
  };
1143
- var DropdownSubTrigger = ({ children, icon, inset, disabled = false, className, ...props }) => {
1144
- const sub = React3__default.useContext(SubContext);
1145
- if (!sub) throw new Error("DropdownSubTrigger must be inside DropdownSub");
1146
- const { open, setOpen, triggerRef, openOnHover } = sub;
1147
- const isMobile = useIsMobile(DROPDOWN_MOBILE_SHEET_MAX_PX + 1);
514
+ var DropdownSheetDepthContext = createContext(0);
515
+ function DropdownSheetCloseButton({ onClose }) {
1148
516
  return /* @__PURE__ */ jsxs(
1149
- "div",
517
+ "button",
1150
518
  {
1151
- ...props,
1152
- ref: (el) => {
1153
- triggerRef.current = el;
1154
- },
1155
- role: "menuitem",
1156
- "aria-haspopup": "menu",
1157
- "aria-expanded": open,
1158
- tabIndex: disabled ? void 0 : -1,
1159
- "aria-disabled": disabled,
1160
- onMouseEnter: () => {
1161
- if (disabled || isMobile || !openOnHover) return;
1162
- setOpen(true);
1163
- },
1164
- onMouseLeave: () => {
1165
- if (isMobile || !openOnHover) return;
1166
- setOpen(false);
1167
- },
1168
- onKeyDown: (e) => {
1169
- if (disabled) return;
1170
- if (e.key === "ArrowRight" || e.key === "Enter") {
1171
- e.preventDefault();
1172
- setOpen(true);
1173
- }
1174
- },
1175
- onClick: () => {
1176
- if (disabled) return;
1177
- setOpen(!open);
519
+ type: "button",
520
+ onClick: (e) => {
521
+ e.stopPropagation();
522
+ onClose();
1178
523
  },
1179
- className: cn(
1180
- "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",
1181
- DROPDOWN_SHEET_MENU_TEXT,
1182
- inset && "pl-9",
1183
- !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",
1184
- disabled && "lg:cursor-not-allowed text-foreground/45 dark:text-foreground/50",
1185
- className
1186
- ),
524
+ className: "flex size-12 shrink-0 cursor-pointer items-center justify-center rounded-full text-fg-primary transition duration-100 ease-linear hover:bg-primary_hover active:scale-[0.96] focus-visible:outline-none focus-visible:[box-shadow:0px_0px_0px_2px_var(--color-bg-primary),0px_0px_0px_4px_var(--color-focus-ring)]",
1187
525
  children: [
1188
- icon && /* @__PURE__ */ jsx("span", { className: "flex size-4 shrink-0 items-center justify-center", children: icon }),
1189
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", "data-menu-label": true, children }),
1190
- /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto size-4 shrink-0 opacity-50" })
526
+ /* @__PURE__ */ jsx(XIcon, { className: "size-5", "aria-hidden": "true" }),
527
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1191
528
  ]
1192
529
  }
1193
530
  );
1194
- };
1195
- var DropdownSubContent = ({
1196
- children,
1197
- duration = 80,
1198
- viewportPadding = 8,
1199
- mobileOptions,
1200
- slideEntrance = true,
1201
- slideEntranceOffsetPx: slideEntranceOffsetPxProp,
1202
- typeahead = true,
1203
- className,
1204
- style,
1205
- onKeyDown: onKeyDownProp,
1206
- ...props
1207
- }) => {
1208
- const sub = React3__default.useContext(SubContext);
1209
- if (!sub) throw new Error("DropdownSubContent must be inside DropdownSub");
1210
- const { open, setOpen, triggerRef, openOnHover } = sub;
1211
- const isMobile = useIsMobile(DROPDOWN_MOBILE_SHEET_MAX_PX + 1);
1212
- const resolvedMobile = resolveDropdownMobileSheet(mobileOptions);
1213
- const isMobileSheet = isMobile && resolvedMobile.sheet;
1214
- const slideOffsetPx = slideEntranceOffsetPxProp ?? DROPDOWN_MOBILE_SHEET_SLIDE_ENTRANCE_OFFSET_DEFAULT_PX;
1215
- const [shouldRender, setShouldRender] = useState(false);
1216
- const [isAnimating, setIsAnimating] = useState(false);
1217
- const [pos, setPos] = useState({
1218
- top: -9999,
1219
- left: -9999,
1220
- side: "right"
1221
- });
1222
- const menuRef = useRef(null);
1223
- const typeaheadStateRef = useRef(createTypeaheadState());
1224
- useEffect(() => {
1225
- if (open) {
1226
- setShouldRender(true);
1227
- return;
1228
- }
1229
- if (!isMobileSheet) {
1230
- setShouldRender(false);
1231
- return;
1232
- }
1233
- setIsAnimating(false);
1234
- const t = setTimeout(
1235
- () => setShouldRender(false),
1236
- DROPDOWN_MOBILE_SHEET_MOTION_MS
1237
- );
1238
- return () => clearTimeout(t);
1239
- }, [open, isMobileSheet]);
531
+ }
532
+ function DropdownSheetChrome({ title, onClose, children }) {
533
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
534
+ /* @__PURE__ */ jsxs("div", { className: cx("flex w-full shrink-0 items-center py-2 pl-4 pr-2", title ? "justify-between gap-3" : "justify-end"), children: [
535
+ title ? /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 truncate text-base font-semibold text-primary", children: title }) : null,
536
+ /* @__PURE__ */ jsx(DropdownSheetCloseButton, { onClose })
537
+ ] }),
538
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto pb-[max(2.5rem,calc(env(safe-area-inset-bottom)+2rem))]", children })
539
+ ] });
540
+ }
541
+ var DropdownPopover = ({ mobileOptions, children, className, style, ...props }) => {
542
+ const isMobile = useIsMobile();
543
+ const resolvedMobile = useMemo(() => resolveSelectMobileOptions(mobileOptions), [mobileOptions]);
544
+ const useMobileSheet = isMobile && resolvedMobile.sheet;
545
+ const overlayState = useContext(OverlayTriggerStateContext);
546
+ const open = overlayState?.isOpen ?? false;
547
+ const parentDepth = useContext(DropdownSheetDepthContext);
548
+ const depth = parentDepth + 1;
549
+ const { shouldRender, panelStyle, backdropStyle } = useMobileSheetAnimation(open, useMobileSheet);
1240
550
  useEffect(() => {
1241
- if (!shouldRender || !open) return;
1242
- let raf2 = 0;
1243
- const raf1 = requestAnimationFrame(() => {
1244
- raf2 = requestAnimationFrame(() => setIsAnimating(true));
1245
- });
1246
- return () => {
1247
- cancelAnimationFrame(raf1);
1248
- if (raf2) cancelAnimationFrame(raf2);
1249
- };
1250
- }, [shouldRender, open]);
1251
- useLayoutEffect(() => {
1252
- if (!shouldRender || isMobileSheet) return;
1253
- if (!triggerRef.current || !menuRef.current) return;
1254
- const update = () => {
1255
- if (!triggerRef.current || !menuRef.current) return;
1256
- setPos(
1257
- computePos(
1258
- triggerRef.current,
1259
- menuRef.current,
1260
- "right",
1261
- "start",
1262
- -8,
1263
- viewportPadding
1264
- )
1265
- );
1266
- };
1267
- update();
1268
- window.addEventListener("resize", update);
551
+ if (!useMobileSheet || !open) return;
552
+ const prev = document.body.style.overflow;
553
+ document.body.style.overflow = "hidden";
1269
554
  return () => {
1270
- window.removeEventListener("resize", update);
1271
- };
1272
- }, [shouldRender, viewportPadding, isMobileSheet]);
1273
- useEffect(() => {
1274
- if (!open || isMobileSheet) return;
1275
- const onScroll = (e) => {
1276
- const t = e.target;
1277
- if (!(t instanceof Node) || menuRef.current?.contains(t)) return;
1278
- const trigger = triggerRef.current;
1279
- if (trigger && (t === trigger || t.contains(trigger))) setOpen(false);
1280
- };
1281
- window.addEventListener("scroll", onScroll, true);
1282
- return () => window.removeEventListener("scroll", onScroll, true);
1283
- }, [open, isMobileSheet, setOpen, triggerRef]);
1284
- useEffect(() => {
1285
- if (!shouldRender || isMobileSheet) return;
1286
- const menu = menuRef.current;
1287
- if (!menu) return;
1288
- const onWheel = (e) => preventMenuWheelChain(menu, e);
1289
- menu.addEventListener("wheel", onWheel, { passive: false });
1290
- return () => menu.removeEventListener("wheel", onWheel);
1291
- }, [shouldRender, isMobileSheet]);
1292
- useEffect(() => {
1293
- if (isAnimating && menuRef.current) {
1294
- menuRef.current.focus();
1295
- }
1296
- }, [isAnimating]);
1297
- useEffect(() => {
1298
- if (!open) resetTypeahead(typeaheadStateRef.current);
1299
- }, [open]);
1300
- useEffect(() => {
1301
- if (!open) return;
1302
- const handler = (e) => {
1303
- const t = e.target;
1304
- if (menuRef.current?.contains(t) || triggerRef.current?.contains(t))
1305
- return;
1306
- const el = e.target instanceof Element ? e.target : null;
1307
- const subPanel = el?.closest?.(`[${DROPDOWN_SUB_CONTENT_ATTR}]`);
1308
- if (subPanel && subPanel !== menuRef.current) return;
1309
- setOpen(false);
555
+ document.body.style.overflow = prev;
1310
556
  };
1311
- document.addEventListener("mousedown", handler);
1312
- return () => document.removeEventListener("mousedown", handler);
1313
- }, [open, setOpen, triggerRef]);
1314
- const handleSubMenuKeyDown = useCallback(
1315
- (e) => {
1316
- onKeyDownProp?.(e);
1317
- if (e.defaultPrevented) return;
1318
- const menu = menuRef.current;
1319
- if (!menu) return;
1320
- const items = getItems(menu);
1321
- const focused = document.activeElement;
1322
- const idx = items.indexOf(focused);
1323
- switch (e.key) {
1324
- case "ArrowLeft":
1325
- case "Escape":
1326
- e.preventDefault();
1327
- setOpen(false);
1328
- triggerRef.current?.focus();
1329
- break;
1330
- case "ArrowDown":
1331
- e.preventDefault();
1332
- if (items.length === 0) break;
1333
- if (idx === -1 || idx === items.length - 1) items[0]?.focus();
1334
- else items[idx + 1]?.focus();
1335
- break;
1336
- case "ArrowUp":
1337
- e.preventDefault();
1338
- if (items.length === 0) break;
1339
- if (idx <= 0) items[items.length - 1]?.focus();
1340
- else items[idx - 1]?.focus();
1341
- break;
1342
- case "Home":
1343
- e.preventDefault();
1344
- items[0]?.focus();
1345
- break;
1346
- case "End":
1347
- e.preventDefault();
1348
- items[items.length - 1]?.focus();
1349
- break;
1350
- default:
1351
- handleTypeaheadKeyDown(e.nativeEvent, items, typeaheadStateRef.current, {
1352
- enabled: typeahead
1353
- });
1354
- break;
1355
- }
1356
- },
1357
- [onKeyDownProp, setOpen, triggerRef, typeahead]
1358
- );
1359
- if (!shouldRender || typeof document === "undefined") return null;
1360
- if (isMobileSheet) {
557
+ }, [useMobileSheet, open]);
558
+ if (!useMobileSheet) {
1361
559
  return /* @__PURE__ */ jsx(
1362
- DropdownMobileBottomSheetPortal,
560
+ Popover,
1363
561
  {
562
+ placement: "bottom right",
1364
563
  ...props,
1365
- open,
1366
- isAnimating,
1367
- slideEntrance,
1368
- slideOffsetPx,
1369
- sheetTitle: resolvedMobile.title,
1370
- sheetExtraClassName: resolvedMobile.sheetExtraClassName,
1371
- contentClassName: resolvedMobile.contentClassName,
1372
- onRequestClose: () => setOpen(false),
1373
- menuRef,
1374
- portalZClassName: "z-[70]",
1375
- isSubPortal: true,
1376
- className,
1377
564
  style,
1378
- role: "menu",
1379
- tabIndex: -1,
1380
- onKeyDown: handleSubMenuKeyDown,
1381
- "data-dropdown-sub-content": "",
565
+ className: (state) => cx(
566
+ "w-62 origin-(--trigger-anchor-point) overflow-auto rounded-lg bg-primary shadow-lg ring-1 ring-secondary_alt will-change-transform",
567
+ state.isEntering && "duration-150 ease-out animate-in fade-in placement-right:slide-in-from-left-0.5 placement-top:slide-in-from-bottom-0.5 placement-bottom:slide-in-from-top-0.5",
568
+ state.isExiting && "duration-100 ease-in animate-out fade-out placement-right:slide-out-to-left-0.5 placement-top:slide-out-to-bottom-0.5 placement-bottom:slide-out-to-top-0.5",
569
+ typeof className === "function" ? className(state) : className
570
+ ),
1382
571
  children
1383
572
  }
1384
573
  );
1385
574
  }
1386
- return createPortal(
575
+ const close = () => overlayState?.close();
576
+ const showMobileSheet = shouldRender;
577
+ const isMobileSheetExiting = showMobileSheet && !open;
578
+ const scrimZIndex = 50 + (depth - 1) * 10;
579
+ const sheetZIndex = scrimZIndex + 1;
580
+ const mobileScrim = shouldRender && typeof document !== "undefined" ? createPortal(
1387
581
  /* @__PURE__ */ jsx(
1388
582
  "div",
1389
583
  {
1390
- ...props,
1391
- ref: menuRef,
1392
- role: "menu",
1393
- tabIndex: -1,
1394
- onMouseEnter: openOnHover ? () => setOpen(true) : void 0,
1395
- onMouseLeave: openOnHover ? () => setOpen(false) : void 0,
1396
- onKeyDown: handleSubMenuKeyDown,
1397
- "data-dropdown-sub-content": "",
1398
- className: cn(
1399
- "bg-background border-primary/8 absolute z-60 rounded-xl border py-1.5 outline-none",
1400
- DROPDOWN_PANEL_SHADOW,
1401
- DROPDOWN_PANEL_SCROLL,
1402
- className,
1403
- pos.maxHeight != null ? "overflow-y-auto" : "overflow-hidden"
1404
- ),
1405
- style: {
1406
- position: "absolute",
1407
- top: pos.top,
1408
- left: pos.left,
1409
- minWidth: DROPDOWN_MENU_MIN_WIDTH_PX,
1410
- maxHeight: pos.maxHeight,
1411
- transformOrigin: SUB_CONTENT_ORIGIN[pos.side],
1412
- transform: isAnimating ? "none" : DROPDOWN_CONTENT_HIDDEN[pos.side],
1413
- opacity: isAnimating ? 1 : 0,
1414
- transitionProperty: "opacity, transform",
1415
- transitionDuration: `${duration}ms`,
1416
- transitionTimingFunction: isAnimating ? DROPDOWN_PANEL_OPEN_EASING : DROPDOWN_PANEL_CLOSE_EASING,
1417
- ...style
1418
- },
1419
- children
584
+ className: "fixed inset-0 bg-overlay/70",
585
+ style: { ...backdropStyle, zIndex: scrimZIndex },
586
+ onClick: close,
587
+ "aria-hidden": "true"
1420
588
  }
1421
589
  ),
1422
590
  document.body
591
+ ) : null;
592
+ return /* @__PURE__ */ jsxs(DropdownSheetDepthContext.Provider, { value: depth, children: [
593
+ mobileScrim,
594
+ /* @__PURE__ */ jsx(
595
+ Popover,
596
+ {
597
+ placement: "bottom",
598
+ containerPadding: 0,
599
+ offset: 0,
600
+ ...props,
601
+ isExiting: isMobileSheetExiting,
602
+ "data-dropdown-mobile-sheet": true,
603
+ style: { ...panelStyle, zIndex: sheetZIndex, ...style },
604
+ className: (state) => cx(
605
+ "fixed! inset-x-0! bottom-0! top-auto! right-0! left-0! flex max-h-[min(90dvh,calc(100dvh-env(safe-area-inset-bottom,0px)))] w-full! max-w-none! flex-col overflow-hidden rounded-t-2xl rounded-b-none border-x-0 border-t border-secondary bg-primary shadow-xl outline-hidden",
606
+ resolvedMobile.sheetClassName,
607
+ typeof className === "function" ? className(state) : className
608
+ ),
609
+ children: /* @__PURE__ */ jsx(DropdownSheetChrome, { title: resolvedMobile.title, onClose: close, children: typeof children === "function" ? null : children })
610
+ }
611
+ )
612
+ ] });
613
+ };
614
+ var DropdownSeparator = (props) => {
615
+ return /* @__PURE__ */ jsx(Separator, { ...props, className: cx("my-1 h-px w-full bg-border-secondary", props.className) });
616
+ };
617
+ var DropdownDotsButton = (props) => {
618
+ return /* @__PURE__ */ jsx(
619
+ Button,
620
+ {
621
+ ...props,
622
+ "aria-label": "Open menu",
623
+ className: (state) => cx(
624
+ "cursor-pointer rounded-md text-fg-quaternary transition duration-100 ease-linear",
625
+ (state.isPressed || state.isHovered) && "text-fg-quaternary_hover",
626
+ focusShadowPlain,
627
+ typeof props.className === "function" ? props.className(state) : props.className
628
+ ),
629
+ children: /* @__PURE__ */ jsx(DotsThreeVerticalIcon, { className: "size-5 transition-inherit-all" })
630
+ }
1423
631
  );
1424
632
  };
633
+ var Dropdown = {
634
+ Root: MenuTrigger,
635
+ Popover: DropdownPopover,
636
+ Menu: DropdownMenu,
637
+ Section: MenuSection,
638
+ SectionHeader: Header,
639
+ Item: DropdownItem,
640
+ Separator: DropdownSeparator,
641
+ DotsButton: DropdownDotsButton
642
+ };
1425
643
 
1426
- export { Dropdown, DropdownCheckboxItem, DropdownChevron, DropdownContent, DropdownItem, DropdownLabel, DropdownMobileClose, DropdownRadioGroup, DropdownRadioItem, DropdownSeparator, DropdownSub, DropdownSubContent, DropdownSubTrigger, DropdownTrigger };
644
+ export { Dropdown };
1427
645
  //# sourceMappingURL=dropdown.js.map
1428
646
  //# sourceMappingURL=dropdown.js.map