@misoto22/design 0.7.0 → 0.9.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 (398) hide show
  1. package/AGENTS.md +87 -0
  2. package/CLAUDE.md +1 -0
  3. package/README.md +50 -5
  4. package/bin/misoto22-design.mjs +59 -13
  5. package/dist/agent/Accordion.md +24 -1
  6. package/dist/agent/Alert.md +23 -1
  7. package/dist/agent/AppShell.md +30 -2
  8. package/dist/agent/ArchitectureFigure.md +25 -2
  9. package/dist/agent/AreaChart.md +27 -2
  10. package/dist/agent/Article.md +26 -3
  11. package/dist/agent/AspectRatio.md +57 -0
  12. package/dist/agent/Avatar.md +25 -5
  13. package/dist/agent/Badge.md +22 -1
  14. package/dist/agent/BarChart.md +29 -2
  15. package/dist/agent/BarList.md +27 -1
  16. package/dist/agent/BigNumber.md +26 -2
  17. package/dist/agent/BoxPlot.md +24 -1
  18. package/dist/agent/Breadcrumb.md +24 -2
  19. package/dist/agent/BulletChart.md +23 -1
  20. package/dist/agent/Button.md +25 -1
  21. package/dist/agent/Calendar.md +37 -3
  22. package/dist/agent/Card.md +24 -2
  23. package/dist/agent/Checkbox.md +23 -2
  24. package/dist/agent/Code.md +50 -0
  25. package/dist/agent/CodeBlock.md +74 -0
  26. package/dist/agent/Collapsible.md +22 -1
  27. package/dist/agent/ColorPicker.md +75 -0
  28. package/dist/agent/Combobox.md +29 -3
  29. package/dist/agent/Command.md +25 -2
  30. package/dist/agent/ComposedChart.md +26 -2
  31. package/dist/agent/ContextMenu.md +37 -4
  32. package/dist/agent/DataflowFigure.md +22 -1
  33. package/dist/agent/DatePicker.md +34 -6
  34. package/dist/agent/DescriptionList.md +68 -0
  35. package/dist/agent/Diagram.md +27 -3
  36. package/dist/agent/DiagramCanvas.md +24 -1
  37. package/dist/agent/DiagramExportMenu.md +29 -3
  38. package/dist/agent/DiagramInspector.md +23 -1
  39. package/dist/agent/DiagramLegend.md +22 -1
  40. package/dist/agent/DiagramMinimap.md +24 -4
  41. package/dist/agent/DiagramToolbar.md +23 -1
  42. package/dist/agent/Dialog.md +26 -3
  43. package/dist/agent/DropdownMenu.md +45 -6
  44. package/dist/agent/EmptyState.md +26 -1
  45. package/dist/agent/ErrorState.md +27 -2
  46. package/dist/agent/Facet.md +25 -1
  47. package/dist/agent/Field.md +45 -4
  48. package/dist/agent/FigureBand.md +24 -1
  49. package/dist/agent/FloatingIconButton.md +23 -1
  50. package/dist/agent/FunnelChart.md +23 -1
  51. package/dist/agent/Heading.md +64 -0
  52. package/dist/agent/Heatmap.md +25 -1
  53. package/dist/agent/Histogram.md +26 -2
  54. package/dist/agent/Input.md +22 -1
  55. package/dist/agent/Kbd.md +19 -1
  56. package/dist/agent/LifecycleFigure.md +22 -1
  57. package/dist/agent/LineChart.md +26 -2
  58. package/dist/agent/LinkArrow.md +20 -1
  59. package/dist/agent/Markdown.md +68 -0
  60. package/dist/agent/NativeSelect.md +23 -2
  61. package/dist/agent/NavItem.md +21 -1
  62. package/dist/agent/NumberField.md +72 -0
  63. package/dist/agent/Pagination.md +28 -2
  64. package/dist/agent/PieChart.md +26 -2
  65. package/dist/agent/Popover.md +23 -1
  66. package/dist/agent/Progress.md +27 -3
  67. package/dist/agent/RadarChart.md +26 -2
  68. package/dist/agent/RadialChart.md +26 -3
  69. package/dist/agent/RadioGroup.md +23 -2
  70. package/dist/agent/SankeyChart.md +25 -2
  71. package/dist/agent/ScatterChart.md +27 -2
  72. package/dist/agent/ScrollArea.md +24 -3
  73. package/dist/agent/SearchableMenu.md +23 -1
  74. package/dist/agent/Select.md +29 -3
  75. package/dist/agent/Separator.md +28 -4
  76. package/dist/agent/SequenceFigure.md +23 -1
  77. package/dist/agent/Sheet.md +25 -2
  78. package/dist/agent/Sidebar.md +193 -0
  79. package/dist/agent/Skeleton.md +24 -2
  80. package/dist/agent/Slider.md +31 -4
  81. package/dist/agent/Sparkline.md +23 -1
  82. package/dist/agent/Spinner.md +24 -2
  83. package/dist/agent/StatusDot.md +20 -1
  84. package/dist/agent/StatusPill.md +28 -2
  85. package/dist/agent/Steps.md +24 -1
  86. package/dist/agent/Switch.md +21 -1
  87. package/dist/agent/Table.md +28 -3
  88. package/dist/agent/Tabs.md +24 -2
  89. package/dist/agent/Tag.md +40 -9
  90. package/dist/agent/Text.md +65 -0
  91. package/dist/agent/Textarea.md +20 -1
  92. package/dist/agent/Timestamp.md +64 -0
  93. package/dist/agent/Toast.md +26 -2
  94. package/dist/agent/ToggleGroup.md +24 -2
  95. package/dist/agent/Toolbar.md +71 -0
  96. package/dist/agent/Tooltip.md +23 -1
  97. package/dist/agent/TreemapChart.md +24 -1
  98. package/dist/agent/WaterfallChart.md +24 -1
  99. package/dist/agent/WorkflowFigure.md +24 -2
  100. package/dist/agent/catalog.json +5915 -699
  101. package/dist/agent/index.md +20 -8
  102. package/dist/article.css +16 -4
  103. package/dist/charts/AreaChart/AreaChart.d.ts +9 -2
  104. package/dist/charts/AreaChart/AreaChart.js +12 -13
  105. package/dist/charts/AreaChart/AreaChart.js.map +1 -1
  106. package/dist/charts/BarChart/BarChart.d.ts +14 -3
  107. package/dist/charts/BarChart/BarChart.js +20 -12
  108. package/dist/charts/BarChart/BarChart.js.map +1 -1
  109. package/dist/charts/BarList/BarList.d.ts +9 -1
  110. package/dist/charts/BarList/BarList.js +9 -1
  111. package/dist/charts/BarList/BarList.js.map +1 -1
  112. package/dist/charts/BigNumber/BigNumber.d.ts +19 -3
  113. package/dist/charts/BigNumber/BigNumber.js +25 -5
  114. package/dist/charts/BigNumber/BigNumber.js.map +1 -1
  115. package/dist/charts/BoxPlot/BoxPlot.js +4 -2
  116. package/dist/charts/BoxPlot/BoxPlot.js.map +1 -1
  117. package/dist/charts/BulletChart/BulletChart.js +44 -9
  118. package/dist/charts/BulletChart/BulletChart.js.map +1 -1
  119. package/dist/charts/ComposedChart/ComposedChart.d.ts +9 -2
  120. package/dist/charts/ComposedChart/ComposedChart.js +10 -10
  121. package/dist/charts/ComposedChart/ComposedChart.js.map +1 -1
  122. package/dist/charts/FunnelChart/FunnelChart.d.ts +7 -2
  123. package/dist/charts/FunnelChart/FunnelChart.js +6 -16
  124. package/dist/charts/FunnelChart/FunnelChart.js.map +1 -1
  125. package/dist/charts/Heatmap/Heatmap.d.ts +17 -3
  126. package/dist/charts/Heatmap/Heatmap.js +20 -11
  127. package/dist/charts/Heatmap/Heatmap.js.map +1 -1
  128. package/dist/charts/Histogram/Histogram.d.ts +24 -1
  129. package/dist/charts/Histogram/Histogram.js +43 -11
  130. package/dist/charts/Histogram/Histogram.js.map +1 -1
  131. package/dist/charts/LineChart/LineChart.d.ts +9 -2
  132. package/dist/charts/LineChart/LineChart.js +11 -12
  133. package/dist/charts/LineChart/LineChart.js.map +1 -1
  134. package/dist/charts/PieChart/PieChart.d.ts +15 -3
  135. package/dist/charts/PieChart/PieChart.js +14 -6
  136. package/dist/charts/PieChart/PieChart.js.map +1 -1
  137. package/dist/charts/RadarChart/RadarChart.d.ts +15 -3
  138. package/dist/charts/RadarChart/RadarChart.js +15 -11
  139. package/dist/charts/RadarChart/RadarChart.js.map +1 -1
  140. package/dist/charts/RadialChart/RadialChart.d.ts +22 -4
  141. package/dist/charts/RadialChart/RadialChart.js +28 -6
  142. package/dist/charts/RadialChart/RadialChart.js.map +1 -1
  143. package/dist/charts/SankeyChart/SankeyChart.d.ts +16 -4
  144. package/dist/charts/SankeyChart/SankeyChart.js +14 -6
  145. package/dist/charts/SankeyChart/SankeyChart.js.map +1 -1
  146. package/dist/charts/ScatterChart/ScatterChart.d.ts +24 -3
  147. package/dist/charts/ScatterChart/ScatterChart.js +21 -15
  148. package/dist/charts/ScatterChart/ScatterChart.js.map +1 -1
  149. package/dist/charts/Sparkline/Sparkline.js +5 -3
  150. package/dist/charts/Sparkline/Sparkline.js.map +1 -1
  151. package/dist/charts/TreemapChart/TreemapChart.d.ts +7 -2
  152. package/dist/charts/TreemapChart/TreemapChart.js +20 -11
  153. package/dist/charts/TreemapChart/TreemapChart.js.map +1 -1
  154. package/dist/charts/WaterfallChart/WaterfallChart.js +4 -2
  155. package/dist/charts/WaterfallChart/WaterfallChart.js.map +1 -1
  156. package/dist/charts/lib/export.d.ts +1 -0
  157. package/dist/charts/lib/figure.d.ts +21 -1
  158. package/dist/charts/lib/figure.js +5 -2
  159. package/dist/charts/lib/figure.js.map +1 -1
  160. package/dist/charts/lib/scale.d.ts +23 -0
  161. package/dist/charts/lib/scale.js +13 -0
  162. package/dist/charts/lib/scale.js.map +1 -0
  163. package/dist/charts/lib/selection.d.ts +20 -0
  164. package/dist/charts/lib/selection.js +18 -0
  165. package/dist/charts/lib/selection.js.map +1 -0
  166. package/dist/charts/lib/toolbar.d.ts +1 -0
  167. package/dist/components/Accordion/Accordion.js +8 -1
  168. package/dist/components/Accordion/Accordion.js.map +1 -1
  169. package/dist/components/AppShell/AppShell.d.ts +6 -0
  170. package/dist/components/AppShell/AppShell.js +34 -4
  171. package/dist/components/AppShell/AppShell.js.map +1 -1
  172. package/dist/components/Article/Article.d.ts +11 -4
  173. package/dist/components/Article/Article.js +13 -0
  174. package/dist/components/Article/Article.js.map +1 -1
  175. package/dist/components/AspectRatio/AspectRatio.d.ts +46 -0
  176. package/dist/components/AspectRatio/AspectRatio.js +33 -0
  177. package/dist/components/AspectRatio/AspectRatio.js.map +1 -0
  178. package/dist/components/Avatar/Avatar.d.ts +12 -3
  179. package/dist/components/Avatar/Avatar.js +6 -1
  180. package/dist/components/Avatar/Avatar.js.map +1 -1
  181. package/dist/components/Breadcrumb/Breadcrumb.d.ts +6 -0
  182. package/dist/components/Breadcrumb/Breadcrumb.js +15 -0
  183. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -1
  184. package/dist/components/Button/Button.js +14 -0
  185. package/dist/components/Button/Button.js.map +1 -1
  186. package/dist/components/Calendar/Calendar.d.ts +29 -3
  187. package/dist/components/Calendar/Calendar.js +60 -12
  188. package/dist/components/Calendar/Calendar.js.map +1 -1
  189. package/dist/components/Card/Card.d.ts +6 -0
  190. package/dist/components/Card/Card.js +1 -1
  191. package/dist/components/Card/Card.js.map +1 -1
  192. package/dist/components/Checkbox/Checkbox.d.ts +5 -2
  193. package/dist/components/Checkbox/Checkbox.js +12 -2
  194. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  195. package/dist/components/Code/Code.d.ts +30 -0
  196. package/dist/components/Code/Code.js +21 -0
  197. package/dist/components/Code/Code.js.map +1 -0
  198. package/dist/components/CodeBlock/CodeBlock.d.ts +141 -0
  199. package/dist/components/CodeBlock/CodeBlock.js +123 -0
  200. package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
  201. package/dist/components/Collapsible/Collapsible.js +10 -2
  202. package/dist/components/Collapsible/Collapsible.js.map +1 -1
  203. package/dist/components/ColorPicker/ColorPicker.d.ts +67 -0
  204. package/dist/components/ColorPicker/ColorPicker.js +334 -0
  205. package/dist/components/ColorPicker/ColorPicker.js.map +1 -0
  206. package/dist/components/Combobox/Combobox.d.ts +15 -1
  207. package/dist/components/Combobox/Combobox.js +25 -5
  208. package/dist/components/Combobox/Combobox.js.map +1 -1
  209. package/dist/components/Command/Command.d.ts +4 -2
  210. package/dist/components/Command/Command.js +14 -2
  211. package/dist/components/Command/Command.js.map +1 -1
  212. package/dist/components/ContextMenu/ContextMenu.d.ts +30 -5
  213. package/dist/components/ContextMenu/ContextMenu.js +33 -3
  214. package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
  215. package/dist/components/DatePicker/DatePicker.d.ts +36 -4
  216. package/dist/components/DatePicker/DatePicker.js +55 -12
  217. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  218. package/dist/components/DescriptionList/DescriptionList.d.ts +73 -0
  219. package/dist/components/DescriptionList/DescriptionList.js +35 -0
  220. package/dist/components/DescriptionList/DescriptionList.js.map +1 -0
  221. package/dist/components/Diagram/Diagram.d.ts +8 -3
  222. package/dist/components/Diagram/Diagram.js +82 -10
  223. package/dist/components/Diagram/Diagram.js.map +1 -1
  224. package/dist/components/Dialog/Dialog.d.ts +18 -3
  225. package/dist/components/Dialog/Dialog.js +21 -3
  226. package/dist/components/Dialog/Dialog.js.map +1 -1
  227. package/dist/components/DropdownMenu/DropdownMenu.d.ts +49 -11
  228. package/dist/components/DropdownMenu/DropdownMenu.js +33 -3
  229. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  230. package/dist/components/EmptyState/EmptyState.d.ts +25 -1
  231. package/dist/components/EmptyState/EmptyState.js +3 -1
  232. package/dist/components/EmptyState/EmptyState.js.map +1 -1
  233. package/dist/components/ErrorState/ErrorState.d.ts +22 -1
  234. package/dist/components/ErrorState/ErrorState.js +12 -3
  235. package/dist/components/ErrorState/ErrorState.js.map +1 -1
  236. package/dist/components/Field/Field.d.ts +70 -3
  237. package/dist/components/Field/Field.js +53 -12
  238. package/dist/components/Field/Field.js.map +1 -1
  239. package/dist/components/Field/field-control.d.ts +31 -0
  240. package/dist/components/Field/field-control.js +12 -0
  241. package/dist/components/Field/field-control.js.map +1 -0
  242. package/dist/components/FloatingIconButton/FloatingIconButton.js +2 -0
  243. package/dist/components/FloatingIconButton/FloatingIconButton.js.map +1 -1
  244. package/dist/components/Heading/Heading.d.ts +62 -0
  245. package/dist/components/Heading/Heading.js +44 -0
  246. package/dist/components/Heading/Heading.js.map +1 -0
  247. package/dist/components/Markdown/Markdown.d.ts +139 -0
  248. package/dist/components/Markdown/Markdown.js +135 -0
  249. package/dist/components/Markdown/Markdown.js.map +1 -0
  250. package/dist/components/Markdown/inline.d.ts +29 -0
  251. package/dist/components/Markdown/inline.js +74 -0
  252. package/dist/components/Markdown/inline.js.map +1 -0
  253. package/dist/components/Markdown/nodes.d.ts +65 -0
  254. package/dist/components/Markdown/nodes.js +1 -0
  255. package/dist/components/Markdown/nodes.js.map +1 -0
  256. package/dist/components/Markdown/parse.d.ts +24 -0
  257. package/dist/components/Markdown/parse.js +110 -0
  258. package/dist/components/Markdown/parse.js.map +1 -0
  259. package/dist/components/Markdown/slug.d.ts +15 -0
  260. package/dist/components/Markdown/slug.js +7 -0
  261. package/dist/components/Markdown/slug.js.map +1 -0
  262. package/dist/components/NativeSelect/NativeSelect.d.ts +6 -0
  263. package/dist/components/NativeSelect/NativeSelect.js +2 -3
  264. package/dist/components/NativeSelect/NativeSelect.js.map +1 -1
  265. package/dist/components/NavItem/NavItem.js +1 -1
  266. package/dist/components/NavItem/NavItem.js.map +1 -1
  267. package/dist/components/NumberField/NumberField.d.ts +69 -0
  268. package/dist/components/NumberField/NumberField.js +162 -0
  269. package/dist/components/NumberField/NumberField.js.map +1 -0
  270. package/dist/components/Pagination/Pagination.d.ts +24 -1
  271. package/dist/components/Pagination/Pagination.js +6 -3
  272. package/dist/components/Pagination/Pagination.js.map +1 -1
  273. package/dist/components/Popover/Popover.js +1 -1
  274. package/dist/components/Popover/Popover.js.map +1 -1
  275. package/dist/components/Progress/Progress.d.ts +17 -5
  276. package/dist/components/Progress/Progress.js +18 -6
  277. package/dist/components/Progress/Progress.js.map +1 -1
  278. package/dist/components/RadioGroup/RadioGroup.d.ts +6 -0
  279. package/dist/components/RadioGroup/RadioGroup.js +11 -1
  280. package/dist/components/RadioGroup/RadioGroup.js.map +1 -1
  281. package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
  282. package/dist/components/ScrollArea/ScrollArea.js +2 -2
  283. package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
  284. package/dist/components/SearchableMenu/SearchableMenu.d.ts +11 -2
  285. package/dist/components/SearchableMenu/SearchableMenu.js +24 -2
  286. package/dist/components/SearchableMenu/SearchableMenu.js.map +1 -1
  287. package/dist/components/Select/Select.d.ts +18 -2
  288. package/dist/components/Select/Select.js +21 -4
  289. package/dist/components/Select/Select.js.map +1 -1
  290. package/dist/components/Separator/Separator.d.ts +21 -3
  291. package/dist/components/Separator/Separator.js +9 -1
  292. package/dist/components/Separator/Separator.js.map +1 -1
  293. package/dist/components/Sheet/Sheet.d.ts +3 -0
  294. package/dist/components/Sheet/Sheet.js +12 -3
  295. package/dist/components/Sheet/Sheet.js.map +1 -1
  296. package/dist/components/Sidebar/Sidebar.d.ts +349 -0
  297. package/dist/components/Sidebar/Sidebar.js +455 -0
  298. package/dist/components/Sidebar/Sidebar.js.map +1 -0
  299. package/dist/components/Skeleton/Skeleton.d.ts +8 -1
  300. package/dist/components/Skeleton/Skeleton.js +1 -1
  301. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  302. package/dist/components/Slider/Slider.d.ts +42 -3
  303. package/dist/components/Slider/Slider.js +121 -30
  304. package/dist/components/Slider/Slider.js.map +1 -1
  305. package/dist/components/Spinner/Spinner.d.ts +8 -0
  306. package/dist/components/Spinner/Spinner.js +3 -2
  307. package/dist/components/Spinner/Spinner.js.map +1 -1
  308. package/dist/components/StatusPill/StatusPill.d.ts +5 -0
  309. package/dist/components/StatusPill/StatusPill.js +6 -0
  310. package/dist/components/StatusPill/StatusPill.js.map +1 -1
  311. package/dist/components/Table/Table.d.ts +20 -0
  312. package/dist/components/Table/Table.js +3 -1
  313. package/dist/components/Table/Table.js.map +1 -1
  314. package/dist/components/Tabs/Tabs.js +7 -1
  315. package/dist/components/Tabs/Tabs.js.map +1 -1
  316. package/dist/components/Tag/Tag.d.ts +68 -9
  317. package/dist/components/Tag/Tag.js +50 -10
  318. package/dist/components/Tag/Tag.js.map +1 -1
  319. package/dist/components/Text/Text.d.ts +62 -0
  320. package/dist/components/Text/Text.js +30 -0
  321. package/dist/components/Text/Text.js.map +1 -0
  322. package/dist/components/Timestamp/Timestamp.d.ts +59 -0
  323. package/dist/components/Timestamp/Timestamp.js +56 -0
  324. package/dist/components/Timestamp/Timestamp.js.map +1 -0
  325. package/dist/components/Toast/Toast.d.ts +9 -1
  326. package/dist/components/Toast/Toast.js +27 -4
  327. package/dist/components/Toast/Toast.js.map +1 -1
  328. package/dist/components/ToggleGroup/ToggleGroup.d.ts +6 -1
  329. package/dist/components/ToggleGroup/ToggleGroup.js +11 -1
  330. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  331. package/dist/components/Toolbar/Toolbar.d.ts +55 -0
  332. package/dist/components/Toolbar/Toolbar.js +43 -0
  333. package/dist/components/Toolbar/Toolbar.js.map +1 -0
  334. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.d.ts +6 -0
  335. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js +48 -8
  336. package/dist/diagrams/ArchitectureFigure/ArchitectureFigure.js.map +1 -1
  337. package/dist/diagrams/DataflowFigure/DataflowFigure.js +21 -2
  338. package/dist/diagrams/DataflowFigure/DataflowFigure.js.map +1 -1
  339. package/dist/diagrams/DiagramCanvas/DiagramCanvas.d.ts +14 -0
  340. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js +14 -7
  341. package/dist/diagrams/DiagramCanvas/DiagramCanvas.js.map +1 -1
  342. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.d.ts +38 -4
  343. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js +14 -16
  344. package/dist/diagrams/DiagramExportMenu/DiagramExportMenu.js.map +1 -1
  345. package/dist/diagrams/DiagramInspector/DiagramInspector.js +2 -2
  346. package/dist/diagrams/DiagramInspector/DiagramInspector.js.map +1 -1
  347. package/dist/diagrams/DiagramMinimap/DiagramMinimap.d.ts +23 -7
  348. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js +45 -18
  349. package/dist/diagrams/DiagramMinimap/DiagramMinimap.js.map +1 -1
  350. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js +44 -12
  351. package/dist/diagrams/LifecycleFigure/LifecycleFigure.js.map +1 -1
  352. package/dist/diagrams/SequenceFigure/SequenceFigure.js +35 -5
  353. package/dist/diagrams/SequenceFigure/SequenceFigure.js.map +1 -1
  354. package/dist/diagrams/WorkflowFigure/WorkflowFigure.d.ts +3 -1
  355. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js +76 -28
  356. package/dist/diagrams/WorkflowFigure/WorkflowFigure.js.map +1 -1
  357. package/dist/diagrams/index.d.ts +1 -0
  358. package/dist/diagrams/index.js +10 -0
  359. package/dist/diagrams/index.js.map +1 -1
  360. package/dist/diagrams/lib/dev.d.ts +61 -0
  361. package/dist/diagrams/lib/dev.js +96 -0
  362. package/dist/diagrams/lib/dev.js.map +1 -0
  363. package/dist/diagrams/lib/frame.d.ts +48 -7
  364. package/dist/diagrams/lib/frame.js +17 -2
  365. package/dist/diagrams/lib/frame.js.map +1 -1
  366. package/dist/diagrams/lib/route.d.ts +22 -1
  367. package/dist/diagrams/lib/route.js +24 -1
  368. package/dist/diagrams/lib/route.js.map +1 -1
  369. package/dist/diagrams/lib/wires.js +9 -5
  370. package/dist/diagrams/lib/wires.js.map +1 -1
  371. package/dist/diagrams/spec.d.ts +64 -12
  372. package/dist/index.d.ts +19 -4
  373. package/dist/index.js +12 -0
  374. package/dist/index.js.map +1 -1
  375. package/dist/keyframes.css +57 -3
  376. package/dist/lib/color.d.ts +80 -0
  377. package/dist/lib/color.js +189 -0
  378. package/dist/lib/color.js.map +1 -0
  379. package/dist/lib/numeric.d.ts +35 -0
  380. package/dist/lib/numeric.js +29 -0
  381. package/dist/lib/numeric.js.map +1 -0
  382. package/dist/lib/overlay-container.d.ts +14 -4
  383. package/dist/lib/overlay-container.js.map +1 -1
  384. package/dist/lib/warn.d.ts +73 -0
  385. package/dist/lib/warn.js +38 -0
  386. package/dist/lib/warn.js.map +1 -0
  387. package/dist/semantic.css +17 -6
  388. package/dist/styles.css +1 -1
  389. package/dist/themes.css +8 -0
  390. package/dist/tokens.css +86 -5
  391. package/dist/tokens.d.ts +4 -1
  392. package/dist/tokens.js +56 -36
  393. package/dist/tokens.json +56 -36
  394. package/llms.txt +35 -0
  395. package/package.json +5 -2
  396. package/skills/misoto22-design/evals/evals.json +84 -0
  397. package/skills/misoto22-design/rules/a11y.md +55 -3
  398. package/skills/misoto22-design/rules/forms.md +8 -1
@@ -2,10 +2,19 @@ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
 
4
4
  interface MenuAction {
5
- /** Stable id, and what the filter matches on. */
5
+ /**
6
+ * Stable identity for the row. Not what the filter matches — the label is,
7
+ * and an id a reader would never type is exactly what this used to be.
8
+ */
6
9
  id: string;
10
+ /** What the row prints. Its text is the first thing the filter matches. */
7
11
  label: ReactNode;
8
- /** Plain text the filter should match beyond the label. */
12
+ /**
13
+ * More text the filter should match, beyond the label's own words.
14
+ *
15
+ * The synonym a reader reaches for first: "download" for Export, "bin" for
16
+ * Delete. Required in practice only when the label prints no text at all.
17
+ */
9
18
  keywords?: string[];
10
19
  /** Printed at the end of the row. */
11
20
  shortcut?: string;
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { ChevronDown } from "lucide-react";
4
- import { useState } from "react";
4
+ import { isValidElement, useState } from "react";
5
5
  import { cn } from "../../lib/cn.js";
6
+ import { DEV, warn } from "../../lib/warn.js";
6
7
  import {
7
8
  Command,
8
9
  CommandEmpty,
@@ -13,6 +14,27 @@ import {
13
14
  CommandSeparator
14
15
  } from "../Command/Command.js";
15
16
  import { Popover, PopoverContent, PopoverTrigger } from "../Popover/Popover.js";
17
+ function textOf(node) {
18
+ if (typeof node === "string") return node;
19
+ if (typeof node === "number") return String(node);
20
+ if (Array.isArray(node)) return node.map(textOf).join(" ");
21
+ if (isValidElement(node)) return textOf(node.props.children);
22
+ return "";
23
+ }
24
+ function filterKeywords(action) {
25
+ const label = textOf(action.label).trim();
26
+ const extra = action.keywords ?? [];
27
+ if (DEV && !label && extra.length === 0) {
28
+ warn({
29
+ code: "SEARCHABLE_MENU_LABEL_UNREADABLE",
30
+ problem: "A SearchableMenu action has a label with no text in it, so the filter has nothing to match and the row can never be found by typing.",
31
+ field: "actions[].label",
32
+ fix: "Give the action keywords with the words a reader would type for it, or put text in the label.",
33
+ component: "SearchableMenu"
34
+ });
35
+ }
36
+ return label ? [label, ...extra] : extra;
37
+ }
16
38
  function SearchableMenu({
17
39
  actions,
18
40
  children,
@@ -54,7 +76,7 @@ function SearchableMenu({
54
76
  CommandItem,
55
77
  {
56
78
  value: action.id,
57
- keywords: action.keywords,
79
+ keywords: filterKeywords(action),
58
80
  disabled: action.disabled,
59
81
  shortcut: action.shortcut,
60
82
  onSelect: () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/SearchableMenu/SearchableMenu.tsx"],"sourcesContent":["'use client'\n\nimport { ChevronDown } from 'lucide-react'\nimport { useState, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '../Command/Command'\nimport { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover'\n\nexport interface MenuAction {\n /** Stable id, and what the filter matches on. */\n id: string\n label: ReactNode\n /** Plain text the filter should match beyond the label. */\n keywords?: string[]\n /** Printed at the end of the row. */\n shortcut?: string\n /** Optional group heading. Rows with the same value are shown together. */\n group?: string\n disabled?: boolean\n destructive?: boolean\n onSelect: () => void\n}\n\nexport interface SearchableMenuProps {\n actions: MenuAction[]\n /** The trigger's text. */\n children: ReactNode\n /** Names the menu for assistive tech. */\n label: string\n searchPlaceholder?: string\n emptyMessage?: string\n align?: 'start' | 'center' | 'end'\n className?: string\n}\n\n/**\n * A menu of actions you can type into.\n *\n * The fourth corner of a square the system otherwise had three of, and the\n * distinction is worth stating because reaching for the wrong one is easy:\n *\n * | | few options | many options |\n * |---|---|---|\n * | **sets a value** | `Select` | `Combobox` |\n * | **runs an action** | `DropdownMenu` | `SearchableMenu` |\n *\n * A `DropdownMenu` past about a dozen rows stops being scannable, and the\n * usual response — nesting submenus — makes it worse. This is the same list\n * with a filter over it.\n *\n * Not the same thing as `Command`: that is a page-level palette, usually modal\n * and usually bound to ⌘K. This is anchored to a control, like the menu it\n * replaces.\n *\n * The rows are `option`s inside a listbox rather than `menuitem`s, because that\n * is what the filtering pattern requires — the highlight moves through\n * `aria-activedescendant` while focus stays in the input, and a menu cannot do\n * that. The trade is deliberate: a menu that cannot be filtered is worse for\n * the reader than a listbox that runs actions.\n *\n * @example\n * <SearchableMenu label=\"Actions\" actions={ACTIONS}>Actions</SearchableMenu>\n */\nexport function SearchableMenu({\n actions,\n children,\n label,\n searchPlaceholder = 'Filter…',\n emptyMessage = 'Nothing matches.',\n align = 'start',\n className,\n}: SearchableMenuProps) {\n const [open, setOpen] = useState(false)\n\n // Grouped in declaration order, so a caller controls the arrangement by the\n // order they list actions rather than by an extra prop.\n const groups: { name: string | undefined; items: MenuAction[] }[] = []\n for (const action of actions) {\n const last = groups.at(-1)\n if (last && last.name === action.group) last.items.push(action)\n else groups.push({ name: action.group, items: [action] })\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n aria-label={label}\n className={cn(\n 'inline-flex min-h-(--control-h-sm) items-center gap-2 rounded-(--radius-pill) border border-(--rule-2) px-4 text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:border-(--ink)',\n className,\n )}\n >\n {children}\n <ChevronDown size={14} strokeWidth={1.5} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n </PopoverTrigger>\n <PopoverContent label={label} align={align} className=\"w-64 overflow-hidden p-0\">\n <Command label={`${label}: ${searchPlaceholder}`} className=\"rounded-none border-0\">\n <CommandInput placeholder={searchPlaceholder} />\n <CommandList>\n <CommandEmpty>{emptyMessage}</CommandEmpty>\n {groups.map((group, index) => (\n <div key={group.name ?? index}>\n {index > 0 && <CommandSeparator />}\n <CommandGroup heading={group.name}>\n {group.items.map((action) => (\n <CommandItem\n key={action.id}\n value={action.id}\n keywords={action.keywords}\n disabled={action.disabled}\n shortcut={action.shortcut}\n onSelect={() => {\n setOpen(false)\n action.onSelect()\n }}\n className={action.destructive ? 'text-(--danger)' : undefined}\n >\n {action.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </div>\n ))}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n\nexport default SearchableMenu\n"],"mappings":";AA6FM,SAQE,KARF;AA3FN,SAAS,mBAAmB;AAC5B,SAAS,gBAAgC;AACzC,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,gBAAgB,sBAAsB;AAyDjD,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,QAAQ;AAAA,EACR;AACF,GAAwB;AACtB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAItC,QAAM,SAA8D,CAAC;AACrE,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,OAAO,GAAG,EAAE;AACzB,QAAI,QAAQ,KAAK,SAAS,OAAO,MAAO,MAAK,MAAM,KAAK,MAAM;AAAA,QACzD,QAAO,KAAK,EAAE,MAAM,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;AAAA,EAC1D;AAEA,SACE,qBAAC,WAAQ,MAAY,cAAc,SACjC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,cAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,UACD,oBAAC,eAAY,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,WAAU,8BAA6B;AAAA;AAAA;AAAA,IAC9F;AAAA,IACA,oBAAC,kBAAe,OAAc,OAAc,WAAU,4BACpD,+BAAC,WAAQ,OAAO,GAAG,KAAK,KAAK,iBAAiB,IAAI,WAAU,yBAC1D;AAAA,0BAAC,gBAAa,aAAa,mBAAmB;AAAA,MAC9C,qBAAC,eACC;AAAA,4BAAC,gBAAc,wBAAa;AAAA,QAC3B,OAAO,IAAI,CAAC,OAAO,UAClB,qBAAC,SACE;AAAA,kBAAQ,KAAK,oBAAC,oBAAiB;AAAA,UAChC,oBAAC,gBAAa,SAAS,MAAM,MAC1B,gBAAM,MAAM,IAAI,CAAC,WAChB;AAAA,YAAC;AAAA;AAAA,cAEC,OAAO,OAAO;AAAA,cACd,UAAU,OAAO;AAAA,cACjB,UAAU,OAAO;AAAA,cACjB,UAAU,OAAO;AAAA,cACjB,UAAU,MAAM;AACd,wBAAQ,KAAK;AACb,uBAAO,SAAS;AAAA,cAClB;AAAA,cACA,WAAW,OAAO,cAAc,oBAAoB;AAAA,cAEnD,iBAAO;AAAA;AAAA,YAXH,OAAO;AAAA,UAYd,CACD,GACH;AAAA,aAnBQ,MAAM,QAAQ,KAoBxB,CACD;AAAA,SACH;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEA,IAAO,yBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/SearchableMenu/SearchableMenu.tsx"],"sourcesContent":["'use client'\n\nimport { ChevronDown } from 'lucide-react'\nimport { isValidElement, useState, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { DEV, warn } from '../../lib/warn'\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandSeparator,\n} from '../Command/Command'\nimport { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover'\n\nexport interface MenuAction {\n /**\n * Stable identity for the row. Not what the filter matches the label is,\n * and an id a reader would never type is exactly what this used to be.\n */\n id: string\n /** What the row prints. Its text is the first thing the filter matches. */\n label: ReactNode\n /**\n * More text the filter should match, beyond the label's own words.\n *\n * The synonym a reader reaches for first: \"download\" for Export, \"bin\" for\n * Delete. Required in practice only when the label prints no text at all.\n */\n keywords?: string[]\n /** Printed at the end of the row. */\n shortcut?: string\n /** Optional group heading. Rows with the same value are shown together. */\n group?: string\n disabled?: boolean\n destructive?: boolean\n onSelect: () => void\n}\n\nexport interface SearchableMenuProps {\n actions: MenuAction[]\n /** The trigger's text. */\n children: ReactNode\n /** Names the menu for assistive tech. */\n label: string\n searchPlaceholder?: string\n emptyMessage?: string\n align?: 'start' | 'center' | 'end'\n className?: string\n}\n\n/** The plain text a label prints, gathered through whatever wraps it. */\nfunction textOf(node: ReactNode): string {\n if (typeof node === 'string') return node\n if (typeof node === 'number') return String(node)\n if (Array.isArray(node)) return node.map(textOf).join(' ')\n if (isValidElement<{ children?: ReactNode }>(node)) return textOf(node.props.children)\n return ''\n}\n\n/**\n * What the filter matches this row on.\n *\n * cmdk derives an item's value from the first string in\n * `[props.value, props.children, ref]`, and only falls back to the row's\n * `textContent` when `value` is absent. This component passes the id as the\n * value, because that is the row's identity and two rows may print the same\n * words — so with the opaque ids an application actually has, the label a\n * reader can SEE scored zero and the menu showed its empty state. Lifting the\n * label's text into the keywords is what makes the visible words match, while\n * the id stays the identity.\n */\nfunction filterKeywords(action: MenuAction): string[] {\n const label = textOf(action.label).trim()\n const extra = action.keywords ?? []\n\n if (DEV && !label && extra.length === 0) {\n warn({\n code: 'SEARCHABLE_MENU_LABEL_UNREADABLE',\n problem:\n 'A SearchableMenu action has a label with no text in it, so the filter has nothing to match and the row can never be found by typing.',\n field: 'actions[].label',\n fix: 'Give the action keywords with the words a reader would type for it, or put text in the label.',\n component: 'SearchableMenu',\n })\n }\n\n return label ? [label, ...extra] : extra\n}\n\n/**\n * A menu of actions you can type into.\n *\n * The fourth corner of a square the system otherwise had three of, and the\n * distinction is worth stating because reaching for the wrong one is easy:\n *\n * | | few options | many options |\n * |---|---|---|\n * | **sets a value** | `Select` | `Combobox` |\n * | **runs an action** | `DropdownMenu` | `SearchableMenu` |\n *\n * A `DropdownMenu` past about a dozen rows stops being scannable, and the\n * usual response — nesting submenus — makes it worse. This is the same list\n * with a filter over it.\n *\n * Not the same thing as `Command`: that is a page-level palette, usually modal\n * and usually bound to ⌘K. This is anchored to a control, like the menu it\n * replaces.\n *\n * The rows are `option`s inside a listbox rather than `menuitem`s, because that\n * is what the filtering pattern requires — the highlight moves through\n * `aria-activedescendant` while focus stays in the input, and a menu cannot do\n * that. The trade is deliberate: a menu that cannot be filtered is worse for\n * the reader than a listbox that runs actions.\n *\n * @example\n * <SearchableMenu label=\"Actions\" actions={ACTIONS}>Actions</SearchableMenu>\n */\nexport function SearchableMenu({\n actions,\n children,\n label,\n searchPlaceholder = 'Filter…',\n emptyMessage = 'Nothing matches.',\n align = 'start',\n className,\n}: SearchableMenuProps) {\n const [open, setOpen] = useState(false)\n\n // Grouped in declaration order, so a caller controls the arrangement by the\n // order they list actions rather than by an extra prop.\n const groups: { name: string | undefined; items: MenuAction[] }[] = []\n for (const action of actions) {\n const last = groups.at(-1)\n if (last && last.name === action.group) last.items.push(action)\n else groups.push({ name: action.group, items: [action] })\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n aria-label={label}\n className={cn(\n 'inline-flex min-h-(--control-h-sm) items-center gap-2 rounded-(--radius-pill) border border-(--rule-2) px-4 text-sm text-(--ink) transition-colors duration-(--duration-fast) hover:border-(--ink)',\n className,\n )}\n >\n {children}\n <ChevronDown size={14} strokeWidth={1.5} aria-hidden className=\"shrink-0 text-(--ink-3-aa)\" />\n </PopoverTrigger>\n <PopoverContent label={label} align={align} className=\"w-64 overflow-hidden p-0\">\n <Command label={`${label}: ${searchPlaceholder}`} className=\"rounded-none border-0\">\n <CommandInput placeholder={searchPlaceholder} />\n <CommandList>\n <CommandEmpty>{emptyMessage}</CommandEmpty>\n {groups.map((group, index) => (\n <div key={group.name ?? index}>\n {index > 0 && <CommandSeparator />}\n <CommandGroup heading={group.name}>\n {group.items.map((action) => (\n <CommandItem\n key={action.id}\n value={action.id}\n keywords={filterKeywords(action)}\n disabled={action.disabled}\n shortcut={action.shortcut}\n onSelect={() => {\n setOpen(false)\n action.onSelect()\n }}\n className={action.destructive ? 'text-(--danger)' : undefined}\n >\n {action.label}\n </CommandItem>\n ))}\n </CommandGroup>\n </div>\n ))}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n )\n}\n\nexport default SearchableMenu\n"],"mappings":";AA8IM,SAQE,KARF;AA5IN,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB,gBAAgC;AACzD,SAAS,UAAU;AACnB,SAAS,KAAK,YAAY;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,gBAAgB,sBAAsB;AAuCxD,SAAS,OAAO,MAAyB;AACvC,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,OAAO,SAAS,SAAU,QAAO,OAAO,IAAI;AAChD,MAAI,MAAM,QAAQ,IAAI,EAAG,QAAO,KAAK,IAAI,MAAM,EAAE,KAAK,GAAG;AACzD,MAAI,eAAyC,IAAI,EAAG,QAAO,OAAO,KAAK,MAAM,QAAQ;AACrF,SAAO;AACT;AAcA,SAAS,eAAe,QAA8B;AACpD,QAAM,QAAQ,OAAO,OAAO,KAAK,EAAE,KAAK;AACxC,QAAM,QAAQ,OAAO,YAAY,CAAC;AAElC,MAAI,OAAO,CAAC,SAAS,MAAM,WAAW,GAAG;AACvC,SAAK;AAAA,MACH,MAAM;AAAA,MACN,SACE;AAAA,MACF,OAAO;AAAA,MACP,KAAK;AAAA,MACL,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO,QAAQ,CAAC,OAAO,GAAG,KAAK,IAAI;AACrC;AA8BO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,QAAQ;AAAA,EACR;AACF,GAAwB;AACtB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAItC,QAAM,SAA8D,CAAC;AACrE,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,OAAO,GAAG,EAAE;AACzB,QAAI,QAAQ,KAAK,SAAS,OAAO,MAAO,MAAK,MAAM,KAAK,MAAM;AAAA,QACzD,QAAO,KAAK,EAAE,MAAM,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;AAAA,EAC1D;AAEA,SACE,qBAAC,WAAQ,MAAY,cAAc,SACjC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,cAAY;AAAA,QACZ,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,UACD,oBAAC,eAAY,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,WAAU,8BAA6B;AAAA;AAAA;AAAA,IAC9F;AAAA,IACA,oBAAC,kBAAe,OAAc,OAAc,WAAU,4BACpD,+BAAC,WAAQ,OAAO,GAAG,KAAK,KAAK,iBAAiB,IAAI,WAAU,yBAC1D;AAAA,0BAAC,gBAAa,aAAa,mBAAmB;AAAA,MAC9C,qBAAC,eACC;AAAA,4BAAC,gBAAc,wBAAa;AAAA,QAC3B,OAAO,IAAI,CAAC,OAAO,UAClB,qBAAC,SACE;AAAA,kBAAQ,KAAK,oBAAC,oBAAiB;AAAA,UAChC,oBAAC,gBAAa,SAAS,MAAM,MAC1B,gBAAM,MAAM,IAAI,CAAC,WAChB;AAAA,YAAC;AAAA;AAAA,cAEC,OAAO,OAAO;AAAA,cACd,UAAU,eAAe,MAAM;AAAA,cAC/B,UAAU,OAAO;AAAA,cACjB,UAAU,OAAO;AAAA,cACjB,UAAU,MAAM;AACd,wBAAQ,KAAK;AACb,uBAAO,SAAS;AAAA,cAClB;AAAA,cACA,WAAW,OAAO,cAAc,oBAAoB;AAAA,cAEnD,iBAAO;AAAA;AAAA,YAXH,OAAO;AAAA,UAYd,CACD,GACH;AAAA,aAnBQ,MAAM,QAAQ,KAoBxB,CACD;AAAA,SACH;AAAA,OACF,GACF;AAAA,KACF;AAEJ;AAEA,IAAO,yBAAQ;","names":[]}
@@ -15,13 +15,29 @@ interface SelectProps extends ComponentProps<typeof SelectPrimitive.Root> {
15
15
  * picker over its own calendar, say.
16
16
  */
17
17
  contentClassName?: string;
18
- /** Names the control. Required — the trigger shows a value, and a value is not a name. */
18
+ /**
19
+ * Names the control. Required — the trigger shows a value, and a value is not
20
+ * a name.
21
+ *
22
+ * It is announced together with the value, not instead of it: the trigger is
23
+ * named by the label and by its own text, so a reader hears "Region,
24
+ * Australia". Inside a `Field` with a label, that label is used and this one
25
+ * is not repeated.
26
+ */
19
27
  label: string;
20
28
  placeholder?: string;
21
29
  /** Paints the resting border with `--danger` and reflects `aria-invalid`. */
22
30
  invalid?: boolean;
23
31
  disabled?: boolean;
24
32
  className?: string;
33
+ /** The TRIGGER's id — the element a label points at. A `Field` sets it. */
34
+ id?: string;
35
+ /** Ids of the copy describing the control. A `Field` sets it from hint, error and description. */
36
+ 'aria-describedby'?: string;
37
+ /** The spelling a form library sets; read together with `invalid`. */
38
+ 'aria-invalid'?: boolean | 'true' | 'false';
39
+ /** Announced on the trigger. A `Field` sets it from `required`. */
40
+ 'aria-required'?: boolean;
25
41
  /** `SelectItem`s, optionally wrapped in `SelectGroup` with a `SelectLabel`. */
26
42
  children: ReactNode;
27
43
  }
@@ -53,7 +69,7 @@ interface SelectProps extends ComponentProps<typeof SelectPrimitive.Root> {
53
69
  * </Select>
54
70
  * </Field>
55
71
  */
56
- declare function Select({ label, placeholder, invalid, disabled, className, contentClassName, children, ...props }: SelectProps): react.JSX.Element;
72
+ declare function Select({ label, placeholder, invalid, disabled, className, contentClassName, children, id, 'aria-describedby': describedBy, 'aria-invalid': ariaInvalid, 'aria-required': ariaRequired, ...props }: SelectProps): react.JSX.Element;
57
73
  type SelectItemProps = ComponentProps<typeof SelectPrimitive.Item>;
58
74
  /** One option. The tick marks the chosen one; the fill marks the highlighted one. */
59
75
  declare function SelectItem({ className, children, ...props }: SelectItemProps): react.JSX.Element;
@@ -2,8 +2,11 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as SelectPrimitive from "@radix-ui/react-select";
4
4
  import { Check, ChevronDown, ChevronUp } from "lucide-react";
5
+ import { useId } from "react";
5
6
  import { cn } from "../../lib/cn.js";
7
+ import { warnBlankName } from "../../lib/warn.js";
6
8
  import { useOverlayContainer } from "../../lib/overlay-container.js";
9
+ import { useFieldControl } from "../Field/field-control.js";
7
10
  import { CONTROL_BASE, CONTROL_BORDER, isInvalid } from "../../lib/control.js";
8
11
  const SelectRoot = SelectPrimitive.Root;
9
12
  const SelectGroup = SelectPrimitive.Group;
@@ -15,15 +18,28 @@ function Select({
15
18
  className,
16
19
  contentClassName,
17
20
  children,
21
+ id,
22
+ "aria-describedby": describedBy,
23
+ "aria-invalid": ariaInvalid,
24
+ "aria-required": ariaRequired,
18
25
  ...props
19
26
  }) {
20
- const bad = isInvalid(invalid);
27
+ warnBlankName("Select", "label", label, "the trigger is announced with no name");
28
+ const bad = isInvalid(invalid, ariaInvalid);
29
+ const field = useFieldControl();
30
+ const generated = useId();
31
+ const triggerId = id ?? generated;
32
+ const valueId = `${triggerId}-value`;
33
+ const nameId = field?.labelId ?? `${triggerId}-name`;
21
34
  const container = useOverlayContainer();
22
35
  return /* @__PURE__ */ jsxs(SelectPrimitive.Root, { disabled, ...props, children: [
23
36
  /* @__PURE__ */ jsxs(
24
37
  SelectPrimitive.Trigger,
25
38
  {
26
- "aria-label": label,
39
+ id: triggerId,
40
+ "aria-labelledby": `${nameId} ${valueId}`,
41
+ "aria-describedby": describedBy,
42
+ "aria-required": ariaRequired,
27
43
  "aria-invalid": bad || void 0,
28
44
  className: cn(
29
45
  CONTROL_BASE,
@@ -32,7 +48,8 @@ function Select({
32
48
  className
33
49
  ),
34
50
  children: [
35
- /* @__PURE__ */ jsx(SelectPrimitive.Value, { placeholder }),
51
+ field?.labelId == null && /* @__PURE__ */ jsx("span", { id: nameId, className: "sr-only", children: label }),
52
+ /* @__PURE__ */ jsx("span", { id: valueId, className: "truncate", children: /* @__PURE__ */ jsx(SelectPrimitive.Value, { placeholder }) }),
36
53
  /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(
37
54
  ChevronDown,
38
55
  {
@@ -54,7 +71,7 @@ function Select({
54
71
  sideOffset: 6,
55
72
  "data-m22-animated": true,
56
73
  className: cn(
57
- "z-(--z-dropdown) max-h-72 min-w-(--radix-select-trigger-width) overflow-hidden rounded-(--radius-lg) border border-(--panel-border) bg-(--panel-bg) panel-blur",
74
+ "z-(--z-dropdown) max-h-72 min-w-(--radix-select-trigger-width) overflow-hidden rounded-(--radius-lg) border border-(--panel-border) bg-(--panel-bg) shadow-(--panel-lift) panel-blur",
58
75
  contentClassName,
59
76
  "data-[state=open]:animate-[m22-pop-in_var(--duration-fast)_var(--ease-out-expo)] data-[state=closed]:animate-[m22-pop-out_var(--duration-fast)_var(--ease)] origin-(--radix-popper-transform-origin)"
60
77
  ),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { Check, ChevronDown, ChevronUp } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useOverlayContainer } from '../../lib/overlay-container'\nimport { CONTROL_BASE, CONTROL_BORDER, isInvalid } from '../../lib/control'\n\n/** Radix Select root, group and label, as typed passthroughs. */\nexport const SelectRoot = SelectPrimitive.Root\nexport const SelectGroup = SelectPrimitive.Group\n\nexport interface SelectProps extends ComponentProps<typeof SelectPrimitive.Root> {\n /**\n * Classes for the option PANEL, not the trigger.\n *\n * `className` styles the trigger, which is the common case. This exists for\n * the uncommon one: a select inside a bounded surface, where the default\n * 18rem of list would cover the thing the reader is choosing for — a year\n * picker over its own calendar, say.\n */\n contentClassName?: string\n /** Names the control. Required — the trigger shows a value, and a value is not a name. */\n label: string\n placeholder?: string\n /** Paints the resting border with `--danger` and reflects `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n className?: string\n /** `SelectItem`s, optionally wrapped in `SelectGroup` with a `SelectLabel`. */\n children: ReactNode\n}\n\n/**\n * A choice from a list, styled the whole way down.\n *\n * The option list is ours — drawn from the same tokens as everything else, so\n * it does not change typeface, spacing and selection colour the moment it\n * opens. That is the whole reason this replaced the native control as the\n * default: a design system whose most common form control stops being part of\n * the system on click is not a design system, it is a stylesheet for closed\n * states.\n *\n * The keyboard contract is Radix's, which means it is the platform's: typeahead\n * works, the arrows move, Home and End reach the ends, and Escape closes\n * without choosing. That was the one genuine argument for staying native, and\n * it is answered.\n *\n * Past roughly a dozen options, reach for `Combobox` — a list nobody can filter\n * is worse than one they can type into. Where the platform picker is genuinely\n * better — a phone, or a form that must survive without JavaScript — reach for\n * `NativeSelect`.\n *\n * @example\n * <Field label=\"Region\">\n * <Select label=\"Region\" defaultValue=\"au\">\n * <SelectItem value=\"au\">Australia</SelectItem>\n * <SelectItem value=\"nz\">New Zealand</SelectItem>\n * </Select>\n * </Field>\n */\nexport function Select({\n label,\n placeholder = 'Select…',\n invalid,\n disabled,\n className,\n contentClassName,\n children,\n ...props\n}: SelectProps) {\n const bad = isInvalid(invalid)\n const container = useOverlayContainer()\n\n return (\n <SelectPrimitive.Root disabled={disabled} {...props}>\n <SelectPrimitive.Trigger\n aria-label={label}\n aria-invalid={bad || undefined}\n className={cn(\n CONTROL_BASE,\n 'group flex cursor-pointer items-center justify-between gap-2 text-start data-[placeholder]:text-(--ink-3-aa)',\n bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,\n className,\n )}\n >\n <SelectPrimitive.Value placeholder={placeholder} />\n <SelectPrimitive.Icon asChild>\n <ChevronDown\n size={16}\n strokeWidth={1.5}\n aria-hidden\n className=\"shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-fast) group-data-[state=open]:rotate-180\"\n />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal container={container ?? undefined}>\n <SelectPrimitive.Content\n collisionBoundary={container ?? undefined}\n collisionPadding={8}\n position=\"popper\"\n sideOffset={6}\n data-m22-animated\n className={cn(\n 'z-(--z-dropdown) max-h-72 min-w-(--radix-select-trigger-width) overflow-hidden rounded-(--radius-lg) border border-(--panel-border) bg-(--panel-bg) panel-blur',\n contentClassName,\n 'data-[state=open]:animate-[m22-pop-in_var(--duration-fast)_var(--ease-out-expo)] data-[state=closed]:animate-[m22-pop-out_var(--duration-fast)_var(--ease)] origin-(--radix-popper-transform-origin)',\n )}\n >\n <SelectPrimitive.ScrollUpButton className=\"flex h-6 items-center justify-center text-(--ink-3-aa)\">\n <ChevronUp size={14} strokeWidth={1.5} aria-hidden />\n </SelectPrimitive.ScrollUpButton>\n <SelectPrimitive.Viewport className=\"p-1.5\">{children}</SelectPrimitive.Viewport>\n <SelectPrimitive.ScrollDownButton className=\"flex h-6 items-center justify-center text-(--ink-3-aa)\">\n <ChevronDown size={14} strokeWidth={1.5} aria-hidden />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n )\n}\n\nexport type SelectItemProps = ComponentProps<typeof SelectPrimitive.Item>\n\n/** One option. The tick marks the chosen one; the fill marks the highlighted one. */\nexport function SelectItem({ className, children, ...props }: SelectItemProps) {\n return (\n <SelectPrimitive.Item\n className={cn(\n 'flex cursor-pointer select-none items-center gap-2.5 rounded-(--radius-row) px-2.5 py-2 text-sm text-(--ink-2) outline-none transition-colors duration-(--duration-fast) data-[highlighted]:bg-(--stone) data-[highlighted]:text-(--ink) data-[disabled]:pointer-events-none data-[disabled]:opacity-(--disabled-opacity)',\n className,\n )}\n {...props}\n >\n {/* The box is always there and only the tick inside it appears, so\n choosing an option does not shunt every label sideways. */}\n <span className=\"grid size-3.5 shrink-0 place-items-center\">\n <SelectPrimitive.ItemIndicator asChild>\n <Check size={14} strokeWidth={2} aria-hidden />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\n/**\n * Mono eyebrow heading for a group of options.\n *\n * Must sit inside a `SelectGroup` — Radix throws otherwise, because a heading\n * with no group is a heading for nothing, and assistive tech would announce it\n * as an option.\n */\nexport function SelectLabel({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n className={cn('px-2.5 py-1.5 eyebrow text-(--ink-3-aa)', className)}\n {...props}\n />\n )\n}\n\n/** Hairline divider between groups. */\nexport function SelectSeparator({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator className={cn('my-1 h-px bg-(--rule)', className)} {...props} />\n )\n}\n\nexport default Select\n"],"mappings":";AA6EM,SAUE,KAVF;AA3EN,YAAY,qBAAqB;AACjC,SAAS,OAAO,aAAa,iBAAiB;AAE9C,SAAS,UAAU;AACnB,SAAS,2BAA2B;AACpC,SAAS,cAAc,gBAAgB,iBAAiB;AAGjD,MAAM,aAAa,gBAAgB;AACnC,MAAM,cAAc,gBAAgB;AAmDpC,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAgB;AACd,QAAM,MAAM,UAAU,OAAO;AAC7B,QAAM,YAAY,oBAAoB;AAEtC,SACE,qBAAC,gBAAgB,MAAhB,EAAqB,UAAqB,GAAG,OAC5C;AAAA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,cAAY;AAAA,QACZ,gBAAc,OAAO;AAAA,QACrB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,MAAM,eAAe,UAAU,eAAe;AAAA,UAC9C;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,gBAAgB,OAAhB,EAAsB,aAA0B;AAAA,UACjD,oBAAC,gBAAgB,MAAhB,EAAqB,SAAO,MAC3B;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,aAAa;AAAA,cACb,eAAW;AAAA,cACX,WAAU;AAAA;AAAA,UACZ,GACF;AAAA;AAAA;AAAA,IACF;AAAA,IAEA,oBAAC,gBAAgB,QAAhB,EAAuB,WAAW,aAAa,QAC9C;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACD,mBAAmB,aAAa;AAAA,QAChC,kBAAkB;AAAA,QAChB,UAAS;AAAA,QACT,YAAY;AAAA,QACZ,qBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,gBAAgB,gBAAhB,EAA+B,WAAU,0DACxC,8BAAC,aAAU,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,GACrD;AAAA,UACA,oBAAC,gBAAgB,UAAhB,EAAyB,WAAU,SAAS,UAAS;AAAA,UACtD,oBAAC,gBAAgB,kBAAhB,EAAiC,WAAU,0DAC1C,8BAAC,eAAY,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,GACvD;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;AAKO,SAAS,WAAW,EAAE,WAAW,UAAU,GAAG,MAAM,GAAoB;AAC7E,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAIJ;AAAA,4BAAC,UAAK,WAAU,6CACd,8BAAC,gBAAgB,eAAhB,EAA8B,SAAO,MACpC,8BAAC,SAAM,MAAM,IAAI,aAAa,GAAG,eAAW,MAAC,GAC/C,GACF;AAAA,QACA,oBAAC,gBAAgB,UAAhB,EAA0B,UAAS;AAAA;AAAA;AAAA,EACtC;AAEJ;AASO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW,GAAG,2CAA2C,SAAS;AAAA,MACjE,GAAG;AAAA;AAAA,EACN;AAEJ;AAGO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,GAAG;AACL,GAAqD;AACnD,SACE,oBAAC,gBAAgB,WAAhB,EAA0B,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO;AAE7F;AAEA,IAAO,iBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["'use client'\n\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { Check, ChevronDown, ChevronUp } from 'lucide-react'\nimport { useId, type ComponentProps, type ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { warnBlankName } from '../../lib/warn'\nimport { useOverlayContainer } from '../../lib/overlay-container'\nimport { useFieldControl } from '../Field/field-control'\nimport { CONTROL_BASE, CONTROL_BORDER, isInvalid } from '../../lib/control'\n\n/** Radix Select root, group and label, as typed passthroughs. */\nexport const SelectRoot = SelectPrimitive.Root\nexport const SelectGroup = SelectPrimitive.Group\n\nexport interface SelectProps extends ComponentProps<typeof SelectPrimitive.Root> {\n /**\n * Classes for the option PANEL, not the trigger.\n *\n * `className` styles the trigger, which is the common case. This exists for\n * the uncommon one: a select inside a bounded surface, where the default\n * 18rem of list would cover the thing the reader is choosing for — a year\n * picker over its own calendar, say.\n */\n contentClassName?: string\n /**\n * Names the control. Required — the trigger shows a value, and a value is not\n * a name.\n *\n * It is announced together with the value, not instead of it: the trigger is\n * named by the label and by its own text, so a reader hears \"Region,\n * Australia\". Inside a `Field` with a label, that label is used and this one\n * is not repeated.\n */\n label: string\n placeholder?: string\n /** Paints the resting border with `--danger` and reflects `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n className?: string\n /** The TRIGGER's id — the element a label points at. A `Field` sets it. */\n id?: string\n /** Ids of the copy describing the control. A `Field` sets it from hint, error and description. */\n 'aria-describedby'?: string\n /** The spelling a form library sets; read together with `invalid`. */\n 'aria-invalid'?: boolean | 'true' | 'false'\n /** Announced on the trigger. A `Field` sets it from `required`. */\n 'aria-required'?: boolean\n /** `SelectItem`s, optionally wrapped in `SelectGroup` with a `SelectLabel`. */\n children: ReactNode\n}\n\n/**\n * A choice from a list, styled the whole way down.\n *\n * The option list is ours — drawn from the same tokens as everything else, so\n * it does not change typeface, spacing and selection colour the moment it\n * opens. That is the whole reason this replaced the native control as the\n * default: a design system whose most common form control stops being part of\n * the system on click is not a design system, it is a stylesheet for closed\n * states.\n *\n * The keyboard contract is Radix's, which means it is the platform's: typeahead\n * works, the arrows move, Home and End reach the ends, and Escape closes\n * without choosing. That was the one genuine argument for staying native, and\n * it is answered.\n *\n * Past roughly a dozen options, reach for `Combobox` — a list nobody can filter\n * is worse than one they can type into. Where the platform picker is genuinely\n * better — a phone, or a form that must survive without JavaScript — reach for\n * `NativeSelect`.\n *\n * @example\n * <Field label=\"Region\">\n * <Select label=\"Region\" defaultValue=\"au\">\n * <SelectItem value=\"au\">Australia</SelectItem>\n * <SelectItem value=\"nz\">New Zealand</SelectItem>\n * </Select>\n * </Field>\n */\nexport function Select({\n label,\n placeholder = 'Select…',\n invalid,\n disabled,\n className,\n contentClassName,\n children,\n id,\n 'aria-describedby': describedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n ...props\n}: SelectProps) {\n warnBlankName('Select', 'label', label, 'the trigger is announced with no name')\n const bad = isInvalid(invalid, ariaInvalid)\n\n const field = useFieldControl()\n const generated = useId()\n // The id belongs on the TRIGGER: Radix's root renders no DOM node at all, so\n // an id handed to it lands nowhere and the label above points at nothing.\n const triggerId = id ?? generated\n const valueId = `${triggerId}-value`\n const nameId = field?.labelId ?? `${triggerId}-name`\n\n const container = useOverlayContainer()\n\n return (\n <SelectPrimitive.Root disabled={disabled} {...props}>\n <SelectPrimitive.Trigger\n id={triggerId}\n // Named by the label AND by its own value, in that order. `aria-label`\n // outranks name-from-content, so naming it \"Region\" told a reader the\n // noun and never the answer — and the answer is the only thing on the\n // trigger.\n aria-labelledby={`${nameId} ${valueId}`}\n aria-describedby={describedBy}\n aria-required={ariaRequired}\n aria-invalid={bad || undefined}\n className={cn(\n CONTROL_BASE,\n 'group flex cursor-pointer items-center justify-between gap-2 text-start data-[placeholder]:text-(--ink-3-aa)',\n bad ? CONTROL_BORDER.invalid : CONTROL_BORDER.resting,\n className,\n )}\n >\n {field?.labelId == null && (\n <span id={nameId} className=\"sr-only\">\n {label}\n </span>\n )}\n {/* Wrapped rather than styled directly: Radix's Value drops className.\n The wrapper is also what `aria-labelledby` points at, so the name\n picks up the value and not the chevron. */}\n <span id={valueId} className=\"truncate\">\n <SelectPrimitive.Value placeholder={placeholder} />\n </span>\n <SelectPrimitive.Icon asChild>\n <ChevronDown\n size={16}\n strokeWidth={1.5}\n aria-hidden\n className=\"shrink-0 text-(--ink-3-aa) transition-transform duration-(--duration-fast) group-data-[state=open]:rotate-180\"\n />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal container={container ?? undefined}>\n <SelectPrimitive.Content\n collisionBoundary={container ?? undefined}\n collisionPadding={8}\n position=\"popper\"\n sideOffset={6}\n data-m22-animated\n className={cn(\n 'z-(--z-dropdown) max-h-72 min-w-(--radix-select-trigger-width) overflow-hidden rounded-(--radius-lg) border border-(--panel-border) bg-(--panel-bg) shadow-(--panel-lift) panel-blur',\n contentClassName,\n 'data-[state=open]:animate-[m22-pop-in_var(--duration-fast)_var(--ease-out-expo)] data-[state=closed]:animate-[m22-pop-out_var(--duration-fast)_var(--ease)] origin-(--radix-popper-transform-origin)',\n )}\n >\n <SelectPrimitive.ScrollUpButton className=\"flex h-6 items-center justify-center text-(--ink-3-aa)\">\n <ChevronUp size={14} strokeWidth={1.5} aria-hidden />\n </SelectPrimitive.ScrollUpButton>\n <SelectPrimitive.Viewport className=\"p-1.5\">{children}</SelectPrimitive.Viewport>\n <SelectPrimitive.ScrollDownButton className=\"flex h-6 items-center justify-center text-(--ink-3-aa)\">\n <ChevronDown size={14} strokeWidth={1.5} aria-hidden />\n </SelectPrimitive.ScrollDownButton>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n )\n}\n\nexport type SelectItemProps = ComponentProps<typeof SelectPrimitive.Item>\n\n/** One option. The tick marks the chosen one; the fill marks the highlighted one. */\nexport function SelectItem({ className, children, ...props }: SelectItemProps) {\n return (\n <SelectPrimitive.Item\n className={cn(\n 'flex cursor-pointer select-none items-center gap-2.5 rounded-(--radius-row) px-2.5 py-2 text-sm text-(--ink-2) outline-none transition-colors duration-(--duration-fast) data-[highlighted]:bg-(--stone) data-[highlighted]:text-(--ink) data-[disabled]:pointer-events-none data-[disabled]:opacity-(--disabled-opacity)',\n className,\n )}\n {...props}\n >\n {/* The box is always there and only the tick inside it appears, so\n choosing an option does not shunt every label sideways. */}\n <span className=\"grid size-3.5 shrink-0 place-items-center\">\n <SelectPrimitive.ItemIndicator asChild>\n <Check size={14} strokeWidth={2} aria-hidden />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\n/**\n * Mono eyebrow heading for a group of options.\n *\n * Must sit inside a `SelectGroup` — Radix throws otherwise, because a heading\n * with no group is a heading for nothing, and assistive tech would announce it\n * as an option.\n */\nexport function SelectLabel({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Label>) {\n return (\n <SelectPrimitive.Label\n className={cn('px-2.5 py-1.5 eyebrow text-(--ink-3-aa)', className)}\n {...props}\n />\n )\n}\n\n/** Hairline divider between groups. */\nexport function SelectSeparator({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator className={cn('my-1 h-px bg-(--rule)', className)} {...props} />\n )\n}\n\nexport default Select\n"],"mappings":";AA6GM,SAkBI,KAlBJ;AA3GN,YAAY,qBAAqB;AACjC,SAAS,OAAO,aAAa,iBAAiB;AAC9C,SAAS,aAAkD;AAC3D,SAAS,UAAU;AACnB,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,cAAc,gBAAgB,iBAAiB;AAGjD,MAAM,aAAa,gBAAgB;AACnC,MAAM,cAAc,gBAAgB;AAmEpC,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,GAAG;AACL,GAAgB;AACd,gBAAc,UAAU,SAAS,OAAO,uCAAuC;AAC/E,QAAM,MAAM,UAAU,SAAS,WAAW;AAE1C,QAAM,QAAQ,gBAAgB;AAC9B,QAAM,YAAY,MAAM;AAGxB,QAAM,YAAY,MAAM;AACxB,QAAM,UAAU,GAAG,SAAS;AAC5B,QAAM,SAAS,OAAO,WAAW,GAAG,SAAS;AAE7C,QAAM,YAAY,oBAAoB;AAEtC,SACE,qBAAC,gBAAgB,MAAhB,EAAqB,UAAqB,GAAG,OAC5C;AAAA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,IAAI;AAAA,QAKJ,mBAAiB,GAAG,MAAM,IAAI,OAAO;AAAA,QACrC,oBAAkB;AAAA,QAClB,iBAAe;AAAA,QACf,gBAAc,OAAO;AAAA,QACrB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,MAAM,eAAe,UAAU,eAAe;AAAA,UAC9C;AAAA,QACF;AAAA,QAEC;AAAA,iBAAO,WAAW,QACjB,oBAAC,UAAK,IAAI,QAAQ,WAAU,WACzB,iBACH;AAAA,UAKF,oBAAC,UAAK,IAAI,SAAS,WAAU,YAC3B,8BAAC,gBAAgB,OAAhB,EAAsB,aAA0B,GACnD;AAAA,UACA,oBAAC,gBAAgB,MAAhB,EAAqB,SAAO,MAC3B;AAAA,YAAC;AAAA;AAAA,cACC,MAAM;AAAA,cACN,aAAa;AAAA,cACb,eAAW;AAAA,cACX,WAAU;AAAA;AAAA,UACZ,GACF;AAAA;AAAA;AAAA,IACF;AAAA,IAEA,oBAAC,gBAAgB,QAAhB,EAAuB,WAAW,aAAa,QAC9C;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACD,mBAAmB,aAAa;AAAA,QAChC,kBAAkB;AAAA,QAChB,UAAS;AAAA,QACT,YAAY;AAAA,QACZ,qBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,gBAAgB,gBAAhB,EAA+B,WAAU,0DACxC,8BAAC,aAAU,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,GACrD;AAAA,UACA,oBAAC,gBAAgB,UAAhB,EAAyB,WAAU,SAAS,UAAS;AAAA,UACtD,oBAAC,gBAAgB,kBAAhB,EAAiC,WAAU,0DAC1C,8BAAC,eAAY,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC,GACvD;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;AAKO,SAAS,WAAW,EAAE,WAAW,UAAU,GAAG,MAAM,GAAoB;AAC7E,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAIJ;AAAA,4BAAC,UAAK,WAAU,6CACd,8BAAC,gBAAgB,eAAhB,EAA8B,SAAO,MACpC,8BAAC,SAAM,MAAM,IAAI,aAAa,GAAG,eAAW,MAAC,GAC/C,GACF;AAAA,QACA,oBAAC,gBAAgB,UAAhB,EAA0B,UAAS;AAAA;AAAA;AAAA,EACtC;AAEJ;AASO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,SACE;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC,WAAW,GAAG,2CAA2C,SAAS;AAAA,MACjE,GAAG;AAAA;AAAA,EACN;AAEJ;AAGO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,GAAG;AACL,GAAqD;AACnD,SACE,oBAAC,gBAAgB,WAAhB,EAA0B,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO;AAE7F;AAEA,IAAO,iBAAQ;","names":[]}
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { HTMLAttributes } from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
3
 
4
4
  interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {
5
5
  orientation?: 'horizontal' | 'vertical';
@@ -11,20 +11,38 @@ interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {
11
11
  * screen reader should hear as distinct.
12
12
  */
13
13
  decorative?: boolean;
14
+ /**
15
+ * Words in the break — "or continue with", "Older".
16
+ *
17
+ * Horizontal only, and it changes the construction rather than the styling:
18
+ * see the note on the component. `decorative` no longer applies, because the
19
+ * label is content and the two rules beside it are decoration either way.
20
+ */
21
+ label?: ReactNode;
14
22
  }
15
23
  /**
16
- * A rule.
24
+ * A rule, with or without words in it.
17
25
  *
18
26
  * In a monochrome system the rule does the work colour would otherwise do, so
19
27
  * it has three weights rather than one: hairline between rows, edge between
20
28
  * blocks, hard under a masthead. Picking by name keeps a page from drifting
21
29
  * into five hand-tuned greys.
22
30
  *
31
+ * **On the label.** "or continue with" was two Separators and a span at every
32
+ * call site, and the usual one-element version — text laid over a single rule
33
+ * with a background to punch a hole in it — needs to know the ground it is
34
+ * sitting on. Get that wrong and the notch is `--paper` on a card that is
35
+ * `--stone`, which reads as a rendering bug. So there is no ground: the rule is
36
+ * drawn twice, one piece either side of the label, and the gap is a gap. It is
37
+ * correct on any surface without being told which one it is on.
38
+ *
23
39
  * @example
24
40
  * <Separator weight="hard" />
25
41
  * @example
26
42
  * <Separator orientation="vertical" className="h-4" />
43
+ * @example
44
+ * <Separator label="or continue with" />
27
45
  */
28
- declare function Separator({ orientation, weight, decorative, className, ...rest }: SeparatorProps): react.JSX.Element;
46
+ declare function Separator({ orientation, weight, decorative, label, className, ...rest }: SeparatorProps): react.JSX.Element;
29
47
 
30
48
  export { Separator, type SeparatorProps, Separator as default };
@@ -1,4 +1,4 @@
1
- import { jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "../../lib/cn.js";
3
3
  const WEIGHT = {
4
4
  hairline: "bg-(--rule)",
@@ -9,9 +9,17 @@ function Separator({
9
9
  orientation = "horizontal",
10
10
  weight = "hairline",
11
11
  decorative = true,
12
+ label,
12
13
  className,
13
14
  ...rest
14
15
  }) {
16
+ if (label != null && orientation === "horizontal") {
17
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full items-center gap-3", className), ...rest, children: [
18
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("h-px flex-1", WEIGHT[weight]) }),
19
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 mono-meta text-(--ink-3-aa)", children: label }),
20
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("h-px flex-1", WEIGHT[weight]) })
21
+ ] });
22
+ }
15
23
  return /* @__PURE__ */ jsx(
16
24
  "div",
17
25
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Separator/Separator.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical'\n /** `hairline` divides rows inside one block; `edge` divides one block from the next. */\n weight?: 'hairline' | 'edge' | 'hard'\n /**\n * A rule that only groups things visually is decoration and must not be\n * announced. Set `false` when the rule genuinely separates two sections a\n * screen reader should hear as distinct.\n */\n decorative?: boolean\n}\n\nconst WEIGHT = {\n hairline: 'bg-(--rule)',\n edge: 'bg-(--rule-2)',\n hard: 'bg-(--rule-hard)',\n} as const\n\n/**\n * A rule.\n *\n * In a monochrome system the rule does the work colour would otherwise do, so\n * it has three weights rather than one: hairline between rows, edge between\n * blocks, hard under a masthead. Picking by name keeps a page from drifting\n * into five hand-tuned greys.\n *\n * @example\n * <Separator weight=\"hard\" />\n * @example\n * <Separator orientation=\"vertical\" className=\"h-4\" />\n */\nexport function Separator({\n orientation = 'horizontal',\n weight = 'hairline',\n decorative = true,\n className,\n ...rest\n}: SeparatorProps) {\n return (\n <div\n role={decorative ? 'none' : 'separator'}\n aria-orientation={decorative ? undefined : orientation}\n className={cn(\n 'shrink-0',\n orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',\n WEIGHT[weight],\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport default Separator\n"],"mappings":"AA0CI;AAzCJ,SAAS,UAAU;AAcnB,MAAM,SAAS;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,MAAM;AACR;AAeO,SAAS,UAAU;AAAA,EACxB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb;AAAA,EACA,GAAG;AACL,GAAmB;AACjB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,aAAa,SAAS;AAAA,MAC5B,oBAAkB,aAAa,SAAY;AAAA,MAC3C,WAAW;AAAA,QACT;AAAA,QACA,gBAAgB,eAAe,gBAAgB;AAAA,QAC/C,OAAO,MAAM;AAAA,QACb;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAO,oBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Separator/Separator.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\nexport interface SeparatorProps extends HTMLAttributes<HTMLDivElement> {\n orientation?: 'horizontal' | 'vertical'\n /** `hairline` divides rows inside one block; `edge` divides one block from the next. */\n weight?: 'hairline' | 'edge' | 'hard'\n /**\n * A rule that only groups things visually is decoration and must not be\n * announced. Set `false` when the rule genuinely separates two sections a\n * screen reader should hear as distinct.\n */\n decorative?: boolean\n /**\n * Words in the break — \"or continue with\", \"Older\".\n *\n * Horizontal only, and it changes the construction rather than the styling:\n * see the note on the component. `decorative` no longer applies, because the\n * label is content and the two rules beside it are decoration either way.\n */\n label?: ReactNode\n}\n\nconst WEIGHT = {\n hairline: 'bg-(--rule)',\n edge: 'bg-(--rule-2)',\n hard: 'bg-(--rule-hard)',\n} as const\n\n/**\n * A rule, with or without words in it.\n *\n * In a monochrome system the rule does the work colour would otherwise do, so\n * it has three weights rather than one: hairline between rows, edge between\n * blocks, hard under a masthead. Picking by name keeps a page from drifting\n * into five hand-tuned greys.\n *\n * **On the label.** \"or continue with\" was two Separators and a span at every\n * call site, and the usual one-element version — text laid over a single rule\n * with a background to punch a hole in it — needs to know the ground it is\n * sitting on. Get that wrong and the notch is `--paper` on a card that is\n * `--stone`, which reads as a rendering bug. So there is no ground: the rule is\n * drawn twice, one piece either side of the label, and the gap is a gap. It is\n * correct on any surface without being told which one it is on.\n *\n * @example\n * <Separator weight=\"hard\" />\n * @example\n * <Separator orientation=\"vertical\" className=\"h-4\" />\n * @example\n * <Separator label=\"or continue with\" />\n */\nexport function Separator({\n orientation = 'horizontal',\n weight = 'hairline',\n decorative = true,\n label,\n className,\n ...rest\n}: SeparatorProps) {\n if (label != null && orientation === 'horizontal') {\n return (\n <div className={cn('flex w-full items-center gap-3', className)} {...rest}>\n <span aria-hidden=\"true\" className={cn('h-px flex-1', WEIGHT[weight])} />\n <span className=\"shrink-0 mono-meta text-(--ink-3-aa)\">{label}</span>\n <span aria-hidden=\"true\" className={cn('h-px flex-1', WEIGHT[weight])} />\n </div>\n )\n }\n\n return (\n <div\n role={decorative ? 'none' : 'separator'}\n aria-orientation={decorative ? undefined : orientation}\n className={cn(\n 'shrink-0',\n orientation === 'horizontal' ? 'h-px w-full' : 'h-full w-px',\n WEIGHT[weight],\n className,\n )}\n {...rest}\n />\n )\n}\n\nexport default Separator\n"],"mappings":"AA8DM,SACE,KADF;AA7DN,SAAS,UAAU;AAsBnB,MAAM,SAAS;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,MAAM;AACR;AAyBO,SAAS,UAAU;AAAA,EACxB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAmB;AACjB,MAAI,SAAS,QAAQ,gBAAgB,cAAc;AACjD,WACE,qBAAC,SAAI,WAAW,GAAG,kCAAkC,SAAS,GAAI,GAAG,MACnE;AAAA,0BAAC,UAAK,eAAY,QAAO,WAAW,GAAG,eAAe,OAAO,MAAM,CAAC,GAAG;AAAA,MACvE,oBAAC,UAAK,WAAU,wCAAwC,iBAAM;AAAA,MAC9D,oBAAC,UAAK,eAAY,QAAO,WAAW,GAAG,eAAe,OAAO,MAAM,CAAC,GAAG;AAAA,OACzE;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,aAAa,SAAS;AAAA,MAC5B,oBAAkB,aAAa,SAAY;AAAA,MAC3C,WAAW;AAAA,QACT;AAAA,QACA,gBAAgB,eAAe,gBAAgB;AAAA,QAC/C,OAAO,MAAM;AAAA,QACb;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,IAAO,oBAAQ;","names":[]}
@@ -27,6 +27,9 @@ interface SheetContentProps extends Omit<ComponentProps<typeof DialogPrimitive.C
27
27
  * The title is required, visible or not. A modal with no accessible name drops
28
28
  * a screen reader into an unnamed region with no way back out.
29
29
  *
30
+ * Portals into the element an enclosing `OverlayContainer` names, docking to
31
+ * that element's edge rather than the viewport's when there is one.
32
+ *
30
33
  * @example
31
34
  * <Sheet>
32
35
  * <SheetTrigger asChild><Button variant="secondary">Filters</Button></SheetTrigger>
@@ -3,6 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as DialogPrimitive from "@radix-ui/react-dialog";
4
4
  import { X } from "lucide-react";
5
5
  import { cn } from "../../lib/cn.js";
6
+ import { useOverlayContainer } from "../../lib/overlay-container.js";
6
7
  const Sheet = DialogPrimitive.Root;
7
8
  const SheetTrigger = DialogPrimitive.Trigger;
8
9
  const SheetClose = DialogPrimitive.Close;
@@ -21,20 +22,28 @@ function SheetContent({
21
22
  children,
22
23
  ...rest
23
24
  }) {
24
- return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { children: [
25
+ const container = useOverlayContainer();
26
+ return /* @__PURE__ */ jsxs(DialogPrimitive.Portal, { container: container ?? void 0, children: [
25
27
  /* @__PURE__ */ jsx(
26
28
  DialogPrimitive.Overlay,
27
29
  {
28
30
  "data-m22-animated": true,
29
- className: "fixed inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]"
31
+ className: cn(
32
+ "inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]",
33
+ container ? "absolute" : "fixed"
34
+ )
30
35
  }
31
36
  ),
32
37
  /* @__PURE__ */ jsxs(
33
38
  DialogPrimitive.Content,
34
39
  {
40
+ "data-m22-animated": true,
35
41
  className: cn(
36
- "fixed z-(--z-modal) flex flex-col overflow-y-auto border-(--panel-border) bg-(--panel-bg) p-6 panel-blur transition-transform duration-(--duration-slow) ease-(--ease-out-expo) scroll-slim",
42
+ "fixed z-(--z-modal) flex flex-col overflow-y-auto border-(--panel-border) bg-(--panel-bg) p-6 shadow-(--panel-lift) panel-blur transition-transform duration-(--duration-slow) ease-(--ease-out-expo) scroll-slim",
37
43
  SIDE[side],
44
+ // Docked to the container's edge, and capped by its box — the widths
45
+ // above are read against the viewport and would overflow a frame.
46
+ container && "absolute max-h-full max-w-full",
38
47
  className
39
48
  ),
40
49
  ...rest,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Sheet/Sheet.tsx"],"sourcesContent":["'use client'\n\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { X } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\n\n/** Radix Dialog root, trigger and close — a sheet IS a dialog, docked. */\nexport const Sheet = DialogPrimitive.Root\nexport const SheetTrigger = DialogPrimitive.Trigger\nexport const SheetClose = DialogPrimitive.Close\n\nexport type SheetSide = 'start' | 'end' | 'top' | 'bottom'\n\n/**\n * Full literal class strings per edge, because Tailwind only generates what it\n * can see verbatim. The inline sides are named in READING order, so a sheet\n * docked to `end` comes from the right in English and the left in Arabic.\n */\nconst SIDE: Record<SheetSide, string> = {\n start:\n 'inset-y-0 start-0 h-full w-[min(24rem,92vw)] border-e data-[state=closed]:-translate-x-full rtl:data-[state=closed]:translate-x-full',\n end: 'inset-y-0 end-0 h-full w-[min(24rem,92vw)] border-s data-[state=closed]:translate-x-full rtl:data-[state=closed]:-translate-x-full',\n top: 'inset-x-0 top-0 w-full max-h-[85vh] border-b data-[state=closed]:-translate-y-full',\n bottom:\n 'inset-x-0 bottom-0 w-full max-h-[85vh] border-t data-[state=closed]:translate-y-full',\n}\n\nexport interface SheetContentProps\n extends Omit<ComponentProps<typeof DialogPrimitive.Content>, 'title'> {\n /** Which edge it is docked to. `end` by default. */\n side?: SheetSide\n title: ReactNode\n description?: ReactNode\n /** Hide the title visually while keeping it for assistive tech. */\n hideTitle?: boolean\n}\n\n/**\n * A panel docked to an edge of the viewport.\n *\n * It is a modal dialog — Radix's, so the focus trap, the escape key, the scroll\n * lock and the `aria-modal` wiring are the same ones `Dialog` gets. The only\n * differences are where it sits and which way it arrives, which is why this\n * shares that implementation rather than reproducing it: a second focus trap is\n * a second focus trap to get wrong.\n *\n * The title is required, visible or not. A modal with no accessible name drops\n * a screen reader into an unnamed region with no way back out.\n *\n * @example\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"secondary\">Filters</Button></SheetTrigger>\n * <SheetContent title=\"Filters\" description=\"Narrow the list.\">…</SheetContent>\n * </Sheet>\n */\nexport function SheetContent({\n side = 'end',\n title,\n description,\n hideTitle = false,\n className,\n children,\n ...rest\n}: SheetContentProps) {\n return (\n <DialogPrimitive.Portal>\n <DialogPrimitive.Overlay\n data-m22-animated\n className=\"fixed inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]\"\n />\n <DialogPrimitive.Content\n className={cn(\n 'fixed z-(--z-modal) flex flex-col overflow-y-auto border-(--panel-border) bg-(--panel-bg) p-6 panel-blur transition-transform duration-(--duration-slow) ease-(--ease-out-expo) scroll-slim',\n SIDE[side],\n className,\n )}\n {...rest}\n >\n <div className={cn('mb-4 flex flex-col gap-1 pe-8', hideTitle && 'sr-only')}>\n <DialogPrimitive.Title className=\"m-0 font-heading text-[length:var(--fs-item)] font-normal text-(--ink)\">\n {title}\n </DialogPrimitive.Title>\n {description !== undefined && (\n <DialogPrimitive.Description className=\"m-0 text-sm leading-relaxed text-(--ink-3-aa)\">\n {description}\n </DialogPrimitive.Description>\n )}\n </div>\n\n <DialogPrimitive.Close\n aria-label=\"Close\"\n className=\"absolute end-3 top-3 grid size-9 place-items-center rounded-(--radius-pill) text-(--ink-3-aa) transition-colors duration-(--duration-fast) hover:bg-(--stone) hover:text-(--ink)\"\n >\n <X size={16} strokeWidth={1.5} aria-hidden />\n </DialogPrimitive.Close>\n\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n )\n}\n\nexport default Sheet\n"],"mappings":";AAmEM,cAYE,YAZF;AAjEN,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAElB,SAAS,UAAU;AAGZ,MAAM,QAAQ,gBAAgB;AAC9B,MAAM,eAAe,gBAAgB;AACrC,MAAM,aAAa,gBAAgB;AAS1C,MAAM,OAAkC;AAAA,EACtC,OACE;AAAA,EACF,KAAK;AAAA,EACL,KAAK;AAAA,EACL,QACE;AACJ;AA8BO,SAAS,aAAa;AAAA,EAC3B,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,SACE,qBAAC,gBAAgB,QAAhB,EACC;AAAA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,qBAAiB;AAAA,QACjB,WAAU;AAAA;AAAA,IACZ;AAAA,IACA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA,KAAK,IAAI;AAAA,UACT;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,+BAAC,SAAI,WAAW,GAAG,iCAAiC,aAAa,SAAS,GACxE;AAAA,gCAAC,gBAAgB,OAAhB,EAAsB,WAAU,0EAC9B,iBACH;AAAA,YACC,gBAAgB,UACf,oBAAC,gBAAgB,aAAhB,EAA4B,WAAU,iDACpC,uBACH;AAAA,aAEJ;AAAA,UAEA;AAAA,YAAC,gBAAgB;AAAA,YAAhB;AAAA,cACC,cAAW;AAAA,cACX,WAAU;AAAA,cAEV,8BAAC,KAAE,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC;AAAA;AAAA,UAC7C;AAAA,UAEC;AAAA;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/Sheet/Sheet.tsx"],"sourcesContent":["'use client'\n\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { X } from 'lucide-react'\nimport type { ComponentProps, ReactNode } from 'react'\nimport { cn } from '../../lib/cn'\nimport { useOverlayContainer } from '../../lib/overlay-container'\n\n/** Radix Dialog root, trigger and close — a sheet IS a dialog, docked. */\nexport const Sheet = DialogPrimitive.Root\nexport const SheetTrigger = DialogPrimitive.Trigger\nexport const SheetClose = DialogPrimitive.Close\n\nexport type SheetSide = 'start' | 'end' | 'top' | 'bottom'\n\n/**\n * Full literal class strings per edge, because Tailwind only generates what it\n * can see verbatim. The inline sides are named in READING order, so a sheet\n * docked to `end` comes from the right in English and the left in Arabic.\n */\nconst SIDE: Record<SheetSide, string> = {\n start:\n 'inset-y-0 start-0 h-full w-[min(24rem,92vw)] border-e data-[state=closed]:-translate-x-full rtl:data-[state=closed]:translate-x-full',\n end: 'inset-y-0 end-0 h-full w-[min(24rem,92vw)] border-s data-[state=closed]:translate-x-full rtl:data-[state=closed]:-translate-x-full',\n top: 'inset-x-0 top-0 w-full max-h-[85vh] border-b data-[state=closed]:-translate-y-full',\n bottom:\n 'inset-x-0 bottom-0 w-full max-h-[85vh] border-t data-[state=closed]:translate-y-full',\n}\n\nexport interface SheetContentProps\n extends Omit<ComponentProps<typeof DialogPrimitive.Content>, 'title'> {\n /** Which edge it is docked to. `end` by default. */\n side?: SheetSide\n title: ReactNode\n description?: ReactNode\n /** Hide the title visually while keeping it for assistive tech. */\n hideTitle?: boolean\n}\n\n/**\n * A panel docked to an edge of the viewport.\n *\n * It is a modal dialog — Radix's, so the focus trap, the escape key, the scroll\n * lock and the `aria-modal` wiring are the same ones `Dialog` gets. The only\n * differences are where it sits and which way it arrives, which is why this\n * shares that implementation rather than reproducing it: a second focus trap is\n * a second focus trap to get wrong.\n *\n * The title is required, visible or not. A modal with no accessible name drops\n * a screen reader into an unnamed region with no way back out.\n *\n * Portals into the element an enclosing `OverlayContainer` names, docking to\n * that element's edge rather than the viewport's when there is one.\n *\n * @example\n * <Sheet>\n * <SheetTrigger asChild><Button variant=\"secondary\">Filters</Button></SheetTrigger>\n * <SheetContent title=\"Filters\" description=\"Narrow the list.\">…</SheetContent>\n * </Sheet>\n */\nexport function SheetContent({\n side = 'end',\n title,\n description,\n hideTitle = false,\n className,\n children,\n ...rest\n}: SheetContentProps) {\n const container = useOverlayContainer()\n\n return (\n <DialogPrimitive.Portal container={container ?? undefined}>\n <DialogPrimitive.Overlay\n data-m22-animated\n className={cn(\n 'inset-0 z-(--z-overlay) bg-(--scrim) data-[state=open]:animate-[m22-fade-in_var(--duration-fast)_var(--ease)]',\n container ? 'absolute' : 'fixed',\n )}\n />\n <DialogPrimitive.Content\n // The panel's own assertion that its travel is decorative — the scrim\n // beside it always made one and this half never did, so under reduced\n // motion the fade was cancelled and the panel still slid the whole\n // width of itself, which reads worse than leaving both alone. See the\n // reduced-motion block in keyframes.css for what the marker now means:\n // documentation with teeth, over a universal floor that no longer\n // depends on anyone remembering it.\n data-m22-animated\n className={cn(\n 'fixed z-(--z-modal) flex flex-col overflow-y-auto border-(--panel-border) bg-(--panel-bg) p-6 shadow-(--panel-lift) panel-blur transition-transform duration-(--duration-slow) ease-(--ease-out-expo) scroll-slim',\n SIDE[side],\n // Docked to the container's edge, and capped by its box — the widths\n // above are read against the viewport and would overflow a frame.\n container && 'absolute max-h-full max-w-full',\n className,\n )}\n {...rest}\n >\n <div className={cn('mb-4 flex flex-col gap-1 pe-8', hideTitle && 'sr-only')}>\n <DialogPrimitive.Title className=\"m-0 font-heading text-[length:var(--fs-item)] font-normal text-(--ink)\">\n {title}\n </DialogPrimitive.Title>\n {description !== undefined && (\n <DialogPrimitive.Description className=\"m-0 text-sm leading-relaxed text-(--ink-3-aa)\">\n {description}\n </DialogPrimitive.Description>\n )}\n </div>\n\n <DialogPrimitive.Close\n aria-label=\"Close\"\n className=\"absolute end-3 top-3 grid size-9 place-items-center rounded-(--radius-pill) text-(--ink-3-aa) transition-colors duration-(--duration-fast) hover:bg-(--stone) hover:text-(--ink)\"\n >\n <X size={16} strokeWidth={1.5} aria-hidden />\n </DialogPrimitive.Close>\n\n {children}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n )\n}\n\nexport default Sheet\n"],"mappings":";AAyEM,cA0BE,YA1BF;AAvEN,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAElB,SAAS,UAAU;AACnB,SAAS,2BAA2B;AAG7B,MAAM,QAAQ,gBAAgB;AAC9B,MAAM,eAAe,gBAAgB;AACrC,MAAM,aAAa,gBAAgB;AAS1C,MAAM,OAAkC;AAAA,EACtC,OACE;AAAA,EACF,KAAK;AAAA,EACL,KAAK;AAAA,EACL,QACE;AACJ;AAiCO,SAAS,aAAa;AAAA,EAC3B,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,YAAY,oBAAoB;AAEtC,SACE,qBAAC,gBAAgB,QAAhB,EAAuB,WAAW,aAAa,QAC9C;AAAA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QACC,qBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA,YAAY,aAAa;AAAA,QAC3B;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC,gBAAgB;AAAA,MAAhB;AAAA,QAQC,qBAAiB;AAAA,QACjB,WAAW;AAAA,UACT;AAAA,UACA,KAAK,IAAI;AAAA;AAAA;AAAA,UAGT,aAAa;AAAA,UACb;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,+BAAC,SAAI,WAAW,GAAG,iCAAiC,aAAa,SAAS,GACxE;AAAA,gCAAC,gBAAgB,OAAhB,EAAsB,WAAU,0EAC9B,iBACH;AAAA,YACC,gBAAgB,UACf,oBAAC,gBAAgB,aAAhB,EAA4B,WAAU,iDACpC,uBACH;AAAA,aAEJ;AAAA,UAEA;AAAA,YAAC,gBAAgB;AAAA,YAAhB;AAAA,cACC,cAAW;AAAA,cACX,WAAU;AAAA,cAEV,8BAAC,KAAE,MAAM,IAAI,aAAa,KAAK,eAAW,MAAC;AAAA;AAAA,UAC7C;AAAA,UAEC;AAAA;AAAA;AAAA,IACH;AAAA,KACF;AAEJ;AAEA,IAAO,gBAAQ;","names":[]}