Skip to content

Instantly share code, notes, and snippets.

@cyberhck
Forked from paibamboo/Tile.tsx
Created January 23, 2024 13:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cyberhck/a477afa38d70c1a2ad110c7bf70dfeec to your computer and use it in GitHub Desktop.
Save cyberhck/a477afa38d70c1a2ad110c7bf70dfeec to your computer and use it in GitHub Desktop.
Tile layout using display grid
import * as React from "react";
import {classes, style as typestyle} from "typestyle";
import {buildBreakpoints} from "../../../helpers/buildBreakpoints";
import {ITileBreakpoint} from "./interfaces";
export interface IProps {
spanColumn?: number;
spanRow?: number;
/**
* Internal usage
*/
rowGap?: number;
/**
* Internal usage
*/
colGap?: number;
/**
* No need to assign this explicitly. It will be assigned by GridContainer parent.
*/
breakpoints?: ITileBreakpoint[];
className?: string;
style?: React.CSSProperties;
}
export class Tile extends React.Component<IProps> {
public static defaultProps: Partial<IProps> = {
breakpoints: [],
spanColumn: 1,
spanRow: 1
};
public render(): JSX.Element {
const {breakpoints, spanColumn, spanRow, rowGap, colGap, children, className, style} = this.props;
// todo: In case of flex, when colGap is defined, distant of left-most and right-most item should be 0 from parent
const classNames = {
gridItem: typestyle(
{
$debugName: "gridItem",
$nest: {
"@supports (display: grid)": {
gridColumn: "span " + spanColumn,
gridRow: "span " + spanRow,
margin: 0
}
},
flexBasis: "auto",
marginBottom: rowGap ? rowGap / 2 + "em" : 0,
marginLeft: colGap ? colGap / 2 + "em" : 0,
marginRight: colGap ? colGap / 2 + "em" : 0,
marginTop: rowGap ? rowGap / 2 + "em" : 0
},
...buildBreakpoints(breakpoints, (breakpoint: ITileBreakpoint) => [
{
$nest: {
"@supports (display: grid)": {
width: "auto"
}
},
width: colGap ?
`calc(${100 / breakpoint.numOfColumns }% - ${colGap}em)` :
`${100 / breakpoint.numOfColumns }%`
}
])
)
};
return (
<div className={classes(classNames.gridItem, className)} style={style}>
{children}
</div>
);
}
}
export default Tile;
import * as React from "react";
import {classes, style as typestyle} from "typestyle";
import {buildBreakpoints} from "../../../helpers/buildBreakpoints";
import {ITileBreakpoint} from "./interfaces";
import {IProps as ITileProps} from "./Tile";
export interface IProps {
/**
* row height in em unit
*/
rowHeight?: number;
/**
* row gap in em unit
*/
rowGap?: number;
/**
* col gap in em unit
*/
colGap?: number;
/**
* specifies number of columns for each breakpoint. Default value is `[{minWidth: 0, numOfColumns: 4}]`
*/
breakpoints?: ITileBreakpoint[];
className?: string;
style?: React.CSSProperties;
}
/**
* Layout using display grid. Will fallback to display flex if display grid is not supported.
*/
export class TilesContainer extends React.Component<IProps> {
public static defaultProps: Partial<IProps> = {
breakpoints: [{minWidth: 0, numOfColumns: 4}],
colGap: 0,
rowGap: 0
};
public render(): JSX.Element {
const {breakpoints, rowHeight, rowGap, colGap, className, style} = this.props;
const children = React.Children.map(this.props.children, (child: React.ReactElement<ITileProps>) =>
React.cloneElement(child, {breakpoints, colGap, rowGap})
);
const classNames = {
tilesContainer: typestyle(
{
$debugName: "tilesContainer",
$nest: {
"@supports (display: grid)": {
display: "grid",
gridAutoFlow: "row dense",
gridAutoRows: rowHeight ? rowHeight + "em" : "auto",
gridColumnGap: colGap + "em",
gridRowGap: rowGap + "em"
}
},
display: "flex",
flexWrap: "wrap"
},
...buildBreakpoints(breakpoints, (breakpoint: ITileBreakpoint) => {
const numOfColumns = breakpoint.numOfColumns;
const baseItemWidth = Math.round(100 / numOfColumns * 100) / 100;
const itemGap = Math.round(colGap * (numOfColumns - 1) / numOfColumns * 100) / 100;
const itemWidth = colGap ? `calc(${baseItemWidth}% - ${itemGap}em)` : `${baseItemWidth}%`;
return [
{
gridTemplateColumns: `repeat(${numOfColumns}, ${itemWidth})`
}
];
})
)
};
return (
<section className={classes(classNames.tilesContainer, className)} style={style}>
{children}
</section>
);
}
}
export default TilesContainer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment