@aurodesignsystem-dev/auro-toast 0.0.0-pr147.13 → 0.0.0-pr147.15

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/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "================================================================================"
8
8
  ],
9
9
  "name": "@aurodesignsystem-dev/auro-toast",
10
- "version": "0.0.0-pr147.13",
10
+ "version": "0.0.0-pr147.15",
11
11
  "description": "auro-toast HTML custom element",
12
12
  "repository": {
13
13
  "type": "git",
@@ -84,6 +84,7 @@
84
84
  "files": [
85
85
  "dist/**/*",
86
86
  "demo/**/*",
87
+ "src/**/*",
87
88
  "custom-elements.json",
88
89
  "CHANGELOG.md",
89
90
  "README.md",
@@ -0,0 +1,485 @@
1
+ // Copyright (c) 2023 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ /* eslint-disable lit/binding-positions, lit/no-invalid-html, max-lines */
7
+ import { LitElement } from "lit";
8
+ import { html } from "lit/static-html.js";
9
+
10
+ import { AuroDependencyVersioning } from "@aurodesignsystem/auro-library/scripts/runtime/dependencyTagVersioning.mjs";
11
+ import AuroLibraryRuntimeUtils from "@aurodesignsystem/auro-library/scripts/utils/runtimeUtils.mjs";
12
+ import { AuroButton } from "@aurodesignsystem/auro-button/class";
13
+ import { AuroIcon } from "@aurodesignsystem/auro-icon/class";
14
+
15
+ // Icons
16
+ import errorIcon from "@alaskaairux/icons/dist/icons/alert/error-stroke.mjs";
17
+ import infoIcon from "@alaskaairux/icons/dist/icons/alert/information-stroke.mjs";
18
+ import successIcon from "@alaskaairux/icons/dist/icons/interface/check-stroke.mjs";
19
+ import closeIcon from "@alaskaairux/icons/dist/icons/interface/x-lg.mjs";
20
+
21
+ import buttonVersion from "./buttonVersion.js";
22
+ import iconVersion from "./iconVersion.js";
23
+
24
+ import colorCss from "./styles/color.scss";
25
+ import styleCss from "./styles/style.scss";
26
+ import tokensCss from "./styles/tokens.scss";
27
+
28
+ const DEFAULT_TIME_TIL_FADE_OUT = 5000;
29
+ const FADE_OUT_DURATION = 300;
30
+
31
+ // See https://git.io/JJ6SJ for "How to document your components using JSDoc"
32
+ /**
33
+ * The `auro-toast` element provides users a way to display short, temporary messages.
34
+ * @customElement auro-toast
35
+ *
36
+ * @csspart type-icon - Apply css to the toast type icon
37
+ * @csspart close-button - Apply css to the toast close button
38
+ * @fires onToastClose - **Deprecated**, use `toast-close` event instead.
39
+ * @event toast-close - Notifies that the toast has been closed
40
+ */
41
+
42
+ // build the component class
43
+ export class AuroToast extends LitElement {
44
+ constructor() {
45
+ super();
46
+
47
+ this._initializeDefaults();
48
+ }
49
+
50
+ _initializeDefaults() {
51
+ /**
52
+ * @private
53
+ */
54
+ this.closeDom = new DOMParser().parseFromString(closeIcon.svg, "text/html");
55
+
56
+ /**
57
+ * @private
58
+ */
59
+ this.closeSvg = this.closeDom.body.firstChild;
60
+ this.closeSvg.setAttribute("slot", "svg");
61
+
62
+ /**
63
+ * @private
64
+ */
65
+ this.successDom = new DOMParser().parseFromString(
66
+ successIcon.svg,
67
+ "text/html",
68
+ );
69
+
70
+ /**
71
+ * @private
72
+ */
73
+ this.successSvg = this.successDom.body.firstChild;
74
+
75
+ this.successSvg.setAttribute("slot", "svg");
76
+
77
+ /**
78
+ * @private
79
+ */
80
+ this.errorDom = new DOMParser().parseFromString(errorIcon.svg, "text/html");
81
+
82
+ /**
83
+ * @private
84
+ */
85
+ this.errorSvg = this.errorDom.body.firstChild;
86
+ this.errorSvg.setAttribute("slot", "svg");
87
+
88
+ /**
89
+ * @private
90
+ */
91
+ this.infoDom = new DOMParser().parseFromString(infoIcon.svg, "text/html");
92
+
93
+ /**
94
+ * @private
95
+ */
96
+ this.infoSvg = this.infoDom.body.firstChild;
97
+ this.infoSvg.setAttribute("slot", "svg");
98
+
99
+ const versioning = new AuroDependencyVersioning();
100
+
101
+ /**
102
+ * @private
103
+ */
104
+ this.buttonTag = versioning.generateTag(
105
+ "auro-button",
106
+ buttonVersion,
107
+ AuroButton,
108
+ );
109
+
110
+ /**
111
+ * @private
112
+ */
113
+ this.iconTag = versioning.generateTag("auro-icon", iconVersion, AuroIcon);
114
+
115
+ /**
116
+ * @private
117
+ */
118
+ this.runtimeUtils = new AuroLibraryRuntimeUtils();
119
+
120
+ /**
121
+ * @private
122
+ */
123
+ this.fadeOutTimer = undefined;
124
+
125
+ /**
126
+ * True when the toast is not inside an auro-toaster and must manage its
127
+ * own live region announcement. Set once in connectedCallback.
128
+ * Default -- assumes toast is inside toaster.
129
+ * @private
130
+ */
131
+ this._isStandalone = false;
132
+ }
133
+
134
+ // This function is to define props used within the scope of this component
135
+ // Be sure to review https://lit.dev/docs/components/properties/
136
+ // to understand how to use reflected attributes with your property settings.
137
+ static get properties() {
138
+ return {
139
+ ...LitElement.properties,
140
+
141
+ /**
142
+ * Prevents the toast from auto-hiding on the default time.
143
+ */
144
+ disableAutoHide: {
145
+ type: Boolean,
146
+ reflect: true,
147
+ attribute: "disableautohide",
148
+ },
149
+
150
+ /**
151
+ * Removes icon from the toast UI.
152
+ */
153
+ noIcon: {
154
+ type: Boolean,
155
+ reflect: true,
156
+ attribute: "noicon",
157
+ },
158
+
159
+ /**
160
+ * Sets the time in milliseconds until the toast hides.
161
+ */
162
+ timeTilHide: {
163
+ type: Number,
164
+ reflect: true,
165
+ attribute: "timetilhide",
166
+ },
167
+
168
+ /**
169
+ * The id of the element that triggered the toast.
170
+ * When the toast is manually closed, focus will return to this element.
171
+ * Takes precedence over the triggerElement property if both are set.
172
+ */
173
+ trigger: {
174
+ type: String,
175
+ reflect: true,
176
+ },
177
+
178
+ /**
179
+ * A direct reference to the element that triggered the toast.
180
+ * When the toast is manually closed, focus will return to this element.
181
+ * Use the trigger attribute instead if you prefer a declarative approach.
182
+ * @type {HTMLElement}
183
+ */
184
+ triggerElement: {
185
+ type: Object,
186
+ attribute: false,
187
+ },
188
+
189
+ /**
190
+ * Component will render visually based on which variant value is set.
191
+ * @type {'error' | 'success' | 'custom'}
192
+ */
193
+ variant: {
194
+ type: String,
195
+ reflect: true,
196
+ },
197
+
198
+ /**
199
+ * Sets state of toast to visible
200
+ */
201
+ visible: {
202
+ type: Boolean,
203
+ reflect: true,
204
+ }
205
+ };
206
+ }
207
+
208
+ static get styles() {
209
+ return [styleCss, colorCss, tokensCss];
210
+ }
211
+
212
+ /**
213
+ * This will register this element with the browser.
214
+ * @param {string} [name="auro-toast"] - The name of the element that you want to register.
215
+ *
216
+ * @example
217
+ * AuroToast.register("custom-toast") // this will register this element to <custom-toast/>
218
+ *
219
+ */
220
+ static register(name = "auro-toast") {
221
+ AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroToast);
222
+ }
223
+
224
+ firstUpdated() {
225
+ // Add the tag name as an attribute if it is different than the component name
226
+ this.runtimeUtils.handleComponentTagRename(this, "auro-toast");
227
+ }
228
+
229
+ /**
230
+ * Returns focus to the trigger element when the toast is manually closed.
231
+ * Not called on auto-dismiss — moving focus during auto-dismiss would
232
+ * interrupt the AT user's current position in the page.
233
+ * @private
234
+ * @returns {void}
235
+ */
236
+ _returnFocus() {
237
+ const target = (this.trigger ? document.getElementById(this.trigger) : null) ??
238
+ this.triggerElement;
239
+
240
+ if (target) {
241
+ target.focus();
242
+ }
243
+ }
244
+
245
+ /**
246
+ * @private
247
+ * @returns {void}
248
+ */
249
+ clickToClose() {
250
+ this._returnFocus();
251
+ this.closeToast();
252
+ clearTimeout(this.fadeOutTimer);
253
+ }
254
+
255
+ /**
256
+ * @private
257
+ * @returns {void}
258
+ */
259
+ fadeOutToast() {
260
+ if (!this.disableAutoHide) {
261
+ const toastContainer = this.shadowRoot.querySelector(".toastContainer");
262
+ if (toastContainer) {
263
+ toastContainer.classList.add("hidden");
264
+ }
265
+
266
+ setTimeout(() => {
267
+ this.closeToast();
268
+ }, FADE_OUT_DURATION);
269
+ }
270
+ }
271
+
272
+ /**
273
+ * @private
274
+ * @returns {void}
275
+ */
276
+ closeToast() {
277
+ clearTimeout(this.fadeOutTimer);
278
+ this.visible = false;
279
+
280
+ /**
281
+ * Emits closed toast event.
282
+ *
283
+ * @deprecated Use `toast-close` event instead.
284
+ * @event onToastClose
285
+ * @type {Object}
286
+ */
287
+ this.dispatchEvent(
288
+ new CustomEvent("onToastClose", {
289
+ bubbles: true,
290
+ composed: true,
291
+ detail: this, // unchanged for backwards compatibility; use `toast-close` for the new `{ visible }` shape
292
+ }),
293
+ );
294
+
295
+ /**
296
+ * Emits closed toast event.
297
+ *
298
+ * @event toast-close
299
+ * @type {{ visible: boolean }}
300
+ */
301
+ this.dispatchEvent(
302
+ new CustomEvent("toast-close", {
303
+ bubbles: true,
304
+ composed: true,
305
+ detail: { visible: false },
306
+ }),
307
+ );
308
+ }
309
+
310
+ /**
311
+ * For mobile, set the onclick function so the toast can be dismissed if it is tapped on anywhere inside the toast.
312
+ * @private
313
+ * @returns {void}
314
+ */
315
+ setOnClick() {
316
+ const mobileBreakPoint = 767;
317
+ if (window.innerWidth < mobileBreakPoint) {
318
+ this.onclick = () => {
319
+ this.fadeOutToast();
320
+ };
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Determines which type icon to render based on the variant prop.
326
+ * @private
327
+ * @returns {HTMLElement} - The icon element to render.
328
+ */
329
+ getVariantIcon() {
330
+ const VARIANT_ICONS = {
331
+ success: this.successSvg,
332
+ error: this.errorSvg,
333
+ default: this.infoSvg,
334
+ };
335
+
336
+ return VARIANT_ICONS[this.variant] || VARIANT_ICONS.default;
337
+ }
338
+
339
+ connectedCallback() {
340
+ super.connectedCallback();
341
+ this.setOnClick();
342
+
343
+ // Dispatch a cancelable event so auro-toaster can signal it will handle
344
+ // announcements. If nothing cancels the event the toast is standalone and
345
+ // must register its own live region on the host element — before
346
+ // any visibility change — so the AT has already observed it as a live
347
+ // region by the time content is rendered into the shadow DOM.
348
+ const event = new CustomEvent('toast-request-announce', {
349
+ bubbles: true,
350
+ cancelable: true,
351
+ composed: true,
352
+ });
353
+
354
+ // NOTE — reverse logic:
355
+ // dispatchEvent() returns TRUE when nobody called preventDefault(), which
356
+ // means no auro-toaster was listening — the toast is standalone and must
357
+ // own its live region. It returns FALSE when a toaster cancelled the event,
358
+ // signalling that the toaster's aria-live region will handle announcements.
359
+ const eventNotPrevented = this.dispatchEvent(event);
360
+
361
+ // Secondary check: even if no toaster answered the event, the toast may
362
+ // be inside another element that already owns a live region (e.g. a plain
363
+ // div[aria-live="polite"]). Setting a role on the host in that case would
364
+ // create a nested live region. aria-live="off" is intentionally excluded
365
+ // — it disables live region behavior and is not an active announcer.
366
+ this._isStandalone = eventNotPrevented && !this._hasAncestorLiveRegion();
367
+
368
+ this._syncStandaloneRole();
369
+ }
370
+
371
+ /**
372
+ * Sets or removes the live-region role on the host depending on whether
373
+ * the toast is standalone. Extracted so connectedCallback and updated()
374
+ * stay in sync without duplicating the logic.
375
+ * @private
376
+ * @returns {void}
377
+ */
378
+ _syncStandaloneRole() {
379
+ if (this._isStandalone) {
380
+ this.setAttribute('role', this.variant === 'error' ? 'alert' : 'status');
381
+ } else {
382
+ this.removeAttribute('role');
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Walks the DOM ancestors (crossing shadow boundaries) looking for any
388
+ * active live region — either an aria-live="polite/assertive" attribute or
389
+ * an implicit live region role (alert, status, log).
390
+ * aria-live="off" is not considered active and is intentionally ignored.
391
+ * @private
392
+ * @returns {boolean}
393
+ */
394
+ _hasAncestorLiveRegion() {
395
+ let node = this.parentElement;
396
+ while (node) {
397
+ if (
398
+ ['polite', 'assertive'].includes(node.getAttribute?.('aria-live')) ||
399
+ ['alert', 'status', 'log'].includes(node.getAttribute?.('role'))
400
+ ) {
401
+ return true;
402
+ }
403
+ // Traverse up, crossing shadow DOM boundaries if needed
404
+ node = node.parentElement ?? node.getRootNode()?.host ?? null;
405
+ }
406
+ return false;
407
+ }
408
+
409
+ updated(changedProperties) {
410
+ if (changedProperties.has("visible")) {
411
+ this.handleSlotContent();
412
+ }
413
+
414
+ // Keep the standalone role in sync if variant changes after connection.
415
+ if (changedProperties.has("variant")) {
416
+ clearTimeout(this.fadeOutTimer);
417
+ this._syncStandaloneRole();
418
+ }
419
+
420
+ // do not auto dismiss for error toasts or if disableAutoHide is set
421
+ if (this.visible && !this.disableAutoHide && this.variant !== "error") {
422
+ clearTimeout(this.fadeOutTimer);
423
+ this.fadeOutTimer = setTimeout(() => {
424
+ this.fadeOutToast();
425
+ }, this.timeTilHide || DEFAULT_TIME_TIL_FADE_OUT);
426
+ }
427
+ }
428
+
429
+ /**
430
+ * Mirrors any defined custom type svg into the correct place in the template.
431
+ * @private
432
+ * @returns {void}
433
+ */
434
+ handleSlotContent() {
435
+ try {
436
+ const customSvg = this.querySelector(`[slot="customSvg"]`);
437
+
438
+ if (customSvg) {
439
+ const iconSvg = customSvg.cloneNode(true);
440
+ const typeIcon = this.shadowRoot.querySelector(".typeIcon");
441
+
442
+ if (typeIcon) {
443
+ iconSvg.setAttribute("slot", "svg");
444
+ typeIcon.appendChild(iconSvg);
445
+ }
446
+ }
447
+ } catch (error) {
448
+ console.error("handleSlotContent", error); // eslint-disable-line no-console
449
+ }
450
+ }
451
+
452
+ render() {
453
+ return html`
454
+ ${this.visible
455
+ ? html`
456
+ <div class="toastContainer">
457
+ ${this.noIcon
458
+ ? undefined
459
+ : html`
460
+ <${this.iconTag} customColor customSvg class="typeIcon body-default" part="type-icon">
461
+ ${this.variant === "custom" ? undefined : html`${this.getVariantIcon()}`}
462
+ </${this.iconTag}>
463
+ `
464
+ }
465
+ <div class="message body-default"><slot></slot></div>
466
+ <${this.buttonTag}
467
+ variant="flat"
468
+ shape="circle"
469
+ size="xs"
470
+ appearance=${this.variant !== "error" && this.variant !== "success" ? "inverse" : this.appearance}
471
+ @click="${this.clickToClose}"
472
+ part="close-button"
473
+ class="closeButton">
474
+ <${this.iconTag} customColor customSvg>
475
+ ${this.closeSvg}
476
+ </${this.iconTag}>
477
+ <span slot="ariaLabel">Close this notification.</span>
478
+ </${this.buttonTag}>
479
+ </div>
480
+ `
481
+ : undefined
482
+ }
483
+ `;
484
+ }
485
+ }
@@ -0,0 +1,175 @@
1
+ // Copyright (c) 2023 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ import { html, LitElement } from "lit";
7
+ import AuroLibraryRuntimeUtils from "@aurodesignsystem/auro-library/scripts/utils/runtimeUtils.mjs";
8
+ import styleCss from "./styles/style-toaster.scss";
9
+
10
+ export class AuroToaster extends LitElement {
11
+ static get styles() {
12
+ return [styleCss];
13
+ }
14
+
15
+ constructor() {
16
+ super();
17
+ // Initialised in the constructor so they survive disconnect/reconnect.
18
+ // If these were in connectedCallback, a reconnected toaster would forget
19
+ // which error toasts it had already announced and could re-announce them.
20
+ this._assertiveResetTimer = undefined;
21
+ this._announcedErrorToasts = new WeakSet();
22
+
23
+ // Cancel the standalone live region request from any child toast — the
24
+ // toaster's own aria-live region handles all announcements.
25
+ // Calling preventDefault() causes dispatchEvent() on the toast to return
26
+ // false, which the toast reads as "a toaster is present — do not set a
27
+ // standalone live region role on the host element."
28
+ this._onToastRequestAnnounce = (e) => e.preventDefault();
29
+ }
30
+
31
+ /**
32
+ * This will register this element with the browser.
33
+ * @param {string} [name="auro-toaster"] - The name of the element that you want to register to.
34
+ *
35
+ * @example
36
+ * AuroToaster.register("custom-toaster") // this will register this element to <custom-toaster/>
37
+ *
38
+ */
39
+ static register(name = "auro-toaster") {
40
+ AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroToaster);
41
+ }
42
+
43
+ connectedCallback() {
44
+ super.connectedCallback();
45
+ this.addEventListener('toast-request-announce', this._onToastRequestAnnounce);
46
+
47
+ /**
48
+ * @private
49
+ *
50
+ * Observes toast attribute changes to determine when we should temporarily
51
+ * switch the live region from "polite" → "assertive".
52
+ *
53
+ * Supported trigger paths:
54
+ * 1. Normal path:
55
+ * - A toast becomes visible
56
+ * - AND it is already an error toast
57
+ * 2. Defensive fallback (unsupported but possible misuse):
58
+ * - A visible toast has its variant changed to "error"
59
+ *
60
+ * Note:
61
+ * Toasts are not intended to mutate while visible. This fallback exists
62
+ * only to preserve accessibility behavior if that contract is violated.
63
+ */
64
+ this._observer = new MutationObserver((mutations) => {
65
+ for (const mutation of mutations) {
66
+ const target = mutation.target;
67
+
68
+ // Only react to auro-toast elements (including versioned tags like
69
+ // auro-toast_1_2_3). Explicitly ignore auro-toaster itself.
70
+ if (!/^auro-toast(_|$)/u.test(target.localName ?? '')) continue;
71
+
72
+ const isVisible = target.hasAttribute?.('visible');
73
+ const isError = target.getAttribute?.('variant') === 'error';
74
+
75
+ // ---------------------------------------------------------------------
76
+ // Case 1: supported behavior
77
+ // A toast becomes visible AND is already an error toast
78
+ // ---------------------------------------------------------------------
79
+ const becameVisible =
80
+ mutation.attributeName === 'visible' &&
81
+ isVisible &&
82
+ isError;
83
+
84
+ // ---------------------------------------------------------------------
85
+ // Case 2: defensive fallback
86
+ // A toast is already visible and its variant is changed to "error"
87
+ // (unsupported usage pattern, but we handle it safely for a11y)
88
+ // ---------------------------------------------------------------------
89
+ const becameErrorWhileVisible =
90
+ mutation.attributeName === 'variant' &&
91
+ mutation.oldValue !== 'error' &&
92
+ isVisible &&
93
+ isError;
94
+
95
+ if (becameVisible || becameErrorWhileVisible) {
96
+ this._setAssertiveTemporarily();
97
+ }
98
+ }
99
+ });
100
+
101
+ this._observer.observe(this, {
102
+ subtree: true,
103
+
104
+ // REQUIRED: without this, attribute changes will not trigger the observer
105
+ attributes: true,
106
+
107
+ // We only care about these two attributes for performance and clarity
108
+ attributeFilter: ['visible', 'variant'],
109
+
110
+ // REQUIRED for detecting transitions (e.g. non-error → error)
111
+ attributeOldValue: true,
112
+ });
113
+ }
114
+
115
+ disconnectedCallback() {
116
+ super.disconnectedCallback();
117
+ this._observer?.disconnect();
118
+ clearTimeout(this._assertiveResetTimer);
119
+ this.removeEventListener('toast-request-announce', this._onToastRequestAnnounce);
120
+
121
+ // Reset the live region to polite so a reconnected toaster does not
122
+ // inherit a stale assertive state left behind by a cleared timer.
123
+ const liveRegion = this.shadowRoot?.querySelector('[aria-live]');
124
+ if (liveRegion) {
125
+ liveRegion.setAttribute('aria-live', 'polite');
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Temporarily sets the live region to assertive so the error toast
131
+ * interrupts the screen reader, then resets to polite after 3 seconds.
132
+ * This ensures subsequent polite toasts don't keep interrupting the user,
133
+ * even if the error toast remains visible (errors are never auto-dismissed).
134
+ * @private
135
+ */
136
+ _setAssertiveTemporarily() {
137
+ const liveRegion = this.shadowRoot?.querySelector('[aria-live]');
138
+ if (!liveRegion) return;
139
+
140
+ clearTimeout(this._assertiveResetTimer);
141
+ liveRegion.setAttribute('aria-live', 'assertive');
142
+
143
+ this._assertiveResetTimer = setTimeout(() => {
144
+ liveRegion.setAttribute('aria-live', 'polite');
145
+ }, 3000);
146
+ }
147
+
148
+ render() {
149
+ return html`
150
+ <div class="toaster-wrapper" aria-live="polite" aria-atomic="false">
151
+ <slot @slotchange="${this._onSlotChange}"></slot>
152
+ </div>
153
+ `;
154
+ }
155
+
156
+ /**
157
+ * Handles slot changes — checks if a newly slotted error toast
158
+ * is already visible at the time it is added to the toaster.
159
+ * @private
160
+ */
161
+ _onSlotChange(e) {
162
+ const newErrorToast = e.target.assignedElements({ flatten: true })
163
+ .find(el =>
164
+ /^auro-toast(_|$)/u.test(el.localName ?? '') &&
165
+ el.getAttribute('variant') === 'error' &&
166
+ el.hasAttribute('visible') &&
167
+ !this._announcedErrorToasts.has(el)
168
+ );
169
+
170
+ if (newErrorToast) {
171
+ this._announcedErrorToasts.add(newErrorToast);
172
+ this._setAssertiveTemporarily();
173
+ }
174
+ }
175
+ }
@@ -0,0 +1 @@
1
+ export default "12.3.2";
@@ -0,0 +1 @@
1
+ export default "9.2.0";
package/src/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { AuroToast } from "./auro-toast.js";
2
+ import { AuroToaster } from "./auro-toaster.js";
3
+
4
+ export { AuroToast, AuroToaster };
@@ -0,0 +1,5 @@
1
+ import { AuroToast } from "./auro-toast.js";
2
+ import { AuroToaster } from "./auro-toaster.js";
3
+
4
+ AuroToast.register();
5
+ AuroToaster.register();
@@ -0,0 +1,34 @@
1
+ // Copyright (c) 2023 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ // Import Auro tokens
7
+ @use "@aurodesignsystem/design-tokens/dist/themes/alaska/SCSSVariables--alaska" as v;
8
+
9
+ :host([visible]) {
10
+ background-color: var(--ds-auro-toast-container-color);
11
+ color: var(--ds-auro-toast-text-color);
12
+
13
+ .typeIcon {
14
+ color: var(--ds-auro-toast-icon-color);
15
+ }
16
+
17
+ .closeButton {
18
+ &:hover {
19
+ background-color: var(--ds-auro-toast-close-button-hover-container-color);
20
+ }
21
+ }
22
+ }
23
+
24
+ :host([variant='error']) {
25
+ --ds-auro-toast-container-color: var(--ds-basic-color-status-error-subtle, #{v.$ds-basic-color-status-error-subtle});
26
+ --ds-auro-toast-icon-color: var(--ds-basic-color-status-error, #{v.$ds-basic-color-status-error});
27
+ --ds-auro-toast-text-color: var(--ds-basic-color-texticon-default, #{v.$ds-basic-color-texticon-default});
28
+ }
29
+
30
+ :host([variant='success']) {
31
+ --ds-auro-toast-container-color: var(--ds-basic-color-status-success-subtle, #{v.$ds-basic-color-status-success-subtle});
32
+ --ds-auro-toast-icon-color: var(--ds-basic-color-status-success, #{v.$ds-basic-color-status-success});
33
+ --ds-auro-toast-text-color: var(--ds-basic-color-texticon-default, #{v.$ds-basic-color-texticon-default});
34
+ }
@@ -0,0 +1,27 @@
1
+ // Copyright (c) 2023 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ // Import Auro tokens
7
+ @use "@aurodesignsystem/design-tokens/dist/legacy/auro-classic/SCSSVariables" as vac;
8
+
9
+ // container styles - defines the look of the outer custom component
10
+ .toaster-wrapper {
11
+ position: fixed;
12
+ z-index: var(--ds-depth-modal, vac.$ds-depth-modal);
13
+ right: 2%;
14
+ bottom: 2%;
15
+ left: 2%;
16
+ display: flex;
17
+ flex-direction: column-reverse;
18
+ align-items: flex-end;
19
+ gap: var(--ds-size-200, vac.$ds-size-200);
20
+ pointer-events: none;
21
+
22
+ @media (width >= #{vac.$ds-grid-breakpoint-lg}) {
23
+ right: 1%;
24
+ left: unset;
25
+ width: 100%;
26
+ }
27
+ }
@@ -0,0 +1,61 @@
1
+ // Copyright (c) 2023 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
2
+ // See LICENSE in the project root for license information.
3
+
4
+ // ---------------------------------------------------------------------
5
+
6
+ // Import Auro tokens
7
+ @use "@aurodesignsystem/design-tokens/dist/legacy/auro-classic/SCSSVariables" as vac;
8
+
9
+ @use '@aurodesignsystem/webcorestylesheets/dist/bundled/type/classes.alaska.min.css';
10
+
11
+ // display: inherit keeps the host in the accessibility tree when not visible.
12
+ // display: none removes it entirely from the accessibility tree —
13
+ //
14
+ // This is used to prevent visual artifacts from toasts that remain in the DOM
15
+ // after hiding.
16
+ :host {
17
+ display: inherit;
18
+ }
19
+
20
+ :host([visible]) {
21
+ display: inline-block;
22
+ min-width: 100%;
23
+ border-radius: var(--ds-size-100, vac.$ds-size-100);
24
+ box-shadow: var(--ds-elevation-200, vac.$ds-elevation-200);
25
+ pointer-events: auto;
26
+
27
+ // Phones (< sm) keep the full-width sizing from the base rule above.
28
+ // From the sm breakpoint up, use fixed pixel bounds so the toast is sized
29
+ // consistently across tablet and desktop widths instead of shrinking to a
30
+ // small fraction of the available space.
31
+ @media (width >= #{vac.$ds-grid-breakpoint-sm}) {
32
+ min-width: 200px;
33
+ max-width: 500px;
34
+ }
35
+
36
+ .toastContainer {
37
+ display: flex;
38
+ flex-direction: row;
39
+ align-items: flex-start;
40
+ padding: var(--ds-size-200, vac.$ds-size-200) var(--ds-size-150, vac.$ds-size-150);
41
+ gap: var(--ds-size-200, vac.$ds-size-200);
42
+ }
43
+
44
+ .hidden {
45
+ opacity: 0;
46
+ transition: visibility 0s 300ms, opacity 300ms ease-out;
47
+ visibility: hidden;
48
+ }
49
+
50
+ [auro-icon] {
51
+ --ds-auro-icon-size: var(--ds-size-300, #{vac.$ds-size-300});
52
+ }
53
+
54
+ .message {
55
+ flex: 1;
56
+ }
57
+
58
+ .closeButton {
59
+ border-radius: 50%;
60
+ }
61
+ }
@@ -0,0 +1,8 @@
1
+ @use "@aurodesignsystem/design-tokens/dist/themes/alaska/SCSSVariables--alaska" as v;
2
+
3
+ :host {
4
+ --ds-auro-toast-close-button-hover-container-color: var(--ds-advanced-color-button-tertiary-background-hover, #{v.$ds-advanced-color-button-tertiary-background-hover});
5
+ --ds-auro-toast-container-color: var(--ds-advanced-color-shared-background-strong, #{v.$ds-advanced-color-shared-background-strong});
6
+ --ds-auro-toast-icon-color: var(--ds-basic-color-texticon-inverse, #{v.$ds-basic-color-texticon-inverse});
7
+ --ds-auro-toast-text-color: var(--ds-basic-color-texticon-inverse, #{v.$ds-basic-color-texticon-inverse});
8
+ }