Created
November 24, 2019 16:18
-
-
Save codev0/c92a0dbd22651f4ef7e8e7ced28cc77e to your computer and use it in GitHub Desktop.
Zurb Foundation mediaQuery utility on es6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { debounce } from 'debounce'; | |
const defaultQueries = { | |
'default': 'only screen', | |
landscape: 'only screen and (orientation: landscape)', | |
portrait: 'only screen and (orientation: portrait)', | |
retina: 'only screen and (-webkit-min-device-pixel-ratio: 2),' + | |
'only screen and (min--moz-device-pixel-ratio: 2),' + | |
'only screen and (-o-min-device-pixel-ratio: 2/1),' + | |
'only screen and (min-device-pixel-ratio: 2),' + | |
'only screen and (min-resolution: 192dpi),' + | |
'only screen and (min-resolution: 2dppx)' | |
}; | |
class MediaQuery { | |
constructor() { | |
this.queries = []; | |
this.current = ''; | |
this._init(); | |
} | |
/** | |
* Initializes the media query helper, by extracting the breakpoint list from the CSS and activating the breakpoint watcher. | |
* @function | |
* @private | |
*/ | |
_init() { | |
// make sure the initialization is only done once when calling _init() several times | |
if (this.isInitialized === true) { | |
return; | |
} else { | |
this.isInitialized = true; | |
} | |
const self = this; | |
const $meta = document.querySelector('meta.foundation-mq'); | |
if (!$meta.length) { | |
const node = document.createElement('meta'); | |
node.setAttribute('class', 'foundation-mq') | |
document.head.appendChild(node); | |
} | |
const extractedStyles = window.getComputedStyle(document.querySelector('meta.foundation-mq')).getPropertyValue('font-family') | |
let namedQueries; | |
namedQueries = this._parseStyleToObject(extractedStyles); | |
self.queries = []; // reset | |
for (let key in namedQueries) { | |
if (namedQueries.hasOwnProperty(key)) { | |
self.queries.push({ | |
name: key, | |
value: `only screen and (min-width: ${namedQueries[key]})` | |
}); | |
self.queries.push({ | |
name: `${key}-down`, | |
value: `only screen and (max-width: ${namedQueries[key]})` | |
}); | |
} | |
} | |
this.current = this._getCurrentSize(); | |
this._watcher(); | |
} | |
/** | |
* Reinitializes the media query helper. | |
* Useful if your CSS breakpoint configuration has just been loaded or has changed since the initialization. | |
* @function | |
* @private | |
*/ | |
_reInit() { | |
this.isInitialized = false; | |
this._init(); | |
} | |
/** | |
* Checks if the screen is at least as wide as a breakpoint. | |
* @function | |
* @param {String} size - Name of the breakpoint to check. | |
* @returns {Boolean} `true` if the breakpoint matches, `false` if it's smaller. | |
*/ | |
atLeast(size) { | |
const query = this.get(size); | |
if (query) { | |
return window.matchMedia(query).matches; | |
} | |
return false; | |
} | |
/** | |
* Checks if the screen matches to a breakpoint. | |
* @function | |
* @param {String} size - Name of the breakpoint to check, either 'small only' or 'small'. Omitting 'only' falls back to using atLeast() method. | |
* @returns {Boolean} `true` if the breakpoint matches, `false` if it does not. | |
*/ | |
is(size) { | |
size = size.trim().split(' '); | |
if (size.length > 1 && size[1] === 'only') { | |
if (size[0] === this._getCurrentSize()) return true; | |
} else { | |
return this.atLeast(size[0]); | |
} | |
return false; | |
} | |
/** | |
* Gets the media query of a breakpoint. | |
* @function | |
* @param {String} size - Name of the breakpoint to get. | |
* @returns {String|null} - The media query of the breakpoint, or `null` if the breakpoint doesn't exist. | |
*/ | |
get(size) { | |
for (let i in this.queries) { | |
if (this.queries.hasOwnProperty(i)) { | |
var query = this.queries[i]; | |
if (size === query.name) return query.value; | |
} | |
} | |
return null; | |
} | |
/** | |
* Gets the current breakpoint name by testing every breakpoint and returning the last one to match (the biggest one). | |
* @function | |
* @private | |
* @returns {String} Name of the current breakpoint. | |
*/ | |
_getCurrentSize() { | |
let matched; | |
for (let i = 0; i < this.queries.length; i++) { | |
let query = this.queries[i]; | |
if (window.matchMedia(query.value).matches) { | |
matched = query; | |
} | |
} | |
if (typeof matched === 'object') { | |
return matched.name; | |
} else { | |
return matched; | |
} | |
} | |
/** | |
* Activates the breakpoint watcher, which fires an event on the window whenever the breakpoint changes. | |
* @function | |
* @private | |
*/ | |
_watcher() { | |
const listener = debounce(() => { | |
let newSize = this._getCurrentSize(), currentSize = this.current; | |
if (newSize !== currentSize) { | |
const event = new CustomEvent('changed:mediaquery', [newSize, currentSize]); | |
// Change the current media query | |
this.current = newSize; | |
// Broadcast the media query change on the window | |
window.dispatchEvent(event); | |
} | |
}, 200); | |
window.removeEventListener('resize', listener); | |
window.addEventListener('resize', listener); | |
} | |
// Thank you: https://github.com/sindresorhus/query-string | |
_parseStyleToObject(str) { | |
let styleObject = {}; | |
if (typeof str !== 'string') { | |
return styleObject; | |
} | |
str = str.trim().slice(1, -1); // browsers re-quote string style values | |
if (!str) { | |
return styleObject; | |
} | |
styleObject = str.split('&').reduce(function (ret, param) { | |
let parts = param.replace(/\+/g, ' ').split('='); | |
let key = parts[0]; | |
let val = parts[1]; | |
key = decodeURIComponent(key); | |
// missing `=` should be `null`: | |
// http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters | |
val = typeof val === 'undefined' ? null : decodeURIComponent(val); | |
if (!ret.hasOwnProperty(key)) { | |
ret[key] = val; | |
} else if (Array.isArray(ret[key])) { | |
ret[key].push(val); | |
} else { | |
ret[key] = [ret[key], val]; | |
} | |
return ret; | |
}, {}); | |
return styleObject; | |
} | |
} | |
export { MediaQuery }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment