mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 00:37:19 +00:00
* Fix snackbar defaults. Fixes #205. * Undo copy settings across. * Oops * Fixing stupid minification bug * Something weird happened with the last commit
98 lines
2.6 KiB
TypeScript
98 lines
2.6 KiB
TypeScript
import * as style from './styles.css';
|
|
|
|
export interface SnackOptions {
|
|
timeout?: number;
|
|
actions?: string[];
|
|
}
|
|
|
|
function createSnack(message: string, options: SnackOptions): [Element, Promise<string>] {
|
|
const {
|
|
timeout = 0,
|
|
actions = [],
|
|
} = options;
|
|
|
|
// Provide a default 'dismiss' action
|
|
if (!timeout && actions.length === 0) actions.push('dismiss');
|
|
|
|
const el = document.createElement('div');
|
|
el.className = style.snackbar;
|
|
el.setAttribute('aria-live', 'assertive');
|
|
el.setAttribute('aria-atomic', 'true');
|
|
el.setAttribute('aria-hidden', 'false');
|
|
|
|
const text = document.createElement('div');
|
|
text.className = style.text;
|
|
text.textContent = message;
|
|
el.appendChild(text);
|
|
|
|
const result = new Promise<string>((resolve) => {
|
|
let timeoutId: number;
|
|
|
|
// Add action buttons
|
|
for (const action of actions) {
|
|
const button = document.createElement('button');
|
|
button.className = style.button;
|
|
button.textContent = action;
|
|
button.addEventListener('click', () => {
|
|
clearTimeout(timeoutId);
|
|
resolve(action);
|
|
});
|
|
el.appendChild(button);
|
|
}
|
|
|
|
// Add timeout
|
|
if (timeout) {
|
|
timeoutId = self.setTimeout(
|
|
() => resolve(''),
|
|
timeout,
|
|
);
|
|
}
|
|
});
|
|
|
|
return [el, result];
|
|
}
|
|
|
|
export default class SnackBarElement extends HTMLElement {
|
|
private _snackbars: [string, SnackOptions, (action: Promise<string>) => void][] = [];
|
|
private _processingQueue = false;
|
|
|
|
/**
|
|
* Show a snackbar. Returns a promise for the name of the action clicked, or an empty string if no
|
|
* action is clicked.
|
|
*/
|
|
showSnackbar(message: string, options: SnackOptions = {}): Promise<string> {
|
|
return new Promise<string>((resolve) => {
|
|
this._snackbars.push([message, options, resolve]);
|
|
if (!this._processingQueue) this._processQueue();
|
|
});
|
|
}
|
|
|
|
private async _processQueue() {
|
|
this._processingQueue = true;
|
|
|
|
while (this._snackbars[0]) {
|
|
const [message, options, resolver] = this._snackbars[0];
|
|
const [el, result] = createSnack(message, options);
|
|
// Pass the result back to the original showSnackbar call.
|
|
resolver(result);
|
|
this.appendChild(el);
|
|
|
|
// Wait for the user to click an action, or for the snack to timeout.
|
|
await result;
|
|
|
|
// Transition the snack away.
|
|
el.setAttribute('aria-hidden', 'true');
|
|
await new Promise((resolve) => {
|
|
el.addEventListener('animationend', () => resolve());
|
|
});
|
|
el.remove();
|
|
|
|
this._snackbars.shift();
|
|
}
|
|
|
|
this._processingQueue = false;
|
|
}
|
|
}
|
|
|
|
customElements.define('snack-bar', SnackBarElement);
|