@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
@@ -0,0 +1,153 @@
1
+ import { Meta, StoryObj } from "@storybook/html-vite"
2
+ import FormItem from "./FormItem/form-item.twig"
3
+ import Label from "./Label/label.twig"
4
+ import TextInput from "./TextInput/input-text.twig"
5
+ import Textarea from "./Textarea/input-textarea.twig"
6
+ import Select from "./Select/input-select.twig"
7
+ import Radio from "./Radio/input-radio.twig"
8
+ import Checkbox from "./Checkbox/input-checkbox.twig"
9
+ import Autocomplete from "./Autocomplete/autocomplete.twig"
10
+ import Button from "../Atom/Button/button.twig"
11
+ import "./form.css"
12
+ import "./Autocomplete/autocomplete.css"
13
+ import "./Autocomplete/Elements/Autocomplete"
14
+ import { InputTypeTypes } from "@pnx-mixtape/ids-shape"
15
+ import { DrupalAttribute } from "drupal-attribute"
16
+
17
+ const meta: Meta = {
18
+ tags: ["autodocs"],
19
+ parameters: {
20
+ a11y: {
21
+ config: {
22
+ rules: [
23
+ {
24
+ // ID's are not unique due to test-runner.
25
+ id: "label",
26
+ enabled: false,
27
+ },
28
+ ],
29
+ },
30
+ },
31
+ },
32
+ render: () =>
33
+ `<form class="mx-vertical-flow">${[
34
+ FormItem({
35
+ id: "validate-text",
36
+ label: Label({ id: "validate-text", title: "Email address", required: true }),
37
+ fields: TextInput({
38
+ id: "validate-text",
39
+ type: InputTypeTypes.EMAIL,
40
+ name: "validate-text",
41
+ placeholder: "you@example.com",
42
+ required: true,
43
+ attributes: new DrupalAttribute().addClass("mx-validate"),
44
+ }),
45
+ }),
46
+ FormItem({
47
+ id: "validate-textarea",
48
+ label: Label({ id: "validate-textarea", title: "Message", required: true }),
49
+ fields: Textarea({
50
+ id: "validate-textarea",
51
+ name: "validate-textarea",
52
+ required: true,
53
+ attributes: new DrupalAttribute().addClass("mx-validate"),
54
+ }),
55
+ }),
56
+ FormItem({
57
+ id: "validate-select",
58
+ label: Label({ id: "validate-select", title: "Favourite colour", required: true }),
59
+ fields: Select({
60
+ id: "validate-select",
61
+ name: "validate-select",
62
+ required: true,
63
+ attributes: new DrupalAttribute().addClass("mx-validate"),
64
+ options: [
65
+ { label: "Choose an option", value: "" },
66
+ { label: "Red", value: "red" },
67
+ { label: "Green", value: "green" },
68
+ { label: "Blue", value: "blue" },
69
+ ],
70
+ }),
71
+ }),
72
+ FormItem({
73
+ id: "validate-radio",
74
+ as: "fieldset",
75
+ label: Label({ title: "Do you like music?", as: "legend", required: true }),
76
+ fields: [
77
+ Radio({
78
+ id: "validate-radio-yes",
79
+ name: "validate-radio",
80
+ label: "Yes",
81
+ value: "yes",
82
+ required: true,
83
+ attributes: new DrupalAttribute().addClass("mx-validate"),
84
+ }),
85
+ Radio({
86
+ id: "validate-radio-no",
87
+ name: "validate-radio",
88
+ label: "No",
89
+ value: "no",
90
+ required: true,
91
+ attributes: new DrupalAttribute().addClass("mx-validate"),
92
+ }),
93
+ ].join(""),
94
+ }),
95
+ FormItem({
96
+ id: "validate-checkbox",
97
+ as: "fieldset",
98
+ label: Label({ title: "Which genres do you like?", as: "legend", required: true }),
99
+ fields: [
100
+ Checkbox({
101
+ id: "validate-checkbox-rock",
102
+ name: "validate-checkbox-rock",
103
+ label: "Rock",
104
+ value: "rock",
105
+ required: true,
106
+ attributes: new DrupalAttribute().addClass("mx-validate"),
107
+ }),
108
+ Checkbox({
109
+ id: "validate-checkbox-jazz",
110
+ name: "validate-checkbox-jazz",
111
+ label: "Jazz",
112
+ value: "jazz",
113
+ required: true,
114
+ attributes: new DrupalAttribute().addClass("mx-validate"),
115
+ }),
116
+ ].join(""),
117
+ }),
118
+ FormItem({
119
+ id: "validate-autocomplete",
120
+ label: Label({ id: "validate-autocomplete", title: "Favourite fruit", required: true }),
121
+ fields: Autocomplete({
122
+ id: "validate-autocomplete",
123
+ name: "validate-autocomplete",
124
+ label: "Favourite fruit",
125
+ type: InputTypeTypes.TEXT,
126
+ required: true,
127
+ attributes: new DrupalAttribute().addClass("mx-validate"),
128
+ options: [
129
+ { label: "Apple", value: "apple" },
130
+ { label: "Banana", value: "banana" },
131
+ { label: "Cherry", value: "cherry" },
132
+ ],
133
+ }),
134
+ }),
135
+ Button({ title: "Submit", as: "submit" }),
136
+ ].join("")}</form>`,
137
+ }
138
+
139
+ export default meta
140
+ type Story = StoryObj
141
+
142
+ /**
143
+ * `mx-validate` opts a control into live native validation — the border
144
+ * turns red once the browser rejects the value and the field has been
145
+ * interacted with, green once it's accepted.
146
+ *
147
+ * Add the class to the control itself (text input, textarea, select), or on
148
+ * the `.mx-radio` / `.mx-checkbox` / `.mx-autocomplete` wrapper for
149
+ * components that put `attributes` on the wrapper rather than the input.
150
+ *
151
+ * Hit Submit to trigger the invalid states on the empty required fields.
152
+ */
153
+ export const Validation: Story = {}
@@ -0,0 +1,130 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Validation 1`] = `
4
+ "<form class="mx-vertical-flow">
5
+ <div class="mx-form-item">
6
+
7
+ <label class="mx-label" for="validate-text">
8
+ Email address
9
+ <span class="mx-required">(required)</span></label>
10
+
11
+
12
+
13
+ <input class="mx-validate mx-input__text" id="validate-text" name="validate-text" type="email" value="" placeholder="you@example.com" required="">
14
+
15
+
16
+
17
+ </div>
18
+
19
+ <div class="mx-form-item">
20
+
21
+ <label class="mx-label" for="validate-textarea">
22
+ Message
23
+ <span class="mx-required">(required)</span></label>
24
+
25
+
26
+
27
+ <textarea class="mx-validate mx-input__textarea" id="unique-4" name="unique-0" aria-describedby="unique-0" required=""></textarea>
28
+
29
+
30
+
31
+ </div>
32
+
33
+ <div class="mx-form-item">
34
+
35
+ <label class="mx-label" for="validate-select">
36
+ Favourite colour
37
+ <span class="mx-required">(required)</span></label>
38
+
39
+
40
+
41
+ <select class="mx-validate mx-input__select" id="unique-5" name="unique-1" aria-describedby="unique-1" required="">
42
+ <button>
43
+ <selectedcontent>Choose an option</selectedcontent>
44
+ </button>
45
+ <option value="">Choose an option</option>
46
+ <option value="red">Red</option>
47
+ <option value="green">Green</option>
48
+ <option value="blue">Blue</option>
49
+ </select>
50
+
51
+
52
+
53
+ </div>
54
+
55
+ <fieldset class="mx-form-item mx-fieldset">
56
+
57
+ <legend class="mx-legend">
58
+ Do you like music?
59
+ <span class="mx-required">(required)</span></legend>
60
+
61
+
62
+ <div class="mx-validate mx-radio">
63
+ <input id="validate-radio-yes" type="radio" name="validate-radio" value="yes" required="">
64
+ <label for="validate-radio-yes">Yes</label>
65
+ </div>
66
+ <div class="mx-validate mx-radio">
67
+ <input id="validate-radio-no" type="radio" name="validate-radio" value="no" required="">
68
+ <label for="validate-radio-no">No</label>
69
+ </div>
70
+
71
+
72
+
73
+ </fieldset>
74
+
75
+ <fieldset class="mx-form-item mx-fieldset">
76
+
77
+ <legend class="mx-legend">
78
+ Which genres do you like?
79
+ <span class="mx-required">(required)</span></legend>
80
+
81
+
82
+
83
+ <div class="mx-validate mx-checkbox">
84
+ <input id="validate-checkbox-rock" type="checkbox" name="validate-checkbox-rock" value="rock" required="">
85
+ <label for="validate-checkbox-rock">Rock</label>
86
+ </div>
87
+
88
+ <div class="mx-validate mx-checkbox">
89
+ <input id="validate-checkbox-jazz" type="checkbox" name="validate-checkbox-jazz" value="jazz" required="">
90
+ <label for="validate-checkbox-jazz">Jazz</label>
91
+ </div>
92
+
93
+
94
+
95
+ </fieldset>
96
+
97
+ <div class="mx-form-item">
98
+
99
+ <label class="mx-label" for="validate-autocomplete">
100
+ Favourite fruit
101
+ <span class="mx-required">(required)</span></label>
102
+
103
+
104
+
105
+ <mx-autocomplete class="mx-autocomplete">
106
+ <div class="mx-autocomplete__control mx-form--inline-button" data-control="">
107
+ <input class="mx-validate mx-input__text" id="unique-6" name="unique-2" type="text" role="combobox" aria-expanded="false" aria-controls="unique-2" aria-autocomplete="list" aria-activedescendant="" aria-describedby="unique-2" aria-label="Favourite fruit" autocomplete="off" required="">
108
+ </div>
109
+ <div class="mx-autocomplete__suggestions">
110
+
111
+ <ul class="mx-autocomplete__listbox" id="unique-0" role="listbox" hidden="">
112
+ <li class="mx-autocomplete__option" id="validate-autocomplete-option-0" role="option" data-value="apple" aria-selected="false">Apple</li>
113
+ <li class="mx-autocomplete__option" id="validate-autocomplete-option-1" role="option" data-value="banana" aria-selected="false">Banana</li>
114
+ <li class="mx-autocomplete__option" id="validate-autocomplete-option-2" role="option" data-value="cherry" aria-selected="false">Cherry</li>
115
+ </ul>
116
+ <output class="sr-only" aria-live="polite" data-autocomplete-status=""></output>
117
+ </div>
118
+ </mx-autocomplete>
119
+
120
+
121
+
122
+ </div>
123
+
124
+ <button class="mx-button" type="submit">
125
+
126
+ <span>Submit</span>
127
+
128
+ </button>
129
+ </form>"
130
+ `;
package/src/Form/form.css CHANGED
@@ -1,3 +1,5 @@
1
+ @import "../Utility/_mixins.css";
2
+
1
3
  /**
2
4
  * Form
3
5
  */
@@ -65,14 +67,15 @@
65
67
  &[disabled] {
66
68
  opacity: var(--disabled-opacity, 0.6);
67
69
  cursor: not-allowed;
68
- }
69
-
70
- &.error {
71
- border-color: var(--error-foreground, var(--colour-error));
72
- }
73
70
 
74
- &.success {
75
- border-color: var(--success-foreground, var(--colour-success));
71
+ @media (--forced-colors) {
72
+ /* opt out so GrayText survives */
73
+ forced-color-adjust: none;
74
+ opacity: 1;
75
+ color: GrayText;
76
+ border-color: GrayText;
77
+ background-color: Canvas;
78
+ }
76
79
  }
77
80
  }
78
81
 
@@ -123,12 +126,12 @@
123
126
  background-color: transparent;
124
127
  }
125
128
 
126
- &:has(.error)::before {
127
- background-color: var(--error-foreground, var(--colour-error));
129
+ &:has(.mx-validate:user-valid)::before {
130
+ background-color: var(--success-foreground, var(--colour-success));
128
131
  }
129
132
 
130
- &:has(.success)::before {
131
- background-color: var(--success-foreground, var(--colour-success));
133
+ &:has(:is(.mx-validate:user-invalid, [aria-invalid="true"]))::before {
134
+ background-color: var(--error-foreground, var(--colour-error));
132
135
  }
133
136
  }
134
137
  }
@@ -153,6 +156,17 @@
153
156
  outline-offset: calc(var(--line-width, 2px) * -1);
154
157
  }
155
158
 
159
+ &:has(.mx-validate:user-valid),
160
+ .mx-validate &:has(:user-valid) {
161
+ border-color: var(--success-foreground, var(--colour-success));
162
+ }
163
+
164
+ &:has(.mx-validate:user-invalid),
165
+ .mx-validate &:has(:user-invalid),
166
+ &:has([aria-invalid="true"]) {
167
+ border-color: var(--error-foreground, var(--colour-error));
168
+ }
169
+
156
170
  & .mx-input__text {
157
171
  background-color: transparent;
158
172
  border: 0;
@@ -195,45 +209,57 @@
195
209
  .mx-checkbox [type="checkbox"] {
196
210
  box-shadow: none;
197
211
  appearance: none;
212
+ display: flex;
198
213
  inline-size: var(--control-size, var(--spacing-m));
199
214
  block-size: var(--control-size, var(--spacing-m));
200
215
  background-color: var(--background, var(--colour-background));
201
216
  border: var(--line-width, 2px) solid var(--line-colour, var(--colour-border));
202
217
  border-radius: var(--border-radius);
218
+ font-size: 1rem;
203
219
 
204
220
  @media (pointer: coarse) {
205
221
  --control-size: 2rem;
206
222
  }
207
223
 
208
- &:checked {
209
- background-image: url("./images/checkmark.svg");
210
- background-size: 0.75rem;
211
- background-position: center;
224
+ &:checked::after {
225
+ content: "";
226
+ display: block;
227
+ inline-size: 0.75rem;
228
+ block-size: 0.75rem;
229
+ margin: auto;
230
+ mask-image: url("./images/checkmark.svg");
231
+ mask-size: contain;
232
+ mask-position: center;
233
+ mask-repeat: no-repeat;
234
+ background-color: var(--checkbox-colour, currentcolor);
235
+
236
+ @add-mixin forced-colors-paint;
212
237
  }
213
238
 
214
239
  &[disabled] {
215
- &::after {
216
- opacity: var(--disabled-opacity, 0.6);
217
- cursor: not-allowed;
218
- content: "";
219
- display: block;
220
- inline-size: 100%;
221
- block-size: 100%;
222
- border-radius: var(--border-radius);
223
- }
240
+ cursor: not-allowed;
224
241
 
225
242
  & + label {
226
243
  opacity: var(--disabled-opacity, 0.6);
227
244
  cursor: not-allowed;
245
+
246
+ @media (--forced-colors) {
247
+ /* opt out or the UA forces this straight back to CanvasText */
248
+ forced-color-adjust: none;
249
+ opacity: 1;
250
+ color: GrayText;
251
+ }
228
252
  }
229
- }
230
253
 
231
- &.error {
232
- border-color: var(--error-foreground, var(--colour-error));
233
- }
254
+ @media (--forced-colors) {
255
+ /* opt out so GrayText survives */
256
+ --forced-colour: GrayText;
234
257
 
235
- &.success {
236
- border-color: var(--success-foreground, var(--colour-success));
258
+ forced-color-adjust: none;
259
+ color: GrayText;
260
+ border-color: GrayText;
261
+ background-color: Canvas;
262
+ }
237
263
  }
238
264
  }
239
265
  }
@@ -256,46 +282,48 @@
256
282
  background-color: var(--background, var(--colour-background));
257
283
  border: var(--line-width, 2px) solid var(--line-colour, var(--colour-border));
258
284
  border-radius: 50%;
285
+ font-size: 1rem;
259
286
 
260
287
  @media (pointer: coarse) {
261
288
  --control-size: 2rem;
262
289
  }
263
290
 
264
- &:checked {
265
- &::after {
266
- content: "";
267
- display: block;
268
- inline-size: 0.5rem;
269
- block-size: 0.5rem;
270
- margin: auto;
271
- border-radius: 50%;
272
- background-color: var(--radio-colour, var(--colour-primary));
273
- }
291
+ &:checked::after {
292
+ content: "";
293
+ display: block;
294
+ inline-size: 0.5rem;
295
+ block-size: 0.5rem;
296
+ margin: auto;
297
+ border-radius: 50%;
298
+ background-color: var(--radio-colour, var(--colour-primary));
299
+
300
+ @add-mixin forced-colors-paint;
274
301
  }
275
302
 
276
303
  &[disabled] {
277
- &::after {
278
- opacity: var(--disabled-opacity, 0.6);
279
- cursor: not-allowed;
280
- content: "";
281
- display: block;
282
- inline-size: 100%;
283
- block-size: 100%;
284
- border-radius: 50%;
285
- }
304
+ cursor: not-allowed;
286
305
 
287
306
  & + label {
288
307
  opacity: var(--disabled-opacity, 0.6);
289
308
  cursor: not-allowed;
309
+
310
+ @media (--forced-colors) {
311
+ /* opt out or the UA forces this straight back to CanvasText */
312
+ forced-color-adjust: none;
313
+ opacity: 1;
314
+ color: GrayText;
315
+ }
290
316
  }
291
- }
292
317
 
293
- &.error {
294
- border-color: var(--error-foreground, var(--colour-error));
295
- }
318
+ @media (--forced-colors) {
319
+ /* opt out so GrayText survives */
320
+ --forced-colour: GrayText;
296
321
 
297
- &.success {
298
- border-color: var(--success-foreground, var(--colour-success));
322
+ forced-color-adjust: none;
323
+ color: GrayText;
324
+ border-color: GrayText;
325
+ background-color: Canvas;
326
+ }
299
327
  }
300
328
  }
301
329
 
@@ -337,6 +365,96 @@
337
365
  }
338
366
  }
339
367
 
368
+ /**
369
+ * Choice cards.
370
+ */
371
+
372
+ @layer design-system.components {
373
+ .mx-choice-card {
374
+ /* @public --choice-padding-block --choice-padding-inline --choice-colour-active */
375
+ display: block;
376
+ position: relative;
377
+ border: var(--line-width, 2px) solid var(--line-colour, var(--colour-border));
378
+ border-radius: var(--border-radius);
379
+ background-color: var(--background, var(--colour-background));
380
+ transition:
381
+ border-color 0.12s linear,
382
+ background-color 0.12s linear;
383
+
384
+ & label {
385
+ display: grid;
386
+ gap: var(--spacing-xxxs);
387
+ padding-block: var(--choice-padding-block, var(--spacing-s));
388
+ padding-inline: calc(
389
+ var(--control-size, var(--spacing-m)) + var(--choice-padding-inline, var(--spacing-m)) * 2
390
+ )
391
+ var(--choice-padding-inline, var(--spacing-m));
392
+ min-block-size: calc(
393
+ var(--control-size, var(--spacing-m)) + var(--choice-padding-block, var(--spacing-s)) * 2
394
+ );
395
+ cursor: pointer;
396
+ font-weight: var(--font-weight-bold);
397
+ }
398
+
399
+ & input {
400
+ position: absolute;
401
+ inset-block-start: var(--choice-padding-block, var(--spacing-s));
402
+ inset-inline-start: var(--choice-padding-inline, var(--spacing-m));
403
+ }
404
+
405
+ &:has(input:checked) {
406
+ border-color: var(--choice-colour-active, var(--colour-primary));
407
+ background-color: color-mix(
408
+ in oklch,
409
+ var(--choice-colour-active, var(--colour-primary)),
410
+ white 95%
411
+ );
412
+ }
413
+
414
+ &:hover {
415
+ border-color: var(--choice-colour-active, var(--colour-primary));
416
+ }
417
+
418
+ &:has(.mx-validate:user-valid),
419
+ .mx-validate &:has(:user-valid) {
420
+ border-color: var(--success-foreground, var(--colour-success));
421
+ }
422
+
423
+ &:has(.mx-validate:user-invalid),
424
+ .mx-validate &:has(:user-invalid),
425
+ &:has([aria-invalid="true"]) {
426
+ border-color: var(--error-foreground, var(--colour-error));
427
+ }
428
+ }
429
+
430
+ .mx-choice-divider {
431
+ display: flex;
432
+ align-items: center;
433
+ gap: var(--spacing-xs);
434
+ font-size: var(--font-size-s);
435
+ color: var(--colour-foreground-alt);
436
+ margin-block-end: var(--spacing-xxxs);
437
+
438
+ &::before,
439
+ &::after {
440
+ content: "";
441
+ flex: 1;
442
+ block-size: 1px;
443
+ background-color: var(--colour-border);
444
+ }
445
+ }
446
+
447
+ .mx-choice-card__hint {
448
+ font-weight: var(--font-weight-normal);
449
+ font-size: var(--font-size-s);
450
+ color: var(--colour-foreground-alt);
451
+ }
452
+
453
+ .mx-description + .mx-choice-card {
454
+ margin-block-start: var(--spacing-xxxs);
455
+ }
456
+ }
457
+
340
458
  /**
341
459
  * Select
342
460
  */
@@ -388,12 +506,25 @@
388
506
  }
389
507
  }
390
508
 
509
+ /* A <select> has no pseudo-element to mask, and the chevron asset is a
510
+ fixed black, so on the legacy path hand the arrow back to the UA under
511
+ forced colours. The base-select path masks ::picker-icon instead. */
512
+ @supports not (appearance: base-select) {
513
+ @media (--forced-colors) {
514
+ appearance: auto;
515
+ background-image: none;
516
+ padding-inline-end: revert;
517
+ }
518
+ }
519
+
391
520
  &::picker-icon {
392
521
  mask-image: url("./images/form-chevron-down.svg");
393
522
  mask-repeat: no-repeat;
394
523
  mask-position: center;
395
524
  background-color: currentcolor;
396
525
  aspect-ratio: 1 / 1;
526
+
527
+ @add-mixin forced-colors-paint;
397
528
  }
398
529
 
399
530
  &:open::picker-icon {
@@ -407,6 +538,8 @@
407
538
  display: block;
408
539
  mask-image: url("./images/checkmark.svg");
409
540
  background-color: currentcolor;
541
+
542
+ @add-mixin forced-colors-paint;
410
543
  }
411
544
 
412
545
  &[multiple] {
@@ -527,10 +660,62 @@
527
660
  .mx-error-message::before {
528
661
  mask-image: url("./images/form-error.svg");
529
662
  background-color: var(--error-foreground, var(--colour-error));
663
+
664
+ @add-mixin forced-colors-paint;
530
665
  }
531
666
 
532
667
  .mx-success-message::before {
533
668
  mask-image: url("./images/form-success.svg");
534
669
  background-color: var(--success-foreground, var(--colour-success));
670
+
671
+ @add-mixin forced-colors-paint;
672
+ }
673
+ }
674
+
675
+ /**
676
+ * Validation state
677
+ *
678
+ * Two separate hooks, deliberately:
679
+ *
680
+ * 1. .mx-validate — opt in to *live* native validation. :user-valid /
681
+ * :user-invalid fire on their own as the user types, so without this class
682
+ * a control is never coloured automatically (filling in an unmarked field
683
+ * doesn't turn it green).
684
+ *
685
+ * Put it on the control itself, or on a .mx-checkbox / .mx-radio /
686
+ * .mx-autocomplete wrapper — those three components put `className` and
687
+ * Drupal `attributes` on the wrapper, not the input, so the wrapper is the
688
+ * only reachable spot. The wrapper half is scoped to those class names on
689
+ * purpose: a bare descendant selector would leak, styling checkboxes
690
+ * inside any .mx-validate ancestor while leaving text inputs alone.
691
+ *
692
+ * 2. [aria-invalid="true"] — an *explicit* error, no opt-in: server-rendered
693
+ * (Drupal) or async failures the browser can't see. The consumer has
694
+ * already decided the field is wrong, so there's nothing to opt into.
695
+ *
696
+ * :user-* is used rather than :valid / :invalid so a blank required field
697
+ * isn't red on page load.
698
+ *
699
+ * Explicit errors are excluded from live success styling so they stay red.
700
+ */
701
+
702
+ @layer design-system.atoms {
703
+ .mx-validate,
704
+ :is(.mx-checkbox, .mx-radio, .mx-autocomplete).mx-validate :is(input, select, textarea) {
705
+ &:user-valid:not([aria-invalid="true"]) {
706
+ border-color: var(--success-foreground, var(--colour-success));
707
+ }
708
+
709
+ &:user-invalid {
710
+ border-color: var(--error-foreground, var(--colour-error));
711
+ }
712
+ }
713
+
714
+ .mx-input__text[aria-invalid="true"],
715
+ .mx-input__select[aria-invalid="true"],
716
+ .mx-input__textarea[aria-invalid="true"],
717
+ .mx-checkbox [type="checkbox"][aria-invalid="true"],
718
+ .mx-radio [type="radio"][aria-invalid="true"] {
719
+ border-color: var(--error-foreground, var(--colour-error));
535
720
  }
536
721
  }