Utilities and UI components for cross-platform React Native apps
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: add `Squares` layout

A specialized `Flow` layout that renders all of its children in exact squares that fill the layout's allocated space as best as possible.

Joseph Hale (Jan 25, 2026, 2:57 AM -0700) 6e687546 3e58797c

+70
+69
src/layouts/Squares.tsx
··· 1 + // Copyright (c) 2026 Joseph Hale 2 + // 3 + // This Source Code Form is subject to the terms of the Mozilla Public 4 + // License, v. 2.0. If a copy of the MPL was not distributed with this 5 + // file, You can obtain one at https://mozilla.org/MPL/2.0/. 6 + 7 + import { View } from "react-native"; 8 + import Measured, { useMeasurements } from "./Measured"; 9 + import Flow, { type FlowDefinition } from "./Flow"; 10 + import styles from "../styles"; 11 + 12 + export interface SquaresProps { 13 + rows: number; 14 + columns: number; 15 + flow?: FlowDefinition; 16 + children: Iterable<React.ReactNode>; 17 + } 18 + 19 + const DEFAULT_FLOW: FlowDefinition = { 20 + origin: 'top-left', 21 + direction: 'column', 22 + } 23 + 24 + /** 25 + * Places its children into a grid of squares. 26 + */ 27 + export default function Squares(props: SquaresProps) { 28 + return ( 29 + <Measured> 30 + <MeasuredSquares {...props} /> 31 + </Measured> 32 + ) 33 + } 34 + 35 + function MeasuredSquares(props: SquaresProps) { 36 + const squares = useSquares(props.rows, props.columns, Array.from(props.children)); 37 + const flow = props.flow || DEFAULT_FLOW; 38 + 39 + return ( 40 + <View style={[styles.layout.centered, styles.layout.filled]}> 41 + <Flow rows={props.rows} columns={props.columns} flow={flow}> 42 + {squares} 43 + </Flow> 44 + </View> 45 + ) 46 + } 47 + 48 + function useSquares(rows: number, columns: number, children: React.ReactNode[]) { 49 + const { width, height } = useMeasurements(); 50 + const length = Math.floor(Math.min(width / columns, height / rows)); 51 + return new Array(rows * columns).fill(null).map((_, i) => ( 52 + <Square key={i} size={length}> 53 + {children[i]} 54 + </Square> 55 + )); 56 + } 57 + 58 + interface SquareProps { 59 + children: React.ReactNode; 60 + size: number; 61 + } 62 + 63 + function Square(props: SquareProps) { 64 + return ( 65 + <View style={{ width: props.size, height: props.size }}> 66 + {props.children} 67 + </View> 68 + ) 69 + }
+1
src/layouts/index.ts
··· 6 6 7 7 export { default as Flow, type FlowProps, type FlowDirectionProps, type FlowDefinition } from "./Flow"; 8 8 export { default as Measured, useMeasurements } from "./Measured"; 9 + export { default as Squares, type SquaresProps } from './Squares';