@pnx-mixtape/mxds 0.1.0-rc.1 → 0.1.0-rc.3

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 (344) hide show
  1. package/.storybook/decorators.ts +15 -0
  2. package/.storybook/{preview.ts → preview.tsx} +8 -1
  3. package/.storybook/src/docs.tsx +29 -0
  4. package/.storybook/themes/campus-vibrant.css +181 -0
  5. package/.storybook/themes/civic-formal.css +246 -0
  6. package/.storybook/{theme-demo.css → themes/demo.css} +14 -7
  7. package/.storybook/themes/health-services.css +255 -0
  8. package/.storybook/themes/research-faculty.css +169 -0
  9. package/dist/build/accordion.css +1 -1
  10. package/dist/build/accordion.entry.js +1 -1
  11. package/dist/build/autocomplete.css +1 -1
  12. package/dist/build/autocomplete.entry.js +1 -1
  13. package/dist/build/base.css +1 -1
  14. package/dist/build/breadcrumb.css +1 -1
  15. package/dist/build/button.css +1 -1
  16. package/dist/build/card.css +1 -1
  17. package/dist/build/chunks/{Accordion-z-dH6nFH.js → Accordion-GN0sME4W.js} +1 -1
  18. package/dist/build/chunks/{AccordionMobile-BYPPNyf5.js → AccordionMobile-DG5jSe8Q.js} +1 -1
  19. package/dist/build/chunks/{Autocomplete-2L6tLLuh.js → Autocomplete-B4RtkAyh.js} +1 -1
  20. package/dist/build/chunks/{ClosableAlert-DdXbF1J2.js → ClosableAlert-DEhj8Nxm.js} +1 -1
  21. package/dist/build/chunks/{Dialog-Ds8gzhri.js → Dialog-Haahn-Yn.js} +1 -1
  22. package/dist/build/chunks/DropMenu-1baQc8Yc.js +1 -0
  23. package/dist/build/chunks/Gallery-D8NGXy2Q.js +1 -0
  24. package/dist/build/chunks/GlobalToggle-B52fdBQu.js +1 -0
  25. package/dist/build/chunks/InPageNavigation-Dyn2TR-N.js +1 -0
  26. package/dist/build/chunks/Navigation-hOrfLq7h.js +1 -0
  27. package/dist/build/chunks/Popover-Cxg-s5Jn.js +1 -0
  28. package/dist/build/chunks/Sticky-BGCuuEJK.js +1 -0
  29. package/dist/build/chunks/Tabs-DYy1YTdU.js +15 -0
  30. package/dist/build/chunks/enums-DLV_1NAf.js +1 -0
  31. package/dist/build/chunks/polyfills-C7pRt54M.js +1 -0
  32. package/dist/build/chunks/utilities-_Bq3TxAQ.js +1 -0
  33. package/dist/build/constants.css +1 -1
  34. package/dist/build/cookie-consent.css +1 -1
  35. package/dist/build/dialog.entry.js +1 -1
  36. package/dist/build/drop-menu.entry.js +1 -1
  37. package/dist/build/elements.js +1 -1
  38. package/dist/build/filters.css +1 -1
  39. package/dist/build/filters.entry.js +1 -1
  40. package/dist/build/form.css +1 -1
  41. package/dist/build/gallery.entry.js +1 -1
  42. package/dist/build/global-alert.entry.js +1 -1
  43. package/dist/build/grid.css +1 -1
  44. package/dist/build/header.entry.js +1 -1
  45. package/dist/build/icon.css +1 -1
  46. package/dist/build/in-page-alert.css +1 -1
  47. package/dist/build/in-page-navigation.entry.js +1 -1
  48. package/dist/build/list-item.css +1 -1
  49. package/dist/build/navigation.css +1 -1
  50. package/dist/build/navigation.entry.js +1 -1
  51. package/dist/build/one-time-code.css +1 -0
  52. package/dist/build/popover.css +1 -1
  53. package/dist/build/popover.entry.js +1 -1
  54. package/dist/build/print.css +1 -1
  55. package/dist/build/progress-indicator.css +1 -0
  56. package/dist/build/react.js +1 -1
  57. package/dist/build/sidebar.css +1 -1
  58. package/dist/build/steps.css +1 -1
  59. package/dist/build/sticky.entry.js +1 -1
  60. package/dist/build/tabs.css +1 -1
  61. package/dist/build/tabs.entry.js +1 -1
  62. package/dist/build/tag.css +1 -1
  63. package/dist/build/utilities.css +1 -1
  64. package/dist/types/Atom/DefinitionList/DefinitionList.d.ts +3 -2
  65. package/dist/types/Atom/DefinitionList/DefinitionList.d.ts.map +1 -1
  66. package/dist/types/Atom/Heading/Heading.d.ts.map +1 -1
  67. package/dist/types/Atom/Link/Link.d.ts.map +1 -1
  68. package/dist/types/Atom/List/List.d.ts +10 -0
  69. package/dist/types/Atom/List/List.d.ts.map +1 -0
  70. package/dist/types/Component/Accordion/Accordion.d.ts.map +1 -1
  71. package/dist/types/Component/Dialog/Dialog.d.ts.map +1 -1
  72. package/dist/types/Component/DropMenu/Elements/DropMenu.d.ts.map +1 -1
  73. package/dist/types/Component/Filters/Elements/Filters.d.ts +20 -1
  74. package/dist/types/Component/Filters/Elements/Filters.d.ts.map +1 -1
  75. package/dist/types/Component/Filters/Filters.d.ts +7 -2
  76. package/dist/types/Component/Filters/Filters.d.ts.map +1 -1
  77. package/dist/types/Component/Gallery/Gallery.d.ts.map +1 -1
  78. package/dist/types/Component/InPageNavigation/Elements/InPageNavigation.d.ts +2 -2
  79. package/dist/types/Component/InPageNavigation/Elements/InPageNavigation.d.ts.map +1 -1
  80. package/dist/types/Component/InPageNavigation/Hooks/useInPageNavigation.d.ts.map +1 -1
  81. package/dist/types/Component/Pagination/Components/PaginationContext.d.ts.map +1 -1
  82. package/dist/types/Component/ProgressIndicator/ProgressIndicator.d.ts +9 -0
  83. package/dist/types/Component/ProgressIndicator/ProgressIndicator.d.ts.map +1 -0
  84. package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
  85. package/dist/types/Component/Tabs/Tabs.d.ts.map +1 -1
  86. package/dist/types/Component/Tag/Tag.d.ts +4 -2
  87. package/dist/types/Component/Tag/Tag.d.ts.map +1 -1
  88. package/dist/types/Form/Autocomplete/Autocomplete.d.ts +2 -2
  89. package/dist/types/Form/Autocomplete/Autocomplete.d.ts.map +1 -1
  90. package/dist/types/Form/Autocomplete/Elements/Autocomplete.d.ts +10 -0
  91. package/dist/types/Form/Autocomplete/Elements/Autocomplete.d.ts.map +1 -1
  92. package/dist/types/Form/Checkbox/FormCheckbox.d.ts.map +1 -1
  93. package/dist/types/Form/CheckboxCard/CheckboxCard.d.ts +23 -0
  94. package/dist/types/Form/CheckboxCard/CheckboxCard.d.ts.map +1 -0
  95. package/dist/types/Form/OneTimeCode/OneTimeCode.d.ts +12 -0
  96. package/dist/types/Form/OneTimeCode/OneTimeCode.d.ts.map +1 -0
  97. package/dist/types/Form/Radio/FormRadio.d.ts.map +1 -1
  98. package/dist/types/Form/RadioCard/RadioCard.d.ts +16 -0
  99. package/dist/types/Form/RadioCard/RadioCard.d.ts.map +1 -0
  100. package/dist/types/Form/Select/FormSelect.d.ts.map +1 -1
  101. package/dist/types/Form/TextInput/FormText.d.ts.map +1 -1
  102. package/dist/types/Form/Textarea/FormTextarea.d.ts.map +1 -1
  103. package/dist/types/Utility/Hooks/useIsomorphicLayoutEffect.d.ts +4 -0
  104. package/dist/types/Utility/Hooks/useIsomorphicLayoutEffect.d.ts.map +1 -0
  105. package/dist/types/enums.d.ts +19 -0
  106. package/dist/types/enums.d.ts.map +1 -1
  107. package/dist/types/react.d.ts +5 -0
  108. package/dist/types/react.d.ts.map +1 -1
  109. package/package.json +8 -8
  110. package/src/Atom/Background/_background.css +2 -2
  111. package/src/Atom/Blockquote/_blockquote.css +9 -2
  112. package/src/Atom/Button/README.md +1 -0
  113. package/src/Atom/Button/__snapshots__/Button.stories.ts.snap +2 -3
  114. package/src/Atom/Button/_buttons-styles.css +6 -6
  115. package/src/Atom/Button/_buttons.css +21 -3
  116. package/src/Atom/Button/button.twig +4 -1
  117. package/src/Atom/DefinitionList/DefinitionList.stories.ts +42 -2
  118. package/src/Atom/DefinitionList/DefinitionList.stories.tsx +36 -0
  119. package/src/Atom/DefinitionList/DefinitionList.tsx +4 -1
  120. package/src/Atom/DefinitionList/DefinitionListItem.stories.ts +1 -1
  121. package/src/Atom/DefinitionList/README.md +43 -0
  122. package/src/Atom/DefinitionList/__snapshots__/DefinitionList.stories.ts.snap +37 -3
  123. package/src/Atom/DefinitionList/__snapshots__/DefinitionList.stories.tsx.snap +2 -0
  124. package/src/Atom/DefinitionList/__snapshots__/DefinitionListItem.stories.ts.snap +3 -3
  125. package/src/Atom/DefinitionList/definition-list-item.twig +1 -0
  126. package/src/Atom/DefinitionList/definition-list.twig +6 -1
  127. package/src/Atom/Heading/Heading.tsx +6 -0
  128. package/src/Atom/Heading/_headings.css +2 -1
  129. package/src/Atom/Icon/_extended-set.css +30 -30
  130. package/src/Atom/Icon/_icon.css +39 -36
  131. package/src/Atom/Image/README.md +2 -2
  132. package/src/Atom/Image/_image.css +12 -6
  133. package/src/Atom/Link/Link.tsx +16 -3
  134. package/src/Atom/Link/__snapshots__/Link.stories.ts.snap +7 -12
  135. package/src/Atom/Link/__snapshots__/Link.stories.tsx.snap +1 -1
  136. package/src/Atom/Link/_links.css +9 -0
  137. package/src/Atom/Link/link.twig +8 -2
  138. package/src/Atom/LinkedImage/linked-image.twig +1 -2
  139. package/src/Atom/List/List.stories.ts +102 -0
  140. package/src/Atom/List/List.stories.tsx +103 -0
  141. package/src/Atom/List/List.tsx +22 -0
  142. package/src/Atom/List/README.md +150 -0
  143. package/src/Atom/List/__snapshots__/List.stories.ts.snap +43 -0
  144. package/src/Atom/List/__snapshots__/List.stories.tsx.snap +13 -0
  145. package/src/Atom/List/_list.css +123 -0
  146. package/src/Atom/List/list.twig +5 -0
  147. package/src/Atom/Media/Media.stories.ts +1 -1
  148. package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +2 -2
  149. package/src/Atom/Spacing/_spacing.css +24 -24
  150. package/src/Atom/Table/__snapshots__/Table.stories.ts.snap +24 -4
  151. package/src/Atom/Table/_table.css +15 -3
  152. package/src/Atom/Table/table.twig +6 -1
  153. package/src/Atom/Text/__snapshots__/Text.stories.ts.snap +3 -2
  154. package/src/Atom/Text/_text-styles.css +21 -1
  155. package/src/Atom/Text/twig/text-styles-example.twig +3 -2
  156. package/src/Atom/_base.css +6 -0
  157. package/src/Atom/_flow.css +1 -1
  158. package/src/Atom/_generic.css +18 -11
  159. package/src/Component/Accordion/Accordion.stories.ts +31 -0
  160. package/src/Component/Accordion/Accordion.tsx +3 -2
  161. package/src/Component/Accordion/AccordionItem.stories.ts +27 -0
  162. package/src/Component/Accordion/__snapshots__/Accordion.stories.ts.snap +36 -0
  163. package/src/Component/Accordion/__snapshots__/AccordionItem.stories.ts.snap +16 -0
  164. package/src/Component/Accordion/accordion.css +2 -0
  165. package/src/Component/Breadcrumb/__snapshots__/Breadcrumb.stories.ts.snap +3 -6
  166. package/src/Component/Breadcrumb/breadcrumb.css +4 -0
  167. package/src/Component/Card/__snapshots__/Card.stories.ts.snap +13 -24
  168. package/src/Component/Card/card.css +2 -2
  169. package/src/Component/Card/card.twig +1 -1
  170. package/src/Component/Carousel/Carousel.stories.ts +101 -23
  171. package/src/Component/Carousel/Carousel.stories.tsx +74 -0
  172. package/src/Component/Carousel/__snapshots__/Carousel.stories.ts.snap +273 -88
  173. package/src/Component/Carousel/__snapshots__/Carousel.stories.tsx.snap +5 -3
  174. package/src/Component/ContentBlock/__snapshots__/ContentBlock.stories.ts.snap +12 -24
  175. package/src/Component/CookieConsent/cookie-consent.css +3 -1
  176. package/src/Component/Dialog/Dialog.stories.ts +33 -0
  177. package/src/Component/Dialog/Dialog.stories.tsx +25 -0
  178. package/src/Component/Dialog/Dialog.tsx +2 -2
  179. package/src/Component/Dialog/__snapshots__/Dialog.stories.ts.snap +33 -2
  180. package/src/Component/Dialog/__snapshots__/Dialog.stories.tsx.snap +2 -0
  181. package/src/Component/DropMenu/DropMenu.stories.ts +39 -1
  182. package/src/Component/DropMenu/DropMenu.stories.tsx +29 -0
  183. package/src/Component/DropMenu/DropMenu.tsx +1 -1
  184. package/src/Component/DropMenu/Elements/DropMenu.ts +10 -1
  185. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +14 -0
  186. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.tsx.snap +3 -1
  187. package/src/Component/Filters/Elements/Filters.ts +71 -1
  188. package/src/Component/Filters/FilterItem.stories.ts +2 -1
  189. package/src/Component/Filters/FilterItem.tsx +1 -1
  190. package/src/Component/Filters/Filters.figma.ts +1 -1
  191. package/src/Component/Filters/Filters.stories.ts +95 -3
  192. package/src/Component/Filters/Filters.stories.tsx +246 -17
  193. package/src/Component/Filters/Filters.tsx +145 -29
  194. package/src/Component/Filters/README.md +102 -37
  195. package/src/Component/Filters/__snapshots__/FilterItem.stories.tsx.snap +3 -3
  196. package/src/Component/Filters/__snapshots__/Filters.stories.ts.snap +82 -4
  197. package/src/Component/Filters/__snapshots__/Filters.stories.tsx.snap +9 -3
  198. package/src/Component/Filters/filters.css +11 -0
  199. package/src/Component/Gallery/Gallery.tsx +2 -2
  200. package/src/Component/HeroBanner/HeroBanner.stories.ts +1 -1
  201. package/src/Component/HeroBanner/__snapshots__/HeroBanner.stories.ts.snap +4 -8
  202. package/src/Component/HeroSearch/__snapshots__/HeroSearch.stories.ts.snap +5 -10
  203. package/src/Component/InPageAlert/__snapshots__/InPageAlert.stories.ts.snap +6 -12
  204. package/src/Component/InPageAlert/in-page-alert.css +2 -1
  205. package/src/Component/InPageNavigation/Elements/InPageNavigation.ts +10 -5
  206. package/src/Component/InPageNavigation/Hooks/useInPageNavigation.ts +10 -5
  207. package/src/Component/InPageNavigation/InPageNavigation.stories.ts +83 -0
  208. package/src/Component/InPageNavigation/InPageNavigation.stories.tsx +130 -0
  209. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +61 -1
  210. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.tsx.snap +4 -0
  211. package/src/Component/InPageNavigation/twig/content-example-duplicate-headings.twig +20 -0
  212. package/src/Component/InPageNavigation/twig/in-page-navigation-story-duplicate-headings.twig +2 -0
  213. package/src/Component/LinkList/__snapshots__/LinkList.stories.ts.snap +6 -12
  214. package/src/Component/ListItem/__snapshots__/ListItem.stories.ts.snap +11 -18
  215. package/src/Component/ListItem/list-item.css +1 -1
  216. package/src/Component/ListItem/list-item.twig +2 -2
  217. package/src/Component/Navigation/Dropdown.stories.tsx +46 -0
  218. package/src/Component/Navigation/Navigation.stories.ts +56 -0
  219. package/src/Component/Navigation/__snapshots__/Dropdown.stories.tsx.snap +2 -0
  220. package/src/Component/Navigation/__snapshots__/Navigation.stories.ts.snap +57 -0
  221. package/src/Component/Navigation/_navigation.css +1 -1
  222. package/src/Component/Pagination/Components/PaginationContext.tsx +2 -1
  223. package/src/Component/Pagination/Components/PaginationItem.tsx +1 -1
  224. package/src/Component/Pagination/Pagination.stories.ts +44 -4
  225. package/src/Component/Pagination/Pagination.stories.tsx +31 -0
  226. package/src/Component/Pagination/__snapshots__/Pagination.stories.ts.snap +69 -12
  227. package/src/Component/Pagination/__snapshots__/Pagination.stories.tsx.snap +3 -1
  228. package/src/Component/Pagination/pagination-item.twig +1 -1
  229. package/src/Component/Pagination/pagination.css +2 -2
  230. package/src/Component/Popover/__snapshots__/Popover.stories.ts.snap +13 -26
  231. package/src/Component/Popover/popover.css +1 -1
  232. package/src/Component/ProgressIndicator/ProgressIndicator.stories.ts +36 -0
  233. package/src/Component/ProgressIndicator/ProgressIndicator.stories.tsx +30 -0
  234. package/src/Component/ProgressIndicator/ProgressIndicator.tsx +60 -0
  235. package/src/Component/ProgressIndicator/README.md +111 -0
  236. package/src/Component/ProgressIndicator/__snapshots__/ProgressIndicator.stories.ts.snap +67 -0
  237. package/src/Component/ProgressIndicator/__snapshots__/ProgressIndicator.stories.tsx.snap +7 -0
  238. package/src/Component/ProgressIndicator/progress-indicator.css +59 -0
  239. package/src/Component/ProgressIndicator/progress-indicator.twig +22 -0
  240. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.ts.snap +1 -2
  241. package/src/Component/SocialLinks/__snapshots__/SocialLinks.stories.ts.snap +6 -9
  242. package/src/Component/Steps/Steps.stories.ts +1 -1
  243. package/src/Component/Steps/steps.css +13 -0
  244. package/src/Component/Sticky/Elements/Sticky.ts +1 -1
  245. package/src/Component/Sticky/sticky.css +3 -3
  246. package/src/Component/Tabs/Elements/Tabs.ts +3 -1
  247. package/src/Component/Tabs/Tabs.stories.ts +77 -21
  248. package/src/Component/Tabs/Tabs.stories.tsx +24 -0
  249. package/src/Component/Tabs/Tabs.tsx +2 -2
  250. package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +20 -2
  251. package/src/Component/Tabs/__snapshots__/Tabs.stories.tsx.snap +3 -1
  252. package/src/Component/Tabs/tabs.css +2 -0
  253. package/src/Component/Tag/README.md +52 -26
  254. package/src/Component/Tag/Tag.stories.tsx +24 -0
  255. package/src/Component/Tag/Tag.tsx +12 -2
  256. package/src/Component/Tag/TagItem.stories.ts +25 -0
  257. package/src/Component/Tag/__snapshots__/Tag.stories.ts.snap +2 -2
  258. package/src/Component/Tag/__snapshots__/Tag.stories.tsx.snap +2 -0
  259. package/src/Component/Tag/tag-item.twig +2 -2
  260. package/src/Component/Tag/tag.css +76 -2
  261. package/src/Form/Autocomplete/Autocomplete.stories.ts +89 -7
  262. package/src/Form/Autocomplete/Autocomplete.stories.tsx +85 -1
  263. package/src/Form/Autocomplete/Autocomplete.tsx +20 -10
  264. package/src/Form/Autocomplete/Elements/Autocomplete.ts +24 -1
  265. package/src/Form/Autocomplete/README.md +26 -26
  266. package/src/Form/Autocomplete/__snapshots__/Autocomplete.stories.ts.snap +39 -5
  267. package/src/Form/Autocomplete/__snapshots__/Autocomplete.stories.tsx.snap +8 -4
  268. package/src/Form/Autocomplete/autocomplete.css +12 -1
  269. package/src/Form/Autocomplete/autocomplete.twig +1 -3
  270. package/src/Form/Checkbox/FormCheckbox.tsx +2 -8
  271. package/src/Form/Checkbox/README.md +23 -18
  272. package/src/Form/Checkbox/input-checkbox.twig +0 -2
  273. package/src/Form/CheckboxCard/CheckboxCard.stories.ts +90 -0
  274. package/src/Form/CheckboxCard/CheckboxCard.stories.tsx +43 -0
  275. package/src/Form/CheckboxCard/CheckboxCard.tsx +102 -0
  276. package/src/Form/CheckboxCard/README.md +163 -0
  277. package/src/Form/CheckboxCard/__snapshots__/CheckboxCard.stories.ts.snap +63 -0
  278. package/src/Form/CheckboxCard/__snapshots__/CheckboxCard.stories.tsx.snap +7 -0
  279. package/src/Form/CheckboxCard/checkbox-card.twig +29 -0
  280. package/src/Form/FormItem/__snapshots__/FormItem.stories.ts.snap +2 -2
  281. package/src/Form/OneTimeCode/OneTimeCode.stories.ts +20 -0
  282. package/src/Form/OneTimeCode/OneTimeCode.stories.tsx +18 -0
  283. package/src/Form/OneTimeCode/OneTimeCode.tsx +56 -0
  284. package/src/Form/OneTimeCode/README.md +83 -0
  285. package/src/Form/OneTimeCode/__snapshots__/OneTimeCode.stories.ts.snap +7 -0
  286. package/src/Form/OneTimeCode/__snapshots__/OneTimeCode.stories.tsx.snap +3 -0
  287. package/src/Form/OneTimeCode/one-time-code.css +13 -0
  288. package/src/Form/OneTimeCode/one-time-code.twig +31 -0
  289. package/src/Form/README.md +65 -13
  290. package/src/Form/Radio/FormRadio.tsx +1 -4
  291. package/src/Form/Radio/input-radio.twig +0 -2
  292. package/src/Form/RadioCard/README.md +146 -0
  293. package/src/Form/RadioCard/RadioCard.stories.ts +95 -0
  294. package/src/Form/RadioCard/RadioCard.stories.tsx +26 -0
  295. package/src/Form/RadioCard/RadioCard.tsx +59 -0
  296. package/src/Form/RadioCard/__snapshots__/RadioCard.stories.ts.snap +69 -0
  297. package/src/Form/RadioCard/__snapshots__/RadioCard.stories.tsx.snap +3 -0
  298. package/src/Form/RadioCard/radio-card.twig +20 -0
  299. package/src/Form/Select/FormSelect.tsx +1 -4
  300. package/src/Form/Select/input-select.twig +0 -2
  301. package/src/Form/TextInput/FormText.stories.tsx +14 -0
  302. package/src/Form/TextInput/FormText.tsx +1 -4
  303. package/src/Form/TextInput/__snapshots__/FormText.stories.tsx.snap +2 -0
  304. package/src/Form/TextInput/input-text.twig +0 -2
  305. package/src/Form/Textarea/FormTextarea.tsx +1 -4
  306. package/src/Form/Textarea/input-textarea.twig +0 -2
  307. package/src/Form/Validation.stories.ts +153 -0
  308. package/src/Form/__snapshots__/Validation.stories.ts.snap +130 -0
  309. package/src/Form/form.css +240 -55
  310. package/src/Layout/Footer/__snapshots__/Footer.stories.ts.snap +18 -33
  311. package/src/Layout/Grid/grid.css +4 -4
  312. package/src/Layout/Header/Header.stories.ts +33 -0
  313. package/src/Layout/Header/Header.stories.tsx +31 -0
  314. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +50 -0
  315. package/src/Layout/Header/__snapshots__/Header.stories.tsx.snap +2 -0
  316. package/src/Layout/Masthead/__snapshots__/Masthead.stories.ts.snap +8 -16
  317. package/src/Layout/Section/__snapshots__/Background.stories.ts.snap +2 -4
  318. package/src/Layout/Section/__snapshots__/Section.stories.ts.snap +4 -8
  319. package/src/Layout/Sidebar/__snapshots__/Sidebar.stories.ts.snap +5 -5
  320. package/src/Layout/Sidebar/sidebar.css +1 -0
  321. package/src/Layout/Sidebar/sidebar.twig +1 -1
  322. package/src/Utility/Hooks/useIsomorphicLayoutEffect.ts +8 -0
  323. package/src/Utility/_layout-utils.css +8 -0
  324. package/src/Utility/_mixins.css +24 -0
  325. package/src/Utility/print.css +51 -29
  326. package/src/Utility/utilities.css +22 -2
  327. package/src/_custom-media.css +1 -0
  328. package/src/constants.css +12 -2
  329. package/src/enums.ts +22 -0
  330. package/src/react.ts +5 -0
  331. package/tools/lib/extract-classnames.mjs +0 -0
  332. package/tools/lint-classnames.mjs +1 -1
  333. package/tools/test-utils/screen-reader.ts +33 -0
  334. package/dist/build/chunks/DropMenu-Co9jZZ4S.js +0 -1
  335. package/dist/build/chunks/Gallery-BT3cxS5m.js +0 -1
  336. package/dist/build/chunks/GlobalToggle-DQHho97V.js +0 -1
  337. package/dist/build/chunks/InPageNavigation-CzR_KZaz.js +0 -1
  338. package/dist/build/chunks/Navigation-B9Wug-ok.js +0 -1
  339. package/dist/build/chunks/Popover-De_CQqcd.js +0 -1
  340. package/dist/build/chunks/Sticky-Kyjykb36.js +0 -1
  341. package/dist/build/chunks/Tabs-Dm8g301e.js +0 -15
  342. package/dist/build/chunks/disclosure-widget-BETzOHLO.js +0 -1
  343. package/dist/build/chunks/polyfills-Dokbkxxk.js +0 -1
  344. package/dist/build/chunks/utilities-C5dAO2YA.js +0 -1
@@ -32,7 +32,7 @@ The input's `aria-describedby` is automatically wired to `help-{id}` — `FormDe
32
32
  <div class="mx-form-item">
33
33
  <label class="mx-label" for="email">Email address</label>
34
34
  <input
35
- class="mx-input__text error"
35
+ class="mx-input__text"
36
36
  id="email"
37
37
  type="email"
38
38
  name="email"
@@ -46,12 +46,13 @@ The input's `aria-describedby` is automatically wired to `help-{id}` — `FormDe
46
46
 
47
47
  ## Input modifier classes
48
48
 
49
- | Class | Effect |
50
- | ------------------------ | ------------------------------------------------------------ |
51
- | `mx-input--wide` | `inline-size: 100%` — fills its container |
52
- | `mx-input--small` | Reduced border (1px), smaller chevron offset |
53
- | `mx-input--icon` | Adds leading icon via `::before` mask |
54
- | `mx-form--inline-button` | Input + button fused into one bordered unit (used in Search) |
49
+ | Class | Effect |
50
+ | ------------------------ | ------------------------------------------------------------- |
51
+ | `mx-input--wide` | `inline-size: 100%` — fills its container |
52
+ | `mx-input--small` | Reduced border (1px), smaller chevron offset |
53
+ | `mx-input--icon` | Adds leading icon via `::before` mask |
54
+ | `mx-form--inline-button` | Input + button fused into one bordered unit (used in Search) |
55
+ | `mx-validate` | Opt in to live `:user-valid` / `:user-invalid` border colours |
55
56
 
56
57
  ## Form actions
57
58
 
@@ -186,13 +187,64 @@ import { FormStatus } from "../../enums"
186
187
 
187
188
  ---
188
189
 
189
- ## Status states (`FormStatus` enum)
190
+ ## Validation state
190
191
 
191
- | Value | Class suffix | Description |
192
- | -------------------- | ------------ | ------------------------------------------------------------ |
193
- | `FormStatus.DEFAULT` | — | Normal state |
194
- | `FormStatus.VALID` | `success` | Green border, success icon on description |
195
- | `FormStatus.INVALID` | `error` | Red border, error icon on description, `aria-invalid="true"` |
192
+ There is no `error` or `success` class to apply. Two hooks drive input borders:
193
+
194
+ ### 1. Live native validation — opt in with `mx-validate`
195
+
196
+ Add `mx-validate` to a control to let the browser colour it as the user types.
197
+ Without the class, a control is **never** coloured automatically — so filling in
198
+ an unmarked field doesn't turn it green.
199
+
200
+ ```html
201
+ <input class="mx-input__text mx-validate" type="email" required />
202
+ ```
203
+
204
+ For checkbox and radio, put it on the wrapper — that's where `className` and
205
+ Drupal `attributes` land:
206
+
207
+ ```html
208
+ <div class="mx-checkbox mx-validate"><input type="checkbox" required /><label>…</label></div>
209
+ ```
210
+
211
+ | Selector | Effect | When it matches |
212
+ | --------------- | ------------ | -------------------------------------------------------------------- |
213
+ | `:user-valid` | Green border | Field passes validation **and** the user has interacted or submitted |
214
+ | `:user-invalid` | Red border | Field fails validation **and** the user has interacted or submitted |
215
+
216
+ `:user-*` is used rather than `:valid`/`:invalid` so a blank `required` field
217
+ isn't red on page load.
218
+
219
+ ### 2. Explicit errors — `aria-invalid`, no opt-in
220
+
221
+ `[aria-invalid="true"]` always paints a red border, with or without
222
+ `mx-validate`. This is for failures the browser can't see: server-rendered
223
+ (Drupal) or async. The consumer has already decided the field is wrong, so
224
+ there's nothing to opt into.
225
+
226
+ Live success styling excludes `[aria-invalid="true"]`, so an explicit error
227
+ stays red even when the field passes native validation.
228
+
229
+ ### `status` prop (`FormStatus` enum)
230
+
231
+ `status` no longer sets border classes. It controls the ARIA state and which
232
+ message block renders:
233
+
234
+ | Value | Effect |
235
+ | -------------------- | -------------------------------------------------------------- |
236
+ | `FormStatus.DEFAULT` | `aria-invalid="false"`, no message block |
237
+ | `FormStatus.VALID` | `mx-success-message` block, green icon — **no green border** |
238
+ | `FormStatus.INVALID` | `aria-invalid="true"` (⇒ red border), `mx-error-message` block |
239
+
240
+ For a server-side error, set `status={FormStatus.INVALID}` — the border follows
241
+ from `aria-invalid`. For client-side rules, use native attributes (`required`,
242
+ `pattern`, `type="email"`, `min`/`max`), add `mx-validate`, and let the browser
243
+ do it.
244
+
245
+ Green borders are live-only: there is no ARIA counterpart to `aria-invalid`, so
246
+ an explicitly-set `VALID` status renders the success message without recolouring
247
+ the border.
196
248
 
197
249
  ---
198
250
 
@@ -40,10 +40,7 @@ const Radio = ({
40
40
  const state = use(RadioContext)
41
41
  const { inputProps } = useRadio(props, state, ref)
42
42
 
43
- const classes = classNames("mx-radio", className, {
44
- error: status === FormStatus.INVALID,
45
- success: status === FormStatus.VALID,
46
- })
43
+ const classes = classNames("mx-radio", className)
47
44
 
48
45
  return (
49
46
  <div className={classes}>
@@ -1,7 +1,5 @@
1
1
  {% set classes = [
2
2
  'mx-radio',
3
- status == "invalid" ? "error" : null,
4
- status == "valid" ? "success" : null,
5
3
  ] %}
6
4
  {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
7
5
  <div{{ attributes }}>
@@ -0,0 +1,146 @@
1
+ # RadioCard
2
+
3
+ A card-style radio — a full padded, bordered, selectable card instead of a small inline control. Use for a small set of mutually-exclusive options that benefit from a larger tap target and optional secondary hint text (e.g. a high-stakes form question), rather than a dense list of ordinary radios.
4
+
5
+ > **HTML/Twig users:** use native `<input type="radio">` with both the `.mx-radio` and `.mx-choice-card` wrapper classes. The react-aria wiring is React-only.
6
+
7
+ `.mx-choice-card` layers on top of `.mx-radio` rather than replacing it — the base class still supplies input reset/sizing, disabled state, and the spacing between stacked cards in a group; `.mx-choice-card`'s higher cascade layer (`design-system.components` vs. `.mx-radio`'s `design-system.atoms`) overrides only what the card treatment needs to change (position, padding, border).
8
+
9
+ `.mx-choice-card` is shared with `CheckboxCard` — it lives in `src/Form/form.css` alongside the base `.mx-checkbox`/`.mx-radio` rules, not in a per-component CSS file, since the two components' card treatments were identical enough to not warrant separate copies.
10
+
11
+ ## CSS Import
12
+
13
+ ```css
14
+ @import "@pnx-mixtape/mxds/src/Form/form.css";
15
+ ```
16
+
17
+ ---
18
+
19
+ ## Twig
20
+
21
+ ```twig
22
+ {% include '@mixtape/Form/RadioCard/radio-card.twig' with {
23
+ id: 'card-yes',
24
+ name: 'card',
25
+ value: 'yes',
26
+ label: 'Yes, I hold a card',
27
+ hint: 'Pensioner Concession, Health Care or DVA card',
28
+ } %}
29
+ ```
30
+
31
+ **radio-card.twig props:**
32
+
33
+ | Prop | Type | Required | Description |
34
+ | ------------ | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
35
+ | `id` | `string` | Yes | Input id |
36
+ | `name` | `string` | Yes | `name` attribute on the input |
37
+ | `value` | `string` | Yes | `value` attribute on the input |
38
+ | `label` | `string` | Yes | Label text rendered inside `<label for="{id}">` |
39
+ | `hint` | `string` | No | Secondary line rendered under the label, inside the card |
40
+ | `checked` | `boolean` | No | Adds `checked="checked"` to the input |
41
+ | `required` | `boolean` | No | Adds the `required` attribute |
42
+ | `status` | `FormStatusTypes` | No | `invalid` adds the `error` class and `aria-invalid="true"`; `valid` adds the `success` class. Defaults to `default` |
43
+ | `attributes` | `Attribute` | No | Optional Drupal-style attributes object — `mx-radio mx-choice-card` (and the status class) is always merged on top |
44
+
45
+ For a group of cards, compose several `radio-card.twig` includes inside a `<fieldset>` — see HTML below.
46
+
47
+ ---
48
+
49
+ ## HTML
50
+
51
+ ```html
52
+ <fieldset class="mx-form-item mx-fieldset mx-fieldset--plain">
53
+ <legend class="mx-legend">Do you hold a current concession card?</legend>
54
+
55
+ <div class="mx-radio mx-choice-card">
56
+ <input type="radio" id="card-yes" name="card" value="yes" />
57
+ <label for="card-yes">
58
+ Yes, I hold a card
59
+ <span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span>
60
+ </label>
61
+ </div>
62
+
63
+ <div class="mx-radio mx-choice-card">
64
+ <input type="radio" id="card-no" name="card" value="no" />
65
+ <label for="card-no">
66
+ No
67
+ <span class="mx-choice-card__hint">You may still be eligible based on your income</span>
68
+ </label>
69
+ </div>
70
+
71
+ <div class="mx-choice-divider">or</div>
72
+
73
+ <div class="mx-radio mx-choice-card">
74
+ <input type="radio" id="card-unsure" name="card" value="unsure" />
75
+ <label for="card-unsure">I am not sure</label>
76
+ </div>
77
+ </fieldset>
78
+ ```
79
+
80
+ `.mx-choice-divider` is also defined in `src/Form/form.css` — plain markup used to split either card type into two groups, already available once you import `form.css`. See [`CheckboxCard`'s README](../CheckboxCard/README.md#or-divider-between-two-option-groups) for more.
81
+
82
+ ---
83
+
84
+ ## React
85
+
86
+ Use `FormRadioCard` as the group wrapper and `RadioCard` for each option — same pattern as `FormRadio`/`Radio`. There's no standalone/single variant (a lone radio isn't a meaningful control on its own, same as `Radio`).
87
+
88
+ ```tsx
89
+ import { FormRadioCard, RadioCard } from "@pnx-mixtape/mxds/react"
90
+
91
+ ;<FormRadioCard label="Do you hold a current concession card?" onChange={setSelected}>
92
+ <RadioCard value="yes" hint="Pensioner Concession, Health Care or DVA card">
93
+ Yes, I hold a card
94
+ </RadioCard>
95
+ <RadioCard value="no" hint="You may still be eligible based on your income">
96
+ No
97
+ </RadioCard>
98
+ </FormRadioCard>
99
+ ```
100
+
101
+ **`FormRadioCard` props:** all `AriaRadioGroupProps` from react-aria + `label: string`
102
+
103
+ **`RadioCard` props:** all `AriaRadioProps` + `hint?: string`, `status?: FormStatus`, `className?: string`
104
+
105
+ ---
106
+
107
+ ### React ⇄ Twig parity
108
+
109
+ Same intentional divergence as `Radio`/`Checkbox`/`CheckboxCard`:
110
+
111
+ - Twig's `label` becomes React `children` — react-aria composes the accessible name from rendered content, not a string prop.
112
+ - Twig's `id`/`name`/`checked`/`required`/`value` are handled by the react-aria hooks (`useRadio`/`useRadioGroup`) via prop spread rather than declared explicitly.
113
+
114
+ ---
115
+
116
+ ## Modifiers
117
+
118
+ No BEM modifier classes — `error`/`success` are applied as plain (unprefixed) status classes, matching `Radio`'s convention, driven by the `status` prop/Twig var.
119
+
120
+ ---
121
+
122
+ ## Accessibility
123
+
124
+ - The input stays a real, focusable `<input type="radio">` — only its default appearance is replaced (`appearance: none` plus a custom checked-state dot), so it keeps native radio semantics, keyboard support (arrow keys to move within the group, per the browser's native radio-group behaviour), and form submission behaviour.
125
+ - The whole card is clickable because the `<label>` fills it — the input itself only needs to be as large as `--control-size` dictates, not the full card.
126
+ - The focus ring (`:focus-visible`) renders on the input itself, inside the card, rather than around the whole card.
127
+ - `hint` text is inside the same `<label>` as the primary text, so both are announced together when the control receives focus — don't rely on `hint` to convey anything the primary `label` text doesn't already establish.
128
+
129
+ ---
130
+
131
+ ## Customisation
132
+
133
+ | Custom property | Applies to | Default |
134
+ | ------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------- |
135
+ | `--choice-padding-block` | `.mx-choice-card` | `var(--spacing-s)` |
136
+ | `--choice-padding-inline` | `.mx-choice-card` | `var(--spacing-m)` |
137
+ | `--choice-colour-active` | `.mx-choice-card`'s border/background tint when checked | `var(--colour-primary)` |
138
+ | `--radio-colour` | The checked dot itself — inherited from `.mx-radio`, not `.mx-choice-card` | `var(--colour-primary)` |
139
+ | `--control-size` | `.mx-choice-card input`, and `.mx-radio`'s own input styling | `var(--spacing-m)` (shared with `Checkbox`/`Radio`) |
140
+ | `--line-width` | `.mx-choice-card`'s border, and `.mx-radio`'s own input border | `2px` |
141
+
142
+ ```css
143
+ .theme--health-services .mx-choice-card {
144
+ --choice-colour-active: var(--colour-primary);
145
+ }
146
+ ```
@@ -0,0 +1,95 @@
1
+ import { Meta, StoryObj } from "@storybook/html-vite"
2
+ import Component from "../FormItem/form-item.twig"
3
+ import InputRadioCard from "./radio-card.twig"
4
+ import Label from "../Label/label.twig"
5
+ import "../form.css"
6
+ import { FormItem as FormItemType } from "@pnx-mixtape/ids-shape"
7
+
8
+ type MxFormItemType = Omit<FormItemType, "fields"> & {
9
+ fields?: string
10
+ }
11
+
12
+ const meta: Meta<MxFormItemType> = {
13
+ tags: ["autodocs"],
14
+ component: Component,
15
+ args: {
16
+ id: "card-set",
17
+ as: "fieldset",
18
+ label: Label({
19
+ title: "Do you hold a current concession card?",
20
+ as: "legend",
21
+ }),
22
+ fields: [
23
+ InputRadioCard({
24
+ id: "card-yes",
25
+ name: "card",
26
+ label: "Yes, I hold a card",
27
+ hint: "Pensioner Concession, Health Care or DVA card",
28
+ value: "yes",
29
+ }),
30
+ InputRadioCard({
31
+ id: "card-applied",
32
+ name: "card",
33
+ label: "I have applied but not received it",
34
+ hint: "You can continue, but we may ask for evidence later",
35
+ value: "applied",
36
+ }),
37
+ InputRadioCard({
38
+ id: "card-no",
39
+ name: "card",
40
+ label: "No",
41
+ hint: "You may still be eligible based on your income",
42
+ value: "no",
43
+ }),
44
+ '<div class="mx-choice-divider">or</div>',
45
+ InputRadioCard({
46
+ id: "card-unsure",
47
+ name: "card",
48
+ label: "I am not sure",
49
+ hint: "We will ask a few more questions to work it out",
50
+ value: "unsure",
51
+ }),
52
+ ].join(""),
53
+ },
54
+ parameters: {
55
+ deepControls: { enabled: true },
56
+ a11y: {
57
+ config: {
58
+ rules: [
59
+ {
60
+ // ID's are not unique due to test-runner.
61
+ id: "label",
62
+ enabled: false,
63
+ },
64
+ ],
65
+ },
66
+ },
67
+ },
68
+ }
69
+
70
+ export default meta
71
+ type Story = StoryObj<MxFormItemType>
72
+
73
+ export const RadioCard: Story = {}
74
+
75
+ export const Checked: Story = {
76
+ args: {
77
+ fields: [
78
+ InputRadioCard({
79
+ id: "card-yes",
80
+ name: "card",
81
+ label: "Yes, I hold a card",
82
+ hint: "Pensioner Concession, Health Care or DVA card",
83
+ value: "yes",
84
+ checked: true,
85
+ }),
86
+ InputRadioCard({
87
+ id: "card-no",
88
+ name: "card",
89
+ label: "No",
90
+ hint: "You may still be eligible based on your income",
91
+ value: "no",
92
+ }),
93
+ ].join(""),
94
+ },
95
+ }
@@ -0,0 +1,26 @@
1
+ import { Meta, StoryObj } from "@storybook/react-vite"
2
+ import RadioCard, { FormRadioCard } from "./RadioCard"
3
+ import { Page } from "../../../.storybook-react/decorators"
4
+
5
+ const meta: Meta<typeof RadioCard> = {
6
+ decorators: [Page],
7
+ component: RadioCard,
8
+ }
9
+
10
+ export default meta
11
+ export const RadioCards: StoryObj<typeof FormRadioCard> = {
12
+ render: ({ children, ...args }) => <FormRadioCard {...args}>{children}</FormRadioCard>,
13
+ args: {
14
+ label: "Do you hold a current concession card?",
15
+ children: (
16
+ <>
17
+ <RadioCard value="yes" hint="Pensioner Concession, Health Care or DVA card">
18
+ Yes, I hold a card
19
+ </RadioCard>
20
+ <RadioCard value="no" hint="You may still be eligible based on your income">
21
+ No
22
+ </RadioCard>
23
+ </>
24
+ ),
25
+ },
26
+ }
@@ -0,0 +1,59 @@
1
+ import { JSX, PropsWithChildren, useRef, createContext, use, useId } from "react"
2
+ import { useRadio, useRadioGroup, AriaRadioProps, AriaRadioGroupProps } from "react-aria"
3
+ import { useRadioGroupState, RadioGroupState } from "react-stately"
4
+ import classNames from "classnames"
5
+ import FormItem from "../FormItem/FormItem"
6
+ import { FormStatus } from "../../enums"
7
+
8
+ const RadioCardContext = createContext<RadioGroupState>(null)
9
+
10
+ type FormRadioCardProps = PropsWithChildren &
11
+ AriaRadioGroupProps & {
12
+ label?: string
13
+ }
14
+
15
+ const FormRadioCard = ({ label, children, ...props }: FormRadioCardProps): JSX.Element => {
16
+ const state = useRadioGroupState(props)
17
+ const { radioGroupProps } = useRadioGroup(props, state)
18
+
19
+ return (
20
+ <FormItem fieldset {...radioGroupProps} legend={label}>
21
+ <RadioCardContext value={state}>{children}</RadioCardContext>
22
+ </FormItem>
23
+ )
24
+ }
25
+
26
+ type RadioCardProps = PropsWithChildren &
27
+ AriaRadioProps & {
28
+ hint?: string
29
+ status?: FormStatus
30
+ className?: string
31
+ }
32
+
33
+ const RadioCard = ({
34
+ children,
35
+ hint = null,
36
+ status = FormStatus.DEFAULT,
37
+ className = "",
38
+ ...props
39
+ }: RadioCardProps): JSX.Element => {
40
+ const id = useId()
41
+ const ref = useRef<HTMLInputElement>(null)
42
+ const state = use(RadioCardContext)
43
+ const { inputProps } = useRadio(props, state, ref)
44
+
45
+ const classes = classNames("mx-radio", "mx-choice-card", className)
46
+
47
+ return (
48
+ <div className={classes}>
49
+ <input id={id} {...inputProps} ref={ref} aria-invalid={status === FormStatus.INVALID} />
50
+ <label htmlFor={id}>
51
+ {children}
52
+ {hint && <span className="mx-choice-card__hint">{hint}</span>}
53
+ </label>
54
+ </div>
55
+ )
56
+ }
57
+
58
+ export default RadioCard
59
+ export { FormRadioCard }
@@ -0,0 +1,69 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Checked 1`] = `
4
+ "
5
+ <fieldset class="mx-form-item mx-fieldset">
6
+
7
+ <legend class="mx-legend">
8
+ Do you hold a current concession card?
9
+ </legend>
10
+
11
+
12
+ <div class="mx-radio mx-choice-card">
13
+ <input id="card-yes" type="radio" name="card" value="yes" checked="checked">
14
+ <label for="card-yes">
15
+ Yes, I hold a card
16
+ <span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span> </label>
17
+ </div>
18
+ <div class="mx-radio mx-choice-card">
19
+ <input id="card-no" type="radio" name="card" value="no">
20
+ <label for="card-no">
21
+ No
22
+ <span class="mx-choice-card__hint">You may still be eligible based on your income</span> </label>
23
+ </div>
24
+
25
+
26
+
27
+ </fieldset>
28
+ "
29
+ `;
30
+
31
+ exports[`Radio Card 1`] = `
32
+ "
33
+ <fieldset class="mx-form-item mx-fieldset">
34
+
35
+ <legend class="mx-legend">
36
+ Do you hold a current concession card?
37
+ </legend>
38
+
39
+
40
+ <div class="mx-radio mx-choice-card">
41
+ <input id="card-yes" type="radio" name="card" value="yes">
42
+ <label for="card-yes">
43
+ Yes, I hold a card
44
+ <span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span> </label>
45
+ </div>
46
+ <div class="mx-radio mx-choice-card">
47
+ <input id="card-applied" type="radio" name="card" value="applied">
48
+ <label for="card-applied">
49
+ I have applied but not received it
50
+ <span class="mx-choice-card__hint">You can continue, but we may ask for evidence later</span> </label>
51
+ </div>
52
+ <div class="mx-radio mx-choice-card">
53
+ <input id="card-no" type="radio" name="card" value="no">
54
+ <label for="card-no">
55
+ No
56
+ <span class="mx-choice-card__hint">You may still be eligible based on your income</span> </label>
57
+ </div>
58
+ <div class="mx-choice-divider">or</div><div class="mx-radio mx-choice-card">
59
+ <input id="card-unsure" type="radio" name="card" value="unsure">
60
+ <label for="card-unsure">
61
+ I am not sure
62
+ <span class="mx-choice-card__hint">We will ask a few more questions to work it out</span> </label>
63
+ </div>
64
+
65
+
66
+
67
+ </fieldset>
68
+ "
69
+ `;
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Radio Cards 1`] = `"<fieldset class="mx-form-item mx-fieldset" role="radiogroup" aria-orientation="vertical" id="react-aria-_r_0_"><legend class="mx-legend">Do you hold a current concession card?</legend><div class="mx-radio mx-choice-card"><input id="_r_6_" data-react-aria-pressable="true" tabindex="0" aria-invalid="false" type="radio" value="yes" name="react-aria-_r_5_"><label for="_r_6_">Yes, I hold a card<span class="mx-choice-card__hint">Pensioner Concession, Health Care or DVA card</span></label></div><div class="mx-radio mx-choice-card"><input id="_r_8_" data-react-aria-pressable="true" tabindex="0" aria-invalid="false" type="radio" value="no" name="react-aria-_r_5_"><label for="_r_8_">No<span class="mx-choice-card__hint">You may still be eligible based on your income</span></label></div></fieldset>"`;
@@ -0,0 +1,20 @@
1
+ {% set classes = [
2
+ 'mx-radio',
3
+ 'mx-choice-card',
4
+ ] %}
5
+ {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
6
+ <div{{ attributes }}>
7
+ <input
8
+ id="{{ id }}"
9
+ type="radio"
10
+ name="{{ name }}"
11
+ value="{{ value }}"
12
+ {% if checked %} checked="checked"{% endif %}
13
+ {% if status == "invalid" %} aria-invalid="true"{% endif %}
14
+ {% if required %} required{% endif %}
15
+ >
16
+ <label for="{{ id }}">
17
+ {{ label }}
18
+ {% if hint %}<span class="mx-choice-card__hint">{{ hint }}</span>{% endif %}
19
+ </label>
20
+ </div>
@@ -32,10 +32,7 @@ const FormSelect = ({
32
32
  const handleChange: ChangeEventHandler<HTMLSelectElement> = ({ currentTarget }) =>
33
33
  setInputValue(currentTarget.value)
34
34
 
35
- const classes = classNames("mx-input__select", className, {
36
- error: status === FormStatus.INVALID,
37
- success: status === FormStatus.VALID,
38
- })
35
+ const classes = classNames("mx-input__select", className)
39
36
 
40
37
  const items = options.map(({ label: optionLabel, value }) => (
41
38
  <Option label={optionLabel} value={value} key={value} />
@@ -1,7 +1,5 @@
1
1
  {% set classes = [
2
2
  'mx-input__select',
3
- status == "invalid" ? "error" : null,
4
- status == "valid" ? "success" : null,
5
3
  ] %}
6
4
  {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
7
5
  {% if hasDescription or status != "default" %}
@@ -14,3 +14,17 @@ const meta: Meta<typeof Component> = {
14
14
 
15
15
  export default meta
16
16
  export const TextInput: StoryObj<typeof Component> = {}
17
+
18
+ /**
19
+ * `mx-validate` opts the input into live native validation — see the Twig
20
+ * `TextInput` stories for the full explanation.
21
+ */
22
+ export const Validate: StoryObj<typeof Component> = {
23
+ args: {
24
+ type: "email",
25
+ placeholder: "you@example.com",
26
+ "aria-label": "Email address",
27
+ required: true,
28
+ className: "mx-validate",
29
+ },
30
+ }
@@ -22,10 +22,7 @@ const FormText = ({
22
22
  const handleChange: ChangeEventHandler<HTMLInputElement> = ({ currentTarget }) =>
23
23
  setInputValue(currentTarget.value)
24
24
 
25
- const classes = classNames("mx-input__text", className, {
26
- error: status === FormStatus.INVALID,
27
- success: status === FormStatus.VALID,
28
- })
25
+ const classes = classNames("mx-input__text", className)
29
26
 
30
27
  return (
31
28
  <input
@@ -1,3 +1,5 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`Text Input 1`] = `"<input class="mx-input__text" id="mix-text" aria-describedby="help-mix-text" aria-invalid="false" placeholder="Placeholder" aria-label="Text input" type="text" value="">"`;
4
+
5
+ exports[`Validate 1`] = `"<input class="mx-input__text mx-validate" id="mix-text" required="" aria-describedby="help-mix-text" aria-invalid="false" placeholder="you@example.com" aria-label="Email address" type="email" value="">"`;
@@ -1,7 +1,5 @@
1
1
  {% set classes = [
2
2
  'mx-input__text',
3
- status == "invalid" ? "error" : null,
4
- status == "valid" ? "success" : null,
5
3
  ] %}
6
4
  {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
7
5
  {% set status = status|default("default") %}
@@ -21,10 +21,7 @@ const FormTextarea = ({
21
21
  const handleChange: ChangeEventHandler<HTMLTextAreaElement> = ({ currentTarget }) =>
22
22
  setInputValue(currentTarget.value)
23
23
 
24
- const classes = classNames("mx-input__textarea", className, {
25
- error: status === FormStatus.INVALID,
26
- success: status === FormStatus.VALID,
27
- })
24
+ const classes = classNames("mx-input__textarea", className)
28
25
 
29
26
  return (
30
27
  <textarea
@@ -1,7 +1,5 @@
1
1
  {% set classes = [
2
2
  'mx-input__textarea',
3
- status == "invalid" ? "error" : null,
4
- status == "valid" ? "success" : null,
5
3
  ] %}
6
4
  {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
7
5
  {% if hasDescription or status != "default" %}