()
| 9 | import styles from './styles.module.css' |
| 10 | |
| 11 | function Masonry() { |
| 12 | // Hook1: Tie media queries to the number of columns |
| 13 | const columns = useMedia( |
| 14 | ['(min-width: 1500px)', '(min-width: 1000px)', '(min-width: 600px)'], |
| 15 | [5, 4, 3], |
| 16 | 2 |
| 17 | ) |
| 18 | // Hook2: Measure the width of the container element |
| 19 | const [ref, { width }] = useMeasure() |
| 20 | // Hook3: Hold items |
| 21 | const [items, set] = React.useState(data) |
| 22 | // Hook4: shuffle data every 2 seconds |
| 23 | React.useEffect(() => { |
| 24 | const t = setInterval(() => set(shuffle), 2000) |
| 25 | return () => clearInterval(t) |
| 26 | }, []) |
| 27 | // Hook5: Form a grid of stacked items using width & columns we got from hooks 1 & 2 |
| 28 | const [heights, gridItems] = React.useMemo(() => { |
| 29 | const heights = new Array(columns).fill(0) // Each column gets a height starting with zero |
| 30 | const gridItems = items.map(child => { |
| 31 | const column = heights.indexOf(Math.min(...heights)) // Basic masonry-grid placing, puts tile into the smallest column using Math.min |
| 32 | const x = (width / columns) * column // x = container width / number of columns * column index, |
| 33 | const y = (heights[column] += child.height / 2) - child.height / 2 // y = it's just the height of the current column |
| 34 | return { |
| 35 | ...child, |
| 36 | x, |
| 37 | y, |
| 38 | width: width / columns, |
| 39 | height: child.height / 2, |
| 40 | } |
| 41 | }) |
| 42 | return [heights, gridItems] |
| 43 | }, [columns, items, width]) |
| 44 | // Hook6: Turn the static grid values into animated transitions, any addition, removal or change will be animated |
| 45 | const transitions = useTransition(gridItems, { |
| 46 | key: (item: { css: string; height: number }) => item.css, |
| 47 | from: ({ x, y, width, height }) => ({ x, y, width, height, opacity: 0 }), |
| 48 | enter: ({ x, y, width, height }) => ({ x, y, width, height, opacity: 1 }), |
| 49 | update: ({ x, y, width, height }) => ({ x, y, width, height }), |
| 50 | leave: { height: 0, opacity: 0 }, |
| 51 | config: { mass: 5, tension: 500, friction: 100 }, |
| 52 | trail: 25, |
| 53 | }) |
| 54 | // Render the grid |
| 55 | return ( |
| 56 | <div |
| 57 | ref={ref} |
| 58 | className={styles.list} |
| 59 | style={{ height: Math.max(...heights) }} |
| 60 | > |
| 61 | {transitions((style, item) => ( |
| 62 | <a.div style={style}> |
| 63 | <div |
| 64 | style={{ |
| 65 | backgroundImage: `url(${item.css}?auto=compress&dpr=2&h=500&w=500)`, |
| 66 | }} |
| 67 | /> |
| 68 | </a.div> |
nothing calls this directly
no test coverage detected
searching dependent graphs…