@tribepad/themis 1.0.1 → 1.0.3

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 (308) hide show
  1. package/dist/elements/Accordion/index.js +1 -335
  2. package/dist/elements/Accordion/index.js.map +1 -1
  3. package/dist/elements/Accordion/index.mjs +1 -317
  4. package/dist/elements/Accordion/index.mjs.map +1 -1
  5. package/dist/elements/AlertDialog/AlertDialog.d.ts +43 -0
  6. package/dist/elements/AlertDialog/AlertDialog.d.ts.map +1 -0
  7. package/dist/elements/AlertDialog/AlertDialog.styles.d.ts +15 -0
  8. package/dist/elements/AlertDialog/AlertDialog.styles.d.ts.map +1 -0
  9. package/dist/elements/AlertDialog/AlertDialog.types.d.ts +72 -0
  10. package/dist/elements/AlertDialog/AlertDialog.types.d.ts.map +1 -0
  11. package/dist/elements/AlertDialog/index.d.ts +25 -0
  12. package/dist/elements/AlertDialog/index.d.ts.map +1 -0
  13. package/dist/elements/AlertDialog/index.js +3 -0
  14. package/dist/elements/AlertDialog/index.js.map +1 -0
  15. package/dist/elements/AlertDialog/index.mjs +3 -0
  16. package/dist/elements/AlertDialog/index.mjs.map +1 -0
  17. package/dist/elements/Avatar/index.js +1 -468
  18. package/dist/elements/Avatar/index.js.map +1 -1
  19. package/dist/elements/Avatar/index.mjs +1 -456
  20. package/dist/elements/Avatar/index.mjs.map +1 -1
  21. package/dist/elements/Badge/index.js +1 -243
  22. package/dist/elements/Badge/index.js.map +1 -1
  23. package/dist/elements/Badge/index.mjs +1 -234
  24. package/dist/elements/Badge/index.mjs.map +1 -1
  25. package/dist/elements/Breadcrumbs/index.js +1 -821
  26. package/dist/elements/Breadcrumbs/index.js.map +1 -1
  27. package/dist/elements/Breadcrumbs/index.mjs +1 -810
  28. package/dist/elements/Breadcrumbs/index.mjs.map +1 -1
  29. package/dist/elements/Button/Button.d.ts +26 -81
  30. package/dist/elements/Button/Button.d.ts.map +1 -1
  31. package/dist/elements/Button/Button.styles.d.ts +35 -0
  32. package/dist/elements/Button/Button.styles.d.ts.map +1 -0
  33. package/dist/elements/Button/Button.types.d.ts +20 -8
  34. package/dist/elements/Button/Button.types.d.ts.map +1 -1
  35. package/dist/elements/Button/index.js +1 -288
  36. package/dist/elements/Button/index.js.map +1 -1
  37. package/dist/elements/Button/index.mjs +1 -283
  38. package/dist/elements/Button/index.mjs.map +1 -1
  39. package/dist/elements/ButtonGroup/index.js +1 -237
  40. package/dist/elements/ButtonGroup/index.js.map +1 -1
  41. package/dist/elements/ButtonGroup/index.mjs +1 -222
  42. package/dist/elements/ButtonGroup/index.mjs.map +1 -1
  43. package/dist/elements/Card/index.js +1 -579
  44. package/dist/elements/Card/index.js.map +1 -1
  45. package/dist/elements/Card/index.mjs +1 -560
  46. package/dist/elements/Card/index.mjs.map +1 -1
  47. package/dist/elements/Carousel/Carousel.d.ts +1 -11
  48. package/dist/elements/Carousel/Carousel.d.ts.map +1 -1
  49. package/dist/elements/Carousel/LazyCarousel.d.ts +1 -1
  50. package/dist/elements/Carousel/LazyCarousel.d.ts.map +1 -1
  51. package/dist/elements/Carousel/index.js +1 -789
  52. package/dist/elements/Carousel/index.js.map +1 -1
  53. package/dist/elements/Carousel/index.mjs +1 -786
  54. package/dist/elements/Carousel/index.mjs.map +1 -1
  55. package/dist/elements/Chart/ChartContext.d.ts.map +1 -1
  56. package/dist/elements/Chart/index.js +1 -1842
  57. package/dist/elements/Chart/index.js.map +1 -1
  58. package/dist/elements/Chart/index.mjs +1 -1832
  59. package/dist/elements/Chart/index.mjs.map +1 -1
  60. package/dist/elements/Checkbox/index.js +1 -316
  61. package/dist/elements/Checkbox/index.js.map +1 -1
  62. package/dist/elements/Checkbox/index.mjs +1 -306
  63. package/dist/elements/Checkbox/index.mjs.map +1 -1
  64. package/dist/elements/CheckboxGroup/index.js +1 -455
  65. package/dist/elements/CheckboxGroup/index.js.map +1 -1
  66. package/dist/elements/CheckboxGroup/index.mjs +1 -439
  67. package/dist/elements/CheckboxGroup/index.mjs.map +1 -1
  68. package/dist/elements/Combobox/Combobox.d.ts +56 -0
  69. package/dist/elements/Combobox/Combobox.d.ts.map +1 -0
  70. package/dist/elements/Combobox/Combobox.styles.d.ts +29 -0
  71. package/dist/elements/Combobox/Combobox.styles.d.ts.map +1 -0
  72. package/dist/elements/Combobox/Combobox.types.d.ts +67 -0
  73. package/dist/elements/Combobox/Combobox.types.d.ts.map +1 -0
  74. package/dist/elements/Combobox/index.d.ts +20 -0
  75. package/dist/elements/Combobox/index.d.ts.map +1 -0
  76. package/dist/elements/Combobox/index.js +3 -0
  77. package/dist/elements/Combobox/index.js.map +1 -0
  78. package/dist/elements/Combobox/index.mjs +3 -0
  79. package/dist/elements/Combobox/index.mjs.map +1 -0
  80. package/dist/elements/DatePicker/DatePicker.d.ts +1 -1
  81. package/dist/elements/DatePicker/DatePicker.d.ts.map +1 -1
  82. package/dist/elements/DatePicker/index.js +1 -903
  83. package/dist/elements/DatePicker/index.js.map +1 -1
  84. package/dist/elements/DatePicker/index.mjs +1 -853
  85. package/dist/elements/DatePicker/index.mjs.map +1 -1
  86. package/dist/elements/Dropdown/Dropdown.d.ts +7 -15
  87. package/dist/elements/Dropdown/Dropdown.d.ts.map +1 -1
  88. package/dist/elements/Dropdown/Dropdown.styles.d.ts +22 -0
  89. package/dist/elements/Dropdown/Dropdown.styles.d.ts.map +1 -0
  90. package/dist/elements/Dropdown/index.d.ts +1 -0
  91. package/dist/elements/Dropdown/index.d.ts.map +1 -1
  92. package/dist/elements/Dropdown/index.js +1 -193
  93. package/dist/elements/Dropdown/index.js.map +1 -1
  94. package/dist/elements/Dropdown/index.mjs +1 -184
  95. package/dist/elements/Dropdown/index.mjs.map +1 -1
  96. package/dist/elements/FileField/index.js +1 -1539
  97. package/dist/elements/FileField/index.js.map +1 -1
  98. package/dist/elements/FileField/index.mjs +1 -1507
  99. package/dist/elements/FileField/index.mjs.map +1 -1
  100. package/dist/elements/FormLayout/index.js +1 -170
  101. package/dist/elements/FormLayout/index.js.map +1 -1
  102. package/dist/elements/FormLayout/index.mjs +1 -167
  103. package/dist/elements/FormLayout/index.mjs.map +1 -1
  104. package/dist/elements/Modal/Modal.d.ts +9 -14
  105. package/dist/elements/Modal/Modal.d.ts.map +1 -1
  106. package/dist/elements/Modal/Modal.styles.d.ts +29 -0
  107. package/dist/elements/Modal/Modal.styles.d.ts.map +1 -0
  108. package/dist/elements/Modal/index.d.ts +1 -0
  109. package/dist/elements/Modal/index.d.ts.map +1 -1
  110. package/dist/elements/Modal/index.js +1 -232
  111. package/dist/elements/Modal/index.js.map +1 -1
  112. package/dist/elements/Modal/index.mjs +1 -220
  113. package/dist/elements/Modal/index.mjs.map +1 -1
  114. package/dist/elements/NumberField/NumberField.variants.d.ts +1 -1
  115. package/dist/elements/NumberField/index.js +1 -666
  116. package/dist/elements/NumberField/index.js.map +1 -1
  117. package/dist/elements/NumberField/index.mjs +1 -654
  118. package/dist/elements/NumberField/index.mjs.map +1 -1
  119. package/dist/elements/OTPInput/OTPInput.d.ts.map +1 -1
  120. package/dist/elements/OTPInput/index.js +1 -734
  121. package/dist/elements/OTPInput/index.js.map +1 -1
  122. package/dist/elements/OTPInput/index.mjs +1 -732
  123. package/dist/elements/OTPInput/index.mjs.map +1 -1
  124. package/dist/elements/Pagination/Pagination.d.ts +45 -0
  125. package/dist/elements/Pagination/Pagination.d.ts.map +1 -0
  126. package/dist/elements/Pagination/Pagination.styles.d.ts +10 -0
  127. package/dist/elements/Pagination/Pagination.styles.d.ts.map +1 -0
  128. package/dist/elements/Pagination/Pagination.types.d.ts +55 -0
  129. package/dist/elements/Pagination/Pagination.types.d.ts.map +1 -0
  130. package/dist/elements/Pagination/index.d.ts +21 -0
  131. package/dist/elements/Pagination/index.d.ts.map +1 -0
  132. package/dist/elements/Pagination/index.js +3 -0
  133. package/dist/elements/Pagination/index.js.map +1 -0
  134. package/dist/elements/Pagination/index.mjs +3 -0
  135. package/dist/elements/Pagination/index.mjs.map +1 -0
  136. package/dist/elements/Panel/index.js +1 -330
  137. package/dist/elements/Panel/index.js.map +1 -1
  138. package/dist/elements/Panel/index.mjs +1 -323
  139. package/dist/elements/Panel/index.mjs.map +1 -1
  140. package/dist/elements/PasswordField/PasswordField.d.ts +27 -0
  141. package/dist/elements/PasswordField/PasswordField.d.ts.map +1 -0
  142. package/dist/elements/PasswordField/PasswordField.styles.d.ts +32 -0
  143. package/dist/elements/PasswordField/PasswordField.styles.d.ts.map +1 -0
  144. package/dist/elements/PasswordField/PasswordField.types.d.ts +100 -0
  145. package/dist/elements/PasswordField/PasswordField.types.d.ts.map +1 -0
  146. package/dist/elements/PasswordField/index.css +2 -0
  147. package/dist/elements/PasswordField/index.css.map +1 -0
  148. package/dist/elements/PasswordField/index.d.ts +20 -0
  149. package/dist/elements/PasswordField/index.d.ts.map +1 -0
  150. package/dist/elements/PasswordField/index.js +3 -0
  151. package/dist/elements/PasswordField/index.js.map +1 -0
  152. package/dist/elements/PasswordField/index.mjs +3 -0
  153. package/dist/elements/PasswordField/index.mjs.map +1 -0
  154. package/dist/elements/Progress/index.js +1 -187
  155. package/dist/elements/Progress/index.js.map +1 -1
  156. package/dist/elements/Progress/index.mjs +1 -181
  157. package/dist/elements/Progress/index.mjs.map +1 -1
  158. package/dist/elements/RadioGroup/index.js +1 -369
  159. package/dist/elements/RadioGroup/index.js.map +1 -1
  160. package/dist/elements/RadioGroup/index.mjs +1 -359
  161. package/dist/elements/RadioGroup/index.mjs.map +1 -1
  162. package/dist/elements/Resizable/index.js +1 -1580
  163. package/dist/elements/Resizable/index.js.map +1 -1
  164. package/dist/elements/Resizable/index.mjs +1 -1566
  165. package/dist/elements/Resizable/index.mjs.map +1 -1
  166. package/dist/elements/SearchField/SearchField.d.ts +27 -0
  167. package/dist/elements/SearchField/SearchField.d.ts.map +1 -0
  168. package/dist/elements/SearchField/SearchField.styles.d.ts +32 -0
  169. package/dist/elements/SearchField/SearchField.styles.d.ts.map +1 -0
  170. package/dist/elements/SearchField/SearchField.types.d.ts +45 -0
  171. package/dist/elements/SearchField/SearchField.types.d.ts.map +1 -0
  172. package/dist/elements/SearchField/index.css +2 -0
  173. package/dist/elements/SearchField/index.css.map +1 -0
  174. package/dist/elements/SearchField/index.d.ts +21 -0
  175. package/dist/elements/SearchField/index.d.ts.map +1 -0
  176. package/dist/elements/SearchField/index.js +3 -0
  177. package/dist/elements/SearchField/index.js.map +1 -0
  178. package/dist/elements/SearchField/index.mjs +3 -0
  179. package/dist/elements/SearchField/index.mjs.map +1 -0
  180. package/dist/elements/Select/Select.d.ts +19 -48
  181. package/dist/elements/Select/Select.d.ts.map +1 -1
  182. package/dist/elements/Select/Select.styles.d.ts +55 -0
  183. package/dist/elements/Select/Select.styles.d.ts.map +1 -0
  184. package/dist/elements/Select/index.js +1 -589
  185. package/dist/elements/Select/index.js.map +1 -1
  186. package/dist/elements/Select/index.mjs +1 -582
  187. package/dist/elements/Select/index.mjs.map +1 -1
  188. package/dist/elements/Skeleton/index.js +1 -82
  189. package/dist/elements/Skeleton/index.js.map +1 -1
  190. package/dist/elements/Skeleton/index.mjs +1 -78
  191. package/dist/elements/Skeleton/index.mjs.map +1 -1
  192. package/dist/elements/Switch/index.js +1 -179
  193. package/dist/elements/Switch/index.js.map +1 -1
  194. package/dist/elements/Switch/index.mjs +1 -173
  195. package/dist/elements/Switch/index.mjs.map +1 -1
  196. package/dist/elements/Table/Table.d.ts +3 -24
  197. package/dist/elements/Table/Table.d.ts.map +1 -1
  198. package/dist/elements/Table/Table.styles.d.ts +24 -0
  199. package/dist/elements/Table/Table.styles.d.ts.map +1 -0
  200. package/dist/elements/Table/index.js +1 -595
  201. package/dist/elements/Table/index.js.map +1 -1
  202. package/dist/elements/Table/index.mjs +1 -578
  203. package/dist/elements/Table/index.mjs.map +1 -1
  204. package/dist/elements/Tabs/Tabs.d.ts +5 -3
  205. package/dist/elements/Tabs/Tabs.d.ts.map +1 -1
  206. package/dist/elements/Tabs/Tabs.types.d.ts +15 -0
  207. package/dist/elements/Tabs/Tabs.types.d.ts.map +1 -1
  208. package/dist/elements/Tabs/index.js +1 -337
  209. package/dist/elements/Tabs/index.js.map +1 -1
  210. package/dist/elements/Tabs/index.mjs +1 -320
  211. package/dist/elements/Tabs/index.mjs.map +1 -1
  212. package/dist/elements/TextField/TextField.d.ts +6 -42
  213. package/dist/elements/TextField/TextField.d.ts.map +1 -1
  214. package/dist/elements/TextField/TextField.hooks.d.ts +63 -0
  215. package/dist/elements/TextField/TextField.hooks.d.ts.map +1 -0
  216. package/dist/elements/TextField/TextField.icons.d.ts +19 -0
  217. package/dist/elements/TextField/TextField.icons.d.ts.map +1 -0
  218. package/dist/elements/TextField/TextField.styles.d.ts +37 -0
  219. package/dist/elements/TextField/TextField.styles.d.ts.map +1 -0
  220. package/dist/elements/TextField/TextField.types.d.ts +3 -0
  221. package/dist/elements/TextField/TextField.types.d.ts.map +1 -1
  222. package/dist/elements/TextField/index.css +1 -22
  223. package/dist/elements/TextField/index.css.map +1 -1
  224. package/dist/elements/TextField/index.js +1 -902
  225. package/dist/elements/TextField/index.js.map +1 -1
  226. package/dist/elements/TextField/index.mjs +1 -882
  227. package/dist/elements/TextField/index.mjs.map +1 -1
  228. package/dist/elements/TimeField/index.js +1 -254
  229. package/dist/elements/TimeField/index.js.map +1 -1
  230. package/dist/elements/TimeField/index.mjs +1 -238
  231. package/dist/elements/TimeField/index.mjs.map +1 -1
  232. package/dist/elements/Toast/Toast.d.ts +0 -22
  233. package/dist/elements/Toast/Toast.d.ts.map +1 -1
  234. package/dist/elements/Toast/index.js +1 -737
  235. package/dist/elements/Toast/index.js.map +1 -1
  236. package/dist/elements/Toast/index.mjs +1 -724
  237. package/dist/elements/Toast/index.mjs.map +1 -1
  238. package/dist/elements/Tooltip/index.js +1 -323
  239. package/dist/elements/Tooltip/index.js.map +1 -1
  240. package/dist/elements/Tooltip/index.mjs +1 -310
  241. package/dist/elements/Tooltip/index.mjs.map +1 -1
  242. package/dist/elements/index.css +1 -22
  243. package/dist/elements/index.css.map +1 -1
  244. package/dist/elements/index.d.ts +13 -1
  245. package/dist/elements/index.d.ts.map +1 -1
  246. package/dist/elements/index.js +1 -12455
  247. package/dist/elements/index.js.map +1 -1
  248. package/dist/elements/index.mjs +1 -12233
  249. package/dist/elements/index.mjs.map +1 -1
  250. package/dist/index.css +1 -22
  251. package/dist/index.css.map +1 -1
  252. package/dist/index.js +2 -12490
  253. package/dist/index.js.map +1 -1
  254. package/dist/index.mjs +2 -12262
  255. package/dist/index.mjs.map +1 -1
  256. package/dist/schemas/index.js +2 -54
  257. package/dist/schemas/index.js.map +1 -1
  258. package/dist/schemas/index.mjs +2 -48
  259. package/dist/schemas/index.mjs.map +1 -1
  260. package/dist/styles/defaults.css +151 -0
  261. package/dist/styles/index.js +1 -166
  262. package/dist/styles/index.js.map +1 -1
  263. package/dist/styles/index.mjs +1 -129
  264. package/dist/styles/index.mjs.map +1 -1
  265. package/dist/styles/shared-variants.d.ts +3 -3
  266. package/dist/styles/shared-variants.d.ts.map +1 -1
  267. package/dist/utils/index.js +1 -12
  268. package/dist/utils/index.js.map +1 -1
  269. package/dist/utils/index.mjs +1 -10
  270. package/dist/utils/index.mjs.map +1 -1
  271. package/package.json +9 -7
  272. package/src/elements/Accordion/Accordion.stories.tsx +1 -1
  273. package/src/elements/AlertDialog/AlertDialog.stories.tsx +124 -0
  274. package/src/elements/Avatar/Avatar.stories.tsx +1 -1
  275. package/src/elements/Badge/Badge.stories.tsx +1 -1
  276. package/src/elements/Breadcrumbs/Breadcrumbs.stories.tsx +1 -1
  277. package/src/elements/Button/Button.stories.tsx +1 -1
  278. package/src/elements/ButtonGroup/ButtonGroup.stories.tsx +1 -1
  279. package/src/elements/Card/Card.stories.tsx +1 -1
  280. package/src/elements/Carousel/Carousel.stories.tsx +1 -1
  281. package/src/elements/Chart/Chart.stories.tsx +1 -1
  282. package/src/elements/Checkbox/Checkbox.stories.tsx +1 -1
  283. package/src/elements/CheckboxGroup/CheckboxGroup.stories.tsx +4 -4
  284. package/src/elements/Combobox/Combobox.stories.tsx +133 -0
  285. package/src/elements/DatePicker/DatePicker.stories.tsx +1 -1
  286. package/src/elements/Dropdown/Dropdown.stories.tsx +1 -1
  287. package/src/elements/FileField/FileField.stories.tsx +2 -2
  288. package/src/elements/FileField/FileProgress.stories.tsx +1 -1
  289. package/src/elements/FormLayout/FormLayout.stories.tsx +1 -1
  290. package/src/elements/Modal/Modal.stories.tsx +1 -1
  291. package/src/elements/NumberField/NumberField.stories.tsx +1 -1
  292. package/src/elements/OTPInput/OTPInput.stories.tsx +1 -1
  293. package/src/elements/Pagination/Pagination.stories.tsx +203 -0
  294. package/src/elements/Panel/Panel.stories.tsx +1 -1
  295. package/src/elements/PasswordField/PasswordField.stories.tsx +167 -0
  296. package/src/elements/Progress/Progress.stories.tsx +7 -2
  297. package/src/elements/RadioGroup/RadioGroup.stories.tsx +3 -3
  298. package/src/elements/Resizable/Resizable.stories.tsx +1 -1
  299. package/src/elements/SearchField/SearchField.stories.tsx +146 -0
  300. package/src/elements/Select/Select.stories.tsx +1 -1
  301. package/src/elements/Skeleton/Skeleton.stories.tsx +1 -1
  302. package/src/elements/Switch/Switch.stories.tsx +1 -1
  303. package/src/elements/Table/Table.stories.tsx +1 -1
  304. package/src/elements/Tabs/Tabs.stories.tsx +46 -2
  305. package/src/elements/TextField/TextField.stories.tsx +1 -1
  306. package/src/elements/TimeField/TimeField.stories.tsx +1 -1
  307. package/src/elements/Toast/Toast.stories.tsx +1 -1
  308. package/src/elements/Tooltip/Tooltip.stories.tsx +1 -1
@@ -1,195 +1,3 @@
1
1
  "use client";
2
- 'use strict';
3
-
4
- var react = require('react');
5
- var reactAriaComponents = require('react-aria-components');
6
- var classVarianceAuthority = require('class-variance-authority');
7
- var lucideReact = require('lucide-react');
8
- var clsx = require('clsx');
9
- var tailwindMerge = require('tailwind-merge');
10
- var jsxRuntime = require('react/jsx-runtime');
11
-
12
- // src/elements/Dropdown/Dropdown.tsx
13
- function cn(...inputs) {
14
- return tailwindMerge.twMerge(clsx.clsx(inputs));
15
- }
16
- var menuVariants = classVarianceAuthority.cva(
17
- // Base styles - semantic tokens with fallbacks
18
- "z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1",
19
- {
20
- variants: {
21
- variant: {
22
- default: ""
23
- }
24
- },
25
- defaultVariants: {
26
- variant: "default"
27
- }
28
- }
29
- );
30
- var menuItemVariants = classVarianceAuthority.cva(
31
- // Base styles - FR-014: 44x44px minimum touch targets
32
- "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
33
- {
34
- variants: {
35
- variant: {
36
- default: ""
37
- }
38
- },
39
- defaultVariants: {
40
- variant: "default"
41
- }
42
- }
43
- );
44
- var DropdownRoot = react.forwardRef(
45
- ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {
46
- const childArray = react.Children.toArray(children);
47
- const hasTrigger = childArray.some(
48
- (child) => react.isValidElement(child) && (child.type === DropdownTrigger || child.type.displayName === "DropdownTrigger")
49
- );
50
- const hasMenu = childArray.some(
51
- (child) => react.isValidElement(child) && (child.type === DropdownMenu || child.type.displayName === "DropdownMenu")
52
- );
53
- if (!hasTrigger || !hasMenu) {
54
- throw new Error(
55
- "Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children"
56
- );
57
- }
58
- return /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.MenuTrigger, { defaultOpen, isOpen, onOpenChange, children });
59
- }
60
- );
61
- DropdownRoot.displayName = "Dropdown";
62
- var DropdownTrigger = react.forwardRef(
63
- ({ children, ...props }, ref) => {
64
- if (react.isValidElement(children)) {
65
- return react.cloneElement(children, {
66
- ...props,
67
- slot: "trigger"
68
- });
69
- }
70
- return /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Button, { ref, ...props, children });
71
- }
72
- );
73
- DropdownTrigger.displayName = "DropdownTrigger";
74
- var DropdownMenu = react.forwardRef(
75
- ({ align = "start", side = "bottom", className, children, ...props }, _ref) => {
76
- const placement = `${side} ${align}`;
77
- return /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Popover, { placement, className: "entering:animate-in exiting:animate-out", children: /* @__PURE__ */ jsxRuntime.jsx(
78
- reactAriaComponents.Menu,
79
- {
80
- className: cn(menuVariants({ variant: "default" }), className),
81
- ...props,
82
- children
83
- }
84
- ) });
85
- }
86
- );
87
- DropdownMenu.displayName = "DropdownMenu";
88
- var DropdownItem = react.forwardRef(
89
- ({
90
- children,
91
- onAction,
92
- isDisabled = false,
93
- shortcut,
94
- icon,
95
- iconRight,
96
- className,
97
- "aria-label": ariaLabel,
98
- ...props
99
- }, _ref) => {
100
- const childArray = react.Children.toArray(children);
101
- const hasSubmenu = childArray.some(
102
- (child) => react.isValidElement(child) && (child.type === DropdownMenu || child.type.displayName === "DropdownMenu")
103
- );
104
- const contentChildren = childArray.filter(
105
- (child) => !react.isValidElement(child) || child.type !== DropdownMenu && child.type.displayName !== "DropdownMenu"
106
- );
107
- const submenu = childArray.find(
108
- (child) => react.isValidElement(child) && (child.type === DropdownMenu || child.type.displayName === "DropdownMenu")
109
- );
110
- if (hasSubmenu && submenu) {
111
- return /* @__PURE__ */ jsxRuntime.jsxs(reactAriaComponents.SubmenuTrigger, { children: [
112
- /* @__PURE__ */ jsxRuntime.jsxs(
113
- reactAriaComponents.MenuItem,
114
- {
115
- "aria-label": ariaLabel,
116
- className: cn(menuItemVariants({ variant: "default" }), className),
117
- ...props,
118
- children: [
119
- icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-2", children: icon }),
120
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: contentChildren }),
121
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "ml-auto h-4 w-4", "aria-hidden": "true" })
122
- ]
123
- }
124
- ),
125
- submenu
126
- ] });
127
- }
128
- return /* @__PURE__ */ jsxRuntime.jsxs(
129
- reactAriaComponents.MenuItem,
130
- {
131
- onAction,
132
- isDisabled,
133
- "aria-label": ariaLabel,
134
- className: cn(menuItemVariants({ variant: "default" }), className),
135
- ...props,
136
- children: [
137
- icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-2", children: icon }),
138
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children }),
139
- iconRight && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto", children: iconRight }),
140
- shortcut && /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100", children: shortcut })
141
- ]
142
- }
143
- );
144
- }
145
- );
146
- DropdownItem.displayName = "DropdownItem";
147
- var DropdownSeparator = react.memo(react.forwardRef(
148
- ({ className, ...props }, _ref) => {
149
- return /* @__PURE__ */ jsxRuntime.jsx(
150
- reactAriaComponents.Separator,
151
- {
152
- className: cn(
153
- "-mx-1 my-1 h-px bg-[var(--accent-background)]",
154
- className
155
- ),
156
- ...props
157
- }
158
- );
159
- }
160
- ));
161
- DropdownSeparator.displayName = "DropdownSeparator";
162
- var DropdownLabel = react.memo(react.forwardRef(
163
- ({ children, className, ...props }, _ref) => {
164
- return /* @__PURE__ */ jsxRuntime.jsx(
165
- reactAriaComponents.Header,
166
- {
167
- className: cn(
168
- "px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]",
169
- className
170
- ),
171
- ...props,
172
- children
173
- }
174
- );
175
- }
176
- ));
177
- DropdownLabel.displayName = "DropdownLabel";
178
- var Dropdown = Object.assign(DropdownRoot, {
179
- Trigger: DropdownTrigger,
180
- Menu: DropdownMenu,
181
- Item: DropdownItem,
182
- Separator: DropdownSeparator,
183
- Label: DropdownLabel
184
- });
185
-
186
- exports.Dropdown = Dropdown;
187
- exports.DropdownItem = DropdownItem;
188
- exports.DropdownLabel = DropdownLabel;
189
- exports.DropdownMenu = DropdownMenu;
190
- exports.DropdownSeparator = DropdownSeparator;
191
- exports.DropdownTrigger = DropdownTrigger;
192
- exports.menuItemVariants = menuItemVariants;
193
- exports.menuVariants = menuVariants;
194
- //# sourceMappingURL=index.js.map
2
+ 'use strict';var react=require('react'),reactAriaComponents=require('react-aria-components'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),classVarianceAuthority=require('class-variance-authority'),jsxRuntime=require('react/jsx-runtime');function d(...e){return tailwindMerge.twMerge(clsx.clsx(e))}var b=classVarianceAuthority.cva("z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1",{variants:{variant:{default:""}},defaultVariants:{variant:"default"}}),w=classVarianceAuthority.cva("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:""}},defaultVariants:{variant:"default"}});function P(e){if(typeof e=="function"||typeof e=="object")return e?.displayName}var E=react.forwardRef(({defaultOpen:e=false,isOpen:o,onOpenChange:n,children:t},p)=>{if(process.env.NODE_ENV!=="production"){let s=react.Children.toArray(t),i=s.some(a=>react.isValidElement(a)&&(a.type===f||P(a.type)==="DropdownTrigger")),c=s.some(a=>react.isValidElement(a)&&(a.type===l||P(a.type)==="DropdownMenu"));if(!i||!c)throw new Error("Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children")}return jsxRuntime.jsx(reactAriaComponents.MenuTrigger,{defaultOpen:e,isOpen:o,onOpenChange:n,children:t})});E.displayName="Dropdown";var f=react.forwardRef(({children:e,...o},n)=>react.isValidElement(e)?react.cloneElement(e,{...o,slot:"trigger"}):jsxRuntime.jsx(reactAriaComponents.Button,{ref:n,...o,children:e}));f.displayName="DropdownTrigger";var l=react.forwardRef(({align:e="start",side:o="bottom",className:n,children:t,...p},s)=>{let i=`${o} ${e}`;return jsxRuntime.jsx(reactAriaComponents.Popover,{placement:i,className:"entering:animate-in exiting:animate-out",children:jsxRuntime.jsx(reactAriaComponents.Menu,{className:d(b({variant:"default"}),n),...p,children:t})})});l.displayName="DropdownMenu";var x=react.forwardRef(({children:e,onAction:o,isDisabled:n=false,shortcut:t,icon:p,iconRight:s,className:i,"aria-label":c,...a},G)=>{let D=react.Children.toArray(e),y=u=>react.isValidElement(u)&&(u.type===l||P(u.type)==="DropdownMenu"),L=D.some(y),h=D.filter(u=>!y(u)),N=D.find(y);return L&&N?jsxRuntime.jsxs(reactAriaComponents.SubmenuTrigger,{children:[jsxRuntime.jsxs(reactAriaComponents.MenuItem,{"aria-label":c,className:d(w({variant:"default"}),i),...a,children:[p&&jsxRuntime.jsx("span",{className:"mr-2",children:p}),jsxRuntime.jsx("span",{className:"flex-1",children:h}),jsxRuntime.jsx(lucideReact.ChevronRight,{className:"ml-auto h-4 w-4","aria-hidden":"true"})]}),N]}):jsxRuntime.jsxs(reactAriaComponents.MenuItem,{onAction:o,isDisabled:n,"aria-label":c,className:d(w({variant:"default"}),i),...a,children:[p&&jsxRuntime.jsx("span",{className:"mr-2",children:p}),jsxRuntime.jsx("span",{className:"flex-1",children:e}),s&&jsxRuntime.jsx("span",{className:"ml-auto",children:s}),t&&jsxRuntime.jsx("kbd",{className:"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100",children:t})]})});x.displayName="DropdownItem";var M=react.memo(react.forwardRef(({className:e,...o},n)=>jsxRuntime.jsx(reactAriaComponents.Separator,{className:d("-mx-1 my-1 h-px bg-[var(--accent-background)]",e),...o})));M.displayName="DropdownSeparator";var T=react.memo(react.forwardRef(({children:e,className:o,...n},t)=>jsxRuntime.jsx(reactAriaComponents.Header,{className:d("px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]",o),...n,children:e})));T.displayName="DropdownLabel";var F=Object.assign(E,{Trigger:f,Menu:l,Item:x,Separator:M,Label:T});exports.Dropdown=F;exports.DropdownItem=x;exports.DropdownLabel=T;exports.DropdownMenu=l;exports.DropdownSeparator=M;exports.DropdownTrigger=f;exports.menuItemVariants=w;exports.menuVariants=b;//# sourceMappingURL=index.js.map
195
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Dropdown/Dropdown.tsx"],"names":["twMerge","clsx","cva","forwardRef","Children","isValidElement","jsx","AriaMenuTrigger","cloneElement","AriaButton","AriaPopover","AriaMenu","AriaSubmenuTrigger","jsxs","AriaMenuItem","ChevronRight","memo","AriaSeparator","AriaHeader"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\n/**\n * Dropdown Menu Component\n * Accessible dropdown menu with React Aria primitives, nested submenus, and CVA styling\n *\n * @see spec.md FR-001 to FR-054 (Dropdown Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, Children, isValidElement, type ReactNode, type ReactElement, cloneElement } from 'react';\nimport {\n MenuTrigger as AriaMenuTrigger,\n SubmenuTrigger as AriaSubmenuTrigger,\n Button as AriaButton,\n Menu as AriaMenu,\n MenuItem as AriaMenuItem,\n Separator as AriaSeparator,\n Header as AriaHeader,\n Popover as AriaPopover,\n} from 'react-aria-components';\nimport { cva } from 'class-variance-authority';\nimport { ChevronRight } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n} from './Dropdown.types';\n\n/**\n * Menu variant styles using CVA\n * @see spec.md FR-040 (CVA for variant styling - single \"default\" variant for v1)\n */\nconst menuVariants = cva(\n // Base styles - semantic tokens with fallbacks\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Menu Item variant styles using CVA\n * @see spec.md FR-041 (CVA for item states: hover, focus, active, disabled)\n */\nconst menuItemVariants = cva(\n // Base styles - FR-014: 44x44px minimum touch targets\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Dropdown Root Component\n * Manages open/close state and coordinates Trigger and Menu children\n *\n * @see spec.md FR-001 to FR-007\n */\ninterface InternalDropdownProps extends DropdownProps {\n children: ReactNode;\n}\n\nconst DropdownRoot = forwardRef<HTMLDivElement, InternalDropdownProps>(\n ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {\n // Validate children: must have exactly one Trigger and one Menu\n const childArray = Children.toArray(children);\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownTrigger || (child.type as any).displayName === 'DropdownTrigger')\n );\n const hasMenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || (child.type as any).displayName === 'DropdownMenu')\n );\n\n if (!hasTrigger || !hasMenu) {\n throw new Error(\n 'Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children'\n );\n }\n\n return (\n <AriaMenuTrigger defaultOpen={defaultOpen} isOpen={isOpen} onOpenChange={onOpenChange}>\n {children}\n </AriaMenuTrigger>\n );\n }\n);\n\nDropdownRoot.displayName = 'Dropdown';\n\n/**\n * Dropdown.Trigger Component\n * Wraps trigger element (typically Button) with proper ARIA attributes\n *\n * @see spec.md FR-008 to FR-012\n */\nconst DropdownTrigger = forwardRef<HTMLButtonElement, DropdownTriggerProps>(\n ({ children, ...props }, ref) => {\n // Clone child and add ref if it's a single React element\n if (isValidElement(children)) {\n return cloneElement(children as ReactElement<any>, {\n ...props,\n slot: 'trigger',\n });\n }\n\n // Fallback: wrap in AriaButton if not a React element\n return (\n <AriaButton ref={ref} {...props}>\n {children}\n </AriaButton>\n );\n }\n);\n\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown.Menu Component\n * Renders menu with positioning, collision detection, and focus management\n *\n * @see spec.md FR-014 to FR-024\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ align = 'start', side = 'bottom', className, children, ...props }, _ref) => {\n // Map align to React Aria placement\n const placement = `${side} ${align}` as any;\n\n return (\n <AriaPopover placement={placement} className=\"entering:animate-in exiting:animate-out\">\n <AriaMenu\n className={cn(menuVariants({ variant: 'default' }), className)}\n {...props}\n >\n {children}\n </AriaMenu>\n </AriaPopover>\n );\n }\n);\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * Dropdown.Item Component\n * Menu item with action callbacks, disabled state, shortcuts, icons, and nested submenu support\n *\n * @see spec.md FR-025 to FR-034\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n (\n {\n children,\n onAction,\n isDisabled = false,\n shortcut,\n icon,\n iconRight,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n _ref\n ) => {\n // Check if this item contains a nested submenu\n const childArray = Children.toArray(children);\n const hasSubmenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || (child.type as any).displayName === 'DropdownMenu')\n );\n\n // Filter children to separate submenu from content\n const contentChildren = childArray.filter(\n (child) =>\n !isValidElement(child) ||\n (child.type !== DropdownMenu && (child.type as any).displayName !== 'DropdownMenu')\n );\n\n const submenu = childArray.find(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || (child.type as any).displayName === 'DropdownMenu')\n );\n\n if (hasSubmenu && submenu) {\n // Render as submenu trigger using React Aria's SubmenuTrigger\n return (\n <AriaSubmenuTrigger>\n <AriaMenuItem\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{contentChildren}</span>\n <ChevronRight className=\"ml-auto h-4 w-4\" aria-hidden=\"true\" />\n </AriaMenuItem>\n {submenu as ReactElement}\n </AriaSubmenuTrigger>\n );\n }\n\n // Regular menu item\n return (\n <AriaMenuItem\n onAction={onAction}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n {iconRight && <span className=\"ml-auto\">{iconRight}</span>}\n {shortcut && (\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100\">\n {shortcut}\n </kbd>\n )}\n </AriaMenuItem>\n );\n }\n);\n\nDropdownItem.displayName = 'DropdownItem';\n\n/**\n * Dropdown.Separator Component\n * Non-focusable visual divider\n *\n * @see spec.md FR-043 to FR-045\n */\nconst DropdownSeparator = memo(forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, _ref) => {\n return (\n <AriaSeparator\n className={cn(\n '-mx-1 my-1 h-px bg-[var(--accent-background)]',\n className\n )}\n {...props}\n />\n );\n }\n));\n\nDropdownSeparator.displayName = 'DropdownSeparator';\n\n/**\n * Dropdown.Label Component\n * Non-interactive section header\n *\n * @see spec.md FR-046 to FR-048\n */\nconst DropdownLabel = memo(forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ children, className, ...props }, _ref) => {\n return (\n <AriaHeader\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]',\n className\n )}\n {...props}\n >\n {children}\n </AriaHeader>\n );\n }\n));\n\nDropdownLabel.displayName = 'DropdownLabel';\n\n/**\n * Export compound component\n */\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n Separator: DropdownSeparator,\n Label: DropdownLabel,\n});\n\n// Export individual components for flexibility\nexport { DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel };\n\n// Export variant functions for external use\nexport { menuVariants, menuItemVariants };\n\n// Export types\nexport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n};\n"]}
1
+ {"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Dropdown/Dropdown.styles.ts","../../../src/elements/Dropdown/Dropdown.tsx"],"names":["cn","inputs","twMerge","clsx","menuVariants","cva","menuItemVariants","getDisplayName","type","DropdownRoot","forwardRef","defaultOpen","isOpen","onOpenChange","children","_ref","childArray","Children","hasTrigger","child","isValidElement","DropdownTrigger","hasMenu","DropdownMenu","jsx","AriaMenuTrigger","props","ref","cloneElement","AriaButton","align","side","className","placement","AriaPopover","AriaMenu","DropdownItem","onAction","isDisabled","shortcut","icon","iconRight","ariaLabel","isDropdownMenu","hasSubmenu","contentChildren","submenu","jsxs","AriaSubmenuTrigger","AriaMenuItem","ChevronRight","DropdownSeparator","memo","AriaSeparator","DropdownLabel","AriaHeader","Dropdown"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n/**\n * Menu variant styles using CVA\n * @see spec.md FR-040 (CVA for variant styling - single \"default\" variant for v1)\n */\nexport const menuVariants = cva(\n // Base styles - semantic tokens with fallbacks\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Menu Item variant styles using CVA\n * @see spec.md FR-041 (CVA for item states: hover, focus, active, disabled)\n */\nexport const menuItemVariants = cva(\n // Base styles - FR-014: 44x44px minimum touch targets\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Type exports for variant props\n * Allows TypeScript inference of variant combinations\n */\nexport type MenuVariantProps = VariantProps<typeof menuVariants>;\nexport type MenuItemVariantProps = VariantProps<typeof menuItemVariants>;\n","\"use client\";\n\n/**\n * Dropdown Menu Component\n * Accessible dropdown menu with React Aria primitives, nested submenus, and CVA styling\n *\n * @see spec.md FR-001 to FR-054 (Dropdown Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, Children, isValidElement, type ReactNode, type ReactElement, cloneElement, type ComponentType } from 'react';\nimport type { Placement } from 'react-aria';\nimport {\n MenuTrigger as AriaMenuTrigger,\n SubmenuTrigger as AriaSubmenuTrigger,\n Button as AriaButton,\n Menu as AriaMenu,\n MenuItem as AriaMenuItem,\n Separator as AriaSeparator,\n Header as AriaHeader,\n Popover as AriaPopover,\n} from 'react-aria-components';\nimport { ChevronRight } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { menuVariants, menuItemVariants } from './Dropdown.styles';\nimport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n} from './Dropdown.types';\n\n/**\n * Type-safe helper to get displayName from a component type.\n */\nfunction getDisplayName(type: unknown): string | undefined {\n if (typeof type === 'function' || typeof type === 'object') {\n return (type as ComponentType)?.displayName;\n }\n return undefined;\n}\n\n/**\n * Dropdown Root Component\n * Manages open/close state and coordinates Trigger and Menu children\n *\n * @see spec.md FR-001 to FR-007\n */\ninterface InternalDropdownProps extends DropdownProps {\n children: ReactNode;\n}\n\nconst DropdownRoot = forwardRef<HTMLDivElement, InternalDropdownProps>(\n ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {\n // Validate children structure in development only\n if (process.env.NODE_ENV !== 'production') {\n const childArray = Children.toArray(children);\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownTrigger || getDisplayName(child.type) === 'DropdownTrigger')\n );\n const hasMenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu')\n );\n\n if (!hasTrigger || !hasMenu) {\n throw new Error(\n 'Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children'\n );\n }\n }\n\n return (\n <AriaMenuTrigger defaultOpen={defaultOpen} isOpen={isOpen} onOpenChange={onOpenChange}>\n {children}\n </AriaMenuTrigger>\n );\n }\n);\n\nDropdownRoot.displayName = 'Dropdown';\n\n/**\n * Dropdown.Trigger Component\n * Wraps trigger element (typically Button) with proper ARIA attributes\n *\n * @see spec.md FR-008 to FR-012\n */\nconst DropdownTrigger = forwardRef<HTMLButtonElement, DropdownTriggerProps>(\n ({ children, ...props }, ref) => {\n // Clone child and add ref if it's a single React element\n if (isValidElement(children)) {\n return cloneElement(children as ReactElement<Record<string, unknown>>, {\n ...props,\n slot: 'trigger',\n });\n }\n\n // Fallback: wrap in AriaButton if not a React element\n return (\n <AriaButton ref={ref} {...props}>\n {children}\n </AriaButton>\n );\n }\n);\n\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown.Menu Component\n * Renders menu with positioning, collision detection, and focus management\n *\n * @see spec.md FR-014 to FR-024\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ align = 'start', side = 'bottom', className, children, ...props }, _ref) => {\n // Map align to React Aria placement\n const placement = `${side} ${align}` as Placement;\n\n return (\n <AriaPopover placement={placement} className=\"entering:animate-in exiting:animate-out\">\n <AriaMenu\n className={cn(menuVariants({ variant: 'default' }), className)}\n {...props}\n >\n {children}\n </AriaMenu>\n </AriaPopover>\n );\n }\n);\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * Dropdown.Item Component\n * Menu item with action callbacks, disabled state, shortcuts, icons, and nested submenu support\n *\n * @see spec.md FR-025 to FR-034\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n (\n {\n children,\n onAction,\n isDisabled = false,\n shortcut,\n icon,\n iconRight,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n _ref\n ) => {\n // Check if this item contains a nested submenu\n const childArray = Children.toArray(children);\n const isDropdownMenu = (child: unknown): boolean =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu');\n\n const hasSubmenu = childArray.some(isDropdownMenu);\n\n // Filter children to separate submenu from content\n const contentChildren = childArray.filter((child) => !isDropdownMenu(child));\n\n const submenu = childArray.find(isDropdownMenu);\n\n if (hasSubmenu && submenu) {\n // Render as submenu trigger using React Aria's SubmenuTrigger\n return (\n <AriaSubmenuTrigger>\n <AriaMenuItem\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{contentChildren}</span>\n <ChevronRight className=\"ml-auto h-4 w-4\" aria-hidden=\"true\" />\n </AriaMenuItem>\n {submenu as ReactElement}\n </AriaSubmenuTrigger>\n );\n }\n\n // Regular menu item\n return (\n <AriaMenuItem\n onAction={onAction}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n {iconRight && <span className=\"ml-auto\">{iconRight}</span>}\n {shortcut && (\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100\">\n {shortcut}\n </kbd>\n )}\n </AriaMenuItem>\n );\n }\n);\n\nDropdownItem.displayName = 'DropdownItem';\n\n/**\n * Dropdown.Separator Component\n * Non-focusable visual divider\n *\n * @see spec.md FR-043 to FR-045\n */\nconst DropdownSeparator = memo(forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, _ref) => {\n return (\n <AriaSeparator\n className={cn(\n '-mx-1 my-1 h-px bg-[var(--accent-background)]',\n className\n )}\n {...props}\n />\n );\n }\n));\n\nDropdownSeparator.displayName = 'DropdownSeparator';\n\n/**\n * Dropdown.Label Component\n * Non-interactive section header\n *\n * @see spec.md FR-046 to FR-048\n */\nconst DropdownLabel = memo(forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ children, className, ...props }, _ref) => {\n return (\n <AriaHeader\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]',\n className\n )}\n {...props}\n >\n {children}\n </AriaHeader>\n );\n }\n));\n\nDropdownLabel.displayName = 'DropdownLabel';\n\n/**\n * Export compound component via Object.assign for backwards compatibility.\n * Enables `<Dropdown.Trigger>`, `<Dropdown.Menu>`, etc.\n *\n * @deprecated v2 — Remove Object.assign pattern in favour of direct named exports\n * (DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel)\n * for better tree-shaking. See named exports below.\n */\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n Separator: DropdownSeparator,\n Label: DropdownLabel,\n});\n\n// Export individual components for flexibility\nexport { DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel };\n\n// Export variant functions for external use\nexport { menuVariants, menuItemVariants };\n\n// Export types\nexport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n};\n"]}
@@ -1,186 +1,3 @@
1
1
  "use client";
2
- import { forwardRef, Children, isValidElement, cloneElement, memo } from 'react';
3
- import { MenuTrigger, Button, Popover, Menu, SubmenuTrigger, MenuItem, Separator, Header } from 'react-aria-components';
4
- import { cva } from 'class-variance-authority';
5
- import { ChevronRight } from 'lucide-react';
6
- import { clsx } from 'clsx';
7
- import { twMerge } from 'tailwind-merge';
8
- import { jsx, jsxs } from 'react/jsx-runtime';
9
-
10
- // src/elements/Dropdown/Dropdown.tsx
11
- function cn(...inputs) {
12
- return twMerge(clsx(inputs));
13
- }
14
- var menuVariants = cva(
15
- // Base styles - semantic tokens with fallbacks
16
- "z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1",
17
- {
18
- variants: {
19
- variant: {
20
- default: ""
21
- }
22
- },
23
- defaultVariants: {
24
- variant: "default"
25
- }
26
- }
27
- );
28
- var menuItemVariants = cva(
29
- // Base styles - FR-014: 44x44px minimum touch targets
30
- "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
31
- {
32
- variants: {
33
- variant: {
34
- default: ""
35
- }
36
- },
37
- defaultVariants: {
38
- variant: "default"
39
- }
40
- }
41
- );
42
- var DropdownRoot = forwardRef(
43
- ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {
44
- const childArray = Children.toArray(children);
45
- const hasTrigger = childArray.some(
46
- (child) => isValidElement(child) && (child.type === DropdownTrigger || child.type.displayName === "DropdownTrigger")
47
- );
48
- const hasMenu = childArray.some(
49
- (child) => isValidElement(child) && (child.type === DropdownMenu || child.type.displayName === "DropdownMenu")
50
- );
51
- if (!hasTrigger || !hasMenu) {
52
- throw new Error(
53
- "Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children"
54
- );
55
- }
56
- return /* @__PURE__ */ jsx(MenuTrigger, { defaultOpen, isOpen, onOpenChange, children });
57
- }
58
- );
59
- DropdownRoot.displayName = "Dropdown";
60
- var DropdownTrigger = forwardRef(
61
- ({ children, ...props }, ref) => {
62
- if (isValidElement(children)) {
63
- return cloneElement(children, {
64
- ...props,
65
- slot: "trigger"
66
- });
67
- }
68
- return /* @__PURE__ */ jsx(Button, { ref, ...props, children });
69
- }
70
- );
71
- DropdownTrigger.displayName = "DropdownTrigger";
72
- var DropdownMenu = forwardRef(
73
- ({ align = "start", side = "bottom", className, children, ...props }, _ref) => {
74
- const placement = `${side} ${align}`;
75
- return /* @__PURE__ */ jsx(Popover, { placement, className: "entering:animate-in exiting:animate-out", children: /* @__PURE__ */ jsx(
76
- Menu,
77
- {
78
- className: cn(menuVariants({ variant: "default" }), className),
79
- ...props,
80
- children
81
- }
82
- ) });
83
- }
84
- );
85
- DropdownMenu.displayName = "DropdownMenu";
86
- var DropdownItem = forwardRef(
87
- ({
88
- children,
89
- onAction,
90
- isDisabled = false,
91
- shortcut,
92
- icon,
93
- iconRight,
94
- className,
95
- "aria-label": ariaLabel,
96
- ...props
97
- }, _ref) => {
98
- const childArray = Children.toArray(children);
99
- const hasSubmenu = childArray.some(
100
- (child) => isValidElement(child) && (child.type === DropdownMenu || child.type.displayName === "DropdownMenu")
101
- );
102
- const contentChildren = childArray.filter(
103
- (child) => !isValidElement(child) || child.type !== DropdownMenu && child.type.displayName !== "DropdownMenu"
104
- );
105
- const submenu = childArray.find(
106
- (child) => isValidElement(child) && (child.type === DropdownMenu || child.type.displayName === "DropdownMenu")
107
- );
108
- if (hasSubmenu && submenu) {
109
- return /* @__PURE__ */ jsxs(SubmenuTrigger, { children: [
110
- /* @__PURE__ */ jsxs(
111
- MenuItem,
112
- {
113
- "aria-label": ariaLabel,
114
- className: cn(menuItemVariants({ variant: "default" }), className),
115
- ...props,
116
- children: [
117
- icon && /* @__PURE__ */ jsx("span", { className: "mr-2", children: icon }),
118
- /* @__PURE__ */ jsx("span", { className: "flex-1", children: contentChildren }),
119
- /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto h-4 w-4", "aria-hidden": "true" })
120
- ]
121
- }
122
- ),
123
- submenu
124
- ] });
125
- }
126
- return /* @__PURE__ */ jsxs(
127
- MenuItem,
128
- {
129
- onAction,
130
- isDisabled,
131
- "aria-label": ariaLabel,
132
- className: cn(menuItemVariants({ variant: "default" }), className),
133
- ...props,
134
- children: [
135
- icon && /* @__PURE__ */ jsx("span", { className: "mr-2", children: icon }),
136
- /* @__PURE__ */ jsx("span", { className: "flex-1", children }),
137
- iconRight && /* @__PURE__ */ jsx("span", { className: "ml-auto", children: iconRight }),
138
- shortcut && /* @__PURE__ */ jsx("kbd", { className: "ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100", children: shortcut })
139
- ]
140
- }
141
- );
142
- }
143
- );
144
- DropdownItem.displayName = "DropdownItem";
145
- var DropdownSeparator = memo(forwardRef(
146
- ({ className, ...props }, _ref) => {
147
- return /* @__PURE__ */ jsx(
148
- Separator,
149
- {
150
- className: cn(
151
- "-mx-1 my-1 h-px bg-[var(--accent-background)]",
152
- className
153
- ),
154
- ...props
155
- }
156
- );
157
- }
158
- ));
159
- DropdownSeparator.displayName = "DropdownSeparator";
160
- var DropdownLabel = memo(forwardRef(
161
- ({ children, className, ...props }, _ref) => {
162
- return /* @__PURE__ */ jsx(
163
- Header,
164
- {
165
- className: cn(
166
- "px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]",
167
- className
168
- ),
169
- ...props,
170
- children
171
- }
172
- );
173
- }
174
- ));
175
- DropdownLabel.displayName = "DropdownLabel";
176
- var Dropdown = Object.assign(DropdownRoot, {
177
- Trigger: DropdownTrigger,
178
- Menu: DropdownMenu,
179
- Item: DropdownItem,
180
- Separator: DropdownSeparator,
181
- Label: DropdownLabel
182
- });
183
-
184
- export { Dropdown, DropdownItem, DropdownLabel, DropdownMenu, DropdownSeparator, DropdownTrigger, menuItemVariants, menuVariants };
185
- //# sourceMappingURL=index.mjs.map
2
+ import {forwardRef,Children,isValidElement,cloneElement,memo}from'react';import {MenuTrigger,Button,Popover,Menu,SubmenuTrigger,MenuItem,Separator,Header}from'react-aria-components';import {ChevronRight}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {cva}from'class-variance-authority';import {jsx,jsxs}from'react/jsx-runtime';function d(...e){return twMerge(clsx(e))}var b=cva("z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1",{variants:{variant:{default:""}},defaultVariants:{variant:"default"}}),w=cva("relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:""}},defaultVariants:{variant:"default"}});function P(e){if(typeof e=="function"||typeof e=="object")return e?.displayName}var E=forwardRef(({defaultOpen:e=false,isOpen:o,onOpenChange:n,children:t},p)=>{if(process.env.NODE_ENV!=="production"){let s=Children.toArray(t),i=s.some(a=>isValidElement(a)&&(a.type===f||P(a.type)==="DropdownTrigger")),c=s.some(a=>isValidElement(a)&&(a.type===l||P(a.type)==="DropdownMenu"));if(!i||!c)throw new Error("Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children")}return jsx(MenuTrigger,{defaultOpen:e,isOpen:o,onOpenChange:n,children:t})});E.displayName="Dropdown";var f=forwardRef(({children:e,...o},n)=>isValidElement(e)?cloneElement(e,{...o,slot:"trigger"}):jsx(Button,{ref:n,...o,children:e}));f.displayName="DropdownTrigger";var l=forwardRef(({align:e="start",side:o="bottom",className:n,children:t,...p},s)=>{let i=`${o} ${e}`;return jsx(Popover,{placement:i,className:"entering:animate-in exiting:animate-out",children:jsx(Menu,{className:d(b({variant:"default"}),n),...p,children:t})})});l.displayName="DropdownMenu";var x=forwardRef(({children:e,onAction:o,isDisabled:n=false,shortcut:t,icon:p,iconRight:s,className:i,"aria-label":c,...a},G)=>{let D=Children.toArray(e),y=u=>isValidElement(u)&&(u.type===l||P(u.type)==="DropdownMenu"),L=D.some(y),h=D.filter(u=>!y(u)),N=D.find(y);return L&&N?jsxs(SubmenuTrigger,{children:[jsxs(MenuItem,{"aria-label":c,className:d(w({variant:"default"}),i),...a,children:[p&&jsx("span",{className:"mr-2",children:p}),jsx("span",{className:"flex-1",children:h}),jsx(ChevronRight,{className:"ml-auto h-4 w-4","aria-hidden":"true"})]}),N]}):jsxs(MenuItem,{onAction:o,isDisabled:n,"aria-label":c,className:d(w({variant:"default"}),i),...a,children:[p&&jsx("span",{className:"mr-2",children:p}),jsx("span",{className:"flex-1",children:e}),s&&jsx("span",{className:"ml-auto",children:s}),t&&jsx("kbd",{className:"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100",children:t})]})});x.displayName="DropdownItem";var M=memo(forwardRef(({className:e,...o},n)=>jsx(Separator,{className:d("-mx-1 my-1 h-px bg-[var(--accent-background)]",e),...o})));M.displayName="DropdownSeparator";var T=memo(forwardRef(({children:e,className:o,...n},t)=>jsx(Header,{className:d("px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]",o),...n,children:e})));T.displayName="DropdownLabel";var F=Object.assign(E,{Trigger:f,Menu:l,Item:x,Separator:M,Label:T});export{F as Dropdown,x as DropdownItem,T as DropdownLabel,l as DropdownMenu,M as DropdownSeparator,f as DropdownTrigger,w as menuItemVariants,b as menuVariants};//# sourceMappingURL=index.mjs.map
186
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Dropdown/Dropdown.tsx"],"names":["AriaMenuTrigger","AriaButton","AriaPopover","AriaMenu","AriaSubmenuTrigger","AriaMenuItem","AriaSeparator","AriaHeader"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\n/**\n * Dropdown Menu Component\n * Accessible dropdown menu with React Aria primitives, nested submenus, and CVA styling\n *\n * @see spec.md FR-001 to FR-054 (Dropdown Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, Children, isValidElement, type ReactNode, type ReactElement, cloneElement } from 'react';\nimport {\n MenuTrigger as AriaMenuTrigger,\n SubmenuTrigger as AriaSubmenuTrigger,\n Button as AriaButton,\n Menu as AriaMenu,\n MenuItem as AriaMenuItem,\n Separator as AriaSeparator,\n Header as AriaHeader,\n Popover as AriaPopover,\n} from 'react-aria-components';\nimport { cva } from 'class-variance-authority';\nimport { ChevronRight } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n} from './Dropdown.types';\n\n/**\n * Menu variant styles using CVA\n * @see spec.md FR-040 (CVA for variant styling - single \"default\" variant for v1)\n */\nconst menuVariants = cva(\n // Base styles - semantic tokens with fallbacks\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Menu Item variant styles using CVA\n * @see spec.md FR-041 (CVA for item states: hover, focus, active, disabled)\n */\nconst menuItemVariants = cva(\n // Base styles - FR-014: 44x44px minimum touch targets\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Dropdown Root Component\n * Manages open/close state and coordinates Trigger and Menu children\n *\n * @see spec.md FR-001 to FR-007\n */\ninterface InternalDropdownProps extends DropdownProps {\n children: ReactNode;\n}\n\nconst DropdownRoot = forwardRef<HTMLDivElement, InternalDropdownProps>(\n ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {\n // Validate children: must have exactly one Trigger and one Menu\n const childArray = Children.toArray(children);\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownTrigger || (child.type as any).displayName === 'DropdownTrigger')\n );\n const hasMenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || (child.type as any).displayName === 'DropdownMenu')\n );\n\n if (!hasTrigger || !hasMenu) {\n throw new Error(\n 'Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children'\n );\n }\n\n return (\n <AriaMenuTrigger defaultOpen={defaultOpen} isOpen={isOpen} onOpenChange={onOpenChange}>\n {children}\n </AriaMenuTrigger>\n );\n }\n);\n\nDropdownRoot.displayName = 'Dropdown';\n\n/**\n * Dropdown.Trigger Component\n * Wraps trigger element (typically Button) with proper ARIA attributes\n *\n * @see spec.md FR-008 to FR-012\n */\nconst DropdownTrigger = forwardRef<HTMLButtonElement, DropdownTriggerProps>(\n ({ children, ...props }, ref) => {\n // Clone child and add ref if it's a single React element\n if (isValidElement(children)) {\n return cloneElement(children as ReactElement<any>, {\n ...props,\n slot: 'trigger',\n });\n }\n\n // Fallback: wrap in AriaButton if not a React element\n return (\n <AriaButton ref={ref} {...props}>\n {children}\n </AriaButton>\n );\n }\n);\n\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown.Menu Component\n * Renders menu with positioning, collision detection, and focus management\n *\n * @see spec.md FR-014 to FR-024\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ align = 'start', side = 'bottom', className, children, ...props }, _ref) => {\n // Map align to React Aria placement\n const placement = `${side} ${align}` as any;\n\n return (\n <AriaPopover placement={placement} className=\"entering:animate-in exiting:animate-out\">\n <AriaMenu\n className={cn(menuVariants({ variant: 'default' }), className)}\n {...props}\n >\n {children}\n </AriaMenu>\n </AriaPopover>\n );\n }\n);\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * Dropdown.Item Component\n * Menu item with action callbacks, disabled state, shortcuts, icons, and nested submenu support\n *\n * @see spec.md FR-025 to FR-034\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n (\n {\n children,\n onAction,\n isDisabled = false,\n shortcut,\n icon,\n iconRight,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n _ref\n ) => {\n // Check if this item contains a nested submenu\n const childArray = Children.toArray(children);\n const hasSubmenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || (child.type as any).displayName === 'DropdownMenu')\n );\n\n // Filter children to separate submenu from content\n const contentChildren = childArray.filter(\n (child) =>\n !isValidElement(child) ||\n (child.type !== DropdownMenu && (child.type as any).displayName !== 'DropdownMenu')\n );\n\n const submenu = childArray.find(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || (child.type as any).displayName === 'DropdownMenu')\n );\n\n if (hasSubmenu && submenu) {\n // Render as submenu trigger using React Aria's SubmenuTrigger\n return (\n <AriaSubmenuTrigger>\n <AriaMenuItem\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{contentChildren}</span>\n <ChevronRight className=\"ml-auto h-4 w-4\" aria-hidden=\"true\" />\n </AriaMenuItem>\n {submenu as ReactElement}\n </AriaSubmenuTrigger>\n );\n }\n\n // Regular menu item\n return (\n <AriaMenuItem\n onAction={onAction}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n {iconRight && <span className=\"ml-auto\">{iconRight}</span>}\n {shortcut && (\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100\">\n {shortcut}\n </kbd>\n )}\n </AriaMenuItem>\n );\n }\n);\n\nDropdownItem.displayName = 'DropdownItem';\n\n/**\n * Dropdown.Separator Component\n * Non-focusable visual divider\n *\n * @see spec.md FR-043 to FR-045\n */\nconst DropdownSeparator = memo(forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, _ref) => {\n return (\n <AriaSeparator\n className={cn(\n '-mx-1 my-1 h-px bg-[var(--accent-background)]',\n className\n )}\n {...props}\n />\n );\n }\n));\n\nDropdownSeparator.displayName = 'DropdownSeparator';\n\n/**\n * Dropdown.Label Component\n * Non-interactive section header\n *\n * @see spec.md FR-046 to FR-048\n */\nconst DropdownLabel = memo(forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ children, className, ...props }, _ref) => {\n return (\n <AriaHeader\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]',\n className\n )}\n {...props}\n >\n {children}\n </AriaHeader>\n );\n }\n));\n\nDropdownLabel.displayName = 'DropdownLabel';\n\n/**\n * Export compound component\n */\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n Separator: DropdownSeparator,\n Label: DropdownLabel,\n});\n\n// Export individual components for flexibility\nexport { DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel };\n\n// Export variant functions for external use\nexport { menuVariants, menuItemVariants };\n\n// Export types\nexport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n};\n"]}
1
+ {"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Dropdown/Dropdown.styles.ts","../../../src/elements/Dropdown/Dropdown.tsx"],"names":["cn","inputs","twMerge","clsx","menuVariants","cva","menuItemVariants","getDisplayName","type","DropdownRoot","forwardRef","defaultOpen","isOpen","onOpenChange","children","_ref","childArray","Children","hasTrigger","child","isValidElement","DropdownTrigger","hasMenu","DropdownMenu","jsx","AriaMenuTrigger","props","ref","cloneElement","AriaButton","align","side","className","placement","AriaPopover","AriaMenu","DropdownItem","onAction","isDisabled","shortcut","icon","iconRight","ariaLabel","isDropdownMenu","hasSubmenu","contentChildren","submenu","jsxs","AriaSubmenuTrigger","AriaMenuItem","ChevronRight","DropdownSeparator","memo","AriaSeparator","DropdownLabel","AriaHeader","Dropdown"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n/**\n * Menu variant styles using CVA\n * @see spec.md FR-040 (CVA for variant styling - single \"default\" variant for v1)\n */\nexport const menuVariants = cva(\n // Base styles - semantic tokens with fallbacks\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] shadow-md data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 p-1\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Menu Item variant styles using CVA\n * @see spec.md FR-041 (CVA for item states: hover, focus, active, disabled)\n */\nexport const menuItemVariants = cva(\n // Base styles - FR-014: 44x44px minimum touch targets\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Type exports for variant props\n * Allows TypeScript inference of variant combinations\n */\nexport type MenuVariantProps = VariantProps<typeof menuVariants>;\nexport type MenuItemVariantProps = VariantProps<typeof menuItemVariants>;\n","\"use client\";\n\n/**\n * Dropdown Menu Component\n * Accessible dropdown menu with React Aria primitives, nested submenus, and CVA styling\n *\n * @see spec.md FR-001 to FR-054 (Dropdown Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, Children, isValidElement, type ReactNode, type ReactElement, cloneElement, type ComponentType } from 'react';\nimport type { Placement } from 'react-aria';\nimport {\n MenuTrigger as AriaMenuTrigger,\n SubmenuTrigger as AriaSubmenuTrigger,\n Button as AriaButton,\n Menu as AriaMenu,\n MenuItem as AriaMenuItem,\n Separator as AriaSeparator,\n Header as AriaHeader,\n Popover as AriaPopover,\n} from 'react-aria-components';\nimport { ChevronRight } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { menuVariants, menuItemVariants } from './Dropdown.styles';\nimport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n} from './Dropdown.types';\n\n/**\n * Type-safe helper to get displayName from a component type.\n */\nfunction getDisplayName(type: unknown): string | undefined {\n if (typeof type === 'function' || typeof type === 'object') {\n return (type as ComponentType)?.displayName;\n }\n return undefined;\n}\n\n/**\n * Dropdown Root Component\n * Manages open/close state and coordinates Trigger and Menu children\n *\n * @see spec.md FR-001 to FR-007\n */\ninterface InternalDropdownProps extends DropdownProps {\n children: ReactNode;\n}\n\nconst DropdownRoot = forwardRef<HTMLDivElement, InternalDropdownProps>(\n ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {\n // Validate children structure in development only\n if (process.env.NODE_ENV !== 'production') {\n const childArray = Children.toArray(children);\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownTrigger || getDisplayName(child.type) === 'DropdownTrigger')\n );\n const hasMenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu')\n );\n\n if (!hasTrigger || !hasMenu) {\n throw new Error(\n 'Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children'\n );\n }\n }\n\n return (\n <AriaMenuTrigger defaultOpen={defaultOpen} isOpen={isOpen} onOpenChange={onOpenChange}>\n {children}\n </AriaMenuTrigger>\n );\n }\n);\n\nDropdownRoot.displayName = 'Dropdown';\n\n/**\n * Dropdown.Trigger Component\n * Wraps trigger element (typically Button) with proper ARIA attributes\n *\n * @see spec.md FR-008 to FR-012\n */\nconst DropdownTrigger = forwardRef<HTMLButtonElement, DropdownTriggerProps>(\n ({ children, ...props }, ref) => {\n // Clone child and add ref if it's a single React element\n if (isValidElement(children)) {\n return cloneElement(children as ReactElement<Record<string, unknown>>, {\n ...props,\n slot: 'trigger',\n });\n }\n\n // Fallback: wrap in AriaButton if not a React element\n return (\n <AriaButton ref={ref} {...props}>\n {children}\n </AriaButton>\n );\n }\n);\n\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown.Menu Component\n * Renders menu with positioning, collision detection, and focus management\n *\n * @see spec.md FR-014 to FR-024\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ align = 'start', side = 'bottom', className, children, ...props }, _ref) => {\n // Map align to React Aria placement\n const placement = `${side} ${align}` as Placement;\n\n return (\n <AriaPopover placement={placement} className=\"entering:animate-in exiting:animate-out\">\n <AriaMenu\n className={cn(menuVariants({ variant: 'default' }), className)}\n {...props}\n >\n {children}\n </AriaMenu>\n </AriaPopover>\n );\n }\n);\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * Dropdown.Item Component\n * Menu item with action callbacks, disabled state, shortcuts, icons, and nested submenu support\n *\n * @see spec.md FR-025 to FR-034\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n (\n {\n children,\n onAction,\n isDisabled = false,\n shortcut,\n icon,\n iconRight,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n _ref\n ) => {\n // Check if this item contains a nested submenu\n const childArray = Children.toArray(children);\n const isDropdownMenu = (child: unknown): boolean =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu');\n\n const hasSubmenu = childArray.some(isDropdownMenu);\n\n // Filter children to separate submenu from content\n const contentChildren = childArray.filter((child) => !isDropdownMenu(child));\n\n const submenu = childArray.find(isDropdownMenu);\n\n if (hasSubmenu && submenu) {\n // Render as submenu trigger using React Aria's SubmenuTrigger\n return (\n <AriaSubmenuTrigger>\n <AriaMenuItem\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{contentChildren}</span>\n <ChevronRight className=\"ml-auto h-4 w-4\" aria-hidden=\"true\" />\n </AriaMenuItem>\n {submenu as ReactElement}\n </AriaSubmenuTrigger>\n );\n }\n\n // Regular menu item\n return (\n <AriaMenuItem\n onAction={onAction}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n {iconRight && <span className=\"ml-auto\">{iconRight}</span>}\n {shortcut && (\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100\">\n {shortcut}\n </kbd>\n )}\n </AriaMenuItem>\n );\n }\n);\n\nDropdownItem.displayName = 'DropdownItem';\n\n/**\n * Dropdown.Separator Component\n * Non-focusable visual divider\n *\n * @see spec.md FR-043 to FR-045\n */\nconst DropdownSeparator = memo(forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, _ref) => {\n return (\n <AriaSeparator\n className={cn(\n '-mx-1 my-1 h-px bg-[var(--accent-background)]',\n className\n )}\n {...props}\n />\n );\n }\n));\n\nDropdownSeparator.displayName = 'DropdownSeparator';\n\n/**\n * Dropdown.Label Component\n * Non-interactive section header\n *\n * @see spec.md FR-046 to FR-048\n */\nconst DropdownLabel = memo(forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ children, className, ...props }, _ref) => {\n return (\n <AriaHeader\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]',\n className\n )}\n {...props}\n >\n {children}\n </AriaHeader>\n );\n }\n));\n\nDropdownLabel.displayName = 'DropdownLabel';\n\n/**\n * Export compound component via Object.assign for backwards compatibility.\n * Enables `<Dropdown.Trigger>`, `<Dropdown.Menu>`, etc.\n *\n * @deprecated v2 — Remove Object.assign pattern in favour of direct named exports\n * (DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel)\n * for better tree-shaking. See named exports below.\n */\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n Separator: DropdownSeparator,\n Label: DropdownLabel,\n});\n\n// Export individual components for flexibility\nexport { DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel };\n\n// Export variant functions for external use\nexport { menuVariants, menuItemVariants };\n\n// Export types\nexport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n};\n"]}