@usefragments/ui 1.6.0 → 1.7.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 (457) hide show
  1. package/README.md +4 -4
  2. package/dist/assets/fragments-wordmark.cjs +2 -2
  3. package/dist/assets/fragments-wordmark.d.ts.map +1 -1
  4. package/dist/assets/fragments-wordmark.js +2 -2
  5. package/dist/assets/ui.css +4720 -4159
  6. package/dist/chart.cjs +24 -6
  7. package/dist/chart.js +24 -6
  8. package/dist/codeblock.cjs +55 -29
  9. package/dist/codeblock.js +55 -29
  10. package/dist/colorpicker.cjs +3 -1
  11. package/dist/colorpicker.js +3 -1
  12. package/dist/components/Accordion/Accordion.module.scss.cjs +8 -8
  13. package/dist/components/Accordion/Accordion.module.scss.js +8 -8
  14. package/dist/components/Alert/Alert.module.scss.cjs +15 -12
  15. package/dist/components/Alert/Alert.module.scss.js +15 -12
  16. package/dist/components/Alert/index.cjs +7 -1
  17. package/dist/components/Alert/index.d.ts +12 -6
  18. package/dist/components/Alert/index.d.ts.map +1 -1
  19. package/dist/components/Alert/index.js +7 -1
  20. package/dist/components/AppShell/AppShell.module.scss.cjs +14 -14
  21. package/dist/components/AppShell/AppShell.module.scss.js +14 -14
  22. package/dist/components/Avatar/Avatar.module.scss.cjs +14 -14
  23. package/dist/components/Avatar/Avatar.module.scss.js +14 -14
  24. package/dist/components/Badge/Badge.module.scss.cjs +19 -19
  25. package/dist/components/Badge/Badge.module.scss.js +19 -19
  26. package/dist/components/BentoGrid/BentoGrid.module.scss.cjs +14 -14
  27. package/dist/components/BentoGrid/BentoGrid.module.scss.js +14 -14
  28. package/dist/components/Box/Box.module.scss.cjs +152 -152
  29. package/dist/components/Box/Box.module.scss.js +152 -152
  30. package/dist/components/Box/index.cjs +64 -75
  31. package/dist/components/Box/index.d.ts +16 -16
  32. package/dist/components/Box/index.d.ts.map +1 -1
  33. package/dist/components/Box/index.js +64 -75
  34. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.cjs +8 -8
  35. package/dist/components/Breadcrumbs/Breadcrumbs.module.scss.js +8 -8
  36. package/dist/components/Button/Button.module.scss.cjs +14 -14
  37. package/dist/components/Button/Button.module.scss.js +14 -14
  38. package/dist/components/Card/Card.module.scss.cjs +29 -17
  39. package/dist/components/Card/Card.module.scss.js +30 -18
  40. package/dist/components/Card/index.cjs +8 -0
  41. package/dist/components/Card/index.d.ts +12 -2
  42. package/dist/components/Card/index.d.ts.map +1 -1
  43. package/dist/components/Card/index.js +8 -0
  44. package/dist/components/Chart/Chart.module.scss.cjs +15 -15
  45. package/dist/components/Chart/Chart.module.scss.js +15 -15
  46. package/dist/components/Chart/index.d.ts.map +1 -1
  47. package/dist/components/Checkbox/Checkbox.module.scss.cjs +9 -9
  48. package/dist/components/Checkbox/Checkbox.module.scss.js +9 -9
  49. package/dist/components/Checkbox/index.cjs +2 -2
  50. package/dist/components/Checkbox/index.d.ts.map +1 -1
  51. package/dist/components/Checkbox/index.js +2 -2
  52. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  53. package/dist/components/Chip/Chip.module.scss.js +15 -15
  54. package/dist/components/Chip/index.cjs +2 -1
  55. package/dist/components/Chip/index.d.ts.map +1 -1
  56. package/dist/components/Chip/index.js +2 -1
  57. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +26 -23
  58. package/dist/components/CodeBlock/CodeBlock.module.scss.js +26 -23
  59. package/dist/components/CodeBlock/css-variables-theme.cjs +98 -0
  60. package/dist/components/CodeBlock/css-variables-theme.d.ts +27 -0
  61. package/dist/components/CodeBlock/css-variables-theme.d.ts.map +1 -0
  62. package/dist/components/CodeBlock/css-variables-theme.js +98 -0
  63. package/dist/components/CodeBlock/index.d.ts +17 -3
  64. package/dist/components/CodeBlock/index.d.ts.map +1 -1
  65. package/dist/components/Collapsible/Collapsible.module.scss.cjs +9 -9
  66. package/dist/components/Collapsible/Collapsible.module.scss.js +9 -9
  67. package/dist/components/ColorPicker/ColorPicker.module.scss.cjs +14 -14
  68. package/dist/components/ColorPicker/ColorPicker.module.scss.js +14 -14
  69. package/dist/components/ColorPicker/index.d.ts.map +1 -1
  70. package/dist/components/Combobox/Combobox.module.scss.cjs +21 -21
  71. package/dist/components/Combobox/Combobox.module.scss.js +21 -21
  72. package/dist/components/Combobox/index.cjs +17 -1
  73. package/dist/components/Combobox/index.d.ts.map +1 -1
  74. package/dist/components/Combobox/index.js +17 -1
  75. package/dist/components/Command/Command.module.scss.cjs +11 -11
  76. package/dist/components/Command/Command.module.scss.js +11 -11
  77. package/dist/components/Command/index.cjs +26 -15
  78. package/dist/components/Command/index.d.ts +2 -2
  79. package/dist/components/Command/index.d.ts.map +1 -1
  80. package/dist/components/Command/index.js +26 -15
  81. package/dist/components/ConversationList/ConversationList.module.scss.cjs +10 -10
  82. package/dist/components/ConversationList/ConversationList.module.scss.js +10 -10
  83. package/dist/components/DataTable/DataTable.icons.cjs +6 -33
  84. package/dist/components/DataTable/DataTable.icons.d.ts.map +1 -1
  85. package/dist/components/DataTable/DataTable.icons.js +6 -33
  86. package/dist/components/DataTable/DataTable.module.scss.cjs +27 -27
  87. package/dist/components/DataTable/DataTable.module.scss.js +27 -27
  88. package/dist/components/DataTable/index.d.ts.map +1 -1
  89. package/dist/components/DatePicker/DatePicker.module.scss.cjs +33 -33
  90. package/dist/components/DatePicker/DatePicker.module.scss.js +33 -33
  91. package/dist/components/DatePicker/index.d.ts.map +1 -1
  92. package/dist/components/Dialog/Dialog.module.scss.cjs +14 -14
  93. package/dist/components/Dialog/Dialog.module.scss.js +14 -14
  94. package/dist/components/Dialog/index.cjs +11 -14
  95. package/dist/components/Dialog/index.d.ts +7 -7
  96. package/dist/components/Dialog/index.d.ts.map +1 -1
  97. package/dist/components/Dialog/index.js +11 -14
  98. package/dist/components/Drawer/Drawer.module.scss.cjs +29 -29
  99. package/dist/components/Drawer/Drawer.module.scss.js +29 -29
  100. package/dist/components/Editor/Editor.module.scss.cjs +17 -17
  101. package/dist/components/Editor/Editor.module.scss.js +17 -17
  102. package/dist/components/Editor/index.d.ts +10 -10
  103. package/dist/components/Editor/index.d.ts.map +1 -1
  104. package/dist/components/EmptyState/EmptyState.module.scss.cjs +11 -8
  105. package/dist/components/EmptyState/EmptyState.module.scss.js +11 -8
  106. package/dist/components/EmptyState/index.cjs +8 -6
  107. package/dist/components/EmptyState/index.d.ts +9 -4
  108. package/dist/components/EmptyState/index.d.ts.map +1 -1
  109. package/dist/components/EmptyState/index.js +8 -6
  110. package/dist/components/Field/Field.module.scss.cjs +5 -5
  111. package/dist/components/Field/Field.module.scss.js +5 -5
  112. package/dist/components/Field/index.cjs +9 -1
  113. package/dist/components/Field/index.d.ts.map +1 -1
  114. package/dist/components/Field/index.js +9 -1
  115. package/dist/components/Fieldset/Fieldset.module.scss.cjs +3 -3
  116. package/dist/components/Fieldset/Fieldset.module.scss.js +3 -3
  117. package/dist/components/Grid/index.cjs +1 -1
  118. package/dist/components/Grid/index.js +1 -1
  119. package/dist/components/Header/Header.module.scss.cjs +33 -33
  120. package/dist/components/Header/Header.module.scss.js +33 -33
  121. package/dist/components/Header/index.cjs +17 -38
  122. package/dist/components/Header/index.d.ts +15 -11
  123. package/dist/components/Header/index.d.ts.map +1 -1
  124. package/dist/components/Header/index.js +17 -38
  125. package/dist/components/Icon/Icon.module.scss.cjs +15 -15
  126. package/dist/components/Icon/Icon.module.scss.js +15 -15
  127. package/dist/components/IconButton/IconButton.module.scss.cjs +8 -8
  128. package/dist/components/IconButton/IconButton.module.scss.js +8 -8
  129. package/dist/components/IconButton/index.cjs +2 -1
  130. package/dist/components/IconButton/index.d.ts.map +1 -1
  131. package/dist/components/IconButton/index.js +2 -1
  132. package/dist/components/Image/Image.module.scss.cjs +27 -27
  133. package/dist/components/Image/Image.module.scss.js +27 -27
  134. package/dist/components/Input/Input.module.scss.cjs +17 -17
  135. package/dist/components/Input/Input.module.scss.js +17 -17
  136. package/dist/components/Link/Link.module.scss.cjs +14 -10
  137. package/dist/components/Link/Link.module.scss.js +14 -10
  138. package/dist/components/Link/index.d.ts +1 -1
  139. package/dist/components/Link/index.d.ts.map +1 -1
  140. package/dist/components/List/List.module.scss.cjs +19 -19
  141. package/dist/components/List/List.module.scss.js +19 -19
  142. package/dist/components/Listbox/Listbox.module.scss.cjs +8 -8
  143. package/dist/components/Listbox/Listbox.module.scss.js +8 -8
  144. package/dist/components/Loading/Loading.module.scss.cjs +34 -34
  145. package/dist/components/Loading/Loading.module.scss.js +34 -34
  146. package/dist/components/Loading/index.cjs +1 -1
  147. package/dist/components/Loading/index.js +1 -1
  148. package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
  149. package/dist/components/Markdown/Markdown.module.scss.js +1 -1
  150. package/dist/components/Markdown/index.d.ts +2 -2
  151. package/dist/components/Markdown/index.d.ts.map +1 -1
  152. package/dist/components/Menu/Menu.module.scss.cjs +14 -14
  153. package/dist/components/Menu/Menu.module.scss.js +14 -14
  154. package/dist/components/Message/Message.module.scss.cjs +18 -18
  155. package/dist/components/Message/Message.module.scss.js +18 -18
  156. package/dist/components/NavigationMenu/NavigationMenu.module.scss.cjs +34 -31
  157. package/dist/components/NavigationMenu/NavigationMenu.module.scss.js +34 -31
  158. package/dist/components/NavigationMenu/index.cjs +32 -15
  159. package/dist/components/NavigationMenu/index.d.ts +12 -6
  160. package/dist/components/NavigationMenu/index.d.ts.map +1 -1
  161. package/dist/components/NavigationMenu/index.js +32 -15
  162. package/dist/components/Pagination/Pagination.module.scss.cjs +10 -10
  163. package/dist/components/Pagination/Pagination.module.scss.js +10 -10
  164. package/dist/components/Popover/Popover.module.scss.cjs +10 -10
  165. package/dist/components/Popover/Popover.module.scss.js +10 -10
  166. package/dist/components/Progress/Progress.module.scss.cjs +25 -25
  167. package/dist/components/Progress/Progress.module.scss.js +25 -25
  168. package/dist/components/Prompt/Prompt.module.scss.cjs +28 -28
  169. package/dist/components/Prompt/Prompt.module.scss.js +28 -28
  170. package/dist/components/RadioGroup/RadioGroup.module.scss.cjs +15 -15
  171. package/dist/components/RadioGroup/RadioGroup.module.scss.js +15 -15
  172. package/dist/components/ScrollArea/ScrollArea.module.scss.cjs +5 -5
  173. package/dist/components/ScrollArea/ScrollArea.module.scss.js +5 -5
  174. package/dist/components/ScrollArea/index.d.ts +4 -4
  175. package/dist/components/ScrollArea/index.d.ts.map +1 -1
  176. package/dist/components/ScrollArea/scroll-state.d.ts +5 -5
  177. package/dist/components/Select/Select.module.scss.cjs +21 -21
  178. package/dist/components/Select/Select.module.scss.js +21 -21
  179. package/dist/components/Separator/Separator.module.scss.cjs +11 -11
  180. package/dist/components/Separator/Separator.module.scss.js +11 -11
  181. package/dist/components/Sidebar/Sidebar.module.scss.cjs +43 -43
  182. package/dist/components/Sidebar/Sidebar.module.scss.js +43 -43
  183. package/dist/components/Sidebar/index.cjs +12 -35
  184. package/dist/components/Sidebar/index.d.ts +19 -19
  185. package/dist/components/Sidebar/index.d.ts.map +1 -1
  186. package/dist/components/Sidebar/index.js +12 -35
  187. package/dist/components/Skeleton/Skeleton.module.scss.cjs +50 -46
  188. package/dist/components/Skeleton/Skeleton.module.scss.js +50 -46
  189. package/dist/components/Slider/Slider.module.scss.cjs +12 -12
  190. package/dist/components/Slider/Slider.module.scss.js +12 -12
  191. package/dist/components/Stack/Stack.module.scss.cjs +25 -25
  192. package/dist/components/Stack/Stack.module.scss.js +25 -25
  193. package/dist/components/Stack/index.cjs +1 -1
  194. package/dist/components/Stack/index.js +1 -1
  195. package/dist/components/Switch/Switch.module.scss.cjs +9 -9
  196. package/dist/components/Switch/Switch.module.scss.js +9 -9
  197. package/dist/components/Table/Table.module.scss.cjs +19 -19
  198. package/dist/components/Table/Table.module.scss.js +19 -19
  199. package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +15 -15
  200. package/dist/components/TableOfContents/TableOfContents.module.scss.js +15 -15
  201. package/dist/components/TableOfContents/index.cjs +13 -9
  202. package/dist/components/TableOfContents/index.d.ts +5 -3
  203. package/dist/components/TableOfContents/index.d.ts.map +1 -1
  204. package/dist/components/TableOfContents/index.js +13 -9
  205. package/dist/components/Tabs/Tabs.module.scss.cjs +12 -12
  206. package/dist/components/Tabs/Tabs.module.scss.js +12 -12
  207. package/dist/components/Tabs/index.cjs +26 -6
  208. package/dist/components/Tabs/index.d.ts.map +1 -1
  209. package/dist/components/Tabs/index.js +26 -6
  210. package/dist/components/Text/Text.module.scss.cjs +87 -75
  211. package/dist/components/Text/Text.module.scss.js +87 -75
  212. package/dist/components/Text/index.cjs +49 -41
  213. package/dist/components/Text/index.d.ts +12 -11
  214. package/dist/components/Text/index.d.ts.map +1 -1
  215. package/dist/components/Text/index.js +49 -41
  216. package/dist/components/Textarea/Textarea.module.scss.cjs +24 -24
  217. package/dist/components/Textarea/Textarea.module.scss.js +24 -24
  218. package/dist/components/Theme/index.cjs +2 -1
  219. package/dist/components/Theme/index.d.ts.map +1 -1
  220. package/dist/components/Theme/index.js +2 -1
  221. package/dist/components/ThemeToggle/ThemeToggle.module.scss.cjs +9 -6
  222. package/dist/components/ThemeToggle/ThemeToggle.module.scss.js +9 -6
  223. package/dist/components/ThemeToggle/index.cjs +31 -6
  224. package/dist/components/ThemeToggle/index.d.ts +7 -2
  225. package/dist/components/ThemeToggle/index.d.ts.map +1 -1
  226. package/dist/components/ThemeToggle/index.js +32 -7
  227. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.cjs +13 -13
  228. package/dist/components/ThinkingIndicator/ThinkingIndicator.module.scss.js +13 -13
  229. package/dist/components/Toast/Toast.module.scss.cjs +20 -20
  230. package/dist/components/Toast/Toast.module.scss.js +20 -20
  231. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +17 -17
  232. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +17 -17
  233. package/dist/components/Tooltip/Tooltip.module.scss.cjs +3 -3
  234. package/dist/components/Tooltip/Tooltip.module.scss.js +3 -3
  235. package/dist/components/Tooltip/index.cjs +24 -40
  236. package/dist/components/Tooltip/index.d.ts +4 -4
  237. package/dist/components/Tooltip/index.d.ts.map +1 -1
  238. package/dist/components/Tooltip/index.js +24 -40
  239. package/dist/components/VisuallyHidden/index.d.ts +2 -2
  240. package/dist/data-table.cjs +2 -1
  241. package/dist/data-table.js +2 -1
  242. package/dist/datepicker.cjs +3 -2
  243. package/dist/datepicker.js +3 -2
  244. package/dist/editor.cjs +68 -28
  245. package/dist/editor.js +68 -28
  246. package/dist/index.cjs +1 -1
  247. package/dist/index.d.ts +1 -1
  248. package/dist/index.d.ts.map +1 -1
  249. package/dist/index.js +2 -2
  250. package/dist/markdown.cjs +21 -29
  251. package/dist/markdown.js +21 -29
  252. package/dist/measurements/generated.cjs +9 -1
  253. package/dist/measurements/generated.d.ts +7 -0
  254. package/dist/measurements/generated.d.ts.map +1 -1
  255. package/dist/measurements/generated.js +9 -1
  256. package/dist/utils/a11y.cjs +5 -2
  257. package/dist/utils/a11y.d.ts +5 -5
  258. package/dist/utils/a11y.d.ts.map +1 -1
  259. package/dist/utils/a11y.js +5 -2
  260. package/dist/utils/canonical-stamp.cjs +2 -8
  261. package/dist/utils/canonical-stamp.d.ts.map +1 -1
  262. package/dist/utils/canonical-stamp.js +1 -7
  263. package/dist/utils/css-warning.cjs +1 -1
  264. package/dist/utils/css-warning.js +1 -1
  265. package/dist/utils/env.cjs +17 -0
  266. package/dist/utils/env.d.ts +3 -0
  267. package/dist/utils/env.d.ts.map +1 -0
  268. package/dist/utils/env.js +17 -0
  269. package/dist/utils/keyboard-shortcuts.cjs +3 -10
  270. package/dist/utils/keyboard-shortcuts.d.ts +4 -4
  271. package/dist/utils/keyboard-shortcuts.d.ts.map +1 -1
  272. package/dist/utils/keyboard-shortcuts.js +3 -10
  273. package/dist/utils/seed-derivation.cjs +10 -6
  274. package/dist/utils/seed-derivation.d.ts.map +1 -1
  275. package/dist/utils/seed-derivation.js +10 -6
  276. package/fragments.json +1 -1
  277. package/package.json +6 -4
  278. package/src/assets/fragments-logo.tsx +2 -2
  279. package/src/assets/fragments-wordmark.tsx +4 -2
  280. package/src/components/Accordion/Accordion.contract.json +24 -48
  281. package/src/components/Alert/Alert.contract.json +37 -53
  282. package/src/components/Alert/Alert.module.scss +24 -0
  283. package/src/components/Alert/index.tsx +55 -29
  284. package/src/components/AppShell/AppShell.contract.json +34 -51
  285. package/src/components/AppShell/AppShell.module.scss +53 -40
  286. package/src/components/Avatar/Avatar.contract.json +31 -48
  287. package/src/components/Avatar/Avatar.module.scss +4 -1
  288. package/src/components/Badge/Badge.contract.json +37 -42
  289. package/src/components/Badge/Badge.module.scss +9 -2
  290. package/src/components/BentoGrid/BentoGrid.contract.json +21 -45
  291. package/src/components/Box/Box.contract.json +40 -148
  292. package/src/components/Box/index.tsx +92 -99
  293. package/src/components/Breadcrumbs/Breadcrumbs.contract.json +21 -34
  294. package/src/components/Breadcrumbs/Breadcrumbs.module.scss +12 -7
  295. package/src/components/Button/Button.module.scss +8 -7
  296. package/src/components/ButtonGroup/ButtonGroup.contract.json +32 -47
  297. package/src/components/Card/Card.module.scss +82 -1
  298. package/src/components/Card/index.tsx +21 -2
  299. package/src/components/Chart/Chart.contract.json +21 -29
  300. package/src/components/Chart/index.tsx +36 -6
  301. package/src/components/Checkbox/Checkbox.contract.json +24 -24
  302. package/src/components/Checkbox/Checkbox.module.scss +32 -23
  303. package/src/components/Checkbox/index.tsx +4 -2
  304. package/src/components/Chip/Chip.contract.json +33 -40
  305. package/src/components/Chip/Chip.module.scss +2 -2
  306. package/src/components/Chip/index.tsx +2 -1
  307. package/src/components/CodeBlock/CodeBlock.contract.json +46 -76
  308. package/src/components/CodeBlock/CodeBlock.module.scss +40 -15
  309. package/src/components/CodeBlock/css-variables-theme.ts +102 -0
  310. package/src/components/CodeBlock/index.tsx +91 -35
  311. package/src/components/Collapsible/Collapsible.contract.json +21 -36
  312. package/src/components/ColorPicker/ColorPicker.contract.json +29 -48
  313. package/src/components/ColorPicker/ColorPicker.module.scss +15 -12
  314. package/src/components/ColorPicker/index.tsx +5 -1
  315. package/src/components/Combobox/Combobox.contract.json +36 -37
  316. package/src/components/Combobox/Combobox.module.scss +1 -1
  317. package/src/components/Combobox/index.tsx +31 -5
  318. package/src/components/Command/Command.contract.json +21 -43
  319. package/src/components/Command/index.tsx +58 -47
  320. package/src/components/ConversationList/ConversationList.contract.json +27 -32
  321. package/src/components/DataTable/DataTable.icons.tsx +4 -21
  322. package/src/components/DataTable/DataTable.module.scss +12 -8
  323. package/src/components/DataTable/index.tsx +8 -7
  324. package/src/components/DatePicker/DatePicker.contract.json +27 -28
  325. package/src/components/DatePicker/DatePicker.module.scss +12 -5
  326. package/src/components/DatePicker/index.tsx +5 -2
  327. package/src/components/Dialog/Dialog.module.scss +3 -3
  328. package/src/components/Dialog/index.tsx +47 -37
  329. package/src/components/Drawer/Drawer.contract.json +22 -36
  330. package/src/components/Editor/Editor.contract.json +31 -48
  331. package/src/components/Editor/Editor.module.scss +36 -14
  332. package/src/components/Editor/index.tsx +240 -179
  333. package/src/components/EmptyState/EmptyState.contract.json +31 -43
  334. package/src/components/EmptyState/EmptyState.module.scss +8 -0
  335. package/src/components/EmptyState/index.tsx +48 -23
  336. package/src/components/Field/Field.contract.json +28 -46
  337. package/src/components/Field/index.tsx +5 -1
  338. package/src/components/Fieldset/Fieldset.contract.json +21 -38
  339. package/src/components/Fieldset/Fieldset.module.scss +10 -3
  340. package/src/components/Form/Form.contract.json +20 -20
  341. package/src/components/Grid/Grid.contract.json +28 -64
  342. package/src/components/Grid/index.tsx +10 -10
  343. package/src/components/Header/Header.contract.json +31 -67
  344. package/src/components/Header/Header.module.scss +36 -21
  345. package/src/components/Header/index.tsx +134 -122
  346. package/src/components/Icon/Icon.contract.json +22 -62
  347. package/src/components/IconButton/IconButton.contract.json +34 -18
  348. package/src/components/IconButton/IconButton.module.scss +6 -7
  349. package/src/components/IconButton/index.tsx +2 -1
  350. package/src/components/Image/Image.contract.json +23 -56
  351. package/src/components/Input/Input.contract.json +26 -32
  352. package/src/components/Input/Input.module.scss +3 -2
  353. package/src/components/Link/Link.contract.json +32 -52
  354. package/src/components/Link/Link.module.scss +23 -6
  355. package/src/components/Link/index.tsx +1 -1
  356. package/src/components/List/List.contract.json +23 -52
  357. package/src/components/List/List.module.scss +1 -1
  358. package/src/components/Listbox/Listbox.contract.json +21 -37
  359. package/src/components/Loading/Loading.contract.json +37 -61
  360. package/src/components/Loading/Loading.module.scss +10 -7
  361. package/src/components/Loading/index.tsx +2 -2
  362. package/src/components/Main/Main.contract.json +17 -9
  363. package/src/components/Markdown/Markdown.contract.json +22 -43
  364. package/src/components/Markdown/Markdown.module.scss +43 -5
  365. package/src/components/Markdown/index.tsx +48 -49
  366. package/src/components/Menu/Menu.contract.json +25 -41
  367. package/src/components/Menu/Menu.module.scss +23 -8
  368. package/src/components/Message/Message.contract.json +29 -52
  369. package/src/components/Message/Message.module.scss +12 -5
  370. package/src/components/NavigationMenu/NavigationMenu.contract.json +36 -45
  371. package/src/components/NavigationMenu/NavigationMenu.module.scss +64 -19
  372. package/src/components/NavigationMenu/index.tsx +105 -81
  373. package/src/components/Pagination/Pagination.contract.json +22 -40
  374. package/src/components/Pagination/Pagination.module.scss +2 -2
  375. package/src/components/Popover/Popover.contract.json +24 -46
  376. package/src/components/Popover/Popover.module.scss +6 -5
  377. package/src/components/Progress/Progress.contract.json +32 -28
  378. package/src/components/Progress/Progress.module.scss +3 -2
  379. package/src/components/Prompt/Prompt.contract.json +31 -47
  380. package/src/components/Prompt/Prompt.module.scss +13 -5
  381. package/src/components/RadioGroup/RadioGroup.contract.json +23 -24
  382. package/src/components/RadioGroup/RadioGroup.module.scss +13 -14
  383. package/src/components/ScrollArea/ScrollArea.contract.json +18 -19
  384. package/src/components/ScrollArea/ScrollArea.module.scss +15 -15
  385. package/src/components/ScrollArea/index.tsx +16 -16
  386. package/src/components/ScrollArea/scroll-state.ts +24 -24
  387. package/src/components/Select/Select.module.scss +2 -2
  388. package/src/components/Separator/Separator.contract.json +24 -48
  389. package/src/components/Sidebar/Sidebar.contract.json +35 -67
  390. package/src/components/Sidebar/Sidebar.module.scss +22 -13
  391. package/src/components/Sidebar/index.tsx +164 -164
  392. package/src/components/Skeleton/Skeleton.contract.json +28 -54
  393. package/src/components/Skeleton/Skeleton.module.scss +27 -10
  394. package/src/components/Slider/Slider.contract.json +27 -39
  395. package/src/components/Slider/Slider.module.scss +3 -3
  396. package/src/components/Stack/Stack.contract.json +29 -56
  397. package/src/components/Stack/Stack.module.scss +13 -12
  398. package/src/components/Stack/index.tsx +3 -3
  399. package/src/components/Switch/Switch.contract.json +33 -46
  400. package/src/components/Switch/Switch.module.scss +64 -26
  401. package/src/components/Table/Table.contract.json +28 -46
  402. package/src/components/Table/Table.module.scss +15 -3
  403. package/src/components/TableOfContents/TableOfContents.contract.json +34 -21
  404. package/src/components/TableOfContents/TableOfContents.module.scss +15 -5
  405. package/src/components/TableOfContents/index.tsx +26 -9
  406. package/src/components/Tabs/Tabs.contract.json +24 -45
  407. package/src/components/Tabs/Tabs.module.scss +1 -1
  408. package/src/components/Tabs/index.tsx +15 -3
  409. package/src/components/Text/Text.contract.json +30 -72
  410. package/src/components/Text/Text.module.scss +21 -4
  411. package/src/components/Text/index.tsx +113 -75
  412. package/src/components/Textarea/Textarea.contract.json +25 -43
  413. package/src/components/Textarea/Textarea.module.scss +2 -4
  414. package/src/components/Theme/Theme.contract.json +32 -51
  415. package/src/components/Theme/index.tsx +2 -1
  416. package/src/components/ThemeToggle/ThemeToggle.module.scss +23 -7
  417. package/src/components/ThemeToggle/index.tsx +43 -7
  418. package/src/components/ThinkingIndicator/ThinkingIndicator.contract.json +23 -40
  419. package/src/components/Toast/Toast.contract.json +30 -40
  420. package/src/components/Toast/Toast.module.scss +1 -1
  421. package/src/components/ToggleGroup/ToggleGroup.contract.json +29 -30
  422. package/src/components/ToggleGroup/ToggleGroup.module.scss +38 -5
  423. package/src/components/Tooltip/Tooltip.contract.json +31 -52
  424. package/src/components/Tooltip/index.tsx +19 -24
  425. package/src/components/VisuallyHidden/VisuallyHidden.contract.json +22 -44
  426. package/src/components/VisuallyHidden/index.tsx +5 -5
  427. package/src/index.ts +2 -2
  428. package/src/measurements/generated.ts +9 -2
  429. package/src/measurements/measurements.json +7 -0
  430. package/src/recipes/_boolean-range.scss +3 -11
  431. package/src/recipes/_field.scss +5 -1
  432. package/src/recipes/_layout.scss +14 -7
  433. package/src/recipes/_popup.scss +12 -2
  434. package/src/recipes/_prose.scss +13 -5
  435. package/src/recipes/_table-chrome.scss +16 -2
  436. package/src/scss.d.ts +1 -1
  437. package/src/styles/globals.scss +20 -19
  438. package/src/tokens/_computed.scss +5 -16
  439. package/src/tokens/_derive.scss +112 -210
  440. package/src/tokens/_measurements.catalog.generated.css +6 -1
  441. package/src/tokens/_measurements.generated.scss +14 -1
  442. package/src/tokens/_mixins.scss +7 -8
  443. package/src/tokens/_palettes.scss +39 -167
  444. package/src/tokens/_seeds.scss +20 -20
  445. package/src/tokens/_variables.scss +183 -38
  446. package/src/utils/a11y.tsx +69 -69
  447. package/src/utils/aria.ts +3 -3
  448. package/src/utils/canonical-stamp.ts +2 -12
  449. package/src/utils/css-warning.ts +7 -7
  450. package/src/utils/env.ts +25 -0
  451. package/src/utils/keyboard-shortcuts.ts +131 -126
  452. package/src/utils/seed-derivation.ts +10 -6
  453. package/src/components/Button/Button.contract.json +0 -218
  454. package/src/components/Card/Card.contract.json +0 -175
  455. package/src/components/DataTable/DataTable.contract.json +0 -302
  456. package/src/components/Dialog/Dialog.contract.json +0 -159
  457. package/src/components/Select/Select.contract.json +0 -259
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
3
  "name": "Combobox",
4
- "description": "Searchable select input that filters a dropdown list of options as you type. Supports single and multiple selection with chips.",
5
- "category": "forms",
4
+ "description": "Filters a list of options as the user types.",
5
+ "category": "inputs",
6
6
  "tags": ["combobox", "autocomplete", "search", "select", "typeahead", "form", "multiselect"],
7
7
  "status": "stable",
8
8
  "sourcePath": "src/components/Combobox/index.tsx",
@@ -133,86 +133,85 @@
133
133
  },
134
134
  "usage": {
135
135
  "when": [
136
- "Users need to search/filter through many options",
137
- "Large option lists where scrolling is impractical",
138
- "When users might know what they are looking for",
139
- "Autocomplete or typeahead functionality",
140
- "Multiple selections from a searchable list"
136
+ "Lists too long to scan by eye",
137
+ "The user roughly knows the value they want",
138
+ "Autocomplete or typeahead",
139
+ "Multi-select from a searchable list"
141
140
  ],
142
141
  "whenNot": [
143
- "Few options (under 5) - use Select or RadioGroup",
144
- "Free-form text with no predefined options - use Input",
145
- "Non-searchable single selection - use Select",
146
- "Actions, not selection - use Menu"
142
+ "Under five options (use Select or RadioGroup)",
143
+ "Free-form text with no known options (use Input)",
144
+ "Short list nobody needs to search (use Select)",
145
+ "Actions rather than values (use Menu)"
147
146
  ],
148
147
  "guidelines": [
149
- "Include a placeholder that explains what to search for",
150
- "Use label prop for accessible field labeling",
151
- "Use helperText for guidance and error for validation messages",
152
- "Provide an empty state message when no results match",
153
- "Group related options with Combobox.Group for large lists",
154
- "Static items may be composed through fragments and groups; filtering preserves wrapper composition",
155
- "Keep option text concise and searchable",
156
- "Use multiple prop for multi-select with chip display"
148
+ "Placeholder names what is searchable",
149
+ "Set label so the field is announced",
150
+ "helperText for guidance, error for the failure reason",
151
+ "Override the built-in \"No results found\" with Combobox.Empty when you have better wording",
152
+ "Group related options with Combobox.Group in long lists",
153
+ "Filtering keeps wrapper composition, so groups and fragments survive",
154
+ "Keep option text short and searchable",
155
+ "multiple turns selections into removable chips"
157
156
  ],
158
157
  "accessibility": [
159
- "Full keyboard navigation support (arrow keys, enter, escape)",
160
- "Type-ahead filtering within options",
161
- "Proper ARIA combobox roles and attributes",
162
- "Screen reader announcements for filtered results",
163
- "Chip removal via keyboard in multi-select mode"
158
+ "Arrow keys, Enter, and Escape all work",
159
+ "Typing filters the list in place",
160
+ "Correct ARIA combobox roles and attributes",
161
+ "Filtered result counts are announced",
162
+ "Chips can be removed from the keyboard"
164
163
  ]
165
164
  },
166
165
  "examples": [
167
166
  {
168
167
  "name": "Default",
169
- "description": "Basic searchable select",
168
+ "description": "Type to narrow the list; unmatched queries show a no-results row.",
170
169
  "code": "<StatefulCombobox placeholder=\"Select a fruit\">\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Item value=\"apple\">Apple</Combobox.Item>\n <Combobox.Item value=\"banana\">Banana</Combobox.Item>\n <Combobox.Item value=\"orange\">Orange</Combobox.Item>\n <Combobox.Item value=\"grape\">Grape</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
171
170
  },
172
171
  {
173
172
  "name": "Multiple Selection",
174
- "description": "Multi-select with chips",
173
+ "description": "Each pick becomes a removable chip in the field.",
175
174
  "code": "<StatefulCombobox multiple placeholder=\"Select fruits...\">\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Item value=\"apple\">Apple</Combobox.Item>\n <Combobox.Item value=\"banana\">Banana</Combobox.Item>\n <Combobox.Item value=\"orange\">Orange</Combobox.Item>\n <Combobox.Item value=\"grape\">Grape</Combobox.Item>\n <Combobox.Item value=\"mango\">Mango</Combobox.Item>\n <Combobox.Item value=\"kiwi\">Kiwi</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
176
175
  },
177
176
  {
178
177
  "name": "With Label and Helper Text",
179
- "description": "Combobox with built-in label and helper text",
178
+ "description": "Helper text tells the user the field is searchable.",
180
179
  "code": "<StatefulCombobox\n label=\"Assignee\"\n placeholder=\"Search assignees...\"\n helperText=\"Type to filter the list of available assignees.\"\n>\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Empty>No matches</Combobox.Empty>\n <Combobox.Item value=\"alice\">Alice Johnson</Combobox.Item>\n <Combobox.Item value=\"bob\">Bob Chen</Combobox.Item>\n <Combobox.Item value=\"carol\">Carol Smith</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
181
180
  },
182
181
  {
183
182
  "name": "Error State",
184
- "description": "Validation error with message",
185
- "code": "<Combobox\n label=\"Reviewer\"\n placeholder=\"Search reviewers...\"\n error=\"Please select a reviewer\"\n disabled\n>\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Item value=\"alice\">Alice</Combobox.Item>\n </Combobox.Content>\n</Combobox>"
183
+ "description": "Red border, and the message replaces helper text.",
184
+ "code": "<Combobox\n label=\"Reviewer\"\n placeholder=\"Search reviewers...\"\n error=\"Please select a reviewer\"\n>\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Item value=\"alice\">Alice</Combobox.Item>\n </Combobox.Content>\n</Combobox>"
186
185
  },
187
186
  {
188
187
  "name": "With Groups",
189
- "description": "Options organized into groups",
188
+ "description": "Headed sections stay intact while filtering.",
190
189
  "code": "<StatefulCombobox placeholder=\"Search countries...\">\n <Combobox.Input />\n <Combobox.Content>\n <>\n <Combobox.Group>\n <Combobox.GroupLabel>North America</Combobox.GroupLabel>\n <Combobox.Item value=\"us\">United States</Combobox.Item>\n <Combobox.Item value=\"ca\">Canada</Combobox.Item>\n <Combobox.Item value=\"mx\">Mexico</Combobox.Item>\n </Combobox.Group>\n <Combobox.Group>\n <Combobox.GroupLabel>Europe</Combobox.GroupLabel>\n <Combobox.Item value=\"uk\">United Kingdom</Combobox.Item>\n <Combobox.Item value=\"de\">Germany</Combobox.Item>\n <Combobox.Item value=\"fr\">France</Combobox.Item>\n </Combobox.Group>\n <Combobox.Empty>No matching country</Combobox.Empty>\n </>\n </Combobox.Content>\n</StatefulCombobox>"
191
190
  },
192
191
  {
193
192
  "name": "With Empty State",
194
- "description": "Shows message when no results match",
195
- "code": "<StatefulCombobox placeholder=\"Search programming languages...\">\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Empty>No results found</Combobox.Empty>\n <Combobox.Item value=\"js\">JavaScript</Combobox.Item>\n <Combobox.Item value=\"ts\">TypeScript</Combobox.Item>\n <Combobox.Item value=\"py\">Python</Combobox.Item>\n <Combobox.Item value=\"rs\">Rust</Combobox.Item>\n <Combobox.Item value=\"go\">Go</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
193
+ "description": "Combobox.Empty replaces the default no-results wording.",
194
+ "code": "<StatefulCombobox placeholder=\"Filter languages...\">\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Empty>No language matches that search</Combobox.Empty>\n <Combobox.Item value=\"js\">JavaScript</Combobox.Item>\n <Combobox.Item value=\"ts\">TypeScript</Combobox.Item>\n <Combobox.Item value=\"py\">Python</Combobox.Item>\n <Combobox.Item value=\"rs\">Rust</Combobox.Item>\n <Combobox.Item value=\"go\">Go</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
196
195
  },
197
196
  {
198
197
  "name": "Scrollable List",
199
- "description": "Long list with scroll hint shows 4 items with half-peek of the 5th",
198
+ "description": "Caps at four rows and half-shows the fifth as a scroll hint.",
200
199
  "code": "<StatefulCombobox placeholder=\"Search languages...\">\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Empty>No results found</Combobox.Empty>\n <Combobox.Item value=\"js\">JavaScript</Combobox.Item>\n <Combobox.Item value=\"ts\">TypeScript</Combobox.Item>\n <Combobox.Item value=\"py\">Python</Combobox.Item>\n <Combobox.Item value=\"rs\">Rust</Combobox.Item>\n <Combobox.Item value=\"go\">Go</Combobox.Item>\n <Combobox.Item value=\"rb\">Ruby</Combobox.Item>\n <Combobox.Item value=\"java\">Java</Combobox.Item>\n <Combobox.Item value=\"swift\">Swift</Combobox.Item>\n <Combobox.Item value=\"kt\">Kotlin</Combobox.Item>\n <Combobox.Item value=\"cpp\">C++</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
201
200
  },
202
201
  {
203
202
  "name": "Custom Max Visible Items",
204
- "description": "Show 6 items before scrolling with half-peek scroll hint",
203
+ "description": "maxVisibleItems raises the cap to six rows.",
205
204
  "code": "<StatefulCombobox placeholder=\"Search cities...\">\n <Combobox.Input />\n <Combobox.Content maxVisibleItems={6}>\n <Combobox.Empty>No results found</Combobox.Empty>\n <Combobox.Item value=\"nyc\">New York</Combobox.Item>\n <Combobox.Item value=\"lon\">London</Combobox.Item>\n <Combobox.Item value=\"tok\">Tokyo</Combobox.Item>\n <Combobox.Item value=\"par\">Paris</Combobox.Item>\n <Combobox.Item value=\"syd\">Sydney</Combobox.Item>\n <Combobox.Item value=\"ber\">Berlin</Combobox.Item>\n <Combobox.Item value=\"tor\">Toronto</Combobox.Item>\n <Combobox.Item value=\"sin\">Singapore</Combobox.Item>\n <Combobox.Item value=\"dub\">Dubai</Combobox.Item>\n <Combobox.Item value=\"sao\">São Paulo</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
206
205
  },
207
206
  {
208
207
  "name": "Disabled",
209
- "description": "Disabled combobox",
208
+ "description": "Dimmed and unfocusable.",
210
209
  "code": "<Combobox disabled placeholder=\"Search...\">\n <Combobox.Input />\n <Combobox.Content>\n <Combobox.Item value=\"1\">Option 1</Combobox.Item>\n </Combobox.Content>\n</Combobox>"
211
210
  },
212
211
  {
213
212
  "name": "Explicit Trigger",
214
- "description": "Hide the built-in input trigger when rendering a separate Combobox.Trigger",
215
- "code": "<StatefulCombobox placeholder=\"Search assignees...\">\n <Combobox.Input showTrigger={false} />\n <Combobox.Trigger aria-label=\"Open assignee list\" />\n <Combobox.Content>\n <Combobox.Item value=\"alice\">Alice</Combobox.Item>\n <Combobox.Item value=\"bob\">Bob</Combobox.Item>\n <Combobox.Item value=\"carol\">Carol</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
213
+ "description": "showTrigger={false} hands the open control to your own Combobox.Trigger.",
214
+ "code": "<StatefulCombobox placeholder=\"Search assignees...\">\n <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>\n <Combobox.Input showTrigger={false} />\n <Combobox.Trigger aria-label=\"Open assignee list\" />\n </div>\n <Combobox.Content>\n <Combobox.Item value=\"alice\">Alice</Combobox.Item>\n <Combobox.Item value=\"bob\">Bob</Combobox.Item>\n <Combobox.Item value=\"carol\">Carol</Combobox.Item>\n </Combobox.Content>\n</StatefulCombobox>"
216
215
  }
217
216
  ],
218
217
  "relations": [
@@ -285,7 +285,7 @@
285
285
 
286
286
  @media (prefers-contrast: more) {
287
287
  .inputWrapper {
288
- border-width: 2px;
288
+ border-width: var(--fui-stroke-default, 2px);
289
289
  border-color: var(--fui-text-primary, $fui-text-primary);
290
290
 
291
291
  &:focus-within {
@@ -4,10 +4,7 @@ import * as React from "react";
4
4
  import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
5
5
  import { useResolvedControlSize } from "../ComponentDefaults";
6
6
  import { mergeAriaIds, useFormFieldIds, type FormFieldProps } from "../../utils/aria";
7
- import {
8
- POPUP_OFFSET_PX,
9
- resolvePopupViewportRows,
10
- } from "../../recipes/popup";
7
+ import { POPUP_OFFSET_PX, resolvePopupViewportRows } from "../../recipes/popup";
11
8
  import styles from "./Combobox.module.scss";
12
9
 
13
10
  // ============================================
@@ -293,6 +290,27 @@ function filterStaticChildren(
293
290
  };
294
291
  }
295
292
 
293
+ /**
294
+ * True when the consumer already supplied a `Combobox.Empty` slot anywhere in
295
+ * the content. Used to decide whether the built-in "no results" fallback is
296
+ * needed — without it an unmatched query renders an empty, collapsed popup.
297
+ */
298
+ function containsEmptySlot(node: React.ReactNode): boolean {
299
+ let found = false;
300
+ React.Children.forEach(node, (child) => {
301
+ if (found || !React.isValidElement(child)) return;
302
+ if (child.type === ComboboxEmpty) {
303
+ found = true;
304
+ return;
305
+ }
306
+ const props = child.props as { children?: React.ReactNode };
307
+ if (props.children !== undefined && containsEmptySlot(props.children)) {
308
+ found = true;
309
+ }
310
+ });
311
+ return found;
312
+ }
313
+
296
314
  // ============================================
297
315
  // Components
298
316
  // ============================================
@@ -631,6 +649,14 @@ function ComboboxContent({
631
649
  () => filterStaticChildren(children, visibleValues),
632
650
  [children, visibleValues]
633
651
  );
652
+ // No matches and no author-supplied empty slot would leave a bare, collapsed
653
+ // popup, so fall back to a readable "no results" row.
654
+ const popupChildren =
655
+ filteredContent.visibleItemCount === 0 && !containsEmptySlot(children) ? (
656
+ <ComboboxEmpty>No results found</ComboboxEmpty>
657
+ ) : (
658
+ filteredContent.children
659
+ );
634
660
 
635
661
  const popupStyle =
636
662
  maxVisibleItems != null
@@ -650,7 +676,7 @@ function ComboboxContent({
650
676
  >
651
677
  <BaseCombobox.Popup {...htmlProps} className={popupClasses} style={popupStyle}>
652
678
  <ComboboxFilteredItemIndexContext.Provider value={filteredItemIndices}>
653
- {filteredContent.children}
679
+ {popupChildren}
654
680
  </ComboboxFilteredItemIndexContext.Provider>
655
681
  </BaseCombobox.Popup>
656
682
  </BaseCombobox.Positioner>
@@ -1,16 +1,9 @@
1
1
  {
2
2
  "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
3
  "name": "Command",
4
- "description": "A searchable command palette for quick actions. Combines an input with a filterable, keyboard-navigable list of actions.",
4
+ "description": "Filters a list of actions as the user types.",
5
5
  "category": "navigation",
6
- "tags": [
7
- "command",
8
- "palette",
9
- "search",
10
- "spotlight",
11
- "quick-actions",
12
- "cmdk"
13
- ],
6
+ "tags": ["command", "palette", "search", "spotlight", "quick-actions", "cmdk"],
14
7
  "status": "stable",
15
8
  "sourcePath": "src/components/Command/index.tsx",
16
9
  "exportName": "Command",
@@ -58,23 +51,22 @@
58
51
  },
59
52
  "usage": {
60
53
  "when": [
61
- "Quick-access command palettes (Ctrl+K)",
62
- "Searchable action menus",
63
- "Inline command lists with filtering",
64
- "Application-wide search interfaces"
54
+ "A keyboard shortcut that jumps anywhere",
55
+ "Action lists too long to scan",
56
+ "Inline lists that need filtering",
57
+ "Search across everything the app can do"
65
58
  ],
66
59
  "whenNot": [
67
- "Simple dropdown menus (use Menu)",
68
- "Form field selection (use Select or Combobox)",
69
- "Static navigation (use Sidebar or Tabs)",
70
- "Search with complex result types (build custom)"
60
+ "A handful of actions (use Menu)",
61
+ "Picking a value for a form (use Select or Combobox)",
62
+ "Fixed navigation (use Sidebar or Tabs)"
71
63
  ],
72
64
  "guidelines": [
73
- "Compose inside Dialog for modal command palette usage",
74
- "Use Command.Group to organize items by category",
75
- "Provide Command.Empty for no-results feedback",
76
- "Use keywords prop for items that should match on aliases",
77
- "Keep item labels short and action-oriented"
65
+ "Wrap in Dialog for the summon-anywhere palette",
66
+ "Group by category once the list gets long",
67
+ "Always supply Command.Empty",
68
+ "Add keywords so aliases and synonyms match",
69
+ "Label rows with a verb"
78
70
  ],
79
71
  "accessibility": [
80
72
  "Uses combobox + listbox ARIA pattern",
@@ -86,22 +78,22 @@
86
78
  "examples": [
87
79
  {
88
80
  "name": "Default",
89
- "description": "Inline command list with search",
81
+ "description": "Search field over a flat list.",
90
82
  "code": "<div style={{ maxWidth: '400px', width: '100%' }}>\n <Command>\n <Command.Input placeholder=\"Type a command...\" />\n <Command.List>\n <Command.Item onItemSelect={() => {}}>Open File</Command.Item>\n <Command.Item onItemSelect={() => {}}>Save Document</Command.Item>\n <Command.Item onItemSelect={() => {}}>Print</Command.Item>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n</div>"
91
83
  },
92
84
  {
93
85
  "name": "Dialog Command Palette",
94
- "description": "Command palette inside a Dialog",
86
+ "description": "The same list summoned over the page.",
95
87
  "code": "<Dialog>\n <Dialog.Trigger asChild>\n <Button variant=\"secondary\">Open Command Palette</Button>\n </Dialog.Trigger>\n <Dialog.Content size=\"sm\">\n <Command>\n <Command.Input placeholder=\"Search commands...\" />\n <Command.List>\n <Command.Group heading=\"Actions\">\n <Command.Item onItemSelect={() => {}}>New File</Command.Item>\n <Command.Item onItemSelect={() => {}}>Open Recent</Command.Item>\n </Command.Group>\n <Command.Separator />\n <Command.Group heading=\"Settings\">\n <Command.Item onItemSelect={() => {}}>Preferences</Command.Item>\n <Command.Item onItemSelect={() => {}}>Keyboard Shortcuts</Command.Item>\n </Command.Group>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n </Dialog.Content>\n</Dialog>"
96
88
  },
97
89
  {
98
90
  "name": "With Groups",
99
- "description": "Organized by category groups",
91
+ "description": "Category labels survive filtering.",
100
92
  "code": "<div style={{ maxWidth: '400px', width: '100%' }}>\n <Command>\n <Command.Input placeholder=\"Search...\" />\n <Command.List>\n <Command.Group heading=\"Suggestions\">\n <Command.Item onItemSelect={() => {}}>Calendar</Command.Item>\n <Command.Item onItemSelect={() => {}}>Calculator</Command.Item>\n </Command.Group>\n <Command.Separator />\n <Command.Group heading=\"Settings\">\n <Command.Item onItemSelect={() => {}}>Profile</Command.Item>\n <Command.Item onItemSelect={() => {}}>Billing</Command.Item>\n <Command.Item disabled onItemSelect={() => {}}>\n Team (coming soon)\n </Command.Item>\n </Command.Group>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n</div>"
101
93
  },
102
94
  {
103
95
  "name": "With Icons",
104
- "description": "Items with leading icons",
96
+ "description": "Leading glyphs speed up scanning.",
105
97
  "code": "<div style={{ maxWidth: '400px', width: '100%' }}>\n <Command>\n <Command.Input placeholder=\"What do you need?\" />\n <Command.List>\n <Command.Item onItemSelect={() => {}}>\n <span style={{ marginRight: '0.5rem', fontSize: '1rem' }}>+</span> New Document\n </Command.Item>\n <Command.Item onItemSelect={() => {}}>\n <span style={{ marginRight: '0.5rem', fontSize: '1rem' }}>{'>'}</span> Open Folder\n </Command.Item>\n <Command.Item onItemSelect={() => {}}>\n <span style={{ marginRight: '0.5rem', fontSize: '1rem' }}>?</span> Search\n </Command.Item>\n <Command.Empty>No results found.</Command.Empty>\n </Command.List>\n </Command>\n</div>"
106
98
  }
107
99
  ],
@@ -132,26 +124,12 @@
132
124
  "Command.Item keywords: string[] - extra filter terms",
133
125
  "Command.Item onItemSelect: (value, event) => void - selection handler"
134
126
  ],
135
- "a11yRules": [
136
- "A11Y_COMBOBOX_ROLE",
137
- "A11Y_LISTBOX_ROLE",
138
- "A11Y_ACTIVE_DESCENDANT"
139
- ]
127
+ "a11yRules": ["A11Y_COMBOBOX_ROLE", "A11Y_LISTBOX_ROLE", "A11Y_ACTIVE_DESCENDANT"]
140
128
  },
141
129
  "ai": {
142
130
  "compositionPattern": "compound",
143
- "subComponents": [
144
- "Input",
145
- "List",
146
- "Item",
147
- "Group",
148
- "Empty",
149
- "Separator"
150
- ],
151
- "requiredChildren": [
152
- "Input",
153
- "List"
154
- ],
131
+ "subComponents": ["Input", "List", "Item", "Group", "Empty", "Separator"],
132
+ "requiredChildren": ["Input", "List"],
155
133
  "commonPatterns": [
156
134
  "<Dialog><Dialog.Trigger><Button>Open Palette</Button></Dialog.Trigger><Dialog.Content size=\"sm\"><Command><Command.Input placeholder=\"Search...\" /><Command.List><Command.Group heading=\"Actions\"><Command.Item onItemSelect={() => {}}>Action 1</Command.Item></Command.Group><Command.Empty>No results.</Command.Empty></Command.List></Command></Dialog.Content></Dialog>"
157
135
  ]
@@ -1,7 +1,7 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
- import * as React from 'react';
4
- import styles from './Command.module.scss';
3
+ import * as React from "react";
4
+ import styles from "./Command.module.scss";
5
5
 
6
6
  // ============================================
7
7
  // Types
@@ -30,7 +30,7 @@ export interface CommandListProps extends React.HTMLAttributes<HTMLDivElement> {
30
30
  children: React.ReactNode;
31
31
  }
32
32
 
33
- export interface CommandItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
33
+ export interface CommandItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect"> {
34
34
  children: React.ReactNode;
35
35
  /** Value used for filtering (falls back to text content) */
36
36
  value?: string;
@@ -78,13 +78,13 @@ function defaultFilter(value: string, search: string, keywords?: string[]): numb
78
78
  }
79
79
 
80
80
  function getTextContent(node: React.ReactNode): string {
81
- if (typeof node === 'string' || typeof node === 'number') return String(node);
82
- if (Array.isArray(node)) return node.map(getTextContent).join(' ');
81
+ if (typeof node === "string" || typeof node === "number") return String(node);
82
+ if (Array.isArray(node)) return node.map(getTextContent).join(" ");
83
83
  if (React.isValidElement(node)) {
84
84
  const childProps = node.props as { children?: React.ReactNode };
85
85
  return getTextContent(childProps.children);
86
86
  }
87
- return '';
87
+ return "";
88
88
  }
89
89
 
90
90
  // ============================================
@@ -115,7 +115,7 @@ const CommandContext = React.createContext<CommandContextValue | null>(null);
115
115
 
116
116
  function useCommandContext() {
117
117
  const ctx = React.useContext(CommandContext);
118
- if (!ctx) throw new Error('Command sub-components must be used within <Command>');
118
+ if (!ctx) throw new Error("Command sub-components must be used within <Command>");
119
119
  return ctx;
120
120
  }
121
121
 
@@ -150,7 +150,7 @@ function SearchIcon() {
150
150
  function CommandRoot({
151
151
  children,
152
152
  search: controlledSearch,
153
- defaultSearch = '',
153
+ defaultSearch = "",
154
154
  onSearchChange,
155
155
  filter = defaultFilter,
156
156
  loop = true,
@@ -231,14 +231,25 @@ function CommandRoot({
231
231
  visibleCount,
232
232
  listId,
233
233
  }),
234
- [search, setSearch, filter, scores, registerItem, unregisterItem, activeId, loop, visibleCount, listId]
234
+ [
235
+ search,
236
+ setSearch,
237
+ filter,
238
+ scores,
239
+ registerItem,
240
+ unregisterItem,
241
+ activeId,
242
+ loop,
243
+ visibleCount,
244
+ listId,
245
+ ]
235
246
  );
236
247
 
237
248
  return (
238
249
  <CommandContext.Provider value={contextValue}>
239
250
  <div
240
251
  {...htmlProps}
241
- className={[styles.command, className].filter(Boolean).join(' ')}
252
+ className={[styles.command, className].filter(Boolean).join(" ")}
242
253
  role="search"
243
254
  >
244
255
  {children}
@@ -247,12 +258,7 @@ function CommandRoot({
247
258
  );
248
259
  }
249
260
 
250
- function CommandInput({
251
- className,
252
- onChange,
253
- onKeyDown,
254
- ...htmlProps
255
- }: CommandInputProps) {
261
+ function CommandInput({ className, onChange, onKeyDown, ...htmlProps }: CommandInputProps) {
256
262
  const { search, setSearch, listRef, setActiveId, activeId, loop, listId } = useCommandContext();
257
263
  const inputRef = React.useRef<HTMLInputElement>(null);
258
264
 
@@ -261,7 +267,7 @@ function CommandInput({
261
267
  if (!list) return [];
262
268
  return Array.from(
263
269
  list.querySelectorAll<HTMLElement>('[data-command-item]:not([data-disabled="true"])')
264
- ).filter((el) => el.style.display !== 'none');
270
+ ).filter((el) => el.style.display !== "none");
265
271
  }, [listRef]);
266
272
 
267
273
  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
@@ -270,45 +276,48 @@ function CommandInput({
270
276
 
271
277
  const items = getEnabledItems();
272
278
  if (items.length === 0) return;
279
+ const firstItem = items[0];
280
+ const lastItem = items.at(-1);
281
+ if (!firstItem || !lastItem) return;
273
282
 
274
- const currentIndex = activeId
275
- ? items.findIndex((item) => item.id === activeId)
276
- : -1;
283
+ const currentIndex = activeId ? items.findIndex((item) => item.id === activeId) : -1;
277
284
 
278
285
  switch (event.key) {
279
- case 'ArrowDown': {
286
+ case "ArrowDown": {
280
287
  event.preventDefault();
281
288
  if (currentIndex < 0) {
282
- setActiveId(items[0].id);
289
+ setActiveId(firstItem.id);
283
290
  } else if (currentIndex < items.length - 1) {
284
- setActiveId(items[currentIndex + 1].id);
291
+ const nextItem = items[currentIndex + 1];
292
+ if (nextItem) setActiveId(nextItem.id);
285
293
  } else if (loop) {
286
- setActiveId(items[0].id);
294
+ setActiveId(firstItem.id);
287
295
  }
288
296
  break;
289
297
  }
290
- case 'ArrowUp': {
298
+ case "ArrowUp": {
291
299
  event.preventDefault();
292
300
  if (currentIndex < 0) {
293
- setActiveId(items[items.length - 1].id);
301
+ setActiveId(lastItem.id);
294
302
  } else if (currentIndex > 0) {
295
- setActiveId(items[currentIndex - 1].id);
303
+ const previousItem = items[currentIndex - 1];
304
+ if (previousItem) setActiveId(previousItem.id);
296
305
  } else if (loop) {
297
- setActiveId(items[items.length - 1].id);
306
+ setActiveId(lastItem.id);
298
307
  }
299
308
  break;
300
309
  }
301
- case 'Home': {
310
+ case "Home": {
302
311
  event.preventDefault();
303
- setActiveId(items[0].id);
312
+ setActiveId(firstItem.id);
304
313
  break;
305
314
  }
306
- case 'End': {
315
+ case "End": {
307
316
  event.preventDefault();
308
- setActiveId(items[items.length - 1].id);
317
+ setActiveId(lastItem.id);
309
318
  break;
310
319
  }
311
- case 'Enter': {
320
+ case "Enter": {
312
321
  event.preventDefault();
313
322
  if (activeId) {
314
323
  const activeItem = items.find((item) => item.id === activeId);
@@ -343,7 +352,7 @@ function CommandInput({
343
352
  setSearch(e.target.value);
344
353
  }}
345
354
  onKeyDown={handleKeyDown}
346
- className={[styles.input, className].filter(Boolean).join(' ')}
355
+ className={[styles.input, className].filter(Boolean).join(" ")}
347
356
  />
348
357
  </div>
349
358
  );
@@ -358,7 +367,7 @@ function CommandList({ children, className, ...htmlProps }: CommandListProps) {
358
367
  {...htmlProps}
359
368
  id={listId}
360
369
  role="listbox"
361
- className={[styles.list, className].filter(Boolean).join(' ')}
370
+ className={[styles.list, className].filter(Boolean).join(" ")}
362
371
  >
363
372
  {children}
364
373
  </div>
@@ -402,11 +411,13 @@ function CommandItem({
402
411
  // Scroll active item into view
403
412
  React.useEffect(() => {
404
413
  if (isActive && itemRef.current) {
405
- itemRef.current.scrollIntoView({ block: 'nearest' });
414
+ itemRef.current.scrollIntoView({ block: "nearest" });
406
415
  }
407
416
  }, [isActive]);
408
417
 
409
- const activateItem = (event: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => {
418
+ const activateItem = (
419
+ event: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>
420
+ ) => {
410
421
  if (disabled) return;
411
422
  onItemSelect?.(textValue, event);
412
423
  };
@@ -440,7 +451,7 @@ function CommandItem({
440
451
  onKeyDown={(e) => {
441
452
  onKeyDown?.(e);
442
453
  if (e.defaultPrevented) return;
443
- if (e.key === 'Enter' || e.key === ' ') {
454
+ if (e.key === "Enter" || e.key === " ") {
444
455
  e.preventDefault();
445
456
  activateItem(e);
446
457
  }
@@ -453,8 +464,8 @@ function CommandItem({
453
464
  className,
454
465
  ]
455
466
  .filter(Boolean)
456
- .join(' ')}
457
- style={{ ...style, display: isVisible ? undefined : 'none' }}
467
+ .join(" ")}
468
+ style={{ ...style, display: isVisible ? undefined : "none" }}
458
469
  >
459
470
  {children}
460
471
  </div>
@@ -470,8 +481,8 @@ function CommandGroup({ children, heading, className, ...htmlProps }: CommandGro
470
481
  // Check if any children are visible after each score update
471
482
  React.useEffect(() => {
472
483
  if (!groupRef.current) return;
473
- const items = groupRef.current.querySelectorAll<HTMLElement>('[data-command-item]');
474
- const anyVisible = Array.from(items).some((item) => item.style.display !== 'none');
484
+ const items = groupRef.current.querySelectorAll<HTMLElement>("[data-command-item]");
485
+ const anyVisible = Array.from(items).some((item) => item.style.display !== "none");
475
486
  setHasVisibleChildren(anyVisible);
476
487
  }, [scores]);
477
488
 
@@ -483,8 +494,8 @@ function CommandGroup({ children, heading, className, ...htmlProps }: CommandGro
483
494
  {...restHtmlProps}
484
495
  role="group"
485
496
  aria-labelledby={heading ? labelId : undefined}
486
- className={[styles.group, className].filter(Boolean).join(' ')}
487
- style={{ ...style, display: hasVisibleChildren ? undefined : 'none' }}
497
+ className={[styles.group, className].filter(Boolean).join(" ")}
498
+ style={{ ...style, display: hasVisibleChildren ? undefined : "none" }}
488
499
  >
489
500
  {heading && (
490
501
  <div id={labelId} className={styles.groupHeading}>
@@ -507,7 +518,7 @@ function CommandEmpty({ children, className, ...htmlProps }: CommandEmptyProps)
507
518
  role="option"
508
519
  aria-disabled="true"
509
520
  aria-selected="false"
510
- className={[styles.empty, className].filter(Boolean).join(' ')}
521
+ className={[styles.empty, className].filter(Boolean).join(" ")}
511
522
  >
512
523
  {children}
513
524
  </div>
@@ -519,7 +530,7 @@ function CommandSeparator({ className, ...htmlProps }: CommandSeparatorProps) {
519
530
  <div
520
531
  {...htmlProps}
521
532
  role="separator"
522
- className={[styles.separator, className].filter(Boolean).join(' ')}
533
+ className={[styles.separator, className].filter(Boolean).join(" ")}
523
534
  />
524
535
  );
525
536
  }