Mirror: React hooks for accessible, common web interactions. UI super powers without the UI.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Pull out observeScrollHeight

+86 -86
+1 -86
src/useScrollRestoration.ts
··· 1 1 import { useLayoutEffect } from './utils/react'; 2 + import { observeScrollHeight } from './utils/observeScrollHeight'; 2 3 import { Ref } from './types'; 3 - 4 - const mutationObservers: Map<HTMLElement, MutationObserver> = new Map(); 5 - const resizeListeners: Map<HTMLElement, Array<() => void>> = new Map(); 6 - 7 - const resizeObserver = new ResizeObserver(entries => { 8 - const parents = new Set<Element>(); 9 - for (let i = 0; i < entries.length; i++) { 10 - const parent = entries[i].target.parentElement; 11 - if (parent && !parents.has(parent)) { 12 - parents.add(parent); 13 - const listeners = resizeListeners.get(parent) || []; 14 - for (let i = 0; i < listeners.length; i++) listeners[i](); 15 - } 16 - } 17 - }); 18 - 19 - function observeScrollHeight( 20 - element: HTMLElement, 21 - onScrollHeightChange: (scrollHeight: number) => void 22 - ): () => void { 23 - const listeners = resizeListeners.get(element) || []; 24 - const isFirstListener = !listeners.length; 25 - resizeListeners.set(element, listeners); 26 - 27 - let previousScrollHeight: null | number = null; 28 - let hasUnmounted = false; 29 - const onResize = () => { 30 - const scrollHeight = element.scrollHeight || 0; 31 - if (!hasUnmounted && scrollHeight !== previousScrollHeight) { 32 - onScrollHeightChange(element.scrollHeight); 33 - previousScrollHeight = scrollHeight; 34 - } 35 - }; 36 - 37 - listeners.push(onResize); 38 - 39 - if (isFirstListener) { 40 - const mutationObserver = new MutationObserver(entries => { 41 - for (let i = 0; i < entries.length; i++) { 42 - const entry = entries[i]; 43 - for (let j = 0; j < entry.addedNodes.length; j++) { 44 - const node = entry.addedNodes[j]; 45 - if (node.nodeType === Node.ELEMENT_NODE) { 46 - resizeObserver.observe(node as Element); 47 - } 48 - } 49 - 50 - for (let j = 0; j < entry.removedNodes.length; j++) { 51 - const node = entry.removedNodes[j]; 52 - if (node.nodeType === Node.ELEMENT_NODE) { 53 - resizeObserver.unobserve(node as Element); 54 - } 55 - } 56 - } 57 - }); 58 - 59 - const childNodes = element.childNodes; 60 - for (let i = 0; i < childNodes.length; i++) 61 - if (childNodes[i].nodeType === Node.ELEMENT_NODE) 62 - resizeObserver.observe(childNodes[i] as Element); 63 - 64 - mutationObserver.observe(element, { childList: true }); 65 - mutationObservers.set(element, mutationObserver); 66 - } 67 - 68 - requestAnimationFrame(onResize); 69 - 70 - return () => { 71 - const listeners = resizeListeners.get(element) || []; 72 - listeners.splice(listeners.indexOf(onResize), 1); 73 - hasUnmounted = true; 74 - 75 - if (!listeners.length) { 76 - const mutationObserver = mutationObservers.get(element); 77 - if (mutationObserver) mutationObserver.disconnect(); 78 - 79 - const childNodes = element.childNodes; 80 - for (let i = 0; i < childNodes.length; i++) 81 - if (childNodes[i].nodeType === Node.ELEMENT_NODE) 82 - resizeObserver.unobserve(childNodes[i] as Element); 83 - 84 - resizeListeners.delete(element); 85 - mutationObservers.delete(element); 86 - } 87 - }; 88 - } 89 4 90 5 const getIdForState = (() => { 91 6 const defaultState = {};
+85
src/utils/observeScrollHeight.ts
··· 1 + const mutationObservers: Map<HTMLElement, MutationObserver> = new Map(); 2 + const resizeListeners: Map<HTMLElement, Array<() => void>> = new Map(); 3 + 4 + const resizeObserver = new ResizeObserver(entries => { 5 + const parents = new Set<Element>(); 6 + for (let i = 0; i < entries.length; i++) { 7 + const parent = entries[i].target.parentElement; 8 + if (parent && !parents.has(parent)) { 9 + parents.add(parent); 10 + const listeners = resizeListeners.get(parent) || []; 11 + for (let i = 0; i < listeners.length; i++) listeners[i](); 12 + } 13 + } 14 + }); 15 + 16 + export function observeScrollHeight( 17 + element: HTMLElement, 18 + onScrollHeightChange: (scrollHeight: number) => void 19 + ): () => void { 20 + const listeners = resizeListeners.get(element) || []; 21 + const isFirstListener = !listeners.length; 22 + resizeListeners.set(element, listeners); 23 + 24 + let previousScrollHeight: null | number = null; 25 + let hasUnmounted = false; 26 + const onResize = () => { 27 + const scrollHeight = element.scrollHeight || 0; 28 + if (!hasUnmounted && scrollHeight !== previousScrollHeight) { 29 + onScrollHeightChange(element.scrollHeight); 30 + previousScrollHeight = scrollHeight; 31 + } 32 + }; 33 + 34 + listeners.push(onResize); 35 + 36 + if (isFirstListener) { 37 + const mutationObserver = new MutationObserver(entries => { 38 + for (let i = 0; i < entries.length; i++) { 39 + const entry = entries[i]; 40 + for (let j = 0; j < entry.addedNodes.length; j++) { 41 + const node = entry.addedNodes[j]; 42 + if (node.nodeType === Node.ELEMENT_NODE) { 43 + resizeObserver.observe(node as Element); 44 + } 45 + } 46 + 47 + for (let j = 0; j < entry.removedNodes.length; j++) { 48 + const node = entry.removedNodes[j]; 49 + if (node.nodeType === Node.ELEMENT_NODE) { 50 + resizeObserver.unobserve(node as Element); 51 + } 52 + } 53 + } 54 + }); 55 + 56 + const childNodes = element.childNodes; 57 + for (let i = 0; i < childNodes.length; i++) 58 + if (childNodes[i].nodeType === Node.ELEMENT_NODE) 59 + resizeObserver.observe(childNodes[i] as Element); 60 + 61 + mutationObserver.observe(element, { childList: true }); 62 + mutationObservers.set(element, mutationObserver); 63 + } 64 + 65 + requestAnimationFrame(onResize); 66 + 67 + return () => { 68 + const listeners = resizeListeners.get(element) || []; 69 + listeners.splice(listeners.indexOf(onResize), 1); 70 + hasUnmounted = true; 71 + 72 + if (!listeners.length) { 73 + const mutationObserver = mutationObservers.get(element); 74 + if (mutationObserver) mutationObserver.disconnect(); 75 + 76 + const childNodes = element.childNodes; 77 + for (let i = 0; i < childNodes.length; i++) 78 + if (childNodes[i].nodeType === Node.ELEMENT_NODE) 79 + resizeObserver.unobserve(childNodes[i] as Element); 80 + 81 + resizeListeners.delete(element); 82 + mutationObservers.delete(element); 83 + } 84 + }; 85 + }