@agnos-ui/core
Version:
Framework-agnostic headless component library.
189 lines (188 loc) • 5.49 kB
JavaScript
import { computed, readable, writable } from "@amadeus-it-group/tansu";
import { extendWidgetProps } from "./services/extendWidget.js";
import { o as directiveSubscribe, g as createAttributesDirective } from "./dom-Bb5ZCr_a.js";
import { true$ } from "./utils/stores.js";
import { h as typeNumberInRangeFactory, b as typeBoolean } from "./writables-DYGjj5T3.js";
import { g as getCommonAlertDefaultConfig, c as createCommonAlert } from "./common-DFyZvkII.js";
import { createWidgetFactory } from "./utils/widget.js";
const toastDefaultConfig = {
autoHide: true,
delay: 5e3
};
const toastConfigValidator = {
autoHide: typeBoolean,
delay: typeNumberInRangeFactory(0, Infinity, { strict: true })
};
function getToastDefaultConfig() {
return { ...getCommonAlertDefaultConfig(), ...toastDefaultConfig };
}
const createToast = createWidgetFactory("toast", (config) => {
let _timeout;
const extendedAlert = extendWidgetProps(
createCommonAlert,
toastDefaultConfig,
toastConfigValidator
)(config);
const time$ = computed(() => {
clearTimeout(_timeout);
if (extendedAlert.stores.autoHide$()) {
_timeout = setTimeout(() => extendedAlert.api.close(), extendedAlert.stores.delay$());
}
});
const bodyDirective = createAttributesDirective(() => ({
attributes: {
role: readable("alert"),
"aria-atomic": readable("true"),
class: computed(() => extendedAlert.stores.className$())
},
classNames: {
"au-toast": true$,
toast: true$
}
}));
const closeButtonDirective = createAttributesDirective(() => ({
attributes: {
type: readable("button"),
"aria-label": computed(() => extendedAlert.stores.ariaCloseButtonLabel$())
},
events: {
click: extendedAlert.api.close
}
}));
return {
...extendedAlert,
directives: {
...extendedAlert.directives,
autoHideDirective: directiveSubscribe(time$),
bodyDirective,
closeButtonDirective
}
};
});
const defaultToasterProps = {
duration: 5e3,
position: "bottomRight",
dismissible: false
};
class Toaster {
#idCount = 0;
#toasts = writable([]);
/**
* Get the toasts value from the store
* @returns The array of toasts.
*/
toasts = computed(
() => this.#toasts().sort((a, b) => b.id - a.id).slice(0, this.options().limit)
);
options = writable(defaultToasterProps);
#timers = /* @__PURE__ */ new Map();
/**
* Get the timers value from the store
* @returns The map of timers.
*/
get timers() {
return new Map(this.#timers);
}
constructor(props) {
this.options.set({
...defaultToasterProps,
...props
});
this.options.subscribe(() => {
this.updateToasts();
});
}
/**
* Add timer for a toast
* @param id Id of the toast
* @param duration Duration of the timer, by default taken from options
*/
addTimer = (id, duration = this.options().duration) => {
if (duration > 0) {
this.#timers.set(id, {
timeout: setTimeout(() => this.removeToast(id), duration),
started: performance.now(),
duration
});
}
};
/**
* Pause a timer for a toast
* @param id Id of the toast
*/
pauseTimer = (id) => {
if (this.#timers.has(id)) {
const timer = this.#timers.get(id);
if (timer && timer.timeout) {
clearTimeout(timer.timeout);
timer.timeout = null;
timer.paused = performance.now();
}
}
};
/**
* Resume a timer for a toast
* @param id Id of the toast
*/
resumeTimer = (id) => {
if (this.#timers.has(id)) {
const timer = this.#timers.get(id);
if (timer) {
const paused = timer.paused ?? timer.started;
const elapsed = paused - timer.started;
const remaining = (timer.duration ?? 0) - elapsed;
this.addTimer(id, remaining);
timer.duration = remaining;
timer.paused = void 0;
}
}
};
/**
* Events directive is used to set events on the Toast component, to keep track for example of pointer enter/leave,
* used to pause / resume the timer in case of duration and pauseOnHover are specified.
*/
eventsDirective = createAttributesDirective((id) => ({
events: {
pointerenter: () => this.options().pauseOnHover && this.pauseTimer(id()),
pointerleave: () => this.options().pauseOnHover && this.resumeTimer(id())
}
}));
/**
* Helper to add a toast to the viewport.
* @param props Options for the toast.
* @returns The ID of the added toast.
*/
addToast = (props) => {
const autoHide = props.autoHide ?? this.options().duration > 0;
this.#toasts.update((toasts) => [...toasts, { id: this.#idCount++, props }]);
if (autoHide) {
this.addTimer(this.#idCount - 1, props.delay);
}
return this.#idCount - 1;
};
/**
* Helper to remove a toast to the viewport.
* @param id Id of the toast to remove.
*/
removeToast = (id) => {
this.#timers.delete(id);
this.#toasts.update((toasts) => toasts.filter((toast) => toast.id !== id));
};
/** Helper to update toasts when options change */
updateToasts = () => {
if (this.options().duration === 0) {
this.options().dismissible = true;
}
};
/** Helper to close all toasts at once */
closeAll = () => {
this.#toasts.set([]);
this.#timers.clear();
};
}
export {
Toaster as T,
createToast as c,
defaultToasterProps as d,
getToastDefaultConfig as g
};