Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Commit

Permalink
0.3.3
Browse files Browse the repository at this point in the history
  • Loading branch information
daniandl committed Sep 16, 2020
1 parent f216395 commit 2c415a8
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 23 deletions.
22 changes: 11 additions & 11 deletions dist/element-queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else {
var a = factory();
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
else if(typeof exports === 'object')
exports["ElementQueries"] = factory();
else
root["ElementQueries"] = factory();
})(window, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
Expand Down Expand Up @@ -100,23 +100,23 @@ return /******/ (function(modules) { // webpackBootstrap
/*!*******************************!*\
!*** ./src/ElementQueries.js ***!
\*******************************/
/*! exports provided: ElementQueries */
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"ElementQueries\", function() { return ElementQueries; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.js\");\n\n\nconst DEFAULT_OPTS = {\n htmlAttrBreakpoints: 'data-eq-breakpoints',\n htmlAttrActive: 'data-eq-active',\n}\n\nclass ElementQueries {\n constructor(opts) {\n this.opts = Object.freeze({ ...DEFAULT_OPTS, ...opts })\n\n this.observer = new ResizeObserver(this.onResize.bind(this))\n this.elements = new WeakMap()\n\n // wait for document load\n if (/complete|interactive|loaded/.test(document.readyState)) {\n this.onDocumentLoad()\n } else {\n document.addEventListener('DOMContentLoaded', this.onDocumentLoad.bind(this), { once: true })\n }\n }\n\n // Internal\n onDocumentLoad() {\n this.init()\n\n this.domObserver = new MutationObserver(this.onDomMutation.bind(this))\n this.domObserver.observe(document.body, { childList: true, subtree: true })\n }\n\n init() {\n const elements = document.querySelectorAll(`[${this.opts.htmlAttrBreakpoints}]`)\n\n for (const element of elements) {\n try {\n this.watch(element)\n } catch (error) {\n console.error(error, element)\n }\n }\n }\n\n onResize(entries) {\n const toUpdate = new Set()\n\n // eslint-disable-next-line no-var\n for (var i = entries.length - 1; i >= 0; i--) {\n const { target: element, borderBoxSize } = entries[i]\n\n if (this.elements.has(element)) {\n let width\n let height\n\n if (borderBoxSize && borderBoxSize[0]) {\n width = borderBoxSize[0].inlineSize\n height = borderBoxSize[0].blockSize\n } else {\n // fallback for Safari\n const rect = element.getBoundingClientRect()\n width = rect.width\n height = rect.height\n }\n\n const elementsEntry = this.elements.get(element)\n this.elements.set(element, { ...elementsEntry, ...{ width, height } })\n toUpdate.add(element)\n }\n }\n\n this.update([...toUpdate])\n }\n\n onDomMutation(mutations) {\n // eslint-disable-next-line no-var\n for (var i = mutations.length - 1; i >= 0; i--) {\n if (mutations[i].addedNodes.length) {\n // eslint-disable-next-line no-var\n for (var k = mutations[i].addedNodes.length - 1; k >= 0; k--) {\n const element = mutations[i].addedNodes[k]\n if (\n element instanceof HTMLElement\n && element.hasAttribute(this.opts.htmlAttrBreakpoints)\n ) {\n try {\n this.watch(element)\n } catch (e) {\n console.error(e, element)\n }\n }\n }\n }\n }\n }\n\n // Methods & Helpers\n /**\n * Watch an element manually\n * @param {HTMLElement} element The DOM element you would like to watch\n */\n watch(element) {\n if (!element || !(element instanceof HTMLElement)) throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].INVALID_ELEMENT)\n if (!element.hasAttribute(this.opts.htmlAttrBreakpoints)) {\n throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].BREAKPOINTS_MISSING)\n }\n\n const breakpointString = Object(_utils__WEBPACK_IMPORTED_MODULE_0__[\"removeWhitespace\"])(element.getAttribute(this.opts.htmlAttrBreakpoints))\n const breakpointMatches = [...breakpointString.matchAll(_utils__WEBPACK_IMPORTED_MODULE_0__[\"BREAKPOINT_REGEX\"])]\n\n if (!breakpointMatches.length) throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].BREAKPOINTS_MISSING)\n\n const breakpoints = breakpointMatches.reduce((acc, match) => {\n if (!match[1] || !match[2]) return acc\n\n acc[match[1]] = +match[2]\n return acc\n }, {})\n\n this.elements.set(element, { breakpoints })\n this.observer.observe(element, { box: 'border-box' })\n }\n\n /**\n * Updates the given elements according to their internal state (eq.elements)\n * @param {Array} elements Array of DOM elements\n */\n update(elements) {\n if (\n !elements\n || !Array.isArray(elements)\n || !elements.length\n || !elements.every(el => el instanceof HTMLElement)\n ) throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].INVALID_ELEMENTS)\n\n // eslint-disable-next-line no-var\n for (var i = elements.length - 1; i >= 0; i--) {\n const element = elements[i]\n\n const entry = this.elements.get(element)\n if (entry && entry.breakpoints) {\n const { width } = entry\n let active = null\n\n const bpsFlipped = Object(_utils__WEBPACK_IMPORTED_MODULE_0__[\"flipObject\"])(entry.breakpoints)\n const bpWidths = Object.values(entry.breakpoints).sort() // sort ASC\n const bpLargest = bpWidths[bpWidths.length - 1]\n\n if (width >= bpLargest) {\n active = bpsFlipped[bpLargest]\n } else if (width > bpWidths[0]) {\n for (let k = 0; k < bpWidths.length; k++) {\n const bpWidth = bpWidths[k]\n\n if (width >= bpWidth) {\n active = bpsFlipped[bpWidth]\n }\n }\n }\n\n if (active) {\n element.setAttribute(this.opts.htmlAttrActive, active)\n continue\n }\n }\n\n element.removeAttribute(this.opts.htmlAttrActive)\n }\n }\n\n /**\n * Disconnects all observers and clears element references\n */\n destroy() {\n if (this.observer) this.observer.disconnect()\n if (this.domObserver) this.domObserver.disconnect()\n\n this.elements = new WeakMap()\n }\n}\n\n\n//# sourceURL=webpack:///./src/ElementQueries.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return ElementQueries; });\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils */ \"./src/utils.js\");\n\n\nconst DEFAULT_OPTS = {\n htmlAttrBreakpoints: 'data-eq-breakpoints',\n htmlAttrActive: 'data-eq-active',\n}\n\nclass ElementQueries {\n constructor(opts) {\n this.opts = Object.freeze({ ...DEFAULT_OPTS, ...opts })\n\n this.observer = new ResizeObserver(this.onResize.bind(this))\n this.elements = new WeakMap()\n\n // wait for document load\n if (/complete|interactive|loaded/.test(document.readyState)) {\n this.onDocumentLoad()\n } else {\n document.addEventListener('DOMContentLoaded', this.onDocumentLoad.bind(this), { once: true })\n }\n }\n\n // Internal\n onDocumentLoad() {\n this.init()\n\n this.domObserver = new MutationObserver(this.onDomMutation.bind(this))\n this.domObserver.observe(document.body, { childList: true, subtree: true })\n }\n\n init() {\n const elements = document.querySelectorAll(`[${this.opts.htmlAttrBreakpoints}]`)\n\n for (const element of elements) {\n try {\n this.watch(element)\n } catch (error) {\n console.error(error, element)\n }\n }\n }\n\n onResize(entries) {\n const toUpdate = new Set()\n\n // eslint-disable-next-line no-var\n for (var i = entries.length - 1; i >= 0; i--) {\n const { target: element, borderBoxSize } = entries[i]\n\n if (this.elements.has(element)) {\n let width\n let height\n\n if (borderBoxSize && borderBoxSize[0]) {\n width = borderBoxSize[0].inlineSize\n height = borderBoxSize[0].blockSize\n } else {\n // fallback for Safari\n const rect = element.getBoundingClientRect()\n width = rect.width\n height = rect.height\n }\n\n const elementsEntry = this.elements.get(element)\n this.elements.set(element, { ...elementsEntry, ...{ width, height } })\n toUpdate.add(element)\n }\n }\n\n this.update([...toUpdate])\n }\n\n onDomMutation(mutations) {\n // eslint-disable-next-line no-var\n for (var i = mutations.length - 1; i >= 0; i--) {\n if (mutations[i].addedNodes.length) {\n // eslint-disable-next-line no-var\n for (var k = mutations[i].addedNodes.length - 1; k >= 0; k--) {\n const element = mutations[i].addedNodes[k]\n if (\n element instanceof HTMLElement\n && element.hasAttribute(this.opts.htmlAttrBreakpoints)\n ) {\n try {\n this.watch(element)\n } catch (e) {\n console.error(e, element)\n }\n }\n }\n }\n }\n }\n\n // Methods & Helpers\n /**\n * Watch an element manually\n * @param {HTMLElement} element The DOM element you would like to watch\n */\n watch(element) {\n if (!element || !(element instanceof HTMLElement)) throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].INVALID_ELEMENT)\n if (!element.hasAttribute(this.opts.htmlAttrBreakpoints)) {\n throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].BREAKPOINTS_MISSING)\n }\n\n const breakpointString = Object(_utils__WEBPACK_IMPORTED_MODULE_0__[\"removeWhitespace\"])(element.getAttribute(this.opts.htmlAttrBreakpoints))\n const breakpointMatches = [...breakpointString.matchAll(_utils__WEBPACK_IMPORTED_MODULE_0__[\"BREAKPOINT_REGEX\"])]\n\n if (!breakpointMatches.length) throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].BREAKPOINTS_MISSING)\n\n const breakpoints = breakpointMatches.reduce((acc, match) => {\n if (!match[1] || !match[2]) return acc\n\n acc[match[1]] = +match[2]\n return acc\n }, {})\n\n this.elements.set(element, { breakpoints })\n this.observer.observe(element, { box: 'border-box' })\n }\n\n /**\n * Updates the given elements according to their internal state (eq.elements)\n * @param {Array} elements Array of DOM elements\n */\n update(elements) {\n if (\n !elements\n || !Array.isArray(elements)\n || !elements.length\n || !elements.every(el => el instanceof HTMLElement)\n ) throw new Error(_utils__WEBPACK_IMPORTED_MODULE_0__[\"Errors\"].INVALID_ELEMENTS)\n\n // eslint-disable-next-line no-var\n for (var i = elements.length - 1; i >= 0; i--) {\n const element = elements[i]\n\n const entry = this.elements.get(element)\n if (entry && entry.breakpoints) {\n const { width } = entry\n let active = null\n\n const bpsFlipped = Object(_utils__WEBPACK_IMPORTED_MODULE_0__[\"flipObject\"])(entry.breakpoints)\n const bpWidths = Object.values(entry.breakpoints).sort() // sort ASC\n const bpLargest = bpWidths[bpWidths.length - 1]\n\n if (width >= bpLargest) {\n active = bpsFlipped[bpLargest]\n } else if (width > bpWidths[0]) {\n for (let k = 0; k < bpWidths.length; k++) {\n const bpWidth = bpWidths[k]\n\n if (width >= bpWidth) {\n active = bpsFlipped[bpWidth]\n }\n }\n }\n\n if (active) {\n element.setAttribute(this.opts.htmlAttrActive, active)\n continue\n }\n }\n\n element.removeAttribute(this.opts.htmlAttrActive)\n }\n }\n\n /**\n * Disconnects all observers and clears element references\n */\n destroy() {\n if (this.observer) this.observer.disconnect()\n if (this.domObserver) this.domObserver.disconnect()\n\n this.elements = new WeakMap()\n }\n}\n\n\n//# sourceURL=webpack://ElementQueries/./src/ElementQueries.js?");

/***/ }),

/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/*! exports provided: ElementQueries */
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ElementQueries__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ElementQueries */ \"./src/ElementQueries.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"ElementQueries\", function() { return _ElementQueries__WEBPACK_IMPORTED_MODULE_0__[\"ElementQueries\"]; });\n\n\n\n/** TODOs\n * TODO move this out of here :)\n * TODO allow passing breakpoint object to .watch() which overrides htmlAttrBreakpoints\n * TODO Support HTMLElement *AND* SVGElement\n * TODO disable if ResizeObserver isnt supported\n * TODO config option: dom observing on/off\n * NOTE general browser-support checks (MutationObserver, etc)\n * NOTE batching resize updates?\n * NOTE throttle observer?\n * NOTE debounce updates on a per-element basis?\n * NOTE use requestAnimationFrame on resize callback?\n * NOTE what do if user changes htmlAttrBreakpoints dynamically\n */\n\n\n//# sourceURL=webpack:///./src/index.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _ElementQueries__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ElementQueries */ \"./src/ElementQueries.js\");\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (_ElementQueries__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n/** TODOs\n * TODO move this out of here :)\n * TODO allow passing breakpoint object to .watch() which overrides htmlAttrBreakpoints\n * TODO Support HTMLElement *AND* SVGElement\n * TODO disable if ResizeObserver isnt supported\n * TODO config option: dom observing on/off\n * NOTE general browser-support checks (MutationObserver, etc)\n * NOTE batching resize updates?\n * NOTE throttle observer?\n * NOTE debounce updates on a per-element basis?\n * NOTE use requestAnimationFrame on resize callback?\n * NOTE what do if user changes htmlAttrBreakpoints dynamically\n */\n\n\n//# sourceURL=webpack://ElementQueries/./src/index.js?");

/***/ }),

Expand All @@ -128,7 +128,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Ele
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BREAKPOINT_REGEX\", function() { return BREAKPOINT_REGEX; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Errors\", function() { return Errors; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"removeWhitespace\", function() { return removeWhitespace; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"flipObject\", function() { return flipObject; });\n// Constants\nconst BREAKPOINT_REGEX = /([_A-z]+[A-z0-9-_]+):(\\d+)/g\n\nconst Errors = {\n INVALID_ELEMENT: 'Please provide a HTMLElement',\n INVALID_ELEMENTS: 'Please provide an array of HTMLElements',\n BREAKPOINTS_MISSING: 'No breakpoints found on element',\n}\n\n// Functions\nconst removeWhitespace = str => str.replace(/ /g, '')\nconst flipObject = o => Object.entries(o)\n .reduce((r, [k, v]) => Object.assign(r, { [v]: k }), {})\n\n\n//# sourceURL=webpack:///./src/utils.js?");
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"BREAKPOINT_REGEX\", function() { return BREAKPOINT_REGEX; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Errors\", function() { return Errors; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"removeWhitespace\", function() { return removeWhitespace; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"flipObject\", function() { return flipObject; });\n// Constants\nconst BREAKPOINT_REGEX = /([_A-z]+[A-z0-9-_]+):(\\d+)/g\n\nconst Errors = {\n INVALID_ELEMENT: 'Please provide a HTMLElement',\n INVALID_ELEMENTS: 'Please provide an array of HTMLElements',\n BREAKPOINTS_MISSING: 'No breakpoints found on element',\n}\n\n// Functions\nconst removeWhitespace = str => str.replace(/ /g, '')\nconst flipObject = o => Object.entries(o)\n .reduce((r, [k, v]) => Object.assign(r, { [v]: k }), {})\n\n\n//# sourceURL=webpack://ElementQueries/./src/utils.js?");

/***/ }),

Expand All @@ -139,9 +139,9 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

eval("module.exports = __webpack_require__(/*! ./src/index.js */\"./src/index.js\");\n\n\n//# sourceURL=webpack:///multi_./src/index.js?");
eval("module.exports = __webpack_require__(/*! ./src/index.js */\"./src/index.js\");\n\n\n//# sourceURL=webpack://ElementQueries/multi_./src/index.js?");

/***/ })

/******/ });
/******/ })["default"];
});
Loading

0 comments on commit 2c415a8

Please sign in to comment.