Created
August 21, 2023 13:56
-
-
Save pffigueiredo/8acab4b4cd7f7e554944d64260659379 to your computer and use it in GitHub Desktop.
Grid React component
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Box, box } from "@singlestore/fusion/components/layout"; | |
import classNames from "classnames"; | |
import React from "react"; | |
import "./grid.scss"; | |
type DynamicTemplate = { | |
type: "dynamic"; | |
repeat: "auto-fill" | "auto-fit"; | |
minDimension: `${number}px`; | |
maxDimension: `${number}px` | `${number}fr` | `${number}%`; | |
}; | |
type StaticTemplate = { | |
type: "static"; | |
count: number; | |
dimension: `${number}px` | `${number}fr` | `${number}%`; | |
}; | |
type GridBaseProps = { | |
gridTemplateColumns?: DynamicTemplate | StaticTemplate; | |
gridTemplateRows?: DynamicTemplate | StaticTemplate; | |
gap: React.ComponentProps<typeof Box>["gap"]; | |
}; | |
type GridComponentProps = { | |
children: React.ReactNode; | |
} & GridBaseProps; | |
type GridClassProps = { | |
// need a ref to inject CSS variables into the DOM | |
ref: React.RefObject<HTMLElement>; | |
} & GridBaseProps; | |
function buildTemplateString(template: DynamicTemplate | StaticTemplate) { | |
if (template.type === "dynamic") { | |
return `repeat(${template.repeat}, minmax(${template.minDimension}, ${template.maxDimension}))`; | |
} | |
if (template.type === "static") { | |
return `repeat(${template.count}, ${template.dimension})`; | |
} | |
throw new Error("Invalid template type"); | |
} | |
export function grid({ | |
gridTemplateColumns, | |
gridTemplateRows, | |
gap, | |
ref, | |
}: GridClassProps) { | |
if (!ref.current) { | |
return ""; | |
} | |
if (gridTemplateColumns) { | |
ref.current.style.setProperty( | |
"--grid-template-columns", | |
buildTemplateString(gridTemplateColumns) | |
); | |
} | |
if (gridTemplateRows) { | |
ref.current.style.setProperty( | |
"--grid-template-columns", | |
buildTemplateString(gridTemplateRows) | |
); | |
} | |
return classNames("grid", box({ gap })); | |
} | |
export function Grid({ | |
children, | |
gap, | |
gridTemplateColumns, | |
gridTemplateRows, | |
}: GridComponentProps) { | |
const style: Record<string, string> = {}; | |
const refDiv = React.useRef<HTMLDivElement>(null); | |
return ( | |
<Box | |
className={grid({ | |
ref: refDiv, | |
gap, | |
gridTemplateColumns, | |
gridTemplateRows, | |
})} | |
gap={gap} | |
style={style} | |
ref={refDiv} | |
> | |
{children} | |
</Box> | |
); | |
} | |
<Grid | |
gap="2x" | |
gridTemplateColumns={{ | |
type: "dynamic", | |
repeat: "auto-fit", | |
minDimension: "200px", | |
maxDimension: "1fr", | |
}} | |
> | |
123 | |
</Grid>; | |
--- | |
.grid { | |
--grid-template-columns: 1fr; | |
--grid-template-rows: 1fr; | |
display: grid; | |
grid-template-columns: var(--grid-template-columns) !important; | |
grid-template-rows: var(--grid-template-rows) !important; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment