UNPKG

vue3-snackbar

Version:

<p align="center"> <a href="https://evomark.co.uk" target="_blank" alt="Link to evoMark's website"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://evomark.co.uk/wp-content/uploads/static/evomark-logo--dark.svg

745 lines (744 loc) 21.6 kB
import { h as y, computed as u, ref as N, onMounted as D, watch as E, createElementBlock as w, openBlock as b, normalizeStyle as G, normalizeClass as T, unref as L, renderSlot as C, createElementVNode as M, createCommentVNode as A, createVNode as _, mergeProps as U, toDisplayString as B, withModifiers as H, toRaw as ee, inject as te, nextTick as se, getCurrentInstance as J, getCurrentScope as ae, onScopeDispose as oe, toValue as K, shallowRef as ne, onUnmounted as re, createBlock as j, Teleport as ie, TransitionGroup as le, withCtx as q, Fragment as ue, renderList as z, createSlots as ce } from "vue"; var de = "M8.27,3L3,8.27V15.73L8.27,21H15.73C17.5,19.24 21,15.73 21,15.73V8.27L15.73,3M9.1,5H14.9L19,9.1V14.9L14.9,19H9.1L5,14.9V9.1M11,15H13V17H11V15M11,7H13V13H11V7", fe = "M12,2L1,21H23M12,6L19.53,19H4.47M11,10V14H13V10M11,16V18H13V16", me = "M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M10 17L5 12L6.41 10.59L10 14.17L17.59 6.58L19 8L10 17Z", pe = "M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z", ge = "M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z"; const ve = { transform: "rotate(var(--r, 0deg)) scale(var(--sx, 1), var(--sy, 1))" }, R = { mdi: { size: 24, viewbox: "0 0 24 24" }, "simple-icons": { size: 24, viewbox: "0 0 24 24" }, default: { size: 0, viewbox: "0 0 0 0" } }, be = { props: { type: { type: String, required: !0 }, path: { type: [String, Object, Array], required: !1 }, pathString: { type: [Array, String, Object], required: !1 } }, setup(t) { return () => t.type === "fad" ? (console.warn("vue3-icon does not currently support Duotone FontAwesome icons"), y("path")) : Array.isArray(t.path) ? y( "g", { style: { fill: "currentcolor" } }, t.path.map((s) => typeof s == "string" ? y("path", { d: s }) : y("path", { ...s })) ) : y("path", { d: t.pathString, style: { fill: "currentcolor" } }); } }, P = { name: "icon", props: { /** * The icon type, e.g. mdi or simple-icons */ type: { type: String, default: "mdi" }, /** * The FontAwesome icon object */ faIcon: { type: Object, default: null }, /** * The svg path for the icon */ path: { type: [String, Object, Array] }, /** * The size of the icon when rendered in the browser */ size: { type: [Number, String], default: 24 }, /** * The SVG viewbox, affects path position, but not render size */ viewbox: { type: String, required: !1 }, /** * Flip the icon either horizontally, vertically, or both */ flip: { type: String, default: "", validator: (t) => ["", "horizontal", "vertical", "both"].includes(t) }, /** * Rotate the icon */ rotate: { type: [Number, String], default: 0 }, /** * Don't add the XML namespace attribute */ noNamespace: { type: Boolean, default: !1 }, /** * Don't add any styles to SVG, disables flip and rotate */ noStyles: { type: Boolean, default: !1 }, /** * Don't add the width/height attributes to the SVG element */ noDimensions: { type: Boolean, default: !1 } }, setup(t) { if (!t.path && !t.faIcon) return console.warn("vue3-icon requires either a 'path' or an 'fa-icon' property"), () => y("div"); const s = u(() => { var f; return ((f = t.faIcon) == null ? void 0 : f.prefix) || t.type; }), o = u(() => parseInt(t.rotate, 10)), e = u(() => R[s.value] || R.default), a = u(() => parseInt(t.size, 10) || e.value.size), i = u(() => t.faIcon ? `0 0 ${t.faIcon.icon[0]} ${t.faIcon.icon[1]}` : !1), l = u(() => i.value || t.viewbox || e.value.viewbox), m = u(() => { if (t.noStyles !== !0) return { ...ve, "--sx": ["both", "horizontal"].includes(t.flip) ? "-1" : "1", "--sy": ["both", "vertical"].includes(t.flip) ? "-1" : "1", "--r": isNaN(o.value) ? o.value : o.value + "deg" }; }), p = u(() => { var f; return t.faIcon ? (f = t.faIcon) == null ? void 0 : f.icon[4] : t.type === "simple-icons" && typeof t.path == "object" ? t.path.path : t.path; }); return () => y( "svg", { xmlns: t.noNamespace !== !0 ? "http://www.w3.org/2000/svg" : void 0, style: m.value, class: ["vue3-icon"], width: t.noDimensions !== !0 ? a.value : void 0, height: t.noDimensions !== !0 ? a.value : void 0, viewBox: l.value }, [y(be, { path: t.path, type: s.value, pathString: p.value })] ); } }, ye = ["role"], he = { class: "vue3-snackbar-message-wrapper" }, ke = { key: 0, class: "vue3-snackbar-message-icon" }, Se = { class: "vue3-snackbar-message-content" }, we = { key: 0, class: "vue3-snackbar-message-badge" }, Ce = { class: "vue3-snackbar-message-title" }, Me = { key: 0, class: "vue3-snackbar-message-additional" }, xe = { class: "vue3-snackbar-message-close" }, Ae = { __name: "Vue3SnackbarMessage", props: { borderClass: { type: String, default: "" }, message: { type: Object, default: () => ({}) }, messageClass: { type: String, default: "" }, messageActionClass: { type: String, default: "vue3-snackbar-message-action" }, dense: { type: Boolean, default: !1 }, iconPresets: { type: Object, required: !0 } }, emits: ["dismiss", "click:action"], setup(t, { emit: s }) { const o = s, e = t; let a = null, i = null, l = N(!1); const m = () => { if ((e.message.duration === 0 || e.message.duration === "0") && e.message.dismissible !== !1) return; const c = !e.message.duration && !e.message.dismissible ? 4e3 : e.message.duration; a = setTimeout(f, c); }; D(m), E( () => e.message.count, (r) => { if (r === 1) return !1; clearTimeout(a), clearTimeout(i), i = setTimeout(() => { l.value = !1; }, 1e3), l.value = !0, m(); } ); const p = () => { a && clearTimeout(a), f(); }, f = () => { o("dismiss", e.message); }, h = u( () => Object.assign( {}, { success: { path: me }, info: { path: ge }, warning: { path: fe }, error: { path: de } }, e.iconPresets ) ), v = u(() => { const r = h.value[e.message.type]; return e.message.type && !r && console.warn("[Vue3 Snackbar] Couldn't find icon preset for type " + e.message.type), r ? (r.type = "mdi", r) : e.message.icon && typeof e.message.icon == "object" ? e.message.icon : { path: "", type: "default" }; }), k = u(() => { var r; return e.message.type === "error" ? "alert" : ((r = e.message) == null ? void 0 : r.role) ?? "status"; }), n = { name: "RenderedAction", render() { const r = u(() => ee(e.message.action)); return r.value ? y(r.value, { message: e.message, isDismissible: e.message.isDismissible, dismiss: p }) : null; } }; return (r, c) => (b(), w("article", { class: T(["vue3-snackbar-message", [ e.message.type || "custom", e.messageClass, e.borderClass, { "has-background": e.message.background, "has-border": e.borderClass, "is-dense": e.dense, "shake-baby-shake": L(l) } ]]), role: k.value, style: G({ "--message-background": e.message.background, "--message-text-color": e.message.textColor, "--message-icon-color": e.message.iconColor }) }, [ C(r.$slots, "message-inner", { message: e.message }, () => [ M("div", he, [ v.value ? (b(), w("div", ke, [ C(r.$slots, "message-icon", { message: e.message, icon: v.value }, () => [ _(L(P), U(v.value, { role: "img" }), null, 16) ]) ])) : A("", !0), M("div", Se, [ C(r.$slots, "message-badge", { message: e.message, count: e.message.count }, () => [ e.message.count > 1 ? (b(), w("div", we, B(e.message.count), 1)) : A("", !0) ]), C(r.$slots, "message-content", { message: e.message, title: e.message.title, text: e.message.text }, () => [ M("div", Ce, B(e.message.title || e.message.text), 1), e.message.title && e.message.text ? (b(), w("div", Me, B(e.message.text), 1)) : A("", !0) ]), r.$slots["message-action"] ? (b(), w("div", { key: 0, class: T(e.messageActionClass), onClick: c[0] || (c[0] = H((d) => o("click:action", { message: e.message }), ["stop"])) }, [ C(r.$slots, "message-action", { message: e.message, isDismissible: e.message.dismissible, dismiss: p }, () => [ _(n) ]) ], 2)) : A("", !0) ]), c[1] || (c[1] = M("div", { class: "spacer" }, null, -1)), M("div", xe, [ C(r.$slots, "message-close-icon", { message: e.message, isDimissible: e.message.dismissible, isDismissible: e.message.dismissible, dismiss: p }, () => [ e.message.dismissible !== !1 ? (b(), w("button", { key: 0, onClick: H(p, ["stop"]) }, [ _(L(P), { type: "mdi", path: L(pe) }, null, 8, ["path"]) ])) : A("", !0) ]) ]) ]) ]) ], 14, ye)); } }, $e = typeof window < "u" ? HTMLElement : Object, Le = { /* ****************************************** * LOCATION PROPS ****************************************** */ top: { type: Boolean, default: !1 }, bottom: { type: Boolean, default: !1 }, left: { type: Boolean, default: !1 }, right: { type: Boolean, default: !1 }, start: { type: Boolean, default: !1 }, end: { type: Boolean, default: !1 }, /* ****************************************** * COLOUR PROPS ****************************************** */ success: { type: String, default: "#4caf50" }, error: { type: String, default: "#ff5252" }, warning: { type: String, default: "#fb8c00" }, info: { type: String, default: "#2196f3" }, iconPresets: { type: Object, default: () => ({}) }, messageTextColor: { type: String, default: "#fff" }, messageIconColor: { type: String, default: "currentColor" }, /* ********************************************* * BACKGROUND PROPS * ******************************************* */ backgroundOpacity: { type: [String, Number], default: 0.12, validator: (t) => !isNaN(parseFloat(t)) && isFinite(t) }, backgroundColor: { type: String, default: "currentColor" }, baseBackgroundColor: { type: String, default: "#fff" }, /* ********************************************* * BEHAVIOUR PROPS * ******************************************* */ duration: { type: [Number, String], default: null }, reverse: { type: Boolean, default: !1 }, limit: { type: Number, default: null }, dismissOnActionClick: { type: Boolean, default: !0 }, groups: { type: Boolean, default: !1 }, attach: { type: [String, $e], default: "body" }, /* ****************************************** * OTHER PROPS ****************************************** */ border: { type: String, default: "", validator: (t) => ["top", "bottom", "left", "right", "start", "end", ""].includes(t) }, messageClass: { type: String }, messageActionClass: { type: String, default: "vue3-snackbar-message-action" }, zIndex: { type: Number, default: 1e4 }, dense: { type: Boolean, default: !1 }, shadow: { type: [Boolean, String], default: !1, validator: (t) => t === !0 || t === !1 || ["xs", "sm", "md", "lg", "xl", "2xl"].includes(t) }, contentWidth: { type: String, default: "min(50vw, 350px)" }, borderWidth: { type: [String, Number], default: 8 } }; function Oe(t) { return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t; } var O = { exports: {} }, W; function Ve() { if (W) return O.exports; W = 1; function t() { } return t.prototype = { on: function(s, o, e) { var a = this.e || (this.e = {}); return (a[s] || (a[s] = [])).push({ fn: o, ctx: e }), this; }, once: function(s, o, e) { var a = this; function i() { a.off(s, i), o.apply(e, arguments); } return i._ = o, this.on(s, i, e); }, emit: function(s) { var o = [].slice.call(arguments, 1), e = ((this.e || (this.e = {}))[s] || []).slice(), a = 0, i = e.length; for (a; a < i; a++) e[a].fn.apply(e[a].ctx, o); return this; }, off: function(s, o) { var e = this.e || (this.e = {}), a = e[s], i = []; if (a && o) for (var l = 0, m = a.length; l < m; l++) a[l].fn !== o && a[l].fn._ !== o && i.push(a[l]); return i.length ? e[s] = i : delete e[s], this; } }, O.exports = t, O.exports.TinyEmitter = t, O.exports; } var I, F; function _e() { if (F) return I; F = 1; var t = Ve(); return I = new t(), I; } var Be = _e(); const V = /* @__PURE__ */ Oe(Be), x = { $on: (...t) => V.on(...t), $once: (...t) => V.once(...t), $off: (...t) => V.off(...t), $emit: (...t) => V.emit(...t) }, $ = N([]), Q = Symbol(), Ie = (t) => Math.abs(t.split("").reduce((s, o) => (s << 5) - s + o.charCodeAt(0) | 0, 0)); let Z = 1; x.$on("add", (t) => { t = { ...t }, t.group || (t.group = Ie(`${t.type}${t.title}${t.text}`).toString(16)), t.id = Z, Z++, $.value.push(t); }); function Ge() { const t = te(Q); if (!t) throw new Error("No Snackbar provided!"); return t; } const Ue = { install: (t, s = {}) => { const { disableGlobals: o = !1 } = s, e = { add: (a) => { x.$emit("add", a); }, clear: () => { x.$emit("clear"); } }; o !== !0 && (t.config.globalProperties.$snackbar = e, typeof window < "u" && (window.$snackbar = e)), t.provide(Q, e); } }; function Te(t) { return ae() ? (oe(t), !0) : !1; } const X = typeof window < "u" && typeof document < "u"; typeof WorkerGlobalScope < "u" && globalThis instanceof WorkerGlobalScope; const Ne = (t) => t != null; function De(t) { return Array.isArray(t) ? t : [t]; } function Ee(t) { return J(); } function He(t, s = !0, o) { Ee() ? D(t, o) : s ? t() : se(t); } const je = X ? window : void 0, qe = X ? window.document : void 0; function ze(t) { var s; const o = K(t); return (s = o == null ? void 0 : o.$el) != null ? s : o; } function Re() { const t = ne(!1), s = J(); return s && D(() => { t.value = !0; }, s), t; } function Pe(t) { const s = Re(); return u(() => (s.value, !!t())); } function We(t, s, o = {}) { const { window: e = je, ...a } = o; let i; const l = Pe(() => e && "MutationObserver" in e), m = () => { i && (i.disconnect(), i = void 0); }, p = u(() => { const k = K(t), n = De(k).map(ze).filter(Ne); return new Set(n); }), f = E( () => p.value, (k) => { m(), l.value && k.size && (i = new MutationObserver(s), k.forEach((n) => i.observe(n, a))); }, { immediate: !0, flush: "post" } ), h = () => i == null ? void 0 : i.takeRecords(), v = () => { f(), m(); }; return Te(v), { isSupported: l, stop: v, takeRecords: h }; } function Fe(t = {}) { const { document: s = qe, selector: o = "html", observe: e = !1, initialValue: a = "ltr" } = t; function i() { var m, p; return (p = (m = s == null ? void 0 : s.querySelector(o)) == null ? void 0 : m.getAttribute("dir")) != null ? p : a; } const l = N(i()); return He(() => l.value = i()), e && s && We( s.querySelector(o), () => l.value = i(), { attributes: !0 } ), u({ get() { return l.value; }, set(m) { var p, f; l.value = m, s && (l.value ? (p = s.querySelector(o)) == null || p.setAttribute("dir", l.value) : (f = s.querySelector(o)) == null || f.removeAttribute("dir")); } }); } const Je = { __name: "Vue3Snackbar", props: { ...Le }, emits: ["added", "group-added", "dismissed", "removed", "cleared", "click:action"], setup(t, { emit: s }) { const o = Fe(), e = t, a = s, i = u(() => ((e.left || e.right) && (e.start || e.end) && console.warn("[Vue3 Snackbar] The left/right and start/end position properties should not be used together."), { "is-top": e.top, "is-bottom": e.top === !1 && e.bottom, "is-left": e.left, "is-right": e.left === !1 && e.right, "is-start": e.start, "is-end": e.start === !1 && e.end, "is-middle": e.top === !1 && e.bottom === !1, "is-centre": ["left", "right", "start", "end"].every((n) => e[n] === !1), "shadow-md": e.shadow === !0, [`shadow-${e.shadow}`]: typeof e.shadow == "string", "is-rtl": o.value === "rtl" })), l = (n) => typeof n == "number" || /[^\d]/.test(n) === !1 ? `${n}px` : n, m = u(() => ({ "--success-colour": e.success, "--error-colour": e.error, "--warning-colour": e.warning, "--info-colour": e.info, "--snackbar-zindex": e.zIndex, "--background-opacity": e.backgroundOpacity, "--background-color": e.backgroundColor, "--base-background-color": e.baseBackgroundColor, "--message-text-color": e.messageTextColor, "--message-icon-color": e.messageIconColor, "--snackbar-content-width": e.contentWidth, "--snackbar-border-width": l(e.borderWidth) })), p = u(() => e.border ? `border-${e.border}` : ""), f = (n, r = !1) => { Object.hasOwn(n, "onRemoved") && typeof n.onRemoved == "function" && n.onRemoved(n, r), a(r ? "dismissed" : "removed", n), $.value = $.value.filter((c) => e.groups ? c.group !== n.group : c.id !== n.id); }, h = u(() => { const r = [...$.value].reduce((c, d) => { e.duration && !d.duration && d.duration !== 0 && (d.duration = +e.duration); const g = e.groups ? d.group : d.id; if (c.has(g)) { const S = c.get(g); d.count = S.count + 1, d.id = S.id, c.set(g, d), a("group-added", d); } else d.count = 1, a("added", d), c.set(g, d); return c; }, /* @__PURE__ */ new Map()); return Array.from(r.values()); }), v = u(() => { const n = e.limit ? h.value.slice(e.limit * -1) : h.value; return e.reverse ? n.reverse() : n; }); E( v, (n) => { const r = n.map((g) => g.id), d = h.value.map((g) => g.id).filter((g) => !r.includes(g)); for (const g of d) { const S = h.value.find((Y) => Y.id === g); S && f(S, !1); } }, { immediate: !0 } ), x.$on("clear", () => { a("cleared"), $.value = []; }), re(() => { x.$off("add"), x.$off("clear"); }); const k = (n) => { a("click:action", n), e.dismissOnActionClick && f(n.message, !0); }; return (n, r) => (b(), j(ie, { to: e.attach }, [ M("section", { id: "vue3-snackbar--container", class: T(["vue3-snackbar", [i.value]]), style: G(m.value), "aria-live": "polite" }, [ _(le, { name: "vue3-snackbar-message", tag: "div", class: "vue3-snackbar--messages" }, { default: q(() => [ (b(!0), w(ue, null, z(v.value, (c) => (b(), j(Ae, { key: c.id, message: c, "message-class": e.messageClass, "message-action-class": e.messageActionClass, dense: e.dense, "border-class": p.value, "icon-presets": e.iconPresets, onDismiss: r[0] || (r[0] = (d) => f(d, !0)), "onClick:action": k }, ce({ _: 2 }, [ z(n.$slots, (d, g) => ({ name: g, fn: q((S) => [ C(n.$slots, g, U({ ref_for: !0 }, S)) ]) })) ]), 1032, ["message", "message-class", "message-action-class", "dense", "border-class", "icon-presets"]))), 128)) ]), _: 3 }) ], 6) ], 8, ["to"])); } }; export { $ as SnackbarMessages, Ue as SnackbarService, Je as Vue3Snackbar, Ge as useSnackbar };