Created
May 9, 2024 14:58
-
-
Save themadarchitect/85d9dbbd77f64c02ff41399da4cc20f7 to your computer and use it in GitHub Desktop.
Layout system
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 { ElementType, FC, ReactNode } from 'react'; | |
| import { cn } from '@/lib/utils'; | |
| import React from 'react'; | |
| import { ComponentPropsWithout, RemovedProps } from './helpers'; | |
| import { Slot } from '@radix-ui/react-slot'; | |
| export interface LayoutProps { | |
| className?: string; | |
| children?: ReactNode; | |
| } | |
| export interface GridProps extends LayoutProps { | |
| columns?: string | number; // Column configuration | |
| rows?: string | number; // Row configuration | |
| gap?: string | number; // General grid gap | |
| gapX?: string | number; // Horizontal gap | |
| gapY?: string | number; // Vertical gap | |
| justify?: 'start' | 'center' | 'end' | 'between'; // Justify content | |
| align?: 'start' | 'center' | 'end' | 'baseline' | 'stretch'; // Align content | |
| display?: 'grid' | 'inline-grid'; // Controls display type | |
| flow?: 'row' | 'column' | 'dense' | 'row-dense' | 'column-dense'; // Controls grid flow | |
| as?: ElementType; // Determines which HTML element to use (div, span, etc.) - defaults to div | |
| asChild?: boolean; | |
| } | |
| type GridElement = React.ElementRef<'div'>; | |
| type GridDivProps = { as?: 'div' } & ComponentPropsWithout<'div', RemovedProps>; | |
| type GridSpanProps = { as: 'span' } & ComponentPropsWithout< | |
| 'span', | |
| RemovedProps | |
| >; | |
| export type CompositeGridProps = GridProps & (GridSpanProps | GridDivProps); | |
| const Grid = React.forwardRef<GridElement, CompositeGridProps>( | |
| ( | |
| { | |
| as: Tag = 'div', | |
| columns = 3, | |
| rows, | |
| gap = 2, | |
| justify = 'start', | |
| align = 'start', | |
| display = 'grid', | |
| flow = 'row', | |
| className, | |
| asChild, | |
| children, | |
| }, | |
| forwardRef, | |
| ) => { | |
| const Comp = asChild ? Slot : Tag; | |
| return ( | |
| <Comp | |
| ref={forwardRef} | |
| className={cn( | |
| display, | |
| `grid-cols-${columns}`, | |
| `gap-${gap}`, | |
| `justify-${justify}`, | |
| `items-${align}`, | |
| `grid-flow-${flow}`, | |
| rows ? `grid-rows-${rows}` : '', | |
| className, | |
| )} | |
| > | |
| {children} | |
| </Comp> | |
| ); | |
| }, | |
| ); | |
| Grid.displayName = 'Grid'; | |
| export interface BoxProps extends LayoutProps { | |
| as?: ElementType; | |
| padding?: string | number; // Padding prop | |
| margin?: string | number; // Margin prop | |
| display?: 'block' | 'inline-block' | 'inline'; // Display prop | |
| gridColumn?: string | number; // Defines grid column | |
| gridColumnStart?: string | number; // Defines grid column start | |
| gridColumnEnd?: string | number; // Defines grid column end | |
| gridRow?: string | number; // Defines grid row | |
| gridRowStart?: string | number; // Defines grid row start | |
| gridRowEnd?: string | number; // Defines grid row end | |
| } | |
| const Box: FC<BoxProps> = ({ | |
| as: Component = 'div', | |
| padding = 0, | |
| margin = 0, | |
| display = 'block', | |
| gridColumn, | |
| gridColumnStart, | |
| gridColumnEnd, | |
| gridRow, | |
| gridRowStart, | |
| gridRowEnd, | |
| className, | |
| children, | |
| }) => { | |
| return ( | |
| <Component | |
| className={cn( | |
| `p-${padding}`, | |
| `m-${margin}`, | |
| display, | |
| gridColumn ? `col-span-${gridColumn}` : '', | |
| gridColumnStart ? `col-start-${gridColumnStart}` : '', | |
| gridColumnEnd ? `col-end-${gridColumnEnd}` : '', | |
| gridRow ? `row-span-${gridRow}` : '', | |
| gridRowStart ? `row-start-${gridRowStart}` : '', | |
| gridRowEnd ? `row-end-${gridRowEnd}` : '', | |
| className, | |
| )} | |
| > | |
| {children} | |
| </Component> | |
| ); | |
| }; | |
| Box.displayName = 'Box'; | |
| export interface FlexProps extends LayoutProps { | |
| as?: ElementType; | |
| direction?: 'row' | 'column'; // Flex direction | |
| justify?: 'start' | 'center' | 'end' | 'between' | 'around'; // Flex justification | |
| align?: 'start' | 'center' | 'end' | 'stretch'; // Flex alignment | |
| gap?: string | number; // Flex gap | |
| gridColumn?: string | number; | |
| gridColumnStart?: string | number; | |
| gridColumnEnd?: string | number; | |
| gridRow?: string | number; | |
| gridRowStart?: string | number; | |
| gridRowEnd?: string | number; | |
| } | |
| const Flex: FC<FlexProps> = ({ | |
| as: Component = 'div', | |
| direction = 'row', | |
| justify = 'start', | |
| align = 'start', | |
| gap = 0, | |
| gridColumn, | |
| gridColumnStart, | |
| gridColumnEnd, | |
| gridRow, | |
| gridRowStart, | |
| gridRowEnd, | |
| className, | |
| children, | |
| }) => { | |
| return ( | |
| <Component | |
| className={cn( | |
| 'flex', | |
| `flex-${direction}`, | |
| `justify-${justify}`, | |
| `items-${align}`, | |
| `gap-${gap}`, | |
| gridColumn ? `col-span-${gridColumn}` : '', | |
| gridColumnStart ? `col-start-${gridColumnStart}` : '', | |
| gridColumnEnd ? `col-end-${gridColumnEnd}` : '', | |
| gridRow ? `row-span-${gridRow}` : '', | |
| gridRowStart ? `row-start-${gridRowStart}` : '', | |
| gridRowEnd ? `row-end-${gridRowEnd}` : '', | |
| className, | |
| )} | |
| > | |
| {children} | |
| </Component> | |
| ); | |
| }; | |
| Flex.displayName = 'Flex'; | |
| export interface SectionProps extends LayoutProps { | |
| backgroundColor?: string; | |
| padding?: string | number; | |
| gridColumn?: string | number; | |
| gridColumnStart?: string | number; | |
| gridColumnEnd?: string | number; | |
| gridRow?: string | number; | |
| gridRowStart?: string | number; | |
| gridRowEnd?: string | number; | |
| } | |
| const Section: FC<SectionProps> = ({ | |
| backgroundColor, | |
| padding = 4, | |
| gridColumn, | |
| gridColumnStart, | |
| gridColumnEnd, | |
| gridRow, | |
| gridRowStart, | |
| gridRowEnd, | |
| className, | |
| children, | |
| }) => { | |
| return ( | |
| <section | |
| className={cn( | |
| `bg-${backgroundColor}`, | |
| `p-${padding}`, | |
| gridColumn ? `col-span-${gridColumn}` : '', | |
| gridColumnStart ? `col-start-${gridColumnStart}` : '', | |
| gridColumnEnd ? `col-end-${gridColumnEnd}` : '', | |
| gridRow ? `row-span-${gridRow}` : '', | |
| gridRowStart ? `row-start-${gridRowStart}` : '', | |
| gridRowEnd ? `row-end-${gridRowEnd}` : '', | |
| className, | |
| )} | |
| > | |
| {children} | |
| </section> | |
| ); | |
| }; | |
| Section.displayName = 'Section'; | |
| interface ContainerProps extends LayoutProps { | |
| as?: ElementType; | |
| maxWidth?: string | number; | |
| gridColumn?: string | number; | |
| gridColumnStart?: string | number; | |
| gridColumnEnd?: string | number; | |
| gridRow?: string | number; | |
| gridRowStart?: string | number; | |
| gridRowEnd?: string | number; | |
| } | |
| const Container: FC<ContainerProps> = ({ | |
| as: Component = 'div', | |
| maxWidth = '7xl', | |
| gridColumn, | |
| gridColumnStart, | |
| gridColumnEnd, | |
| gridRow, | |
| gridRowStart, | |
| gridRowEnd, | |
| className, | |
| children, | |
| }) => { | |
| return ( | |
| <Component | |
| className={cn( | |
| 'mx-auto', | |
| `max-w-${maxWidth}`, | |
| gridColumn ? `col-span-${gridColumn}` : '', | |
| gridColumnStart ? `col-start-${gridColumnStart}` : '', | |
| gridColumnEnd ? `col-end-${gridColumnEnd}` : '', | |
| gridRow ? `row-span-${gridRow}` : '', | |
| gridRowStart ? `row-start-${gridRowStart}` : '', | |
| gridRowEnd ? `row-end-${gridRowEnd}` : '', | |
| className, | |
| )} | |
| > | |
| {children} | |
| </Component> | |
| ); | |
| }; | |
| Container.displayName = 'Container'; | |
| export { Grid, Box, Flex, Section, Container }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment