@cl-light-ds/ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +45 -45
  2. package/package.json +1 -1
  3. package/src/components/accordion/Accordion.astro +248 -248
  4. package/src/components/accordion/AccordionContent.astro +26 -26
  5. package/src/components/accordion/AccordionItem.astro +36 -36
  6. package/src/components/accordion/AccordionTrigger.astro +118 -118
  7. package/src/components/accordion/CHANGELOG.md +41 -41
  8. package/src/components/accordion/index.ts +4 -4
  9. package/src/components/alert/Alert.astro +167 -167
  10. package/src/components/alert/AlertDescription.astro +24 -24
  11. package/src/components/alert/AlertTitle.astro +24 -24
  12. package/src/components/alert/CHANGELOG.md +5 -5
  13. package/src/components/alert/index.ts +4 -4
  14. package/src/components/avatar/Avatar.astro +197 -197
  15. package/src/components/avatar/AvatarBadge.astro +44 -44
  16. package/src/components/avatar/AvatarFallback.astro +26 -26
  17. package/src/components/avatar/AvatarGroup.astro +26 -26
  18. package/src/components/avatar/AvatarGroupCount.astro +30 -30
  19. package/src/components/avatar/AvatarImage.astro +46 -46
  20. package/src/components/avatar/CHANGELOG.md +44 -44
  21. package/src/components/avatar/index.ts +6 -6
  22. package/src/components/badge/Badge.astro +167 -167
  23. package/src/components/badge/CHANGELOG.md +49 -49
  24. package/src/components/badge/index.ts +2 -2
  25. package/src/components/breadcrumb/Breadcrumb.astro +76 -76
  26. package/src/components/breadcrumb/BreadcrumbItem.astro +32 -32
  27. package/src/components/breadcrumb/BreadcrumbList.astro +26 -26
  28. package/src/components/breadcrumb/BreadcrumbSeparator.astro +26 -26
  29. package/src/components/breadcrumb/CHANGELOG.md +24 -24
  30. package/src/components/breadcrumb/index.ts +5 -5
  31. package/src/components/button/Button.astro +233 -233
  32. package/src/components/button/CHANGELOG.md +41 -41
  33. package/src/components/button/index.ts +2 -2
  34. package/src/components/button-group/ButtonGroup.astro +130 -130
  35. package/src/components/button-group/ButtonGroupSeparator.astro +30 -30
  36. package/src/components/button-group/ButtonGroupText.astro +21 -21
  37. package/src/components/button-group/CHANGELOG.md +34 -34
  38. package/src/components/button-group/index.ts +3 -3
  39. package/src/components/card/CHANGELOG.md +162 -119
  40. package/src/components/card/Card.astro +197 -182
  41. package/src/components/card/CardAction.astro +26 -26
  42. package/src/components/card/CardContent.astro +28 -28
  43. package/src/components/card/CardDescription.astro +28 -28
  44. package/src/components/card/CardFooter.astro +24 -24
  45. package/src/components/card/CardHeader.astro +30 -30
  46. package/src/components/card/CardMedia.astro +27 -27
  47. package/src/components/card/CardMediaActions.astro +21 -0
  48. package/src/components/card/CardMediaSelect.astro +21 -0
  49. package/src/components/card/CardOverlay.astro +32 -32
  50. package/src/components/card/CardTitle.astro +21 -21
  51. package/src/components/card/index.ts +12 -10
  52. package/src/components/carousel/CHANGELOG.md +5 -5
  53. package/src/components/carousel/Carousel.astro +106 -106
  54. package/src/components/carousel/CarouselSlide.astro +22 -22
  55. package/src/components/carousel/index.ts +3 -3
  56. package/src/components/checkbox/CHANGELOG.md +58 -58
  57. package/src/components/checkbox/Checkbox.astro +159 -159
  58. package/src/components/checkbox/index.ts +1 -1
  59. package/src/components/collapsible/CHANGELOG.md +5 -5
  60. package/src/components/collapsible/Collapsible.astro +202 -202
  61. package/src/components/collapsible/CollapsibleContent.astro +36 -36
  62. package/src/components/collapsible/CollapsibleTrigger.astro +34 -34
  63. package/src/components/collapsible/index.ts +4 -4
  64. package/src/components/combobox/CHANGELOG.md +27 -27
  65. package/src/components/combobox/Combobox.astro +365 -365
  66. package/src/components/combobox/ComboboxContent.astro +37 -37
  67. package/src/components/combobox/ComboboxEmpty.astro +18 -18
  68. package/src/components/combobox/ComboboxGroup.astro +19 -19
  69. package/src/components/combobox/ComboboxInput.astro +74 -74
  70. package/src/components/combobox/ComboboxItem.astro +39 -39
  71. package/src/components/combobox/ComboboxLabel.astro +18 -18
  72. package/src/components/combobox/ComboboxList.astro +21 -21
  73. package/src/components/combobox/ComboboxSeparator.astro +17 -17
  74. package/src/components/combobox/ComboboxTrigger.astro +30 -30
  75. package/src/components/combobox/ComboboxValue.astro +22 -22
  76. package/src/components/combobox/index.ts +11 -11
  77. package/src/components/date/CHANGELOG.md +18 -18
  78. package/src/components/date/Date.astro +137 -137
  79. package/src/components/date/index.ts +2 -2
  80. package/src/components/dialog/CHANGELOG.md +39 -39
  81. package/src/components/dialog/Dialog.astro +196 -196
  82. package/src/components/dialog/DialogClose.astro +23 -23
  83. package/src/components/dialog/DialogContent.astro +42 -42
  84. package/src/components/dialog/DialogDescription.astro +18 -18
  85. package/src/components/dialog/DialogFooter.astro +18 -18
  86. package/src/components/dialog/DialogHeader.astro +18 -18
  87. package/src/components/dialog/DialogOverlay.astro +19 -19
  88. package/src/components/dialog/DialogTitle.astro +18 -18
  89. package/src/components/dialog/DialogTrigger.astro +37 -37
  90. package/src/components/dialog/index.ts +9 -9
  91. package/src/components/dropdown-menu/CHANGELOG.md +194 -194
  92. package/src/components/dropdown-menu/DropdownMenu.astro +226 -226
  93. package/src/components/dropdown-menu/DropdownMenuCheckboxItem.astro +114 -114
  94. package/src/components/dropdown-menu/DropdownMenuContent.astro +42 -42
  95. package/src/components/dropdown-menu/DropdownMenuGroup.astro +19 -19
  96. package/src/components/dropdown-menu/DropdownMenuItem.astro +220 -220
  97. package/src/components/dropdown-menu/DropdownMenuItemContent.astro +79 -79
  98. package/src/components/dropdown-menu/DropdownMenuLabel.astro +20 -20
  99. package/src/components/dropdown-menu/DropdownMenuPortal.astro +13 -13
  100. package/src/components/dropdown-menu/DropdownMenuRadioGroup.astro +13 -13
  101. package/src/components/dropdown-menu/DropdownMenuRadioItem.astro +101 -101
  102. package/src/components/dropdown-menu/DropdownMenuSeparator.astro +18 -18
  103. package/src/components/dropdown-menu/DropdownMenuShortcut.astro +18 -18
  104. package/src/components/dropdown-menu/DropdownMenuTrigger.astro +49 -49
  105. package/src/components/dropdown-menu/dropdown-menu-item-variants.ts +24 -24
  106. package/src/components/dropdown-menu/index.ts +12 -12
  107. package/src/components/field/CHANGELOG.md +33 -33
  108. package/src/components/field/Field.astro +664 -664
  109. package/src/components/field/FieldContent.astro +20 -20
  110. package/src/components/field/FieldDescription.astro +22 -22
  111. package/src/components/field/FieldError.astro +51 -51
  112. package/src/components/field/FieldGroup.astro +20 -20
  113. package/src/components/field/FieldLabel.astro +22 -22
  114. package/src/components/field/FieldLegend.astro +23 -23
  115. package/src/components/field/FieldSeparator.astro +30 -30
  116. package/src/components/field/FieldSet.astro +20 -20
  117. package/src/components/field/FieldTitle.astro +20 -20
  118. package/src/components/field/index.ts +10 -10
  119. package/src/components/hover-card/CHANGELOG.md +20 -20
  120. package/src/components/hover-card/HoverCard.astro +235 -235
  121. package/src/components/hover-card/HoverCardContent.astro +54 -54
  122. package/src/components/hover-card/HoverCardTrigger.astro +38 -38
  123. package/src/components/hover-card/index.ts +3 -3
  124. package/src/components/input/CHANGELOG.md +29 -29
  125. package/src/components/input/Input.astro +130 -130
  126. package/src/components/input/index.ts +2 -2
  127. package/src/components/input-group/CHANGELOG.md +49 -49
  128. package/src/components/input-group/InputGroup.astro +135 -135
  129. package/src/components/input-group/InputGroupAddon.astro +49 -49
  130. package/src/components/input-group/InputGroupButton.astro +58 -58
  131. package/src/components/input-group/InputGroupInput.astro +18 -18
  132. package/src/components/input-group/InputGroupText.astro +21 -21
  133. package/src/components/input-group/InputGroupTextarea.astro +17 -17
  134. package/src/components/input-group/controlClasses.ts +2 -2
  135. package/src/components/input-group/index.ts +6 -6
  136. package/src/components/item/CHANGELOG.md +27 -27
  137. package/src/components/item/Item.astro +122 -122
  138. package/src/components/item/ItemActions.astro +21 -21
  139. package/src/components/item/ItemContent.astro +25 -25
  140. package/src/components/item/ItemDescription.astro +25 -25
  141. package/src/components/item/ItemFooter.astro +24 -24
  142. package/src/components/item/ItemGroup.astro +24 -24
  143. package/src/components/item/ItemHeader.astro +24 -24
  144. package/src/components/item/ItemMedia.astro +47 -47
  145. package/src/components/item/ItemSeparator.astro +21 -21
  146. package/src/components/item/ItemTitle.astro +25 -25
  147. package/src/components/item/index.ts +10 -10
  148. package/src/components/kbd/CHANGELOG.md +5 -5
  149. package/src/components/kbd/Kbd.astro +145 -145
  150. package/src/components/kbd/KbdGroup.astro +55 -55
  151. package/src/components/kbd/index.ts +2 -2
  152. package/src/components/label/CHANGELOG.md +28 -28
  153. package/src/components/label/Label.astro +97 -97
  154. package/src/components/label/index.ts +2 -2
  155. package/src/components/link-group/CHANGELOG.md +75 -75
  156. package/src/components/link-group/LinkGroup.astro +67 -67
  157. package/src/components/link-group/LinkGroupItem.astro +32 -32
  158. package/src/components/link-group/LinkGroupList.astro +25 -25
  159. package/src/components/link-group/LinkGroupTitle.astro +22 -22
  160. package/src/components/link-group/index.ts +5 -5
  161. package/src/components/link-group/link-group-list-variants.ts +15 -15
  162. package/src/components/marquee/CHANGELOG.md +5 -5
  163. package/src/components/marquee/Marquee.astro +119 -119
  164. package/src/components/marquee/index.ts +2 -2
  165. package/src/components/native-select/CHANGELOG.md +5 -5
  166. package/src/components/native-select/NativeSelect.astro +125 -125
  167. package/src/components/native-select/NativeSelectOptGroup.astro +14 -14
  168. package/src/components/native-select/NativeSelectOption.astro +9 -9
  169. package/src/components/native-select/index.ts +3 -3
  170. package/src/components/navigation-menu/CHANGELOG.md +63 -63
  171. package/src/components/navigation-menu/NavigationMenu.astro +414 -414
  172. package/src/components/navigation-menu/NavigationMenuContent.astro +37 -37
  173. package/src/components/navigation-menu/NavigationMenuIndicator.astro +24 -24
  174. package/src/components/navigation-menu/NavigationMenuItem.astro +22 -22
  175. package/src/components/navigation-menu/NavigationMenuLink.astro +18 -18
  176. package/src/components/navigation-menu/NavigationMenuList.astro +21 -21
  177. package/src/components/navigation-menu/NavigationMenuPositioner.astro +44 -44
  178. package/src/components/navigation-menu/NavigationMenuTrigger.astro +30 -30
  179. package/src/components/navigation-menu/NavigationMenuViewport.astro +19 -19
  180. package/src/components/navigation-menu/index.ts +10 -10
  181. package/src/components/organisms/lightning-sidebar-nav/CHANGELOG.md +50 -0
  182. package/src/components/organisms/lightning-sidebar-nav/LightningSidebarNav.astro +176 -0
  183. package/src/components/organisms/lightning-sidebar-nav/SidebarNav.astro +50 -0
  184. package/src/components/organisms/lightning-sidebar-nav/SidebarNavGroup.astro +74 -0
  185. package/src/components/organisms/lightning-sidebar-nav/SidebarNavItem.astro +94 -0
  186. package/src/components/organisms/lightning-sidebar-nav/SidebarNavProBadge.astro +26 -0
  187. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSection.astro +71 -0
  188. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSkeleton.astro +67 -0
  189. package/src/components/organisms/lightning-sidebar-nav/SidebarNavSubItem.astro +69 -0
  190. package/src/components/organisms/lightning-sidebar-nav/SidebarNavUsage.astro +78 -0
  191. package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceAvatar.astro +46 -0
  192. package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceSwitcher.astro +130 -0
  193. package/src/components/organisms/lightning-sidebar-nav/icons.ts +46 -0
  194. package/src/components/organisms/lightning-sidebar-nav/index.ts +18 -0
  195. package/src/components/organisms/lightning-sidebar-nav/types.ts +77 -0
  196. package/src/components/popover/CHANGELOG.md +20 -20
  197. package/src/components/popover/Popover.astro +211 -211
  198. package/src/components/popover/PopoverClose.astro +18 -18
  199. package/src/components/popover/PopoverContent.astro +50 -50
  200. package/src/components/popover/PopoverDescription.astro +18 -18
  201. package/src/components/popover/PopoverHeader.astro +18 -18
  202. package/src/components/popover/PopoverTitle.astro +18 -18
  203. package/src/components/popover/PopoverTrigger.astro +35 -35
  204. package/src/components/popover/index.ts +7 -7
  205. package/src/components/radio-group/CHANGELOG.md +31 -31
  206. package/src/components/radio-group/RadioGroup.astro +81 -81
  207. package/src/components/radio-group/RadioGroupItem.astro +51 -51
  208. package/src/components/radio-group/index.ts +3 -3
  209. package/src/components/select/CHANGELOG.md +39 -39
  210. package/src/components/select/Select.astro +373 -373
  211. package/src/components/select/SelectContent.astro +91 -91
  212. package/src/components/select/SelectGroup.astro +19 -19
  213. package/src/components/select/SelectItem.astro +48 -48
  214. package/src/components/select/SelectLabel.astro +18 -18
  215. package/src/components/select/SelectSeparator.astro +17 -17
  216. package/src/components/select/SelectTrigger.astro +34 -34
  217. package/src/components/select/SelectValue.astro +22 -22
  218. package/src/components/select/index.ts +8 -8
  219. package/src/components/separator/CHANGELOG.md +5 -5
  220. package/src/components/separator/Separator.astro +60 -60
  221. package/src/components/separator/index.ts +2 -2
  222. package/src/components/skeleton/CHANGELOG.md +5 -5
  223. package/src/components/skeleton/Skeleton.astro +121 -121
  224. package/src/components/skeleton/index.ts +1 -1
  225. package/src/components/slider/CHANGELOG.md +5 -5
  226. package/src/components/slider/Slider.astro +198 -198
  227. package/src/components/slider/index.ts +1 -1
  228. package/src/components/spinner/CHANGELOG.md +18 -18
  229. package/src/components/spinner/Spinner.astro +135 -135
  230. package/src/components/spinner/index.ts +1 -1
  231. package/src/components/sticky-surface/CHANGELOG.md +5 -5
  232. package/src/components/sticky-surface/StickySurface.astro +152 -152
  233. package/src/components/sticky-surface/index.ts +2 -2
  234. package/src/components/switch/CHANGELOG.md +29 -29
  235. package/src/components/switch/Switch.astro +106 -106
  236. package/src/components/switch/index.ts +1 -1
  237. package/src/components/table/CHANGELOG.md +24 -24
  238. package/src/components/table/Table.astro +358 -251
  239. package/src/components/table/TableBody.astro +17 -18
  240. package/src/components/table/TableBulkToolbar.astro +37 -0
  241. package/src/components/table/TableCaption.astro +17 -17
  242. package/src/components/table/TableCell.astro +45 -21
  243. package/src/components/table/TableCellText.astro +17 -0
  244. package/src/components/table/TableColumnMenu.astro +50 -0
  245. package/src/components/table/TableEditableCell.astro +287 -0
  246. package/src/components/table/TableEmpty.astro +17 -0
  247. package/src/components/table/TableFolderCell.astro +38 -0
  248. package/src/components/table/TableFooter.astro +21 -21
  249. package/src/components/table/TableHead.astro +90 -21
  250. package/src/components/table/TableHeader.astro +17 -17
  251. package/src/components/table/TablePagination.astro +57 -0
  252. package/src/components/table/TableRow.astro +52 -21
  253. package/src/components/table/TableSelectAllBanner.astro +34 -0
  254. package/src/components/table/TableSelectCell.astro +50 -0
  255. package/src/components/table/TableSkeletonRow.astro +21 -0
  256. package/src/components/table/index.ts +19 -9
  257. package/src/components/table/table-cell-variants.ts +29 -0
  258. package/src/components/tabs/CHANGELOG.md +5 -5
  259. package/src/components/tabs/Tabs.astro +306 -306
  260. package/src/components/tabs/TabsContent.astro +47 -47
  261. package/src/components/tabs/TabsList.astro +69 -69
  262. package/src/components/tabs/TabsTrigger.astro +40 -40
  263. package/src/components/tabs/index.ts +6 -6
  264. package/src/components/textarea/CHANGELOG.md +22 -22
  265. package/src/components/textarea/Textarea.astro +58 -58
  266. package/src/components/textarea/index.ts +2 -2
  267. package/src/components/toggle/CHANGELOG.md +23 -23
  268. package/src/components/toggle/Toggle.astro +150 -150
  269. package/src/components/toggle/index.ts +1 -1
  270. package/src/components/toggle-group/CHANGELOG.md +18 -18
  271. package/src/components/toggle-group/ToggleGroup.astro +236 -236
  272. package/src/components/toggle-group/ToggleGroupItem.astro +48 -48
  273. package/src/components/toggle-group/index.ts +2 -2
  274. package/src/components/tooltip/CHANGELOG.md +22 -22
  275. package/src/components/tooltip/Tooltip.astro +357 -357
  276. package/src/components/tooltip/TooltipContent.astro +85 -85
  277. package/src/components/tooltip/TooltipTrigger.astro +34 -34
  278. package/src/components/tooltip/index.ts +3 -3
  279. package/src/lib/table-controller.ts +1090 -0
  280. package/src/lib/toggle-group-controller.ts +113 -113
  281. package/src/lib/toggle-shared.ts +27 -27
  282. package/src/lib/utils.ts +6 -6
  283. package/src/styles/globals.css +197 -177
@@ -1,19 +1,19 @@
1
- ---
2
- import { cn } from "@cl-light-ds/ui/lib/utils";
3
- import type { HTMLAttributes } from "astro/types";
4
-
5
- interface Props extends HTMLAttributes<"div"> {
6
- class?: string;
7
- }
8
-
9
- const { class: className = "", ...rest } = Astro.props as Props;
10
- ---
11
-
12
- <div
13
- hidden
14
- data-slot="dialog-overlay"
15
- class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className)}
16
- {...rest}
17
- >
18
- <slot />
19
- </div>
1
+ ---
2
+ import { cn } from "@cl-light-ds/ui/lib/utils";
3
+ import type { HTMLAttributes } from "astro/types";
4
+
5
+ interface Props extends HTMLAttributes<"div"> {
6
+ class?: string;
7
+ }
8
+
9
+ const { class: className = "", ...rest } = Astro.props as Props;
10
+ ---
11
+
12
+ <div
13
+ hidden
14
+ data-slot="dialog-overlay"
15
+ class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className)}
16
+ {...rest}
17
+ >
18
+ <slot />
19
+ </div>
@@ -1,18 +1,18 @@
1
- ---
2
- import { cn } from "@cl-light-ds/ui/lib/utils";
3
- import type { HTMLAttributes } from "astro/types";
4
-
5
- interface Props extends HTMLAttributes<"div"> {
6
- class?: string;
7
- }
8
-
9
- const { class: className = "", ...rest } = Astro.props as Props;
10
- ---
11
-
12
- <div
13
- {...rest}
14
- data-slot="dialog-title"
15
- class={cn("text-xl leading-6 font-semibold cn-font-heading", className)}
16
- >
17
- <slot />
18
- </div>
1
+ ---
2
+ import { cn } from "@cl-light-ds/ui/lib/utils";
3
+ import type { HTMLAttributes } from "astro/types";
4
+
5
+ interface Props extends HTMLAttributes<"div"> {
6
+ class?: string;
7
+ }
8
+
9
+ const { class: className = "", ...rest } = Astro.props as Props;
10
+ ---
11
+
12
+ <div
13
+ {...rest}
14
+ data-slot="dialog-title"
15
+ class={cn("text-xl leading-6 font-semibold cn-font-heading", className)}
16
+ >
17
+ <slot />
18
+ </div>
@@ -1,37 +1,37 @@
1
- ---
2
- import { cn } from "@cl-light-ds/ui/lib/utils";
3
- import type { HTMLAttributes } from "astro/types";
4
-
5
- interface Props extends HTMLAttributes<"button"> {
6
- class?: string;
7
- /** Radix-like: render wrapper so the child can be the interactive element */
8
- asChild?: boolean;
9
- }
10
-
11
- const {
12
- class: className = "",
13
- asChild = false,
14
- type = "button",
15
- ...rest
16
- } = Astro.props as Props;
17
-
18
- const defaultClasses =
19
- "cursor-pointer select-none outline-none group-focus-within:pointer-events-none inline-flex items-center gap-1";
20
- ---
21
-
22
- {
23
- asChild ? (
24
- <div data-slot="dialog-trigger" data-as-child class={cn("", defaultClasses, className)}>
25
- <slot />
26
- </div>
27
- ) : (
28
- <button
29
- {...rest}
30
- type={type}
31
- data-slot="dialog-trigger"
32
- class={cn("", defaultClasses, className)}
33
- >
34
- <slot />
35
- </button>
36
- )
37
- }
1
+ ---
2
+ import { cn } from "@cl-light-ds/ui/lib/utils";
3
+ import type { HTMLAttributes } from "astro/types";
4
+
5
+ interface Props extends HTMLAttributes<"button"> {
6
+ class?: string;
7
+ /** Radix-like: render wrapper so the child can be the interactive element */
8
+ asChild?: boolean;
9
+ }
10
+
11
+ const {
12
+ class: className = "",
13
+ asChild = false,
14
+ type = "button",
15
+ ...rest
16
+ } = Astro.props as Props;
17
+
18
+ const defaultClasses =
19
+ "cursor-pointer select-none outline-none group-focus-within:pointer-events-none inline-flex items-center gap-1";
20
+ ---
21
+
22
+ {
23
+ asChild ? (
24
+ <div data-slot="dialog-trigger" data-as-child class={cn("", defaultClasses, className)}>
25
+ <slot />
26
+ </div>
27
+ ) : (
28
+ <button
29
+ {...rest}
30
+ type={type}
31
+ data-slot="dialog-trigger"
32
+ class={cn("", defaultClasses, className)}
33
+ >
34
+ <slot />
35
+ </button>
36
+ )
37
+ }
@@ -1,9 +1,9 @@
1
- export { default as Dialog } from "./Dialog.astro";
2
- export { default as DialogTitle } from "./DialogTitle.astro";
3
- export { default as DialogDescription } from "./DialogDescription.astro";
4
- export { default as DialogContent } from "./DialogContent.astro";
5
- export { default as DialogFooter } from "./DialogFooter.astro";
6
- export { default as DialogClose } from "./DialogClose.astro";
7
- export { default as DialogHeader } from "./DialogHeader.astro";
8
- export { default as DialogTrigger } from "./DialogTrigger.astro";
9
- export { default as DialogOverlay } from "./DialogOverlay.astro";
1
+ export { default as Dialog } from "./Dialog.astro";
2
+ export { default as DialogTitle } from "./DialogTitle.astro";
3
+ export { default as DialogDescription } from "./DialogDescription.astro";
4
+ export { default as DialogContent } from "./DialogContent.astro";
5
+ export { default as DialogFooter } from "./DialogFooter.astro";
6
+ export { default as DialogClose } from "./DialogClose.astro";
7
+ export { default as DialogHeader } from "./DialogHeader.astro";
8
+ export { default as DialogTrigger } from "./DialogTrigger.astro";
9
+ export { default as DialogOverlay } from "./DialogOverlay.astro";
@@ -1,194 +1,194 @@
1
- # Changelog
2
-
3
- All notable changes to the `DropdownMenu` component will be documented in this file.
4
-
5
- ## Date 10th Sep 2026
6
- ## Figma alignment (node 2329-6521, prop table 7392-10142)
7
-
8
- ### Variants
9
-
10
- - Added a `category` variant to `DropdownMenuItem` (`variant: "default" | "destructive" | "category"`, was `"default" | "destructive"`), matching Figma's `.item` component set which documents `Category` as a third item variant. Renders as a non-interactive (`role="presentation"`, `tabindex={-1}`, `pointer-events-none`), muted (`text-muted-foreground font-medium`) row — the visual is intentionally close to the existing `DropdownMenuLabel`, but this variant lives on `DropdownMenuItem` itself so it can sit inline in a list without an extra import, per Figma's own prop table contract. It does not render a separator automatically — pair it with the existing `<DropdownMenuSeparator />` if a divider is wanted, same as any other item.
11
- - Converted `DropdownMenuItem` from hardcoded `data-[variant=...]:` Tailwind selectors to `class-variance-authority` (`cva`), matching the pattern already used by `Card`/`Button`/`Badge`/`Avatar`.
12
-
13
- ### Sizing & Spacing
14
-
15
- - **Radius:** `rounded-sm` (4px) → `rounded-lg` (8px) on `DropdownMenuItem`, `DropdownMenuCheckboxItem`, and `DropdownMenuRadioItem` — Figma's item box is consistently `rounded-[8px]`.
16
- - **Padding:** `py-1.5` (6px) → `py-1` (4px) on all three item components — Figma's item is `py-[4px]` (`spacing/1`), horizontal `px-2` (`spacing/2`, 8px) was already correct.
17
- - **Typography:** item label moved from unstyled `text-sm` (14px, regular) → `text-xs font-semibold` (12px/600) on all three item components, matching Figma's `text/sm/sm-semibold` text style for the item label. Supportive text (new, see below) is `text-xs font-normal text-muted-foreground`.
18
- - **Popover chrome** (`DropdownMenuContent`): `ring-1 ring-foreground/10` → `border border-border` (Figma uses a real 1px border, not a ring); `shadow-md` → Figma's actual 3-layer `shadow-lg` drop-shadow (`0.3px 2px/-2.2 spread #1F003B05, 0.5px 3.2px/-1.4 #1F003B08, 0.7px 4px/-1.8 #1F003B0F`); `p-1` (4px) → `p-2` (8px); added an explicit `gap-1.5` (6px) between items, matching Figma's item-to-item gap (previously no gap was set at all, relying on nothing — items had no separation beyond their own padding).
19
-
20
- ### New Props (`DropdownMenuItem` only)
21
-
22
- Following the Button/Badge "boolean prop, auto-detected from a named slot via `Astro.slots.has(...)`" convention:
23
-
24
- - `checked?: boolean` (default `false`) — presentational checked state, only visible when `showCheckbox` is also set.
25
- - `showCheckbox?: boolean` (default `false`) — reserves a 20px leading slot for a checkmark; **kept the existing indicator pattern** (no visible box at rest, a checkmark fades in when `checked`), matching `DropdownMenuCheckboxItem`'s existing visual language rather than inventing Figma's filled-square glyph, which has no documented unchecked state in the file. `DropdownMenuCheckboxItem` itself is unchanged — this is a separate, presentation-only affordance for a plain `DropdownMenuItem`.
26
- - `leadingIcon?: boolean` (default: has a `leading-icon` slot) — renders `<slot name="leading-icon" />` at 20px.
27
- - `avatar?: boolean` (default: has an `avatar` slot) — renders `<slot name="avatar" />`. Use `<Avatar size="sm">` (24px) — it already matches Figma's item avatar size exactly, no new Avatar sizing needed.
28
- - `showBadge?: boolean` (default: has a `badge` slot) — renders `<slot name="badge" />`. Use `<Badge size="sm">`.
29
- - `showSubmenuIcon?: boolean` (default `false`) — renders a static 20px chevron-right. **Cosmetic only** — there is no nested-submenu infrastructure (flyout positioning, keyboard handling) anywhere in `DropdownMenu` yet. See "Flagged for the designer" below.
30
- - `supportiveText?: boolean` (default: has a `supportive-text` slot) — renders a second, muted line under the item label via `<slot name="supportive-text" />`.
31
-
32
- `leadingIcon`, `avatar`, and `showCheckbox` are independent booleans (can combine), per Figma's literal prop table — not consolidated into a single `leading` enum.
33
-
34
- ### Trigger
35
-
36
- - `DropdownMenuTrigger` now defaults `variant="outline"` (was inheriting `Button`'s own default `"default"`/primary-blue variant) — Figma's default/closed trigger state is a white/bordered button, not primary. Still fully overridable via the existing `variant` prop.
37
- - `DropdownMenuTrigger` now renders a default trailing chevron (`ChevronDown` from `@lucide/astro`) when the consumer doesn't slot their own `tail-icon` content — Figma's trigger always shows a chevron as core anatomy, not an opt-in add-on. It rotates 180° when the menu is open via a new `group/dropdown-menu` marker added to `DropdownMenu.astro`'s root (`data-state` lands on that root element, confirmed in `@data-slot/dropdown-menu`'s runtime). Pass `tailIcon={false}` to opt out entirely, or your own `<Icon slot="tail-icon" />` to override.
38
-
39
- ### Tokens (`globals.css`)
40
-
41
- - No new tokens needed. Every color/radius used above (`background`, `background-hover`, `muted`, `muted-foreground`, `foreground`, `border`, `ring`, `chart-1`, `destructive`, `popover`, `primary`, `primary-foreground`) already existed — this was a binding/usage fix, not a token-addition pass.
42
-
43
- ### Storybook & Docs
44
-
45
- - `apps/web/src/pages/storybook/_sections/dropdown-menu.astro`: added the seven new `DropdownMenuItem` prop rows to `itemProps`, updated the `variant` row to include `"category"`, and added preview blocks for leading icon / avatar / badge / supportive text / category / checkbox.
46
- - `DropdownMenuStory.astro` / `DropdownMenu.stories.ts`: added stories covering the new item variants/props.
47
-
48
- ### Not changed
49
-
50
- - `DropdownMenuLabel.astro` — spotted a pre-existing bug while auditing (its class list sets both `text-xs` and `text-sm`, with `text-sm` winning via `tailwind-merge`, so labels render at 14px instead of the intended 12px) but left as-is since it wasn't part of this pass's scope; worth a follow-up fix.
51
- - `DropdownMenuGroup.astro`, `DropdownMenuSeparator.astro`, `DropdownMenuPortal.astro`, `DropdownMenuRadioGroup.astro`, `DropdownMenuShortcut.astro` — no Figma delta identified.
52
-
53
- ### Flagged for the designer / engineering (not addressed in this pass)
54
-
55
- - **Real nested submenus:** Figma's `.item` prop table documents `showSubmenuIcon`, implying a submenu affordance, but no submenu flyout, positioning, or keyboard-navigation behavior exists anywhere in `DropdownMenu`'s runtime (`@data-slot/dropdown-menu`). This pass ships the chevron as a static, cosmetic icon only. Building real nested submenus is a separate, larger feature.
56
- - **Checkbox unchecked state:** Figma's item file only shows a filled/checked 20px checkbox square in its Left Content — there's no authored unchecked-square state to match. `showCheckbox`/`checked` on `DropdownMenuItem` therefore reuses the existing checkmark-only indicator pattern instead; worth designing a real unchecked square in Figma if a literal checkbox control (vs. a checked-indicator) is wanted here later.
57
- - **`DropdownMenuLabel` vs. `DropdownMenuItem variant="category"` overlap:** these are now two different ways to render a muted section header (one a dedicated component, one an item variant). Worth a follow-up design decision on whether `DropdownMenuLabel` should be deprecated in favor of `variant="category"`, or the two are meant to serve genuinely different call sites.
58
-
59
- ## Date 10th Sep 2026 (follow-up)
60
- ## Fix: menuitemcheckbox/menuitemradio alignment + item padding (node 2329-6521, prop table 7392-10142)
61
-
62
- The designer updated Figma again after the first pass above: the `DropdownMenuItem` prop table now
63
- explicitly ties `showCheckbox` to *"menuitemcheckbox"* and adds a new `showRadio` → *"menuitemradio"*,
64
- and the item component's padding/radio glyph changed. This entry reconciles that with the framework's
65
- existing three-component structure (`DropdownMenuItem` / `DropdownMenuCheckboxItem` / `DropdownMenuRadioItem`)
66
- rather than collapsing them into one — see "Architecture" below for why.
67
-
68
- ### Architecture
69
-
70
- - Extracted the shared item chrome into two new **internal, non-exported** files (not added to `index.ts`,
71
- same precedent as `DropdownMenuStory.astro`): `dropdown-menu-item-variants.ts` (the single `cva` box-class
72
- builder) and `DropdownMenuItemContent.astro` (the shared Left Content / label / Right Content layout).
73
- `DropdownMenuItem`, `DropdownMenuCheckboxItem`, and `DropdownMenuRadioItem` all now render through these,
74
- instead of each duplicating the same padding/typography classes.
75
- - **Did not consolidate into one role-switching component.** Figma's single-component mental model
76
- (`DropdownMenuItem` + a boolean that "becomes" a checkbox/radio) doesn't map cleanly onto this
77
- framework: `@data-slot/dropdown-menu`'s runtime detects real interactive item type purely from each
78
- element's `data-slot` value and manages `role`/`tabindex`/`aria-checked`/checked-state tracking
79
- automatically for `[data-slot="dropdown-menu-checkbox-item"]` / `[data-slot="dropdown-menu-radio-item"]`.
80
- Collapsing three ARIA-correct, already-working components into one conditionally-shaped component would
81
- have been a much larger, riskier change for no framework-side benefit — the shared-chrome extraction above
82
- gets the same "one visual spec, one place" outcome without touching the runtime contract.
83
-
84
- ### Sizing & Spacing
85
-
86
- - **Padding correction:** Figma's item box is now uniform `p-2` (8px on all sides) for `default`/`destructive`
87
- — was `px-2 py-1` last pass (a padding fix I hadn't fully caught the first time). Row height grows
88
- 24px → 32px accordingly, on `DropdownMenuItem`, `DropdownMenuCheckboxItem`, and `DropdownMenuRadioItem`.
89
- - **`category` has its own distinct, tighter padding** (`pt-1 px-1 pb-0 gap-1`, no `p-2`) — this was already
90
- structurally different in Figma and wasn't captured correctly last pass, where it incorrectly shared the
91
- interactive variants' row padding.
92
- - `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` **dropped their old asymmetric `pr-8 pl-2` padding**
93
- entirely — no longer needed now that the checked/selected indicator lives in Left Content instead of
94
- floating absolute-right (see below), so they use the exact same `p-2` box as a plain `DropdownMenuItem`.
95
-
96
- ### Checkbox / Radio glyph — switched to Figma's literal look
97
-
98
- - `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` moved from the old shadcn-style indicator (invisible
99
- until checked, a bare checkmark fading in at `absolute right-2`) to Figma's literal glyph: an
100
- always-reserved 20px box (`rounded-sm`, checkbox) or circle (`rounded-full`, radio) in Left Content,
101
- outlined (`border-input`) when unchecked and `bg-primary border-primary` + a white check icon / centered
102
- dot when checked. Visual language borrowed directly from the existing `Checkbox.astro`/`RadioGroupItem.astro`
103
- components (same token usage, scaled to the item's 20px glyph size) rather than inventing new colors.
104
- - This is driven purely by CSS off the `data-checked` attribute the runtime **already sets** on these exact
105
- elements (confirmed in `@data-slot/dropdown-menu`'s source) via `group-data-checked/dropdown-menu-item:` —
106
- no new JavaScript needed, no change to the runtime's checked-state tracking or click/keyboard handling.
107
- - `DropdownMenuItem`'s own presentational `showCheckbox` also switched from the old checkmark-only pattern to
108
- the same 20px box glyph (driven by its static `checked` prop, not runtime state), for visual consistency
109
- with the real components. New presentational `showRadio` (see below) uses the matching circle glyph.
110
- - **Resolves last pass's "Checkbox unchecked state" flag** — Figma still doesn't author a literal unchecked
111
- square, but reusing `Checkbox`'s existing unchecked visual (bordered, no fill) is a defensible, low-risk
112
- default that's already established elsewhere in the design system.
113
-
114
- ### New Props
115
-
116
- - `DropdownMenuItem` gains `showRadio?: boolean` (default `false`), mirroring `showCheckbox` — presentational
117
- only, reuses the shared `checked` prop. Per Figma's prop table: `showRadio` → *"Show radiobutton which is
118
- menuitemradio"*.
119
- - `DropdownMenuCheckboxItem` and `DropdownMenuRadioItem` both gain the same extra prop surface
120
- `DropdownMenuItem` got last pass: `leadingIcon`, `avatar`, `showBadge`, `showSubmenuIcon`, `supportiveText`
121
- (same `Astro.slots.has(...)`-default convention). Sharing chrome made this nearly free, and Figma's own
122
- item variants already mix a checkbox with other leading/trailing content in the same row.
123
- - `value`, `disabled`, `inset`, `defaultChecked`, `role="menuitemcheckbox"`/`"menuitemradio"`,
124
- `data-slot="dropdown-menu-checkbox-item"`/`"dropdown-menu-radio-item"` are all **unchanged** — this is the
125
- ARIA/runtime contract and was not touched.
126
-
127
- ### Fixed (implementation bug, not a Figma delta)
128
-
129
- - While building the shared chrome, caught a real bug in the first draft: forwarding a
130
- `<Fragment slot="leading-icon">` etc. from each root component into the shared `DropdownMenuItemContent`
131
- made `Astro.slots.has("leading-icon")` always return `true` inside that shared partial (it saw the
132
- pass-through Fragment, not whether the real end-consumer supplied content), so empty leading-icon/avatar/
133
- badge wrapper `<span>`s rendered on every single item regardless of props. Fixed by resolving
134
- `Astro.slots.has(...)` defaults in each outer component (`DropdownMenuItem`/`CheckboxItem`/`RadioItem`,
135
- against their *own* callers) and passing explicit resolved booleans down — the shared partial no longer
136
- does any slot introspection of its own. Verified via built story output before/after (span count per item
137
- went from unconditional-always to matching only the items that actually set the prop).
138
-
139
- ### Storybook & Docs
140
-
141
- - `apps/web/src/pages/storybook/_sections/dropdown-menu.astro`: added a `showRadio` row to `itemProps`;
142
- updated `leadingIcon`/`avatar`/`showBadge`/`showSubmenuIcon`/`supportiveText` descriptions to note they now
143
- apply to all three item components, not just `DropdownMenuItem`; enriched the Single Select/Multi Select
144
- preview blocks to exercise the new prop parity (`supportiveText` on a radio item, `showBadge` on a checkbox
145
- item); added `showRadio` to the "Item content" preview.
146
- - `DropdownMenuStory.astro`/`DropdownMenu.stories.ts`: added a new `CheckboxRadioContent` story
147
- (`showCheckboxRadio` prop) covering presentational checked/unchecked checkbox and radio glyphs side by side
148
- with the real, runtime-tracked `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` (one with `avatar`, one
149
- with `showBadge`) so both visual systems are directly comparable.
150
-
151
- ### Flagged for the designer / engineering (not addressed in this pass)
152
-
153
- - **`showCheckbox`/`showRadio` on plain `DropdownMenuItem` are cosmetic only** — they draw the glyph via a
154
- static prop and don't manage checked/selected state or emit events. Don't reach for them expecting real
155
- interactivity; that's what `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` are for. Worth a naming pass
156
- if this keeps causing confusion (e.g. renaming the presentational props to make the distinction more
157
- obvious in autocomplete).
158
- - Carried over from last pass, still open: real nested submenus (`showSubmenuIcon` is still cosmetic-only),
159
- and the `DropdownMenuLabel` vs. `variant="category"` overlap.
160
-
161
- ## Date 10th Sep 2026 (follow-up)
162
- ## Fix: distinct Hover vs. Focus states (node 2529-2338, item states)
163
-
164
- While adding a states preview to the Storybook docs, caught that `DropdownMenuItem` (and by extension
165
- `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem`, which share its `cva`) only ever had **one** interactive
166
- style — `focus:bg-background-hover` — with no real `:hover` class at all. Figma documents Hover and Focused
167
- as two visually distinct states (Hover: grey background only; Focused: a blue border + ring, no background
168
- change), which wasn't implemented.
169
-
170
- ### Fixed
171
-
172
- - `dropdown-menu-item-variants.ts`: added a real `hover:bg-background-hover` (per variant, `destructive` gets
173
- `hover:text-destructive dark:hover:bg-destructive/20`) so mouse hover now works with plain CSS — no JS
174
- required, matching Figma's Hover state.
175
- - Replaced `focus:bg-background-hover` with `focus-visible:border-ring focus-visible:ring-2
176
- focus-visible:ring-chart-1`, matching Figma's Focused effect (`border-ring` + a 2px ring) and the same
177
- `focus-visible:border-ring focus-visible:ring-*` pattern already used by `Button`/`Card`. Added
178
- `border border-transparent` to the shared base so the border can swap color on focus without any layout
179
- shift (same technique `Button`/`Card` already use).
180
- - Using `:focus-visible` instead of plain `:focus` is deliberate: the dropdown runtime calls a real
181
- `element.focus()` on pointer hover (so highlight tracks the mouse for accessibility purposes) — with
182
- `:focus-visible`, browsers' own heuristics correctly suppress the keyboard-style ring for that
183
- pointer-triggered focus (real `:hover` covers the visual instead) while still showing the ring for genuine
184
- keyboard navigation (Tab/Arrow keys). Net effect: mouse hover shows grey background only, keyboard
185
- navigation shows the blue ring — exactly Figma's distinction, with no behavior change to the runtime itself.
186
-
187
- ### Storybook & Docs
188
-
189
- - `apps/web/src/pages/storybook/_sections/dropdown-menu.astro`: added a new "DropdownMenuItem states" preview
190
- (Default/Hover/Focus/Disabled) above "DropdownMenuItem variants" — Hover/Focus rows use a forced `class`
191
- override for an always-visible reference, with a note that the same states are live (hover/Tab to see them
192
- for real anywhere in the gallery).
193
-
194
- ## Unreleased
1
+ # Changelog
2
+
3
+ All notable changes to the `DropdownMenu` component will be documented in this file.
4
+
5
+ ## Date 10th Sep 2026
6
+ ## Figma alignment (node 2329-6521, prop table 7392-10142)
7
+
8
+ ### Variants
9
+
10
+ - Added a `category` variant to `DropdownMenuItem` (`variant: "default" | "destructive" | "category"`, was `"default" | "destructive"`), matching Figma's `.item` component set which documents `Category` as a third item variant. Renders as a non-interactive (`role="presentation"`, `tabindex={-1}`, `pointer-events-none`), muted (`text-muted-foreground font-medium`) row — the visual is intentionally close to the existing `DropdownMenuLabel`, but this variant lives on `DropdownMenuItem` itself so it can sit inline in a list without an extra import, per Figma's own prop table contract. It does not render a separator automatically — pair it with the existing `<DropdownMenuSeparator />` if a divider is wanted, same as any other item.
11
+ - Converted `DropdownMenuItem` from hardcoded `data-[variant=...]:` Tailwind selectors to `class-variance-authority` (`cva`), matching the pattern already used by `Card`/`Button`/`Badge`/`Avatar`.
12
+
13
+ ### Sizing & Spacing
14
+
15
+ - **Radius:** `rounded-sm` (4px) → `rounded-lg` (8px) on `DropdownMenuItem`, `DropdownMenuCheckboxItem`, and `DropdownMenuRadioItem` — Figma's item box is consistently `rounded-[8px]`.
16
+ - **Padding:** `py-1.5` (6px) → `py-1` (4px) on all three item components — Figma's item is `py-[4px]` (`spacing/1`), horizontal `px-2` (`spacing/2`, 8px) was already correct.
17
+ - **Typography:** item label moved from unstyled `text-sm` (14px, regular) → `text-xs font-semibold` (12px/600) on all three item components, matching Figma's `text/sm/sm-semibold` text style for the item label. Supportive text (new, see below) is `text-xs font-normal text-muted-foreground`.
18
+ - **Popover chrome** (`DropdownMenuContent`): `ring-1 ring-foreground/10` → `border border-border` (Figma uses a real 1px border, not a ring); `shadow-md` → Figma's actual 3-layer `shadow-lg` drop-shadow (`0.3px 2px/-2.2 spread #1F003B05, 0.5px 3.2px/-1.4 #1F003B08, 0.7px 4px/-1.8 #1F003B0F`); `p-1` (4px) → `p-2` (8px); added an explicit `gap-1.5` (6px) between items, matching Figma's item-to-item gap (previously no gap was set at all, relying on nothing — items had no separation beyond their own padding).
19
+
20
+ ### New Props (`DropdownMenuItem` only)
21
+
22
+ Following the Button/Badge "boolean prop, auto-detected from a named slot via `Astro.slots.has(...)`" convention:
23
+
24
+ - `checked?: boolean` (default `false`) — presentational checked state, only visible when `showCheckbox` is also set.
25
+ - `showCheckbox?: boolean` (default `false`) — reserves a 20px leading slot for a checkmark; **kept the existing indicator pattern** (no visible box at rest, a checkmark fades in when `checked`), matching `DropdownMenuCheckboxItem`'s existing visual language rather than inventing Figma's filled-square glyph, which has no documented unchecked state in the file. `DropdownMenuCheckboxItem` itself is unchanged — this is a separate, presentation-only affordance for a plain `DropdownMenuItem`.
26
+ - `leadingIcon?: boolean` (default: has a `leading-icon` slot) — renders `<slot name="leading-icon" />` at 20px.
27
+ - `avatar?: boolean` (default: has an `avatar` slot) — renders `<slot name="avatar" />`. Use `<Avatar size="sm">` (24px) — it already matches Figma's item avatar size exactly, no new Avatar sizing needed.
28
+ - `showBadge?: boolean` (default: has a `badge` slot) — renders `<slot name="badge" />`. Use `<Badge size="sm">`.
29
+ - `showSubmenuIcon?: boolean` (default `false`) — renders a static 20px chevron-right. **Cosmetic only** — there is no nested-submenu infrastructure (flyout positioning, keyboard handling) anywhere in `DropdownMenu` yet. See "Flagged for the designer" below.
30
+ - `supportiveText?: boolean` (default: has a `supportive-text` slot) — renders a second, muted line under the item label via `<slot name="supportive-text" />`.
31
+
32
+ `leadingIcon`, `avatar`, and `showCheckbox` are independent booleans (can combine), per Figma's literal prop table — not consolidated into a single `leading` enum.
33
+
34
+ ### Trigger
35
+
36
+ - `DropdownMenuTrigger` now defaults `variant="outline"` (was inheriting `Button`'s own default `"default"`/primary-blue variant) — Figma's default/closed trigger state is a white/bordered button, not primary. Still fully overridable via the existing `variant` prop.
37
+ - `DropdownMenuTrigger` now renders a default trailing chevron (`ChevronDown` from `@lucide/astro`) when the consumer doesn't slot their own `tail-icon` content — Figma's trigger always shows a chevron as core anatomy, not an opt-in add-on. It rotates 180° when the menu is open via a new `group/dropdown-menu` marker added to `DropdownMenu.astro`'s root (`data-state` lands on that root element, confirmed in `@data-slot/dropdown-menu`'s runtime). Pass `tailIcon={false}` to opt out entirely, or your own `<Icon slot="tail-icon" />` to override.
38
+
39
+ ### Tokens (`globals.css`)
40
+
41
+ - No new tokens needed. Every color/radius used above (`background`, `background-hover`, `muted`, `muted-foreground`, `foreground`, `border`, `ring`, `chart-1`, `destructive`, `popover`, `primary`, `primary-foreground`) already existed — this was a binding/usage fix, not a token-addition pass.
42
+
43
+ ### Storybook & Docs
44
+
45
+ - `apps/web/src/pages/storybook/_sections/dropdown-menu.astro`: added the seven new `DropdownMenuItem` prop rows to `itemProps`, updated the `variant` row to include `"category"`, and added preview blocks for leading icon / avatar / badge / supportive text / category / checkbox.
46
+ - `DropdownMenuStory.astro` / `DropdownMenu.stories.ts`: added stories covering the new item variants/props.
47
+
48
+ ### Not changed
49
+
50
+ - `DropdownMenuLabel.astro` — spotted a pre-existing bug while auditing (its class list sets both `text-xs` and `text-sm`, with `text-sm` winning via `tailwind-merge`, so labels render at 14px instead of the intended 12px) but left as-is since it wasn't part of this pass's scope; worth a follow-up fix.
51
+ - `DropdownMenuGroup.astro`, `DropdownMenuSeparator.astro`, `DropdownMenuPortal.astro`, `DropdownMenuRadioGroup.astro`, `DropdownMenuShortcut.astro` — no Figma delta identified.
52
+
53
+ ### Flagged for the designer / engineering (not addressed in this pass)
54
+
55
+ - **Real nested submenus:** Figma's `.item` prop table documents `showSubmenuIcon`, implying a submenu affordance, but no submenu flyout, positioning, or keyboard-navigation behavior exists anywhere in `DropdownMenu`'s runtime (`@data-slot/dropdown-menu`). This pass ships the chevron as a static, cosmetic icon only. Building real nested submenus is a separate, larger feature.
56
+ - **Checkbox unchecked state:** Figma's item file only shows a filled/checked 20px checkbox square in its Left Content — there's no authored unchecked-square state to match. `showCheckbox`/`checked` on `DropdownMenuItem` therefore reuses the existing checkmark-only indicator pattern instead; worth designing a real unchecked square in Figma if a literal checkbox control (vs. a checked-indicator) is wanted here later.
57
+ - **`DropdownMenuLabel` vs. `DropdownMenuItem variant="category"` overlap:** these are now two different ways to render a muted section header (one a dedicated component, one an item variant). Worth a follow-up design decision on whether `DropdownMenuLabel` should be deprecated in favor of `variant="category"`, or the two are meant to serve genuinely different call sites.
58
+
59
+ ## Date 10th Sep 2026 (follow-up)
60
+ ## Fix: menuitemcheckbox/menuitemradio alignment + item padding (node 2329-6521, prop table 7392-10142)
61
+
62
+ The designer updated Figma again after the first pass above: the `DropdownMenuItem` prop table now
63
+ explicitly ties `showCheckbox` to *"menuitemcheckbox"* and adds a new `showRadio` → *"menuitemradio"*,
64
+ and the item component's padding/radio glyph changed. This entry reconciles that with the framework's
65
+ existing three-component structure (`DropdownMenuItem` / `DropdownMenuCheckboxItem` / `DropdownMenuRadioItem`)
66
+ rather than collapsing them into one — see "Architecture" below for why.
67
+
68
+ ### Architecture
69
+
70
+ - Extracted the shared item chrome into two new **internal, non-exported** files (not added to `index.ts`,
71
+ same precedent as `DropdownMenuStory.astro`): `dropdown-menu-item-variants.ts` (the single `cva` box-class
72
+ builder) and `DropdownMenuItemContent.astro` (the shared Left Content / label / Right Content layout).
73
+ `DropdownMenuItem`, `DropdownMenuCheckboxItem`, and `DropdownMenuRadioItem` all now render through these,
74
+ instead of each duplicating the same padding/typography classes.
75
+ - **Did not consolidate into one role-switching component.** Figma's single-component mental model
76
+ (`DropdownMenuItem` + a boolean that "becomes" a checkbox/radio) doesn't map cleanly onto this
77
+ framework: `@data-slot/dropdown-menu`'s runtime detects real interactive item type purely from each
78
+ element's `data-slot` value and manages `role`/`tabindex`/`aria-checked`/checked-state tracking
79
+ automatically for `[data-slot="dropdown-menu-checkbox-item"]` / `[data-slot="dropdown-menu-radio-item"]`.
80
+ Collapsing three ARIA-correct, already-working components into one conditionally-shaped component would
81
+ have been a much larger, riskier change for no framework-side benefit — the shared-chrome extraction above
82
+ gets the same "one visual spec, one place" outcome without touching the runtime contract.
83
+
84
+ ### Sizing & Spacing
85
+
86
+ - **Padding correction:** Figma's item box is now uniform `p-2` (8px on all sides) for `default`/`destructive`
87
+ — was `px-2 py-1` last pass (a padding fix I hadn't fully caught the first time). Row height grows
88
+ 24px → 32px accordingly, on `DropdownMenuItem`, `DropdownMenuCheckboxItem`, and `DropdownMenuRadioItem`.
89
+ - **`category` has its own distinct, tighter padding** (`pt-1 px-1 pb-0 gap-1`, no `p-2`) — this was already
90
+ structurally different in Figma and wasn't captured correctly last pass, where it incorrectly shared the
91
+ interactive variants' row padding.
92
+ - `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` **dropped their old asymmetric `pr-8 pl-2` padding**
93
+ entirely — no longer needed now that the checked/selected indicator lives in Left Content instead of
94
+ floating absolute-right (see below), so they use the exact same `p-2` box as a plain `DropdownMenuItem`.
95
+
96
+ ### Checkbox / Radio glyph — switched to Figma's literal look
97
+
98
+ - `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` moved from the old shadcn-style indicator (invisible
99
+ until checked, a bare checkmark fading in at `absolute right-2`) to Figma's literal glyph: an
100
+ always-reserved 20px box (`rounded-sm`, checkbox) or circle (`rounded-full`, radio) in Left Content,
101
+ outlined (`border-input`) when unchecked and `bg-primary border-primary` + a white check icon / centered
102
+ dot when checked. Visual language borrowed directly from the existing `Checkbox.astro`/`RadioGroupItem.astro`
103
+ components (same token usage, scaled to the item's 20px glyph size) rather than inventing new colors.
104
+ - This is driven purely by CSS off the `data-checked` attribute the runtime **already sets** on these exact
105
+ elements (confirmed in `@data-slot/dropdown-menu`'s source) via `group-data-checked/dropdown-menu-item:` —
106
+ no new JavaScript needed, no change to the runtime's checked-state tracking or click/keyboard handling.
107
+ - `DropdownMenuItem`'s own presentational `showCheckbox` also switched from the old checkmark-only pattern to
108
+ the same 20px box glyph (driven by its static `checked` prop, not runtime state), for visual consistency
109
+ with the real components. New presentational `showRadio` (see below) uses the matching circle glyph.
110
+ - **Resolves last pass's "Checkbox unchecked state" flag** — Figma still doesn't author a literal unchecked
111
+ square, but reusing `Checkbox`'s existing unchecked visual (bordered, no fill) is a defensible, low-risk
112
+ default that's already established elsewhere in the design system.
113
+
114
+ ### New Props
115
+
116
+ - `DropdownMenuItem` gains `showRadio?: boolean` (default `false`), mirroring `showCheckbox` — presentational
117
+ only, reuses the shared `checked` prop. Per Figma's prop table: `showRadio` → *"Show radiobutton which is
118
+ menuitemradio"*.
119
+ - `DropdownMenuCheckboxItem` and `DropdownMenuRadioItem` both gain the same extra prop surface
120
+ `DropdownMenuItem` got last pass: `leadingIcon`, `avatar`, `showBadge`, `showSubmenuIcon`, `supportiveText`
121
+ (same `Astro.slots.has(...)`-default convention). Sharing chrome made this nearly free, and Figma's own
122
+ item variants already mix a checkbox with other leading/trailing content in the same row.
123
+ - `value`, `disabled`, `inset`, `defaultChecked`, `role="menuitemcheckbox"`/`"menuitemradio"`,
124
+ `data-slot="dropdown-menu-checkbox-item"`/`"dropdown-menu-radio-item"` are all **unchanged** — this is the
125
+ ARIA/runtime contract and was not touched.
126
+
127
+ ### Fixed (implementation bug, not a Figma delta)
128
+
129
+ - While building the shared chrome, caught a real bug in the first draft: forwarding a
130
+ `<Fragment slot="leading-icon">` etc. from each root component into the shared `DropdownMenuItemContent`
131
+ made `Astro.slots.has("leading-icon")` always return `true` inside that shared partial (it saw the
132
+ pass-through Fragment, not whether the real end-consumer supplied content), so empty leading-icon/avatar/
133
+ badge wrapper `<span>`s rendered on every single item regardless of props. Fixed by resolving
134
+ `Astro.slots.has(...)` defaults in each outer component (`DropdownMenuItem`/`CheckboxItem`/`RadioItem`,
135
+ against their *own* callers) and passing explicit resolved booleans down — the shared partial no longer
136
+ does any slot introspection of its own. Verified via built story output before/after (span count per item
137
+ went from unconditional-always to matching only the items that actually set the prop).
138
+
139
+ ### Storybook & Docs
140
+
141
+ - `apps/web/src/pages/storybook/_sections/dropdown-menu.astro`: added a `showRadio` row to `itemProps`;
142
+ updated `leadingIcon`/`avatar`/`showBadge`/`showSubmenuIcon`/`supportiveText` descriptions to note they now
143
+ apply to all three item components, not just `DropdownMenuItem`; enriched the Single Select/Multi Select
144
+ preview blocks to exercise the new prop parity (`supportiveText` on a radio item, `showBadge` on a checkbox
145
+ item); added `showRadio` to the "Item content" preview.
146
+ - `DropdownMenuStory.astro`/`DropdownMenu.stories.ts`: added a new `CheckboxRadioContent` story
147
+ (`showCheckboxRadio` prop) covering presentational checked/unchecked checkbox and radio glyphs side by side
148
+ with the real, runtime-tracked `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` (one with `avatar`, one
149
+ with `showBadge`) so both visual systems are directly comparable.
150
+
151
+ ### Flagged for the designer / engineering (not addressed in this pass)
152
+
153
+ - **`showCheckbox`/`showRadio` on plain `DropdownMenuItem` are cosmetic only** — they draw the glyph via a
154
+ static prop and don't manage checked/selected state or emit events. Don't reach for them expecting real
155
+ interactivity; that's what `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem` are for. Worth a naming pass
156
+ if this keeps causing confusion (e.g. renaming the presentational props to make the distinction more
157
+ obvious in autocomplete).
158
+ - Carried over from last pass, still open: real nested submenus (`showSubmenuIcon` is still cosmetic-only),
159
+ and the `DropdownMenuLabel` vs. `variant="category"` overlap.
160
+
161
+ ## Date 10th Sep 2026 (follow-up)
162
+ ## Fix: distinct Hover vs. Focus states (node 2529-2338, item states)
163
+
164
+ While adding a states preview to the Storybook docs, caught that `DropdownMenuItem` (and by extension
165
+ `DropdownMenuCheckboxItem`/`DropdownMenuRadioItem`, which share its `cva`) only ever had **one** interactive
166
+ style — `focus:bg-background-hover` — with no real `:hover` class at all. Figma documents Hover and Focused
167
+ as two visually distinct states (Hover: grey background only; Focused: a blue border + ring, no background
168
+ change), which wasn't implemented.
169
+
170
+ ### Fixed
171
+
172
+ - `dropdown-menu-item-variants.ts`: added a real `hover:bg-background-hover` (per variant, `destructive` gets
173
+ `hover:text-destructive dark:hover:bg-destructive/20`) so mouse hover now works with plain CSS — no JS
174
+ required, matching Figma's Hover state.
175
+ - Replaced `focus:bg-background-hover` with `focus-visible:border-ring focus-visible:ring-2
176
+ focus-visible:ring-chart-1`, matching Figma's Focused effect (`border-ring` + a 2px ring) and the same
177
+ `focus-visible:border-ring focus-visible:ring-*` pattern already used by `Button`/`Card`. Added
178
+ `border border-transparent` to the shared base so the border can swap color on focus without any layout
179
+ shift (same technique `Button`/`Card` already use).
180
+ - Using `:focus-visible` instead of plain `:focus` is deliberate: the dropdown runtime calls a real
181
+ `element.focus()` on pointer hover (so highlight tracks the mouse for accessibility purposes) — with
182
+ `:focus-visible`, browsers' own heuristics correctly suppress the keyboard-style ring for that
183
+ pointer-triggered focus (real `:hover` covers the visual instead) while still showing the ring for genuine
184
+ keyboard navigation (Tab/Arrow keys). Net effect: mouse hover shows grey background only, keyboard
185
+ navigation shows the blue ring — exactly Figma's distinction, with no behavior change to the runtime itself.
186
+
187
+ ### Storybook & Docs
188
+
189
+ - `apps/web/src/pages/storybook/_sections/dropdown-menu.astro`: added a new "DropdownMenuItem states" preview
190
+ (Default/Hover/Focus/Disabled) above "DropdownMenuItem variants" — Hover/Focus rows use a forced `class`
191
+ override for an always-visible reference, with a note that the same states are live (hover/Tab to see them
192
+ for real anywhere in the gallery).
193
+
194
+ ## Unreleased