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

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 (199) hide show
  1. package/.claude/skills/create-mxds-component/SKILL.md +77 -0
  2. package/DESIGN.md +595 -0
  3. package/README.md +1 -2
  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/button.css +1 -1
  9. package/dist/build/card.css +1 -1
  10. package/dist/build/chunks/Accordion-D2wp8hBG.js +44 -0
  11. package/dist/build/chunks/AccordionGroup-BYtoAFxg.js +47 -0
  12. package/dist/build/chunks/AccordionMobile-D3sTeiM5.js +26 -0
  13. package/dist/build/chunks/Autocomplete-kRo8RNbC.js +135 -0
  14. package/dist/build/chunks/BackToTop-4M-Wl7z3.js +64 -0
  15. package/dist/build/chunks/ClosableAlert-yy84gae6.js +55 -0
  16. package/dist/build/chunks/CookieConsent-wd8gQ2Oe.js +18 -0
  17. package/dist/build/chunks/Dialog-DWoXW-7Z.js +48 -0
  18. package/dist/build/chunks/DropMenu-CSTZq0Zt.js +68 -0
  19. package/dist/build/chunks/FeedbackForm-BochXEDx.js +64 -0
  20. package/dist/build/chunks/Gallery-Rkfv7Mbb.js +165 -0
  21. package/dist/build/chunks/GlobalToggle-CzlkpLpc.js +82 -0
  22. package/dist/build/chunks/InPageNavigation-D1Kk-rCm.js +86 -0
  23. package/dist/build/chunks/Navigation-CDQnN61h.js +147 -0
  24. package/dist/build/chunks/Popover-CiTAftNU.js +30 -0
  25. package/dist/build/chunks/Sticky-DoVndENm.js +51 -0
  26. package/dist/build/chunks/Tabs-BDlxCDNh.js +160 -0
  27. package/dist/build/chunks/Translate-bmM38j6z.js +46 -0
  28. package/dist/build/chunks/cookie-compliance-CG6x-TcV.js +119 -0
  29. package/dist/build/chunks/enums-BrHxPZZ_.js +36 -0
  30. package/dist/build/chunks/polyfills-D-qh1a_2.js +33 -0
  31. package/dist/build/chunks/utilities-Dd-08SW6.js +255 -0
  32. package/dist/build/content-block.css +1 -1
  33. package/dist/build/cookie-consent.entry.js +1 -1
  34. package/dist/build/dialog.entry.js +1 -1
  35. package/dist/build/drop-menu.entry.js +1 -1
  36. package/dist/build/elements.js +147 -1
  37. package/dist/build/feedback-form.css +1 -0
  38. package/dist/build/feedback-form.entry.js +1 -0
  39. package/dist/build/filters.entry.js +145 -1
  40. package/dist/build/gallery.entry.js +1 -1
  41. package/dist/build/global-alert.entry.js +1 -1
  42. package/dist/build/header.css +1 -1
  43. package/dist/build/header.entry.js +1 -1
  44. package/dist/build/icon.css +1 -1
  45. package/dist/build/in-page-navigation.entry.js +1 -1
  46. package/dist/build/navigation.entry.js +1 -1
  47. package/dist/build/pagination.css +1 -1
  48. package/dist/build/popover.entry.js +1 -1
  49. package/dist/build/react.js +2270 -1
  50. package/dist/build/sticky.entry.js +1 -1
  51. package/dist/build/tabs.entry.js +1 -1
  52. package/dist/build/translate.css +1 -0
  53. package/dist/build/translate.entry.js +1 -0
  54. package/dist/build/utility-list.entry.js +53 -1
  55. package/dist/types/Component/BackToTop/BackToTop.d.ts +20 -0
  56. package/dist/types/Component/BackToTop/BackToTop.d.ts.map +1 -0
  57. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts +27 -0
  58. package/dist/types/Component/BackToTop/Elements/BackToTop.d.ts.map +1 -0
  59. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts +2 -0
  60. package/dist/types/Component/BackToTop/back-to-top.entry.d.ts.map +1 -0
  61. package/dist/types/Component/DropMenu/DropMenu.d.ts +2 -1
  62. package/dist/types/Component/DropMenu/DropMenu.d.ts.map +1 -1
  63. package/dist/types/Component/Tabs/Components/TabDropMenu.d.ts.map +1 -1
  64. package/dist/types/Component/Tabs/Elements/Tabs.d.ts.map +1 -1
  65. package/dist/types/Component/Translate/Elements/Translate.d.ts +23 -0
  66. package/dist/types/Component/Translate/Elements/Translate.d.ts.map +1 -0
  67. package/dist/types/Component/Translate/Translate.d.ts +37 -0
  68. package/dist/types/Component/Translate/Translate.d.ts.map +1 -0
  69. package/dist/types/Component/Translate/languages.d.ts +11 -0
  70. package/dist/types/Component/Translate/languages.d.ts.map +1 -0
  71. package/dist/types/Component/Translate/translate.entry.d.ts +2 -0
  72. package/dist/types/Component/Translate/translate.entry.d.ts.map +1 -0
  73. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts +37 -0
  74. package/dist/types/Form/FeedbackForm/Elements/FeedbackForm.d.ts.map +1 -0
  75. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts +36 -0
  76. package/dist/types/Form/FeedbackForm/FeedbackForm.d.ts.map +1 -0
  77. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts +2 -0
  78. package/dist/types/Form/FeedbackForm/feedback-form.entry.d.ts.map +1 -0
  79. package/dist/types/Utility/Elements/google-translate-widget.d.ts +91 -0
  80. package/dist/types/Utility/Elements/google-translate-widget.d.ts.map +1 -0
  81. package/dist/types/Utility/utilities.d.ts +2 -0
  82. package/dist/types/Utility/utilities.d.ts.map +1 -1
  83. package/dist/types/elements.d.ts +3 -0
  84. package/dist/types/elements.d.ts.map +1 -1
  85. package/dist/types/enums.d.ts +3 -1
  86. package/dist/types/enums.d.ts.map +1 -1
  87. package/dist/types/react.d.ts +3 -0
  88. package/dist/types/react.d.ts.map +1 -1
  89. package/docs/API.md +1215 -0
  90. package/docs/CSSGuidelines.md +891 -0
  91. package/docs/CodeQuality.md +940 -0
  92. package/docs/ComponentArchitecture.md +714 -0
  93. package/docs/Contributing.md +626 -0
  94. package/docs/MemoryManagement.md +598 -0
  95. package/docs/Migrations.md +6 -0
  96. package/docs/README.md +100 -0
  97. package/docs/Security.md +444 -0
  98. package/docs/Testing.md +739 -0
  99. package/docs/Troubleshooting.md +674 -0
  100. package/package.json +6 -3
  101. package/src/Atom/Button/Button.tsx +1 -1
  102. package/src/Atom/Button/__snapshots__/Button.stories.tsx.snap +2 -2
  103. package/src/Atom/Button/_buttons.css +1 -0
  104. package/src/Atom/Icon/README.md +1 -1
  105. package/src/Atom/Icon/_icon.css +1 -0
  106. package/src/Atom/Icon/images/thumb.svg +1 -0
  107. package/src/Atom/Media/__snapshots__/Media.stories.ts.snap +4 -9
  108. package/src/Atom/Media/media.twig +4 -5
  109. package/src/Component/BackToTop/BackToTop.stories.ts +127 -0
  110. package/src/Component/BackToTop/BackToTop.stories.tsx +53 -0
  111. package/src/Component/BackToTop/BackToTop.tsx +120 -0
  112. package/src/Component/BackToTop/Elements/BackToTop.ts +119 -0
  113. package/src/Component/BackToTop/README.md +164 -0
  114. package/src/Component/BackToTop/__snapshots__/BackToTop.stories.ts.snap +24 -0
  115. package/src/Component/BackToTop/__snapshots__/BackToTop.stories.tsx.snap +3 -0
  116. package/src/Component/BackToTop/back-to-top.css +70 -0
  117. package/src/Component/BackToTop/back-to-top.entry.js +1 -0
  118. package/src/Component/BackToTop/back-to-top.twig +26 -0
  119. package/src/Component/Card/Components/CardContent.tsx +1 -1
  120. package/src/Component/Card/Components/CardMedia.tsx +1 -1
  121. package/src/Component/Card/__snapshots__/Card.stories.tsx.snap +3 -3
  122. package/src/Component/Card/card.css +1 -1
  123. package/src/Component/Carousel/Carousel.stories.ts +66 -36
  124. package/src/Component/Carousel/__snapshots__/Carousel.stories.tsx.snap +5 -5
  125. package/src/Component/ContentBlock/Components/ContentBlockMedia.tsx +1 -1
  126. package/src/Component/ContentBlock/content-block.css +1 -1
  127. package/src/Component/DropMenu/DropMenu.stories.ts +21 -2
  128. package/src/Component/DropMenu/DropMenu.tsx +14 -4
  129. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.ts.snap +3 -3
  130. package/src/Component/DropMenu/__snapshots__/DropMenu.stories.tsx.snap +2 -2
  131. package/src/Component/DropMenu/drop-menu.twig +7 -1
  132. package/src/Component/HeroBanner/__snapshots__/HeroBanner.stories.tsx.snap +1 -1
  133. package/src/Component/InPageNavigation/__snapshots__/InPageNavigation.stories.ts.snap +48 -13
  134. package/src/Component/InPageNavigation/in-page-navigation.twig +4 -6
  135. package/src/Component/ListItem/Components/ListItemMedia.tsx +1 -1
  136. package/src/Component/Pagination/Pagination.stories.ts +57 -27
  137. package/src/Component/Pagination/pagination.css +16 -7
  138. package/src/Component/Popover/__snapshots__/Popover.stories.tsx.snap +3 -3
  139. package/src/Component/Tabs/Components/TabDropMenu.tsx +7 -1
  140. package/src/Component/Tabs/Elements/Tabs.ts +13 -3
  141. package/src/Component/Tabs/Tabs.stories.ts +33 -12
  142. package/src/Component/Tabs/Tabs.stories.tsx +28 -14
  143. package/src/Component/Tabs/__snapshots__/Tabs.stories.ts.snap +3 -3
  144. package/src/Component/Tabs/__snapshots__/Tabs.stories.tsx.snap +2 -2
  145. package/src/Component/Translate/Elements/Translate.ts +76 -0
  146. package/src/Component/Translate/README.md +283 -0
  147. package/src/Component/Translate/Translate.stories.ts +87 -0
  148. package/src/Component/Translate/Translate.stories.tsx +77 -0
  149. package/src/Component/Translate/Translate.tsx +213 -0
  150. package/src/Component/Translate/__snapshots__/Translate.stories.ts.snap +18 -0
  151. package/src/Component/Translate/__snapshots__/Translate.stories.tsx.snap +3 -0
  152. package/src/Component/Translate/languages.ts +39 -0
  153. package/src/Component/Translate/translate.css +62 -0
  154. package/src/Component/Translate/translate.entry.js +1 -0
  155. package/src/Component/Translate/translate.twig +44 -0
  156. package/src/Form/Autocomplete/Autocomplete.stories.tsx +2 -1
  157. package/src/Form/FeedbackForm/Elements/FeedbackForm.ts +122 -0
  158. package/src/Form/FeedbackForm/FeedbackForm.stories.ts +99 -0
  159. package/src/Form/FeedbackForm/FeedbackForm.stories.tsx +73 -0
  160. package/src/Form/FeedbackForm/FeedbackForm.tsx +196 -0
  161. package/src/Form/FeedbackForm/README.md +233 -0
  162. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.ts.snap +125 -0
  163. package/src/Form/FeedbackForm/__snapshots__/FeedbackForm.stories.tsx.snap +5 -0
  164. package/src/Form/FeedbackForm/feedback-form.css +74 -0
  165. package/src/Form/FeedbackForm/feedback-form.entry.js +1 -0
  166. package/src/Form/FeedbackForm/feedback-form.twig +80 -0
  167. package/src/Layout/Header/Components/GlobalToggle.tsx +1 -1
  168. package/src/Layout/Header/Header.stories.ts +53 -48
  169. package/src/Layout/Header/Header.stories.tsx +35 -22
  170. package/src/Layout/Header/Header.tsx +2 -2
  171. package/src/Layout/Header/__snapshots__/Header.stories.ts.snap +14 -10
  172. package/src/Layout/Header/__snapshots__/Header.stories.tsx.snap +2 -2
  173. package/src/Layout/Header/_toggles.css +7 -7
  174. package/src/Layout/Page/__snapshots__/Page.stories.tsx.snap +1 -1
  175. package/src/Utility/Elements/google-translate-widget.ts +293 -0
  176. package/src/Utility/global.d.ts +4 -0
  177. package/src/Utility/utilities.ts +2 -0
  178. package/src/elements.ts +3 -0
  179. package/src/enums.ts +2 -0
  180. package/src/react.ts +3 -0
  181. package/dist/build/chunks/Accordion-GN0sME4W.js +0 -1
  182. package/dist/build/chunks/AccordionGroup-Bzqp5__q.js +0 -1
  183. package/dist/build/chunks/AccordionMobile-DG5jSe8Q.js +0 -1
  184. package/dist/build/chunks/Autocomplete-B4RtkAyh.js +0 -1
  185. package/dist/build/chunks/ClosableAlert-DEhj8Nxm.js +0 -1
  186. package/dist/build/chunks/CookieConsent-BkCMRVST.js +0 -1
  187. package/dist/build/chunks/Dialog-Haahn-Yn.js +0 -1
  188. package/dist/build/chunks/DropMenu-1baQc8Yc.js +0 -1
  189. package/dist/build/chunks/Gallery-D8NGXy2Q.js +0 -1
  190. package/dist/build/chunks/GlobalToggle-B52fdBQu.js +0 -1
  191. package/dist/build/chunks/InPageNavigation-Dyn2TR-N.js +0 -1
  192. package/dist/build/chunks/Navigation-hOrfLq7h.js +0 -1
  193. package/dist/build/chunks/Popover-Cxg-s5Jn.js +0 -1
  194. package/dist/build/chunks/Sticky-BGCuuEJK.js +0 -1
  195. package/dist/build/chunks/Tabs-DYy1YTdU.js +0 -15
  196. package/dist/build/chunks/cookie-compliance-Bbm-0vpj.js +0 -1
  197. package/dist/build/chunks/enums-DLV_1NAf.js +0 -1
  198. package/dist/build/chunks/polyfills-C7pRt54M.js +0 -1
  199. package/dist/build/chunks/utilities-_Bq3TxAQ.js +0 -1
@@ -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
  }
@@ -21,6 +21,8 @@ type DropMenuType = {
21
21
  id?: string
22
22
  role?: "menu" | "tablist"
23
23
  placement?: PopoverPlacementModifier
24
+ description?: string
25
+ ariaLabel?: string
24
26
  }
25
27
 
26
28
  /**
@@ -38,6 +40,7 @@ const meta: Meta<DropMenuType> = {
38
40
  { label: "Stories", href: "#stories" },
39
41
  ],
40
42
  placement: PopoverPlacementModifier.BOTTOM_START,
43
+ description: "Results will update when you make a selection. Press escape to close.",
41
44
  },
42
45
  argTypes: {
43
46
  placement: {
@@ -75,6 +78,22 @@ const meta: Meta<DropMenuType> = {
75
78
  options: ["menu", "tablist"],
76
79
  type: "string",
77
80
  },
81
+ description: {
82
+ description:
83
+ "Screen-reader-only text describing the popover, announced via `aria-describedby` when it opens.",
84
+ control: "text",
85
+ table: {
86
+ type: { summary: "string" },
87
+ },
88
+ },
89
+ ariaLabel: {
90
+ description:
91
+ "Overrides the popover's accessible name. Defaults to the trigger button's `label` via `aria-labelledby`.",
92
+ control: "text",
93
+ table: {
94
+ type: { summary: "string" },
95
+ },
96
+ },
78
97
  },
79
98
  }
80
99
 
@@ -168,11 +187,11 @@ export const ScreenReaderAnnouncements: Story = {
168
187
  await expect(log).toEqual([
169
188
  "document",
170
189
  "button, Categories",
171
- "menu, Categories, orientated vertically",
190
+ "menu, Categories, Results will update when you make a selection. Press escape to close., orientated vertically",
172
191
  "menuitemradio, News, not checked, position 1, set size 3",
173
192
  "menuitemradio, Events, not checked, position 2, set size 3",
174
193
  "menuitemradio, Stories, not checked, position 3, set size 3",
175
- "end of menu, Categories, orientated vertically",
194
+ "end of menu, Categories, Results will update when you make a selection. Press escape to close., orientated vertically",
176
195
  "end of document",
177
196
  ])
178
197
 
@@ -19,6 +19,7 @@ type DropMenuProps = PropsWithChildren & {
19
19
  popoverClassName?: string
20
20
  role?: "menu" | "tablist"
21
21
  ariaLabel?: string
22
+ triggerDescription?: string
22
23
  description?: string
23
24
  }
24
25
 
@@ -37,6 +38,7 @@ const DropMenu = ({
37
38
  popoverClassName,
38
39
  role = "menu",
39
40
  ariaLabel,
41
+ triggerDescription,
40
42
  description = "Results will update when you make a selection. Press escape to close.",
41
43
  }: DropMenuProps): JSX.Element => {
42
44
  const { dropMenuId, triggerId, descriptionId, popoverRef } = useDropMenuContext()
@@ -55,9 +57,20 @@ const DropMenu = ({
55
57
  className={classNames([...triggerClassNames, "mx-popover__trigger"])}
56
58
  popoverTarget={dropMenuId}
57
59
  style={triggerStyle}
60
+ aria-describedby={triggerDescription ? `${triggerId}-desc` : null}
58
61
  >
59
62
  {label}
60
63
  </button>
64
+ {triggerDescription && (
65
+ <span id={`${triggerId}-desc`} className="sr-only" aria-hidden="true">
66
+ {triggerDescription}
67
+ </span>
68
+ )}
69
+ {description && (
70
+ <span id={descriptionId} className="sr-only" aria-hidden="true">
71
+ {description}
72
+ </span>
73
+ )}
61
74
  <div
62
75
  id={dropMenuId}
63
76
  className={classNames("mx-popover mx-drop-menu", popoverClassName)}
@@ -66,12 +79,9 @@ const DropMenu = ({
66
79
  ref={popoverRef}
67
80
  aria-labelledby={ariaLabel ? null : triggerId}
68
81
  aria-label={ariaLabel}
69
- aria-describedby={descriptionId}
82
+ aria-describedby={descriptionId ? descriptionId : null}
70
83
  role={role}
71
84
  >
72
- <div id={descriptionId} className="sr-only" aria-hidden="true">
73
- {description}
74
- </div>
75
85
  <FocusScope>{children}</FocusScope>
76
86
  </div>
77
87
  </Container>
@@ -5,7 +5,7 @@ exports[`Buttons 1`] = `
5
5
  <button id="unique-0" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
6
6
  Categories
7
7
  </button>
8
- <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="" role="menu">
8
+ <span id="unique-1" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</span><div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-labelledby="unique-0" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="" role="menu">
9
9
  <button type="button" data-id="news" role="menuitemradio" aria-checked="false">News</button>
10
10
  <button type="button" data-id="events" role="menuitemradio" aria-checked="true">Events</button>
11
11
  <button type="button" data-id="stories" role="menuitemradio" aria-checked="false">Stories</button>
@@ -19,7 +19,7 @@ exports[`Drop Menu 1`] = `
19
19
  <button id="unique-0" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
20
20
  Categories
21
21
  </button>
22
- <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="">
22
+ <span id="unique-1" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</span><div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-labelledby="unique-0" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="">
23
23
  <a href="#news">News</a>
24
24
  <a href="#events">Events</a>
25
25
  <a href="#stories">Stories</a>
@@ -33,7 +33,7 @@ exports[`Screen Reader Announcements 1`] = `
33
33
  <button id="unique-0" class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end" popovertarget="dropdown-menu" style="anchor-name: --dropdown-menu">
34
34
  Categories
35
35
  </button>
36
- <div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="" role="menu">
36
+ <span id="unique-1" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</span><div class="mx-popover mx-drop-menu" id="dropdown-menu" aria-labelledby="unique-0" aria-describedby="unique-0" style="position-anchor: --dropdown-menu" data-placement="bottom-start" popover="" role="menu">
37
37
  <button type="button" data-id="news" role="menuitemradio" aria-checked="false">News</button>
38
38
  <button type="button" data-id="events" role="menuitemradio" aria-checked="false">Events</button>
39
39
  <button type="button" data-id="stories" role="menuitemradio" aria-checked="false">Stories</button>
@@ -1,5 +1,5 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`Drop Menu 1`] = `"<button id="drop-menu-storybook-target" type="button" class="mx-button mx-icon mx-icon--chevron-down mx-icon--end mx-popover__trigger" popovertarget="drop-menu-storybook" style="anchor-name: --drop-menu-drop-menu-storybook;">Categories</button><div id="drop-menu-storybook" class="mx-popover mx-drop-menu" popover="" aria-labelledby="drop-menu-storybook-target" aria-describedby="drop-menu-storybook-description" role="menu" style="position-anchor: --drop-menu-drop-menu-storybook;"><div id="drop-menu-storybook-description" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</div><span data-focus-scope-start="true" hidden=""></span><button type="button" data-id="news" aria-checked="false" role="menuitemradio">News</button><button type="button" data-id="events" aria-checked="false" role="menuitemradio">Events</button><button type="button" data-id="stories" aria-checked="false" role="menuitemradio">Stories</button><span data-focus-scope-end="true" hidden=""></span></div>"`;
3
+ exports[`Drop Menu 1`] = `"<button id="drop-menu-storybook-target" type="button" class="mx-button mx-icon mx-icon--chevron-down mx-icon--end mx-popover__trigger" popovertarget="drop-menu-storybook" style="anchor-name: --drop-menu-drop-menu-storybook;">Categories</button><span id="drop-menu-storybook-description" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</span><div id="drop-menu-storybook" class="mx-popover mx-drop-menu" popover="" aria-labelledby="drop-menu-storybook-target" aria-describedby="drop-menu-storybook-description" role="menu" style="position-anchor: --drop-menu-drop-menu-storybook;"><span data-focus-scope-start="true" hidden=""></span><button type="button" data-id="news" aria-checked="false" role="menuitemradio">News</button><button type="button" data-id="events" aria-checked="false" role="menuitemradio">Events</button><button type="button" data-id="stories" aria-checked="false" role="menuitemradio">Stories</button><span data-focus-scope-end="true" hidden=""></span></div>"`;
4
4
 
5
- exports[`Screen Reader Announcements 1`] = `"<button id="drop-menu-storybook-target" type="button" class="mx-button mx-icon mx-icon--chevron-down mx-icon--end mx-popover__trigger" popovertarget="drop-menu-storybook" style="anchor-name: --drop-menu-drop-menu-storybook;">Categories</button><div id="drop-menu-storybook" class="mx-popover mx-drop-menu" popover="" aria-labelledby="drop-menu-storybook-target" aria-describedby="drop-menu-storybook-description" role="menu" style="position-anchor: --drop-menu-drop-menu-storybook;"><div id="drop-menu-storybook-description" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</div><span data-focus-scope-start="true" hidden=""></span><button type="button" data-id="news" aria-checked="false" role="menuitemradio">News</button><button type="button" data-id="events" aria-checked="false" role="menuitemradio">Events</button><button type="button" data-id="stories" aria-checked="false" role="menuitemradio">Stories</button><span data-focus-scope-end="true" hidden=""></span></div>"`;
5
+ exports[`Screen Reader Announcements 1`] = `"<button id="drop-menu-storybook-target" type="button" class="mx-button mx-icon mx-icon--chevron-down mx-icon--end mx-popover__trigger" popovertarget="drop-menu-storybook" style="anchor-name: --drop-menu-drop-menu-storybook;">Categories</button><span id="drop-menu-storybook-description" class="sr-only" aria-hidden="true">Results will update when you make a selection. Press escape to close.</span><div id="drop-menu-storybook" class="mx-popover mx-drop-menu" popover="" aria-labelledby="drop-menu-storybook-target" aria-describedby="drop-menu-storybook-description" role="menu" style="position-anchor: --drop-menu-drop-menu-storybook;"><span data-focus-scope-start="true" hidden=""></span><button type="button" data-id="news" aria-checked="false" role="menuitemradio">News</button><button type="button" data-id="events" aria-checked="false" role="menuitemradio">Events</button><button type="button" data-id="stories" aria-checked="false" role="menuitemradio">Stories</button><span data-focus-scope-end="true" hidden=""></span></div>"`;
@@ -1,18 +1,24 @@
1
1
  <mx-dropmenu closeonclick>
2
2
  {% set id = id|default('dropdown-menu') %}
3
3
  {% set name = id ~ '-target' %}
4
+ {% set triggerDescriptionId = name ~ '-descr' %}
5
+ {% set descriptionId = name ~ '-description' %}
4
6
  <button
5
7
  id="{{ name }}"
6
8
  class="mx-popover__trigger mx-button mx-icon mx-icon--chevron-down mx-icon--end"
7
9
  popovertarget="{{ id }}"
8
10
  style="anchor-name: --{{ id }}"
11
+ {% if triggerDescription %}aria-describedby="{{ triggerDescriptionId }}"{% endif %}
9
12
  >
10
13
  {{ label }}
11
14
  </button>
15
+ {% if triggerDescription %}<span id="{{ triggerDescriptionId }}" class="sr-only" aria-hidden="true">{{ triggerDescription }}</span>{% endif %}
16
+ {% if description %}<span id="{{ descriptionId }}" class="sr-only" aria-hidden="true">{{ description }}</span>{% endif %}
12
17
  <div
13
18
  class="mx-popover mx-drop-menu"
14
19
  id="{{ id }}"
15
- aria-describedby="{{ name }}"
20
+ {% if ariaLabel %}aria-label="{{ ariaLabel }}"{% else %}aria-labelledby="{{ name }}"{% endif %}
21
+ {% if description %}aria-describedby="{{ descriptionId }}"{% endif %}
16
22
  style="position-anchor: --{{ id }}"
17
23
  data-placement="{{ placement|default('bottom-start') }}"
18
24
  popover