Skip to content

Instantly share code, notes, and snippets.

@themadarchitect
Created May 9, 2024 14:58
Show Gist options
  • Select an option

  • Save themadarchitect/85d9dbbd77f64c02ff41399da4cc20f7 to your computer and use it in GitHub Desktop.

Select an option

Save themadarchitect/85d9dbbd77f64c02ff41399da4cc20f7 to your computer and use it in GitHub Desktop.
Layout system
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