maz-ui
Version:
A standalone components library for Vue.Js 3 & Nuxt.Js 3
262 lines (261 loc) • 11.2 kB
JavaScript
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
};