@pnx-mixtape/mxds 0.1.0-rc.4 → 0.1.0-rc.6

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 (236) hide show
  1. package/.claude/skills/create-mxds-component/SKILL.md +77 -0
  2. package/DESIGN.md +595 -0
  3. package/README.md +2 -3
  4. package/dist/build/accordion.entry.js +2 -1
  5. package/dist/build/autocomplete.entry.js +1 -1
  6. package/dist/build/back-to-top.css +1 -0
  7. package/dist/build/back-to-top.entry.js +1 -0
  8. package/dist/build/base.css +1 -1
  9. package/dist/build/button.css +1 -1
  10. package/dist/build/card.css +1 -1
  11. package/dist/build/chunks/Accordion-Bqe8vTNR.js +44 -0
  12. package/dist/build/chunks/AccordionGroup-BYtoAFxg.js +47 -0
  13. package/dist/build/chunks/AccordionMobile-D517oXYZ.js +26 -0
  14. package/dist/build/chunks/Autocomplete-kRo8RNbC.js +135 -0
  15. package/dist/build/chunks/BackToTop-4M-Wl7z3.js +64 -0
  16. package/dist/build/chunks/ClosableAlert-CZ114JsL.js +55 -0
  17. package/dist/build/chunks/CookieConsent-wd8gQ2Oe.js +18 -0
  18. package/dist/build/chunks/Dialog-DoYcGqhW.js +48 -0
  19. package/dist/build/chunks/DropMenu-CSTZq0Zt.js +68 -0
  20. package/dist/build/chunks/FeedbackForm-BsL7fv8s.js +64 -0
  21. package/dist/build/chunks/Gallery-DqJPujX5.js +165 -0
  22. package/dist/build/chunks/GlobalToggle-7H3F1Wvc.js +82 -0
  23. package/dist/build/chunks/InPageNavigation-D7m3IN89.js +86 -0
  24. package/dist/build/chunks/Navigation-CRModT40.js +142 -0
  25. package/dist/build/chunks/Popover-CiTAftNU.js +30 -0
  26. package/dist/build/chunks/Sticky-C1H8MNqK.js +51 -0
  27. package/dist/build/chunks/Tabs-BJD3kABL.js +160 -0
  28. package/dist/build/chunks/Translate-yAgySwet.js +46 -0
  29. package/dist/build/chunks/cookie-compliance-CG6x-TcV.js +119 -0
  30. package/dist/build/chunks/enums-BrHxPZZ_.js +36 -0
  31. package/dist/build/chunks/polyfills-D-qh1a_2.js +33 -0
  32. package/dist/build/chunks/utilities-B9mNRs7V.js +255 -0
  33. package/dist/build/content-block.css +1 -1
  34. package/dist/build/cookie-consent.entry.js +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 +147 -1
  38. package/dist/build/feedback-form.css +1 -0
  39. package/dist/build/feedback-form.entry.js +1 -0
  40. package/dist/build/filters.entry.js +145 -1
  41. package/dist/build/form.css +1 -1
  42. package/dist/build/gallery.entry.js +1 -1
  43. package/dist/build/global-alert.entry.js +1 -1
  44. package/dist/build/header.css +1 -1
  45. package/dist/build/header.entry.js +1 -1
  46. package/dist/build/icon.css +1 -1
  47. package/dist/build/in-page-navigation.entry.js +1 -1
  48. package/dist/build/navigation.css +1 -1
  49. package/dist/build/navigation.entry.js +1 -1
  50. package/dist/build/pagination.css +1 -1
  51. package/dist/build/popover.entry.js +1 -1
  52. package/dist/build/react.js +2291 -1
  53. package/dist/build/side-navigation.css +1 -1
  54. package/dist/build/sidebar.css +1 -1
  55. package/dist/build/sticky.entry.js +1 -1
  56. package/dist/build/tabs.entry.js +1 -1
  57. package/dist/build/translate.css +1 -0
  58. package/dist/build/translate.entry.js +1 -0
  59. package/dist/build/utility-list.entry.js +53 -1
  60. package/dist/types/Component/BackToTop/BackToTop.d.ts +20 -0
  61. package/dist/types/Component/BackToTop/BackToTop.d.ts.map +1 -0
  62. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts +27 -0
  63. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts.map +1 -0
  64. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts +2 -0
  65. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts.map +1 -0
  66. package/dist/types/Component/DropMenu/DropMenu.d.ts +2 -1
  67. package/dist/types/Component/DropMenu/DropMenu.d.ts.map +1 -1
  68. package/dist/types/Component/Navigation/Elements/Navigation.d.ts +2 -3
  69. package/dist/types/Component/Navigation/Elements/Navigation.d.ts.map +1 -1
  70. package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts +3 -3
  71. package/dist/types/Component/SideNavigation/Components/SideNavigationTree.d.ts.map +1 -1
  72. package/dist/types/Component/SideNavigation/SideNavigation.d.ts +3 -1
  73. package/dist/types/Component/SideNavigation/SideNavigation.d.ts.map +1 -1
  74. package/dist/types/Component/Tabs/Components/TabDropMenu.d.ts.map +1 -1
  75. package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
  76. package/dist/types/Component/Translate/Elements/Translate.d.ts +23 -0
  77. package/dist/types/Component/Translate/Elements/Translate.d.ts.map +1 -0
  78. package/dist/types/Component/Translate/Translate.d.ts +37 -0
  79. package/dist/types/Component/Translate/Translate.d.ts.map +1 -0
  80. package/dist/types/Component/Translate/languages.d.ts +11 -0
  81. package/dist/types/Component/Translate/languages.d.ts.map +1 -0
  82. package/dist/types/Component/Translate/translate.entry.d.ts +2 -0
  83. package/dist/types/Component/Translate/translate.entry.d.ts.map +1 -0
  84. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts +37 -0
  85. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts.map +1 -0
  86. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts +36 -0
  87. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts.map +1 -0
  88. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts +2 -0
  89. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts.map +1 -0
  90. package/dist/types/Utility/Elements/google-translate-widget.d.ts +91 -0
  91. package/dist/types/Utility/Elements/google-translate-widget.d.ts.map +1 -0
  92. package/dist/types/Utility/utilities.d.ts +2 -0
  93. package/dist/types/Utility/utilities.d.ts.map +1 -1
  94. package/dist/types/elements.d.ts +3 -0
  95. package/dist/types/elements.d.ts.map +1 -1
  96. package/dist/types/enums.d.ts +3 -1
  97. package/dist/types/enums.d.ts.map +1 -1
  98. package/dist/types/react.d.ts +3 -0
  99. package/dist/types/react.d.ts.map +1 -1
  100. package/dist/types/tokens.d.ts +1 -0
  101. package/dist/types/tokens.d.ts.map +1 -1
  102. package/docs/API.md +1215 -0
  103. package/docs/CSSGuidelines.md +893 -0
  104. package/docs/CodeQuality.md +940 -0
  105. package/docs/ComponentArchitecture.md +714 -0
  106. package/docs/Contributing.md +626 -0
  107. package/docs/MemoryManagement.md +598 -0
  108. package/docs/Migrations.md +6 -0
  109. package/docs/README.md +100 -0
  110. package/docs/Security.md +444 -0
  111. package/docs/Testing.md +739 -0
  112. package/docs/Troubleshooting.md +674 -0
  113. package/package.json +9 -6
  114. package/src/Atom/Button/Button.tsx +1 -1
  115. package/src/Atom/Button/__snapshots__/Button.stories.tsx.snap +2 -2
  116. package/src/Atom/Button/_buttons.css +1 -0
  117. package/src/Atom/Icon/README.md +1 -1
  118. package/src/Atom/Icon/_icon.css +1 -0
  119. package/src/Atom/Icon/images/thumb.svg +1 -0
  120. package/src/Atom/Link/_links.css +1 -0
  121. package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +4 -9
  122. package/src/Atom/Media/media.twig +4 -5
  123. package/src/Component/BackToTop/BackToTop.stories.ts +127 -0
  124. package/src/Component/BackToTop/BackToTop.stories.tsx +53 -0
  125. package/src/Component/BackToTop/BackToTop.tsx +120 -0
  126. package/src/Component/BackToTop/Elements/BackToTop.ts +119 -0
  127. package/src/Component/BackToTop/README.md +164 -0
  128. package/src/Component/BackToTop/__snapshots__/BackToTop.stories.ts.snap +24 -0
  129. package/src/Component/BackToTop/__snapshots__/BackToTop.stories.tsx.snap +3 -0
  130. package/src/Component/BackToTop/back-to-top.css +70 -0
  131. package/src/Component/BackToTop/back-to-top.entry.js +1 -0
  132. package/src/Component/BackToTop/back-to-top.twig +26 -0
  133. package/src/Component/Card/Components/CardContent.tsx +1 -1
  134. package/src/Component/Card/Components/CardMedia.tsx +1 -1
  135. package/src/Component/Card/__snapshots__/Card.stories.tsx.snap +3 -3
  136. package/src/Component/Card/card.css +1 -1
  137. package/src/Component/Carousel/Carousel.stories.ts +66 -36
  138. package/src/Component/Carousel/__snapshots__/Carousel.stories.tsx.snap +5 -5
  139. package/src/Component/ContentBlock/Components/ContentBlockMedia.tsx +1 -1
  140. package/src/Component/ContentBlock/content-block.css +1 -1
  141. package/src/Component/DropMenu/DropMenu.stories.ts +21 -2
  142. package/src/Component/DropMenu/DropMenu.tsx +14 -4
  143. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +3 -3
  144. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.tsx.snap +2 -2
  145. package/src/Component/DropMenu/drop-menu.twig +7 -1
  146. package/src/Component/HeroBanner/__snapshots__/HeroBanner.stories.tsx.snap +1 -1
  147. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +48 -13
  148. package/src/Component/InPageNavigation/in-page-navigation.twig +4 -6
  149. package/src/Component/ListItem/Components/ListItemMedia.tsx +1 -1
  150. package/src/Component/Navigation/Elements/Navigation.ts +25 -29
  151. package/src/Component/Navigation/README.md +11 -10
  152. package/src/Component/Navigation/__snapshots__/Navigation.stories.ts.snap +8 -8
  153. package/src/Component/Navigation/_navigation-dropdown.css +9 -11
  154. package/src/Component/Navigation/_navigation-mega.css +5 -11
  155. package/src/Component/Navigation/_navigation.css +5 -3
  156. package/src/Component/Navigation/menu.twig +1 -1
  157. package/src/Component/Navigation/navigation.twig +0 -1
  158. package/src/Component/Pagination/Pagination.stories.ts +57 -27
  159. package/src/Component/Pagination/pagination.css +16 -7
  160. package/src/Component/Popover/__snapshots__/Popover.stories.tsx.snap +3 -3
  161. package/src/Component/SideNavigation/Components/SideNavigationTree.tsx +68 -24
  162. package/src/Component/SideNavigation/README.md +78 -32
  163. package/src/Component/SideNavigation/SideNavigation.stories.ts +41 -2
  164. package/src/Component/SideNavigation/SideNavigation.stories.tsx +31 -0
  165. package/src/Component/SideNavigation/SideNavigation.tsx +13 -3
  166. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.ts.snap +87 -3
  167. package/src/Component/SideNavigation/__snapshots__/SideNavigation.stories.tsx.snap +2 -0
  168. package/src/Component/SideNavigation/side-navigation.css +3 -3
  169. package/src/Component/SideNavigation/side-navigation.twig +10 -3
  170. package/src/Component/Tabs/Components/TabDropMenu.tsx +7 -1
  171. package/src/Component/Tabs/Elements/Tabs.ts +13 -3
  172. package/src/Component/Tabs/Tabs.stories.ts +33 -12
  173. package/src/Component/Tabs/Tabs.stories.tsx +28 -14
  174. package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +3 -3
  175. package/src/Component/Tabs/__snapshots__/Tabs.stories.tsx.snap +2 -2
  176. package/src/Component/Translate/Elements/Translate.ts +76 -0
  177. package/src/Component/Translate/README.md +285 -0
  178. package/src/Component/Translate/Translate.stories.ts +87 -0
  179. package/src/Component/Translate/Translate.stories.tsx +77 -0
  180. package/src/Component/Translate/Translate.tsx +213 -0
  181. package/src/Component/Translate/__snapshots__/Translate.stories.ts.snap +18 -0
  182. package/src/Component/Translate/__snapshots__/Translate.stories.tsx.snap +3 -0
  183. package/src/Component/Translate/languages.ts +39 -0
  184. package/src/Component/Translate/translate.css +62 -0
  185. package/src/Component/Translate/translate.entry.js +1 -0
  186. package/src/Component/Translate/translate.twig +44 -0
  187. package/src/Form/Autocomplete/Autocomplete.stories.tsx +2 -1
  188. package/src/Form/FeedbackForm/Elements/FeedbackForm.ts +122 -0
  189. package/src/Form/FeedbackForm/FeedbackForm.stories.ts +99 -0
  190. package/src/Form/FeedbackForm/FeedbackForm.stories.tsx +73 -0
  191. package/src/Form/FeedbackForm/FeedbackForm.tsx +196 -0
  192. package/src/Form/FeedbackForm/README.md +233 -0
  193. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.ts.snap +125 -0
  194. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.tsx.snap +5 -0
  195. package/src/Form/FeedbackForm/feedback-form.css +74 -0
  196. package/src/Form/FeedbackForm/feedback-form.entry.js +1 -0
  197. package/src/Form/FeedbackForm/feedback-form.twig +80 -0
  198. package/src/Form/form.css +17 -19
  199. package/src/Introduction.mdx +1 -1
  200. package/src/Layout/Footer/__snapshots__/Footer.stories.ts.snap +3 -3
  201. package/src/Layout/Header/Components/GlobalToggle.tsx +1 -1
  202. package/src/Layout/Header/Header.stories.ts +53 -48
  203. package/src/Layout/Header/Header.stories.tsx +35 -22
  204. package/src/Layout/Header/Header.tsx +2 -2
  205. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +18 -14
  206. package/src/Layout/Header/__snapshots__/Header.stories.tsx.snap +2 -2
  207. package/src/Layout/Header/_toggles.css +7 -7
  208. package/src/Layout/Page/__snapshots__/Page.stories.tsx.snap +1 -1
  209. package/src/Layout/Sidebar/sidebar.css +10 -3
  210. package/src/Utility/Elements/google-translate-widget.ts +293 -0
  211. package/src/Utility/global.d.ts +4 -0
  212. package/src/Utility/utilities.ts +2 -0
  213. package/src/_custom-media.css +2 -0
  214. package/src/elements.ts +3 -0
  215. package/src/enums.ts +2 -0
  216. package/src/react.ts +3 -0
  217. package/src/tokens.js +1 -0
  218. package/dist/build/chunks/Accordion-GN0sME4W.js +0 -1
  219. package/dist/build/chunks/AccordionGroup-Bzqp5__q.js +0 -1
  220. package/dist/build/chunks/AccordionMobile-DG5jSe8Q.js +0 -1
  221. package/dist/build/chunks/Autocomplete-B4RtkAyh.js +0 -1
  222. package/dist/build/chunks/ClosableAlert-DEhj8Nxm.js +0 -1
  223. package/dist/build/chunks/CookieConsent-BkCMRVST.js +0 -1
  224. package/dist/build/chunks/Dialog-Haahn-Yn.js +0 -1
  225. package/dist/build/chunks/DropMenu-1baQc8Yc.js +0 -1
  226. package/dist/build/chunks/Gallery-D8NGXy2Q.js +0 -1
  227. package/dist/build/chunks/GlobalToggle-B52fdBQu.js +0 -1
  228. package/dist/build/chunks/InPageNavigation-Dyn2TR-N.js +0 -1
  229. package/dist/build/chunks/Navigation-hOrfLq7h.js +0 -1
  230. package/dist/build/chunks/Popover-Cxg-s5Jn.js +0 -1
  231. package/dist/build/chunks/Sticky-BGCuuEJK.js +0 -1
  232. package/dist/build/chunks/Tabs-DYy1YTdU.js +0 -15
  233. package/dist/build/chunks/cookie-compliance-Bbm-0vpj.js +0 -1
  234. package/dist/build/chunks/enums-DLV_1NAf.js +0 -1
  235. package/dist/build/chunks/polyfills-C7pRt54M.js +0 -1
  236. package/dist/build/chunks/utilities-_Bq3TxAQ.js +0 -1
@@ -0,0 +1,164 @@
1
+ # BackToTop
2
+
3
+ A trigger that appears once the reader has scrolled past a threshold and jumps back to a target
4
+ element on the page. Shows/hides itself via `IntersectionObserver`, and manages focus and
5
+ reduced-motion-aware smooth scrolling when activated.
6
+
7
+ ---
8
+
9
+ ## CSS Import
10
+
11
+ ```css
12
+ @import "@pnx-mixtape/mxds/src/Component/BackToTop/back-to-top.css";
13
+ ```
14
+
15
+ ---
16
+
17
+ ## Twig
18
+
19
+ ```twig
20
+ {% include '@mixtape/Component/BackToTop/back-to-top.twig' with {
21
+ href: '#main',
22
+ title: 'Back to top',
23
+ } %}
24
+
25
+ {# Watch a specific element (e.g. the page's <h1>) instead of a scroll distance #}
26
+ {% include '@mixtape/Component/BackToTop/back-to-top.twig' with {
27
+ target: '#page-title',
28
+ href: '#main',
29
+ } %}
30
+ ```
31
+
32
+ **back-to-top.twig props:**
33
+
34
+ | Prop | Type | Default | Description |
35
+ | -------------- | ----------- | ------------- | ------------------------------------------------------------------------------------------------------------ |
36
+ | `href` | `string` | `#main` | Scroll destination — a same-page hash |
37
+ | `title` | `string` | `Back to top` | Trigger label |
38
+ | `target` | `string` | — | CSS selector of an element to observe — visible once it scrolls above the viewport top |
39
+ | `visibleAfter` | `string` | `100vh` | Distance down the page before the trigger appears. Only used when `target` is unset |
40
+ | `offset` | `number` | — | Pixel offset to avoid overlapping another fixed element (e.g. a sticky CTA bar). Sets `--back-to-top-offset` |
41
+ | `breakpoint` | `string` | — | `l` restricts display to the large breakpoint and up. Omit to show at all viewport sizes |
42
+ | `attributes` | `Attribute` | — | Optional Drupal-style attributes object — modifier classes are merged on top |
43
+
44
+ ---
45
+
46
+ ## HTML + Web Component
47
+
48
+ ```html
49
+ <mx-back-to-top class="mx-back-to-top" target="#page-title">
50
+ <a class="mx-button mx-button--light mx-button--small mx-back-to-top__trigger" href="#main">
51
+ <span class="mx-icon mx-icon--arrow-up"></span>
52
+ <span>Back to top</span>
53
+ </a>
54
+ </mx-back-to-top>
55
+ ```
56
+
57
+ Registers as `<mx-back-to-top>`. Import the element to activate its behaviour:
58
+
59
+ ```js
60
+ import "@pnx-mixtape/mxds/src/Component/BackToTop/Elements/BackToTop"
61
+ ```
62
+
63
+ **`<mx-back-to-top>` attributes:**
64
+
65
+ | Attribute | Description |
66
+ | -------------- | ----------------------------------------------------------------------------------------------------- |
67
+ | `target` | CSS selector of an element to observe — visible once it scrolls above the viewport top |
68
+ | `visibleafter` | Distance down the page before the trigger appears (default `100vh`). Used only when `target` is unset |
69
+
70
+ If no `target` is set, visibility is driven by a plain scroll-position check instead (`window.scrollY` compared against `visibleafter`, resolved from a `px` or `vh` value) rather than an `IntersectionObserver` — this avoids depending on the host page's containing-block/positioning context, which a synthetic absolutely-positioned sentinel would be sensitive to.
71
+
72
+ **Behaviour on click:** the Web Component intercepts the click, scrolls the destination into view
73
+ (`behavior: smooth`, or `auto` when `prefers-reduced-motion: reduce`), temporarily makes the
74
+ destination focusable if it isn't already (`tabindex="-1"`, removed again on blur), moves focus
75
+ to it, and updates the URL hash via `history.pushState` — all without a full native anchor jump,
76
+ so the smooth scroll and reduced-motion behaviour are never a race against the browser's own
77
+ default jump.
78
+
79
+ **Event:**
80
+
81
+ ```js
82
+ document.querySelector("mx-back-to-top").addEventListener("back-to-top-toggle", e => {
83
+ console.log(e.detail.isVisible) // true when the trigger becomes visible, false when it hides
84
+ })
85
+ ```
86
+
87
+ ---
88
+
89
+ ## React
90
+
91
+ ```tsx
92
+ import { BackToTop } from "@pnx-mixtape/mxds/react"
93
+
94
+ <BackToTop />
95
+
96
+ // Watch a specific element instead of a scroll distance
97
+ <BackToTop target="#page-title" href="#main" />
98
+
99
+ // Desktop-only, offset to avoid overlapping a sticky CTA bar
100
+ <BackToTop breakpoint="l" offset={56} />
101
+ ```
102
+
103
+ **`BackToTop` props:**
104
+
105
+ | Prop | Type | Default | Description |
106
+ | ----------------- | ------------------------------ | ------------- | -------------------------------------------------------------------------------------- |
107
+ | `to` | `string` | `#main` | Scroll destination — a same-page hash |
108
+ | `title` | `string` | `Back to top` | Trigger label |
109
+ | `target` | `string` | — | CSS selector of an element to observe — visible once it scrolls above the viewport top |
110
+ | `visibleAfter` | `string` | `100vh` | Distance down the page before the trigger appears. Only used when `target` is unset |
111
+ | `offset` | `number` | — | Pixel offset to avoid overlapping another fixed element. Sets `--back-to-top-offset` |
112
+ | `breakpoint` | `"l"` | — | Restrict display to the large breakpoint and up. Omit to show at all viewport sizes |
113
+ | `className` | `string` | — | Extra class on the root |
114
+ | `onVisibleChange` | `(isVisible: boolean) => void` | — | Called whenever the visible state changes. React analogue of `back-to-top-toggle` |
115
+
116
+ ---
117
+
118
+ ## Modifiers
119
+
120
+ | CSS class | React `breakpoint` | Behaviour |
121
+ | ------------------- | ------------------ | ----------------------------------------------------------- |
122
+ | `mx-back-to-top` | `undefined` | Visible (once scrolled) at all viewport sizes |
123
+ | `mx-back-to-top--l` | `"l"` | Visible (once scrolled) only at the large breakpoint and up |
124
+
125
+ ---
126
+
127
+ ### React ⇄ Twig parity
128
+
129
+ `onVisibleChange` has no Twig equivalent — Twig/HTML has no concept of a function prop. The
130
+ `<mx-back-to-top>` Web Component dispatches a `back-to-top-toggle` `CustomEvent` instead; listen
131
+ for it if you need the same notification outside React.
132
+
133
+ ---
134
+
135
+ ## Accessibility
136
+
137
+ - The trigger is a real `<a href>` (via the `Button` atom, `as: 'link'`) and is always visible,
138
+ in the tab order, and keyboard-activatable **without JavaScript**. The scroll-gated show/hide
139
+ behaviour is only switched on once JS has confirmed it can drive it — the Web Component adds
140
+ an `is-enhanced` class in `connectedCallback`, and React (which always has JS) adds it
141
+ unconditionally — so a blocked or failed script load can never leave the trigger permanently
142
+ hidden or unreachable.
143
+ - On activation, focus is moved to the scroll destination. If the destination isn't natively
144
+ focusable, a temporary `tabindex="-1"` is added and removed again once it loses focus — this
145
+ fixes a common gap where a plain anchor jump scrolls the page but leaves screen reader focus
146
+ behind.
147
+ - Smooth scrolling respects `prefers-reduced-motion: reduce` (falls back to an instant jump).
148
+ - Hidden from print via `@media print`.
149
+
150
+ ---
151
+
152
+ ## Customisation via CSS custom properties
153
+
154
+ ```css
155
+ .mx-back-to-top {
156
+ --back-to-top-gap: 64px; /* distance from the bottom of the viewport */
157
+ --back-to-top-offset: 0; /* additional offset, e.g. to clear a sticky CTA bar */
158
+ --back-to-top-inline-end: var(--spacing-m); /* distance from the side of the viewport */
159
+ --back-to-top-z-index: 10;
160
+ }
161
+ ```
162
+
163
+ The React component writes `--back-to-top-offset` as an inline style from the `offset` prop. In
164
+ HTML/Twig, pass `offset` (which sets it inline) or override any of these in your own CSS.
@@ -0,0 +1,24 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Back To Top 1`] = `
4
+ "
5
+ <div style="block-size: 100px; padding-block-start: 2rem;">
6
+ <p>Scroll down to reveal the "Back to top" trigger.</p>
7
+ </div>
8
+ <div id="main" tabindex="-1">
9
+ <h2>Main content</h2>
10
+ <p>This is the scroll destination.</p>
11
+ </div>
12
+
13
+ <mx-back-to-top class="mx-back-to-top is-enhanced" visibleafter="1vh">
14
+
15
+ <a class="mx-back-to-top__trigger mx-button--small mx-button mx-button--light" href="#main">
16
+
17
+ <span class="mx-icon mx-icon--arrow-up"></span>
18
+
19
+ Back to top
20
+ </a>
21
+ </mx-back-to-top>
22
+
23
+ "
24
+ `;
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`Back To Top 1`] = `"<div style="block-size: 50vh; padding-block-start: 2rem;"><p>Scroll down to reveal the "Back to top" trigger.</p></div><div id="main" tabindex="-1"><h2>Main content</h2><p>This is the scroll destination.</p></div><div class="mx-back-to-top is-enhanced"><a href="#main" class="mx-button mx-back-to-top__trigger mx-button--small mx-button--light"><span class="mx-icon mx-icon--arrow-up"></span>Back to top</a></div>"`;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * BackToTop
3
+ */
4
+
5
+ @define-mixin back-to-top {
6
+ display: var(--back-to-top-display, none);
7
+ position: fixed;
8
+ inset-inline-end: var(--back-to-top-inline-end, var(--spacing-m));
9
+ inset-block-end: calc(
10
+ var(--back-to-top-gap, 64px) + var(--back-to-top-offset, var(--sticky-offset, 0px))
11
+ );
12
+ z-index: var(--back-to-top-z-index, 10);
13
+ }
14
+
15
+ @layer design-system.defaults {
16
+ mx-back-to-top {
17
+ display: block;
18
+ }
19
+ }
20
+
21
+ @layer design-system.components {
22
+ /* @public --back-to-top-gap --back-to-top-offset --back-to-top-inline-end --back-to-top-z-index */
23
+ .mx-back-to-top {
24
+ --back-to-top-display: block;
25
+
26
+ @add-mixin back-to-top;
27
+
28
+ @media print {
29
+ --back-to-top-display: none;
30
+ }
31
+ }
32
+
33
+ .mx-back-to-top--l {
34
+ @add-mixin back-to-top;
35
+
36
+ @media (--large-up) {
37
+ --back-to-top-display: block;
38
+ }
39
+
40
+ @media print {
41
+ --back-to-top-display: none;
42
+ }
43
+ }
44
+
45
+ /*
46
+ * Visibility is only gated behind scroll position once JS has confirmed it can drive it
47
+ * (`is-enhanced`, added by the Web Component/React on mount) — without JS the trigger stays
48
+ * visible and reachable at all times, rather than being permanently hidden by a script that
49
+ * failed to load.
50
+ */
51
+ :is(.mx-back-to-top, .mx-back-to-top--l).is-enhanced {
52
+ visibility: hidden;
53
+ opacity: 0;
54
+ transition:
55
+ visibility 0s linear 300ms,
56
+ opacity 300ms;
57
+
58
+ @media (--reduce-motion) {
59
+ transition: none;
60
+ }
61
+
62
+ &.is-visible {
63
+ visibility: visible;
64
+ opacity: 1;
65
+ transition:
66
+ visibility 0s linear 0s,
67
+ opacity 300ms;
68
+ }
69
+ }
70
+ }
@@ -0,0 +1 @@
1
+ import "./Elements/BackToTop"
@@ -0,0 +1,26 @@
1
+ {% set baseClass = 'mx-back-to-top' %}
2
+ {% set classes = [
3
+ baseClass,
4
+ breakpoint ? baseClass~"--"~breakpoint : null,
5
+ ] %}
6
+ {% set attributes = (attributes ?? create_attribute()).addClass(classes) %}
7
+ {% set resolvedHref = href|default('#main') %}
8
+ {% set resolvedTitle = title|default('Back to top') %}
9
+ {% set arrowIcon %}
10
+ {% include '@mixtape/Atom/Icon/icon.twig' with { icon: 'arrow-up' } only %}
11
+ {% endset %}
12
+
13
+ <mx-back-to-top{{ attributes }}
14
+ {%- if target %} target="{{ target }}"{% endif -%}
15
+ {%- if visibleAfter %} visibleafter="{{ visibleAfter }}"{% endif -%}
16
+ {%- if offset %} style="--back-to-top-offset: {{ offset }}px"{% endif -%}
17
+ >
18
+ {% include '@mixtape/Atom/Button/button.twig' with {
19
+ as: 'link',
20
+ href: resolvedHref,
21
+ title: resolvedTitle,
22
+ modifiers: ['light'],
23
+ iconStart: arrowIcon,
24
+ attributes: create_attribute().addClass(['mx-back-to-top__trigger', 'mx-button--small']),
25
+ } %}
26
+ </mx-back-to-top>
@@ -2,7 +2,7 @@ import { JSX, PropsWithChildren } from "react"
2
2
  import classNames from "classnames"
3
3
 
4
4
  const CardContent = ({ children }: PropsWithChildren): JSX.Element => {
5
- return <div className={classNames("mx-card__content", "mx-vertical-flow-flex")}>{children}</div>
5
+ return <div className={classNames("mx-card__content", "mx-vertical-flow")}>{children}</div>
6
6
  }
7
7
 
8
8
  export default CardContent
@@ -8,7 +8,7 @@ type CardProps = PropsWithChildren & {
8
8
  const CardMedia = ({ children, skeleton = false }: CardProps): JSX.Element => {
9
9
  return (
10
10
  <figure className={classNames("mx-card__media", "stack")}>
11
- {skeleton && <div className="mx-skeleton mx-skeleton--bg"></div>}
11
+ {skeleton && <div className="skeleton skeleton--bg"></div>}
12
12
  {children}
13
13
  </figure>
14
14
  )
@@ -1,7 +1,7 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`Block Link 1`] = `"<div class="mx-container"><article class="mx-card mx-card--block"><figure class="mx-card__media stack"><div class="mx-skeleton mx-skeleton--bg"></div><img alt="" src="https://picsum.photos/id/56/558/418?grayscale"></figure><div class="mx-card__content mx-vertical-flow-flex"><h2 class="" id="key-feature-or-secti">Key feature or Section Name</h2><p class="">A short description to help explain enough about the subject matter to encourage visitors to learn more.</p><a href="http://example.com" class="mx-link mx-link--more">Learn More</a></div></article></div>"`;
3
+ exports[`Block Link 1`] = `"<div class="mx-container"><article class="mx-card mx-card--block"><figure class="mx-card__media stack"><div class="skeleton skeleton--bg"></div><img alt="" src="https://picsum.photos/id/56/558/418?grayscale"></figure><div class="mx-card__content mx-vertical-flow"><h2 class="" id="key-feature-or-secti">Key feature or Section Name</h2><p class="">A short description to help explain enough about the subject matter to encourage visitors to learn more.</p><a href="http://example.com" class="mx-link mx-link--more">Learn More</a></div></article></div>"`;
4
4
 
5
- exports[`Card 1`] = `"<div class="mx-container"><article class="mx-card"><figure class="mx-card__media stack"><div class="mx-skeleton mx-skeleton--bg"></div><img alt="" src="https://picsum.photos/id/56/558/418?grayscale"></figure><div class="mx-card__content mx-vertical-flow-flex"><h2 class="" id="key-feature-or-secti">Key feature or Section Name</h2><p class="">A short description to help explain enough about the subject matter to encourage visitors to learn more.</p><a href="http://example.com" class="mx-link mx-link--more">Learn More</a></div></article></div>"`;
5
+ exports[`Card 1`] = `"<div class="mx-container"><article class="mx-card"><figure class="mx-card__media stack"><div class="skeleton skeleton--bg"></div><img alt="" src="https://picsum.photos/id/56/558/418?grayscale"></figure><div class="mx-card__content mx-vertical-flow"><h2 class="" id="key-feature-or-secti">Key feature or Section Name</h2><p class="">A short description to help explain enough about the subject matter to encourage visitors to learn more.</p><a href="http://example.com" class="mx-link mx-link--more">Learn More</a></div></article></div>"`;
6
6
 
7
- exports[`Reverse 1`] = `"<div class="mx-container"><article class="mx-card mx-card--reversed"><figure class="mx-card__media stack"><div class="mx-skeleton mx-skeleton--bg"></div><img alt="" src="https://picsum.photos/id/56/558/418?grayscale"></figure><div class="mx-card__content mx-vertical-flow-flex"><h2 class="" id="key-feature-or-secti">Key feature or Section Name</h2><p class="">A short description to help explain enough about the subject matter to encourage visitors to learn more.</p><a href="http://example.com" class="mx-link mx-link--more">Learn More</a></div></article></div>"`;
7
+ exports[`Reverse 1`] = `"<div class="mx-container"><article class="mx-card mx-card--reversed"><figure class="mx-card__media stack"><div class="skeleton skeleton--bg"></div><img alt="" src="https://picsum.photos/id/56/558/418?grayscale"></figure><div class="mx-card__content mx-vertical-flow"><h2 class="" id="key-feature-or-secti">Key feature or Section Name</h2><p class="">A short description to help explain enough about the subject matter to encourage visitors to learn more.</p><a href="http://example.com" class="mx-link mx-link--more">Learn More</a></div></article></div>"`;
@@ -88,7 +88,7 @@
88
88
  }
89
89
  }
90
90
 
91
- & .mx-skeleton--bg {
91
+ & .skeleton--bg {
92
92
  grid-area: media;
93
93
  }
94
94
 
@@ -292,6 +292,15 @@ export const Carousel: Story = {
292
292
 
293
293
  /**
294
294
  * Steps a virtual screen reader through the page and asserts on what it announces.
295
+ *
296
+ * How many tiles the IntersectionObserver marks visible (vs. `aria-hidden`)
297
+ * depends on the carousel's rendered width, which Chromatic varies via
298
+ * `chromatic.modes` (mobile and desktop). This branches on the real,
299
+ * observed visibility of the second tile rather than hardcoding one shape.
300
+ * Whichever mode a local run happens to render at, only one branch runs
301
+ * meaningfully for that run - the other is exercised by Chromatic's other
302
+ * mode in CI. See "Testing Mobile / matchMedia-Driven Behavior in Play
303
+ * Functions" in docs/Testing.md.
295
304
  */
296
305
  export const ScreenReaderAnnouncements: Story = {
297
306
  play: async ({ canvasElement }) => {
@@ -304,43 +313,64 @@ export const ScreenReaderAnnouncements: Story = {
304
313
  { timeout: 2000 },
305
314
  )
306
315
 
316
+ const onlyFirstTileVisible =
317
+ canvasElement.querySelector('[data-index="1"]')?.getAttribute("aria-hidden") === "true"
307
318
  const log = await runScreenReaderWalkthrough()
308
- await expect(log).toEqual([
309
- "document",
310
- "group, Quick page controls",
311
- "button, previous page, disabled",
312
- "button, next page",
313
- "end of group, Quick page controls",
314
- "article",
315
- "heading, Tile 1, level 3",
316
- "paragraph",
317
- "Tiles are just block cards without an image.",
318
- "end of paragraph",
319
- "link, Find out more",
320
- "end of article",
321
- "article",
322
- "heading, Tile 2, level 3",
323
- "paragraph",
324
- "Tiles are just block cards without an image.",
325
- "end of paragraph",
326
- "link, Find out more",
327
- "end of article",
328
- "article",
329
- "heading, Tile 3, level 3",
330
- "paragraph",
331
- "Tiles are just block cards without an image.",
332
- "end of paragraph",
333
- "link, Find out more",
334
- "end of article",
335
- "article",
336
- "heading, Tile 4, level 3",
337
- "paragraph",
338
- "Tiles are just block cards without an image.",
339
- "end of paragraph",
340
- "link, Find out more",
341
- "end of article",
342
- "end of document",
343
- ])
319
+
320
+ if (onlyFirstTileVisible) {
321
+ await expect(log).toEqual([
322
+ "document",
323
+ "group, Quick page controls",
324
+ "button, previous page, disabled",
325
+ "button, next page",
326
+ "end of group, Quick page controls",
327
+ "article",
328
+ "heading, Tile 1, level 3",
329
+ "paragraph",
330
+ "Tiles are just block cards without an image.",
331
+ "end of paragraph",
332
+ "link, Find out more",
333
+ "end of article",
334
+ "end of document",
335
+ ])
336
+ } else {
337
+ await expect(log).toEqual([
338
+ "document",
339
+ "group, Quick page controls",
340
+ "button, previous page, disabled",
341
+ "button, next page",
342
+ "end of group, Quick page controls",
343
+ "article",
344
+ "heading, Tile 1, level 3",
345
+ "paragraph",
346
+ "Tiles are just block cards without an image.",
347
+ "end of paragraph",
348
+ "link, Find out more",
349
+ "end of article",
350
+ "article",
351
+ "heading, Tile 2, level 3",
352
+ "paragraph",
353
+ "Tiles are just block cards without an image.",
354
+ "end of paragraph",
355
+ "link, Find out more",
356
+ "end of article",
357
+ "article",
358
+ "heading, Tile 3, level 3",
359
+ "paragraph",
360
+ "Tiles are just block cards without an image.",
361
+ "end of paragraph",
362
+ "link, Find out more",
363
+ "end of article",
364
+ "article",
365
+ "heading, Tile 4, level 3",
366
+ "paragraph",
367
+ "Tiles are just block cards without an image.",
368
+ "end of paragraph",
369
+ "link, Find out more",
370
+ "end of article",
371
+ "end of document",
372
+ ])
373
+ }
344
374
  },
345
375
  }
346
376
 
@@ -1,11 +1,11 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`Default 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_0_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul></div>"`;
3
+ exports[`Default 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_0_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul></div>"`;
4
4
 
5
- exports[`Screen Reader Announcements 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_s_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" inert="" aria-hidden="true"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" inert="" aria-hidden="true"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul></div>"`;
5
+ exports[`Screen Reader Announcements 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_s_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" inert="" aria-hidden="true"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" inert="" aria-hidden="true"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul></div>"`;
6
6
 
7
- exports[`With Counter 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_e_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul><div class="mx-carousel__pagination" data-pagination="counter" role="group" aria-label="Page controls"><button type="button" data-index="0" aria-label="Page 1" disabled="" aria-current="page">1</button><button type="button" data-index="1" aria-label="Page 2">2</button></div></div>"`;
7
+ exports[`With Counter 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_e_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul><div class="mx-carousel__pagination" data-pagination="counter" role="group" aria-label="Page controls"><button type="button" data-index="0" aria-label="Page 1" disabled="" aria-current="page">1</button><button type="button" data-index="1" aria-label="Page 2">2</button></div></div>"`;
8
8
 
9
- exports[`With Loop 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_l_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul></div>"`;
9
+ exports[`With Loop 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_l_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul></div>"`;
10
10
 
11
- exports[`With Pagination 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_7_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow-flex"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul><div class="mx-carousel__pagination" data-pagination="pagination" role="group" aria-label="Page controls"><button type="button" data-index="0" aria-label="Page 1" disabled="" aria-current="page">1</button><button type="button" data-index="1" aria-label="Page 2">2</button></div></div>"`;
11
+ exports[`With Pagination 1`] = `"<div class="mx-carousel" role="region" aria-roledescription="carousel" id="_r_7_"><div class="mx-carousel__buttons" role="group" aria-label="Quick page controls"><button class="mx-button mx-button--icon-only mx-carousel__prev" type="button" disabled=""><span class="sr-only">previous page</span><span class="mx-icon mx-icon--chevron-left" aria-hidden="true"></span></button><button class="mx-button mx-button--icon-only mx-carousel__next" type="button"><span class="sr-only">next page</span><span class="mx-icon mx-icon--chevron-right" aria-hidden="true"></span></button></div><ul class="mx-carousel__scrollable" aria-live="off" tabindex="0"><li data-index="0" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-1">Tile 1</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="1" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-2">Tile 2</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="2" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-3">Tile 3</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="3" aria-hidden="false"><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-4">Tile 4</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="4" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-5">Tile 5</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li><li data-index="5" aria-hidden="true" inert=""><div class="mx-container"><article class="mx-card mx-card--block mx-background--box"><div class="mx-card__content mx-vertical-flow"><h3 class="" id="tile-6">Tile 6</h3><p class="mx-text--lede">Tiles are just block cards without an image.</p><a href="#" class="mx-link mx-link--more">Find out more</a></div></article></div></li></ul><div class="mx-carousel__pagination" data-pagination="pagination" role="group" aria-label="Page controls"><button type="button" data-index="0" aria-label="Page 1" disabled="" aria-current="page">1</button><button type="button" data-index="1" aria-label="Page 2">2</button></div></div>"`;
@@ -8,7 +8,7 @@ type CardProps = PropsWithChildren & {
8
8
  const ContentBlockMedia = ({ children, skeleton = false }: CardProps): JSX.Element => {
9
9
  return (
10
10
  <figure className={classNames("mx-content-block__media", "stack")}>
11
- {skeleton && <div className="mx-skeleton mx-skeleton--bg"></div>}
11
+ {skeleton && <div className="skeleton skeleton--bg"></div>}
12
12
  {children}
13
13
  </figure>
14
14
  )
@@ -25,7 +25,7 @@
25
25
  display: block;
26
26
  }
27
27
 
28
- & .mx-skeleton--bg {
28
+ & .skeleton--bg {
29
29
  aspect-ratio: var(--ratio);
30
30
  }
31
31
  }