UNPKG

vue3-mq

Version:

Build responsive design into your Vue 3 app

430 lines (429 loc) 11.9 kB
import { ref as m, reactive as F, readonly as v, computed as u, h as w, TransitionGroup as G, Transition as J, inject as H } from "vue"; const E = m([]), L = m(null), _ = m(null), P = m(null), j = m(null), i = F({ current: "" }), x = [], U = m(!1), p = v(E), W = v(L), X = v(_), ee = v(P), te = v(j), c = v(i), ne = (e) => { E.value = e; }, oe = (e) => { L.value = e; }, re = (e) => { _.value = e; }, se = (e) => { P.value = e; }, ae = (e) => { j.value = e; }, A = (e = W.value) => { i.current = e; const n = p.value.findIndex( (t) => t.name === e ), o = p.value.map((t) => t.name); for (let t = 0; t < o.length; t++) { if (t > 0 && t < o.length - 1) { const r = o[t] + "Minus", s = o[t] + "Plus"; i[r] = n <= t, i[s] = n >= t; } i[o[t]] = o[t] === e; } }, ie = () => { const e = Object.keys(i); for (let n of e) delete i[n]; A(), D(), z(), K(); }, D = (e = X.value) => { i.orientation = e, i.isLandscape = e === "landscape", i.isPortrait = e === "portrait"; }, z = (e = ee.value || "light") => { i.theme = e, i.isDark = e === "dark", i.isLight = e === "light"; }, K = (e = te.value || "no-preference") => { i.motionPreference = e, i.isMotion = e === "no-preference", i.isInert = e === "reduce"; }; function le() { for (; x.length > 0; ) { const e = x.shift(); if (e && typeof e == "object") { const { mql: n, cb: o } = e; n.addEventListener && typeof n.addEventListener == "function" ? n.removeEventListener("change", o) : n.removeListener(o); } } } function ue() { return p.value.reduce( (n, o, t, r) => { const s = `(min-width: ${o.min}px)`, a = t < r.length - 1 ? `(max-width: ${r[t + 1].min - 1}px)` : null, l = s + (a ? " and " + a : ""); return Object.assign(n, { [o.name]: l }); }, {} ); } function k(e, n) { if (typeof window > "u" || !window.matchMedia) return !1; if (typeof window < "u" && !window.matchMedia) return console.error( "Vue3 Mq: No MatchMedia support detected in this browser. Responsive breakpoints not available." ), !1; { U.value = !0; const o = window.matchMedia(e), t = ({ matches: s }) => { s && n(); }; x.push({ mql: o, cb: t }), o.addEventListener && typeof o.addEventListener == "function" ? o.addEventListener("change", t) : o.addListener(t), t(o); } } const f = (e) => p.value.some( (n) => n.name === e ), S = (e, n) => { const o = n.value.map((t) => t.name); if (e) { if (Array.isArray(e)) return e.filter((t) => f(t)); if (typeof e == "string" && /\w+\+$/.test(e)) { if (e = e.replace(/\+$/, ""), f(e) === !1) return console.error( `Vue3 Mq: ${e} is not a valid breakpoint key. Invalid range.` ), o; const t = n.value.findIndex((r) => r.name === e); return n.value.slice(t).map((r) => r.name); } else if (typeof e == "string" && /\w+-$/.test(e)) { if (e = e.replace(/-$/, ""), f(e) === !1) return console.error( `Vue3 Mq: ${e} is not a valid breakpoint key. Invalid range.` ), o; const t = n.value.findIndex((r) => r.name === e); return n.value.slice(0, t + 1).map((r) => r.name); } else if (typeof e == "string" && /^\w+-\w+$/.test(e)) { const [t, r] = e.split("-"); if (f(t) === !1) return console.error( `Vue3 Mq: ${t} is not a valid breakpoint key. Invalid range.` ), o; if (f(r) === !1) return console.error( `Vue3 Mq: ${r} is not a valid breakpoint key. Invalid range.` ), o; const s = n.value.findIndex((l) => l.name === t), a = n.value.findIndex((l) => l.name === r); return n.value.slice(s, a + 1).map((l) => l.name); } else return typeof e == "string" && f(e) === !0 ? [e] : o; } else return o; }, $ = (e, n) => { const o = []; return !e && !n ? ["landscape", "portrait"] : (e && o.push("landscape"), n && o.push("portrait"), o); }, R = (e, n) => { const o = []; return !n && !e ? ["light", "dark"] : (n && o.push("light"), e && o.push("dark"), o); }, b = (e, n) => { const o = []; return !e && !n ? ["reduce", "no-preference"] : (e && o.push("reduce"), n && o.push("no-preference"), o); }, ce = { xs: 0, sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400 }, de = { xs: 0, sm: 576, md: 768, lg: 992, xl: 1200 }, fe = { xs: 0, sm: 768, md: 992, lg: 1200 }, pe = { xs: 0, sm: 600, md: 960, lg: 1280, xl: 1920, xxl: 2560 }, me = { xs: 0, sm: 600, md: 960, lg: 1264, xl: 1904 }, ve = { xs: 0, sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536 }, he = { phone: 0, tablet: 768, laptop: 1370, desktop: 1906 }, ge = { mobile: 0, small: 600, medium: 782, large: 960, xlarge: 1080, wide: 1280, huge: 1440 }, q = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, bootstrap3: fe, bootstrap4: de, bootstrap5: ce, devices: he, tailwind: ve, vuetify: me, vuetify3: pe, wordpress: ge }, Symbol.toStringTag, { value: "Module" })), ye = (e) => { if (typeof e == "string" && q[e]) return q[e]; { const n = Object.keys(q); return console.error( `Vue3 Mq: "${e}" is not a valid preset. Available options are: ${n.join( ", " )}` ), !1; } }, ke = (e) => ["landscape", "portrait"].includes(e) === !1 ? (console.error( `Vue3 Mq: "${e}" is not a valid default orientation. Reverting to unset value.` ), null) : e, Me = (e = null) => ["dark", "light"].includes(e) === !1 && e !== null ? (console.error( `Vue3 Mq: "${e}" is not a valid default theme. Reverting to unset value.` ), null) : e, we = (e = null) => ["no-preference", "reduce"].includes(e) === !1 && e !== null ? (console.error( `Vue3 Mq: "${e}" is not a valid default motion preference. Reverting to unset value.` ), null) : e, O = (e) => { if (!e || typeof e != "object") return !1; const n = []; for (let r in e) { const s = parseFloat(e[r]); if (!r || typeof r != "string") { console.warn( `Vue3 Mq: Invalid or missing breakpoint key (${JSON.stringify( r )}). Skipping.` ); continue; } else if (/^[^a-z]/i.test(r) || /[^a-zA-Z0-9_]/.test(r)) { console.warn( `Vue3 Mq: "${r}" is an invalid breakpoint key. Breakpoint keys must start with a letter and contain only alphanumeric characters and underscores. Skipping.` ); continue; } else if (!s && s !== 0 || isNaN(s) || s < 0) { console.warn( `Vue3 Mq: "${r}: ${e[r]}" is not a valid breakpoint. Breakpoints should be a number of zero or above. Skipping.` ); continue; } n.push({ name: r, min: s }); } return n.some( (r) => r.min === 0 ) || console.warn( "Vue3 Mq: You have not declared a breakpoint with a minimum value of 0. There may be screen sizes to which Vue3Mq does not respond." ), new Set( n.map((r) => r.min) ).size < n.length && console.warn( "Vue3 Mq: Your breakpoint configuration contains duplicate values. Behaviour may be unpredictable." ), n.length === 0 ? !1 : n.sort((r, s) => r.min - s.min); }, qe = (e) => { const n = e.split(":"), o = {}; for (let t of n) /\D/.test(t) !== !1 && (["landscape", "portrait"].includes(t) ? o.slotOrientation = t : ["light", "dark"].includes(t) ? o.slotTheme = t : ["inert", "motion"].includes(t) ? o.slotMotion = t : o.slotBp = t); return o; }, xe = { name: "fade", mode: "out-in" }, Te = { name: "MqResponsive", props: { /** * Breakpoints to target when rendering component */ target: [String, Array], /** * Only render in a landscape view */ landscape: { type: Boolean, default: !1 }, /** * Only render in a portrait view */ portrait: { type: Boolean, default: !1 }, /** * Only render when dark mode is preferred */ dark: { type: Boolean, default: !1 }, /** * Only render when light mode is preferred */ light: { type: Boolean, default: !1 }, /** * Only render when reduced motion is preferred */ inert: { type: Boolean, default: !1 }, /** * Only render when normal motion is preferred */ motion: { type: Boolean, default: !1 }, /** * HTML tag to use when rendering */ tag: { type: String, default: "div" }, /** * When in group mode, the HTML tag to use on list items */ listTag: { type: String, default: "div" }, /** * Render items as part of a transition group */ group: { type: Boolean, default: !1 } }, setup(e, { attrs: n, emit: o, slots: t }) { const r = u(() => S( e.target, p )), s = u(() => $( e.landscape, e.portrait )), a = u(() => R(e.dark, e.light)), l = u(() => b(e.inert, e.motion)), h = u(() => r.value.includes(c.current) && s.value.includes(c.orientation) && a.value.includes(c.theme) && l.value.includes(c.motionPreference)), M = (d) => { if (!e.group && t.length > 0) return t; const g = []; for (let y in t) { const { slotBp: Q, slotOrientation: T, slotTheme: V, slotMotion: B } = qe(y), N = u(() => S( Q, p )), C = u(() => $( T === "landscape", T === "portrait" )), Y = u(() => R( V === "dark", V === "light" )), Z = u(() => b( B === "inert", B === "motion" )); u(() => N.value.includes( c.current ) && C.value.includes( c.orientation ) && Y.value.includes(c.theme) && Z.value.includes( c.motionPreference )).value === !0 && g.push( w( d || t[y], { key: y }, d ? t[y]() : void 0 ) ); } return g.length > 0 ? g : void 0; }; return t.default ? () => h.value ? w(e.tag, { ...n }, t.default()) : void 0 : () => { const d = Object.assign( {}, xe, n, { tag: e.tag } ), g = e.group ? G : J; return w( g, d, () => M(e.listTag) ); }; } }; function I({ breakpoints: e, preset: n }) { const o = n ? ye(n) : !1, t = e ? O(e) : !1; if (o === !1 && !t) throw new TypeError( "Vue3 Mq: You must provide a valid preset, or valid breakpoint settings." ); ne( t || O(o) ), le(), ie(); const r = ue(); for (const s in r) { const a = r[s]; k(a, () => { A(s); }); } ["portrait", "landscape"].forEach((s) => { const a = () => { D(s); }; k(`(orientation: ${s})`, a); }), ["light", "dark"].forEach((s) => { const a = () => { z(s); }; k(`(prefers-color-scheme: ${s})`, a); }), ["reduce", "no-preference"].forEach((s) => { const a = () => { K(s); }; k(`(prefers-reduced-motion: ${s})`, a); }); } function $e() { const e = H("mq"); if (e) return e; throw new Error( "Vue3Mq is not installed in this app. Please follow the installation instructions and try again." ); } const Ve = (e, { preset: n = "bootstrap5", breakpoints: o, defaultBreakpoint: t, defaultOrientation: r = "landscape", defaultMotion: s = "no-preference", defaultTheme: a, global: l = !1 } = {}) => { try { const h = ke(r), M = Me(a), d = we(s); oe(t), re(h), se(M), ae(d), e.provide("mq", c), e.provide("updateBreakpoints", I), l === !0 && (e.component("MqResponsive", Te), e.config.globalProperties.$mq = c), I({ breakpoints: o, preset: n }); } catch (h) { console.error(h); } }, Re = { install: Ve }; export { Te as MqResponsive, Re as Vue3Mq, p as availableBreakpoints, I as updateBreakpoints, $e as useMq };