react-photo-album
Version:
Responsive photo gallery component for React
54 lines (53 loc) • 2.25 kB
JavaScript
"use client";
import { useRef, useReducer, useCallback } from "react";
function useArray(array) {
const ref = useRef(array);
if (!array || !ref.current || array.length !== ref.current.length || ref.current.some((el, i) => el !== array[i])) {
ref.current = array;
}
return ref.current;
}
function containerWidthReducer(state, [newContainerWidth, newScrollbarWidth]) {
const [containerWidth, scrollbarWidth] = state;
if (containerWidth !== void 0 && scrollbarWidth !== void 0 && newContainerWidth !== void 0 && newScrollbarWidth !== void 0 && newContainerWidth > containerWidth && newContainerWidth - containerWidth <= 20 && newScrollbarWidth < scrollbarWidth) {
return [containerWidth, newScrollbarWidth];
}
return containerWidth !== newContainerWidth || scrollbarWidth !== newScrollbarWidth ? [newContainerWidth, newScrollbarWidth] : state;
}
function resolveContainerWidth(el, breakpoints) {
let width = el?.clientWidth;
if (width !== void 0 && breakpoints && breakpoints.length > 0) {
const sorted = [...breakpoints.filter((x) => x > 0)].sort((a, b) => b - a);
sorted.push(Math.floor(sorted[sorted.length - 1] / 2));
width = sorted.find((breakpoint, index) => breakpoint <= width || index === sorted.length - 1);
}
return width;
}
function useContainerWidth(ref, breakpointsArray, defaultContainerWidth) {
const [[containerWidth], dispatch] = useReducer(containerWidthReducer, [defaultContainerWidth]);
const breakpoints = useArray(breakpointsArray);
const observerRef = useRef(void 0);
const containerRef = useCallback(
(node) => {
observerRef.current?.disconnect();
observerRef.current = void 0;
const updateWidth = () => dispatch([resolveContainerWidth(node, breakpoints), window.innerWidth - document.documentElement.clientWidth]);
updateWidth();
if (node && typeof ResizeObserver !== "undefined") {
observerRef.current = new ResizeObserver(updateWidth);
observerRef.current.observe(node);
}
if (typeof ref === "function") {
ref(node);
} else if (ref) {
ref.current = node;
}
},
[ref, breakpoints]
);
return { containerRef, containerWidth };
}
export {
useArray,
useContainerWidth
};