@sixthshift/design-system 0.2.1 → 0.4.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 (604) hide show
  1. package/README.md +242 -33
  2. package/dist/components/Badge/Badge.d.ts +65 -7
  3. package/dist/components/Badge/Badge.d.ts.map +1 -1
  4. package/dist/components/Badge/Badge.js +56 -46
  5. package/dist/components/Badge/Badge.js.map +1 -1
  6. package/dist/components/Badge/index.d.ts +1 -1
  7. package/dist/components/Badge/index.d.ts.map +1 -1
  8. package/dist/components/Badge/index.js +1 -1
  9. package/dist/components/Badge/index.js.map +1 -1
  10. package/dist/components/BarChart/BarChart.d.ts +20 -2
  11. package/dist/components/BarChart/BarChart.d.ts.map +1 -1
  12. package/dist/components/BarChart/BarChart.js +17 -3
  13. package/dist/components/BarChart/BarChart.js.map +1 -1
  14. package/dist/components/Button/Button.d.ts +85 -6
  15. package/dist/components/Button/Button.d.ts.map +1 -1
  16. package/dist/components/Button/Button.js +97 -106
  17. package/dist/components/Button/Button.js.map +1 -1
  18. package/dist/components/Button/index.d.ts +1 -1
  19. package/dist/components/Button/index.d.ts.map +1 -1
  20. package/dist/components/Button/index.js +1 -1
  21. package/dist/components/Button/index.js.map +1 -1
  22. package/dist/components/Calendar/Calendar.d.ts +31 -1
  23. package/dist/components/Calendar/Calendar.d.ts.map +1 -1
  24. package/dist/components/Calendar/Calendar.js +94 -225
  25. package/dist/components/Calendar/Calendar.js.map +1 -1
  26. package/dist/components/Calendar/CalendarView.d.ts +15 -0
  27. package/dist/components/Calendar/CalendarView.d.ts.map +1 -0
  28. package/dist/components/Calendar/CalendarView.js +263 -0
  29. package/dist/components/Calendar/CalendarView.js.map +1 -0
  30. package/dist/components/Calendar/calendar.types.d.ts +87 -27
  31. package/dist/components/Calendar/calendar.types.d.ts.map +1 -1
  32. package/dist/components/Calendar/calendar.types.js +10 -3
  33. package/dist/components/Calendar/calendar.types.js.map +1 -1
  34. package/dist/components/Calendar/index.d.ts +16 -2
  35. package/dist/components/Calendar/index.d.ts.map +1 -1
  36. package/dist/components/Calendar/index.js +15 -1
  37. package/dist/components/Calendar/index.js.map +1 -1
  38. package/dist/components/Card/Card.d.ts +13 -0
  39. package/dist/components/Card/Card.d.ts.map +1 -1
  40. package/dist/components/Card/Card.js +15 -2
  41. package/dist/components/Card/Card.js.map +1 -1
  42. package/dist/components/Checkbox/Checkbox.d.ts +21 -0
  43. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  44. package/dist/components/Checkbox/Checkbox.js +22 -1
  45. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  46. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts +22 -0
  47. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts.map +1 -1
  48. package/dist/components/CheckboxGroup/CheckboxGroup.js +22 -0
  49. package/dist/components/CheckboxGroup/CheckboxGroup.js.map +1 -1
  50. package/dist/components/Code/Editor/Editor.js +2 -2
  51. package/dist/components/Code/Editor/Editor.js.map +1 -1
  52. package/dist/components/Code/Editor/themes.d.ts +2 -2
  53. package/dist/components/Code/Editor/themes.d.ts.map +1 -1
  54. package/dist/components/Code/Editor/themes.js +50 -32
  55. package/dist/components/Code/Editor/themes.js.map +1 -1
  56. package/dist/components/Code/ValidationStatus/ValidationStatus.d.ts.map +1 -1
  57. package/dist/components/Code/ValidationStatus/ValidationStatus.js.map +1 -1
  58. package/dist/components/DatePicker/DatePicker.d.ts +45 -2
  59. package/dist/components/DatePicker/DatePicker.d.ts.map +1 -1
  60. package/dist/components/DatePicker/DatePicker.js +228 -11
  61. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  62. package/dist/components/DatePicker/DateSegments.d.ts +60 -0
  63. package/dist/components/DatePicker/DateSegments.d.ts.map +1 -0
  64. package/dist/components/DatePicker/DateSegments.js +80 -0
  65. package/dist/components/DatePicker/DateSegments.js.map +1 -0
  66. package/dist/components/DatePicker/datepicker.types.d.ts +53 -37
  67. package/dist/components/DatePicker/datepicker.types.d.ts.map +1 -1
  68. package/dist/components/DatePicker/datepicker.types.js +5 -3
  69. package/dist/components/DatePicker/datepicker.types.js.map +1 -1
  70. package/dist/components/DatePicker/index.d.ts +10 -1
  71. package/dist/components/DatePicker/index.d.ts.map +1 -1
  72. package/dist/components/DatePicker/index.js +8 -0
  73. package/dist/components/DatePicker/index.js.map +1 -1
  74. package/dist/components/DateRangePicker/DateRangePicker.d.ts +22 -3
  75. package/dist/components/DateRangePicker/DateRangePicker.d.ts.map +1 -1
  76. package/dist/components/DateRangePicker/DateRangePicker.js +38 -24
  77. package/dist/components/DateRangePicker/DateRangePicker.js.map +1 -1
  78. package/dist/components/DateRangePicker/daterangepicker.types.d.ts +26 -21
  79. package/dist/components/DateRangePicker/daterangepicker.types.d.ts.map +1 -1
  80. package/dist/components/DateRangePicker/daterangepicker.types.js +6 -0
  81. package/dist/components/DateRangePicker/daterangepicker.types.js.map +1 -1
  82. package/dist/components/DateRangePicker/index.d.ts +8 -1
  83. package/dist/components/DateRangePicker/index.d.ts.map +1 -1
  84. package/dist/components/DateRangePicker/index.js +6 -0
  85. package/dist/components/DateRangePicker/index.js.map +1 -1
  86. package/dist/components/DateTimePicker/DateTimePicker.d.ts +32 -4
  87. package/dist/components/DateTimePicker/DateTimePicker.d.ts.map +1 -1
  88. package/dist/components/DateTimePicker/DateTimePicker.js +133 -42
  89. package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
  90. package/dist/components/DateTimePicker/DateTimeSegments.d.ts +41 -0
  91. package/dist/components/DateTimePicker/DateTimeSegments.d.ts.map +1 -0
  92. package/dist/components/DateTimePicker/DateTimeSegments.js +67 -0
  93. package/dist/components/DateTimePicker/DateTimeSegments.js.map +1 -0
  94. package/dist/components/DateTimePicker/datetimepicker.types.d.ts +26 -18
  95. package/dist/components/DateTimePicker/datetimepicker.types.d.ts.map +1 -1
  96. package/dist/components/DateTimePicker/datetimepicker.types.js +10 -0
  97. package/dist/components/DateTimePicker/datetimepicker.types.js.map +1 -1
  98. package/dist/components/DateTimePicker/index.d.ts +8 -1
  99. package/dist/components/DateTimePicker/index.d.ts.map +1 -1
  100. package/dist/components/DateTimePicker/index.js +6 -0
  101. package/dist/components/DateTimePicker/index.js.map +1 -1
  102. package/dist/components/DateTimeRangePicker/DateTimeRangePicker.d.ts +30 -4
  103. package/dist/components/DateTimeRangePicker/DateTimeRangePicker.d.ts.map +1 -1
  104. package/dist/components/DateTimeRangePicker/DateTimeRangePicker.js +171 -72
  105. package/dist/components/DateTimeRangePicker/DateTimeRangePicker.js.map +1 -1
  106. package/dist/components/DateTimeRangePicker/datetimerangepicker.types.d.ts +28 -19
  107. package/dist/components/DateTimeRangePicker/datetimerangepicker.types.d.ts.map +1 -1
  108. package/dist/components/DateTimeRangePicker/datetimerangepicker.types.js +8 -0
  109. package/dist/components/DateTimeRangePicker/datetimerangepicker.types.js.map +1 -1
  110. package/dist/components/DateTimeRangePicker/index.d.ts +8 -0
  111. package/dist/components/DateTimeRangePicker/index.d.ts.map +1 -1
  112. package/dist/components/DateTimeRangePicker/index.js +7 -0
  113. package/dist/components/DateTimeRangePicker/index.js.map +1 -1
  114. package/dist/components/Field/Field.d.ts +18 -20
  115. package/dist/components/Field/Field.d.ts.map +1 -1
  116. package/dist/components/Field/Field.js +22 -5
  117. package/dist/components/Field/Field.js.map +1 -1
  118. package/dist/components/FormField/FormField.d.ts +15 -0
  119. package/dist/components/FormField/FormField.d.ts.map +1 -1
  120. package/dist/components/FormField/FormField.js +15 -0
  121. package/dist/components/FormField/FormField.js.map +1 -1
  122. package/dist/components/HoverCard/HoverCard.d.ts +6 -0
  123. package/dist/components/HoverCard/HoverCard.d.ts.map +1 -1
  124. package/dist/components/HoverCard/HoverCard.js +6 -0
  125. package/dist/components/HoverCard/HoverCard.js.map +1 -1
  126. package/dist/components/Input/Input.d.ts +15 -0
  127. package/dist/components/Input/Input.d.ts.map +1 -1
  128. package/dist/components/Input/Input.js +18 -3
  129. package/dist/components/Input/Input.js.map +1 -1
  130. package/dist/components/LineChart/LineChart.d.ts +35 -2
  131. package/dist/components/LineChart/LineChart.d.ts.map +1 -1
  132. package/dist/components/LineChart/LineChart.js +22 -3
  133. package/dist/components/LineChart/LineChart.js.map +1 -1
  134. package/dist/components/Markdown/Markdown.d.ts +19 -4
  135. package/dist/components/Markdown/Markdown.d.ts.map +1 -1
  136. package/dist/components/Markdown/Markdown.js +20 -2
  137. package/dist/components/Markdown/Markdown.js.map +1 -1
  138. package/dist/components/Message/Message.d.ts +49 -4
  139. package/dist/components/Message/Message.d.ts.map +1 -1
  140. package/dist/components/Message/Message.js +62 -11
  141. package/dist/components/Message/Message.js.map +1 -1
  142. package/dist/components/Message/index.d.ts +1 -1
  143. package/dist/components/Message/index.d.ts.map +1 -1
  144. package/dist/components/Modal/Modal.d.ts +60 -5
  145. package/dist/components/Modal/Modal.d.ts.map +1 -1
  146. package/dist/components/Modal/Modal.js +52 -6
  147. package/dist/components/Modal/Modal.js.map +1 -1
  148. package/dist/components/Modal/components/ModalContext.d.ts +14 -0
  149. package/dist/components/Modal/components/ModalContext.d.ts.map +1 -1
  150. package/dist/components/Modal/components/ModalContext.js.map +1 -1
  151. package/dist/components/Modal/components/ModalHeader.d.ts.map +1 -1
  152. package/dist/components/Modal/components/ModalHeader.js +13 -2
  153. package/dist/components/Modal/components/ModalHeader.js.map +1 -1
  154. package/dist/components/Popover/Popover.d.ts +29 -0
  155. package/dist/components/Popover/Popover.d.ts.map +1 -1
  156. package/dist/components/Popover/Popover.js +36 -0
  157. package/dist/components/Popover/Popover.js.map +1 -1
  158. package/dist/components/Popover/components/PopoverBody.d.ts.map +1 -1
  159. package/dist/components/Popover/components/PopoverBody.js +5 -2
  160. package/dist/components/Popover/components/PopoverBody.js.map +1 -1
  161. package/dist/components/Popover/components/PopoverContext.d.ts +1 -0
  162. package/dist/components/Popover/components/PopoverContext.d.ts.map +1 -1
  163. package/dist/components/Popover/components/PopoverContext.js.map +1 -1
  164. package/dist/components/Popover/components/PopoverTrigger.d.ts.map +1 -1
  165. package/dist/components/Popover/components/PopoverTrigger.js +2 -2
  166. package/dist/components/Popover/components/PopoverTrigger.js.map +1 -1
  167. package/dist/components/ProgressBar/ProgressBar.d.ts +16 -1
  168. package/dist/components/ProgressBar/ProgressBar.d.ts.map +1 -1
  169. package/dist/components/ProgressBar/ProgressBar.js +19 -3
  170. package/dist/components/ProgressBar/ProgressBar.js.map +1 -1
  171. package/dist/components/RadioButton/RadioButton.d.ts +26 -0
  172. package/dist/components/RadioButton/RadioButton.d.ts.map +1 -1
  173. package/dist/components/RadioButton/RadioButton.js +35 -1
  174. package/dist/components/RadioButton/RadioButton.js.map +1 -1
  175. package/dist/components/RadioButtonGroup/RadioButtonGroup.d.ts +26 -0
  176. package/dist/components/RadioButtonGroup/RadioButtonGroup.d.ts.map +1 -1
  177. package/dist/components/RadioButtonGroup/RadioButtonGroup.js +33 -0
  178. package/dist/components/RadioButtonGroup/RadioButtonGroup.js.map +1 -1
  179. package/dist/components/SearchInput/SearchInput.d.ts +10 -0
  180. package/dist/components/SearchInput/SearchInput.d.ts.map +1 -1
  181. package/dist/components/SearchInput/SearchInput.js +12 -1
  182. package/dist/components/SearchInput/SearchInput.js.map +1 -1
  183. package/dist/components/Select/Select.d.ts +10 -2
  184. package/dist/components/Select/Select.d.ts.map +1 -1
  185. package/dist/components/Select/Select.js +63 -18
  186. package/dist/components/Select/Select.js.map +1 -1
  187. package/dist/components/Select/SelectDropdown.d.ts +14 -2
  188. package/dist/components/Select/SelectDropdown.d.ts.map +1 -1
  189. package/dist/components/Select/SelectDropdown.js +20 -4
  190. package/dist/components/Select/SelectDropdown.js.map +1 -1
  191. package/dist/components/Select/SelectTrigger.d.ts +10 -3
  192. package/dist/components/Select/SelectTrigger.d.ts.map +1 -1
  193. package/dist/components/Select/SelectTrigger.js +12 -3
  194. package/dist/components/Select/SelectTrigger.js.map +1 -1
  195. package/dist/components/Select/useSelectKeyboard.d.ts +15 -1
  196. package/dist/components/Select/useSelectKeyboard.d.ts.map +1 -1
  197. package/dist/components/Select/useSelectKeyboard.js +73 -65
  198. package/dist/components/Select/useSelectKeyboard.js.map +1 -1
  199. package/dist/components/Separator/Separator.d.ts +10 -0
  200. package/dist/components/Separator/Separator.d.ts.map +1 -1
  201. package/dist/components/Separator/Separator.js +10 -0
  202. package/dist/components/Separator/Separator.js.map +1 -1
  203. package/dist/components/Sheet/Sheet.d.ts +25 -5
  204. package/dist/components/Sheet/Sheet.d.ts.map +1 -1
  205. package/dist/components/Sheet/Sheet.js +24 -6
  206. package/dist/components/Sheet/Sheet.js.map +1 -1
  207. package/dist/components/Sheet/components/SheetContext.d.ts +10 -0
  208. package/dist/components/Sheet/components/SheetContext.d.ts.map +1 -1
  209. package/dist/components/Sheet/components/SheetContext.js.map +1 -1
  210. package/dist/components/Sheet/components/SheetFooter.js +1 -1
  211. package/dist/components/Sheet/components/SheetFooter.js.map +1 -1
  212. package/dist/components/Sheet/components/SheetHeader.d.ts.map +1 -1
  213. package/dist/components/Sheet/components/SheetHeader.js +11 -2
  214. package/dist/components/Sheet/components/SheetHeader.js.map +1 -1
  215. package/dist/components/Sparkline/Sparkline.d.ts +21 -2
  216. package/dist/components/Sparkline/Sparkline.d.ts.map +1 -1
  217. package/dist/components/Sparkline/Sparkline.js +16 -3
  218. package/dist/components/Sparkline/Sparkline.js.map +1 -1
  219. package/dist/components/Spinner/Spinner.d.ts +27 -2
  220. package/dist/components/Spinner/Spinner.d.ts.map +1 -1
  221. package/dist/components/Spinner/Spinner.js +28 -3
  222. package/dist/components/Spinner/Spinner.js.map +1 -1
  223. package/dist/components/Switch/Switch.d.ts +18 -0
  224. package/dist/components/Switch/Switch.d.ts.map +1 -1
  225. package/dist/components/Switch/Switch.js +19 -1
  226. package/dist/components/Switch/Switch.js.map +1 -1
  227. package/dist/components/Tabs/Tabs.d.ts +8 -2
  228. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  229. package/dist/components/Tabs/Tabs.js +6 -0
  230. package/dist/components/Tabs/Tabs.js.map +1 -1
  231. package/dist/components/Tabs/components/TabsList.d.ts +1 -1
  232. package/dist/components/Tabs/components/TabsList.d.ts.map +1 -1
  233. package/dist/components/Tabs/components/TabsList.js +5 -4
  234. package/dist/components/Tabs/components/TabsList.js.map +1 -1
  235. package/dist/components/Tabs/components/TabsPanels.d.ts +1 -1
  236. package/dist/components/Tabs/components/TabsPanels.d.ts.map +1 -1
  237. package/dist/components/Tabs/components/TabsPanels.js +5 -3
  238. package/dist/components/Tabs/components/TabsPanels.js.map +1 -1
  239. package/dist/components/Tabs/components/TabsTrigger.d.ts.map +1 -1
  240. package/dist/components/Tabs/components/TabsTrigger.js +22 -6
  241. package/dist/components/Tabs/components/TabsTrigger.js.map +1 -1
  242. package/dist/components/TagChip/TagChip.d.ts +16 -13
  243. package/dist/components/TagChip/TagChip.d.ts.map +1 -1
  244. package/dist/components/TagChip/TagChip.js +18 -3
  245. package/dist/components/TagChip/TagChip.js.map +1 -1
  246. package/dist/components/TagInput/TagInput.d.ts +12 -9
  247. package/dist/components/TagInput/TagInput.d.ts.map +1 -1
  248. package/dist/components/TagInput/TagInput.js +16 -4
  249. package/dist/components/TagInput/TagInput.js.map +1 -1
  250. package/dist/components/Text/Text.d.ts +9 -0
  251. package/dist/components/Text/Text.d.ts.map +1 -1
  252. package/dist/components/Text/Text.js +9 -0
  253. package/dist/components/Text/Text.js.map +1 -1
  254. package/dist/components/TextInline/TextInline.d.ts +15 -4
  255. package/dist/components/TextInline/TextInline.d.ts.map +1 -1
  256. package/dist/components/TextInline/TextInline.js +11 -0
  257. package/dist/components/TextInline/TextInline.js.map +1 -1
  258. package/dist/components/Textarea/Textarea.d.ts +12 -0
  259. package/dist/components/Textarea/Textarea.d.ts.map +1 -1
  260. package/dist/components/Textarea/Textarea.js +13 -1
  261. package/dist/components/Textarea/Textarea.js.map +1 -1
  262. package/dist/components/TimePicker/TimeColumn.d.ts +10 -1
  263. package/dist/components/TimePicker/TimeColumn.d.ts.map +1 -1
  264. package/dist/components/TimePicker/TimeColumn.js +8 -1
  265. package/dist/components/TimePicker/TimeColumn.js.map +1 -1
  266. package/dist/components/TimePicker/TimePicker.d.ts +34 -2
  267. package/dist/components/TimePicker/TimePicker.d.ts.map +1 -1
  268. package/dist/components/TimePicker/TimePicker.js +118 -15
  269. package/dist/components/TimePicker/TimePicker.js.map +1 -1
  270. package/dist/components/TimePicker/TimeSegments.d.ts +50 -0
  271. package/dist/components/TimePicker/TimeSegments.d.ts.map +1 -0
  272. package/dist/components/TimePicker/TimeSegments.js +93 -0
  273. package/dist/components/TimePicker/TimeSegments.js.map +1 -0
  274. package/dist/components/TimePicker/timepicker.hooks.d.ts +0 -4
  275. package/dist/components/TimePicker/timepicker.hooks.d.ts.map +1 -1
  276. package/dist/components/TimePicker/timepicker.hooks.js +1 -23
  277. package/dist/components/TimePicker/timepicker.hooks.js.map +1 -1
  278. package/dist/components/TimePicker/timepicker.types.d.ts +14 -15
  279. package/dist/components/TimePicker/timepicker.types.d.ts.map +1 -1
  280. package/dist/components/TimePicker/timepicker.types.js +4 -3
  281. package/dist/components/TimePicker/timepicker.types.js.map +1 -1
  282. package/dist/components/Toast/Toast.d.ts +27 -0
  283. package/dist/components/Toast/Toast.d.ts.map +1 -1
  284. package/dist/components/Toast/Toast.js +28 -1
  285. package/dist/components/Toast/Toast.js.map +1 -1
  286. package/dist/components/Toggle/Toggle.d.ts +31 -12
  287. package/dist/components/Toggle/Toggle.d.ts.map +1 -1
  288. package/dist/components/Toggle/Toggle.js +19 -31
  289. package/dist/components/Toggle/Toggle.js.map +1 -1
  290. package/dist/components/Toggle/index.d.ts +1 -1
  291. package/dist/components/Toggle/index.d.ts.map +1 -1
  292. package/dist/components/Toggle/index.js +1 -1
  293. package/dist/components/Toggle/index.js.map +1 -1
  294. package/dist/components/ToggleGroup/ToggleGroup.d.ts +17 -0
  295. package/dist/components/ToggleGroup/ToggleGroup.d.ts.map +1 -1
  296. package/dist/components/ToggleGroup/ToggleGroup.js +17 -0
  297. package/dist/components/ToggleGroup/ToggleGroup.js.map +1 -1
  298. package/dist/components/ToggleGroup/ToggleGroupItem.d.ts +1 -1
  299. package/dist/components/ToggleGroup/ToggleGroupItem.d.ts.map +1 -1
  300. package/dist/components/ToggleGroup/ToggleGroupItem.js +7 -6
  301. package/dist/components/ToggleGroup/ToggleGroupItem.js.map +1 -1
  302. package/dist/components/ToggleGroup/ToggleGroupMultiple.d.ts +4 -3
  303. package/dist/components/ToggleGroup/ToggleGroupMultiple.d.ts.map +1 -1
  304. package/dist/components/ToggleGroup/ToggleGroupMultiple.js +2 -2
  305. package/dist/components/ToggleGroup/ToggleGroupMultiple.js.map +1 -1
  306. package/dist/components/ToggleGroup/ToggleGroupSingle.d.ts +4 -3
  307. package/dist/components/ToggleGroup/ToggleGroupSingle.d.ts.map +1 -1
  308. package/dist/components/ToggleGroup/ToggleGroupSingle.js +2 -2
  309. package/dist/components/ToggleGroup/ToggleGroupSingle.js.map +1 -1
  310. package/dist/components/ToggleGroup/toggleGroup.types.d.ts +12 -3
  311. package/dist/components/ToggleGroup/toggleGroup.types.d.ts.map +1 -1
  312. package/dist/components/Tooltip/Tooltip.d.ts +6 -0
  313. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  314. package/dist/components/Tooltip/Tooltip.js +6 -0
  315. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  316. package/dist/date-time/index.d.ts +2 -0
  317. package/dist/date-time/index.d.ts.map +1 -1
  318. package/dist/date-time/index.js +9 -1
  319. package/dist/date-time/index.js.map +1 -1
  320. package/dist/date-time/iso.d.ts +261 -0
  321. package/dist/date-time/iso.d.ts.map +1 -0
  322. package/dist/date-time/iso.js +358 -0
  323. package/dist/date-time/iso.js.map +1 -0
  324. package/dist/date-time/now.d.ts +7 -6
  325. package/dist/date-time/now.d.ts.map +1 -1
  326. package/dist/date-time/now.js +3 -3
  327. package/dist/date-time/now.js.map +1 -1
  328. package/dist/internal/PickerField.d.ts +45 -0
  329. package/dist/internal/PickerField.d.ts.map +1 -0
  330. package/dist/internal/PickerField.js +24 -0
  331. package/dist/internal/PickerField.js.map +1 -0
  332. package/dist/internal/SegmentedField.d.ts +98 -0
  333. package/dist/internal/SegmentedField.d.ts.map +1 -0
  334. package/dist/internal/SegmentedField.js +315 -0
  335. package/dist/internal/SegmentedField.js.map +1 -0
  336. package/dist/internal/index.d.ts +2 -0
  337. package/dist/internal/index.d.ts.map +1 -1
  338. package/dist/internal/index.js +2 -0
  339. package/dist/internal/index.js.map +1 -1
  340. package/dist/theme/index.d.ts +4 -3
  341. package/dist/theme/index.d.ts.map +1 -1
  342. package/dist/theme/index.js +3 -2
  343. package/dist/theme/index.js.map +1 -1
  344. package/dist/theme/schema.d.ts +49 -33
  345. package/dist/theme/schema.d.ts.map +1 -1
  346. package/dist/theme/schema.js +30 -21
  347. package/dist/theme/schema.js.map +1 -1
  348. package/package.json +11 -59
  349. package/src/components/Badge/Badge.tsx +87 -49
  350. package/src/components/Badge/index.ts +10 -1
  351. package/src/components/BarChart/BarChart.tsx +37 -30
  352. package/src/components/Button/Button.tsx +129 -106
  353. package/src/components/Button/index.ts +10 -1
  354. package/src/components/Calendar/Calendar.tsx +104 -401
  355. package/src/components/Calendar/CalendarView.tsx +454 -0
  356. package/src/components/Calendar/calendar.types.ts +104 -29
  357. package/src/components/Calendar/index.ts +16 -17
  358. package/src/components/Card/Card.tsx +15 -2
  359. package/src/components/Checkbox/Checkbox.tsx +22 -2
  360. package/src/components/CheckboxGroup/CheckboxGroup.tsx +22 -0
  361. package/src/components/Code/Editor/Editor.tsx +2 -2
  362. package/src/components/Code/Editor/themes.ts +50 -32
  363. package/src/components/Code/ValidationStatus/ValidationStatus.tsx +6 -3
  364. package/src/components/DatePicker/DatePicker.tsx +369 -42
  365. package/src/components/DatePicker/DateSegments.tsx +125 -0
  366. package/src/components/DatePicker/datepicker.types.ts +58 -39
  367. package/src/components/DatePicker/index.ts +11 -3
  368. package/src/components/DateRangePicker/DateRangePicker.tsx +38 -24
  369. package/src/components/DateRangePicker/daterangepicker.types.ts +29 -23
  370. package/src/components/DateRangePicker/index.ts +9 -1
  371. package/src/components/DateTimePicker/DateTimePicker.tsx +189 -88
  372. package/src/components/DateTimePicker/DateTimeSegments.tsx +113 -0
  373. package/src/components/DateTimePicker/datetimepicker.types.ts +29 -19
  374. package/src/components/DateTimePicker/index.ts +9 -1
  375. package/src/components/DateTimeRangePicker/DateTimeRangePicker.tsx +251 -126
  376. package/src/components/DateTimeRangePicker/datetimerangepicker.types.ts +31 -20
  377. package/src/components/DateTimeRangePicker/index.ts +9 -0
  378. package/src/components/Field/Field.tsx +25 -26
  379. package/src/components/FormField/FormField.tsx +15 -0
  380. package/src/components/HoverCard/HoverCard.tsx +6 -0
  381. package/src/components/Input/Input.tsx +19 -4
  382. package/src/components/LineChart/LineChart.tsx +164 -141
  383. package/src/components/Markdown/Markdown.tsx +21 -3
  384. package/src/components/Message/Message.tsx +83 -17
  385. package/src/components/Message/index.ts +1 -1
  386. package/src/components/Modal/Modal.tsx +157 -86
  387. package/src/components/Modal/components/ModalContext.tsx +14 -0
  388. package/src/components/Modal/components/ModalHeader.tsx +15 -3
  389. package/src/components/Popover/Popover.tsx +36 -0
  390. package/src/components/Popover/components/PopoverBody.tsx +6 -1
  391. package/src/components/Popover/components/PopoverContext.tsx +1 -0
  392. package/src/components/Popover/components/PopoverTrigger.tsx +2 -1
  393. package/src/components/ProgressBar/ProgressBar.tsx +46 -28
  394. package/src/components/RadioButton/RadioButton.tsx +34 -3
  395. package/src/components/RadioButtonGroup/RadioButtonGroup.tsx +32 -0
  396. package/src/components/SearchInput/SearchInput.tsx +13 -2
  397. package/src/components/Select/Select.tsx +75 -19
  398. package/src/components/Select/SelectDropdown.tsx +45 -12
  399. package/src/components/Select/SelectTrigger.tsx +31 -8
  400. package/src/components/Select/useSelectKeyboard.ts +20 -10
  401. package/src/components/Separator/Separator.tsx +10 -0
  402. package/src/components/Sheet/Sheet.tsx +114 -83
  403. package/src/components/Sheet/components/SheetContext.tsx +10 -0
  404. package/src/components/Sheet/components/SheetFooter.tsx +1 -1
  405. package/src/components/Sheet/components/SheetHeader.tsx +18 -3
  406. package/src/components/Sparkline/Sparkline.tsx +40 -36
  407. package/src/components/Spinner/Spinner.tsx +28 -3
  408. package/src/components/Switch/Switch.tsx +27 -4
  409. package/src/components/Tabs/Tabs.tsx +6 -0
  410. package/src/components/Tabs/components/TabsList.tsx +5 -3
  411. package/src/components/Tabs/components/TabsPanels.tsx +5 -3
  412. package/src/components/Tabs/components/TabsTrigger.tsx +22 -5
  413. package/src/components/TagChip/TagChip.tsx +27 -18
  414. package/src/components/TagInput/TagInput.tsx +16 -11
  415. package/src/components/Text/Text.tsx +9 -0
  416. package/src/components/TextInline/TextInline.tsx +11 -0
  417. package/src/components/Textarea/Textarea.tsx +13 -1
  418. package/src/components/TimePicker/TimeColumn.tsx +24 -1
  419. package/src/components/TimePicker/TimePicker.tsx +157 -51
  420. package/src/components/TimePicker/TimeSegments.tsx +131 -0
  421. package/src/components/TimePicker/timepicker.hooks.ts +1 -24
  422. package/src/components/TimePicker/timepicker.types.ts +14 -16
  423. package/src/components/Toast/Toast.tsx +28 -1
  424. package/src/components/Toggle/Toggle.tsx +34 -32
  425. package/src/components/Toggle/index.ts +1 -1
  426. package/src/components/ToggleGroup/ToggleGroup.tsx +17 -0
  427. package/src/components/ToggleGroup/ToggleGroupItem.tsx +13 -8
  428. package/src/components/ToggleGroup/ToggleGroupMultiple.tsx +3 -1
  429. package/src/components/ToggleGroup/ToggleGroupSingle.tsx +3 -1
  430. package/src/components/ToggleGroup/toggleGroup.types.ts +12 -3
  431. package/src/components/Tooltip/Tooltip.tsx +6 -0
  432. package/src/date-time/index.ts +61 -1
  433. package/src/date-time/iso.ts +511 -0
  434. package/src/date-time/now.ts +10 -9
  435. package/src/internal/PickerField.tsx +90 -0
  436. package/src/internal/SegmentedField.tsx +445 -0
  437. package/src/internal/index.ts +2 -0
  438. package/src/theme/index.ts +11 -9
  439. package/src/theme/recipes/badge.css +140 -0
  440. package/src/theme/recipes/button.css +167 -0
  441. package/src/theme/recipes/card.css +26 -0
  442. package/src/theme/recipes/checkbox.css +44 -0
  443. package/src/theme/recipes/field.css +14 -0
  444. package/src/theme/recipes/index.css +28 -0
  445. package/src/theme/recipes/input.css +29 -0
  446. package/src/theme/recipes/message.css +47 -0
  447. package/src/theme/recipes/modal.css +31 -0
  448. package/src/theme/recipes/radio-button.css +42 -0
  449. package/src/theme/recipes/search-input.css +16 -0
  450. package/src/theme/recipes/select.css +105 -0
  451. package/src/theme/recipes/sheet.css +34 -0
  452. package/src/theme/recipes/spinner.css +17 -0
  453. package/src/theme/recipes/switch.css +39 -0
  454. package/src/theme/recipes/tabs.css +41 -0
  455. package/src/theme/recipes/tag-chip.css +27 -0
  456. package/src/theme/recipes/textarea.css +20 -0
  457. package/src/theme/recipes/toggle.css +92 -0
  458. package/src/theme/schema.ts +59 -58
  459. package/src/theme/tokens.css +824 -0
  460. package/dist/components/Avatar/Avatar.d.ts +0 -6
  461. package/dist/components/Avatar/Avatar.d.ts.map +0 -1
  462. package/dist/components/Avatar/Avatar.js +0 -11
  463. package/dist/components/Avatar/Avatar.js.map +0 -1
  464. package/dist/components/Avatar/index.d.ts +0 -2
  465. package/dist/components/Avatar/index.d.ts.map +0 -1
  466. package/dist/components/Avatar/index.js +0 -2
  467. package/dist/components/Avatar/index.js.map +0 -1
  468. package/dist/components/Breadcrumb/Breadcrumb.d.ts +0 -12
  469. package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +0 -1
  470. package/dist/components/Breadcrumb/Breadcrumb.js +0 -19
  471. package/dist/components/Breadcrumb/Breadcrumb.js.map +0 -1
  472. package/dist/components/Breadcrumb/index.d.ts +0 -2
  473. package/dist/components/Breadcrumb/index.d.ts.map +0 -1
  474. package/dist/components/Breadcrumb/index.js +0 -2
  475. package/dist/components/Breadcrumb/index.js.map +0 -1
  476. package/dist/components/ColorDot/ColorDot.d.ts +0 -13
  477. package/dist/components/ColorDot/ColorDot.d.ts.map +0 -1
  478. package/dist/components/ColorDot/ColorDot.js +0 -34
  479. package/dist/components/ColorDot/ColorDot.js.map +0 -1
  480. package/dist/components/ColorDot/index.d.ts +0 -2
  481. package/dist/components/ColorDot/index.d.ts.map +0 -1
  482. package/dist/components/ColorDot/index.js +0 -2
  483. package/dist/components/ColorDot/index.js.map +0 -1
  484. package/dist/components/EmptyState/EmptyState.d.ts +0 -15
  485. package/dist/components/EmptyState/EmptyState.d.ts.map +0 -1
  486. package/dist/components/EmptyState/EmptyState.js +0 -7
  487. package/dist/components/EmptyState/EmptyState.js.map +0 -1
  488. package/dist/components/EmptyState/index.d.ts +0 -2
  489. package/dist/components/EmptyState/index.d.ts.map +0 -1
  490. package/dist/components/EmptyState/index.js +0 -2
  491. package/dist/components/EmptyState/index.js.map +0 -1
  492. package/dist/components/HeatMap/HeatMapCalendar.d.ts +0 -11
  493. package/dist/components/HeatMap/HeatMapCalendar.d.ts.map +0 -1
  494. package/dist/components/HeatMap/HeatMapCalendar.js +0 -68
  495. package/dist/components/HeatMap/HeatMapCalendar.js.map +0 -1
  496. package/dist/components/HeatMap/HeatMapMatrix.d.ts +0 -12
  497. package/dist/components/HeatMap/HeatMapMatrix.d.ts.map +0 -1
  498. package/dist/components/HeatMap/HeatMapMatrix.js +0 -35
  499. package/dist/components/HeatMap/HeatMapMatrix.js.map +0 -1
  500. package/dist/components/HeatMap/heat-map.utils.d.ts +0 -10
  501. package/dist/components/HeatMap/heat-map.utils.d.ts.map +0 -1
  502. package/dist/components/HeatMap/heat-map.utils.js +0 -10
  503. package/dist/components/HeatMap/heat-map.utils.js.map +0 -1
  504. package/dist/components/HeatMap/index.d.ts +0 -4
  505. package/dist/components/HeatMap/index.d.ts.map +0 -1
  506. package/dist/components/HeatMap/index.js +0 -3
  507. package/dist/components/HeatMap/index.js.map +0 -1
  508. package/dist/components/MetricList/MetricList.d.ts +0 -9
  509. package/dist/components/MetricList/MetricList.d.ts.map +0 -1
  510. package/dist/components/MetricList/MetricList.js +0 -6
  511. package/dist/components/MetricList/MetricList.js.map +0 -1
  512. package/dist/components/MetricList/MetricRow.d.ts +0 -13
  513. package/dist/components/MetricList/MetricRow.d.ts.map +0 -1
  514. package/dist/components/MetricList/MetricRow.js +0 -13
  515. package/dist/components/MetricList/MetricRow.js.map +0 -1
  516. package/dist/components/MetricList/index.d.ts +0 -3
  517. package/dist/components/MetricList/index.d.ts.map +0 -1
  518. package/dist/components/MetricList/index.js +0 -3
  519. package/dist/components/MetricList/index.js.map +0 -1
  520. package/dist/components/NavBottom/NavBottom.d.ts +0 -15
  521. package/dist/components/NavBottom/NavBottom.d.ts.map +0 -1
  522. package/dist/components/NavBottom/NavBottom.js +0 -19
  523. package/dist/components/NavBottom/NavBottom.js.map +0 -1
  524. package/dist/components/NavBottom/index.d.ts +0 -3
  525. package/dist/components/NavBottom/index.d.ts.map +0 -1
  526. package/dist/components/NavBottom/index.js +0 -2
  527. package/dist/components/NavBottom/index.js.map +0 -1
  528. package/dist/components/NavSide/NavItem.d.ts +0 -9
  529. package/dist/components/NavSide/NavItem.d.ts.map +0 -1
  530. package/dist/components/NavSide/NavItem.js +0 -13
  531. package/dist/components/NavSide/NavItem.js.map +0 -1
  532. package/dist/components/NavSide/NavSide.d.ts +0 -15
  533. package/dist/components/NavSide/NavSide.d.ts.map +0 -1
  534. package/dist/components/NavSide/NavSide.js +0 -10
  535. package/dist/components/NavSide/NavSide.js.map +0 -1
  536. package/dist/components/NavSide/index.d.ts +0 -3
  537. package/dist/components/NavSide/index.d.ts.map +0 -1
  538. package/dist/components/NavSide/index.js +0 -2
  539. package/dist/components/NavSide/index.js.map +0 -1
  540. package/dist/components/NavSide/types.d.ts +0 -38
  541. package/dist/components/NavSide/types.d.ts.map +0 -1
  542. package/dist/components/NavSide/types.js +0 -2
  543. package/dist/components/NavSide/types.js.map +0 -1
  544. package/dist/components/Pagination/Pagination.d.ts +0 -35
  545. package/dist/components/Pagination/Pagination.d.ts.map +0 -1
  546. package/dist/components/Pagination/Pagination.js +0 -26
  547. package/dist/components/Pagination/Pagination.js.map +0 -1
  548. package/dist/components/Pagination/index.d.ts +0 -3
  549. package/dist/components/Pagination/index.d.ts.map +0 -1
  550. package/dist/components/Pagination/index.js +0 -2
  551. package/dist/components/Pagination/index.js.map +0 -1
  552. package/dist/components/Skeleton/Skeleton.d.ts +0 -3
  553. package/dist/components/Skeleton/Skeleton.d.ts.map +0 -1
  554. package/dist/components/Skeleton/Skeleton.js +0 -7
  555. package/dist/components/Skeleton/Skeleton.js.map +0 -1
  556. package/dist/components/Skeleton/index.d.ts +0 -2
  557. package/dist/components/Skeleton/index.d.ts.map +0 -1
  558. package/dist/components/Skeleton/index.js +0 -2
  559. package/dist/components/Skeleton/index.js.map +0 -1
  560. package/dist/components/StatsCard/StatsCard.d.ts +0 -17
  561. package/dist/components/StatsCard/StatsCard.d.ts.map +0 -1
  562. package/dist/components/StatsCard/StatsCard.js +0 -13
  563. package/dist/components/StatsCard/StatsCard.js.map +0 -1
  564. package/dist/components/StatsCard/index.d.ts +0 -2
  565. package/dist/components/StatsCard/index.d.ts.map +0 -1
  566. package/dist/components/StatsCard/index.js +0 -2
  567. package/dist/components/StatsCard/index.js.map +0 -1
  568. package/dist/styles.css +0 -2
  569. package/dist/theme.generated.css +0 -438
  570. package/src/components/Avatar/Avatar.tsx +0 -19
  571. package/src/components/Avatar/index.ts +0 -1
  572. package/src/components/Breadcrumb/Breadcrumb.tsx +0 -47
  573. package/src/components/Breadcrumb/index.ts +0 -5
  574. package/src/components/ColorDot/ColorDot.tsx +0 -50
  575. package/src/components/ColorDot/index.ts +0 -1
  576. package/src/components/EmptyState/EmptyState.tsx +0 -29
  577. package/src/components/EmptyState/index.ts +0 -1
  578. package/src/components/HeatMap/HeatMapCalendar.tsx +0 -127
  579. package/src/components/HeatMap/HeatMapMatrix.tsx +0 -75
  580. package/src/components/HeatMap/heat-map.utils.ts +0 -15
  581. package/src/components/HeatMap/index.ts +0 -3
  582. package/src/components/MetricList/MetricList.tsx +0 -13
  583. package/src/components/MetricList/MetricRow.tsx +0 -30
  584. package/src/components/MetricList/index.ts +0 -2
  585. package/src/components/NavBottom/NavBottom.tsx +0 -53
  586. package/src/components/NavBottom/index.ts +0 -3
  587. package/src/components/NavSide/NavItem.tsx +0 -39
  588. package/src/components/NavSide/NavSide.tsx +0 -40
  589. package/src/components/NavSide/index.ts +0 -2
  590. package/src/components/NavSide/types.ts +0 -36
  591. package/src/components/Pagination/Pagination.tsx +0 -86
  592. package/src/components/Pagination/index.ts +0 -2
  593. package/src/components/Skeleton/Skeleton.tsx +0 -7
  594. package/src/components/Skeleton/index.ts +0 -1
  595. package/src/components/StatsCard/StatsCard.tsx +0 -40
  596. package/src/components/StatsCard/index.ts +0 -1
  597. package/src/styles/base.css +0 -41
  598. package/src/theme/palette.json +0 -100
  599. package/src/theme/palette.schema.json +0 -40
  600. package/src/theme/theme.json +0 -349
  601. package/src/theme/theme.schema.json +0 -876
  602. package/src/theme/typography.json +0 -7
  603. package/src/theme/typography.schema.json +0 -36
  604. package/tailwind.config.ts +0 -261
@@ -1,5 +1,6 @@
1
1
  import { Caption } from "@sixthshift/design-system/caption";
2
2
  import { cn } from "@sixthshift/design-system/utils";
3
+ import * as React from "react";
3
4
 
4
5
  export type ProgressBarProps = {
5
6
  completed: number;
@@ -10,33 +11,50 @@ export type ProgressBarProps = {
10
11
  className?: string;
11
12
  };
12
13
 
13
- export const ProgressBar = ({ completed, total, showFraction = true, label = "Progress", className }: ProgressBarProps) => {
14
- // A caller can hand us anything; the bar must not render an out-of-range
15
- // width (a negative `width` is invalid CSS) or report impossible progress.
16
- const isMeasurable = total > 0;
17
- const clamped = isMeasurable ? Math.min(Math.max(completed, 0), total) : 0;
18
- const percentage = isMeasurable ? (clamped / total) * 100 : 0;
14
+ /**
15
+ * Determinate progress meter: a labelled fill bar plus an optional `n/total`
16
+ * fraction (`showFraction`, default `true`).
17
+ *
18
+ * The bar itself is `role="progressbar"` with `aria-valuemin`/`-valuenow`/
19
+ * `-valuemax`/`-valuetext`, and `label` (default `"Progress"`) sets its
20
+ * accessible name — give it something more specific than the default when
21
+ * more than one bar can appear on a page. `completed` is clamped into
22
+ * `[0, total]` before it drives the fill width or `aria-valuenow`, so an
23
+ * out-of-range value (negative, or greater than `total`) can't produce
24
+ * invalid CSS or an impossible reported value — though the fraction text
25
+ * still shows the raw, unclamped numbers. When `total` is not positive the
26
+ * bar renders as indeterminate: no `aria-valuenow`/`aria-valuemax`, 0% fill.
27
+ */
28
+ export const ProgressBar = React.forwardRef<HTMLDivElement, ProgressBarProps>(
29
+ ({ completed, total, showFraction = true, label = "Progress", className }, ref) => {
30
+ // A caller can hand us anything; the bar must not render an out-of-range
31
+ // width (a negative `width` is invalid CSS) or report impossible progress.
32
+ const isMeasurable = total > 0;
33
+ const clamped = isMeasurable ? Math.min(Math.max(completed, 0), total) : 0;
34
+ const percentage = isMeasurable ? (clamped / total) * 100 : 0;
19
35
 
20
- return (
21
- <div className={cn("flex items-center gap-3", className)}>
22
- <div
23
- role="progressbar"
24
- aria-label={label}
25
- aria-valuemin={0}
26
- aria-valuemax={isMeasurable ? total : undefined}
27
- // An indeterminate progressbar omits aria-valuenow; with no positive
28
- // total there is no meaningful progress to report.
29
- aria-valuenow={isMeasurable ? clamped : undefined}
30
- aria-valuetext={isMeasurable ? `${clamped} of ${total}` : undefined}
31
- className="h-2 flex-1 overflow-hidden rounded-full bg-bg-strong"
32
- >
33
- <div className="h-full rounded-full bg-fg-success transition-all" style={{ width: `${percentage}%` }} />
36
+ return (
37
+ <div ref={ref} className={cn("flex items-center gap-3", className)}>
38
+ <div
39
+ role="progressbar"
40
+ aria-label={label}
41
+ aria-valuemin={0}
42
+ aria-valuemax={isMeasurable ? total : undefined}
43
+ // An indeterminate progressbar omits aria-valuenow; with no positive
44
+ // total there is no meaningful progress to report.
45
+ aria-valuenow={isMeasurable ? clamped : undefined}
46
+ aria-valuetext={isMeasurable ? `${clamped} of ${total}` : undefined}
47
+ className="h-2 flex-1 overflow-hidden rounded-full bg-bg-strong"
48
+ >
49
+ <div className="h-full rounded-full bg-fg-success transition-all" style={{ width: `${percentage}%` }} />
50
+ </div>
51
+ {showFraction && (
52
+ <Caption className="shrink-0">
53
+ {completed}/{total}
54
+ </Caption>
55
+ )}
34
56
  </div>
35
- {showFraction && (
36
- <Caption className="shrink-0">
37
- {completed}/{total}
38
- </Caption>
39
- )}
40
- </div>
41
- );
42
- };
57
+ );
58
+ }
59
+ );
60
+ ProgressBar.displayName = "ProgressBar";
@@ -23,6 +23,32 @@ const RadioButtonIcon = () => (
23
23
  </svg>
24
24
  );
25
25
 
26
+ /**
27
+ * A single custom radio option — a button with `role="radio"` rather than
28
+ * a native `<input type="radio">`, so it can be styled without fighting
29
+ * native radio rendering.
30
+ *
31
+ * Unlike `Checkbox`, it holds no internal state: `checked` is a plain
32
+ * controlled prop (default `false`, no `defaultChecked`), and clicking an
33
+ * unselected radio calls `onCheckedChange(true)` — the caller owns tracking
34
+ * which option in a group is selected. In practice that means using
35
+ * `RadioButtonGroup` to manage a group's value, or wiring up the shared
36
+ * selection by hand.
37
+ *
38
+ * Clicking an already-selected radio does nothing and reports nothing: a radio
39
+ * is not a toggle, and the way to deselect one is to select a sibling. That
40
+ * makes `onCheckedChange` a one-way signal — it is only ever called with
41
+ * `true`.
42
+ *
43
+ * Only participates in native form submission when `name` is set, via a
44
+ * hidden native `<input type="radio">` rendered alongside the button and
45
+ * kept in sync (`value` defaults to `"on"`); give every radio in a group the
46
+ * same `name` to group them for native submission.
47
+ *
48
+ * Passing `label` wraps the button and a `<Label>` together and wires
49
+ * `htmlFor`/`id` between them; without it, you get just the button and must
50
+ * supply your own accessible name.
51
+ */
26
52
  const RadioButton = React.forwardRef<HTMLButtonElement, RadioButtonProps>(
27
53
  ({ className, checked = false, onCheckedChange, disabled, name, value = "on", label, labelClassName, id: idProp, ...props }, ref) => {
28
54
  const generatedId = React.useId();
@@ -39,10 +65,15 @@ const RadioButton = React.forwardRef<HTMLButtonElement, RadioButtonProps>(
39
65
  data-state={checked ? "checked" : "unchecked"}
40
66
  disabled={disabled}
41
67
  ref={ref}
42
- onClick={() => onCheckedChange?.(!checked)}
68
+ // A radio is not a toggle: activating the selected option leaves it
69
+ // selected, and reports nothing, so a caller holding the selection
70
+ // does not see a spurious change. Deselection happens by selecting a
71
+ // sibling, which is what `RadioButtonGroup` does.
72
+ onClick={() => {
73
+ if (!checked) onCheckedChange?.(true);
74
+ }}
43
75
  className={cn(
44
- "peer h-4 w-4 shrink-0 cursor-pointer rounded-full border border-border-brand shadow focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
45
- checked && "bg-bg-brand text-fg-on-brand",
76
+ "radio-button peer border-(color:--radio-button-border) focus-visible:ring-(color:--radio-button-ring) h-4 w-4 shrink-0 cursor-pointer rounded-full border bg-(--radio-button-bg) text-(--radio-button-fg) shadow focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
46
77
  className
47
78
  )}
48
79
  {...props}
@@ -37,6 +37,32 @@ export type RadioButtonGroupProps = Omit<React.HTMLAttributes<HTMLDivElement>, "
37
37
  onBlur?: () => void;
38
38
  };
39
39
 
40
+ /**
41
+ * A set of mutually exclusive radio options sharing one controlled/
42
+ * uncontrolled `string` selection, via the `value`/`defaultValue`/
43
+ * `onValueChange` triad (`useControllableState`).
44
+ *
45
+ * `variant="default"` (the default) renders one `RadioButton` per option.
46
+ * `variant="button"` is a separate rendering path — not a re-skinned
47
+ * `RadioButton` — a row/column of plain buttons with `role="radio"`;
48
+ * contiguous buttons touch and share borders (`appearance="segmented"`, the
49
+ * default) or sit apart with their own rounded corners
50
+ * (`appearance="separate"`).
51
+ *
52
+ * Implements the WAI-ARIA radiogroup keyboard pattern: the group is one tab
53
+ * stop, landing on the checked option (or the first enabled option if none
54
+ * is checked), and arrow/Home/End keys move focus *and* selection between
55
+ * enabled options, wrapping at the ends.
56
+ *
57
+ * Form submission only happens when `name` is set. In the default variant
58
+ * that means each underlying `RadioButton` gets `name`, so one hidden
59
+ * native radio input is rendered per option; in the button variant the
60
+ * group itself renders a single hidden `<input type="hidden">` carrying the
61
+ * selected value.
62
+ *
63
+ * Renders `role="radiogroup"`; focus leaving the whole group — not just
64
+ * moving between options — fires `onBlur`.
65
+ */
40
66
  const RadioButtonGroup = React.forwardRef<HTMLDivElement, RadioButtonGroupProps>(
41
67
  (
42
68
  {
@@ -81,6 +107,12 @@ const RadioButtonGroup = React.forwardRef<HTMLDivElement, RadioButtonGroupProps>
81
107
  );
82
108
 
83
109
  const handleOptionSelect = (optionValue: string) => {
110
+ // Re-selecting the current option reports nothing, as a native radio does
111
+ // not. The guard lives here as well as in `RadioButton` because the button
112
+ // variant is a separate rendering path that never goes through it — and
113
+ // the two variants must not disagree about this. `ToggleGroup` in
114
+ // `"single"` mode already works this way.
115
+ if (optionValue === value) return;
84
116
  setValue(optionValue);
85
117
  };
86
118
 
@@ -1,4 +1,5 @@
1
1
  import { Input } from "@sixthshift/design-system/input";
2
+ import { cn } from "@sixthshift/design-system/utils";
2
3
  import { Search, X } from "lucide-react";
3
4
  import * as React from "react";
4
5
 
@@ -10,6 +11,16 @@ export type SearchInputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>,
10
11
  clearLabel?: string;
11
12
  };
12
13
 
14
+ /**
15
+ * Text input specialised for search: a search icon fixed on the left and,
16
+ * once there is a value, a clear button on the right.
17
+ *
18
+ * Wraps `Input`, using its `iconLeft`/`iconRight` slots, rather than
19
+ * reimplementing the field. Always controlled — `value` is required and
20
+ * there is no `defaultValue`/uncontrolled mode. `onChange` receives the
21
+ * string value directly, not the change event. Clearing calls `onClear` if
22
+ * provided, otherwise calls `onChange("")`.
23
+ */
13
24
  const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
14
25
  ({ className, value, onChange, onClear, clearLabel = "Clear search", ...props }, ref) => {
15
26
  const handleClear = () => {
@@ -29,12 +40,12 @@ const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
29
40
  iconLeft={<Search />}
30
41
  iconRight={
31
42
  value ? (
32
- <button type="button" onClick={handleClear} aria-label={clearLabel} className="rounded hover:bg-bg-subtle">
43
+ <button type="button" onClick={handleClear} aria-label={clearLabel} className="rounded hover:bg-(--search-input-clear-bg-hovered)">
33
44
  <X />
34
45
  </button>
35
46
  ) : undefined
36
47
  }
37
- className={className}
48
+ className={cn("search-input", className)}
38
49
  {...props}
39
50
  />
40
51
  );
@@ -1,7 +1,7 @@
1
1
  import { autoUpdate, flip, offset, shift, size, useFloating } from "@floating-ui/react";
2
2
  import { useControllableState } from "@sixthshift/design-system/hooks";
3
- import { type HTMLAttributes, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
- import { SelectDropdown } from "./SelectDropdown";
3
+ import { forwardRef, type HTMLAttributes, type ReactElement, type Ref, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { SelectDropdown, selectOptionId } from "./SelectDropdown";
5
5
  import { SelectTriggerButton, SelectTriggerSearch } from "./SelectTrigger";
6
6
  import { useSelectKeyboard } from "./useSelectKeyboard";
7
7
 
@@ -37,7 +37,13 @@ type SelectMultipleProps<T extends string = string> = SelectBaseProps<T> & {
37
37
 
38
38
  export type SelectProps<T extends string = string> = SelectSingleProps<T> | SelectMultipleProps<T>;
39
39
 
40
- export const Select = <T extends string = string>(props: SelectProps<T>) => {
40
+ /**
41
+ * `forwardRef` erases the generic, so the implementation takes the ref as an
42
+ * ordinary second argument and the exported `Select` re-declares the generic
43
+ * signature over it. Consumers keep `Select<"a" | "b">` inference *and* get a
44
+ * ref; without the cast they would have to choose.
45
+ */
46
+ const SelectRoot = forwardRef(function SelectRoot<T extends string = string>(props: SelectProps<T>, rootRef: Ref<HTMLDivElement>) {
41
47
  const {
42
48
  options,
43
49
  onBlur,
@@ -71,6 +77,11 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
71
77
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
72
78
  const [searchValue, setSearchValue] = useState("");
73
79
  const listboxRef = useRef<HTMLDivElement | null>(null);
80
+ // Also held in state: the listbox is portalled, and FloatingPortal creates its
81
+ // container in an effect, so the node lands a commit after `open` flips. A ref
82
+ // alone is still null when the open effect runs — state re-renders us when the
83
+ // node actually arrives.
84
+ const [listboxNode, setListboxNode] = useState<HTMLDivElement | null>(null);
74
85
  const inputRef = useRef<HTMLInputElement>(null);
75
86
  const optionRefs = useRef<Map<number, HTMLButtonElement>>(new Map());
76
87
  const wasOpenRef = useRef(false);
@@ -111,6 +122,11 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
111
122
  whileElementsMounted: autoUpdate,
112
123
  });
113
124
 
125
+ const setListbox = useCallback((node: HTMLDivElement | null) => {
126
+ listboxRef.current = node;
127
+ setListboxNode(node);
128
+ }, []);
129
+
114
130
  const focusTrigger = useCallback(() => {
115
131
  (refs.reference.current as HTMLElement | null)?.focus();
116
132
  }, [refs.reference]);
@@ -142,18 +158,38 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
142
158
  [isMultiple, setMultiValue, setSingleValue]
143
159
  );
144
160
 
161
+ const handleListKeyDown = useSelectKeyboard({
162
+ open,
163
+ searchable,
164
+ searchValue,
165
+ highlightedIndex,
166
+ displayOptions: filteredOptions,
167
+ setOpen,
168
+ setHighlightedIndex,
169
+ setSearchValue,
170
+ handleSelect,
171
+ focusTrigger,
172
+ });
173
+
145
174
  const handleTriggerKeyDown = useCallback(
146
175
  (event: React.KeyboardEvent<HTMLButtonElement>) => {
147
176
  if (disabled || collapsed) return;
148
177
  if (!open && (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter" || event.key === " ")) {
149
178
  event.preventDefault();
150
179
  setOpen(true);
180
+ return;
151
181
  }
152
182
  if (searchable && !open && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
153
183
  setOpen(true);
184
+ return;
154
185
  }
186
+ // Focus normally moves into the listbox as it opens, but it can still be
187
+ // on the trigger — the frame the dropdown mounts in, or after the user
188
+ // shift-tabs back to it. Handle navigation here too rather than dropping
189
+ // the keystroke.
190
+ handleListKeyDown(event);
155
191
  },
156
- [disabled, collapsed, open, setOpen, searchable]
192
+ [disabled, collapsed, open, setOpen, searchable, handleListKeyDown]
157
193
  );
158
194
 
159
195
  const handleSearchChange = useCallback((val: string) => {
@@ -186,6 +222,14 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
186
222
  wasOpenRef.current = open;
187
223
  }, [open, filteredOptions, searchable, selectedValues]);
188
224
 
225
+ // Non-searchable: focus the listbox itself, so arrow keys reach the scoped
226
+ // keydown handler and a screen reader follows aria-activedescendant. The
227
+ // searchable variant keeps focus in its input instead.
228
+ useEffect(() => {
229
+ if (!open || searchable) return;
230
+ listboxNode?.focus();
231
+ }, [open, searchable, listboxNode]);
232
+
189
233
  // Scroll highlighted option into view
190
234
  useEffect(() => {
191
235
  if (open && highlightedIndex >= 0) {
@@ -215,32 +259,28 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
215
259
  return () => document.removeEventListener("mousedown", handler);
216
260
  }, [open, setOpen, refs]);
217
261
 
218
- useSelectKeyboard({
219
- open,
220
- searchable,
221
- searchValue,
222
- highlightedIndex,
223
- displayOptions: filteredOptions,
224
- setOpen,
225
- setHighlightedIndex,
226
- setSearchValue,
227
- handleSelect,
228
- focusTrigger,
229
- });
230
-
231
262
  // The listbox id must be unique per instance: it is referenced by
232
263
  // aria-controls, and a hardcoded value meant two Selects on one page
233
264
  // produced duplicate ids and cross-wired ARIA.
234
265
  const listboxId = useId();
266
+ const activeOptionId = open && highlightedIndex >= 0 && highlightedIndex < filteredOptions.length ? selectOptionId(listboxId, highlightedIndex) : undefined;
235
267
 
236
268
  // Strip mode from DOM props
237
269
  const { mode: _, value: _v, defaultValue: _dv, onValueChange: _oc, ...htmlProps } = restProps as Record<string, unknown>;
238
270
 
271
+ // `role="listbox"` requires an accessible name of its own, and the trigger
272
+ // can't supply one: its label is the current *value*, and in searchable mode
273
+ // it is an input whose name would resolve to whatever has been typed. Use the
274
+ // caller's `aria-label` when there is one, else the placeholder — the closest
275
+ // thing this component has to a field label.
276
+ const listboxLabel = typeof htmlProps["aria-label"] === "string" ? (htmlProps["aria-label"] as string) : placeholder;
277
+
239
278
  return (
240
279
  <>
241
280
  {searchable && open && !collapsed ? (
242
281
  <SelectTriggerSearch
243
282
  setReference={refs.setReference}
283
+ rootRef={rootRef}
244
284
  inputRef={inputRef}
245
285
  searchValue={searchValue}
246
286
  disabled={disabled}
@@ -248,12 +288,15 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
248
288
  open={open}
249
289
  className={className}
250
290
  onSearchChange={handleSearchChange}
291
+ onKeyDown={handleListKeyDown}
251
292
  listboxId={listboxId}
293
+ activeOptionId={activeOptionId}
252
294
  props={htmlProps as React.InputHTMLAttributes<HTMLInputElement>}
253
295
  />
254
296
  ) : (
255
297
  <SelectTriggerButton
256
298
  setReference={refs.setReference}
299
+ rootRef={rootRef}
257
300
  open={open}
258
301
  disabled={disabled}
259
302
  collapsed={collapsed}
@@ -272,7 +315,9 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
272
315
  <SelectDropdown
273
316
  setFloating={refs.setFloating}
274
317
  listboxId={listboxId}
275
- listboxRef={listboxRef}
318
+ setListbox={setListbox}
319
+ label={listboxLabel}
320
+ activeOptionId={activeOptionId}
276
321
  floatingStyles={floatingStyles}
277
322
  displayOptions={filteredOptions}
278
323
  highlightedIndex={highlightedIndex}
@@ -282,8 +327,19 @@ export const Select = <T extends string = string>(props: SelectProps<T>) => {
282
327
  multiple={isMultiple}
283
328
  onSelect={handleSelect}
284
329
  onHighlight={setHighlightedIndex}
330
+ onKeyDown={handleListKeyDown}
285
331
  />
286
332
  )}
287
333
  </>
288
334
  );
289
- };
335
+ });
336
+
337
+ SelectRoot.displayName = "Select";
338
+
339
+ /**
340
+ * NOTE: Storybook shows the copy in Select.stories.tsx
341
+ * (`parameters.docs.description.component`), not this comment. react-docgen
342
+ * cannot extract a description from this declaration shape, so keeping a
343
+ * second copy here would only drift. Edit the stories file.
344
+ */
345
+ export const Select = SelectRoot as <T extends string = string>(props: SelectProps<T> & { ref?: Ref<HTMLDivElement> }) => ReactElement;
@@ -4,10 +4,22 @@ import { Check } from "lucide-react";
4
4
  import type React from "react";
5
5
  import type { WritableRefObject } from "../../internal/types";
6
6
 
7
+ /**
8
+ * Options are addressed by id, not by focus: the listbox (or the search input)
9
+ * keeps focus and points `aria-activedescendant` at the highlighted option, so
10
+ * both sides need to agree on the id.
11
+ */
12
+ export const selectOptionId = (listboxId: string, index: number) => `${listboxId}-option-${index}`;
13
+
7
14
  interface SelectDropdownProps<T extends string> {
8
15
  setFloating: (node: HTMLElement | null) => void;
9
16
  listboxId: string;
10
- listboxRef: WritableRefObject<HTMLDivElement | null>;
17
+ /** Publishes the listbox node upward — Select focuses it and scrolls it. */
18
+ setListbox: (node: HTMLDivElement | null) => void;
19
+ /** Names the listbox — a bare `role="listbox"` has no accessible name. */
20
+ label: string;
21
+ /** The highlighted option's id, or undefined when nothing is highlighted. */
22
+ activeOptionId: string | undefined;
11
23
  floatingStyles: React.CSSProperties;
12
24
  displayOptions: readonly { value: T; label: string }[];
13
25
  highlightedIndex: number;
@@ -17,12 +29,15 @@ interface SelectDropdownProps<T extends string> {
17
29
  multiple: boolean;
18
30
  onSelect: (value: T) => void;
19
31
  onHighlight: (index: number) => void;
32
+ onKeyDown: (event: React.KeyboardEvent<HTMLElement>) => void;
20
33
  }
21
34
 
22
35
  export const SelectDropdown = <T extends string>({
23
36
  setFloating,
24
37
  listboxId,
25
- listboxRef,
38
+ setListbox,
39
+ label,
40
+ activeOptionId,
26
41
  floatingStyles,
27
42
  displayOptions,
28
43
  highlightedIndex,
@@ -32,25 +47,35 @@ export const SelectDropdown = <T extends string>({
32
47
  multiple,
33
48
  onSelect,
34
49
  onHighlight,
50
+ onKeyDown,
35
51
  }: SelectDropdownProps<T>) => (
36
52
  <FloatingPortal>
37
53
  <div
38
54
  ref={(node) => {
39
55
  setFloating(node);
40
- listboxRef.current = node;
56
+ setListbox(node);
41
57
  }}
42
58
  id={listboxId}
43
59
  role="listbox"
60
+ aria-label={label}
44
61
  aria-multiselectable={multiple || undefined}
62
+ aria-activedescendant={activeOptionId}
63
+ // Focus lands here when the dropdown opens (the searchable variant keeps
64
+ // it in the input instead), which is what makes `aria-activedescendant`
65
+ // and the scoped keydown handler work.
45
66
  tabIndex={-1}
67
+ onKeyDown={onKeyDown}
46
68
  style={floatingStyles}
47
- className="z-popover max-h-60 overflow-y-auto rounded-md border border-border-normal bg-bg-normal shadow-lg"
69
+ className="select-dropdown border-(color:--select-dropdown-border) z-popover max-h-60 overflow-y-auto rounded-md border bg-(--select-dropdown-bg) shadow-lg"
48
70
  >
49
71
  {displayOptions.length === 0 ? (
50
- <div className="px-3 py-2 text-center text-fg-subtle text-sm">{searchValue ? `No results for "${searchValue}"` : "No options available"}</div>
72
+ <div className="px-3 py-2 text-center text-(--select-dropdown-empty-fg) text-sm">
73
+ {searchValue ? `No results for "${searchValue}"` : "No options available"}
74
+ </div>
51
75
  ) : (
52
76
  displayOptions.map((option, index) => {
53
77
  const isSelected = selectedValues.has(option.value);
78
+ const isHighlighted = highlightedIndex === index;
54
79
  return (
55
80
  <button
56
81
  key={option.value}
@@ -59,23 +84,31 @@ export const SelectDropdown = <T extends string>({
59
84
  else optionRefs.current.delete(index);
60
85
  }}
61
86
  type="button"
87
+ id={selectOptionId(listboxId, index)}
62
88
  role="option"
63
89
  aria-selected={isSelected}
90
+ // Surfaces the keyboard/mouse "current" option as an attribute
91
+ // the select.css recipe selects on, rather than compiling it
92
+ // straight into a class name — see select.css's header.
93
+ data-highlighted={isHighlighted ? "true" : undefined}
94
+ // The options are not tab stops and must not steal focus: the
95
+ // listbox holds it and delegates via aria-activedescendant, so a
96
+ // click that moved focus onto the option would strand the keyboard
97
+ // handler with nothing listening.
98
+ tabIndex={-1}
99
+ onMouseDown={(event) => event.preventDefault()}
64
100
  onClick={() => onSelect(option.value)}
65
101
  onMouseEnter={() => onHighlight(index)}
66
102
  className={cn(
67
- `flex w-full cursor-pointer items-center px-3 py-2 text-fg-normal text-sm transition-colors`,
103
+ `select-option flex w-full cursor-pointer items-center bg-(--select-option-bg) px-3 py-2 text-(--select-option-fg) text-sm transition-colors`,
68
104
  multiple && "gap-2",
69
- highlightedIndex === index && "bg-bg-subtle",
70
- isSelected ? "font-medium text-fg-normal" : "text-fg-subtle"
105
+ isSelected && "font-medium"
71
106
  )}
72
107
  >
73
108
  {multiple && (
74
109
  <span
75
- className={cn(
76
- "flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border",
77
- isSelected ? "border-border-brand bg-bg-brand text-fg-on-brand" : "border-border-normal"
78
- )}
110
+ data-selected={isSelected ? "true" : undefined}
111
+ className="select-option-indicator border-(color:--select-option-indicator-border) flex h-4 w-4 shrink-0 items-center justify-center rounded-xs border bg-(--select-option-indicator-bg) text-(--select-option-indicator-fg)"
79
112
  >
80
113
  {isSelected && <Check className="h-3 w-3" />}
81
114
  </span>
@@ -1,9 +1,12 @@
1
1
  import { cn } from "@sixthshift/design-system/utils";
2
2
  import { ChevronDown, X } from "lucide-react";
3
- import type { HTMLAttributes } from "react";
3
+ import type { HTMLAttributes, Ref } from "react";
4
+ import type { WritableRefObject } from "../../internal/types";
4
5
 
5
6
  interface SelectTriggerButtonProps {
6
7
  setReference: (node: HTMLElement | null) => void;
8
+ /** Consumer ref from Select, attached to this trigger's root element. */
9
+ rootRef?: Ref<HTMLDivElement>;
7
10
  listboxId: string;
8
11
  open: boolean;
9
12
  disabled: boolean;
@@ -19,6 +22,7 @@ interface SelectTriggerButtonProps {
19
22
 
20
23
  export const SelectTriggerButton = ({
21
24
  setReference,
25
+ rootRef,
22
26
  listboxId,
23
27
  open,
24
28
  disabled,
@@ -37,7 +41,7 @@ export const SelectTriggerButton = ({
37
41
  const showClear = showClearButton && !collapsed;
38
42
 
39
43
  return (
40
- <div className="relative w-full">
44
+ <div ref={rootRef} className="select-trigger relative w-full">
41
45
  <button
42
46
  ref={setReference}
43
47
  type="button"
@@ -45,7 +49,7 @@ export const SelectTriggerButton = ({
45
49
  onKeyDown={onKeyDown}
46
50
  disabled={disabled}
47
51
  className={cn(
48
- `flex w-full cursor-pointer items-center gap-2 rounded-md border border-border-normal bg-bg-normal px-3 py-2 font-medium text-fg-normal text-sm transition-colors hover:bg-bg-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50`,
52
+ `border-(color:--select-trigger-border) focus-visible:ring-(color:--select-trigger-ring) flex w-full cursor-pointer items-center gap-2 rounded-md border bg-(--select-trigger-bg) px-3 py-2 font-medium text-(--select-trigger-fg) text-sm transition-colors hover:bg-(--select-trigger-bg-hovered) focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50`,
49
53
  collapsed ? "justify-center" : "justify-between",
50
54
  showClear && "pr-9",
51
55
  className
@@ -63,7 +67,7 @@ export const SelectTriggerButton = ({
63
67
  <>
64
68
  <span className="truncate">{displayLabel}</span>
65
69
  <span className="flex shrink-0 items-center gap-1">
66
- <ChevronDown className={cn("h-4 w-4 text-fg-subtle transition-transform", open && "rotate-180")} />
70
+ <ChevronDown className={cn("h-4 w-4 text-(--select-trigger-icon-fg) transition-transform", open && "rotate-180")} />
67
71
  </span>
68
72
  </>
69
73
  )}
@@ -73,7 +77,7 @@ export const SelectTriggerButton = ({
73
77
  type="button"
74
78
  onClick={onClear}
75
79
  disabled={disabled}
76
- className="absolute top-1/2 right-8 -translate-y-1/2 rounded-sm p-0.5 text-fg-subtle hover:bg-bg-subtle hover:text-fg-normal focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
80
+ className="select-trigger-clear focus-visible:ring-(color:--select-trigger-ring) absolute top-1/2 right-8 -translate-y-1/2 rounded-sm p-0.5 text-(--select-trigger-clear-fg) hover:bg-(--select-trigger-clear-bg-hovered) hover:text-(--select-trigger-clear-fg-hovered) focus-visible:outline-none focus-visible:ring-2"
77
81
  aria-label="Clear selection"
78
82
  >
79
83
  <X className="h-3.5 w-3.5" />
@@ -85,7 +89,11 @@ export const SelectTriggerButton = ({
85
89
 
86
90
  interface SelectTriggerSearchProps {
87
91
  setReference: (node: HTMLElement | null) => void;
92
+ /** Consumer ref from Select, attached to this trigger's root element. */
93
+ rootRef?: Ref<HTMLDivElement>;
88
94
  listboxId: string;
95
+ /** Id of the highlighted option — the input keeps focus and delegates to it. */
96
+ activeOptionId: string | undefined;
89
97
  inputRef: React.RefObject<HTMLInputElement | null>;
90
98
  searchValue: string;
91
99
  disabled: boolean;
@@ -93,12 +101,15 @@ interface SelectTriggerSearchProps {
93
101
  open: boolean;
94
102
  className: string | undefined;
95
103
  onSearchChange: (value: string) => void;
104
+ onKeyDown: (event: React.KeyboardEvent<HTMLElement>) => void;
96
105
  props: React.InputHTMLAttributes<HTMLInputElement>;
97
106
  }
98
107
 
99
108
  export const SelectTriggerSearch = ({
100
109
  setReference,
110
+ rootRef,
101
111
  listboxId,
112
+ activeOptionId,
102
113
  inputRef,
103
114
  searchValue,
104
115
  disabled,
@@ -106,25 +117,37 @@ export const SelectTriggerSearch = ({
106
117
  open,
107
118
  className,
108
119
  onSearchChange,
120
+ onKeyDown,
109
121
  props,
110
122
  }: SelectTriggerSearchProps) => (
111
- <div ref={setReference} className={cn("relative flex w-full items-center", className)}>
123
+ // floating-ui anchors to this element and the consumer may also want it, so
124
+ // both refs run off one callback rather than one silently winning.
125
+ <div
126
+ ref={(node) => {
127
+ setReference(node);
128
+ if (typeof rootRef === "function") rootRef(node);
129
+ else if (rootRef) (rootRef as WritableRefObject<HTMLDivElement | null>).current = node;
130
+ }}
131
+ className={cn("select-trigger relative flex w-full items-center", className)}
132
+ >
112
133
  <input
113
134
  ref={inputRef as React.RefObject<HTMLInputElement>}
114
135
  type="text"
115
136
  value={searchValue}
116
137
  onChange={(e) => onSearchChange(e.target.value)}
138
+ onKeyDown={onKeyDown}
117
139
  placeholder={displayLabel}
118
140
  disabled={disabled}
119
141
  className={cn(
120
- `flex-1 rounded-md border border-border-normal bg-bg-normal px-3 py-2 font-medium text-fg-normal text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:cursor-not-allowed disabled:opacity-50`
142
+ `border-(color:--select-trigger-border) focus-visible:ring-(color:--select-trigger-ring) flex-1 rounded-md border bg-(--select-trigger-bg) px-3 py-2 font-medium text-(--select-trigger-fg) text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50`
121
143
  )}
122
144
  role="combobox"
123
145
  aria-expanded={open}
124
146
  aria-controls={listboxId}
147
+ aria-activedescendant={activeOptionId}
125
148
  aria-autocomplete="list"
126
149
  {...props}
127
150
  />
128
- <ChevronDown className="pointer-events-none absolute right-3 h-4 w-4 text-fg-subtle" />
151
+ <ChevronDown className="pointer-events-none absolute right-3 h-4 w-4 text-(--select-trigger-icon-fg)" />
129
152
  </div>
130
153
  );