@nexim/snackbar
Version:
Snackbar component with signal capability.
244 lines (235 loc) • 8.88 kB
JavaScript
/* @nexim/snackbar v2.1.0 */
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
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
var main_exports = {};
__export(main_exports, {
SnackbarElement: () => SnackbarElement,
snackbarSignal: () => snackbarSignal
});
module.exports = __toCommonJS(main_exports);
var import_package_tracer = require("@alwatr/package-tracer");
// src/lib/handler.ts
var import_delay = require("@alwatr/delay");
var import_logger = require("@alwatr/logger");
var import_debounce = __toESM(require("debounce"), 1);
// src/lib/signal.ts
var import_flux = require("@alwatr/flux");
var snackbarActionButtonClickedSignal = /* @__PURE__ */ new import_flux.AlwatrTrigger({
name: "snackbar-action-button-click"
});
var snackbarCloseButtonClickedSignal = /* @__PURE__ */ new import_flux.AlwatrTrigger({
name: "snackbar-close-button-click"
});
var snackbarSignal = /* @__PURE__ */ new import_flux.AlwatrSignal({ name: "snackbar" });
// src/lib/handler.ts
var logger = (0, import_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") {
import_delay.delay.by(options.duration).then(closeSnackbar);
}
}
var debouncedShowSnackbar = (0, import_debounce.default)((options) => {
showSnackbar(options);
}, 50);
snackbarSignal.subscribe((options) => {
debouncedShowSnackbar(options);
});
// src/lib/element.ts
var import_delay3 = require("@alwatr/delay");
var import_element = require("@nexim/element");
var import_lit = require("lit");
var import_decorators = require("lit/decorators.js");
// src/lib/utils.ts
var import_delay2 = require("@alwatr/delay");
function waitForNextFrame() {
return new Promise((resolve) => {
import_delay2.delay.untilNextAnimationFrame().then(() => {
import_delay2.delay.immediate().then(resolve);
});
});
}
// src/lib/element.ts
var SnackbarElement = class extends (0, import_element.lightDomMixin)((0, import_element.loggerMixin)(import_lit.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 import_delay3.delay.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 = import_lit.nothing;
if (actionButtonHtml != import_lit.nothing || closeButtonHtml != import_lit.nothing) {
actionButtonHandler = import_lit.html`<div>${actionButtonHtml} ${closeButtonHtml}</div>`;
}
return [import_lit.html`<span>${this.content}</span>`, actionButtonHandler];
}
/**
* Render the action button.
*/
renderActionButton__() {
if (this.actionButtonLabel == null) return import_lit.nothing;
this.logger_.logMethodArgs?.("renderActionButton__", { actionLabel: this.actionButtonLabel });
return import_lit.html` <button class="action-button" @click=${this.actionButtonClickHandler__.bind(this)}>${this.actionButtonLabel}</button> `;
}
/**
* Render the close button.
*/
renderCloseButton__() {
if (!this.addCloseButton) return import_lit.nothing;
this.logger_.logMethod?.("renderCloseButton__");
return import_lit.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([
(0, import_decorators.property)({ type: String })
], SnackbarElement.prototype, "content", 2);
__decorateClass([
(0, import_decorators.property)({ type: String, attribute: "action-button-label" })
], SnackbarElement.prototype, "actionButtonLabel", 2);
__decorateClass([
(0, import_decorators.property)({ type: Boolean, attribute: "add-close-button" })
], SnackbarElement.prototype, "addCloseButton", 2);
SnackbarElement = __decorateClass([
(0, import_decorators.customElement)("snack-bar")
], SnackbarElement);
// src/main.ts
__dev_mode__: import_package_tracer.packageTracer.add("@nexim/snackbar", "2.1.0");
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SnackbarElement,
snackbarSignal
});
//# sourceMappingURL=main.cjs.map