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
JavaScript
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
};