use-resize-observer@7.0.0
code:script.js
import { useRef, useState, useEffect, useMemo, useCallback } from '../preact@10.5.13/hooks.js';
// This of course could've been more streamlined with internal state instead of
// refs, but then host hooks / components could not opt out of renders.
// This could've been exported to its own module, but the current build doesn't
// seem to work with module imports and I had no more time to spend on this...
function useResolvedElement(subscriber, refOrElement) {
var _ref;
// The default ref has to be non-conditionally declared here whether or not
// it'll be used as that's how hooks work.
var ref = null; // Default ref
var refElement = useRef(null);
var callbackRefElement = useRef(null);
var refCallback = useCallback(function (element) {
callbackRefElement.current = element;
callSubscriber();
}, []);
var lastReportedElementRef = useRef(null);
var cleanupRef = useRef();
var callSubscriber = function callSubscriber() {
var element = null;
if (callbackRefElement.current) {
element = callbackRefElement.current;
} else if (refElement.current) {
element = refElement.current;
} else if (refOrElement instanceof HTMLElement) {
element = refOrElement;
}
if (lastReportedElementRef.current === element) {
return;
}
if (cleanupRef.current) {
cleanupRef.current(); // Making sure the cleanup is not called accidentally multiple times.
cleanupRef.current = null;
}
lastReportedElementRef.current = element; // Only calling the subscriber, if there's an actual element to report.
if (element) {
cleanupRef.current = subscriber(element);
}
};
if (refOrElement && !(refOrElement instanceof HTMLElement)) {
// Overriding the default ref with the given one
ref = refOrElement;
} // On each render, we check whether a ref changed, or if we got a new raw
// element.
useEffect(function () {
// Note that this does not mean that "element" will necessarily be whatever
// the ref currently holds. It'll simply "update" element each render to
// the current ref value, but there's no guarantee that the ref value will
// not change later without a render.
// This may or may not be a problem depending on the specific use case.
if (ref) {
refElement.current = ref.current;
}
callSubscriber();
return refCallback;
}
function useResizeObserver(opts) {
if (opts === void 0) {
opts = {};
}
// Saving the callback as a ref. With this, I don't need to put onResize in the
// effect dep array, and just passing in an anonymous function without memoising
// will not reinstantiate the hook's ResizeObserver
var onResize = opts.onResize;
var onResizeRef = useRef(undefined);
onResizeRef.current = onResize; // Using a single instance throughout the hook's lifetime
var resizeObserverRef = useRef();
var _useState = useState({
width: undefined,
height: undefined
}),
setSize = _useState1; // In certain edge cases the RO might want to report a size change just after // the component unmounted.
var didUnmount = useRef(false);
useEffect(function () {
return function () {
didUnmount.current = true;
};
}, []); // Using a ref to track the previous width / height to avoid unnecessary renders
var previous = useRef({
width: undefined,
height: undefined
}); // This block is kinda like a useEffect, only it's called whenever a new
// element could be resolved based on the ref option. It also has a cleanup
// function.
var refCallback = useResolvedElement(function (element) {
// Initialising the RO instance
if (!resizeObserverRef.current) {
// Saving a single instance, used by the hook from this point on.
resizeObserverRef.current = new ResizeObserver(function (entries) {
if (!Array.isArray(entries)) {
return;
} // Since we only observe the one element, we don't need to loop over the
// array
if (!entries.length) {
return;
}
var entry = entries0; // Math.round is in line with how CSS resolves sub-pixel values var newWidth = Math.round(entry.contentRect.width);
var newHeight = Math.round(entry.contentRect.height);
if (previous.current.width !== newWidth || previous.current.height !== newHeight) {
var newSize = {
width: newWidth,
height: newHeight
};
if (onResizeRef.current) {
onResizeRef.current(newSize);
} else {
previous.current.width = newWidth;
previous.current.height = newHeight;
if (!didUnmount.current) {
setSize(newSize);
}
}
}
});
}
resizeObserverRef.current.observe(element);
return function () {
if (resizeObserverRef.current) {
resizeObserverRef.current.unobserve(element);
}
};
}, opts.ref);
return useMemo(function () {
return {
ref: refCallback,
width: size.width,
height: size.height
};
}
export default useResizeObserver;