From 70de8f25f04a64c850018649a4c88e6d94594dfb Mon Sep 17 00:00:00 2001
From: Gabe Klein <gabe@termtm.com>
Date: Fri, 25 Sep 2020 16:25:28 -0600
Subject: [PATCH 1/6] simplify checking for observedNodes' changes

---
 src/index.ts | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index 0dffc73..f2f42a8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,30 +1,20 @@
-let props: (keyof DOMRect)[] = [
-	"bottom",
-	"height",
-	"left",
-	"right",
-	"top",
-	"width",
-];
-
-let rectChanged = (a: DOMRect = {} as DOMRect, b: DOMRect = {} as DOMRect) =>
-	props.some((prop) => a[prop] !== b[prop]);
+let COMPARE_KEYS = [
+	"bottom", "height", "left", "right", "top", "width"
+] as const;
 
 let observedNodes = new Map<Element, RectProps>();
 let rafId: number;
 
 let run = () => {
-	const changedStates: RectProps[] = [];
 	observedNodes.forEach((state, node) => {
 		let newRect = node.getBoundingClientRect();
-		if (rectChanged(newRect, state.rect)) {
-			state.rect = newRect;
-			changedStates.push(state);
-		}
-	});
 
-	changedStates.forEach((state) => {
-		state.callbacks.forEach((cb) => cb(state.rect));
+		for(const key of COMPARE_KEYS)
+			if(newRect[key] !== (state.rect || {})[key]){
+				state.rect = newRect;
+				state.callbacks.forEach(cb => cb(state.rect))
+				break;
+			}
 	});
 
 	rafId = window.requestAnimationFrame(run);

From 234afce3dab4cb07e6446b8ab75acd7486f304b6 Mon Sep 17 00:00:00 2001
From: Gabe Klein <gabe@termtm.com>
Date: Fri, 25 Sep 2020 16:27:48 -0600
Subject: [PATCH 2/6] tighten up types

---
 src/index.ts | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index f2f42a8..dace80c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,8 @@
+type RectProps = {
+	rect: DOMRect;
+	callbacks: Function[];
+};
+
 let COMPARE_KEYS = [
 	"bottom", "height", "left", "right", "top", "width"
 ] as const;
@@ -10,7 +15,7 @@ let run = () => {
 		let newRect = node.getBoundingClientRect();
 
 		for(const key of COMPARE_KEYS)
-			if(newRect[key] !== (state.rect || {})[key]){
+			if(newRect[key] !== state.rect[key]){
 				state.rect = newRect;
 				state.callbacks.forEach(cb => cb(state.rect))
 				break;
@@ -31,8 +36,7 @@ export default function observeRect(
 				observedNodes.get(node)!.callbacks.push(cb);
 			} else {
 				observedNodes.set(node, {
-					rect: undefined,
-					hasRectChanged: false,
+					rect: {} as any,
 					callbacks: [cb],
 				});
 			}
@@ -54,12 +58,4 @@ export default function observeRect(
 			}
 		},
 	};
-}
-
-export type PartialRect = Partial<DOMRect>;
-
-export type RectProps = {
-	rect: DOMRect | undefined;
-	hasRectChanged: boolean;
-	callbacks: Function[];
-};
+}
\ No newline at end of file

From 423ab4ae3e8ab72fa33f64748c173d95eee81f9f Mon Sep 17 00:00:00 2001
From: Gabe Klein <gabe@termtm.com>
Date: Fri, 25 Sep 2020 16:34:35 -0600
Subject: [PATCH 3/6] optimize main loop

---
 src/index.ts | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index dace80c..fa75ba4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -8,22 +8,25 @@ let COMPARE_KEYS = [
 ] as const;
 
 let observedNodes = new Map<Element, RectProps>();
-let rafId: number;
+let active: boolean;
 
-let run = () => {
-	observedNodes.forEach((state, node) => {
-		let newRect = node.getBoundingClientRect();
+function checkForUpdates(){
+	if(active){
+		observedNodes.forEach(assertDidUpdate);
+		window.requestAnimationFrame(checkForUpdates);
+	}
+};
 
-		for(const key of COMPARE_KEYS)
-			if(newRect[key] !== state.rect[key]){
-				state.rect = newRect;
-				state.callbacks.forEach(cb => cb(state.rect))
-				break;
-			}
-	});
+function assertDidUpdate(state: RectProps, node: Element){
+	let newRect = node.getBoundingClientRect();
 
-	rafId = window.requestAnimationFrame(run);
-};
+	for(const key of COMPARE_KEYS)
+		if(newRect[key] !== state.rect[key]){
+			state.rect = newRect;
+			state.callbacks.forEach(cb => cb(state.rect))
+			break;
+		}
+}
 
 export default function observeRect(
 	node: Element,
@@ -40,7 +43,10 @@ export default function observeRect(
 					callbacks: [cb],
 				});
 			}
-			if (wasEmpty) run();
+			if (wasEmpty) {
+				active = true;
+				checkForUpdates();
+			}
 		},
 
 		unobserve() {
@@ -54,7 +60,8 @@ export default function observeRect(
 				if (!state.callbacks.length) observedNodes.delete(node);
 
 				// Stop the loop
-				if (!observedNodes.size) cancelAnimationFrame(rafId);
+				if (!observedNodes.size)
+					active = false;
 			}
 		},
 	};

From 57101bd562006bb337319a58bfd33e7a5aae1fda Mon Sep 17 00:00:00 2001
From: Gabe Klein <gabe@termtm.com>
Date: Fri, 25 Sep 2020 16:39:53 -0600
Subject: [PATCH 4/6] store callbacks in a Set instead of array

---
 src/index.ts | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index fa75ba4..adcda8e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,6 @@
 type RectProps = {
 	rect: DOMRect;
-	callbacks: Function[];
+	callbacks: Set<Function>;
 };
 
 let COMPARE_KEYS = [
@@ -30,17 +30,17 @@ function assertDidUpdate(state: RectProps, node: Element){
 
 export default function observeRect(
 	node: Element,
-	cb: (rect: DOMRect) => void
+	callback: (rect: DOMRect) => void
 ) {
 	return {
 		observe() {
 			let wasEmpty = observedNodes.size === 0;
 			if (observedNodes.has(node)) {
-				observedNodes.get(node)!.callbacks.push(cb);
+				observedNodes.get(node)!.callbacks.add(callback);
 			} else {
 				observedNodes.set(node, {
 					rect: {} as any,
-					callbacks: [cb],
+					callbacks: new Set([callback]),
 				});
 			}
 			if (wasEmpty) {
@@ -52,12 +52,11 @@ export default function observeRect(
 		unobserve() {
 			let state = observedNodes.get(node);
 			if (state) {
-				// Remove the callback
-				const index = state.callbacks.indexOf(cb);
-				if (index >= 0) state.callbacks.splice(index, 1);
+				state.callbacks.delete(callback);
 
 				// Remove the node reference
-				if (!state.callbacks.length) observedNodes.delete(node);
+				if (!state.callbacks.size)
+					observedNodes.delete(node);
 
 				// Stop the loop
 				if (!observedNodes.size)

From 1d31a22de0adcdf5b2223516f83401fedab10c07 Mon Sep 17 00:00:00 2001
From: Gabe Klein <gabe@termtm.com>
Date: Fri, 25 Sep 2020 18:08:02 -0600
Subject: [PATCH 5/6] use a closure to assist unobserve

---
 src/index.ts | 46 +++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index adcda8e..15a9315 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -31,37 +31,37 @@ function assertDidUpdate(state: RectProps, node: Element){
 export default function observeRect(
 	node: Element,
 	callback: (rect: DOMRect) => void
-) {
+){
+	let state = observedNodes.get(node);
+
 	return {
-		observe() {
-			let wasEmpty = observedNodes.size === 0;
-			if (observedNodes.has(node)) {
-				observedNodes.get(node)!.callbacks.add(callback);
-			} else {
-				observedNodes.set(node, {
+		observe(){
+			if(state)
+				state.callbacks.add(callback);
+			else {
+				observedNodes.set(node, state = {
 					rect: {} as any,
 					callbacks: new Set([callback]),
 				});
-			}
-			if (wasEmpty) {
-				active = true;
-				checkForUpdates();
+		
+				if(!active){
+					active = true;
+					checkForUpdates();
+				}
 			}
 		},
-
-		unobserve() {
-			let state = observedNodes.get(node);
-			if (state) {
+		unobserve(){
+			if(state){
 				state.callbacks.delete(callback);
-
-				// Remove the node reference
-				if (!state.callbacks.size)
+	
+				if(!state.callbacks.size)
 					observedNodes.delete(node);
-
-				// Stop the loop
-				if (!observedNodes.size)
+	
+				state = undefined;
+	
+				if(!observedNodes.size)
 					active = false;
 			}
-		},
-	};
+		}
+	}
 }
\ No newline at end of file

From 2459deb29a199282e4c6997cfb01173f809d50c7 Mon Sep 17 00:00:00 2001
From: Gabe Klein <gabe@termtm.com>
Date: Fri, 25 Sep 2020 18:33:48 -0600
Subject: [PATCH 6/6] indent w spaces instead

---
 src/index.ts | 94 ++++++++++++++++++++++++++--------------------------
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index 15a9315..93243d8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,67 +1,67 @@
 type RectProps = {
-	rect: DOMRect;
-	callbacks: Set<Function>;
+  rect: DOMRect;
+  callbacks: Set<Function>;
 };
 
 let COMPARE_KEYS = [
-	"bottom", "height", "left", "right", "top", "width"
+  "bottom", "height", "left", "right", "top", "width"
 ] as const;
 
 let observedNodes = new Map<Element, RectProps>();
 let active: boolean;
 
 function checkForUpdates(){
-	if(active){
-		observedNodes.forEach(assertDidUpdate);
-		window.requestAnimationFrame(checkForUpdates);
-	}
+  if(active){
+    observedNodes.forEach(assertDidUpdate);
+    window.requestAnimationFrame(checkForUpdates);
+  }
 };
 
 function assertDidUpdate(state: RectProps, node: Element){
-	let newRect = node.getBoundingClientRect();
+  let newRect = node.getBoundingClientRect();
 
-	for(const key of COMPARE_KEYS)
-		if(newRect[key] !== state.rect[key]){
-			state.rect = newRect;
-			state.callbacks.forEach(cb => cb(state.rect))
-			break;
-		}
+  for(const key of COMPARE_KEYS)
+    if(newRect[key] !== state.rect[key]){
+      state.rect = newRect;
+      state.callbacks.forEach(cb => cb(state.rect))
+      break;
+    }
 }
 
 export default function observeRect(
-	node: Element,
-	callback: (rect: DOMRect) => void
+  node: Element,
+  callback: (rect: DOMRect) => void
 ){
-	let state = observedNodes.get(node);
+  let state = observedNodes.get(node);
 
-	return {
-		observe(){
-			if(state)
-				state.callbacks.add(callback);
-			else {
-				observedNodes.set(node, state = {
-					rect: {} as any,
-					callbacks: new Set([callback]),
-				});
-		
-				if(!active){
-					active = true;
-					checkForUpdates();
-				}
-			}
-		},
-		unobserve(){
-			if(state){
-				state.callbacks.delete(callback);
-	
-				if(!state.callbacks.size)
-					observedNodes.delete(node);
-	
-				state = undefined;
-	
-				if(!observedNodes.size)
-					active = false;
-			}
-		}
-	}
+  return {
+    observe(){
+      if(state)
+        state.callbacks.add(callback);
+      else {
+        observedNodes.set(node, state = {
+          rect: {} as any,
+          callbacks: new Set([callback]),
+        });
+
+        if(!active){
+          active = true;
+          checkForUpdates();
+        }
+      }
+    },
+    unobserve(){
+      if(state){
+        state.callbacks.delete(callback);
+
+        if(!state.callbacks.size)
+          observedNodes.delete(node);
+
+        state = undefined;
+
+        if(!observedNodes.size)
+          active = false;
+      }
+    }
+  }
 }
\ No newline at end of file