@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.
- package/README.md +11 -6
- package/components/BookCard.js +1 -1
- package/components/Breadcrumbs.js +2 -2
- package/components/Checkbox.js +1 -1
- package/components/Chips.js +1 -1
- package/components/CopyButton.js +2 -2
- package/components/CtaButton.js +1 -1
- package/components/Drawer.js +1 -1
- package/components/EmbedContainer.js +1 -1
- package/components/Footer.js +1 -1
- package/components/FormAction.js +1 -1
- package/components/FormErrorSummary.js +1 -1
- package/components/FormGroup.js +1 -1
- package/components/FullWidth.js +1 -1
- package/components/Gallery.js +2 -2
- package/components/Hero.js +2 -2
- package/components/HighlightBox.js +1 -1
- package/components/HorizontalBookCard.js +1 -1
- package/components/HorizontalCard.js +1 -1
- package/components/IconCard.js +1 -1
- package/components/Legend.js +1 -1
- package/components/Loader.js +1 -1
- package/components/MegaMenu.js +2 -2
- package/components/Notice.js +2 -2
- package/components/PageHeader.js +2 -2
- package/components/Pager.js +2 -2
- package/components/QuoteHighlight.js +2 -2
- package/components/QuoteHighlight.js.LICENSE.txt +2 -0
- package/components/Radio.js +1 -1
- package/components/Range.js +1 -1
- package/components/ScrollContainer.js +2 -2
- package/components/SegmentedControl.js +9 -0
- package/components/SegmentedControl.js.LICENSE.txt +9 -0
- package/components/Select.js +1 -1
- package/components/ServiceNotice.js +2 -2
- package/components/ShareButtons.js +2 -2
- package/components/ShowMore.js +2 -2
- package/components/SkipLink.js +1 -1
- package/components/StatsCard.js +1 -1
- package/components/SyndicationSearchWidget.js +2 -2
- package/components/Tab.js +2 -2
- package/components/TextCta.js +1 -1
- package/components/TextInput.js +1 -1
- package/components/Textarea.js +1 -1
- package/components/Tree.js +1 -1
- package/components/UserFeedback.js +1 -1
- package/components/VerticalCard.js +1 -1
- package/components/hydrate.js +2 -2
- package/css/style-all.css +60 -40
- package/css/style-all.css.map +1 -1
- package/css/style-delta.css +59 -39
- package/css/style-delta.css.map +1 -1
- package/css/style-gutenberg.css +16 -7
- package/css/style-gutenberg.css.map +1 -1
- package/css/style-irp.css +60 -40
- package/css/style-irp.css.map +1 -1
- package/css/style-mcr.css +59 -39
- package/css/style-mcr.css.map +1 -1
- package/css/style-preventionweb.css +60 -40
- package/css/style-preventionweb.css.map +1 -1
- package/css/style.css +59 -39
- package/css/style.css.map +1 -1
- package/error-pages/401.html +3 -3
- package/error-pages/403.html +3 -3
- package/error-pages/404.html +4 -4
- package/error-pages/429.html +3 -3
- package/error-pages/500.html +6 -6
- package/error-pages/502.html +3 -3
- package/error-pages/503.html +3 -3
- package/error-pages/504.html +3 -3
- package/error-pages/5xx.html +4 -4
- package/error-pages/challenge.html +3 -3
- package/error-pages/managed-challenge.html +3 -3
- package/js/README.md +31 -25
- package/js/copy-button.js +17 -0
- package/js/drawer.js +752 -0
- package/js/hub-header.js +217 -0
- package/js/show-more.js +144 -10
- package/js/switch-pending.js +195 -46
- package/package.json +8 -3
- package/scss/Atom/BaseTypography/Blockquote/blockquote.scss +2 -1
- package/scss/Atom/BaseTypography/Cite/cite.scss +2 -1
- package/scss/Atom/BaseTypography/Code/code.scss +8 -2
- package/scss/Atom/Icons/icons.scss +1 -1
- package/scss/Atom/Images/AuthorImage/author-image.scss +16 -1
- package/scss/Atom/StatusLabel/status-label.scss +331 -8
- package/scss/Atom/Table/table.scss +8 -3
- package/scss/Atom/Tag/tag.scss +20 -2
- package/scss/Components/Breadcrumbs/breadcrumbs.scss +8 -4
- package/scss/Components/Buttons/CtaButton/cta-button.scss +15 -0
- package/scss/Components/Cards/Card/card.scss +37 -10
- package/scss/Components/Cards/StatsCard/stats-card.scss +2 -10
- package/scss/Components/DataViz/Legend/legend.scss +2 -1
- package/scss/Components/ErrorPages/error-pages.scss +8 -0
- package/scss/Components/Forms/SegmentedControl/segmented-control.scss +412 -0
- package/scss/Components/Forms/_form-base.scss +109 -18
- package/scss/Components/Hero/hero.scss +296 -57
- package/scss/Components/MegaMenu/mega-menu.scss +26 -6
- package/scss/Components/OnThisPageNav/on-this-page-nav.scss +3 -1
- package/scss/Components/PageHeader/page-header.scss +13 -28
- package/scss/Components/Pager/pager.scss +3 -1
- package/scss/Components/QuoteHighlight/quote-highlight.scss +6 -1
- package/scss/Components/ScrollContainer/scroll-container.scss +11 -0
- package/scss/Components/SyndicationSearchWidget/syndication-search-widget.scss +51 -24
- package/scss/Components/Tab/tab.scss +1 -1
- package/scss/Components/TextCta/text-cta.scss +11 -3
- package/scss/Patterns/HubHeader/hub-header.scss +14 -3
- package/scss/Utilities/FullWidth/full-width.scss +14 -1
- package/scss/assets/scss/_components.scss +1 -0
- package/scss/assets/scss/_fonts.scss +11 -0
- package/scss/assets/scss/_foundational.scss +7 -0
- package/scss/assets/scss/_mixins.scss +32 -0
- package/scss/assets/scss/_tokens-data-viz.scss +9 -0
- package/scss/assets/scss/_variables.scss +16 -3
- package/scss/assets/scss/generated/_tokens-irp.scss +20 -4
- package/scss/assets/scss/generated/_tokens-mangrove.scss +6 -0
- package/scss/assets/scss/generated/_tokens-preventionweb.scss +20 -4
- package/js/__tests__/copy-button.test.js +0 -112
- package/js/__tests__/show-more.test.js +0 -80
- package/js/__tests__/table-of-contents.test.js +0 -196
- package/scss/Components/SyndicationSearchWidget/SyndicationSearchWidget.scss +0 -11
- package/scss/Components/TableOfContents/TableOfContents.scss +0 -11
- package/scss/Utilities/FullWidth/FullWidth.scss +0 -11
- package/scss/Utilities/ShowMore/ShowMore.scss +0 -11
package/js/switch-pending.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Pending state for .mg-switch: announces progress, ignores presses while a
|
|
2
|
-
// save runs, times out, and reverts on failure.
|
|
2
|
+
// save runs, times out, and reverts on failure. The announcements are also
|
|
3
|
+
// available on their own, as mgSwitchAnnouncer(). See Checkbox.mdx.
|
|
3
4
|
|
|
4
5
|
/** A request that has not settled by then is aborted and reverts. */
|
|
5
6
|
export const PENDING_TIMEOUT_MS = 10000;
|
|
@@ -115,10 +116,47 @@ function resolveStatus(input, option) {
|
|
|
115
116
|
return described || null;
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
// A switch input, from the input itself or a wrapper such as its label. Takes
|
|
120
|
+
// anything, because mgSwitchAnnouncer() is public and a document or a stray
|
|
121
|
+
// value should get the no-op announcer rather than a TypeError.
|
|
118
122
|
function toInput(element) {
|
|
119
|
-
if (!element) return null;
|
|
120
|
-
if (
|
|
121
|
-
|
|
123
|
+
if (!element || typeof element !== 'object') return null;
|
|
124
|
+
if (
|
|
125
|
+
typeof element.matches === 'function' &&
|
|
126
|
+
element.matches(INPUT_SELECTOR)
|
|
127
|
+
) {
|
|
128
|
+
return element;
|
|
129
|
+
}
|
|
130
|
+
return element.querySelector?.(INPUT_SELECTOR) ?? null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// A setting written in HTML, on the input or its label. The input wins, as it
|
|
134
|
+
// does for data-mg-switch-labels; an option passed in JavaScript wins over both.
|
|
135
|
+
function settingAttribute(input, name) {
|
|
136
|
+
const own = input.getAttribute(name);
|
|
137
|
+
if (own !== null) return own;
|
|
138
|
+
return input.closest('label')?.getAttribute(name) ?? null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Milliseconds before a save is abandoned, or Infinity for no deadline.
|
|
143
|
+
* `0` and `Infinity` both disable it; anything unusable falls back to the
|
|
144
|
+
* default, as it did before the option accepted those two.
|
|
145
|
+
*/
|
|
146
|
+
function resolveTimeout(value, input) {
|
|
147
|
+
let setting = value;
|
|
148
|
+
if (setting === undefined || setting === null) {
|
|
149
|
+
const raw = settingAttribute(input, 'data-mg-switch-timeout');
|
|
150
|
+
if (raw !== null && raw.trim() !== '') setting = Number(raw);
|
|
151
|
+
}
|
|
152
|
+
if (setting === 0 || setting === Infinity) return Infinity;
|
|
153
|
+
return Number.isFinite(setting) && setting > 0 ? setting : PENDING_TIMEOUT_MS;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Whether a failed save moves the switch back. */
|
|
157
|
+
function resolveRevert(value, input) {
|
|
158
|
+
if (typeof value === 'boolean') return value;
|
|
159
|
+
return settingAttribute(input, 'data-mg-switch-revert') !== 'false';
|
|
122
160
|
}
|
|
123
161
|
|
|
124
162
|
function cancelWrite(status, owner) {
|
|
@@ -145,24 +183,11 @@ function noResponderError() {
|
|
|
145
183
|
);
|
|
146
184
|
}
|
|
147
185
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (existing) {
|
|
153
|
-
// An explicit call takes over a switch that page-load auto-init enhanced,
|
|
154
|
-
// so its options are not silently ignored.
|
|
155
|
-
if (!existing.auto || auto) return existing.handle;
|
|
156
|
-
existing.handle.destroy();
|
|
157
|
-
}
|
|
158
|
-
const { signal } = options;
|
|
159
|
-
if (signal?.aborted) return noop;
|
|
160
|
-
|
|
186
|
+
// The announcements, on their own: the live region, the label resolution, the
|
|
187
|
+
// re-announce trick and the rate limit, without the save state machine.
|
|
188
|
+
// mgSwitchPending() runs this one, so there is a single implementation.
|
|
189
|
+
function createAnnouncer(input, options) {
|
|
161
190
|
const view = input.ownerDocument.defaultView || window;
|
|
162
|
-
const timeout =
|
|
163
|
-
Number.isFinite(options.timeout) && options.timeout > 0
|
|
164
|
-
? options.timeout
|
|
165
|
-
: PENDING_TIMEOUT_MS;
|
|
166
191
|
const labels = {
|
|
167
192
|
...SWITCH_PENDING_DEFAULT_LABELS,
|
|
168
193
|
...readLabels(input.closest('label')),
|
|
@@ -194,9 +219,7 @@ function enhance(input, options, auto) {
|
|
|
194
219
|
);
|
|
195
220
|
}
|
|
196
221
|
|
|
197
|
-
let current = null;
|
|
198
222
|
let lastNudge = -Infinity;
|
|
199
|
-
let destroyed = false;
|
|
200
223
|
const owner = {};
|
|
201
224
|
|
|
202
225
|
const write = text => {
|
|
@@ -227,23 +250,123 @@ function enhance(input, options, auto) {
|
|
|
227
250
|
status.textContent = text;
|
|
228
251
|
};
|
|
229
252
|
|
|
253
|
+
const say = value => write(formatLabel(value, labelText(input), input));
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
get status() {
|
|
257
|
+
return status;
|
|
258
|
+
},
|
|
259
|
+
get labels() {
|
|
260
|
+
return labels;
|
|
261
|
+
},
|
|
262
|
+
label: () => labelText(input),
|
|
263
|
+
announce: say,
|
|
264
|
+
pending: () => say(labels.saving),
|
|
265
|
+
stillSaving(force = false) {
|
|
266
|
+
const now = Date.now();
|
|
267
|
+
if (!force && now - lastNudge < STILL_SAVING_INTERVAL_MS) return false;
|
|
268
|
+
lastNudge = now;
|
|
269
|
+
say(labels.stillSaving);
|
|
270
|
+
return true;
|
|
271
|
+
},
|
|
272
|
+
settled: checked => say(checked ? labels.on : labels.off),
|
|
273
|
+
failed: () => say(labels.error),
|
|
274
|
+
destroy() {
|
|
275
|
+
cancelWrite(status, owner);
|
|
276
|
+
createdStatus?.remove();
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const NOOP_ANNOUNCER = Object.freeze({
|
|
282
|
+
status: null,
|
|
283
|
+
labels: SWITCH_PENDING_DEFAULT_LABELS,
|
|
284
|
+
label: () => '',
|
|
285
|
+
announce: () => {},
|
|
286
|
+
pending: () => {},
|
|
287
|
+
stillSaving: () => false,
|
|
288
|
+
settled: () => {},
|
|
289
|
+
failed: () => {},
|
|
290
|
+
destroy: () => {},
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* The switch's announcements, without the save state machine: for apps that
|
|
295
|
+
* own the control's position and only want the accessible part.
|
|
296
|
+
*
|
|
297
|
+
* It resolves or creates the live region, resolves the switch's label the way
|
|
298
|
+
* the accessible name is resolved, formats `{label}` and function labels, and
|
|
299
|
+
* re-announces a repeated message. Announcements are skipped for a switch that
|
|
300
|
+
* has left the page, and a region it created is taken off the page with it.
|
|
301
|
+
*
|
|
302
|
+
* @param {HTMLInputElement|Element} element A `.mg-switch__input`, or a
|
|
303
|
+
* wrapper such as its label
|
|
304
|
+
* @param {Object} [options]
|
|
305
|
+
* @param {Element|string} [options.status] Live region, or a selector for one
|
|
306
|
+
* @param {Object} [options.labels] `{ saving, stillSaving, error, on, off }`,
|
|
307
|
+
* merged over `data-mg-switch-labels` and the defaults
|
|
308
|
+
* @returns {{
|
|
309
|
+
* status: Element|null,
|
|
310
|
+
* labels: Object,
|
|
311
|
+
* label: () => string,
|
|
312
|
+
* announce: (text: string|Function) => void,
|
|
313
|
+
* pending: () => void,
|
|
314
|
+
* stillSaving: (force?: boolean) => boolean,
|
|
315
|
+
* settled: (checked: boolean) => void,
|
|
316
|
+
* failed: () => void,
|
|
317
|
+
* destroy: () => void,
|
|
318
|
+
* }}
|
|
319
|
+
*/
|
|
320
|
+
export function mgSwitchAnnouncer(element, options = {}) {
|
|
321
|
+
const input = toInput(element);
|
|
322
|
+
if (!input || typeof input.getAttribute !== 'function') return NOOP_ANNOUNCER;
|
|
323
|
+
return createAnnouncer(input, options || {});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function enhance(input, options, auto) {
|
|
327
|
+
const noop = { destroy() {} };
|
|
328
|
+
if (!input || typeof input.addEventListener !== 'function') return noop;
|
|
329
|
+
const existing = registry.instances.get(input);
|
|
330
|
+
if (existing) {
|
|
331
|
+
// An explicit call takes over a switch that page-load auto-init enhanced,
|
|
332
|
+
// so its options are not silently ignored.
|
|
333
|
+
if (!existing.auto || auto) return existing.handle;
|
|
334
|
+
existing.handle.destroy();
|
|
335
|
+
}
|
|
336
|
+
const { signal } = options;
|
|
337
|
+
if (signal?.aborted) return noop;
|
|
338
|
+
|
|
339
|
+
const view = input.ownerDocument.defaultView || window;
|
|
340
|
+
const timeout = resolveTimeout(options.timeout, input);
|
|
341
|
+
const revert = resolveRevert(options.revert, input);
|
|
342
|
+
const announcer = createAnnouncer(input, options);
|
|
343
|
+
|
|
344
|
+
let current = null;
|
|
345
|
+
let destroyed = false;
|
|
346
|
+
// Only an aria-invalid this helper set is cleared, and whatever the page had
|
|
347
|
+
// there is put back, so one the page authored for its own reasons survives a
|
|
348
|
+
// failed save rather than being overwritten and then removed.
|
|
349
|
+
let flaggedInvalid = false;
|
|
350
|
+
let invalidBefore = null;
|
|
351
|
+
|
|
230
352
|
const emit = (type, detail) =>
|
|
231
353
|
input.dispatchEvent(
|
|
232
354
|
new CustomEvent(type, { bubbles: true, cancelable: false, detail })
|
|
233
355
|
);
|
|
234
356
|
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
357
|
+
const clearInvalid = () => {
|
|
358
|
+
if (!flaggedInvalid) return;
|
|
359
|
+
flaggedInvalid = false;
|
|
360
|
+
if (invalidBefore === null) input.removeAttribute('aria-invalid');
|
|
361
|
+
else input.setAttribute('aria-invalid', invalidBefore);
|
|
362
|
+
invalidBefore = null;
|
|
240
363
|
};
|
|
241
364
|
|
|
242
365
|
const onClick = event => {
|
|
243
366
|
if (!current) return;
|
|
244
367
|
// Cancelling the click keeps checked where it is.
|
|
245
368
|
event.preventDefault();
|
|
246
|
-
stillSaving();
|
|
369
|
+
announcer.stillSaving();
|
|
247
370
|
};
|
|
248
371
|
|
|
249
372
|
const requestSave = (checked, requestSignal) => {
|
|
@@ -295,14 +418,16 @@ function enhance(input, options, auto) {
|
|
|
295
418
|
if (current) {
|
|
296
419
|
// A script changed the switch mid-request: undo it.
|
|
297
420
|
input.checked = !input.checked;
|
|
298
|
-
stillSaving();
|
|
421
|
+
announcer.stillSaving();
|
|
299
422
|
return;
|
|
300
423
|
}
|
|
301
424
|
|
|
302
425
|
const requested = input.checked;
|
|
303
426
|
const request = { controller: new AbortController() };
|
|
304
427
|
current = request;
|
|
305
|
-
|
|
428
|
+
// A new attempt: the switch is saving again, not known to be unsaved.
|
|
429
|
+
clearInvalid();
|
|
430
|
+
announcer.pending();
|
|
306
431
|
// Mark busy a frame later, so the new state is announced first.
|
|
307
432
|
request.frame = view.requestAnimationFrame(() => {
|
|
308
433
|
if (current === request) input.setAttribute('aria-busy', 'true');
|
|
@@ -315,32 +440,51 @@ function enhance(input, options, auto) {
|
|
|
315
440
|
view.clearTimeout(request.timer);
|
|
316
441
|
view.cancelAnimationFrame(request.frame);
|
|
317
442
|
input.setAttribute('aria-busy', 'false');
|
|
318
|
-
const label = labelText(input);
|
|
319
443
|
if (ok) {
|
|
320
444
|
// A form reset or a script may have moved it without a change event.
|
|
321
445
|
input.checked = requested;
|
|
322
|
-
|
|
446
|
+
announcer.settled(requested);
|
|
323
447
|
emit('mg-switch:settled', { checked: requested, ok: true });
|
|
324
448
|
return;
|
|
325
449
|
}
|
|
326
450
|
request.controller.abort(error);
|
|
327
|
-
|
|
328
|
-
|
|
451
|
+
// Without revert the switch keeps what the user asked for, so its
|
|
452
|
+
// position no longer matches what is saved. aria-invalid says so to
|
|
453
|
+
// assistive technology and gives CSS a hook; the page still owns
|
|
454
|
+
// showing the failure and offering a way to try again.
|
|
455
|
+
input.checked = revert ? !requested : requested;
|
|
456
|
+
if (!revert) {
|
|
457
|
+
if (!flaggedInvalid) invalidBefore = input.getAttribute('aria-invalid');
|
|
458
|
+
input.setAttribute('aria-invalid', 'true');
|
|
459
|
+
flaggedInvalid = true;
|
|
460
|
+
}
|
|
461
|
+
announcer.failed();
|
|
329
462
|
emit('mg-switch:failed', {
|
|
330
|
-
checked:
|
|
463
|
+
checked: input.checked,
|
|
331
464
|
requested,
|
|
465
|
+
reverted: revert,
|
|
332
466
|
reason,
|
|
333
467
|
error,
|
|
334
468
|
});
|
|
335
469
|
};
|
|
336
470
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
471
|
+
if (timeout === Infinity) {
|
|
472
|
+
// No deadline: the save owns settling, so aria-busy stays true until it
|
|
473
|
+
// does. Say once, where the deadline would have been, that the save is
|
|
474
|
+
// still running, so a screen reader user is not left on "Saving…" with
|
|
475
|
+
// a control marked busy and no further word.
|
|
476
|
+
request.timer = view.setTimeout(() => {
|
|
477
|
+
if (current === request) announcer.stillSaving(true);
|
|
478
|
+
}, PENDING_TIMEOUT_MS);
|
|
479
|
+
} else {
|
|
480
|
+
request.timer = view.setTimeout(() => {
|
|
481
|
+
const error = new DOMException(
|
|
482
|
+
`Saving the switch took longer than ${timeout}ms.`,
|
|
483
|
+
'TimeoutError'
|
|
484
|
+
);
|
|
485
|
+
settle(false, 'timeout', error);
|
|
486
|
+
}, timeout);
|
|
487
|
+
}
|
|
344
488
|
|
|
345
489
|
emit('mg-switch:pending', { checked: requested });
|
|
346
490
|
// A pending listener may have destroyed the helper.
|
|
@@ -365,7 +509,7 @@ function enhance(input, options, auto) {
|
|
|
365
509
|
input.removeEventListener('click', onClick);
|
|
366
510
|
input.removeEventListener('change', onChange);
|
|
367
511
|
signal?.removeEventListener('abort', onAbort);
|
|
368
|
-
|
|
512
|
+
clearInvalid();
|
|
369
513
|
const request = current;
|
|
370
514
|
current = null;
|
|
371
515
|
if (request) {
|
|
@@ -374,7 +518,7 @@ function enhance(input, options, auto) {
|
|
|
374
518
|
request.controller.abort();
|
|
375
519
|
input.removeAttribute('aria-busy');
|
|
376
520
|
}
|
|
377
|
-
|
|
521
|
+
announcer.destroy();
|
|
378
522
|
if (registry.instances.get(input)?.handle === handle) {
|
|
379
523
|
registry.instances.delete(input);
|
|
380
524
|
input.removeAttribute(ENHANCED_ATTR);
|
|
@@ -400,7 +544,12 @@ function enhance(input, options, auto) {
|
|
|
400
544
|
* Saves the new position; resolving means success. Without it, a cancelable
|
|
401
545
|
* `mg-switch:save` event is dispatched for a listener to answer.
|
|
402
546
|
* @param {Element|string} [options.status] Live region, or a selector for one
|
|
403
|
-
* @param {number} [options.timeout=10000] Milliseconds before a save fails
|
|
547
|
+
* @param {number} [options.timeout=10000] Milliseconds before a save fails.
|
|
548
|
+
* `0` or `Infinity` means no deadline: the save must settle itself, and
|
|
549
|
+
* `aria-busy` stays true until it does.
|
|
550
|
+
* @param {boolean} [options.revert=true] Whether a failed save moves the
|
|
551
|
+
* switch back. With `false` it keeps the requested position and gets
|
|
552
|
+
* `aria-invalid="true"` instead, for apps that own the control's position.
|
|
404
553
|
* @param {Object} [options.labels] `{ saving, stillSaving, error, on, off }`
|
|
405
554
|
* @param {AbortSignal} [options.signal] Aborting it destroys the helper
|
|
406
555
|
* @returns {{ destroy: () => void }}
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@undrr/undrr-mangrove",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Mangrove design System for UNDRR",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
5
|
"files": [
|
|
7
6
|
"components/**/*",
|
|
8
7
|
"css/**/*",
|
|
9
8
|
"js/**/*",
|
|
10
9
|
"scss/**/*.scss",
|
|
11
10
|
"error-pages/**/*",
|
|
12
|
-
"fonts/**/*"
|
|
11
|
+
"fonts/**/*",
|
|
12
|
+
"!**/__tests__/**",
|
|
13
|
+
"!**/__snapshots__/**",
|
|
14
|
+
"!**/__mocks__/**",
|
|
15
|
+
"!**/__fixtures__/**",
|
|
16
|
+
"!**/*.test.*",
|
|
17
|
+
"!**/*.spec.*"
|
|
13
18
|
],
|
|
14
19
|
"repository": {
|
|
15
20
|
"type": "git",
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Full documentation:
|
|
7
7
|
* https://github.com/unisdr/undrr-mangrove/blob/main/stories/Atom/BaseTypography/BaseTypography.mdx
|
|
8
8
|
*/
|
|
9
|
-
.mg-body blockquote
|
|
9
|
+
.mg-body blockquote,
|
|
10
|
+
.mg-content blockquote {
|
|
10
11
|
font-size: var(--mg-font-size-600);
|
|
11
12
|
font-weight: 600;
|
|
12
13
|
line-height: 1.16;
|
|
@@ -144,12 +144,18 @@ figure.mg-code-block {
|
|
|
144
144
|
|
|
145
145
|
// Line numbers — emitted by react-syntax-highlighter when showLineNumbers={true}.
|
|
146
146
|
// Class name is react-syntax-highlighter's API, not a Mangrove BEM class.
|
|
147
|
+
// The gutter colour was neutral-400 (#7e8082), which measures 4.39:1 on the
|
|
148
|
+
// neutral-800 code surface and so failed axe's colour-contrast rule on every
|
|
149
|
+
// number. neutral-300 is the next step up and clears 4.5:1 comfortably; it
|
|
150
|
+
// matches the comment colour, which is the intended de-emphasised tone for
|
|
151
|
+
// this surface anyway. The neutral ramp is defined once in tokens/mangrove.yaml
|
|
152
|
+
// and no theme overrides it, so these ratios hold in every theme.
|
|
147
153
|
.react-syntax-highlighter-line-number {
|
|
148
154
|
display: inline-block;
|
|
149
155
|
min-width: 2.5em;
|
|
150
156
|
padding-right: var(--mg-spacing-100);
|
|
151
157
|
text-align: right;
|
|
152
|
-
color: rgb(var(--mg-color-neutral-
|
|
158
|
+
color: rgb(var(--mg-color-neutral-300)); // #96999c — 6.08:1 on neutral-800
|
|
153
159
|
user-select: none;
|
|
154
160
|
pointer-events: none;
|
|
155
161
|
}
|
|
@@ -165,7 +171,7 @@ figure.mg-code-block {
|
|
|
165
171
|
.token.prolog,
|
|
166
172
|
.token.doctype,
|
|
167
173
|
.token.cdata {
|
|
168
|
-
color: rgb(var(--mg-color-neutral-300)); // #
|
|
174
|
+
color: rgb(var(--mg-color-neutral-300)); // #96999c — 6.08:1 on neutral-800
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
.token.keyword,
|
|
@@ -147,11 +147,26 @@
|
|
|
147
147
|
--mg-author-image-accent: rgb(var(--mg-color-interactive));
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// The accent drives three things: the avatar ring, the focus outline and the
|
|
151
|
+
// title. The Sendai orange is fine as the ring — a band of colour with no copy
|
|
152
|
+
// over it — but it is 2.65 as ink on white, under the 4.5 the title needs, and
|
|
153
|
+
// 2.95 as an outline against white, under the 3.0 a focus indicator needs. So
|
|
154
|
+
// this variant keeps the orange ring and hands those two back to the tokens
|
|
155
|
+
// that are sized for them.
|
|
156
|
+
// See docs/COLOUR-CONTRAST-METHODOLOGY.md#the-orange-accent-carries-no-text
|
|
150
157
|
.mg-author-image--secondary {
|
|
151
158
|
--mg-author-image-accent: rgb(var(--mg-color-secondary));
|
|
152
159
|
--mg-author-image-hover-tint: rgb(var(--mg-color-secondary) / 0.5);
|
|
153
160
|
}
|
|
154
161
|
|
|
162
|
+
.mg-author-image--secondary .mg-author-image__title {
|
|
163
|
+
color: rgb(var(--mg-color-text));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.mg-author-image--secondary .mg-author-image__link:focus-visible {
|
|
167
|
+
outline-color: rgb(var(--mg-color-focus-ring));
|
|
168
|
+
}
|
|
169
|
+
|
|
155
170
|
.mg-author-image--tertiary {
|
|
156
171
|
--mg-author-image-accent: rgb(var(--mg-color-tertiary));
|
|
157
172
|
--mg-author-image-hover-tint: rgb(var(--mg-color-tertiary) / 0.5);
|
|
@@ -188,7 +203,7 @@
|
|
|
188
203
|
|
|
189
204
|
.mg-author-image--horizontal .mg-author-image__content {
|
|
190
205
|
align-content: center;
|
|
191
|
-
text-align:
|
|
206
|
+
text-align: start;
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
.mg-author-image--vertical .mg-author-image__meta {
|