@undrr/undrr-mangrove 2.0.0-rc.2 → 2.0.0

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 (124) hide show
  1. package/README.md +11 -6
  2. package/components/BookCard.js +1 -1
  3. package/components/Breadcrumbs.js +2 -2
  4. package/components/Checkbox.js +1 -1
  5. package/components/Chips.js +1 -1
  6. package/components/CopyButton.js +2 -2
  7. package/components/CtaButton.js +1 -1
  8. package/components/Drawer.js +1 -1
  9. package/components/EmbedContainer.js +1 -1
  10. package/components/Footer.js +1 -1
  11. package/components/FormAction.js +1 -1
  12. package/components/FormErrorSummary.js +1 -1
  13. package/components/FormGroup.js +1 -1
  14. package/components/FullWidth.js +1 -1
  15. package/components/Gallery.js +2 -2
  16. package/components/Hero.js +2 -2
  17. package/components/HighlightBox.js +1 -1
  18. package/components/HorizontalBookCard.js +1 -1
  19. package/components/HorizontalCard.js +1 -1
  20. package/components/IconCard.js +1 -1
  21. package/components/Legend.js +1 -1
  22. package/components/Loader.js +1 -1
  23. package/components/MegaMenu.js +2 -2
  24. package/components/Notice.js +2 -2
  25. package/components/PageHeader.js +2 -2
  26. package/components/Pager.js +2 -2
  27. package/components/QuoteHighlight.js +2 -2
  28. package/components/QuoteHighlight.js.LICENSE.txt +2 -0
  29. package/components/Radio.js +1 -1
  30. package/components/Range.js +1 -1
  31. package/components/ScrollContainer.js +2 -2
  32. package/components/SegmentedControl.js +9 -0
  33. package/components/SegmentedControl.js.LICENSE.txt +9 -0
  34. package/components/Select.js +1 -1
  35. package/components/ServiceNotice.js +2 -2
  36. package/components/ShareButtons.js +2 -2
  37. package/components/ShowMore.js +2 -2
  38. package/components/SkipLink.js +1 -1
  39. package/components/StatsCard.js +1 -1
  40. package/components/SyndicationSearchWidget.js +2 -2
  41. package/components/Tab.js +2 -2
  42. package/components/TextCta.js +1 -1
  43. package/components/TextInput.js +1 -1
  44. package/components/Textarea.js +1 -1
  45. package/components/Tree.js +1 -1
  46. package/components/UserFeedback.js +1 -1
  47. package/components/VerticalCard.js +1 -1
  48. package/components/hydrate.js +2 -2
  49. package/css/style-all.css +60 -40
  50. package/css/style-all.css.map +1 -1
  51. package/css/style-delta.css +59 -39
  52. package/css/style-delta.css.map +1 -1
  53. package/css/style-gutenberg.css +16 -7
  54. package/css/style-gutenberg.css.map +1 -1
  55. package/css/style-irp.css +60 -40
  56. package/css/style-irp.css.map +1 -1
  57. package/css/style-mcr.css +59 -39
  58. package/css/style-mcr.css.map +1 -1
  59. package/css/style-preventionweb.css +60 -40
  60. package/css/style-preventionweb.css.map +1 -1
  61. package/css/style.css +59 -39
  62. package/css/style.css.map +1 -1
  63. package/error-pages/401.html +3 -3
  64. package/error-pages/403.html +3 -3
  65. package/error-pages/404.html +4 -4
  66. package/error-pages/429.html +3 -3
  67. package/error-pages/500.html +6 -6
  68. package/error-pages/502.html +3 -3
  69. package/error-pages/503.html +3 -3
  70. package/error-pages/504.html +3 -3
  71. package/error-pages/5xx.html +4 -4
  72. package/error-pages/challenge.html +3 -3
  73. package/error-pages/managed-challenge.html +3 -3
  74. package/js/README.md +31 -25
  75. package/js/copy-button.js +17 -0
  76. package/js/drawer.js +752 -0
  77. package/js/hub-header.js +217 -0
  78. package/js/show-more.js +144 -10
  79. package/js/switch-pending.js +195 -46
  80. package/package.json +8 -3
  81. package/scss/Atom/BaseTypography/Blockquote/blockquote.scss +2 -1
  82. package/scss/Atom/BaseTypography/Cite/cite.scss +2 -1
  83. package/scss/Atom/BaseTypography/Code/code.scss +8 -2
  84. package/scss/Atom/Icons/icons.scss +1 -1
  85. package/scss/Atom/Images/AuthorImage/author-image.scss +16 -1
  86. package/scss/Atom/StatusLabel/status-label.scss +331 -8
  87. package/scss/Atom/Table/table.scss +8 -3
  88. package/scss/Atom/Tag/tag.scss +20 -2
  89. package/scss/Components/Breadcrumbs/breadcrumbs.scss +8 -4
  90. package/scss/Components/Buttons/CtaButton/cta-button.scss +15 -0
  91. package/scss/Components/Cards/Card/card.scss +37 -10
  92. package/scss/Components/Cards/StatsCard/stats-card.scss +2 -10
  93. package/scss/Components/DataViz/Legend/legend.scss +2 -1
  94. package/scss/Components/ErrorPages/error-pages.scss +8 -0
  95. package/scss/Components/Forms/SegmentedControl/segmented-control.scss +412 -0
  96. package/scss/Components/Forms/_form-base.scss +109 -18
  97. package/scss/Components/Hero/hero.scss +296 -57
  98. package/scss/Components/MegaMenu/mega-menu.scss +26 -6
  99. package/scss/Components/OnThisPageNav/on-this-page-nav.scss +3 -1
  100. package/scss/Components/PageHeader/page-header.scss +13 -28
  101. package/scss/Components/Pager/pager.scss +3 -1
  102. package/scss/Components/QuoteHighlight/quote-highlight.scss +6 -1
  103. package/scss/Components/ScrollContainer/scroll-container.scss +11 -0
  104. package/scss/Components/SyndicationSearchWidget/syndication-search-widget.scss +51 -24
  105. package/scss/Components/Tab/tab.scss +1 -1
  106. package/scss/Components/TextCta/text-cta.scss +11 -3
  107. package/scss/Patterns/HubHeader/hub-header.scss +14 -3
  108. package/scss/Utilities/FullWidth/full-width.scss +14 -1
  109. package/scss/assets/scss/_components.scss +1 -0
  110. package/scss/assets/scss/_fonts.scss +11 -0
  111. package/scss/assets/scss/_foundational.scss +7 -0
  112. package/scss/assets/scss/_mixins.scss +32 -0
  113. package/scss/assets/scss/_tokens-data-viz.scss +9 -0
  114. package/scss/assets/scss/_variables.scss +16 -3
  115. package/scss/assets/scss/generated/_tokens-irp.scss +20 -4
  116. package/scss/assets/scss/generated/_tokens-mangrove.scss +6 -0
  117. package/scss/assets/scss/generated/_tokens-preventionweb.scss +20 -4
  118. package/js/__tests__/copy-button.test.js +0 -112
  119. package/js/__tests__/show-more.test.js +0 -80
  120. package/js/__tests__/table-of-contents.test.js +0 -196
  121. package/scss/Components/SyndicationSearchWidget/SyndicationSearchWidget.scss +0 -11
  122. package/scss/Components/TableOfContents/TableOfContents.scss +0 -11
  123. package/scss/Utilities/FullWidth/FullWidth.scss +0 -11
  124. package/scss/Utilities/ShowMore/ShowMore.scss +0 -11
@@ -65,14 +65,14 @@
65
65
  <div></div>
66
66
  </div>
67
67
  <div class="mg-error-page__container">
68
- <a href="https://www.undrr.org/"><div class="undrr-logo" aria-hidden="true"></div></a>
68
+ <a href="https://www.undrr.org/" aria-label="UNDRR home"><div class="undrr-logo" aria-hidden="true"></div></a>
69
69
  <h1>Checking your browser</h1>
70
70
  <p>This is a routine check to keep the site secure. It only takes a moment.</p>
71
71
  <!-- Cloudflare CAPTCHA box - REQUIRED for managed challenge pages -->
72
72
  ::CAPTCHA_BOX::
73
73
  <p>
74
74
  Having trouble?
75
- <a href="https://www.undrr.org/contact-us">Contact us</a>
75
+ <a href="https://www.undrr.org/contact-us">Contact UNDRR</a>
76
76
  and include the details below.
77
77
  </p>
78
78
  <!-- Cloudflare tokens - replace with your platform's variables if not using Cloudflare -->
@@ -90,7 +90,7 @@
90
90
  document.head.appendChild(el);
91
91
  }
92
92
  // Load full CSS from CDN (includes fonts)
93
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0-rc.2/css/style.css'});
93
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
94
94
  // Load analytics
95
95
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
96
96
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
package/js/README.md CHANGED
@@ -1,31 +1,35 @@
1
1
  # Vanilla JS scripts
2
2
 
3
- Standalone JavaScript modules that work without React. Each file in this directory is auto-discovered by `webpack.entries.js` and produces a UMD bundle at `dist/js/{name}.min.js`.
3
+ Standalone JavaScript modules that work without React. Each file in this directory ships as source: the build copies it, it is not bundled or minified.
4
4
 
5
5
  ## How they ship
6
6
 
7
7
  ```
8
8
  stories/assets/js/my-script.js ← source (this directory)
9
- ↓ webpack build (Config 1, UMD)
10
- dist/js/my-script.min.js ← minified bundle (Drupal/CDN)
11
- ↓ CopyPlugin
12
- dist/assets/js/my-script.js ← unminified copy
13
- ↓ npm-publish.yml (CI)
9
+ ↓ CopyPlugin (webpack Config 1)
10
+ dist/assets/js/my-script.js ← verbatim copy (CDN)
11
+ ↓ assemble-npm-package.mjs (CI)
14
12
  @undrr/undrr-mangrove/js/my-script.js ← npm package
15
13
  ```
16
14
 
17
- The GitHub Actions publish workflow (`npm-publish.yml`) copies `dist/assets/js/*` into the npm package at the top-level `js/` directory. This happens automatically — no manual registration is needed.
15
+ They are ES modules, so a page loads one with `<script type="module">`. There is no minified or UMD variant and nothing is emitted under `dist/js/`.
16
+
17
+ The publish workflow (`npm-publish.yml`) runs `scripts/assemble-npm-package.mjs`, which copies `dist/assets/js/*` into the npm package at the top-level `js/` directory. This happens automatically — the build needs no manual registration. The AI manifest does: see step 6 below.
18
18
 
19
19
  ## Current scripts
20
20
 
21
- | File | Component | Purpose |
22
- | --------------------- | -------------------------------------------------- | ---------------------------------------------------------------------- |
23
- | `on-this-page-nav.js` | [OnThisPageNav](../../Components/OnThisPageNav/) | Sticky horizontal "On this page" navigation with scroll-spy |
24
- | `tabs.js` | [Tab](../../Components/Tab/) | Tabbed content with keyboard navigation and deep linking |
25
- | `show-more.js` | [ShowMore](../../../Utilities/ShowMore/) | Expand/collapse toggle for content sections |
26
- | `copy-button.js` | [CopyButton](../../Components/Buttons/CopyButton/) | Zero-dependency clipboard copy button with transient feedback |
27
- | `switch-pending.js` | [Checkbox](../../Components/Forms/Checkbox/) | Pending state for `.mg-switch`: announces, guards, times out, reverts |
28
- | `undrr.js` | — | Shared constants (key codes, breakpoints) and `window.UNDRR` namespace |
21
+ | File | Component | Purpose |
22
+ | ---------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
23
+ | `on-this-page-nav.js` | [OnThisPageNav](../../Components/OnThisPageNav/) | Sticky horizontal "On this page" navigation with scroll-spy |
24
+ | `tabs.js` | [Tab](../../Components/Tab/) | Tabbed content with keyboard navigation and deep linking |
25
+ | `show-more.js` | [ShowMore](../../../Utilities/ShowMore/) | Expand/collapse toggle for content sections |
26
+ | `copy-button.js` | [CopyButton](../../Components/Buttons/CopyButton/) | Zero-dependency clipboard copy button with transient feedback |
27
+ | `switch-pending.js` | [Checkbox](../../Components/Forms/Checkbox/) | Pending state for `.mg-switch`: announces, guards, and optionally times out and reverts; also exports the announcements alone |
28
+ | `hub-header.js` | [HubHeader](../../Patterns/ContentHub/) | Current section from the URL, scroll into view and edge fades for static hub header markup |
29
+ | `drawer.js` | [Drawer](../../Components/Navigation/Drawer/) | Open and close, Escape, focus management and a modal focus trap for a drawer or floating panel you rendered yourself |
30
+ | `preview-access.js` | [PreviewAccess](../../Components/PreviewAccess/) | Password gate and preview notice for staging and pre-publication review |
31
+ | `table-of-contents.js` | [TableOfContents](../../Components/TableOfContents/) | In-page table of contents generated from the article's headings, with scrollspy |
32
+ | `undrr.js` | — | Shared constants (key codes, breakpoints) and `window.UNDRR` namespace |
29
33
 
30
34
  ## Adding a new script
31
35
 
@@ -41,19 +45,21 @@ The GitHub Actions publish workflow (`npm-publish.yml`) copies `dist/assets/js/*
41
45
  ```
42
46
  4. Use `data-mg-*` attributes for activation and configuration
43
47
  5. Guard against double-init: `if (el.dataset.mgMyFeatureInitialized) return;`
44
- 6. Create a companion SCSS file in `stories/Components/YourComponent/` and import it in `_components.scss`
45
- 7. Run `yarn build` — the script appears at `dist/js/my-feature.min.js`
48
+ This is required, not optional — see [HYDRATION-AUTHORING.md](../../../docs/HYDRATION-AUTHORING.md) for why a per-element flag and not a module-scope `WeakMap`.
49
+ 6. Register the module in `VANILLA_SCRIPTS` in `scripts/ai-manifest/generate-ai-manifest.js`, and add a `vanillaModule` contract to its component in `scripts/ai-manifest/component-data.js` if it drives one. `yarn validate-manifest` fails on a module that ships undocumented, and on a contract that names a file which does not exist.
50
+ 7. Create a companion SCSS file in `stories/Components/YourComponent/` and import it in `_components.scss`
51
+ 8. Run `yarn build` — the script appears at `dist/assets/js/my-feature.js`
46
52
 
47
- No webpack config or `src/index.js` changes are needed. The file is picked up automatically by the glob pattern in `webpack.entries.js`.
53
+ No webpack config or `src/index.js` changes are needed. CopyPlugin copies this whole directory, so a new file is picked up by being here.
48
54
 
49
55
  ## Differences from React components
50
56
 
51
- | | Vanilla JS (this directory) | React components |
52
- | ------------------ | --------------------------------- | ---------------------------------------- |
53
- | Entry discovery | Auto (glob) | Manual (webpack.config.js) |
54
- | Output | `dist/js/*.min.js` (UMD) | `dist/components/*.js` (ESM) |
55
- | npm location | `@undrr/undrr-mangrove/js/` | `@undrr/undrr-mangrove/components/` |
56
- | React dependency | None | Externalized (provided by import map) |
57
- | Drupal integration | Load script directly as a library | Wrapper + hydration via `createHydrator` |
57
+ | | Vanilla JS (this directory) | React components |
58
+ | ------------------ | ---------------------------------- | ---------------------------------------- |
59
+ | Entry discovery | Auto (whole directory is copied) | Manual (webpack.config.js) |
60
+ | Output | `dist/assets/js/*.js` (ESM source) | `dist/components/*.js` (ESM bundle) |
61
+ | npm location | `@undrr/undrr-mangrove/js/` | `@undrr/undrr-mangrove/components/` |
62
+ | React dependency | None | Externalized (provided by import map) |
63
+ | Drupal integration | Load script directly as a library | Wrapper + hydration via `createHydrator` |
58
64
 
59
65
  See [ARCHITECTURE.md](../../../docs/ARCHITECTURE.md) for the full build system documentation.
package/js/copy-button.js CHANGED
@@ -5,8 +5,13 @@
5
5
  * Initializes standalone copy buttons without requiring React.
6
6
  *
7
7
  * Expected HTML:
8
+ * The button is icon-only, so it needs an accessible name: give it an
9
+ * `aria-label` (or `data-aria-label`, which this script copies onto
10
+ * `aria-label` when the button has no name of its own).
11
+ *
8
12
  * <button type="button" class="mg-button mg-button-primary mg-button-outline mg-button--icon mg-copy-button"
9
13
  * data-mg-copy-button
14
+ * aria-label="Copy to clipboard"
10
15
  * data-text-to-copy="https://example.org"
11
16
  * data-tooltip-label="Copied!"
12
17
  * data-copied-label="Copied to clipboard."
@@ -36,6 +41,18 @@ export function mgCopyButton(scope) {
36
41
  if (button.dataset.mgCopyButtonInitialized) return;
37
42
  button.dataset.mgCopyButtonInitialized = 'true';
38
43
 
44
+ // An icon-only button with no accessible name announces as just "button"
45
+ // (WCAG 4.1.2). Markup copied from earlier docs carried the label in
46
+ // `data-aria-label`, which nothing read; honour it rather than ship a
47
+ // nameless control, without overriding a real name if one is present.
48
+ if (
49
+ button.dataset.ariaLabel &&
50
+ !button.getAttribute('aria-label') &&
51
+ !button.getAttribute('aria-labelledby')
52
+ ) {
53
+ button.setAttribute('aria-label', button.dataset.ariaLabel);
54
+ }
55
+
39
56
  let timer = null;
40
57
 
41
58
  button.addEventListener('click', async () => {