UNPKG

maz-ui

Version:

A standalone components library for Vue.Js 3 & Nuxt.Js 3

262 lines (261 loc) 11.2 kB
import { useMountComponent } from "../composables/useMountComponent.js"; import { defineComponent, defineAsyncComponent, ref, computed, watch, onMounted, createBlock, openBlock, Transition, withCtx, withDirectives, createElementVNode, normalizeClass, withModifiers, createCommentVNode, createElementBlock, resolveDynamicComponent, toDisplayString, Fragment, renderList, unref, mergeProps, normalizeStyle, createVNode, vShow } from "vue"; import { MazExclamationCircle, MazCheckCircle, MazInformationCircle, MazExclamationTriangle, MazXMark, MazArrowTopRightOnSquare, MazLinkIcon } from "@maz-ui/icons"; import { useTimer } from "../composables/useTimer.js"; import { _ as _export_sfc } from "../chunks/_plugin-vue_export-helper.B--vMWp3.js"; import '../assets/toast.DRXp_3fJ.css';const _hoisted_1 = ["textContent", "innerHTML"], _hoisted_2 = { key: 1, class: "m-toast__progress-bar" }, _sfc_main = /* @__PURE__ */ defineComponent({ __name: "MazToast", props: { message: {}, type: { default: "info" }, destroy: { type: Function }, html: { type: Boolean, default: !1 }, maxToasts: { type: [Number, Boolean], default: !1 }, queue: { type: Boolean }, position: { default: "bottom-right" }, pauseOnHover: { type: Boolean, default: !0 }, timeout: { type: [Number, Boolean], default: 1e4 }, persistent: { type: Boolean }, icon: { type: [Boolean, Function, Object], default: !0 }, button: {}, buttons: {} }, emits: ["close", "click", "open"], setup(__props, { expose: __expose, emit: __emit }) { const emits = __emit, MazBtn = defineAsyncComponent(() => import("../components/MazBtn.js")), Toast = ref(), internalButtons = computed(() => { const buttonArray = []; return __props.button && buttonArray.push(__props.button), __props.buttons && buttonArray.push(...__props.buttons), buttonArray; }), iconComponent = computed(() => { if (__props.icon) switch (__props.type) { case "destructive": return MazExclamationTriangle; case "info": return MazInformationCircle; case "success": return MazCheckCircle; case "warning": return MazExclamationCircle; default: return; } }), positionY = computed(() => __props.position.includes("top") ? "top" : "bottom"), positionX = computed(() => __props.position.includes("left") ? "left" : __props.position.includes("right") ? "right" : "center"), transitionName = computed(() => positionX.value !== "center" ? positionX.value === "right" ? "m-slide-right" : "m-slide-left" : positionY.value === "top" ? "m-slide-top" : "m-slide-bottom"), isActive = ref(!1), queueTimer = ref(), containerClassName = `m-toast-container m-reset-css --${positionY.value} --${positionX.value}`, selectorContainerClass = `.${containerClassName.replaceAll(" ", ".")}`, timer = useTimer({ callback: closeToast, timeout: typeof __props.timeout == "number" ? __props.timeout : 0, callbackOffsetTime: 200 }); function createParents() { const container = document.querySelector(selectorContainerClass); if (!container && !container) { const body = document.body, toCreate = document.createElement("div"); toCreate.className = containerClassName, body.append(toCreate); } } function shouldQueue() { const container = document.querySelector(selectorContainerClass); return !__props.queue && __props.maxToasts === !1 ? !1 : typeof __props.maxToasts == "number" && container ? __props.maxToasts <= container.childElementCount : container && container.childElementCount > 0; } function showNotice() { if (shouldQueue()) { queueTimer.value = setTimeout(showNotice, 250); return; } const container = document.querySelector(selectorContainerClass); Toast.value && container && container.prepend(Toast.value), isActive.value = !0, typeof __props.timeout == "number" && __props.timeout > 0 && !__props.persistent && timer.start(); } const progressBarWidth = ref("100%"); function getProgressBarColor() { switch (__props.type) { case "destructive": return "maz-bg-destructive-800"; case "info": return "maz-bg-info-800"; case "success": return "maz-bg-success-800"; case "warning": return "maz-bg-warning-800"; default: return "maz-bg-contrast-foreground"; } } watch( timer.remainingTime, (remainingTime) => { if (typeof __props.timeout == "number") { const percent = 100 * remainingTime / __props.timeout; progressBarWidth.value = `${percent}%`; } } ); function click(event, shouldClose = !0) { emits("click", event), shouldClose && closeToast(); } const isActionLoading = ref(!1); async function onButtonClick(button, event) { button.onClick && (isActionLoading.value = !0, timer.pause(), await button.onClick(), timer.resume(), isActionLoading.value = !1), click(event, button.closeToast ?? !1); } function toggleTimer(shouldPause) { !__props.pauseOnHover || __props.persistent || isActionLoading.value || (shouldPause ? timer.pause() : timer.resume()); } function stopTimer() { timer.stop(), queueTimer.value && clearTimeout(queueTimer.value); } function closeToast() { stopTimer(), isActive.value = !1; } function onAnimationEnter() { emits("open"); } function onAnimationLeave() { emits("close"), Toast.value?.remove(), __props.destroy?.(); const container = document.querySelector(selectorContainerClass); container && !container?.hasChildNodes() && container.remove(); } function getButtonRightIcon(button) { return !button.to && !button.href ? button.rightIcon : button.target === "_blank" ? MazArrowTopRightOnSquare : MazLinkIcon; } return __expose({ /** * Close the toast * @description This is used to close the toast */ closeToast }), onMounted(() => { createParents(), showNotice(); }), (_ctx, _cache) => (openBlock(), createBlock(Transition, { name: transitionName.value, appear: "", onAfterLeave: onAnimationLeave, onAfterEnter: onAnimationEnter }, { default: withCtx(() => [ withDirectives(createElementVNode("div", { ref_key: "Toast", ref: Toast, class: normalizeClass(["m-toast m-reset-css", [ `--${__props.type}`, `--${positionY.value}`, `--${positionX.value}`, { "--persistent": __props.persistent } ]]) }, [ createElementVNode("button", { role: "alert", class: "m-toast__button", onMouseover: _cache[0] || (_cache[0] = ($event) => toggleTimer(!0)), onMouseleave: _cache[1] || (_cache[1] = ($event) => toggleTimer(!1)), onTouchstartPassive: _cache[2] || (_cache[2] = ($event) => toggleTimer(!0)), onTouchendPassive: _cache[3] || (_cache[3] = ($event) => toggleTimer(!1)), onClick: _cache[4] || (_cache[4] = withModifiers(($event) => click($event), ["stop"])) }, [ iconComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(iconComponent.value), { key: 0, class: "maz-text-2xl" })) : createCommentVNode("", !0), createElementVNode("div", { class: "m-toast__message", textContent: toDisplayString(__props.html ? void 0 : __props.message), innerHTML: __props.html ? __props.message : void 0 }, null, 8, _hoisted_1), (openBlock(!0), createElementBlock(Fragment, null, renderList(internalButtons.value, (toastButton, index) => (openBlock(), createBlock(unref(MazBtn), mergeProps({ key: index }, { ref_for: !0 }, { ...toastButton, onClick: void 0 }, { loading: isActionLoading.value || toastButton.loading, "right-icon": getButtonRightIcon(toastButton), onClick: withModifiers(($event) => onButtonClick(toastButton, $event), ["stop"]) }), null, 16, ["loading", "right-icon", "onClick"]))), 128)), typeof __props.timeout == "number" && __props.timeout > 0 && !__props.persistent ? (openBlock(), createElementBlock("div", _hoisted_2, [ createElementVNode("div", { style: normalizeStyle({ width: progressBarWidth.value }), class: normalizeClass(["m-toast__progress-bar-inner", getProgressBarColor()]) }, null, 6) ])) : createCommentVNode("", !0) ], 32), createElementVNode("button", { class: "m-toast__close", onClick: _cache[5] || (_cache[5] = withModifiers(($event) => click($event), ["stop"])) }, [ createVNode(unref(MazXMark), { class: "m-toast__close-icon" }) ]) ], 2), [ [vShow, isActive.value] ]) ]), _: 1 }, 8, ["name"])); } }), MazToast = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d1646cf7"]]), DEFAULT_OPTIONS = { position: "bottom-right", timeout: 1e4, persistent: !1 }; class ToastHandler { constructor(app, globalOptions) { this.app = app, this.globalOptions = globalOptions; } show(message, options) { const props = { ...DEFAULT_OPTIONS, ...this.globalOptions, ...options, message }, { destroy, vNode } = useMountComponent(MazToast, { props, app: this.app }); return { destroy, close: () => vNode.component?.exposed?.closeToast() }; } getLocalOptions(options) { const DEFAULT_BUTTON_OPTIONS = { size: "xs", color: options?.type ?? "contrast", closeToast: !1 }, button = options?.button ? { ...DEFAULT_BUTTON_OPTIONS, ...options.button } : void 0, buttons = options?.buttons?.map((button2) => ({ ...DEFAULT_BUTTON_OPTIONS, ...button2 })); return { type: options?.type ?? "contrast", ...options, buttons, button }; } message(message, options) { return this.show(message, this.getLocalOptions(options)); } success(message, options) { return this.show(message, this.getLocalOptions({ ...options, type: "success" })); } error(message, options) { return this.show(message, this.getLocalOptions({ ...options, type: "destructive" })); } info(message, options) { return this.show(message, this.getLocalOptions({ ...options, type: "info" })); } warning(message, options) { return this.show(message, this.getLocalOptions({ ...options, type: "warning" })); } } const ToastPlugin = { install(app, options) { const toastHandler = new ToastHandler(app, options); app.provide("mazToast", toastHandler), app.config.globalProperties.$mazToast = toastHandler; } }; export { ToastHandler, ToastPlugin };