Skip to content

Instantly share code, notes, and snippets.

@knownasilya
Last active August 8, 2024 20:08
Show Gist options
  • Save knownasilya/007f91454f566bb6219b53202b71fe98 to your computer and use it in GitHub Desktop.
Save knownasilya/007f91454f566bb6219b53202b71fe98 to your computer and use it in GitHub Desktop.
  const [size, toolbarRef] = useElementInlineResized<'small' | 'medium' | 'full', HTMLDivElement>({
    match: {
      small: 250,
      medium: 544,
      full: Infinity,
    },
  });
import {RefObject, useEffect, useRef, useState} from 'react';
import {throttle} from 'lodash';
export default function useElementInlineResized<Size extends string, T extends HTMLElement>({
match,
onMatched,
ref,
throttleMs,
}: {
match: Record<Size, number>;
onMatched?: (size: Size) => void;
ref?: RefObject<T>;
throttleMs?: number;
}): [Size, RefObject<T>] {
const backupRef = useRef<T>(null);
const actualRef = ref ?? backupRef;
const [size, setSize] = useState<Size | null>(null);
useEffect(() => {
const resizeObserver = new ResizeObserver(
throttle((entries) => {
if (!actualRef.current) {
return;
}
afterReflow(() => {
const matches = Object.entries(match);
const foundEntry = matches.find(([, value]) => {
return entries.length && entries[0].borderBoxSize[0].inlineSize <= value;
});
if (foundEntry) {
onMatched ? onMatched(foundEntry[0] as Size) : setSize(foundEntry[0] as Size);
}
});
}, throttleMs ?? 100)
);
if (actualRef.current && actualRef.current instanceof Element) {
resizeObserver.observe(actualRef.current, {box: 'border-box'});
}
return () => resizeObserver.disconnect();
}, [actualRef.current]);
return [size, actualRef];
}
function afterReflow(callback) {
window.setTimeout(() => {
window.requestAnimationFrame(callback);
}, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment