@undrr/undrr-mangrove 2.0.0 → 2.0.1

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 (175) hide show
  1. package/README.md +9 -5
  2. package/components/BookCard.js +2 -2
  3. package/components/Breadcrumbs.js +2 -2
  4. package/components/Checkbox.js +2 -2
  5. package/components/Chips.js +2 -2
  6. package/components/CopyButton.js +2 -2
  7. package/components/CtaButton.js +2 -2
  8. package/components/Drawer.js +3 -3
  9. package/components/Drawer.js.LICENSE.txt +3 -1
  10. package/components/EmbedContainer.js +2 -2
  11. package/components/Footer.js +2 -2
  12. package/components/FormAction.js +2 -2
  13. package/components/FormErrorSummary.js +2 -2
  14. package/components/FormGroup.js +2 -2
  15. package/components/FullWidth.js +2 -2
  16. package/components/Gallery.js +2 -2
  17. package/components/Hero.js +2 -2
  18. package/components/HighlightBox.js +2 -2
  19. package/components/HorizontalBookCard.js +3 -3
  20. package/components/HorizontalBookCard.js.LICENSE.txt +3 -1
  21. package/components/HorizontalCard.js +3 -3
  22. package/components/HorizontalCard.js.LICENSE.txt +3 -1
  23. package/components/IconCard.js +3 -3
  24. package/components/IconCard.js.LICENSE.txt +3 -1
  25. package/components/Legend.js +2 -2
  26. package/components/Loader.js +3 -3
  27. package/components/MegaMenu.js +2 -2
  28. package/components/Notice.js +2 -2
  29. package/components/PageHeader.js +2 -2
  30. package/components/Pager.js +2 -2
  31. package/components/ProgressBar.js +9 -0
  32. package/components/ProgressBar.js.LICENSE.txt +9 -0
  33. package/components/QuoteHighlight.js +3 -3
  34. package/components/QuoteHighlight.js.LICENSE.txt +3 -1
  35. package/components/Radio.js +2 -2
  36. package/components/Range.js +2 -2
  37. package/components/ScrollContainer.js +2 -2
  38. package/components/SegmentedControl.js +2 -2
  39. package/components/Select.js +2 -2
  40. package/components/ServiceNotice.js +2 -2
  41. package/components/ShareButtons.js +3 -3
  42. package/components/ShowMore.js +2 -2
  43. package/components/SkipLink.js +2 -2
  44. package/components/StatsCard.js +3 -3
  45. package/components/StatsCard.js.LICENSE.txt +3 -1
  46. package/components/SyndicationSearchWidget.js +3 -3
  47. package/components/Tab.js +2 -2
  48. package/components/TextCta.js +3 -3
  49. package/components/TextCta.js.LICENSE.txt +3 -1
  50. package/components/TextInput.js +2 -2
  51. package/components/Textarea.js +2 -2
  52. package/components/Tree.js +2 -2
  53. package/components/UserFeedback.js +2 -2
  54. package/components/VerticalCard.js +3 -3
  55. package/components/VerticalCard.js.LICENSE.txt +3 -1
  56. package/components/hydrate.js +2 -2
  57. package/css/style-all.css +110 -90
  58. package/css/style-all.css.map +1 -1
  59. package/css/style-delta.css +110 -90
  60. package/css/style-delta.css.map +1 -1
  61. package/css/style-gutenberg.css +9 -9
  62. package/css/style-irp.css +110 -90
  63. package/css/style-irp.css.map +1 -1
  64. package/css/style-mcr.css +110 -90
  65. package/css/style-mcr.css.map +1 -1
  66. package/css/style-preventionweb.css +110 -90
  67. package/css/style-preventionweb.css.map +1 -1
  68. package/css/style.css +110 -90
  69. package/css/style.css.map +1 -1
  70. package/docs/EDITORIAL-MANUAL.md +193 -0
  71. package/docs/llms-editorial-manual.txt +200 -0
  72. package/docs/llms-page-building.txt +1140 -0
  73. package/docs/llms-search-widget.txt +765 -0
  74. package/error-pages/401.html +1 -1
  75. package/error-pages/403.html +1 -1
  76. package/error-pages/404.html +1 -1
  77. package/error-pages/429.html +1 -1
  78. package/error-pages/500.html +1 -1
  79. package/error-pages/502.html +1 -1
  80. package/error-pages/503.html +1 -1
  81. package/error-pages/504.html +1 -1
  82. package/error-pages/5xx.html +1 -1
  83. package/error-pages/challenge.html +1 -1
  84. package/error-pages/managed-challenge.html +1 -1
  85. package/js/cite-this.js +352 -0
  86. package/package.json +6 -1
  87. package/scss/Atom/BaseTypography/Abbr/abbr.scss +1 -1
  88. package/scss/Atom/BaseTypography/Blockquote/blockquote.scss +1 -1
  89. package/scss/Atom/BaseTypography/Cite/cite.scss +1 -1
  90. package/scss/Atom/BaseTypography/Code/code.scss +1 -1
  91. package/scss/Atom/BaseTypography/Mark/mark.scss +1 -1
  92. package/scss/Atom/BaseTypography/Quotation/quotation.scss +1 -1
  93. package/scss/Atom/BaseTypography/Small/small.scss +1 -1
  94. package/scss/Atom/Colors/color.scss +1 -1
  95. package/scss/Atom/EmptyState/empty-state.scss +1 -1
  96. package/scss/Atom/Icons/_icon-definitions.scss +35 -3
  97. package/scss/Atom/Icons/icons.scss +1 -1
  98. package/scss/Atom/Images/AuthorImage/author-image.scss +1 -1
  99. package/scss/Atom/Images/Image/image.scss +1 -1
  100. package/scss/Atom/Images/ImageCaptionCredit/image-caption-credit.scss +7 -2
  101. package/scss/Atom/Images/ImageCredit/image-credit.scss +1 -1
  102. package/scss/Atom/Layout/Container/container.scss +1 -1
  103. package/scss/Atom/Layout/Grid/grid.scss +1 -1
  104. package/scss/Atom/Layout/Spacing/spacing.scss +1 -1
  105. package/scss/Atom/Logo/logo.scss +1 -1
  106. package/scss/Atom/Navigation/Breadcrumb/breadcrumb.scss +1 -1
  107. package/scss/Atom/Navigation/MenuItems/menu-items.scss +1 -1
  108. package/scss/Atom/ReachElement/Details/details.scss +1 -1
  109. package/scss/Atom/ReachElement/Figcaption/figcaption.scss +1 -1
  110. package/scss/Atom/StatusLabel/status-label.scss +1 -1
  111. package/scss/Atom/Table/table.scss +1 -1
  112. package/scss/Atom/Tag/tag.scss +1 -1
  113. package/scss/Atom/Video/video.scss +1 -1
  114. package/scss/Components/Boilerplate/boilerplate.scss +1 -1
  115. package/scss/Components/Breadcrumbs/breadcrumbs.scss +1 -1
  116. package/scss/Components/Buttons/Chips/chips.scss +1 -1
  117. package/scss/Components/Buttons/CopyButton/copy-button.scss +1 -1
  118. package/scss/Components/Buttons/CtaButton/buttons.scss +1 -1
  119. package/scss/Components/Buttons/CtaButton/cta-button.scss +1 -1
  120. package/scss/Components/Buttons/ShareButtons/share-buttons.scss +90 -1
  121. package/scss/Components/Cards/Card/card.scss +1 -1
  122. package/scss/Components/Cards/StatsCard/stats-card.scss +1 -1
  123. package/scss/Components/CiteThis/cite-this.scss +186 -0
  124. package/scss/Components/CookieConsentBanner/cookie-consent-banner.scss +1 -1
  125. package/scss/Components/DataViz/Legend/legend.scss +1 -1
  126. package/scss/Components/ErrorPages/error-pages.scss +1 -1
  127. package/scss/Components/Footer/footer.scss +1 -1
  128. package/scss/Components/Forms/Checkbox/checkbox.scss +1 -1
  129. package/scss/Components/Forms/FormAction/form-action.scss +1 -1
  130. package/scss/Components/Forms/FormGroup/form-group.scss +1 -1
  131. package/scss/Components/Forms/InputFields/input-fields.scss +1 -1
  132. package/scss/Components/Forms/Radio/radio.scss +1 -1
  133. package/scss/Components/Forms/Range/range.scss +1 -1
  134. package/scss/Components/Forms/SegmentedControl/segmented-control.scss +1 -1
  135. package/scss/Components/Forms/Select/select.scss +1 -1
  136. package/scss/Components/Forms/TextInput/text-input.scss +1 -1
  137. package/scss/Components/Forms/Textarea/textarea.scss +1 -1
  138. package/scss/Components/Forms/_form-base.scss +1 -1
  139. package/scss/Components/Gallery/gallery.scss +1 -1
  140. package/scss/Components/Hero/hero.scss +1 -1
  141. package/scss/Components/HighlightBox/highlight-box.scss +1 -1
  142. package/scss/Components/MegaMenu/mega-menu.scss +1 -1
  143. package/scss/Components/MegaMenu/megamenu.scss +1 -1
  144. package/scss/Components/Navigation/Drawer/drawer.scss +1 -1
  145. package/scss/Components/Navigation/Tree/tree.scss +1 -1
  146. package/scss/Components/Notice/notice.scss +1 -1
  147. package/scss/Components/OnThisPageNav/on-this-page-nav.scss +1 -1
  148. package/scss/Components/PageHeader/page-header.scss +1 -1
  149. package/scss/Components/Pager/pager.scss +1 -1
  150. package/scss/Components/PreviewAccess/preview-access.scss +1 -1
  151. package/scss/Components/ProgressBar/progress-bar.scss +215 -0
  152. package/scss/Components/QuoteHighlight/quote-highlight.scss +1 -1
  153. package/scss/Components/ScrollContainer/scroll-container.scss +1 -1
  154. package/scss/Components/Snackbar/snackbar.scss +1 -1
  155. package/scss/Components/SyndicationSearchWidget/_deprecated-teaser-hide.scss +1 -1
  156. package/scss/Components/SyndicationSearchWidget/syndication-search-widget.scss +1 -1
  157. package/scss/Components/Tab/tab.scss +1 -1
  158. package/scss/Components/TableOfContents/table-of-contents.scss +1 -1
  159. package/scss/Components/TextCta/text-cta.scss +1 -1
  160. package/scss/Components/TextCta/textcta.scss +1 -1
  161. package/scss/Components/UserFeedback/user-feedback.scss +1 -1
  162. package/scss/Molecules/ImageCaption/image-caption.scss +17 -3
  163. package/scss/Molecules/SectionHeader/section-header.scss +1 -1
  164. package/scss/Molecules/SectionHeader/sectionheader.scss +1 -1
  165. package/scss/Patterns/HubHeader/hub-header.scss +1 -1
  166. package/scss/Patterns/_shared/pattern-demo.scss +1 -1
  167. package/scss/Utilities/EmbedContainer/embed-container.scss +1 -1
  168. package/scss/Utilities/FullWidth/full-width.scss +1 -1
  169. package/scss/Utilities/Loader/loader.scss +55 -12
  170. package/scss/Utilities/Normalize/normalize.scss +1 -1
  171. package/scss/Utilities/PagePatterns/page-patterns.scss +1 -1
  172. package/scss/Utilities/ShowMore/show-more.scss +1 -1
  173. package/scss/Utilities/SkipLink/skip-link.scss +1 -1
  174. package/scss/assets/scss/_components.scss +2 -0
  175. package/scss/assets/scss/_variables.scss +2 -2
@@ -88,7 +88,7 @@
88
88
  document.head.appendChild(el);
89
89
  }
90
90
  // Load full CSS from CDN (includes fonts)
91
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
91
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
92
92
  // Load analytics
93
93
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
94
94
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -84,7 +84,7 @@
84
84
  document.head.appendChild(el);
85
85
  }
86
86
  // Load full CSS from CDN (includes fonts)
87
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
87
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
88
88
  // Load analytics
89
89
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
90
90
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -96,7 +96,7 @@
96
96
  document.head.appendChild(el);
97
97
  }
98
98
  // Load full CSS from CDN (includes fonts)
99
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
99
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
100
100
  // Load analytics
101
101
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
102
102
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -91,7 +91,7 @@
91
91
  document.head.appendChild(el);
92
92
  }
93
93
  // Load full CSS from CDN (includes fonts)
94
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
94
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
95
95
  // Load analytics
96
96
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
97
97
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -87,7 +87,7 @@
87
87
  document.head.appendChild(el);
88
88
  }
89
89
  // Load full CSS from CDN (includes fonts)
90
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
90
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
91
91
  // Load analytics
92
92
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
93
93
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -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/css/style.css'});
93
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/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:''});
@@ -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/css/style.css'});
93
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/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:''});
@@ -87,7 +87,7 @@
87
87
  document.head.appendChild(el);
88
88
  }
89
89
  // Load full CSS from CDN (includes fonts)
90
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
90
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
91
91
  // Load analytics
92
92
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
93
93
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -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/css/style.css'});
93
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/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:''});
@@ -88,7 +88,7 @@
88
88
  document.head.appendChild(el);
89
89
  }
90
90
  // Load full CSS from CDN (includes fonts)
91
- load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.0/css/style.css'});
91
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/css/style.css'});
92
92
  // Load analytics
93
93
  load('script',{src:'https://assets.undrr.org/analytics/v1.0.0/google_analytics_enhancements.js',crossorigin:'anonymous'});
94
94
  load('script',{src:'https://messaging.undrr.org/src/undrr-messaging.js',defer:''});
@@ -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/css/style.css'});
93
+ load('link',{rel:'stylesheet',href:'https://assets.undrr.org/mangrove/2.0.1/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:''});
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Vanilla citation dialog for server-rendered pages.
3
+ * The host owns editorial approval and analytics; this module only resolves,
4
+ * displays, copies, and announces a citation.
5
+ */
6
+ const WORK_TYPES = new Set([
7
+ 'Article',
8
+ 'Book',
9
+ 'Chapter',
10
+ 'CreativeWork',
11
+ 'NewsArticle',
12
+ 'Report',
13
+ 'ScholarlyArticle',
14
+ 'TechArticle',
15
+ 'WebPage',
16
+ ]);
17
+
18
+ const instances = new WeakMap();
19
+ let nextDialogId = 0;
20
+
21
+ function firstText(value) {
22
+ if (Array.isArray(value))
23
+ return value.map(firstText).filter(Boolean).join(', ');
24
+ if (typeof value === 'string') return value.trim();
25
+ if (value && typeof value === 'object') {
26
+ return firstText(value.name || value.legalName);
27
+ }
28
+ return '';
29
+ }
30
+
31
+ function cleanUrl(value, base, stripQuery = false) {
32
+ try {
33
+ const url = new URL(value, base);
34
+ if (!['https:', 'http:'].includes(url.protocol)) return '';
35
+ url.hash = '';
36
+ if (stripQuery) url.search = '';
37
+ return url.href.replace(/\/$/, '');
38
+ } catch {
39
+ return '';
40
+ }
41
+ }
42
+
43
+ function canonicalUrl(doc) {
44
+ const canonical = doc.querySelector('link[rel="canonical"]')?.href;
45
+ return cleanUrl(
46
+ canonical || doc.location.href,
47
+ doc.location.href,
48
+ !canonical
49
+ );
50
+ }
51
+
52
+ function workTypes(node) {
53
+ return [node?.['@type']]
54
+ .flat()
55
+ .filter(Boolean)
56
+ .map(type => String(type).split(/[\/#]/).pop());
57
+ }
58
+
59
+ function schemaNodes(value) {
60
+ if (Array.isArray(value)) return value.flatMap(schemaNodes);
61
+ if (!value || typeof value !== 'object') return [];
62
+ return [
63
+ value,
64
+ ...schemaNodes(value['@graph']),
65
+ ...schemaNodes(value.mainEntity),
66
+ ];
67
+ }
68
+
69
+ function referenceUrl(value) {
70
+ if (typeof value === 'string') return value;
71
+ return value?.['@id'] || value?.url || '';
72
+ }
73
+
74
+ function schemaWork(doc, canonical) {
75
+ const base = doc.location.href;
76
+ const candidates = [];
77
+ for (const script of doc.querySelectorAll(
78
+ 'script[type="application/ld+json"]'
79
+ )) {
80
+ try {
81
+ candidates.push(...schemaNodes(JSON.parse(script.textContent)));
82
+ } catch {
83
+ // Malformed JSON-LD must not prevent the page citation fallback.
84
+ }
85
+ }
86
+ const matches = candidates.filter(node => {
87
+ if (!workTypes(node).some(type => WORK_TYPES.has(type))) return false;
88
+ return [node.mainEntityOfPage, node.url, node['@id']].some(
89
+ value => cleanUrl(referenceUrl(value), base) === canonical
90
+ );
91
+ });
92
+ // The WebPage may identify its primary work through mainEntity instead of
93
+ // repeating mainEntityOfPage on that work.
94
+ const page = matches.find(node => workTypes(node).includes('WebPage'));
95
+ const mainEntity = schemaNodes(page?.mainEntity).find(node =>
96
+ workTypes(node).some(type => WORK_TYPES.has(type) && type !== 'WebPage')
97
+ );
98
+ // A matching work is preferable to a matching WebPage wrapper.
99
+ return (
100
+ matches.find(node => !workTypes(node).includes('WebPage')) ||
101
+ mainEntity ||
102
+ matches[0]
103
+ );
104
+ }
105
+
106
+ function publicationYear(value) {
107
+ const match = String(value || '').match(/^(\d{4})(?:-|$)/);
108
+ return match ? match[1] : '';
109
+ }
110
+
111
+ function formatCitation({ author, title, publisher, year, url, accessed }) {
112
+ const lead = author ? `${author}${year ? ` (${year})` : ''}, ` : '';
113
+ const titlePart = `“${title}”`;
114
+ const source = publisher && publisher !== author ? `, ${publisher}` : '';
115
+ const date = !author && year ? ` (${year})` : '';
116
+ const access = year ? '' : `, accessed ${accessed}`;
117
+ return `${lead}${titlePart}${source}${date}${access}, ${url}.`;
118
+ }
119
+
120
+ /** Resolve a citation, in editorial → configured → matching JSON-LD → page order. */
121
+ export function resolveCitation(element, now = new Date()) {
122
+ const doc = element.ownerDocument;
123
+ const canonical = canonicalUrl(doc);
124
+ const data = element.dataset;
125
+ const explicit = data.mgCiteThisCitation?.trim();
126
+ if (explicit) return { text: explicit, source: 'provided', url: canonical };
127
+
128
+ const configured = [
129
+ data.mgCiteThisAuthor,
130
+ data.mgCiteThisPublisher,
131
+ data.mgCiteThisYear,
132
+ data.mgCiteThisTitle,
133
+ data.mgCiteThisUrl,
134
+ ].some(Boolean);
135
+ const work = schemaWork(doc, canonical);
136
+ const title =
137
+ data.mgCiteThisTitle?.trim() ||
138
+ firstText(work?.headline || work?.name) ||
139
+ doc.title?.trim() ||
140
+ doc.querySelector('meta[property="og:title"]')?.content?.trim() ||
141
+ doc.querySelector('h1')?.textContent?.trim() ||
142
+ 'Untitled page';
143
+ const site =
144
+ data.mgCiteThisSite?.trim() ||
145
+ doc.querySelector('meta[property="og:site_name"]')?.content?.trim() ||
146
+ new URL(canonical).hostname.replace(/^www\./, '');
147
+ const author = data.mgCiteThisAuthor?.trim() || firstText(work?.author);
148
+ const publisher =
149
+ data.mgCiteThisPublisher?.trim() || firstText(work?.publisher) || site;
150
+ const year = publicationYear(data.mgCiteThisYear || work?.datePublished);
151
+ const url =
152
+ cleanUrl(data.mgCiteThisUrl || work?.url || canonical, doc.location.href) ||
153
+ canonical;
154
+ const pageLang = doc.documentElement.lang || 'en-GB';
155
+ const locale = pageLang === 'en' ? 'en-GB' : pageLang;
156
+ const accessed = new Intl.DateTimeFormat(locale, {
157
+ day: 'numeric',
158
+ month: 'long',
159
+ year: 'numeric',
160
+ }).format(now);
161
+ return {
162
+ text: formatCitation({ author, title, publisher, year, url, accessed }),
163
+ source: configured ? 'metadata' : work ? 'schema' : 'page',
164
+ url,
165
+ };
166
+ }
167
+
168
+ function elementsIn(scope) {
169
+ if (!scope) return [];
170
+ if (!scope.querySelectorAll) return Array.from(scope).flatMap(elementsIn);
171
+ return [
172
+ ...(scope.matches?.('[data-mg-cite-this]') ? [scope] : []),
173
+ ...scope.querySelectorAll('[data-mg-cite-this]'),
174
+ ];
175
+ }
176
+
177
+ function emit(element, name, citation) {
178
+ element.dispatchEvent(
179
+ new CustomEvent(`mg-cite-this:${name}`, {
180
+ bubbles: true,
181
+ detail: {
182
+ source: citation.source,
183
+ url: cleanUrl(citation.url, element.ownerDocument.location.href, true),
184
+ },
185
+ })
186
+ );
187
+ }
188
+
189
+ function createFallback(element) {
190
+ const doc = element.ownerDocument;
191
+ const fallback = doc.createElement('details');
192
+ fallback.className = 'mg-cite-this__fallback';
193
+ const summary = doc.createElement('summary');
194
+ summary.className = 'mg-cite-this__summary';
195
+ summary.textContent = element.dataset.mgCiteThisLabel || 'Cite this';
196
+ const content = doc.createElement('div');
197
+ content.className = 'mg-cite-this__content';
198
+ const output = doc.createElement('p');
199
+ output.className = 'mg-cite-this__text mg-code';
200
+ output.dataset.mgCiteThisText = '';
201
+ const actions = doc.createElement('div');
202
+ actions.className = 'mg-cite-this__actions';
203
+ const copy = doc.createElement('button');
204
+ copy.type = 'button';
205
+ copy.className = 'mg-cite-this__copy';
206
+ copy.dataset.mgCiteThisCopy = '';
207
+ copy.textContent = element.dataset.mgCiteThisCopyLabel || 'Copy citation';
208
+ copy.hidden = true;
209
+ const status = doc.createElement('span');
210
+ status.className = 'mg-cite-this__status';
211
+ status.dataset.mgCiteThisStatus = '';
212
+ status.setAttribute('role', 'status');
213
+ status.setAttribute('aria-live', 'polite');
214
+ actions.append(copy, status);
215
+ content.append(output, actions);
216
+ fallback.append(summary, content);
217
+ element.append(fallback);
218
+ return fallback;
219
+ }
220
+
221
+ /** Initialise citation dialogs within a document or Drupal behaviour scope. */
222
+ export function mgCiteThis(scope = document) {
223
+ for (const element of elementsIn(scope)) {
224
+ if (instances.has(element)) continue;
225
+ const existing = element.querySelector('details.mg-cite-this__fallback');
226
+ const generated = !existing && element.childElementCount === 0;
227
+ const fallback = generated ? createFallback(element) : existing;
228
+ const output = fallback?.querySelector('[data-mg-cite-this-text]');
229
+ const summary = fallback?.querySelector('summary');
230
+ const content = fallback?.querySelector('.mg-cite-this__content');
231
+ if (!fallback || !summary || !content || !output) continue;
232
+
233
+ const doc = element.ownerDocument;
234
+ const citation = resolveCitation(element);
235
+ output.textContent = citation.text;
236
+ element.dataset.mgCiteThisSource = citation.source;
237
+ const dialog = doc.createElement('dialog');
238
+ if (typeof dialog.showModal !== 'function') {
239
+ if (generated) instances.set(element, () => fallback.remove());
240
+ continue;
241
+ }
242
+
243
+ const trigger = doc.createElement('button');
244
+ trigger.type = 'button';
245
+ trigger.className = 'mg-cite-this__trigger';
246
+ trigger.textContent = summary.textContent.trim();
247
+ trigger.setAttribute('aria-haspopup', 'dialog');
248
+
249
+ const dialogId = `mg-cite-this-dialog-${++nextDialogId}`;
250
+ const title = doc.createElement('h2');
251
+ title.id = `${dialogId}-title`;
252
+ title.className = 'mg-cite-this__title';
253
+ title.tabIndex = -1;
254
+ title.textContent = trigger.textContent;
255
+
256
+ const close = doc.createElement('button');
257
+ close.type = 'button';
258
+ close.className = 'mg-icon-button mg-cite-this__close';
259
+ close.setAttribute(
260
+ 'aria-label',
261
+ element.dataset.mgCiteThisCloseLabel || 'Close'
262
+ );
263
+ const closeIcon = doc.createElement('span');
264
+ closeIcon.className = 'mg-icon mg-icon-close';
265
+ closeIcon.setAttribute('aria-hidden', 'true');
266
+ close.append(closeIcon);
267
+
268
+ const header = doc.createElement('div');
269
+ header.className = 'mg-cite-this__dialog-header';
270
+ header.append(title, close);
271
+
272
+ const dialogContent = content.cloneNode(true);
273
+ const copy = dialogContent.querySelector('[data-mg-cite-this-copy]');
274
+ const status = dialogContent.querySelector('[data-mg-cite-this-status]');
275
+ if (copy) copy.hidden = false;
276
+ dialog.className = 'mg-cite-this__dialog';
277
+ dialog.setAttribute('aria-labelledby', title.id);
278
+ dialog.append(header, dialogContent);
279
+ element.append(trigger, dialog);
280
+ fallback.hidden = true;
281
+
282
+ let statusTimer;
283
+ const onOpen = () => {
284
+ dialog.showModal();
285
+ title.focus();
286
+ emit(element, 'open', citation);
287
+ };
288
+ const onClose = () => {
289
+ clearTimeout(statusTimer);
290
+ if (status) status.textContent = '';
291
+ trigger.focus();
292
+ };
293
+ const closeDialog = () => dialog.close();
294
+ const onCopy = async () => {
295
+ try {
296
+ await navigator.clipboard.writeText(citation.text);
297
+ if (status)
298
+ status.textContent =
299
+ element.dataset.mgCiteThisCopiedLabel || 'Citation copied';
300
+ emit(element, 'copy', citation);
301
+ clearTimeout(statusTimer);
302
+ statusTimer = setTimeout(() => {
303
+ if (status) status.textContent = '';
304
+ }, 3000);
305
+ } catch {
306
+ if (status)
307
+ status.textContent =
308
+ element.dataset.mgCiteThisFailedLabel ||
309
+ 'Copy failed. Select the citation and copy it manually.';
310
+ emit(element, 'copy-error', citation);
311
+ clearTimeout(statusTimer);
312
+ statusTimer = setTimeout(() => {
313
+ if (status) status.textContent = '';
314
+ }, 5000);
315
+ }
316
+ };
317
+ trigger.addEventListener('click', onOpen);
318
+ close.addEventListener('click', closeDialog);
319
+ dialog.addEventListener('close', onClose);
320
+ copy?.addEventListener('click', onCopy);
321
+ instances.set(element, () => {
322
+ clearTimeout(statusTimer);
323
+ trigger.removeEventListener('click', onOpen);
324
+ close.removeEventListener('click', closeDialog);
325
+ dialog.removeEventListener('close', onClose);
326
+ copy?.removeEventListener('click', onCopy);
327
+ if (dialog.open) dialog.close();
328
+ trigger.remove();
329
+ dialog.remove();
330
+ if (generated) fallback.remove();
331
+ else fallback.hidden = false;
332
+ });
333
+ }
334
+ }
335
+
336
+ /** Remove listeners before replacing content in a client-side navigation. */
337
+ export function mgCiteThisDestroy(scope = document) {
338
+ for (const element of elementsIn(scope)) {
339
+ instances.get(element)?.();
340
+ instances.delete(element);
341
+ }
342
+ }
343
+
344
+ if (typeof document !== 'undefined') {
345
+ if (document.readyState === 'loading') {
346
+ document.addEventListener('DOMContentLoaded', () => mgCiteThis(), {
347
+ once: true,
348
+ });
349
+ } else {
350
+ mgCiteThis();
351
+ }
352
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undrr/undrr-mangrove",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Mangrove design System for UNDRR",
5
5
  "files": [
6
6
  "components/**/*",
@@ -9,6 +9,7 @@
9
9
  "scss/**/*.scss",
10
10
  "error-pages/**/*",
11
11
  "fonts/**/*",
12
+ "docs/**/*",
12
13
  "!**/__tests__/**",
13
14
  "!**/__snapshots__/**",
14
15
  "!**/__mocks__/**",
@@ -20,6 +21,10 @@
20
21
  "type": "git",
21
22
  "url": "https://github.com/unisdr/undrr-mangrove.git"
22
23
  },
24
+ "homepage": "https://mangrove.undrr.org/",
25
+ "bugs": {
26
+ "url": "https://github.com/PreventionWeb/undrr-mangrove/issues"
27
+ },
23
28
  "keywords": [],
24
29
  "author": "",
25
30
  "license": "Apache-2.0"
@@ -4,7 +4,7 @@
4
4
  * Styles for HTML <abbr> elements with subtle dotted underlines and accessible expansion styling.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  abbr[title] {
10
10
  border-bottom: 2px dashed rgb(var(--mg-color-red-900));
@@ -4,7 +4,7 @@
4
4
  * Typography and border accent styles for standard HTML <blockquote> elements.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  .mg-body blockquote,
10
10
  .mg-content blockquote {
@@ -4,7 +4,7 @@
4
4
  * Typographic styles for HTML <cite> citation references.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  .mg-body cite,
10
10
  .mg-content cite {
@@ -4,7 +4,7 @@
4
4
  * Monospace typographic styling for inline <code> elements.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  .mg-code,
10
10
  code {
@@ -4,7 +4,7 @@
4
4
  * Highlight styling for HTML <mark> elements using theme-aware highlight colors.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  mark {
10
10
  background: var(--mg-color-yellow-light);
@@ -4,7 +4,7 @@
4
4
  * Inline quotation typography and glyph styles for <q> elements.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  q {
10
10
  font-style: italic;
@@ -4,7 +4,7 @@
4
4
  * Reduced scale typography styles for fine print and secondary metadata (<small>).
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
8
8
  */
9
9
  small {
10
10
  @extend %paragraph-font-100;
@@ -4,6 +4,6 @@
4
4
  * Color swatch and background/text utility helper classes across brand palettes.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/Colors/color.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/Colors/color.mdx
8
8
  */
9
9
  // empty
@@ -4,7 +4,7 @@
4
4
  * Placeholder presentation for empty search results, missing data, or filtered-out views.
5
5
  *
6
6
  * Full documentation:
7
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/EmptyState/EmptyState.mdx
7
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/EmptyState/EmptyState.mdx
8
8
  */
9
9
  // Empty state — what a list, table, chart or dashboard tile shows when it has
10
10
  // no content to show.
@@ -5,10 +5,10 @@
5
5
  * Generated by scripts/icon-build.cjs — do not edit by hand.
6
6
  *
7
7
  * Full documentation:
8
- * https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/Icons/Icons.mdx
8
+ * https://github.com/PreventionWeb/undrr-mangrove/blob/main/stories/Atom/Icons/Icons.mdx
9
9
  */
10
10
  // To regenerate: yarn build:icons
11
- // 98 icons from Lucide, OCHA, and custom SVG sources.
11
+ // 106 icons from Lucide, OCHA, and custom SVG sources.
12
12
 
13
13
  .mg-icon-globe::before {
14
14
  --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10'/><path d='M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20M2 12h20'/></svg>");
@@ -55,7 +55,7 @@
55
55
  }
56
56
 
57
57
  .mg-icon-pen-nib::before {
58
- --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z'/><path d='m18 13-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18M2.3 2.3l7.286 7.286'/><circle cx='11' cy='11' r='2'/></svg>");
58
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='m18 13-.654-4.736a4 4 0 0 0-2.756-3.266l-9.163-2.9a2 2 0 0 0-2.017.493l-.82.819a2 2 0 0 0-.492 2.017l2.9 9.163a4 4 0 0 0 3.266 2.756L13 18'/><path d='M18.648 12.352a1.205 1.205 0 0 1 1.704 0l1.296 1.296a1.205 1.205 0 0 1 0 1.704l-6.296 6.296a1.205 1.205 0 0 1-1.704 0l-1.296-1.296a1.205 1.205 0 0 1 0-1.704zM3 3l6.586 6.586'/><circle cx='11' cy='11' r='2'/></svg>");
59
59
  }
60
60
 
61
61
  .mg-icon-code-branch::before {
@@ -126,6 +126,38 @@
126
126
  --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8'/><path d='M21 3v5h-5M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16'/><path d='M8 16H3v5'/></svg>");
127
127
  }
128
128
 
129
+ .mg-icon-plus::before {
130
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='M5 12h14M12 5v14'/></svg>");
131
+ }
132
+
133
+ .mg-icon-minus::before {
134
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='M5 12h14'/></svg>");
135
+ }
136
+
137
+ .mg-icon-pause::before {
138
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><rect width='5' height='18' x='14' y='3' rx='1'/><rect width='5' height='18' x='5' y='3' rx='1'/></svg>");
139
+ }
140
+
141
+ .mg-icon-play::before {
142
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z'/></svg>");
143
+ }
144
+
145
+ .mg-icon-circle-minus::before {
146
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10'/><path d='M8 12h8'/></svg>");
147
+ }
148
+
149
+ .mg-icon-expand::before {
150
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='m15 15 6 6M15 9l6-6M21 16v5h-5M21 8V3h-5M3 16v5h5M3 21l6-6M3 8V3h5M9 9 3 3'/></svg>");
151
+ }
152
+
153
+ .mg-icon-shrink::before {
154
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='m15 15 6 6m-6-6v4.8m0-4.8h4.8M9 19.8V15m0 0H4.2M9 15l-6 6M15 4.2V9m0 0h4.8M15 9l6-6M9 4.2V9m0 0H4.2M9 9 3 3'/></svg>");
155
+ }
156
+
157
+ .mg-icon-layers::before {
158
+ --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><path d='M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z'/><path d='M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12'/><path d='M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17'/></svg>");
159
+ }
160
+
129
161
  .mg-icon-clone::before {
130
162
  --mg-icon-svg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' viewBox='0 0 24 24'><rect width='14' height='14' x='8' y='8' rx='2' ry='2'/><path d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/></svg>");
131
163
  }