diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7e45dcf --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: marcj diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..4f29079 --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +.idea +tests diff --git a/css-element-queries.d.ts b/css-element-queries.d.ts new file mode 100644 index 0000000..3fe0706 --- /dev/null +++ b/css-element-queries.d.ts @@ -0,0 +1,2 @@ +export { ResizeSensor, ResizeSensorCallback, Size } from "./src/ResizeSensor"; +export { ElementQueries } from './src/ElementQueries'; \ No newline at end of file diff --git a/package.json b/package.json index 154a842..964230f 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "css-element-queries", - "version": "1.1.1", + "version": "1.2.3", "description": "CSS-Element-Queries Polyfill. Proof-of-concept for high-speed element dimension/media queries in valid css.", "main": "index.js", + "typings": "css-element-queries.d.ts", "directories": { "test": "test" }, diff --git a/src/ElementQueries.d.ts b/src/ElementQueries.d.ts new file mode 100644 index 0000000..00c5d93 --- /dev/null +++ b/src/ElementQueries.d.ts @@ -0,0 +1,14 @@ +export declare class ElementQueries { + /** + * Attaches to DOMLoadContent + */ + static listen(): void; + + /** + * Parses all available CSS and attach ResizeSensor to those elements which have rules attached. + * Make sure this is called after 'load' event, because CSS files are not ready when domReady is fired. + */ + static init(): void; +} + +export default ElementQueries; diff --git a/src/ElementQueries.js b/src/ElementQueries.js index 23038d0..4fe4298 100755 --- a/src/ElementQueries.js +++ b/src/ElementQueries.js @@ -170,13 +170,12 @@ if (!element.elementQueriesSetupInformation) { element.elementQueriesSetupInformation = new SetupInformation(element, id); } + if (!element.elementQueriesSensor) { element.elementQueriesSensor = new ResizeSensor(element, function () { element.elementQueriesSetupInformation.call(); }); } - - element.elementQueriesSetupInformation.call(); } /** @@ -441,7 +440,7 @@ for (var i = 0, j = document.styleSheets.length; i < j; i++) { try { if (document.styleSheets[i].href && 0 === document.styleSheets[i].href.indexOf('file://')) { - console.log("CssElementQueries: unable to parse local css files, " + document.styleSheets[i].href); + console.warn("CssElementQueries: unable to parse local css files, " + document.styleSheets[i].href); } readRules(document.styleSheets[i].cssRules || document.styleSheets[i].rules || document.styleSheets[i].cssText); diff --git a/src/ResizeSensor.d.ts b/src/ResizeSensor.d.ts index b0a5fdf..3fba8c6 100644 --- a/src/ResizeSensor.d.ts +++ b/src/ResizeSensor.d.ts @@ -1,11 +1,37 @@ -export declare type ResizeSensorCallback = (size: { width: number; height: number; }) => void; +export declare interface Size { + width: number; + height: number; +} + +export declare type ResizeSensorCallback = (size: Size) => void; -declare class ResizeSensor { +export declare class ResizeSensor { + /** + * Creates a new resize sensor on given elements. The provided callback is called max 1 times per requestAnimationFrame and + * is called initially. + */ constructor(element: Element | Element[], callback: ResizeSensorCallback); + + /** + * Removes the resize sensor, and stops listening to resize events. + */ detach(callback?: ResizeSensorCallback): void; + + /** + * Resets the resize sensors, so for the next element resize is correctly detected. This is rare cases necessary + * when the resize sensor isn't initialised correctly or is in a broken state due to DOM modifications. + */ reset(): void; + /** + * Removes the resize sensor, and stops listening to resize events. + */ static detach(element: Element | Element[], callback?: ResizeSensorCallback): void; + + /** + * Resets the resize sensors, so for the next element resize is correctly detected. This is rare cases necessary + * when the resize sensor isn't initialised correctly or is in a broken state due to DOM modifications. + */ static reset(element: Element | Element[]): void; } diff --git a/src/ResizeSensor.js b/src/ResizeSensor.js index 555a906..9a25503 100755 --- a/src/ResizeSensor.js +++ b/src/ResizeSensor.js @@ -19,14 +19,28 @@ if (typeof window === "undefined") { return null; } + // https://github.com/Semantic-Org/Semantic-UI/issues/3855 + // https://github.com/marcj/css-element-queries/issues/257 + var globalWindow = typeof window != 'undefined' && window.Math == Math + ? window + : typeof self != 'undefined' && self.Math == Math + ? self + : Function('return this')(); // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor. // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and // would generate too many unnecessary events. - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || + var requestAnimationFrame = globalWindow.requestAnimationFrame || + globalWindow.mozRequestAnimationFrame || + globalWindow.webkitRequestAnimationFrame || function (fn) { - return window.setTimeout(fn, 20); + return globalWindow.setTimeout(fn, 20); + }; + + var cancelAnimationFrame = globalWindow.cancelAnimationFrame || + globalWindow.mozCancelAnimationFrame || + globalWindow.webkitCancelAnimationFrame || + function (timer) { + globalWindow.clearTimeout(timer); }; /** @@ -74,6 +88,18 @@ } } + /** + * Apply CSS styles to element. + * + * @param {HTMLElement} element + * @param {Object} style + */ + function setStyle(element, style) { + Object.keys(style).forEach(function(key) { + element.style[key] = style[key]; + }); + } + /** * Class for dimension change detection. * @@ -83,6 +109,9 @@ * @constructor */ var ResizeSensor = function(element, callback) { + //Is used when checking in reset() only for invisible elements + var lastAnimationFrameForInvisibleCheck = 0; + /** * * @constructor @@ -131,35 +160,64 @@ element.resizeSensor = document.createElement('div'); element.resizeSensor.dir = 'ltr'; element.resizeSensor.className = 'resize-sensor'; - var style = 'pointer-events: none; position: absolute; left: 0px; top: 0px; right: 0; bottom: 0; ' + - 'overflow: hidden; z-index: -1; visibility: hidden; max-width: 100%;'; - var styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;'; - - element.resizeSensor.style.cssText = style; - element.resizeSensor.innerHTML = - '
' + - '\ No newline at end of file +