Files
sendou.ink/apps/web-react/app/modules/responsive-masonry/components/ResponsiveMasonry.tsx

60 lines
1.2 KiB
TypeScript

// adapted from https://github.com/cedricdelpoux/react-responsive-masonry
import React from "react";
import { useWindowSize } from "~/hooks/useWindowSize";
import Masonry from "./Masonry";
const COLUMN_COUNTS = {
L: 3,
M: 2,
S: 1,
};
const BREAKPOINTS = {
L: 900,
M: 750,
S: 350,
} as const;
type Breakpoint = keyof typeof BREAKPOINTS;
const MasonryResponsive = ({
children,
}: {
children: React.ReactNode | React.ReactNode[];
}) => {
const breakpoint = useBreakpoint();
const columnsCount = COLUMN_COUNTS[breakpoint];
return (
<div>
{React.Children.map(children, (child, index) =>
React.cloneElement(child as React.ReactElement<any>, {
key: index,
columnsCount,
}),
)}
</div>
);
};
export function ResponsiveMasonry({ children }: { children: React.ReactNode }) {
return (
<MasonryResponsive>
<Masonry gutter="1rem">{children}</Masonry>
</MasonryResponsive>
);
}
function useBreakpoint(): Breakpoint {
const { width } = useWindowSize();
const ascending = Object.entries(BREAKPOINTS).sort((a, b) => a[1] - b[1]);
return ascending.reduce<Breakpoint>(
(current, [name, minWidth]) =>
width >= minWidth ? (name as Breakpoint) : current,
ascending[0][0] as Breakpoint,
);
}