@tempoxyz/ds 0.3.1 → 0.3.2

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 (345) hide show
  1. package/dist/web/components/Accordion.css +1 -1
  2. package/dist/web/components/Accordion.js.zyzz.json +1 -1
  3. package/dist/web/components/AddressCard.css +1 -0
  4. package/dist/web/components/AddressCard.d.ts +85 -0
  5. package/dist/web/components/AddressCard.d.ts.map +1 -0
  6. package/dist/web/components/AddressCard.js +79 -0
  7. package/dist/web/components/AddressCard.js.map +1 -0
  8. package/dist/web/components/AddressCard.js.zyzz.json +1 -0
  9. package/dist/web/components/AgentLogo.js +1 -1
  10. package/dist/web/components/AgentLogo.js.map +1 -1
  11. package/dist/web/components/AgentLogo.js.zyzz.json +1 -1
  12. package/dist/web/components/Alert.css +1 -1
  13. package/dist/web/components/Alert.js.zyzz.json +1 -1
  14. package/dist/web/components/AlertDialog.js.zyzz.json +1 -1
  15. package/dist/web/components/Amount.css +1 -1
  16. package/dist/web/components/Amount.js.zyzz.json +1 -1
  17. package/dist/web/components/AmountInput.css +1 -1
  18. package/dist/web/components/AmountInput.d.ts +1 -1
  19. package/dist/web/components/AmountInput.d.ts.map +1 -1
  20. package/dist/web/components/AmountInput.js.zyzz.json +1 -1
  21. package/dist/web/components/AppShell.css +1 -1
  22. package/dist/web/components/AppShell.d.ts +21 -3
  23. package/dist/web/components/AppShell.d.ts.map +1 -1
  24. package/dist/web/components/AppShell.js +74 -32
  25. package/dist/web/components/AppShell.js.map +1 -1
  26. package/dist/web/components/AppShell.js.zyzz.json +1 -1
  27. package/dist/web/components/AssetChip.css +1 -1
  28. package/dist/web/components/AssetChip.d.ts.map +1 -1
  29. package/dist/web/components/AssetChip.js.map +1 -1
  30. package/dist/web/components/AssetChip.js.zyzz.json +1 -1
  31. package/dist/web/components/Autocomplete.js.zyzz.json +1 -1
  32. package/dist/web/components/Avatar.css +1 -1
  33. package/dist/web/components/Avatar.d.ts +68 -6
  34. package/dist/web/components/Avatar.d.ts.map +1 -1
  35. package/dist/web/components/Avatar.js +27 -7
  36. package/dist/web/components/Avatar.js.map +1 -1
  37. package/dist/web/components/Avatar.js.zyzz.json +1 -1
  38. package/dist/web/components/Badge.css +1 -1
  39. package/dist/web/components/Badge.d.ts +48 -0
  40. package/dist/web/components/Badge.d.ts.map +1 -1
  41. package/dist/web/components/Badge.js +5 -3
  42. package/dist/web/components/Badge.js.map +1 -1
  43. package/dist/web/components/Badge.js.zyzz.json +1 -1
  44. package/dist/web/components/Banner.js.zyzz.json +1 -1
  45. package/dist/web/components/BarChart.css +1 -1
  46. package/dist/web/components/BarChart.js.zyzz.json +1 -1
  47. package/dist/web/components/Breadcrumbs.css +1 -1
  48. package/dist/web/components/Breadcrumbs.js.zyzz.json +1 -1
  49. package/dist/web/components/Button.css +1 -1
  50. package/dist/web/components/Button.d.ts +72 -6
  51. package/dist/web/components/Button.d.ts.map +1 -1
  52. package/dist/web/components/Button.js +5 -3
  53. package/dist/web/components/Button.js.map +1 -1
  54. package/dist/web/components/Button.js.zyzz.json +1 -1
  55. package/dist/web/components/ButtonGroup.js.zyzz.json +1 -1
  56. package/dist/web/components/Calendar.css +1 -1
  57. package/dist/web/components/Calendar.js.zyzz.json +1 -1
  58. package/dist/web/components/Callout.css +1 -0
  59. package/dist/web/components/Callout.d.ts +23 -0
  60. package/dist/web/components/Callout.d.ts.map +1 -0
  61. package/dist/web/components/Callout.js +26 -0
  62. package/dist/web/components/Callout.js.map +1 -0
  63. package/dist/web/components/Callout.js.zyzz.json +1 -0
  64. package/dist/web/components/Checkbox.css +1 -1
  65. package/dist/web/components/Checkbox.js.zyzz.json +1 -1
  66. package/dist/web/components/CheckboxGroup.js.zyzz.json +1 -1
  67. package/dist/web/components/ChoiceGroup.css +1 -1
  68. package/dist/web/components/ChoiceGroup.d.ts +17 -10
  69. package/dist/web/components/ChoiceGroup.d.ts.map +1 -1
  70. package/dist/web/components/ChoiceGroup.js +5 -5
  71. package/dist/web/components/ChoiceGroup.js.map +1 -1
  72. package/dist/web/components/ChoiceGroup.js.zyzz.json +1 -1
  73. package/dist/web/components/Choicebox.css +1 -1
  74. package/dist/web/components/Choicebox.js.zyzz.json +1 -1
  75. package/dist/web/components/Code.css +1 -0
  76. package/dist/web/components/Code.d.ts +25 -0
  77. package/dist/web/components/Code.d.ts.map +1 -0
  78. package/dist/web/components/Code.js +28 -0
  79. package/dist/web/components/Code.js.map +1 -0
  80. package/dist/web/components/Code.js.zyzz.json +1 -0
  81. package/dist/web/components/Combobox.css +1 -1
  82. package/dist/web/components/Combobox.js.zyzz.json +1 -1
  83. package/dist/web/components/Container.js.zyzz.json +1 -1
  84. package/dist/web/components/CopyButton.d.ts +8 -1
  85. package/dist/web/components/CopyButton.d.ts.map +1 -1
  86. package/dist/web/components/CopyButton.js.map +1 -1
  87. package/dist/web/components/CopyButton.js.zyzz.json +1 -1
  88. package/dist/web/components/DatePicker.css +1 -1
  89. package/dist/web/components/DatePicker.js.zyzz.json +1 -1
  90. package/dist/web/components/Dialog.css +1 -1
  91. package/dist/web/components/Dialog.d.ts.map +1 -1
  92. package/dist/web/components/Dialog.js +1 -0
  93. package/dist/web/components/Dialog.js.map +1 -1
  94. package/dist/web/components/Dialog.js.zyzz.json +1 -1
  95. package/dist/web/components/Drawer.js.zyzz.json +1 -1
  96. package/dist/web/components/Empty.css +1 -1
  97. package/dist/web/components/Empty.js.zyzz.json +1 -1
  98. package/dist/web/components/Field.css +1 -1
  99. package/dist/web/components/Field.d.ts +41 -5
  100. package/dist/web/components/Field.d.ts.map +1 -1
  101. package/dist/web/components/Field.js +19 -13
  102. package/dist/web/components/Field.js.map +1 -1
  103. package/dist/web/components/Field.js.zyzz.json +1 -1
  104. package/dist/web/components/Fieldset.js.zyzz.json +1 -1
  105. package/dist/web/components/Frame.css +1 -1
  106. package/dist/web/components/Frame.js.zyzz.json +1 -1
  107. package/dist/web/components/Gauge.js.zyzz.json +1 -1
  108. package/dist/web/components/GetStartedVisual.css +1 -0
  109. package/dist/web/components/GetStartedVisual.d.ts +59 -0
  110. package/dist/web/components/GetStartedVisual.d.ts.map +1 -0
  111. package/dist/web/components/GetStartedVisual.js +31 -0
  112. package/dist/web/components/GetStartedVisual.js.map +1 -0
  113. package/dist/web/components/GetStartedVisual.js.zyzz.json +1 -0
  114. package/dist/web/components/Grid.js.zyzz.json +1 -1
  115. package/dist/web/components/HeroVisual.css +1 -0
  116. package/dist/web/components/HeroVisual.d.ts +96 -0
  117. package/dist/web/components/HeroVisual.d.ts.map +1 -0
  118. package/dist/web/components/HeroVisual.js +202 -0
  119. package/dist/web/components/HeroVisual.js.map +1 -0
  120. package/dist/web/components/HeroVisual.js.zyzz.json +1 -0
  121. package/dist/web/components/Hex.css +1 -1
  122. package/dist/web/components/Hex.js.zyzz.json +1 -1
  123. package/dist/web/components/IconTile.js.zyzz.json +1 -1
  124. package/dist/web/components/Identicon.js.zyzz.json +1 -1
  125. package/dist/web/components/Inline.js.zyzz.json +1 -1
  126. package/dist/web/components/Inset.js.zyzz.json +1 -1
  127. package/dist/web/components/Kbd.css +1 -1
  128. package/dist/web/components/Kbd.d.ts +8 -7
  129. package/dist/web/components/Kbd.d.ts.map +1 -1
  130. package/dist/web/components/Kbd.js +1 -1
  131. package/dist/web/components/Kbd.js.map +1 -1
  132. package/dist/web/components/Kbd.js.zyzz.json +1 -1
  133. package/dist/web/components/ListGroup.css +1 -1
  134. package/dist/web/components/ListGroup.d.ts +35 -65
  135. package/dist/web/components/ListGroup.d.ts.map +1 -1
  136. package/dist/web/components/ListGroup.js +9 -10
  137. package/dist/web/components/ListGroup.js.map +1 -1
  138. package/dist/web/components/ListGroup.js.zyzz.json +1 -1
  139. package/dist/web/components/LoadingDots.js.zyzz.json +1 -1
  140. package/dist/web/components/Menu.css +1 -1
  141. package/dist/web/components/Menu.js.zyzz.json +1 -1
  142. package/dist/web/components/NativeSelect.css +1 -0
  143. package/dist/web/components/NativeSelect.d.ts +50 -0
  144. package/dist/web/components/NativeSelect.d.ts.map +1 -0
  145. package/dist/web/components/NativeSelect.js +50 -0
  146. package/dist/web/components/NativeSelect.js.map +1 -0
  147. package/dist/web/components/NativeSelect.js.zyzz.json +1 -0
  148. package/dist/web/components/NetworkLogo.js.zyzz.json +1 -1
  149. package/dist/web/components/NumberField.css +1 -1
  150. package/dist/web/components/NumberField.js.zyzz.json +1 -1
  151. package/dist/web/components/OtpField.css +1 -1
  152. package/dist/web/components/OtpField.js.zyzz.json +1 -1
  153. package/dist/web/components/Pagination.css +1 -1
  154. package/dist/web/components/Pagination.js.zyzz.json +1 -1
  155. package/dist/web/components/Popover.css +1 -1
  156. package/dist/web/components/Popover.js.zyzz.json +1 -1
  157. package/dist/web/components/Progress.css +1 -1
  158. package/dist/web/components/Progress.d.ts +1 -1
  159. package/dist/web/components/Progress.d.ts.map +1 -1
  160. package/dist/web/components/Progress.js +2 -1
  161. package/dist/web/components/Progress.js.map +1 -1
  162. package/dist/web/components/Progress.js.zyzz.json +1 -1
  163. package/dist/web/components/Qr.js.zyzz.json +1 -1
  164. package/dist/web/components/RadioGroup.css +1 -1
  165. package/dist/web/components/RadioGroup.d.ts +1 -1
  166. package/dist/web/components/RadioGroup.js.zyzz.json +1 -1
  167. package/dist/web/components/SecretValue.css +1 -1
  168. package/dist/web/components/SecretValue.js.zyzz.json +1 -1
  169. package/dist/web/components/Select.css +1 -1
  170. package/dist/web/components/Select.d.ts +1 -1
  171. package/dist/web/components/Select.d.ts.map +1 -1
  172. package/dist/web/components/Select.js.map +1 -1
  173. package/dist/web/components/Select.js.zyzz.json +1 -1
  174. package/dist/web/components/Separator.css +1 -1
  175. package/dist/web/components/Separator.js.zyzz.json +1 -1
  176. package/dist/web/components/SidebarMenu.css +1 -1
  177. package/dist/web/components/SidebarMenu.d.ts +8 -2
  178. package/dist/web/components/SidebarMenu.d.ts.map +1 -1
  179. package/dist/web/components/SidebarMenu.js +10 -10
  180. package/dist/web/components/SidebarMenu.js.map +1 -1
  181. package/dist/web/components/SidebarMenu.js.zyzz.json +1 -1
  182. package/dist/web/components/Skeleton.js.zyzz.json +1 -1
  183. package/dist/web/components/Slider.css +1 -1
  184. package/dist/web/components/Slider.js.zyzz.json +1 -1
  185. package/dist/web/components/Snippet.css +1 -1
  186. package/dist/web/components/Snippet.js.zyzz.json +1 -1
  187. package/dist/web/components/Spinner.js.zyzz.json +1 -1
  188. package/dist/web/components/SplitBar.css +1 -1
  189. package/dist/web/components/SplitBar.js.zyzz.json +1 -1
  190. package/dist/web/components/SplitButton.css +1 -1
  191. package/dist/web/components/SplitButton.d.ts +3 -1
  192. package/dist/web/components/SplitButton.d.ts.map +1 -1
  193. package/dist/web/components/SplitButton.js +2 -2
  194. package/dist/web/components/SplitButton.js.map +1 -1
  195. package/dist/web/components/SplitButton.js.zyzz.json +1 -1
  196. package/dist/web/components/Stack.js.zyzz.json +1 -1
  197. package/dist/web/components/StatusChip.css +1 -1
  198. package/dist/web/components/StatusChip.js.zyzz.json +1 -1
  199. package/dist/web/components/StatusIndicator.css +1 -0
  200. package/dist/web/components/StatusIndicator.d.ts +74 -0
  201. package/dist/web/components/StatusIndicator.d.ts.map +1 -0
  202. package/dist/web/components/StatusIndicator.js +32 -0
  203. package/dist/web/components/StatusIndicator.js.map +1 -0
  204. package/dist/web/components/StatusIndicator.js.zyzz.json +1 -0
  205. package/dist/web/components/StatusRow.css +1 -1
  206. package/dist/web/components/StatusRow.js.zyzz.json +1 -1
  207. package/dist/web/components/Stepper.js.zyzz.json +1 -1
  208. package/dist/web/components/SuccessHero.css +1 -0
  209. package/dist/web/components/SuccessHero.d.ts +74 -0
  210. package/dist/web/components/SuccessHero.d.ts.map +1 -0
  211. package/dist/web/components/SuccessHero.js +167 -0
  212. package/dist/web/components/SuccessHero.js.map +1 -0
  213. package/dist/web/components/SuccessHero.js.zyzz.json +1 -0
  214. package/dist/web/components/Surface.css +1 -1
  215. package/dist/web/components/Surface.d.ts +3 -2
  216. package/dist/web/components/Surface.d.ts.map +1 -1
  217. package/dist/web/components/Surface.js +2 -2
  218. package/dist/web/components/Surface.js.map +1 -1
  219. package/dist/web/components/Surface.js.zyzz.json +1 -1
  220. package/dist/web/components/Switch.css +1 -1
  221. package/dist/web/components/Switch.d.ts +6 -6
  222. package/dist/web/components/Switch.d.ts.map +1 -1
  223. package/dist/web/components/Switch.js +3 -2
  224. package/dist/web/components/Switch.js.map +1 -1
  225. package/dist/web/components/Switch.js.zyzz.json +1 -1
  226. package/dist/web/components/Table.css +1 -1
  227. package/dist/web/components/Table.d.ts +85 -0
  228. package/dist/web/components/Table.d.ts.map +1 -1
  229. package/dist/web/components/Table.js +14 -6
  230. package/dist/web/components/Table.js.map +1 -1
  231. package/dist/web/components/Table.js.zyzz.json +1 -1
  232. package/dist/web/components/Tabs.css +1 -1
  233. package/dist/web/components/Tabs.d.ts +183 -6
  234. package/dist/web/components/Tabs.d.ts.map +1 -1
  235. package/dist/web/components/Tabs.js +18 -13
  236. package/dist/web/components/Tabs.js.map +1 -1
  237. package/dist/web/components/Tabs.js.zyzz.json +1 -1
  238. package/dist/web/components/TempoLogo.js +1 -1
  239. package/dist/web/components/TempoLogo.js.map +1 -1
  240. package/dist/web/components/TempoLogo.js.zyzz.json +1 -1
  241. package/dist/web/components/TextInput.css +1 -1
  242. package/dist/web/components/TextInput.d.ts +80 -2
  243. package/dist/web/components/TextInput.d.ts.map +1 -1
  244. package/dist/web/components/TextInput.js +19 -7
  245. package/dist/web/components/TextInput.js.map +1 -1
  246. package/dist/web/components/TextInput.js.zyzz.json +1 -1
  247. package/dist/web/components/Textarea.css +1 -1
  248. package/dist/web/components/Textarea.d.ts +7 -1
  249. package/dist/web/components/Textarea.d.ts.map +1 -1
  250. package/dist/web/components/Textarea.js +3 -2
  251. package/dist/web/components/Textarea.js.map +1 -1
  252. package/dist/web/components/Textarea.js.zyzz.json +1 -1
  253. package/dist/web/components/Toast.css +1 -1
  254. package/dist/web/components/Toast.d.ts +16 -3
  255. package/dist/web/components/Toast.d.ts.map +1 -1
  256. package/dist/web/components/Toast.js +29 -17
  257. package/dist/web/components/Toast.js.map +1 -1
  258. package/dist/web/components/Toast.js.zyzz.json +1 -1
  259. package/dist/web/components/Token.css +1 -1
  260. package/dist/web/components/Token.js.zyzz.json +1 -1
  261. package/dist/web/components/TokenLogo.js.zyzz.json +1 -1
  262. package/dist/web/components/Tooltip.css +1 -1
  263. package/dist/web/components/Tooltip.d.ts.map +1 -1
  264. package/dist/web/components/Tooltip.js +3 -2
  265. package/dist/web/components/Tooltip.js.map +1 -1
  266. package/dist/web/components/Tooltip.js.zyzz.json +1 -1
  267. package/dist/web/components/VerificationCode.css +1 -1
  268. package/dist/web/components/VerificationCode.js.zyzz.json +1 -1
  269. package/dist/web/components/Visual.js.zyzz.json +1 -1
  270. package/dist/web/components/internal/Field.css +1 -1
  271. package/dist/web/components/internal/Field.js.zyzz.json +1 -1
  272. package/dist/web/components/internal/GetStartedArtwork.d.ts +10 -0
  273. package/dist/web/components/internal/GetStartedArtwork.d.ts.map +1 -0
  274. package/dist/web/components/internal/GetStartedArtwork.js +11 -0
  275. package/dist/web/components/internal/GetStartedArtwork.js.map +1 -0
  276. package/dist/web/components/internal/InputGroup.js.zyzz.json +1 -1
  277. package/dist/web/components/internal/Listbox.css +1 -1
  278. package/dist/web/components/internal/Listbox.js.zyzz.json +1 -1
  279. package/dist/web/components/internal/Streaks.css +1 -0
  280. package/dist/web/components/internal/Streaks.d.ts +48 -0
  281. package/dist/web/components/internal/Streaks.d.ts.map +1 -0
  282. package/dist/web/components/internal/Streaks.js +48 -0
  283. package/dist/web/components/internal/Streaks.js.map +1 -0
  284. package/dist/web/components/internal/Streaks.js.zyzz.json +1 -0
  285. package/dist/web/components/internal/TabBar.d.ts +7 -3
  286. package/dist/web/components/internal/TabBar.d.ts.map +1 -1
  287. package/dist/web/components/internal/TabBar.js.map +1 -1
  288. package/dist/web/index.d.ts +8 -0
  289. package/dist/web/index.d.ts.map +1 -1
  290. package/dist/web/index.js +8 -0
  291. package/dist/web/index.js.map +1 -1
  292. package/dist/web/index.js.zyzz.json +1 -1
  293. package/dist/web/vars.d.ts +25 -3
  294. package/dist/web/vars.d.ts.map +1 -1
  295. package/dist/web/vars.js.map +1 -1
  296. package/dist/web/vars.js.zyzz.json +1 -1
  297. package/dist/web/zyzz.config.d.ts +125 -15
  298. package/dist/web/zyzz.config.d.ts.map +1 -1
  299. package/dist/web/zyzz.config.js.zyzz.json +1 -1
  300. package/package.json +1 -1
  301. package/src/web/components/AddressCard.tsx +216 -0
  302. package/src/web/components/AgentLogo.tsx +1 -1
  303. package/src/web/components/AmountInput.tsx +1 -1
  304. package/src/web/components/AppShell.tsx +127 -31
  305. package/src/web/components/AssetChip.tsx +4 -1
  306. package/src/web/components/Avatar.tsx +73 -6
  307. package/src/web/components/Badge.tsx +39 -3
  308. package/src/web/components/Button.tsx +64 -11
  309. package/src/web/components/Callout.tsx +45 -0
  310. package/src/web/components/ChoiceGroup.tsx +26 -12
  311. package/src/web/components/Code.tsx +42 -0
  312. package/src/web/components/CopyButton.tsx +8 -4
  313. package/src/web/components/Dialog.tsx +2 -1
  314. package/src/web/components/Field.tsx +53 -20
  315. package/src/web/components/GetStartedVisual.tsx +66 -0
  316. package/src/web/components/HeroVisual.tsx +304 -0
  317. package/src/web/components/Kbd.tsx +16 -9
  318. package/src/web/components/ListGroup.tsx +47 -81
  319. package/src/web/components/NativeSelect.tsx +167 -0
  320. package/src/web/components/Progress.tsx +3 -2
  321. package/src/web/components/RadioGroup.tsx +1 -1
  322. package/src/web/components/Select.tsx +2 -1
  323. package/src/web/components/SidebarMenu.tsx +9 -4
  324. package/src/web/components/SplitButton.tsx +11 -4
  325. package/src/web/components/StatusIndicator.tsx +94 -0
  326. package/src/web/components/SuccessHero.tsx +249 -0
  327. package/src/web/components/Surface.tsx +5 -3
  328. package/src/web/components/Switch.tsx +18 -25
  329. package/src/web/components/Table.tsx +69 -1
  330. package/src/web/components/Tabs.tsx +172 -10
  331. package/src/web/components/TempoLogo.tsx +1 -1
  332. package/src/web/components/TextInput.tsx +87 -5
  333. package/src/web/components/Textarea.tsx +9 -1
  334. package/src/web/components/Toast.tsx +67 -34
  335. package/src/web/components/Tooltip.tsx +6 -4
  336. package/src/web/components/internal/GetStartedArtwork.tsx +356 -0
  337. package/src/web/components/internal/Streaks.tsx +173 -0
  338. package/src/web/components/internal/TabBar.ts +7 -3
  339. package/src/web/components/visuals/GetStartedConnect.svg +36 -0
  340. package/src/web/components/visuals/GetStartedFunds.svg +31 -0
  341. package/src/web/components/visuals/GetStartedPasskey.svg +34 -0
  342. package/src/web/components/visuals/README.md +15 -0
  343. package/src/web/index.ts +8 -0
  344. package/src/web/logos/README.md +1 -1
  345. package/src/web/vars.ts +14 -3
@@ -5,7 +5,7 @@ import { useRender } from '@base-ui/react/use-render'
5
5
  import type { ComponentPropsWithRef, MouseEvent, ReactNode } from 'react'
6
6
  import type * as zyzz from 'zyzz'
7
7
  import { ChevronRight } from '../icons/ChevronRight.js'
8
- import { style, variants, vars } from '../zyzz.config.js'
8
+ import { style, variants } from '../zyzz.config.js'
9
9
  import * as RowDisabled from './internal/RowDisabled.js'
10
10
  import * as RowsSize from './internal/RowsSize.js'
11
11
 
@@ -122,8 +122,8 @@ export namespace ListGroup {
122
122
  /**
123
123
  * Stacks a `ListGroup.Title` above a `ListGroup.Description`, beside a leading avatar or logo and a
124
124
  * trailing control. A row that holds it pads 12px above and below. `large` sets a 16px title 2px
125
- * above a monospace description, for the row that introduces a `boxed` group, such as a wallet
126
- * above its address. Defaults to `size="medium"`.
125
+ * above a monospace description, in a row that pads 8px above and below, for the row that
126
+ * introduces a `boxed` group, such as a wallet above its address. Defaults to `size="medium"`.
127
127
  */
128
128
  export function Info(props: Info.Props) {
129
129
  const { className, size, vars, ...attributes } = props
@@ -262,8 +262,7 @@ export namespace ListGroup {
262
262
 
263
263
  /**
264
264
  * `variant` sets the container. `plain` rows have none and line up with the content around them.
265
- * `boxed` rows sit in a bordered block with 16px sides and 8px above and below, and a row's
266
- * hover fill reaches the border. `spaced` rows
265
+ * `boxed` rows sit in a bordered block with 16px sides and 8px above and below. `spaced` rows
267
266
  * sit in the same block with 16px all round, 12px apart, with 14px text and no row padding.
268
267
  *
269
268
  * Rows are 36px with 12px text, which fits a 32px control. `dividers={false}` drops the line
@@ -292,8 +291,8 @@ export namespace ListGroup {
292
291
  /**
293
292
  * Renders a button when pressable, a `label` around a radio when it has a `value`, or a link or
294
293
  * other element through `render`. `ref` and attributes reach that element. Children sit 12px
295
- * apart, such as an `Avatar`, a `ListGroup.Info` and a trailing `Button`. A pressable row's hover
296
- * fill covers the row, flush with its content. A static row that holds a control, such as a Copy
294
+ * apart, such as an `Avatar`, a `ListGroup.Info` and a trailing `Button`. A pressable row stays
295
+ * flush with its content, and its hover fill and focus ring bleed 12px past it at each side. A static row that holds a control, such as a Copy
297
296
  * `Button`, takes the same fill on hover and stays static, so the control is the only target.
298
297
  * A `Select` in a row hugs its value at the row's end, in the row's type, 32px tall and without a
299
298
  * fill of its own.
@@ -391,8 +390,8 @@ export namespace ListGroup {
391
390
  /** Content of the row, laid out 12px apart. */
392
391
  children?: ReactNode | undefined
393
392
  /**
394
- * Dims the row to 40% and disables it: a button row sets `disabled`, a radio row disables
395
- * its radio and ignores presses, and any other row sets `aria-disabled` and ignores
393
+ * Dims the row to 40% opacity and disables it: a button row sets `disabled`, a radio row
394
+ * disables its radio and ignores presses, and any other row sets `aria-disabled` and ignores
396
395
  * presses. A static row also disables the native controls inside it, such as a Copy
397
396
  * `Button`, and every `Switch` and `Checkbox`, which leave the Tab order and ignore presses
398
397
  * and input. Its children receive no presses, and its text stays readable.
@@ -653,6 +652,8 @@ namespace styles {
653
652
  '& > [data-divider]:first-child::before': { display: 'none' },
654
653
  // A title over a description pads 12px, which fits a 40px leading image.
655
654
  '& [data-divider]:has([data-info])': { paddingBlock: '12' },
655
+ // A large title over a description pads 8px, which fits a 40px leading image in 56px.
656
+ '& [data-divider]:has([data-info][data-size="large"])': { paddingBlock: '8' },
656
657
  // A row with a meter pads 10px, which centers a 24px agent logo in 44px.
657
658
  '& [data-divider]:has([role="meter"])': { paddingBlock: '10' },
658
659
  // A hovered row's fill would otherwise sit between two visible separators.
@@ -676,48 +677,8 @@ namespace styles {
676
677
  borderRadius: 'sm',
677
678
  borderStyle: 'solid',
678
679
  borderWidth: 'regular',
679
- isolation: 'isolate !custom',
680
680
  paddingBlock: '8',
681
681
  paddingInline: '16',
682
- selectors: {
683
- // A large title leads the group from the block's own top padding.
684
- '& > [data-divider]:first-child:has([data-info][data-size="large"])': {
685
- paddingBlockStart: '0',
686
- },
687
- // A row's fill is a layer behind the row that reaches the border across the block's
688
- // 16px sides, and its 8px above the first row and below the last. The row keeps its
689
- // place, and the fill rounds inside the border at the block's corners.
690
- '& > [data-divider]::after': {
691
- backgroundColor: 'transparent !custom',
692
- content: '"" !custom',
693
- insetBlock: '0',
694
- insetInline: '-16',
695
- position: 'absolute',
696
- transitionDuration: '160',
697
- transitionProperty: 'background-color',
698
- transitionTimingFunction: 'snappy',
699
- zIndex: '-1 !custom',
700
- },
701
- '& > [data-divider]:first-child::after': {
702
- borderStartEndRadius: `calc(${vars.radius.sm} - 1px) !custom`,
703
- borderStartStartRadius: `calc(${vars.radius.sm} - 1px) !custom`,
704
- insetBlockStart: '-8',
705
- },
706
- '& > [data-divider]:last-child::after': {
707
- borderEndEndRadius: `calc(${vars.radius.sm} - 1px) !custom`,
708
- borderEndStartRadius: `calc(${vars.radius.sm} - 1px) !custom`,
709
- insetBlockEnd: '-8',
710
- },
711
- '& > [data-divider]:is(a[href], button, [role="button"], :has(:where(a[href], :is(button, input, select, textarea, [data-select-trigger]):not(:disabled, [data-disabled])))):not(:disabled, [data-disabled], [data-radio]):hover::after':
712
- { backgroundColor: 'container.regular' },
713
- '& > [data-divider]:is(a[href], button, [role="button"]):not(:disabled, [data-disabled]):active::after':
714
- {
715
- backgroundColor: 'container.strong',
716
- },
717
- },
718
- '@media (prefers-reduced-motion: reduce)': {
719
- selectors: { '& > [data-divider]::after': { transitionProperty: 'none' } },
720
- },
721
682
  },
722
683
  plain: {},
723
684
  spaced: {
@@ -757,53 +718,57 @@ namespace styles {
757
718
  columnGap: '12',
758
719
  display: 'flex',
759
720
  font: 'inherit !custom',
721
+ // The row isolates its highlight, which paints below the content and above whatever is
722
+ // behind the row.
723
+ isolation: 'isolate !custom',
760
724
  minHeight: '36',
761
725
  outlineColor: 'transparent !custom',
762
- outlineOffset: '0',
763
726
  outlineStyle: 'solid !custom',
764
727
  outlineWidth: '2',
765
728
  paddingBlock: '2',
766
729
  paddingInline: '0',
730
+ position: 'relative',
767
731
  textAlign: 'start',
768
732
  textDecoration: 'none !custom',
769
733
  transitionDuration: '160',
770
- transitionProperty: 'background-color, box-shadow, opacity, outline-color, outline-offset',
734
+ transitionProperty: 'opacity',
771
735
  transitionTimingFunction: 'snappy',
772
736
  width: '100% !custom',
773
737
  selectors: {
774
- // The row keeps Figma's List Row geometry, flush with its content, and its fill bleeds
775
- // 12px past the content at each side. A shadow on each side draws the bleed: an outer
776
- // shadow never paints under the row, so a translucent fill never doubles. A dialog body
777
- // scrolls and clips at its 4px padding, so the bleed there is 4px, except in a surface,
778
- // whose rows draw none. A boxed group draws the fill behind its rows. A static row that holds an enabled control takes the same fill
779
- // on hover, without becoming pressable.
780
- '&:is(a[href], button, [role="button"], :has(:where(a[href], :is(button, input, select, textarea, [data-select-trigger]):not(:disabled, [data-disabled])))):not([data-radio])':
781
- { borderRadius: 'xs' },
782
- '&:is(a[href], button, [role="button"], :has(:where(a[href], :is(button, input, select, textarea, [data-select-trigger]):not(:disabled, [data-disabled])))):not(:disabled, [data-disabled], [data-radio], [data-variant="boxed"] > *):hover':
783
- {
784
- backgroundColor: 'container.regular',
785
- boxShadow: `-12px 0 0 0 ${vars.color.container.regular}, 12px 0 0 0 ${vars.color.container.regular} !custom`,
786
- },
738
+ // The row keeps Figma's List Row geometry, flush with its content. Its highlight is a
739
+ // layer behind the content that bleeds 12px past the content at each side, rounds at
740
+ // 12px, and draws the hover fill and the focus ring. A dialog body scrolls and clips at
741
+ // its 4px padding, so the bleed there is 4px, except in a surface. A static row that
742
+ // holds an enabled control takes the same fill on hover, without becoming pressable.
743
+ '&[data-divider]::after': {
744
+ backgroundColor: 'transparent !custom',
745
+ borderRadius: 'xs',
746
+ content: '"" !custom',
747
+ insetBlock: '0',
748
+ insetInline: '-12',
749
+ outlineColor: 'transparent !custom',
750
+ outlineOffset: '-2',
751
+ outlineStyle: 'solid !custom',
752
+ outlineWidth: '2',
753
+ pointerEvents: 'none',
754
+ position: 'absolute',
755
+ transitionDuration: '160',
756
+ transitionProperty: 'background-color, outline-color',
757
+ transitionTimingFunction: 'snappy',
758
+ zIndex: '-1 !custom',
759
+ },
760
+ '&:is(a[href], button, [role="button"], :has(:where(a[href], :is(button, input, select, textarea, [data-select-trigger]):not(:disabled, [data-disabled])))):not(:disabled, [data-disabled], [data-radio]):hover::after':
761
+ { backgroundColor: 'container.regular' },
787
762
  '&:is(a[href], button, [role="button"]):not(:disabled, [data-disabled])': {
788
763
  cursor: 'pointer',
789
764
  },
790
- '&:is(a[href], button, [role="button"]):not(:disabled, [data-disabled], [data-variant="boxed"] > *):active':
791
- {
792
- backgroundColor: 'container.strong',
793
- boxShadow: `-12px 0 0 0 ${vars.color.container.strong}, 12px 0 0 0 ${vars.color.container.strong} !custom`,
794
- },
795
- ':is([data-dialog-body], [data-dialog-body] :not([data-surface-size])) > [data-list-group]:not([data-variant="boxed"]) > &:is(a[href], button, [role="button"], :has(:where(a[href], :is(button, input, select, textarea, [data-select-trigger]):not(:disabled, [data-disabled])))):not(:disabled, [data-disabled], [data-radio]):hover':
796
- {
797
- boxShadow: `-4px 0 0 0 ${vars.color.container.regular}, 4px 0 0 0 ${vars.color.container.regular} !custom`,
798
- },
799
- ':is([data-dialog-body], [data-dialog-body] :not([data-surface-size])) > [data-list-group]:not([data-variant="boxed"]) > &:is(a[href], button, [role="button"]):not(:disabled, [data-disabled]):active':
800
- {
801
- boxShadow: `-4px 0 0 0 ${vars.color.container.strong}, 4px 0 0 0 ${vars.color.container.strong} !custom`,
802
- },
803
- '&:is(a[href], button, [role="button"]):focus-visible': {
765
+ '&:is(a[href], button, [role="button"]):not(:disabled, [data-disabled], [data-radio]):active::after':
766
+ { backgroundColor: 'container.strong' },
767
+ '&:is(a[href], button, [role="button"]):not([data-radio]):focus-visible::after': {
804
768
  outlineColor: 'border.focus',
805
- outlineOffset: '-2',
806
769
  },
770
+ ':is([data-dialog-body], [data-dialog-body] :not([data-surface-size])) > [data-list-group]:not([data-variant="boxed"]) > &[data-divider]::after':
771
+ { insetInline: '-4' },
807
772
  // A radio row is a bordered block whose border thickens when checked and focused, as
808
773
  // Figma lays out its stroke, so the row grows by 1px a side for focus.
809
774
  '&[data-radio]': {
@@ -833,13 +798,14 @@ namespace styles {
833
798
  borderWidth: 'thick',
834
799
  },
835
800
  '&[data-radio]:active:not(:has(> [data-disabled]))': { scale: 'press' },
801
+ // The Platform designs dim a disabled row to 40%, as they dim a disabled button, above the
802
+ // 32% of opacity.disabled.
836
803
  '&[data-disabled], &[data-radio]:has(> [data-disabled])': {
837
804
  cursor: 'default',
838
- opacity: 'disabled',
805
+ opacity: '0.4 !custom',
839
806
  },
840
807
  },
841
808
  '@media (prefers-reduced-motion: reduce)': {
842
- transitionProperty: 'background-color, box-shadow, opacity, outline-color',
843
809
  selectors: {
844
810
  '&[data-radio]': { transitionProperty: 'background-color, border-color, opacity' },
845
811
  '&[data-radio]:active': { scale: 'none !custom' },
@@ -0,0 +1,167 @@
1
+ import * as BaseUi from '@base-ui/react/field'
2
+ import type { ComponentPropsWithRef } from 'react'
3
+ import type * as zyzz from 'zyzz'
4
+ import { ChevronDown } from '../icons/ChevronDown.js'
5
+ import { style } from '../zyzz.config.js'
6
+
7
+ /**
8
+ * A native `select` styled as a 48px field, with a chevron at its end. It registers as the control
9
+ * of the enclosing `Field.Root`, which supplies its label, description, error and disabled state.
10
+ * The browser draws the options in its own picker, so it fits forms that need the platform picker,
11
+ * such as on touch devices. Base UI has no primitive for a native `select`, so it renders the
12
+ * element through `Field.Control`.
13
+ *
14
+ * - Give it a visible `Field.Label`, or an `aria-label` when none fits.
15
+ * - Lead with a disabled, empty `option` that names the choice, such as "Select environment", and
16
+ * set `defaultValue=""` so it shows until a value is picked.
17
+ * - Use `Select` instead when the options need icons, groups with styling, or a custom popup.
18
+ *
19
+ * @example
20
+ * <Field.Root>
21
+ * <Field.Label>Environment</Field.Label>
22
+ * <NativeSelect defaultValue="">
23
+ * <option disabled value="">
24
+ * Select environment
25
+ * </option>
26
+ * <option value="production">Production</option>
27
+ * <option value="staging">Staging</option>
28
+ * </NativeSelect>
29
+ * </Field.Root>
30
+ *
31
+ * @see {@link https://base-ui.com/react/components/field | Base UI Field}
32
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select | MDN select element}
33
+ * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/labels-or-instructions.html | WCAG 2.2 Labels or Instructions}
34
+ * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/error-identification.html | WCAG 2.2 Error Identification}
35
+ */
36
+ export function NativeSelect(props: NativeSelect.Props) {
37
+ const { className, invalid = false, vars, ...attributes } = props
38
+
39
+ return (
40
+ <span {...styles.root()} data-native-select="">
41
+ {/* Field.Control sets aria-invalid for an invalid Field.Root, which an absent prop keeps. */}
42
+ <BaseUi.Field.Control
43
+ render={
44
+ <select
45
+ {...(invalid && { 'aria-invalid': true })}
46
+ {...attributes}
47
+ {...styles.select({ className, style: props.style, vars })}
48
+ />
49
+ }
50
+ />
51
+ <ChevronDown {...styles.icon()} />
52
+ </span>
53
+ )
54
+ }
55
+
56
+ export namespace NativeSelect {
57
+ export type Props = ComponentPropsWithRef<'select'> &
58
+ zyzz.Props.Variants<typeof styles.select> & {
59
+ /**
60
+ * Fills the field red with a 1px red border and sets `aria-invalid`. An invalid
61
+ * `Field.Root` sets it too.
62
+ *
63
+ * @default false
64
+ */
65
+ invalid?: boolean | undefined
66
+ }
67
+ }
68
+
69
+ namespace styles {
70
+ // The chevron keeps the primary color, and a disabled field fades it to 40%, as the design does.
71
+ export const icon = style(
72
+ {
73
+ alignSelf: 'center',
74
+ color: 'content.primary',
75
+ fontSize: '16',
76
+ gridArea: '1 / 1 !custom',
77
+ justifySelf: 'end',
78
+ marginInlineEnd: '16',
79
+ pointerEvents: 'none',
80
+ transitionDuration: '160',
81
+ transitionProperty: 'opacity !custom',
82
+ transitionTimingFunction: 'snappy',
83
+ selectors: { ':has(> select:disabled) > &': { opacity: '0.4 !custom' } },
84
+ },
85
+ { id: 'tds/web/native-select/icon' },
86
+ )
87
+
88
+ // The focus border is drawn over the field, so focus never moves the text past its 0.5px line.
89
+ export const root = style(
90
+ {
91
+ borderRadius: 'xs',
92
+ display: 'grid',
93
+ position: 'relative',
94
+ selectors: {
95
+ '&::after': {
96
+ borderColor: 'transparent !custom',
97
+ borderRadius: 'inherit !custom',
98
+ borderStyle: 'solid !custom',
99
+ borderWidth: 'regular',
100
+ boxSizing: 'border-box',
101
+ content: '"" !custom',
102
+ cornerShape: 'inherit !custom',
103
+ inset: '0',
104
+ pointerEvents: 'none',
105
+ position: 'absolute',
106
+ transitionDuration: '160',
107
+ transitionProperty: 'border-color !custom',
108
+ transitionTimingFunction: 'snappy',
109
+ },
110
+ '&:has(> select:focus-visible)::after': { borderColor: 'border.focus' },
111
+ },
112
+ },
113
+ { id: 'tds/web/native-select' },
114
+ )
115
+
116
+ // The end padding holds the 16px chevron, 8px from the text and 16px from the edge.
117
+ export const select = style(
118
+ {
119
+ appearance: 'none !custom',
120
+ backgroundColor: 'background.elevated',
121
+ borderColor: 'line.secondary',
122
+ borderRadius: 'xs',
123
+ borderStyle: 'solid',
124
+ borderWidth: 'thin',
125
+ boxSizing: 'border-box',
126
+ color: 'content.primary',
127
+ cursor: 'pointer',
128
+ gridArea: '1 / 1 !custom',
129
+ height: '48',
130
+ margin: '0',
131
+ minWidth: '0',
132
+ // Forced colors paint transparent outlines, so this outline is the focus ring only there.
133
+ outlineColor: 'transparent !custom',
134
+ outlineOffset: '2',
135
+ outlineStyle: 'solid !custom',
136
+ outlineWidth: '2',
137
+ paddingBlock: '0',
138
+ paddingInlineEnd: '40',
139
+ paddingInlineStart: '16',
140
+ transitionDuration: '160',
141
+ transitionProperty: 'background-color, border-color, color, outline-color !custom',
142
+ transitionTimingFunction: 'snappy',
143
+ typography: 'body.b2',
144
+ width: '100% !custom',
145
+ selectors: {
146
+ '&:where(:hover:not(:disabled))': { borderColor: 'line.primary' },
147
+ '&[aria-invalid="true"], [data-invalid] &': {
148
+ backgroundColor: 'container.negative',
149
+ borderColor: 'border.negative',
150
+ borderWidth: 'regular',
151
+ },
152
+ // Chromium fades a disabled select to 70%, which the subtle fill replaces.
153
+ '&:disabled': {
154
+ backgroundColor: 'container.subtle',
155
+ color: 'content.tertiary',
156
+ cursor: 'default',
157
+ opacity: '1 !custom',
158
+ },
159
+ },
160
+ '@media (forced-colors: active)': {
161
+ outlineStyle: 'none !custom',
162
+ selectors: { '&:focus-visible': { outlineStyle: 'solid !custom' } },
163
+ },
164
+ },
165
+ { id: 'tds/web/native-select/select' },
166
+ )
167
+ }
@@ -164,17 +164,18 @@ namespace styles {
164
164
  )
165
165
 
166
166
  export const label = style(
167
- { color: 'content.primary', flex: '1 !custom', typography: 'body.b3' },
167
+ { color: 'content.primary', flex: '1 !custom', typography: 'body.b3Strong' },
168
168
  { id: 'tds/web/progress/label' },
169
169
  )
170
170
 
171
+ // The label row sits 12px above the track.
171
172
  export const root = variants(
172
173
  {
173
174
  base: {
174
175
  columnGap: '8',
175
176
  display: 'flex',
176
177
  flexWrap: 'wrap',
177
- rowGap: '8',
178
+ rowGap: '12',
178
179
  width: '100% !custom',
179
180
  },
180
181
  defaultVariants: { intent: 'neutral' },
@@ -91,7 +91,7 @@ export namespace RadioGroup {
91
91
  namespace styles {
92
92
  export const group = variants(
93
93
  {
94
- base: { display: 'flex', flexDirection: 'column', rowGap: '12' },
94
+ base: { display: 'flex', flexDirection: 'column', rowGap: '16' },
95
95
  defaultVariants: { size: 'medium' },
96
96
  variants: {
97
97
  // Every item is 16, 20 or 24px with a dot that scales with it. The hit area stays at least 36px.
@@ -351,9 +351,10 @@ namespace styles {
351
351
  // a trigger that hugs its content grows 4px wider.
352
352
  '&[role="combobox"]:focus-visible': { paddingInline: 'calc(1rem + 2px) !custom' },
353
353
  '&[role="combobox"]:focus-visible::before': { borderWidth: 'thick' },
354
+ // The Platform select dims to 40%, past the 32% of the shared disabled opacity.
354
355
  '&[role="combobox"]:is(:disabled, [data-disabled])': {
355
356
  color: 'content.primary',
356
- opacity: 'disabled',
357
+ opacity: '0.4 !custom',
357
358
  },
358
359
  },
359
360
  },
@@ -448,8 +448,10 @@ namespace styles {
448
448
  paddingInline: '10',
449
449
  },
450
450
  // Base UI triggers mark the row `data-popup-open` while their menu or popover is open.
451
- '&:hover:not(:disabled, [data-disabled]), &[data-popup-open]': {
452
- backgroundColor: 'container.regular',
451
+ '&:hover:not(:disabled, [data-disabled])': { backgroundColor: 'container.regular' },
452
+ // An open row keeps the stronger fill while the pointer rests on it.
453
+ '&[data-popup-open]:not(:disabled, [data-disabled])': {
454
+ backgroundColor: 'container.strong',
453
455
  },
454
456
  '&:is(:disabled, [data-disabled])': { cursor: 'default', opacity: 'disabled' },
455
457
  },
@@ -620,10 +622,13 @@ namespace styles {
620
622
  active: {
621
623
  false: {},
622
624
  true: {
623
- backgroundColor: 'container.regular',
625
+ backgroundColor: 'container.strong',
624
626
  color: 'content.primary',
625
627
  typography: 'body.b2Strong',
626
- selectors: { '[data-sidebar-menu-size="large"] &': { typography: 'body.b1Strong' } },
628
+ selectors: {
629
+ '&:hover': { backgroundColor: 'container.strong' },
630
+ '[data-sidebar-menu-size="large"] &': { typography: 'body.b1Strong' },
631
+ },
627
632
  },
628
633
  },
629
634
  },
@@ -52,6 +52,7 @@ export namespace SplitButton {
52
52
  return (
53
53
  <splitContext.Provider value={{ size, variant }}>
54
54
  <div
55
+ data-size={size ?? 'medium'}
55
56
  data-variant={variant ?? 'primary'}
56
57
  role="group"
57
58
  {...attributes}
@@ -63,10 +64,11 @@ export namespace SplitButton {
63
64
 
64
65
  export namespace Root {
65
66
  export type Props = ComponentPropsWithRef<'div'> &
66
- zyzz.Props.Variants<typeof styles.root> &
67
- Pick<Button.Props, 'variant'> & {
67
+ zyzz.Props.Variants<typeof styles.root> & {
68
68
  /** Size of both buttons. The 24px `xsmall` pill can't join a trigger, so it is left out. */
69
69
  size?: Exclude<Button.Props['size'], 'xsmall'> | undefined
70
+ /** Style of both buttons. The `text` style has no fill to join a trigger, so it is left out. */
71
+ variant?: Exclude<Button.Props['variant'], 'text'> | undefined
70
72
  }
71
73
  }
72
74
 
@@ -107,11 +109,16 @@ namespace styles {
107
109
  // and squircle rather than the circle of an icon button.
108
110
  '& > [aria-haspopup]': {
109
111
  borderBottomLeftRadius: 'none',
110
- borderBottomRightRadius: 'xs',
112
+ borderBottomRightRadius: 'sm',
111
113
  borderTopLeftRadius: 'none',
112
- borderTopRightRadius: 'xs',
114
+ borderTopRightRadius: 'sm',
113
115
  cornerShape: 'squircle',
114
116
  },
117
+ // A small action rounds at xs, so its trigger does too.
118
+ '&[data-size="small"] > [aria-haspopup]': {
119
+ borderBottomRightRadius: 'xs',
120
+ borderTopRightRadius: 'xs',
121
+ },
115
122
  '& > [aria-haspopup] > svg': {
116
123
  transitionDuration: '240',
117
124
  transitionProperty: 'transform',
@@ -0,0 +1,94 @@
1
+ import type { ComponentPropsWithRef } from 'react'
2
+ import type * as zyzz from 'zyzz'
3
+ import { style, variants } from '../zyzz.config.js'
4
+
5
+ /**
6
+ * A label led by an 8px dot in the color of its `intent`, rendered as a `span` without a fill. It
7
+ * sets no live region, so a status that changes in place needs one around it.
8
+ *
9
+ * - Keep the label to one or two words that name the status, such as Online or Degraded.
10
+ * - Pick the `intent` from the outcome: `positive` for healthy or live, `warning` for degraded,
11
+ * `negative` for down or failed, and `neutral` for idle or unknown.
12
+ * - Use `StatusChip` where the status needs a filled pill, such as in a table row.
13
+ *
14
+ * @example
15
+ * <StatusIndicator intent="positive">Operational</StatusIndicator>
16
+ *
17
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/span | MDN span element}
18
+ * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html | WCAG 2.2 Use of Color}
19
+ * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/status-messages.html | WCAG 2.2 Status Messages}
20
+ */
21
+ export function StatusIndicator(props: StatusIndicator.Props) {
22
+ const { children, className, intent, vars, ...attributes } = props
23
+
24
+ return (
25
+ <span
26
+ {...attributes}
27
+ data-intent={intent ?? 'neutral'}
28
+ {...styles.indicator({ className, intent, style: props.style, vars })}
29
+ >
30
+ {/* The label names the status, so the dot is decorative. */}
31
+ <span aria-hidden="true" data-status-indicator-dot="" {...styles.dot()} />
32
+ {children}
33
+ </span>
34
+ )
35
+ }
36
+
37
+ export namespace StatusIndicator {
38
+ export type Props = ComponentPropsWithRef<'span'> & zyzz.Props.Variants<typeof styles.indicator>
39
+ }
40
+
41
+ namespace styles {
42
+ export const dot = style(
43
+ {
44
+ borderRadius: 'full',
45
+ cornerShape: 'round',
46
+ flexShrink: '0 !custom',
47
+ height: '8',
48
+ width: '8',
49
+ },
50
+ { id: 'tds/web/status-indicator/dot' },
51
+ )
52
+
53
+ // The label stays secondary at every intent, and the dot takes the intent color.
54
+ export const indicator = variants(
55
+ {
56
+ base: {
57
+ alignItems: 'center',
58
+ color: 'content.secondary',
59
+ columnGap: '8',
60
+ display: 'inline-flex',
61
+ height: '24',
62
+ typography: 'body.b3',
63
+ verticalAlign: 'middle',
64
+ whiteSpace: 'nowrap',
65
+ },
66
+ defaultVariants: { intent: 'neutral' },
67
+ variants: {
68
+ intent: {
69
+ negative: {
70
+ selectors: {
71
+ '& > [data-status-indicator-dot]': { backgroundColor: 'content.negative' },
72
+ },
73
+ },
74
+ neutral: {
75
+ selectors: {
76
+ '& > [data-status-indicator-dot]': { backgroundColor: 'content.secondary' },
77
+ },
78
+ },
79
+ positive: {
80
+ selectors: {
81
+ '& > [data-status-indicator-dot]': { backgroundColor: 'content.positive' },
82
+ },
83
+ },
84
+ warning: {
85
+ selectors: {
86
+ '& > [data-status-indicator-dot]': { backgroundColor: 'content.warning' },
87
+ },
88
+ },
89
+ },
90
+ },
91
+ },
92
+ { id: 'tds/web/status-indicator' },
93
+ )
94
+ }