UNPKG

@nexim/snackbar

Version:
211 lines (202 loc) 6.95 kB
/* @nexim/snackbar v2.1.0 */ var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __decorateClass = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp(target, key, result); return result; }; // src/main.ts import { packageTracer } from "@alwatr/package-tracer"; // src/lib/handler.ts import { delay } from "@alwatr/delay"; import { createLogger } from "@alwatr/logger"; import debounce from "debounce"; // src/lib/signal.ts import { AlwatrSignal, AlwatrTrigger } from "@alwatr/flux"; var snackbarActionButtonClickedSignal = /* @__PURE__ */ new AlwatrTrigger({ name: "snackbar-action-button-click" }); var snackbarCloseButtonClickedSignal = /* @__PURE__ */ new AlwatrTrigger({ name: "snackbar-close-button-click" }); var snackbarSignal = /* @__PURE__ */ new AlwatrSignal({ name: "snackbar" }); // src/lib/handler.ts var logger = createLogger("@nexim/snackbar"); var closeLastSnackbar = null; var unsubscribeActionButtonHandler = null; var unsubscribeCloseButtonHandler = null; function createSnackbarElement(options) { const element = document.createElement("snack-bar"); element.setAttribute("content", options.content); if (options.addCloseButton === true) { element.setAttribute("add-close-button", ""); } if (options.action != null) { element.setAttribute("action-button-label", options.action.label); } return element; } function handleActionButtonClick(closeSnackbar, handler) { logger.logMethod?.("handleActionButtonClick"); (async () => { try { await handler(); } catch (error) { logger.error("handleActionButtonClick", "call_handler_failed", error); } })(); return closeSnackbar(); } async function showSnackbar(options) { logger.logMethodArgs?.("showSnackbar", { options }); options.duration ?? (options.duration = "5s"); const element = createSnackbarElement(options); let closed = false; const closeSnackbar = async () => { if (closed) return; logger.logMethodArgs?.("closeSnackbar", { options }); await element.close(); unsubscribeActionButtonHandler?.(); unsubscribeCloseButtonHandler?.(); closed = true; }; await closeLastSnackbar?.(); closeLastSnackbar = closeSnackbar; if (options.action != null) { unsubscribeActionButtonHandler = snackbarActionButtonClickedSignal.subscribe( handleActionButtonClick.bind(null, closeSnackbar, options.action.handler) ).unsubscribe; } if (options.addCloseButton === true) { unsubscribeCloseButtonHandler = snackbarCloseButtonClickedSignal.subscribe(closeSnackbar.bind(null)).unsubscribe; } document.body.appendChild(element); if (options.duration !== "infinite") { delay.by(options.duration).then(closeSnackbar); } } var debouncedShowSnackbar = debounce((options) => { showSnackbar(options); }, 50); snackbarSignal.subscribe((options) => { debouncedShowSnackbar(options); }); // src/lib/element.ts import { delay as delay3 } from "@alwatr/delay"; import { lightDomMixin, loggerMixin } from "@nexim/element"; import { html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators.js"; // src/lib/utils.ts import { delay as delay2 } from "@alwatr/delay"; function waitForNextFrame() { return new Promise((resolve) => { delay2.untilNextAnimationFrame().then(() => { delay2.immediate().then(resolve); }); }); } // src/lib/element.ts var SnackbarElement = class extends lightDomMixin(loggerMixin(LitElement)) { constructor() { super(...arguments); this.content = ""; this.actionButtonLabel = null; this.addCloseButton = false; } // ms firstUpdated(changedProperties) { super.firstUpdated(changedProperties); waitForNextFrame().then(() => { this.setAttribute("open", ""); }); } /** * Close the snackbar and remove it from the DOM. * Waits for the closing animation to end before removing the element. * * @internal * This method should be used by the package API, not directly, to ensure proper signal unsubscription. */ async close() { this.logger_.logMethod?.("close"); this.removeAttribute("open"); await delay3.by(SnackbarElement.openAndCloseAnimationDuration__); this.remove(); } /** * Handle the close button click event. * Sends a signal when the action button is clicked. */ closeButtonClickHandler__() { this.logger_.logMethod?.("closeButtonClickHandler__"); snackbarCloseButtonClickedSignal.notify(); } /** * Handle the action button click event. * Sends a signal when the action button is clicked. */ actionButtonClickHandler__() { this.logger_.logMethod?.("actionButtonClickHandler__"); snackbarActionButtonClickedSignal.notify(); } /** * Render the snackbar component. */ render() { super.render(); const actionButtonHtml = this.renderActionButton__(); const closeButtonHtml = this.renderCloseButton__(); let actionButtonHandler = nothing; if (actionButtonHtml != nothing || closeButtonHtml != nothing) { actionButtonHandler = html`<div>${actionButtonHtml} ${closeButtonHtml}</div>`; } return [html`<span>${this.content}</span>`, actionButtonHandler]; } /** * Render the action button. */ renderActionButton__() { if (this.actionButtonLabel == null) return nothing; this.logger_.logMethodArgs?.("renderActionButton__", { actionLabel: this.actionButtonLabel }); return html` <button class="action-button" @click=${this.actionButtonClickHandler__.bind(this)}>${this.actionButtonLabel}</button> `; } /** * Render the close button. */ renderCloseButton__() { if (!this.addCloseButton) return nothing; this.logger_.logMethod?.("renderCloseButton__"); return html` <button class="close-button" @click=${this.closeButtonClickHandler__.bind(this)}> <span class="icon">close</span> </button> `; } }; /** * Duration for the open and close animation in milliseconds. */ SnackbarElement.openAndCloseAnimationDuration__ = 200; __decorateClass([ property({ type: String }) ], SnackbarElement.prototype, "content", 2); __decorateClass([ property({ type: String, attribute: "action-button-label" }) ], SnackbarElement.prototype, "actionButtonLabel", 2); __decorateClass([ property({ type: Boolean, attribute: "add-close-button" }) ], SnackbarElement.prototype, "addCloseButton", 2); SnackbarElement = __decorateClass([ customElement("snack-bar") ], SnackbarElement); // src/main.ts __dev_mode__: packageTracer.add("@nexim/snackbar", "2.1.0"); export { SnackbarElement, snackbarSignal }; //# sourceMappingURL=main.mjs.map