vue3-mq
Version:
Build responsive design into your Vue 3 app
2 lines (1 loc) • 8.49 kB
JavaScript
(function(c,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],s):(c=typeof globalThis<"u"?globalThis:c||self,s(c.Vue3Mq={},c.Vue))})(this,function(c,s){"use strict";const T=s.ref([]),x=s.ref(null),V=s.ref(null),B=s.ref(null),S=s.ref(null),a=s.reactive({current:""}),k=[],K=s.ref(!1),f=s.readonly(T),Q=s.readonly(x),N=s.readonly(V),C=s.readonly(B),Y=s.readonly(S),d=s.readonly(a),Z=e=>{T.value=e},F=e=>{x.value=e},G=e=>{V.value=e},J=e=>{B.value=e},H=e=>{S.value=e},b=(e=Q.value)=>{a.current=e;const n=f.value.findIndex(t=>t.name===e),o=f.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",i=o[t]+"Plus";a[r]=n<=t,a[i]=n>=t}a[o[t]]=o[t]===e}},U=()=>{const e=Object.keys(a);for(let n of e)delete a[n];b(),R(),$(),O()},R=(e=N.value)=>{a.orientation=e,a.isLandscape=e==="landscape",a.isPortrait=e==="portrait"},$=(e=C.value||"light")=>{a.theme=e,a.isDark=e==="dark",a.isLight=e==="light"},O=(e=Y.value||"no-preference")=>{a.motionPreference=e,a.isMotion=e==="no-preference",a.isInert=e==="reduce"};function W(){for(;k.length>0;){const e=k.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 X(){return f.value.reduce((n,o,t,r)=>{const i=`(min-width: ${o.min}px)`,l=t<r.length-1?`(max-width: ${r[t+1].min-1}px)`:null,u=i+(l?" and "+l:"");return Object.assign(n,{[o.name]:u})},{})}function y(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;{K.value=!0;const o=window.matchMedia(e),t=({matches:i})=>{i&&n()};k.push({mql:o,cb:t}),o.addEventListener&&typeof o.addEventListener=="function"?o.addEventListener("change",t):o.addListener(t),t(o)}}const m=e=>f.value.some(n=>n.name===e),I=(e,n)=>{const o=n.value.map(t=>t.name);if(e){if(Array.isArray(e))return e.filter(t=>m(t));if(typeof e=="string"&&/\w+\+$/.test(e)){if(e=e.replace(/\+$/,""),m(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(/-$/,""),m(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(m(t)===!1)return console.error(`Vue3 Mq: ${t} is not a valid breakpoint key. Invalid range.`),o;if(m(r)===!1)return console.error(`Vue3 Mq: ${r} is not a valid breakpoint key. Invalid range.`),o;const i=n.value.findIndex(u=>u.name===t),l=n.value.findIndex(u=>u.name===r);return n.value.slice(i,l+1).map(u=>u.name)}else return typeof e=="string"&&m(e)===!0?[e]:o}else return o},E=(e,n)=>{const o=[];return!e&&!n?["landscape","portrait"]:(e&&o.push("landscape"),n&&o.push("portrait"),o)},L=(e,n)=>{const o=[];return!n&&!e?["light","dark"]:(n&&o.push("light"),e&&o.push("dark"),o)},j=(e,n)=>{const o=[];return!e&&!n?["reduce","no-preference"]:(e&&o.push("reduce"),n&&o.push("no-preference"),o)},M=Object.freeze(Object.defineProperty({__proto__:null,bootstrap3:{xs:0,sm:768,md:992,lg:1200},bootstrap4:{xs:0,sm:576,md:768,lg:992,xl:1200},bootstrap5:{xs:0,sm:576,md:768,lg:992,xl:1200,xxl:1400},devices:{phone:0,tablet:768,laptop:1370,desktop:1906},tailwind:{xs:0,sm:640,md:768,lg:1024,xl:1280,xxl:1536},vuetify:{xs:0,sm:600,md:960,lg:1264,xl:1904},vuetify3:{xs:0,sm:600,md:960,lg:1280,xl:1920,xxl:2560},wordpress:{mobile:0,small:600,medium:782,large:960,xlarge:1080,wide:1280,huge:1440}},Symbol.toStringTag,{value:"Module"})),ee=e=>{if(typeof e=="string"&&M[e])return M[e];{const n=Object.keys(M);return console.error(`Vue3 Mq: "${e}" is not a valid preset. Available options are: ${n.join(", ")}`),!1}},te=e=>["landscape","portrait"].includes(e)===!1?(console.error(`Vue3 Mq: "${e}" is not a valid default orientation. Reverting to unset value.`),null):e,ne=(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,oe=(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,P=e=>{if(!e||typeof e!="object")return!1;const n=[];for(let r in e){const i=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(!i&&i!==0||isNaN(i)||i<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:i})}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,i)=>r.min-i.min)},re=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},se={name:"fade",mode:"out-in"},_={name:"MqResponsive",props:{target:[String,Array],landscape:{type:Boolean,default:!1},portrait:{type:Boolean,default:!1},dark:{type:Boolean,default:!1},light:{type:Boolean,default:!1},inert:{type:Boolean,default:!1},motion:{type:Boolean,default:!1},tag:{type:String,default:"div"},listTag:{type:String,default:"div"},group:{type:Boolean,default:!1}},setup(e,{attrs:n,emit:o,slots:t}){const r=s.computed(()=>I(e.target,f)),i=s.computed(()=>E(e.landscape,e.portrait)),l=s.computed(()=>L(e.dark,e.light)),u=s.computed(()=>j(e.inert,e.motion)),h=s.computed(()=>r.value.includes(d.current)&&i.value.includes(d.orientation)&&l.value.includes(d.theme)&&u.value.includes(d.motionPreference)),w=p=>{if(!e.group&&t.length>0)return t;const g=[];for(let v in t){const{slotBp:le,slotOrientation:A,slotTheme:D,slotMotion:z}=re(v),ue=s.computed(()=>I(le,f)),ce=s.computed(()=>E(A==="landscape",A==="portrait")),de=s.computed(()=>L(D==="dark",D==="light")),fe=s.computed(()=>j(z==="inert",z==="motion"));s.computed(()=>ue.value.includes(d.current)&&ce.value.includes(d.orientation)&&de.value.includes(d.theme)&&fe.value.includes(d.motionPreference)).value===!0&&g.push(s.h(p||t[v],{key:v},p?t[v]():void 0))}return g.length>0?g:void 0};return t.default?()=>h.value?s.h(e.tag,{...n},t.default()):void 0:()=>{const p=Object.assign({},se,n,{tag:e.tag}),g=e.group?s.TransitionGroup:s.Transition;return s.h(g,p,()=>w(e.listTag))}}};function q({breakpoints:e,preset:n}){const o=n?ee(n):!1,t=e?P(e):!1;if(o===!1&&!t)throw new TypeError("Vue3 Mq: You must provide a valid preset, or valid breakpoint settings.");Z(t||P(o)),W(),U();const r=X();for(const i in r){const l=r[i];y(l,()=>{b(i)})}["portrait","landscape"].forEach(i=>{const l=()=>{R(i)};y(`(orientation: ${i})`,l)}),["light","dark"].forEach(i=>{const l=()=>{$(i)};y(`(prefers-color-scheme: ${i})`,l)}),["reduce","no-preference"].forEach(i=>{const l=()=>{O(i)};y(`(prefers-reduced-motion: ${i})`,l)})}function ie(){const e=s.inject("mq");if(e)return e;throw new Error("Vue3Mq is not installed in this app. Please follow the installation instructions and try again.")}const ae={install:(e,{preset:n="bootstrap5",breakpoints:o,defaultBreakpoint:t,defaultOrientation:r="landscape",defaultMotion:i="no-preference",defaultTheme:l,global:u=!1}={})=>{try{const h=te(r),w=ne(l),p=oe(i);F(t),G(h),J(w),H(p),e.provide("mq",d),e.provide("updateBreakpoints",q),u===!0&&(e.component("MqResponsive",_),e.config.globalProperties.$mq=d),q({breakpoints:o,preset:n})}catch(h){console.error(h)}}};c.MqResponsive=_,c.Vue3Mq=ae,c.availableBreakpoints=f,c.updateBreakpoints=q,c.useMq=ie,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});