@mich8060/unified-design-system 0.1.10

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 (454) hide show
  1. package/LICENSE +21 -0
  2. package/README.lib.md +103 -0
  3. package/README.md +265 -0
  4. package/dist/LICENSE +21 -0
  5. package/dist/README.md +103 -0
  6. package/dist/package.json +49 -0
  7. package/dist/styles.css +20544 -0
  8. package/dist/uds-components.es.js +67031 -0
  9. package/dist/uds-components.es.js.map +1 -0
  10. package/dist/uds-components.umd.js +67048 -0
  11. package/dist/uds-components.umd.js.map +1 -0
  12. package/package.json +158 -0
  13. package/src/styles/_typography.scss +932 -0
  14. package/src/styles/_utilities.scss +3738 -0
  15. package/src/styles/_variables.scss +620 -0
  16. package/src/styles/prism-custom.css +204 -0
  17. package/src/styles/prism-custom.scss +205 -0
  18. package/src/styles/tokens.css +1463 -0
  19. package/src/styles/tokens.scss +1116 -0
  20. package/src/ui/Accordion/Accordion.ai.md +69 -0
  21. package/src/ui/Accordion/Accordion.scss +87 -0
  22. package/src/ui/Accordion/Accordion.spec.ts +25 -0
  23. package/src/ui/Accordion/Accordion.stories.tsx +46 -0
  24. package/src/ui/Accordion/Accordion.test.tsx +54 -0
  25. package/src/ui/Accordion/Accordion.tsx +73 -0
  26. package/src/ui/Accordion/Accordion.types.ts +15 -0
  27. package/src/ui/Accordion/index.js +1 -0
  28. package/src/ui/ActionMenu/ActionMenu.ai.md +106 -0
  29. package/src/ui/ActionMenu/ActionMenu.jsx +437 -0
  30. package/src/ui/ActionMenu/ActionMenu.scss +252 -0
  31. package/src/ui/ActionMenu/ActionMenu.spec.ts +12 -0
  32. package/src/ui/ActionMenu/ActionMenu.stories.jsx +14 -0
  33. package/src/ui/ActionMenu/ActionMenu.stories.tsx +124 -0
  34. package/src/ui/ActionMenu/ActionMenu.test.tsx +1 -0
  35. package/src/ui/ActionMenu/ActionMenu.tsx +6 -0
  36. package/src/ui/ActionMenu/ActionMenu.types.ts +3 -0
  37. package/src/ui/ActionMenu/index.js +1 -0
  38. package/src/ui/Avatar/Avatar.ai.md +54 -0
  39. package/src/ui/Avatar/Avatar.jsx +49 -0
  40. package/src/ui/Avatar/Avatar.scss +87 -0
  41. package/src/ui/Avatar/Avatar.spec.ts +12 -0
  42. package/src/ui/Avatar/Avatar.stories.jsx +14 -0
  43. package/src/ui/Avatar/Avatar.stories.tsx +14 -0
  44. package/src/ui/Avatar/Avatar.test.tsx +1 -0
  45. package/src/ui/Avatar/Avatar.tsx +6 -0
  46. package/src/ui/Avatar/Avatar.types.ts +3 -0
  47. package/src/ui/Avatar/index.js +1 -0
  48. package/src/ui/Badge/Badge.ai.md +37 -0
  49. package/src/ui/Badge/Badge.jsx +64 -0
  50. package/src/ui/Badge/Badge.scss +84 -0
  51. package/src/ui/Badge/Badge.spec.ts +12 -0
  52. package/src/ui/Badge/Badge.stories.jsx +14 -0
  53. package/src/ui/Badge/Badge.stories.tsx +14 -0
  54. package/src/ui/Badge/Badge.test.tsx +1 -0
  55. package/src/ui/Badge/Badge.tsx +6 -0
  56. package/src/ui/Badge/Badge.types.ts +3 -0
  57. package/src/ui/Badge/index.js +1 -0
  58. package/src/ui/Branding/Branding.ai.md +81 -0
  59. package/src/ui/Branding/Branding.jsx +127 -0
  60. package/src/ui/Branding/Branding.scss +57 -0
  61. package/src/ui/Branding/Branding.spec.ts +12 -0
  62. package/src/ui/Branding/Branding.stories.jsx +14 -0
  63. package/src/ui/Branding/Branding.stories.tsx +14 -0
  64. package/src/ui/Branding/Branding.test.tsx +1 -0
  65. package/src/ui/Branding/Branding.tsx +6 -0
  66. package/src/ui/Branding/Branding.types.ts +3 -0
  67. package/src/ui/Branding/index.js +1 -0
  68. package/src/ui/Breadcrumb/Breadcrumb.ai.md +50 -0
  69. package/src/ui/Breadcrumb/Breadcrumb.jsx +167 -0
  70. package/src/ui/Breadcrumb/Breadcrumb.scss +46 -0
  71. package/src/ui/Breadcrumb/Breadcrumb.spec.ts +12 -0
  72. package/src/ui/Breadcrumb/Breadcrumb.stories.jsx +26 -0
  73. package/src/ui/Breadcrumb/Breadcrumb.stories.tsx +14 -0
  74. package/src/ui/Breadcrumb/Breadcrumb.test.tsx +1 -0
  75. package/src/ui/Breadcrumb/Breadcrumb.tsx +6 -0
  76. package/src/ui/Breadcrumb/Breadcrumb.types.ts +3 -0
  77. package/src/ui/Breadcrumb/index.js +2 -0
  78. package/src/ui/Button/Button.ai.md +122 -0
  79. package/src/ui/Button/Button.figma.tsx +49 -0
  80. package/src/ui/Button/Button.scss +188 -0
  81. package/src/ui/Button/Button.spec.ts +52 -0
  82. package/src/ui/Button/Button.stories.tsx +199 -0
  83. package/src/ui/Button/Button.test.tsx +85 -0
  84. package/src/ui/Button/Button.tsx +131 -0
  85. package/src/ui/Button/Button.types.ts +32 -0
  86. package/src/ui/Button/index.js +1 -0
  87. package/src/ui/Calendar/Calendar.ai.md +151 -0
  88. package/src/ui/Calendar/Calendar.jsx +504 -0
  89. package/src/ui/Calendar/Calendar.scss +451 -0
  90. package/src/ui/Calendar/Calendar.spec.ts +12 -0
  91. package/src/ui/Calendar/Calendar.stories.jsx +14 -0
  92. package/src/ui/Calendar/Calendar.stories.tsx +14 -0
  93. package/src/ui/Calendar/Calendar.test.tsx +1 -0
  94. package/src/ui/Calendar/Calendar.tsx +6 -0
  95. package/src/ui/Calendar/Calendar.types.ts +3 -0
  96. package/src/ui/Calendar/index.js +1 -0
  97. package/src/ui/Card/Card.ai.md +41 -0
  98. package/src/ui/Card/Card.jsx +25 -0
  99. package/src/ui/Card/Card.scss +47 -0
  100. package/src/ui/Card/Card.spec.ts +12 -0
  101. package/src/ui/Card/Card.stories.jsx +28 -0
  102. package/src/ui/Card/Card.stories.tsx +14 -0
  103. package/src/ui/Card/Card.test.tsx +1 -0
  104. package/src/ui/Card/Card.tsx +6 -0
  105. package/src/ui/Card/Card.types.ts +3 -0
  106. package/src/ui/Card/index.js +1 -0
  107. package/src/ui/Checkbox/Checkbox.ai.md +50 -0
  108. package/src/ui/Checkbox/Checkbox.jsx +73 -0
  109. package/src/ui/Checkbox/Checkbox.scss +115 -0
  110. package/src/ui/Checkbox/Checkbox.spec.ts +12 -0
  111. package/src/ui/Checkbox/Checkbox.stories.jsx +14 -0
  112. package/src/ui/Checkbox/Checkbox.stories.tsx +14 -0
  113. package/src/ui/Checkbox/Checkbox.test.tsx +1 -0
  114. package/src/ui/Checkbox/Checkbox.tsx +6 -0
  115. package/src/ui/Checkbox/Checkbox.types.ts +3 -0
  116. package/src/ui/Checkbox/index.js +1 -0
  117. package/src/ui/Chip/Chip.ai.md +43 -0
  118. package/src/ui/Chip/Chip.jsx +102 -0
  119. package/src/ui/Chip/Chip.scss +118 -0
  120. package/src/ui/Chip/Chip.spec.ts +12 -0
  121. package/src/ui/Chip/Chip.stories.jsx +14 -0
  122. package/src/ui/Chip/Chip.stories.tsx +14 -0
  123. package/src/ui/Chip/Chip.test.tsx +1 -0
  124. package/src/ui/Chip/Chip.tsx +6 -0
  125. package/src/ui/Chip/Chip.types.ts +3 -0
  126. package/src/ui/Chip/index.js +1 -0
  127. package/src/ui/Datepicker/Datepicker.ai.md +45 -0
  128. package/src/ui/Datepicker/Datepicker.jsx +330 -0
  129. package/src/ui/Datepicker/Datepicker.scss +206 -0
  130. package/src/ui/Datepicker/Datepicker.spec.ts +12 -0
  131. package/src/ui/Datepicker/Datepicker.stories.jsx +14 -0
  132. package/src/ui/Datepicker/Datepicker.stories.tsx +14 -0
  133. package/src/ui/Datepicker/Datepicker.test.tsx +1 -0
  134. package/src/ui/Datepicker/Datepicker.tsx +6 -0
  135. package/src/ui/Datepicker/Datepicker.types.ts +3 -0
  136. package/src/ui/Datepicker/index.js +2 -0
  137. package/src/ui/Divider/Divider.ai.md +34 -0
  138. package/src/ui/Divider/Divider.jsx +89 -0
  139. package/src/ui/Divider/Divider.scss +116 -0
  140. package/src/ui/Divider/Divider.spec.ts +12 -0
  141. package/src/ui/Divider/Divider.stories.jsx +14 -0
  142. package/src/ui/Divider/Divider.stories.tsx +14 -0
  143. package/src/ui/Divider/Divider.test.tsx +1 -0
  144. package/src/ui/Divider/Divider.tsx +6 -0
  145. package/src/ui/Divider/Divider.types.ts +3 -0
  146. package/src/ui/Divider/index.js +1 -0
  147. package/src/ui/DotStatus/DotStatus.ai.md +36 -0
  148. package/src/ui/DotStatus/DotStatus.jsx +64 -0
  149. package/src/ui/DotStatus/DotStatus.scss +87 -0
  150. package/src/ui/DotStatus/DotStatus.spec.ts +12 -0
  151. package/src/ui/DotStatus/DotStatus.stories.jsx +14 -0
  152. package/src/ui/DotStatus/DotStatus.stories.tsx +14 -0
  153. package/src/ui/DotStatus/DotStatus.test.tsx +1 -0
  154. package/src/ui/DotStatus/DotStatus.tsx +6 -0
  155. package/src/ui/DotStatus/DotStatus.types.ts +3 -0
  156. package/src/ui/DotStatus/index.js +1 -0
  157. package/src/ui/Dropdown/Dropdown.ai.md +118 -0
  158. package/src/ui/Dropdown/Dropdown.scss +129 -0
  159. package/src/ui/Dropdown/Dropdown.spec.ts +54 -0
  160. package/src/ui/Dropdown/Dropdown.stories.tsx +59 -0
  161. package/src/ui/Dropdown/Dropdown.test.tsx +37 -0
  162. package/src/ui/Dropdown/Dropdown.tsx +119 -0
  163. package/src/ui/Dropdown/Dropdown.types.ts +25 -0
  164. package/src/ui/Dropdown/index.js +1 -0
  165. package/src/ui/EventCard/EventCard.ai.md +101 -0
  166. package/src/ui/EventCard/EventCard.jsx +92 -0
  167. package/src/ui/EventCard/EventCard.scss +186 -0
  168. package/src/ui/EventCard/EventCard.spec.ts +12 -0
  169. package/src/ui/EventCard/EventCard.stories.jsx +14 -0
  170. package/src/ui/EventCard/EventCard.stories.tsx +14 -0
  171. package/src/ui/EventCard/EventCard.test.tsx +1 -0
  172. package/src/ui/EventCard/EventCard.tsx +6 -0
  173. package/src/ui/EventCard/EventCard.types.ts +3 -0
  174. package/src/ui/EventCard/index.js +1 -0
  175. package/src/ui/Field/Field.ai.md +69 -0
  176. package/src/ui/Field/Field.jsx +89 -0
  177. package/src/ui/Field/Field.scss +76 -0
  178. package/src/ui/Field/Field.spec.ts +12 -0
  179. package/src/ui/Field/Field.stories.jsx +14 -0
  180. package/src/ui/Field/Field.stories.tsx +14 -0
  181. package/src/ui/Field/Field.test.tsx +1 -0
  182. package/src/ui/Field/Field.tsx +6 -0
  183. package/src/ui/Field/Field.types.ts +3 -0
  184. package/src/ui/Field/index.js +1 -0
  185. package/src/ui/FileUpload/FileUpload.ai.md +38 -0
  186. package/src/ui/FileUpload/FileUpload.figma.tsx +28 -0
  187. package/src/ui/FileUpload/FileUpload.jsx +153 -0
  188. package/src/ui/FileUpload/FileUpload.scss +78 -0
  189. package/src/ui/FileUpload/FileUpload.spec.ts +12 -0
  190. package/src/ui/FileUpload/FileUpload.stories.jsx +14 -0
  191. package/src/ui/FileUpload/FileUpload.stories.tsx +14 -0
  192. package/src/ui/FileUpload/FileUpload.test.tsx +1 -0
  193. package/src/ui/FileUpload/FileUpload.tsx +6 -0
  194. package/src/ui/FileUpload/FileUpload.types.ts +3 -0
  195. package/src/ui/FileUpload/index.js +2 -0
  196. package/src/ui/Flex/Flex.ai.md +130 -0
  197. package/src/ui/Flex/Flex.jsx +53 -0
  198. package/src/ui/Flex/Flex.scss +119 -0
  199. package/src/ui/Flex/Flex.spec.ts +12 -0
  200. package/src/ui/Flex/Flex.stories.jsx +14 -0
  201. package/src/ui/Flex/Flex.stories.tsx +14 -0
  202. package/src/ui/Flex/Flex.test.tsx +1 -0
  203. package/src/ui/Flex/Flex.tsx +6 -0
  204. package/src/ui/Flex/Flex.types.ts +3 -0
  205. package/src/ui/Flex/index.js +1 -0
  206. package/src/ui/Icon/Icon.ai.md +46 -0
  207. package/src/ui/Icon/Icon.figma.tsx +22 -0
  208. package/src/ui/Icon/Icon.jsx +47 -0
  209. package/src/ui/Icon/Icon.scss +1 -0
  210. package/src/ui/Icon/Icon.spec.ts +12 -0
  211. package/src/ui/Icon/Icon.stories.jsx +14 -0
  212. package/src/ui/Icon/Icon.stories.tsx +14 -0
  213. package/src/ui/Icon/Icon.test.tsx +1 -0
  214. package/src/ui/Icon/Icon.tsx +6 -0
  215. package/src/ui/Icon/Icon.types.ts +3 -0
  216. package/src/ui/Icon/index.js +1 -0
  217. package/src/ui/ImageAspect/ImageAspect.ai.md +37 -0
  218. package/src/ui/ImageAspect/ImageAspect.jsx +56 -0
  219. package/src/ui/ImageAspect/ImageAspect.scss +62 -0
  220. package/src/ui/ImageAspect/ImageAspect.spec.ts +12 -0
  221. package/src/ui/ImageAspect/ImageAspect.stories.jsx +14 -0
  222. package/src/ui/ImageAspect/ImageAspect.stories.tsx +14 -0
  223. package/src/ui/ImageAspect/ImageAspect.test.tsx +1 -0
  224. package/src/ui/ImageAspect/ImageAspect.tsx +6 -0
  225. package/src/ui/ImageAspect/ImageAspect.types.ts +3 -0
  226. package/src/ui/ImageAspect/index.js +1 -0
  227. package/src/ui/Input/Input.ai.md +89 -0
  228. package/src/ui/Input/Input.figma.tsx +35 -0
  229. package/src/ui/Input/Input.scss +126 -0
  230. package/src/ui/Input/Input.spec.ts +54 -0
  231. package/src/ui/Input/Input.stories.tsx +72 -0
  232. package/src/ui/Input/Input.test.tsx +70 -0
  233. package/src/ui/Input/Input.tsx +91 -0
  234. package/src/ui/Input/Input.types.ts +22 -0
  235. package/src/ui/Input/index.js +2 -0
  236. package/src/ui/Key/Key.ai.md +31 -0
  237. package/src/ui/Key/Key.jsx +37 -0
  238. package/src/ui/Key/Key.scss +31 -0
  239. package/src/ui/Key/Key.spec.ts +12 -0
  240. package/src/ui/Key/Key.stories.jsx +14 -0
  241. package/src/ui/Key/Key.stories.tsx +14 -0
  242. package/src/ui/Key/Key.test.tsx +1 -0
  243. package/src/ui/Key/Key.tsx +6 -0
  244. package/src/ui/Key/Key.types.ts +3 -0
  245. package/src/ui/Key/index.js +1 -0
  246. package/src/ui/Menu/Menu.jsx +232 -0
  247. package/src/ui/Menu/Menu.scss +370 -0
  248. package/src/ui/Menu/Menu.spec.ts +12 -0
  249. package/src/ui/Menu/Menu.stories.jsx +41 -0
  250. package/src/ui/Menu/Menu.stories.tsx +14 -0
  251. package/src/ui/Menu/Menu.test.tsx +1 -0
  252. package/src/ui/Menu/Menu.tsx +6 -0
  253. package/src/ui/Menu/Menu.types.ts +3 -0
  254. package/src/ui/Menu/index.js +1 -0
  255. package/src/ui/MicroCalendar/MicroCalendar.ai.md +35 -0
  256. package/src/ui/MicroCalendar/MicroCalendar.jsx +393 -0
  257. package/src/ui/MicroCalendar/MicroCalendar.scss +289 -0
  258. package/src/ui/MicroCalendar/MicroCalendar.spec.ts +12 -0
  259. package/src/ui/MicroCalendar/MicroCalendar.stories.jsx +14 -0
  260. package/src/ui/MicroCalendar/MicroCalendar.stories.tsx +14 -0
  261. package/src/ui/MicroCalendar/MicroCalendar.test.tsx +1 -0
  262. package/src/ui/MicroCalendar/MicroCalendar.tsx +6 -0
  263. package/src/ui/MicroCalendar/MicroCalendar.types.ts +3 -0
  264. package/src/ui/MicroCalendar/index.js +1 -0
  265. package/src/ui/Modal/Modal.ai.md +150 -0
  266. package/src/ui/Modal/Modal.jsx +173 -0
  267. package/src/ui/Modal/Modal.scss +179 -0
  268. package/src/ui/Modal/Modal.spec.ts +12 -0
  269. package/src/ui/Modal/Modal.stories.jsx +14 -0
  270. package/src/ui/Modal/Modal.stories.tsx +14 -0
  271. package/src/ui/Modal/Modal.test.tsx +1 -0
  272. package/src/ui/Modal/Modal.tsx +6 -0
  273. package/src/ui/Modal/Modal.types.ts +3 -0
  274. package/src/ui/Modal/index.js +1 -0
  275. package/src/ui/Pagination/Pagination.ai.md +30 -0
  276. package/src/ui/Pagination/Pagination.jsx +237 -0
  277. package/src/ui/Pagination/Pagination.scss +182 -0
  278. package/src/ui/Pagination/Pagination.spec.ts +12 -0
  279. package/src/ui/Pagination/Pagination.stories.jsx +14 -0
  280. package/src/ui/Pagination/Pagination.stories.tsx +14 -0
  281. package/src/ui/Pagination/Pagination.test.tsx +1 -0
  282. package/src/ui/Pagination/Pagination.tsx +6 -0
  283. package/src/ui/Pagination/Pagination.types.ts +3 -0
  284. package/src/ui/Pagination/index.js +1 -0
  285. package/src/ui/PillToggle/PillToggle.ai.md +44 -0
  286. package/src/ui/PillToggle/PillToggle.jsx +56 -0
  287. package/src/ui/PillToggle/PillToggle.scss +84 -0
  288. package/src/ui/PillToggle/PillToggle.spec.ts +12 -0
  289. package/src/ui/PillToggle/PillToggle.stories.jsx +14 -0
  290. package/src/ui/PillToggle/PillToggle.stories.tsx +14 -0
  291. package/src/ui/PillToggle/PillToggle.test.tsx +1 -0
  292. package/src/ui/PillToggle/PillToggle.tsx +6 -0
  293. package/src/ui/PillToggle/PillToggle.types.ts +3 -0
  294. package/src/ui/PillToggle/index.js +1 -0
  295. package/src/ui/Playground/Playground.ai.md +96 -0
  296. package/src/ui/Playground/Playground.jsx +524 -0
  297. package/src/ui/Playground/Playground.scss +310 -0
  298. package/src/ui/Playground/Playground.spec.ts +12 -0
  299. package/src/ui/Playground/Playground.stories.jsx +14 -0
  300. package/src/ui/Playground/Playground.stories.tsx +14 -0
  301. package/src/ui/Playground/Playground.test.tsx +1 -0
  302. package/src/ui/Playground/Playground.tsx +6 -0
  303. package/src/ui/Playground/Playground.types.ts +3 -0
  304. package/src/ui/Playground/index.js +2 -0
  305. package/src/ui/ProgressCircle/ProgressCircle.ai.md +36 -0
  306. package/src/ui/ProgressCircle/ProgressCircle.jsx +147 -0
  307. package/src/ui/ProgressCircle/ProgressCircle.scss +143 -0
  308. package/src/ui/ProgressCircle/ProgressCircle.spec.ts +12 -0
  309. package/src/ui/ProgressCircle/ProgressCircle.stories.jsx +14 -0
  310. package/src/ui/ProgressCircle/ProgressCircle.stories.tsx +14 -0
  311. package/src/ui/ProgressCircle/ProgressCircle.test.tsx +1 -0
  312. package/src/ui/ProgressCircle/ProgressCircle.tsx +6 -0
  313. package/src/ui/ProgressCircle/ProgressCircle.types.ts +3 -0
  314. package/src/ui/ProgressCircle/index.js +1 -0
  315. package/src/ui/ProgressIndicator/ProgressIndicator.ai.md +27 -0
  316. package/src/ui/ProgressIndicator/ProgressIndicator.jsx +92 -0
  317. package/src/ui/ProgressIndicator/ProgressIndicator.scss +133 -0
  318. package/src/ui/ProgressIndicator/ProgressIndicator.spec.ts +12 -0
  319. package/src/ui/ProgressIndicator/ProgressIndicator.stories.jsx +14 -0
  320. package/src/ui/ProgressIndicator/ProgressIndicator.stories.tsx +14 -0
  321. package/src/ui/ProgressIndicator/ProgressIndicator.test.tsx +1 -0
  322. package/src/ui/ProgressIndicator/ProgressIndicator.tsx +6 -0
  323. package/src/ui/ProgressIndicator/ProgressIndicator.types.ts +3 -0
  324. package/src/ui/ProgressIndicator/index.js +1 -0
  325. package/src/ui/Radio/Radio.ai.md +53 -0
  326. package/src/ui/Radio/Radio.jsx +57 -0
  327. package/src/ui/Radio/Radio.scss +89 -0
  328. package/src/ui/Radio/Radio.spec.ts +12 -0
  329. package/src/ui/Radio/Radio.stories.jsx +14 -0
  330. package/src/ui/Radio/Radio.stories.tsx +14 -0
  331. package/src/ui/Radio/Radio.test.tsx +1 -0
  332. package/src/ui/Radio/Radio.tsx +6 -0
  333. package/src/ui/Radio/Radio.types.ts +3 -0
  334. package/src/ui/Radio/index.js +1 -0
  335. package/src/ui/Slider/Slider.ai.md +33 -0
  336. package/src/ui/Slider/Slider.jsx +283 -0
  337. package/src/ui/Slider/Slider.scss +156 -0
  338. package/src/ui/Slider/Slider.spec.ts +12 -0
  339. package/src/ui/Slider/Slider.stories.jsx +14 -0
  340. package/src/ui/Slider/Slider.stories.tsx +14 -0
  341. package/src/ui/Slider/Slider.test.tsx +1 -0
  342. package/src/ui/Slider/Slider.tsx +6 -0
  343. package/src/ui/Slider/Slider.types.ts +3 -0
  344. package/src/ui/Slider/index.js +1 -0
  345. package/src/ui/Status/Status.ai.md +36 -0
  346. package/src/ui/Status/Status.jsx +66 -0
  347. package/src/ui/Status/Status.scss +90 -0
  348. package/src/ui/Status/Status.spec.ts +12 -0
  349. package/src/ui/Status/Status.stories.jsx +14 -0
  350. package/src/ui/Status/Status.stories.tsx +14 -0
  351. package/src/ui/Status/Status.test.tsx +1 -0
  352. package/src/ui/Status/Status.tsx +6 -0
  353. package/src/ui/Status/Status.types.ts +3 -0
  354. package/src/ui/Status/index.js +1 -0
  355. package/src/ui/Steps/Steps.ai.md +56 -0
  356. package/src/ui/Steps/Steps.jsx +201 -0
  357. package/src/ui/Steps/Steps.scss +240 -0
  358. package/src/ui/Steps/Steps.spec.ts +12 -0
  359. package/src/ui/Steps/Steps.stories.jsx +14 -0
  360. package/src/ui/Steps/Steps.stories.tsx +14 -0
  361. package/src/ui/Steps/Steps.test.tsx +1 -0
  362. package/src/ui/Steps/Steps.tsx +6 -0
  363. package/src/ui/Steps/Steps.types.ts +3 -0
  364. package/src/ui/Steps/index.js +1 -0
  365. package/src/ui/Table/Table.ai.md +108 -0
  366. package/src/ui/Table/Table.jsx +143 -0
  367. package/src/ui/Table/Table.scss +90 -0
  368. package/src/ui/Table/Table.spec.ts +12 -0
  369. package/src/ui/Table/Table.stories.jsx +14 -0
  370. package/src/ui/Table/Table.stories.tsx +14 -0
  371. package/src/ui/Table/Table.test.tsx +1 -0
  372. package/src/ui/Table/Table.tsx +6 -0
  373. package/src/ui/Table/Table.types.ts +3 -0
  374. package/src/ui/Table/index.js +1 -0
  375. package/src/ui/Tabs/TabItem.jsx +80 -0
  376. package/src/ui/Tabs/Tabs.ai.md +52 -0
  377. package/src/ui/Tabs/Tabs.figma.tsx +30 -0
  378. package/src/ui/Tabs/Tabs.jsx +318 -0
  379. package/src/ui/Tabs/Tabs.scss +164 -0
  380. package/src/ui/Tabs/Tabs.spec.ts +12 -0
  381. package/src/ui/Tabs/Tabs.stories.jsx +18 -0
  382. package/src/ui/Tabs/Tabs.stories.tsx +14 -0
  383. package/src/ui/Tabs/Tabs.test.tsx +1 -0
  384. package/src/ui/Tabs/Tabs.tsx +6 -0
  385. package/src/ui/Tabs/Tabs.types.ts +3 -0
  386. package/src/ui/Tabs/index.js +3 -0
  387. package/src/ui/Tag/Tag.ai.md +59 -0
  388. package/src/ui/Tag/Tag.figma.tsx +29 -0
  389. package/src/ui/Tag/Tag.jsx +93 -0
  390. package/src/ui/Tag/Tag.scss +258 -0
  391. package/src/ui/Tag/Tag.spec.ts +12 -0
  392. package/src/ui/Tag/Tag.stories.jsx +14 -0
  393. package/src/ui/Tag/Tag.stories.tsx +14 -0
  394. package/src/ui/Tag/Tag.test.tsx +1 -0
  395. package/src/ui/Tag/Tag.tsx +6 -0
  396. package/src/ui/Tag/Tag.types.ts +3 -0
  397. package/src/ui/Tag/index.js +2 -0
  398. package/src/ui/Textarea/Textarea.ai.md +40 -0
  399. package/src/ui/Textarea/Textarea.figma.tsx +35 -0
  400. package/src/ui/Textarea/Textarea.jsx +68 -0
  401. package/src/ui/Textarea/Textarea.scss +71 -0
  402. package/src/ui/Textarea/Textarea.spec.ts +12 -0
  403. package/src/ui/Textarea/Textarea.stories.jsx +14 -0
  404. package/src/ui/Textarea/Textarea.stories.tsx +14 -0
  405. package/src/ui/Textarea/Textarea.test.tsx +1 -0
  406. package/src/ui/Textarea/Textarea.tsx +6 -0
  407. package/src/ui/Textarea/Textarea.types.ts +3 -0
  408. package/src/ui/Textarea/index.js +2 -0
  409. package/src/ui/Toast/Toast.ai.md +47 -0
  410. package/src/ui/Toast/Toast.jsx +75 -0
  411. package/src/ui/Toast/Toast.scss +132 -0
  412. package/src/ui/Toast/Toast.spec.ts +12 -0
  413. package/src/ui/Toast/Toast.stories.jsx +14 -0
  414. package/src/ui/Toast/Toast.stories.tsx +14 -0
  415. package/src/ui/Toast/Toast.test.tsx +1 -0
  416. package/src/ui/Toast/Toast.tsx +6 -0
  417. package/src/ui/Toast/Toast.types.ts +3 -0
  418. package/src/ui/Toast/index.js +2 -0
  419. package/src/ui/Toggle/Toggle.ai.md +37 -0
  420. package/src/ui/Toggle/Toggle.jsx +73 -0
  421. package/src/ui/Toggle/Toggle.scss +139 -0
  422. package/src/ui/Toggle/Toggle.spec.ts +12 -0
  423. package/src/ui/Toggle/Toggle.stories.jsx +14 -0
  424. package/src/ui/Toggle/Toggle.stories.tsx +14 -0
  425. package/src/ui/Toggle/Toggle.test.tsx +1 -0
  426. package/src/ui/Toggle/Toggle.tsx +6 -0
  427. package/src/ui/Toggle/Toggle.types.ts +3 -0
  428. package/src/ui/Toggle/index.js +1 -0
  429. package/src/ui/Tooltip/Tooltip.ai.md +33 -0
  430. package/src/ui/Tooltip/Tooltip.figma.tsx +24 -0
  431. package/src/ui/Tooltip/Tooltip.jsx +125 -0
  432. package/src/ui/Tooltip/Tooltip.scss +80 -0
  433. package/src/ui/Tooltip/Tooltip.spec.ts +12 -0
  434. package/src/ui/Tooltip/Tooltip.stories.jsx +14 -0
  435. package/src/ui/Tooltip/Tooltip.stories.tsx +14 -0
  436. package/src/ui/Tooltip/Tooltip.test.tsx +1 -0
  437. package/src/ui/Tooltip/Tooltip.tsx +6 -0
  438. package/src/ui/Tooltip/Tooltip.types.ts +3 -0
  439. package/src/ui/Tooltip/index.js +2 -0
  440. package/src/ui/UDS/UDS.jsx +52 -0
  441. package/src/ui/UDS/UDS.scss +49 -0
  442. package/src/ui/UDS/UDS.spec.ts +12 -0
  443. package/src/ui/UDS/UDS.stories.jsx +22 -0
  444. package/src/ui/UDS/UDS.stories.tsx +14 -0
  445. package/src/ui/UDS/UDS.test.tsx +1 -0
  446. package/src/ui/UDS/UDS.tsx +6 -0
  447. package/src/ui/UDS/UDS.types.ts +3 -0
  448. package/src/ui/UDS/index.js +1 -0
  449. package/src/ui/_spec/createMetaFromSpec.ts +35 -0
  450. package/src/ui/_spec/createStoryArgsFromSpec.ts +8 -0
  451. package/src/ui/_spec/generated/spec-props-reference.md +55 -0
  452. package/src/ui/_spec/specStorySync.test.ts +73 -0
  453. package/src/ui/_spec/types.ts +21 -0
  454. package/src/ui/index.js +66 -0
@@ -0,0 +1,122 @@
1
+ # Button
2
+
3
+ Primary action trigger component supporting multiple visual styles, sizes, and icon layouts.
4
+
5
+ ## When to Use
6
+ - Triggering actions (submit, save, delete, navigate)
7
+ - Primary CTA buttons, secondary actions, destructive confirmations
8
+ - Icon-only actions in toolbars or compact UIs
9
+
10
+ ## Props
11
+
12
+ | Prop | Type | Default | Values | Description |
13
+ |------|------|---------|--------|-------------|
14
+ | `label` | `string` | — | Any text | Button text label |
15
+ | `appearance` | `string` | `"primary"` | `"primary"`, `"soft"`, `"outline"`, `"text"`, `"ghost"`, `"disabled"`, `"destructive"` | Visual style variant |
16
+ | `layout` | `string` | `"label-only"` | `"label-only"`, `"icon-left"`, `"icon-right"`, `"icon-only"`, `"only"` | Content arrangement |
17
+ | `size` | `string` | `"default"` | `"large"`, `"default"`, `"small"`, `"xsmall"` | Button size |
18
+ | `icon` | `string` or `ReactNode` | — | Phosphor icon name (e.g., `"ArrowRight"`, `"Plus"`, `"Trash"`) or JSX | Icon to display |
19
+ | `iconSize` | `number` | — | Any number | Override icon size in px |
20
+ | `className` | `string` | `""` | Any CSS class | Additional CSS classes |
21
+ | `tracking` | `string` or `object` | — | `"event-name"` or `{ event, category, ... }` | Fires a `uds:track` CustomEvent on click with a structured payload |
22
+ | `onClick` | `function` | — | — | Click handler |
23
+ | `disabled` | `boolean` | `false` | — | Disables the button |
24
+ | `aria-label` | `string` | — | — | Accessible label (auto-generated for icon-only) |
25
+
26
+ ## Examples
27
+
28
+ ### Basic buttons
29
+ ```jsx
30
+ <Button label="Save" />
31
+ <Button label="Cancel" appearance="outline" />
32
+ <Button label="Delete" appearance="destructive" />
33
+ ```
34
+
35
+ ### With icons
36
+ ```jsx
37
+ <Button label="Add Item" icon="Plus" layout="icon-left" />
38
+ <Button label="Next" icon="ArrowRight" layout="icon-right" />
39
+ <Button icon="Trash" layout="icon-only" aria-label="Delete item" />
40
+ ```
41
+
42
+ ### Size variants
43
+ ```jsx
44
+ <Button label="Large" size="large" />
45
+ <Button label="Default" />
46
+ <Button label="Small" size="small" />
47
+ <Button label="XSmall" size="xsmall" />
48
+ ```
49
+
50
+ ### All appearances
51
+ ```jsx
52
+ <Button label="Primary" appearance="primary" />
53
+ <Button label="Soft" appearance="soft" />
54
+ <Button label="Outline" appearance="outline" />
55
+ <Button label="Text" appearance="text" />
56
+ <Button label="Ghost" appearance="ghost" />
57
+ <Button label="Destructive" appearance="destructive" />
58
+ <Button label="Disabled" appearance="disabled" />
59
+ ```
60
+
61
+ ### Action bar pattern
62
+ ```jsx
63
+ <Flex gap="8" justifyContent="flex-end">
64
+ <Button label="Cancel" appearance="outline" onClick={onCancel} />
65
+ <Button label="Save Changes" icon="FloppyDisk" layout="icon-left" onClick={onSave} />
66
+ </Flex>
67
+ ```
68
+
69
+ ### Toolbar with icon-only buttons
70
+ ```jsx
71
+ <Flex gap="4">
72
+ <Button icon="TextB" layout="icon-only" appearance="ghost" aria-label="Bold" />
73
+ <Button icon="TextItalic" layout="icon-only" appearance="ghost" aria-label="Italic" />
74
+ <Button icon="TextUnderline" layout="icon-only" appearance="ghost" aria-label="Underline" />
75
+ </Flex>
76
+ ```
77
+
78
+ ### Data tracking
79
+ ```jsx
80
+ // Simple string event name
81
+ <Button label="Sign Up" tracking="signup-cta" onClick={handleSignUp} />
82
+
83
+ // Rich payload — all fields are merged into the CustomEvent detail
84
+ <Button
85
+ label="Add to Cart"
86
+ icon="ShoppingCart"
87
+ layout="icon-left"
88
+ tracking={{ event: "add_to_cart", category: "ecommerce", productId: "widget-123" }}
89
+ onClick={handleAddToCart}
90
+ />
91
+
92
+ // Subscribe in your app root
93
+ useEffect(() => {
94
+ const handler = (e) => analytics.track(e.detail.event ?? e.detail.action, e.detail);
95
+ window.addEventListener("uds:track", handler);
96
+ return () => window.removeEventListener("uds:track", handler);
97
+ }, []);
98
+ ```
99
+
100
+ ## Composition
101
+
102
+ - **In forms**: Place at the bottom of form sections, typically paired with a cancel button
103
+ - **In `Card`**: Use in card footer for card-level actions
104
+ - **In `UDS.PageHeader`**: Pass as `actions` prop for page-level actions
105
+ - **In `Table` rows**: Use `size="xsmall"` or `"small"` with `appearance="ghost"` for inline row actions
106
+ - **In `UDS.Modal` footer**: Primary + secondary action buttons
107
+
108
+ ## Do's and Don'ts
109
+
110
+ ✅ **Do**: Use `appearance="destructive"` for delete/remove actions
111
+ ✅ **Do**: Always provide `aria-label` for icon-only buttons
112
+ ✅ **Do**: Use `icon` prop with a Phosphor icon name string (e.g., `icon="Plus"`)
113
+ ✅ **Do**: Use `layout="icon-left"` for action buttons with context (e.g., "Add User")
114
+
115
+ ❌ **Don't**: Use `appearance="disabled"` for conditional disabling — use the `disabled` prop instead
116
+ ❌ **Don't**: Use `appearance="primary"` for every button — reserve for the main page action
117
+ ❌ **Don't**: Nest interactive elements inside Button
118
+
119
+ ## Accessibility
120
+ - Icon-only buttons automatically get `aria-label` from the `label` prop or icon name
121
+ - Disabled buttons use native `disabled` attribute
122
+ - Renders as `<button type="button">` by default
@@ -0,0 +1,49 @@
1
+ import React from "react"
2
+ import Button from "./Button"
3
+ import figma from "@figma/code-connect"
4
+
5
+ /**
6
+ * -- This file was auto-generated by Code Connect --
7
+ * `props` includes a mapping from Figma properties and variants to
8
+ * suggested values. You should update this to match the props of your
9
+ * code component, and update the `example` function to return the
10
+ * code example you'd like to see in Figma
11
+ */
12
+
13
+ figma.connect(
14
+ Button,
15
+ "https://www.figma.com/file/LkIyThUA0oVNsDEAyOF7ER/Design-System--Components?node-id=19%3A360",
16
+ {
17
+ props: {
18
+ label: figma.string("Label"),
19
+ appearance: figma.enum("Appearance", {
20
+ Primary: "primary",
21
+ Soft: "soft",
22
+ Disabled: "disabled",
23
+ Outline: "outline",
24
+ "Ghost+": "ghost-",
25
+ Destructive: "destructive",
26
+ Ghost: "ghost",
27
+ }),
28
+ layout: figma.enum("Layout", {
29
+ "Label Only": "label-only",
30
+ "Icon Right": "icon-right",
31
+ "Icon Left": "icon-left",
32
+ "Icon Only": "icon-only",
33
+ }),
34
+ state: figma.enum("State", {
35
+ Default: "default",
36
+ Focus: "focus",
37
+ Hover: "hover",
38
+ }),
39
+ size: figma.enum("Size", {
40
+ XSmall: "xsmall",
41
+ Large: "large",
42
+ Default: "default",
43
+ Small: "small",
44
+ }),
45
+ onDark: figma.boolean("On Dark"),
46
+ },
47
+ example: (props) => <Button />,
48
+ },
49
+ )
@@ -0,0 +1,188 @@
1
+ @use "../../styles/typography" as *;
2
+
3
+ .uds-button {
4
+ all: unset;
5
+ @include uds-body-16-semibold;
6
+ align-items: center;
7
+ background: var(--uds-button-surface-primary-default);
8
+ border: var(--uds-border-width-1) solid var(--uds-button-border-primary-default);
9
+ border-radius: var(--uds-radius-4);
10
+ box-sizing: border-box;
11
+ color: var(--uds-button-text-default);
12
+ cursor: pointer;
13
+ display: inline-flex;
14
+ justify-content: center;
15
+ gap: var(--uds-gap-4);
16
+ height: fit-content;
17
+ padding-inline: var(--uds-spacing-16);
18
+ padding-block: var(--uds-spacing-10);
19
+ text-transform: capitalize;
20
+ width: fit-content;
21
+ transition: all var(--uds-animation-duration-200) var(--uds-animation-ease-standard);
22
+
23
+ &:hover:not(:disabled) {
24
+ background: var(--uds-button-surface-primary-hover);
25
+ border-color: var(--uds-button-border-primary-hover);
26
+ color: var(--uds-button-text-default);
27
+ }
28
+
29
+ &__icon {
30
+ display: inline-flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ line-height: 0;
34
+
35
+ svg {
36
+ width: 20px;
37
+ height: 20px;
38
+ flex-shrink: 0;
39
+ }
40
+ }
41
+
42
+ &__label {
43
+ display: inline-block;
44
+ padding: 0 var(--uds-spacing-4);
45
+ white-space: nowrap;
46
+ }
47
+
48
+ &:focus-visible {
49
+ outline: solid var(--uds-focus-ring-width) var(--uds-focus-ring-border);
50
+ outline-offset: var(--uds-focus-ring-offset);
51
+ }
52
+
53
+ &.large {
54
+ @include uds-body-20-semibold;
55
+ padding: var(--uds-spacing-12) var(--uds-spacing-18);
56
+
57
+ .uds-button__icon svg {
58
+ width: 24px;
59
+ height: 24px;
60
+ }
61
+ }
62
+
63
+ &.small {
64
+ @include uds-body-14-semibold;
65
+ padding: var(--uds-spacing-8) var(--uds-spacing-12);
66
+
67
+ .uds-button__icon svg {
68
+ width: 16px;
69
+ height: 16px;
70
+ }
71
+ }
72
+
73
+ &.xsmall {
74
+ @include uds-body-12-semibold;
75
+ padding: var(--uds-spacing-8) var(--uds-spacing-10);
76
+
77
+ .uds-button__icon svg {
78
+ width: 16px;
79
+ height: 16px;
80
+ }
81
+ }
82
+
83
+ &.icon {
84
+ &-only {
85
+ padding: var(--uds-spacing-12);
86
+
87
+ &.large {
88
+ padding: var(--uds-spacing-14);
89
+
90
+ .uds-button__icon svg {
91
+ width: 24px;
92
+ height: 24px;
93
+ }
94
+ }
95
+
96
+ &.small {
97
+ padding: var(--uds-spacing-10);
98
+
99
+ .uds-button__icon svg {
100
+ width: 16px;
101
+ height: 16px;
102
+ }
103
+ }
104
+
105
+ &.xsmall {
106
+ padding: var(--uds-spacing-8);
107
+
108
+ .uds-button__icon svg {
109
+ width: 16px;
110
+ height: 16px;
111
+ }
112
+ }
113
+ }
114
+ }
115
+
116
+ &.soft {
117
+ background: var(--uds-button-surface-secondary-default);
118
+ border-color: var(--uds-button-border-secondary-default);
119
+ color: var(--uds-button-text-secondary);
120
+
121
+ &:hover:not(:disabled) {
122
+ background: var(--uds-button-surface-secondary-hover);
123
+ border-color: var(--uds-button-border-secondary-hover);
124
+ color: var(--uds-button-text-secondary);
125
+ }
126
+ }
127
+
128
+ &.outline {
129
+ background: var(--uds-color-transparent);
130
+ border: solid 1px var(--uds-border-primary);
131
+ color: var(--uds-text-primary);
132
+
133
+ &:hover:not(:disabled) {
134
+ background: var(--uds-color-transparent);
135
+ border-color: var(--uds-border-brand-primary);
136
+ color: var(--uds-text-primary);
137
+ }
138
+ }
139
+
140
+ &.text {
141
+ background: var(--uds-surface-transparent);
142
+ color: var(--uds-text-primary);
143
+ border-color: var(--uds-border-transparent);
144
+
145
+ &:hover:not(:disabled) {
146
+ background: var(--uds-surface-transparent);
147
+ color: var(--uds-text-brand-primary);
148
+ border-color: var(--uds-border-transparent);
149
+ }
150
+ }
151
+
152
+ &.ghost {
153
+ background: var(--uds-surface-transparent);
154
+ color: var(--uds-text-brand-primary);
155
+ border-color: var(--uds-border-transparent);
156
+
157
+ &:hover:not(:disabled) {
158
+ background: var(--uds-surface-transparent);
159
+ color: var(--uds-text-brand-primary);
160
+ border-color: var(--uds-border-transparent);
161
+ }
162
+ }
163
+
164
+ &.destructive {
165
+ background: var(--uds-button-surface-primary-destructive);
166
+ color: var(--uds-button-text-default);
167
+ border-color: var(--uds-button-border-primary-destructive);
168
+
169
+ &:hover:not(:disabled) {
170
+ background: var(--uds-button-surface-primary-destructive);
171
+ color: var(--uds-button-text-default);
172
+ border-color: var(--uds-button-border-primary-destructive);
173
+ }
174
+ }
175
+
176
+ &.disabled {
177
+ background: var(--uds-button-surface-primary-disabled);
178
+ color: var(--uds-button-text-disabled);
179
+ cursor: not-allowed;
180
+ border-color: var(--uds-button-border-primary-disabled);
181
+ box-shadow: none;
182
+ pointer-events: none;
183
+ }
184
+
185
+ &:disabled {
186
+ cursor: not-allowed;
187
+ }
188
+ }
@@ -0,0 +1,52 @@
1
+ export const BUTTON_LAYOUTS = [
2
+ "label-only",
3
+ "icon-left",
4
+ "icon-right",
5
+ "icon-only",
6
+ "only",
7
+ ] as const;
8
+
9
+ export const BUTTON_APPEARANCES = [
10
+ "primary",
11
+ "soft",
12
+ "outline",
13
+ "text",
14
+ "ghost",
15
+ "disabled",
16
+ "destructive",
17
+ ] as const;
18
+
19
+ export const BUTTON_SIZES = ["large", "default", "small", "xsmall"] as const;
20
+
21
+ export const BUTTON_DEFAULTS = {
22
+ appearance: "primary",
23
+ layout: "label-only",
24
+ size: "default",
25
+ } as const;
26
+
27
+ export const BUTTON_CLASS_MAP = {
28
+ layout: {
29
+ "label-only": "label-only",
30
+ "icon-left": "icon-left",
31
+ "icon-right": "icon-right",
32
+ "icon-only": "icon-only",
33
+ only: "only",
34
+ } as const,
35
+ appearance: {
36
+ primary: "primary",
37
+ soft: "soft",
38
+ outline: "outline",
39
+ text: "text",
40
+ ghost: "ghost",
41
+ disabled: "disabled",
42
+ destructive: "destructive",
43
+ } as const,
44
+ size: {
45
+ large: "large",
46
+ default: "default",
47
+ small: "small",
48
+ xsmall: "xsmall",
49
+ } as const,
50
+ } as const;
51
+
52
+ export const BUTTON_BASE_CLASS = "uds-button";
@@ -0,0 +1,199 @@
1
+ import Button from "./Button";
2
+ import { createStoryArgsFromSpec } from "../_spec/createStoryArgsFromSpec";
3
+ import {
4
+ BUTTON_APPEARANCES,
5
+ BUTTON_DEFAULTS,
6
+ BUTTON_LAYOUTS,
7
+ BUTTON_SIZES,
8
+ } from "./Button.spec";
9
+ import type { StorySpec } from "../_spec/types";
10
+
11
+ type ButtonStoryArgs = {
12
+ label: string;
13
+ icon?: string;
14
+ appearance: (typeof BUTTON_APPEARANCES)[number];
15
+ layout: (typeof BUTTON_LAYOUTS)[number];
16
+ size: (typeof BUTTON_SIZES)[number];
17
+ iconSize?: number;
18
+ disabled?: boolean;
19
+ tracking?: string | Record<string, unknown>;
20
+ "aria-label"?: string;
21
+ };
22
+
23
+ const BUTTON_DEFAULT_ARGS: ButtonStoryArgs = {
24
+ label: "Button",
25
+ icon: "Plus",
26
+ appearance: BUTTON_DEFAULTS.appearance,
27
+ layout: BUTTON_DEFAULTS.layout,
28
+ size: BUTTON_DEFAULTS.size,
29
+ };
30
+
31
+ const BUTTON_STORY_SPEC = {
32
+ defaults: BUTTON_DEFAULT_ARGS,
33
+ options: {
34
+ appearance: BUTTON_APPEARANCES,
35
+ layout: BUTTON_LAYOUTS,
36
+ size: BUTTON_SIZES,
37
+ },
38
+ stories: {
39
+ primary: { label: "Primary", appearance: "primary" },
40
+ soft: { label: "Soft", appearance: "soft" },
41
+ outline: { label: "Outline", appearance: "outline" },
42
+ text: { label: "Text", appearance: "text" },
43
+ ghost: { label: "Ghost", appearance: "ghost" },
44
+ destructive: { label: "Destructive", appearance: "destructive" },
45
+ disabled: { label: "Disabled", appearance: "disabled", disabled: true },
46
+ large: { label: "Large", size: "large" },
47
+ small: { label: "Small", size: "small" },
48
+ xsmall: { label: "XSmall", size: "xsmall" },
49
+ iconLeft: { label: "Add Item", icon: "Plus", layout: "icon-left" },
50
+ iconRight: { label: "Next", icon: "ArrowRight", layout: "icon-right" },
51
+ iconOnly: { icon: "Trash", layout: "icon-only", label: "", "aria-label": "Delete item" },
52
+ customIconSize: {
53
+ label: "Download",
54
+ icon: "DownloadSimple",
55
+ layout: "icon-left",
56
+ iconSize: 24,
57
+ },
58
+ trackingString: {
59
+ label: "Sign Up",
60
+ tracking: "signup-cta",
61
+ },
62
+ trackingObject: {
63
+ label: "Add to Cart",
64
+ icon: "ShoppingCart",
65
+ layout: "icon-left",
66
+ tracking: {
67
+ event: "add_to_cart",
68
+ category: "ecommerce",
69
+ productId: "widget-123",
70
+ },
71
+ },
72
+ } as const,
73
+ } satisfies StorySpec<ButtonStoryArgs>;
74
+
75
+ const fromSpec = createStoryArgsFromSpec<ButtonStoryArgs>(
76
+ BUTTON_STORY_SPEC.defaults,
77
+ );
78
+
79
+ export default {
80
+ title: "Components/Button",
81
+ component: Button,
82
+ tags: ["autodocs"],
83
+ args: BUTTON_STORY_SPEC.defaults,
84
+ argTypes: {
85
+ label: {
86
+ control: "text",
87
+ description: "Button text label",
88
+ },
89
+ tracking: {
90
+ control: "object",
91
+ description:
92
+ 'Analytics payload — string or object. Fires a "uds:track" CustomEvent on click.',
93
+ },
94
+ icon: {
95
+ control: "text",
96
+ description: "Phosphor icon name (e.g. ArrowRight, Plus, Trash)",
97
+ },
98
+ iconSize: {
99
+ control: "number",
100
+ description: "Override icon size in px",
101
+ },
102
+ disabled: {
103
+ control: "boolean",
104
+ description: "Disables the button",
105
+ },
106
+ onClick: {
107
+ action: "clicked",
108
+ description: "Click handler",
109
+ },
110
+ appearance: {
111
+ control: "select",
112
+ options: [...BUTTON_APPEARANCES],
113
+ description: "Visual style variant",
114
+ },
115
+ layout: {
116
+ control: "select",
117
+ options: [...BUTTON_LAYOUTS],
118
+ description: "Content arrangement",
119
+ },
120
+ size: {
121
+ control: "select",
122
+ options: [...BUTTON_SIZES],
123
+ description: "Button size",
124
+ },
125
+ },
126
+ parameters: {
127
+ layout: "centered",
128
+ },
129
+ };
130
+
131
+ export const Default = {
132
+ args: fromSpec({}),
133
+ };
134
+
135
+ export const Primary = {
136
+ args: fromSpec(BUTTON_STORY_SPEC.stories.primary),
137
+ };
138
+
139
+ export const Soft = {
140
+ args: fromSpec(BUTTON_STORY_SPEC.stories.soft),
141
+ };
142
+
143
+ export const Outline = {
144
+ args: fromSpec(BUTTON_STORY_SPEC.stories.outline),
145
+ };
146
+
147
+ export const Text = {
148
+ args: fromSpec(BUTTON_STORY_SPEC.stories.text),
149
+ };
150
+
151
+ export const Ghost = {
152
+ args: fromSpec(BUTTON_STORY_SPEC.stories.ghost),
153
+ };
154
+
155
+ export const Destructive = {
156
+ args: fromSpec(BUTTON_STORY_SPEC.stories.destructive),
157
+ };
158
+
159
+ export const Disabled = {
160
+ args: fromSpec(BUTTON_STORY_SPEC.stories.disabled),
161
+ };
162
+
163
+ export const Large = {
164
+ args: fromSpec(BUTTON_STORY_SPEC.stories.large),
165
+ };
166
+
167
+ export const Small = {
168
+ args: fromSpec(BUTTON_STORY_SPEC.stories.small),
169
+ };
170
+
171
+ export const XSmall = {
172
+ args: fromSpec(BUTTON_STORY_SPEC.stories.xsmall),
173
+ };
174
+
175
+ export const IconLeft = {
176
+ args: fromSpec(BUTTON_STORY_SPEC.stories.iconLeft),
177
+ };
178
+
179
+ export const IconRight = {
180
+ args: fromSpec(BUTTON_STORY_SPEC.stories.iconRight),
181
+ };
182
+
183
+ export const IconOnly = {
184
+ args: fromSpec(BUTTON_STORY_SPEC.stories.iconOnly),
185
+ };
186
+
187
+ export const CustomIconSize = {
188
+ args: fromSpec(BUTTON_STORY_SPEC.stories.customIconSize),
189
+ };
190
+
191
+ export const TrackingString = {
192
+ name: "Tracking (string)",
193
+ args: fromSpec(BUTTON_STORY_SPEC.stories.trackingString),
194
+ };
195
+
196
+ export const TrackingObject = {
197
+ name: "Tracking (object)",
198
+ args: fromSpec(BUTTON_STORY_SPEC.stories.trackingObject),
199
+ };
@@ -0,0 +1,85 @@
1
+ import { describe, test, jest } from "@jest/globals";
2
+ import { render, screen, fireEvent } from "@testing-library/react";
3
+ import Button from "./Button";
4
+ import {
5
+ BUTTON_APPEARANCES,
6
+ BUTTON_DEFAULTS,
7
+ BUTTON_LAYOUTS,
8
+ BUTTON_SIZES,
9
+ } from "./Button.spec";
10
+
11
+ describe("Button spec sync", () => {
12
+ test("renders with spec defaults", () => {
13
+ render(<Button label="Default" />);
14
+ const button = screen.getByRole("button", { name: "Default" });
15
+ expect(button).toHaveClass("uds-button");
16
+ expect(button).not.toHaveClass(BUTTON_DEFAULTS.appearance);
17
+ expect(button).not.toHaveClass(BUTTON_DEFAULTS.layout);
18
+ expect(button).not.toHaveClass(BUTTON_DEFAULTS.size);
19
+ });
20
+
21
+ test("supports all appearance options from spec", () => {
22
+ BUTTON_APPEARANCES.forEach((appearance) => {
23
+ const { unmount } = render(<Button label={appearance} appearance={appearance} />);
24
+ const button = screen.getByRole("button", { name: appearance });
25
+ if (appearance === BUTTON_DEFAULTS.appearance) {
26
+ expect(button).not.toHaveClass(appearance);
27
+ } else {
28
+ expect(button).toHaveClass(appearance);
29
+ }
30
+ unmount();
31
+ });
32
+ });
33
+
34
+ test("supports all size options from spec", () => {
35
+ BUTTON_SIZES.forEach((size) => {
36
+ const { unmount } = render(<Button label={size} size={size} />);
37
+ const button = screen.getByRole("button", { name: size });
38
+ if (size === BUTTON_DEFAULTS.size) {
39
+ expect(button).not.toHaveClass(size);
40
+ } else {
41
+ expect(button).toHaveClass(size);
42
+ }
43
+ unmount();
44
+ });
45
+ });
46
+
47
+ test("supports all layout options from spec", () => {
48
+ BUTTON_LAYOUTS.forEach((layout) => {
49
+ const isIconOnly = layout === "icon-only" || layout === "only";
50
+ const baseProps = {
51
+ icon: "Plus",
52
+ layout,
53
+ } as const;
54
+ const props = isIconOnly
55
+ ? { ...baseProps, "aria-label": "icon-action" }
56
+ : { ...baseProps, label: layout };
57
+
58
+ const { unmount } = render(
59
+ <Button {...props} />,
60
+ );
61
+
62
+ const button = screen.getByRole("button", {
63
+ name: isIconOnly ? "icon-action" : layout,
64
+ });
65
+
66
+ if (layout === BUTTON_DEFAULTS.layout) {
67
+ expect(button).not.toHaveClass(layout);
68
+ } else {
69
+ expect(button).toHaveClass(layout);
70
+ }
71
+ unmount();
72
+ });
73
+ });
74
+
75
+ test("tracks click event when tracking prop is provided", () => {
76
+ const onTrack = jest.fn();
77
+ window.addEventListener("uds:track", onTrack as EventListener);
78
+
79
+ render(<Button label="Track me" tracking="cta-click" />);
80
+ fireEvent.click(screen.getByRole("button", { name: "Track me" }));
81
+
82
+ expect(onTrack).toHaveBeenCalled();
83
+ window.removeEventListener("uds:track", onTrack as EventListener);
84
+ });
85
+ });