├── .gitignore
├── src
├── banner.js
├── ComputedStyleObserverEntry.js
├── index.js
├── ComputedStyleObserver.js
└── elementStateMonitor.js
├── package.json
├── LICENSE
├── dist
├── computedStyleObserver.min.js
├── computedStyleObserver.js
└── computedStyleObserver.js.map
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
--------------------------------------------------------------------------------
/src/banner.js:
--------------------------------------------------------------------------------
1 | /* ComputedStyleObserver | (C) Keith Clark | MIT | https://github.com/keithclark/ComputedStyleObserver */
2 |
--------------------------------------------------------------------------------
/src/ComputedStyleObserverEntry.js:
--------------------------------------------------------------------------------
1 | export default class {
2 | constructor(target, property, value, prevValue) {
3 | this.target = target;
4 | this.property = property;
5 | this.value = value;
6 | this.previousValue = prevValue;
7 | }
8 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import ComputedStyleObserver from './ComputedStyleObserver';
2 | import ComputedStyleObserverEntry from './ComputedStyleObserverEntry';
3 |
4 | window.ComputedStyleObserver = ComputedStyleObserver;
5 | window.ComputedStyleObserverEntry = ComputedStyleObserverEntry;
6 |
--------------------------------------------------------------------------------
/src/ComputedStyleObserver.js:
--------------------------------------------------------------------------------
1 | import {registerElement, unregisterElement, unregisterObserver} from './elementStateMonitor';
2 |
3 | let observers = new WeakMap();
4 |
5 | export default class {
6 |
7 | constructor(callback, properties = null) {
8 |
9 | if (Array.isArray(properties)) {
10 | properties = [...properties];
11 | }
12 |
13 | observers.set(this, {callback, properties});
14 | }
15 |
16 | disconnect() {
17 | unregisterObserver(observers.get(this));
18 | }
19 |
20 | observe(targetElement) {
21 | return registerElement(targetElement, observers.get(this));
22 | }
23 |
24 | unobserve(targetElement) {
25 | return unregisterElement(targetElement, observers.get(this));
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "computed-style-observer",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "dev": "rollup -f iife -m -i src/index.js -o dist/computedStyleObserver.js -w",
8 | "build": "rollup -f iife -m -i src/index.js -o dist/computedStyleObserver.js",
9 | "minify": "minify dist/computedStyleObserver.js | cat src/banner.js - > dist/computedStyleObserver.min.js",
10 | "dist": "npm run build && npm run minify"
11 | },
12 | "devDependencies": {
13 | "babel-cli": "^6.26.0",
14 | "babel-minify": "^0.5.0",
15 | "rollup": "^0.57.1"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/keithclark/ComputedStyleObserver.git"
20 | },
21 | "author": "Keith Clark",
22 | "bugs": {
23 | "url": "https://github.com/keithclark/ComputedStyleObserver/issues"
24 | },
25 | "homepage": "https://github.com/keithclark/ComputedStyleObserver#readme",
26 | "license": "MIT"
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Keith Clark
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/dist/computedStyleObserver.min.js:
--------------------------------------------------------------------------------
1 | /* ComputedStyleObserver | (C) Keith Clark | MIT | https://github.com/keithclark/ComputedStyleObserver */
2 | (function(){"use strict";const a=1,b=0;let c=b,d=new Map;const e=(b,e)=>{let f=d.get(b);return(f||(f={styles:{},observers:[]},d.set(b,f)),!f.observers.includes(e))&&(f.observers.push(e),c!==a&&(c=a,j()),!0)},f=(a,e)=>{let f=d.get(a);if(!f)return!1;let g=f.observers.indexOf(e);return-1!==g&&(f.observers.splice(g,1),0===f.observers.length&&d.delete(a),0===d.size&&(c=b),!0)},g=a=>{d.forEach((b,c)=>{b.observers.includes(a)&&f(c,a)})},h=()=>{d.forEach((a,b)=>{i(b,a)})},i=(a,b)=>{let c=getComputedStyle(a),d={};b.observers.forEach(e=>{let f=[];e.properties.forEach(e=>{let g=c[e],h=b.styles[e];g!==h&&h&&f.push(new ComputedStyleObserverEntry(a,e,g,h)),d[e]=g}),f.length&&e.callback(f)}),b.styles=d},j=()=>{c===a&&(requestAnimationFrame(j),h())};let k=new WeakMap;window.ComputedStyleObserver=class{constructor(a,b=null){Array.isArray(b)&&(b=[...b]),k.set(this,{callback:a,properties:b})}disconnect(){g(k.get(this))}observe(a){return e(a,k.get(this))}unobserve(a){return f(a,k.get(this))}},window.ComputedStyleObserverEntry=class{constructor(a,b,c,d){this.target=a,this.property=b,this.value=c,this.previousValue=d}}})();
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # A Computed Style Observer
2 |
3 | This prototype `ComputedStyleObserver` provides the ability to watch for changes being made to the style properties of DOM elements.
4 |
5 | ## Example
6 |
7 | ```html
8 |
17 |
18 |
19 | Hover over me and watch the console
20 |
21 |
22 |
23 |
24 |
25 |
39 | ```
40 |
41 | ## :warning: A note on performance
42 |
43 | Internally, `ComputedStyleObserver` calls `getComputedStyle` for each observed element, every animation frame. Since `getComputedStyle` will trigger a style recalc (and sometimes reflows), performance will suffer as the number of observed elements increases.
44 |
45 | ---
46 |
47 | ## ComputedStyleObserver
48 |
49 | ### Constructor
50 |
51 | #### `ComputedStyleObserver(callback, properties)`
52 |
53 | Creates and returns a new `ComputedStyleObserver` which will invoke a specified callback function when style changes for the given properties occur.
54 |
55 | The `callback` function will receive an array of `ComputedStyleObserverEntry` objects, one for each property change that occured.
56 |
57 | `properties` is an array of strings specifying which CSS property names should be
58 | observed. (i.e. "background-color", "border-radius" etc.)
59 |
60 | ### Methods
61 |
62 | #### `disconnect()`
63 |
64 | Prevents the `ComputedStyleObserver` instance from receiving further notifications until `observe()` is called again.
65 |
66 | #### `observe(targetElement)`
67 |
68 | Configures the `ComputedStyleObserver` instance to begin receiving notifications for the specificed `targetElement` through its callback function when style changes occur.
69 |
70 | #### `unobserve(targetElement)`
71 |
72 | Prevents the `ComputedStyleObserver` instance from receiving further notifications for the specificed `targetElement`.
73 |
74 |
75 | ## ComputedStyleObserverEntry
76 |
77 | A `ComputedStyleObserverEntry` represents an individual style mutation. It is the object that is passed to `ComputedStyleObserver`'s callback.
78 |
79 | ### Properties
80 |
81 | #### `target`
82 | The DOM node the mutation affected
83 |
84 | #### `property`
85 | The style property that mutated
86 |
87 | #### `value`
88 | The current value of the property
89 |
90 | #### `previousValue`
91 | The previous value of the property
92 |
93 |
94 | ---
95 |
96 | # Contributing
97 |
98 | ## Requirements
99 |
100 | * Node / NPM
101 |
102 | ## Setup
103 |
104 | 1) Clone this repo.
105 | 2) Install dependencies: `npm install`
106 | 3) Build the project with the watch task: `npm run dev`
107 | 4) Start editing...
108 |
109 | ## Other build options
110 |
111 | * `npm run dist` - builds the both the unminified and minified distribution files to the `/dist/` folder.
112 |
--------------------------------------------------------------------------------
/src/elementStateMonitor.js:
--------------------------------------------------------------------------------
1 | import './ComputedStyleObserverEntry';
2 |
3 | const POLLSTATE_RUNNING = 1;
4 | const POLLSTATE_STOPPED = 0;
5 |
6 |
7 | let pollState = POLLSTATE_STOPPED;
8 | let elements = new Map();
9 |
10 |
11 | /**
12 | * Registers an element and an observer.
13 | *
14 | * @param {DOMElement}
15 | * The element to watch
16 | * @param {ComputedStyleObserver}
17 | * Observer instance responsible for handling changes
18 | */
19 | const registerElement = (elem, observer) => {
20 | let state = elements.get(elem);
21 |
22 | if (!state) {
23 | state = {
24 | styles: {},
25 | observers: []
26 | }
27 | elements.set(elem, state);
28 | }
29 |
30 | // only allow an observer to watch an element once
31 | if (state.observers.includes(observer)) {
32 | return false;
33 | }
34 |
35 | state.observers.push(observer);
36 |
37 | // if we're not already polling the DOM, start now.
38 | if (pollState !== POLLSTATE_RUNNING) {
39 | pollState = POLLSTATE_RUNNING;
40 | poll();
41 | }
42 |
43 | return true;
44 | }
45 |
46 |
47 | /**
48 | *
49 | * @param {DOMElement}
50 | * The element to stop watching
51 | * @param {ComputedStyleObserver}
52 | * Observer instance responsible for handling changes
53 | */
54 | const unregisterElement = (elem, observer) => {
55 | let state = elements.get(elem);
56 | if (!state) {
57 | return false;
58 | }
59 |
60 | let index = state.observers.indexOf(observer);
61 |
62 | // if the observer doesn't exist, exit now
63 | if (index === -1) {
64 | return false;
65 | }
66 |
67 | state.observers.splice(index, 1);
68 |
69 | // remove the element from the map if it has no observers
70 | if (state.observers.length === 0) {
71 | elements.delete(elem);
72 | }
73 |
74 | // if the map is empty, stop polling the DOM
75 | if (elements.size === 0) {
76 | pollState = POLLSTATE_STOPPED;
77 | }
78 |
79 | return true;
80 | }
81 |
82 |
83 | /**
84 | * Stop watching all elements for a specific observer
85 | */
86 | const unregisterObserver = observer => {
87 | elements.forEach((state, element) => {
88 | if (state.observers.includes(observer)) {
89 | unregisterElement(element, observer);
90 | }
91 | })
92 | }
93 |
94 |
95 | /**
96 | * Updates the state of every currently observed element
97 | */
98 | const update = () => {
99 | elements.forEach((state, element) => {
100 | updateElementState(element, state);
101 | });
102 | }
103 |
104 |
105 | /**
106 | * Determines if the `computedStyle` of the passed element has changed since
107 | * this function was last called. Any changes in `computedStyle` are filtered
108 | * against the property list of each ComputedStyleObserver and, if any
109 | * relevant changes exist, the observer callback is invoked with a list of
110 | * `ComputedStyleObserverEntry` objects.
111 | *
112 | * @param {DOMElement} elem
113 | * The element to update
114 | * @param {Object} state
115 | * The element's state object
116 | */
117 | const updateElementState = (elem, state) => {
118 | let styles = getComputedStyle(elem);
119 | let newValues = {};
120 |
121 | state.observers.forEach(observer => {
122 | let changes = [];
123 |
124 | observer.properties.forEach(property => {
125 | let value = styles[property];
126 | let previousValue = state.styles[property];
127 | if (value !== previousValue) {
128 | if (previousValue) {
129 | changes.push(new ComputedStyleObserverEntry(
130 | elem,
131 | property,
132 | value,
133 | previousValue
134 | ));
135 | }
136 | }
137 | newValues[property] = value;
138 | });
139 |
140 | if (changes.length) {
141 | observer.callback(changes);
142 | }
143 | })
144 |
145 | state.styles = newValues;
146 | }
147 |
148 |
149 | /**
150 | * Start watching elements for changes.
151 | */
152 | const poll = () => {
153 | if (pollState === POLLSTATE_RUNNING) {
154 | requestAnimationFrame(poll);
155 | update();
156 | }
157 | }
158 |
159 |
160 | export {
161 | registerElement,
162 | unregisterElement,
163 | unregisterObserver
164 | }
165 |
--------------------------------------------------------------------------------
/dist/computedStyleObserver.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | class ComputedStyleObserverEntry$1 {
5 | constructor(target, property, value, prevValue) {
6 | this.target = target;
7 | this.property = property;
8 | this.value = value;
9 | this.previousValue = prevValue;
10 | }
11 | }
12 |
13 | const POLLSTATE_RUNNING = 1;
14 | const POLLSTATE_STOPPED = 0;
15 |
16 |
17 | let pollState = POLLSTATE_STOPPED;
18 | let elements = new Map();
19 |
20 |
21 | /**
22 | * Registers an element and an observer.
23 | *
24 | * @param {DOMElement}
25 | * The element to watch
26 | * @param {ComputedStyleObserver}
27 | * Observer instance responsible for handling changes
28 | */
29 | const registerElement = (elem, observer) => {
30 | let state = elements.get(elem);
31 |
32 | if (!state) {
33 | state = {
34 | styles: {},
35 | observers: []
36 | };
37 | elements.set(elem, state);
38 | }
39 |
40 | // only allow an observer to watch an element once
41 | if (state.observers.includes(observer)) {
42 | return false;
43 | }
44 |
45 | state.observers.push(observer);
46 |
47 | // if we're not already polling the DOM, start now.
48 | if (pollState !== POLLSTATE_RUNNING) {
49 | pollState = POLLSTATE_RUNNING;
50 | poll();
51 | }
52 |
53 | return true;
54 | };
55 |
56 |
57 | /**
58 | *
59 | * @param {DOMElement}
60 | * The element to stop watching
61 | * @param {ComputedStyleObserver}
62 | * Observer instance responsible for handling changes
63 | */
64 | const unregisterElement = (elem, observer) => {
65 | let state = elements.get(elem);
66 | if (!state) {
67 | return false;
68 | }
69 |
70 | let index = state.observers.indexOf(observer);
71 |
72 | // if the observer doesn't exist, exit now
73 | if (index === -1) {
74 | return false;
75 | }
76 |
77 | state.observers.splice(index, 1);
78 |
79 | // remove the element from the map if it has no observers
80 | if (state.observers.length === 0) {
81 | elements.delete(elem);
82 | }
83 |
84 | // if the map is empty, stop polling the DOM
85 | if (elements.size === 0) {
86 | pollState = POLLSTATE_STOPPED;
87 | }
88 |
89 | return true;
90 | };
91 |
92 |
93 | /**
94 | * Stop watching all elements for a specific observer
95 | */
96 | const unregisterObserver = observer => {
97 | elements.forEach((state, element) => {
98 | if (state.observers.includes(observer)) {
99 | unregisterElement(element, observer);
100 | }
101 | });
102 | };
103 |
104 |
105 | /**
106 | * Updates the state of every currently observed element
107 | */
108 | const update = () => {
109 | elements.forEach((state, element) => {
110 | updateElementState(element, state);
111 | });
112 | };
113 |
114 |
115 | /**
116 | * Determines if the `computedStyle` of the passed element has changed since
117 | * this function was last called. Any changes in `computedStyle` are filtered
118 | * against the property list of each ComputedStyleObserver and, if any
119 | * relevant changes exist, the observer callback is invoked with a list of
120 | * `ComputedStyleObserverEntry` objects.
121 | *
122 | * @param {DOMElement} elem
123 | * The element to update
124 | * @param {Object} state
125 | * The element's state object
126 | */
127 | const updateElementState = (elem, state) => {
128 | let styles = getComputedStyle(elem);
129 | let newValues = {};
130 |
131 | state.observers.forEach(observer => {
132 | let changes = [];
133 |
134 | observer.properties.forEach(property => {
135 | let value = styles[property];
136 | let previousValue = state.styles[property];
137 | if (value !== previousValue) {
138 | if (previousValue) {
139 | changes.push(new ComputedStyleObserverEntry(
140 | elem,
141 | property,
142 | value,
143 | previousValue
144 | ));
145 | }
146 | }
147 | newValues[property] = value;
148 | });
149 |
150 | if (changes.length) {
151 | observer.callback(changes);
152 | }
153 | });
154 |
155 | state.styles = newValues;
156 | };
157 |
158 |
159 | /**
160 | * Start watching elements for changes.
161 | */
162 | const poll = () => {
163 | if (pollState === POLLSTATE_RUNNING) {
164 | requestAnimationFrame(poll);
165 | update();
166 | }
167 | };
168 |
169 | let observers = new WeakMap();
170 |
171 | class ComputedStyleObserver {
172 |
173 | constructor(callback, properties = null) {
174 |
175 | if (Array.isArray(properties)) {
176 | properties = [...properties];
177 | }
178 |
179 | observers.set(this, {callback, properties});
180 | }
181 |
182 | disconnect() {
183 | unregisterObserver(observers.get(this));
184 | }
185 |
186 | observe(targetElement) {
187 | return registerElement(targetElement, observers.get(this));
188 | }
189 |
190 | unobserve(targetElement) {
191 | return unregisterElement(targetElement, observers.get(this));
192 | }
193 |
194 | }
195 |
196 | window.ComputedStyleObserver = ComputedStyleObserver;
197 | window.ComputedStyleObserverEntry = ComputedStyleObserverEntry$1;
198 |
199 | }());
200 | //# sourceMappingURL=computedStyleObserver.js.map
201 |
--------------------------------------------------------------------------------
/dist/computedStyleObserver.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"computedStyleObserver.js","sources":["../src/ComputedStyleObserverEntry.js","../src/elementStateMonitor.js","../src/ComputedStyleObserver.js","../src/index.js"],"sourcesContent":["export default class {\n constructor(target, property, value, prevValue) {\n this.target = target;\n this.property = property;\n this.value = value;\n this.previousValue = prevValue;\n }\n}","import './ComputedStyleObserverEntry';\n\nconst POLLSTATE_RUNNING = 1;\nconst POLLSTATE_STOPPED = 0;\n\n\nlet pollState = POLLSTATE_STOPPED;\nlet elements = new Map();\n\n\n/**\n * Registers an element and an observer.\n * \n * @param {DOMElement}\n * The element to watch\n * @param {ComputedStyleObserver} \n * Observer instance responsible for handling changes\n */\nconst registerElement = (elem, observer) => {\n let state = elements.get(elem);\n\n if (!state) {\n state = {\n styles: {},\n observers: []\n }\n elements.set(elem, state);\n }\n\n // only allow an observer to watch an element once\n if (state.observers.includes(observer)) {\n return false;\n }\n\n state.observers.push(observer);\n\n // if we're not already polling the DOM, start now.\n if (pollState !== POLLSTATE_RUNNING) {\n pollState = POLLSTATE_RUNNING;\n poll();\n }\n\n return true;\n}\n\n\n/**\n * \n * @param {DOMElement}\n * The element to stop watching\n * @param {ComputedStyleObserver}\n * Observer instance responsible for handling changes\n */\nconst unregisterElement = (elem, observer) => {\n let state = elements.get(elem);\n if (!state) {\n return false;\n }\n\n let index = state.observers.indexOf(observer);\n\n // if the observer doesn't exist, exit now\n if (index === -1) {\n return false;\n }\n\n state.observers.splice(index, 1);\n\n // remove the element from the map if it has no observers\n if (state.observers.length === 0) {\n elements.delete(elem);\n }\n\n // if the map is empty, stop polling the DOM\n if (elements.size === 0) {\n pollState = POLLSTATE_STOPPED;\n }\n\n return true;\n}\n\n\n/**\n * Stop watching all elements for a specific observer\n */\nconst unregisterObserver = observer => {\n elements.forEach((state, element) => {\n if (state.observers.includes(observer)) {\n unregisterElement(element, observer);\n }\n })\n}\n\n\n/**\n * Updates the state of every currently observed element\n */\nconst update = () => {\n elements.forEach((state, element) => {\n updateElementState(element, state);\n });\n}\n\n\n/**\n * Determines if the `computedStyle` of the passed element has changed since\n * this function was last called. Any changes in `computedStyle` are filtered\n * against the property list of each ComputedStyleObserver and, if any\n * relevant changes exist, the observer callback is invoked with a list of\n * `ComputedStyleObserverEntry` objects.\n * \n * @param {DOMElement} elem\n * The element to update\n * @param {Object} state\n * The element's state object\n */\nconst updateElementState = (elem, state) => {\n let styles = getComputedStyle(elem);\n let newValues = {};\n\n state.observers.forEach(observer => {\n let changes = [];\n \n observer.properties.forEach(property => {\n let value = styles[property];\n let previousValue = state.styles[property];\n if (value !== previousValue) {\n if (previousValue) {\n changes.push(new ComputedStyleObserverEntry(\n elem,\n property,\n value,\n previousValue\n ));\n }\n }\n newValues[property] = value;\n });\n\n if (changes.length) {\n observer.callback(changes);\n }\n })\n\n state.styles = newValues;\n}\n\n\n/**\n * Start watching elements for changes.\n */\nconst poll = () => {\n if (pollState === POLLSTATE_RUNNING) {\n requestAnimationFrame(poll);\n update();\n }\n}\n\n\nexport {\n registerElement,\n unregisterElement,\n unregisterObserver\n}\n","import {registerElement, unregisterElement, unregisterObserver} from './elementStateMonitor';\n\nlet observers = new WeakMap();\n\nexport default class {\n\n constructor(callback, properties = null) {\n\n if (Array.isArray(properties)) {\n properties = [...properties];\n }\n\n observers.set(this, {callback, properties});\n }\n\n disconnect() {\n unregisterObserver(observers.get(this));\n }\n\n observe(targetElement) {\n return registerElement(targetElement, observers.get(this));\n }\n\n unobserve(targetElement) {\n return unregisterElement(targetElement, observers.get(this));\n }\n\n}\n","import ComputedStyleObserver from './ComputedStyleObserver';\nimport ComputedStyleObserverEntry from './ComputedStyleObserverEntry';\n\nwindow.ComputedStyleObserver = ComputedStyleObserver;\nwindow.ComputedStyleObserverEntry = ComputedStyleObserverEntry;\n"],"names":["ComputedStyleObserverEntry"],"mappings":"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"}
--------------------------------------------------------------------------------