import React, { forwardRef, ReactNode, HTMLAttributes } from 'react'; import { cn } from '../../lib/utils'; import { getViewport } from '../../lib/responsive'; // Grid column types type GridCols = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; // Grid gap types type GridGap = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'responsive'; // Grid props interface interface GridProps extends HTMLAttributes { children?: ReactNode; cols?: GridCols; gap?: GridGap; colsSm?: GridCols; colsMd?: GridCols; colsLg?: GridCols; colsXl?: GridCols; alignItems?: 'start' | 'center' | 'end' | 'stretch'; justifyItems?: 'start' | 'center' | 'end' | 'stretch'; // Mobile-first stacking stackMobile?: boolean; // Responsive columns responsiveCols?: { mobile?: GridCols; tablet?: GridCols; desktop?: GridCols; }; } // Grid item props interface interface GridItemProps extends HTMLAttributes { children?: ReactNode; colSpan?: GridCols; colSpanSm?: GridCols; colSpanMd?: GridCols; colSpanLg?: GridCols; colSpanXl?: GridCols; rowSpan?: GridCols; rowSpanSm?: GridCols; rowSpanMd?: GridCols; rowSpanLg?: GridCols; rowSpanXl?: GridCols; } // Helper function to get gap styles const getGapStyles = (gap: GridGap, responsiveGap?: boolean) => { if (gap === 'responsive' || responsiveGap) { return 'gap-2 xs:gap-3 sm:gap-4 md:gap-6 lg:gap-8'; } switch (gap) { case 'none': return 'gap-0'; case 'xs': return 'gap-1'; case 'sm': return 'gap-2'; case 'md': return 'gap-4'; case 'lg': return 'gap-6'; case 'xl': return 'gap-8'; case '2xl': return 'gap-12'; default: return 'gap-4'; } }; // Helper function to get column classes const getColClasses = (cols: GridCols | undefined, breakpoint: string = '') => { if (!cols) return ''; const prefix = breakpoint ? `${breakpoint}:` : ''; return `${prefix}grid-cols-${cols}`; }; // Helper function to get span classes const getSpanClasses = (span: GridCols | undefined, type: 'col' | 'row', breakpoint: string = '') => { if (!span) return ''; const prefix = breakpoint ? `${breakpoint}:` : ''; const typePrefix = type === 'col' ? 'col' : 'row'; return `${prefix}${typePrefix}-span-${span}`; }; // Helper function to get responsive column classes const getResponsiveColClasses = (responsiveCols: GridProps['responsiveCols']) => { if (!responsiveCols) return ''; let classes = ''; // Mobile (default) if (responsiveCols.mobile) { classes += `grid-cols-${responsiveCols.mobile} `; } // Tablet if (responsiveCols.tablet) { classes += `md:grid-cols-${responsiveCols.tablet} `; } // Desktop if (responsiveCols.desktop) { classes += `lg:grid-cols-${responsiveCols.desktop} `; } return classes; }; // Main Grid Component export const Grid = forwardRef( ( { cols = 1, gap = 'md', colsSm, colsMd, colsLg, colsXl, alignItems, justifyItems, className = '', children, stackMobile = false, responsiveCols, ...props }, ref ) => { // Get responsive column configuration const getResponsiveColumns = () => { if (responsiveCols) { return getResponsiveColClasses(responsiveCols); } if (stackMobile) { // Mobile-first: 1 column, then scale up return `grid-cols-1 sm:grid-cols-2 ${colsMd ? `md:grid-cols-${colsMd}` : 'md:grid-cols-3'} ${colsLg ? `lg:grid-cols-${colsLg}` : ''}`; } // Default responsive behavior let colClasses = `grid-cols-${cols}`; if (colsSm) colClasses += ` sm:grid-cols-${colsSm}`; if (colsMd) colClasses += ` md:grid-cols-${colsMd}`; if (colsLg) colClasses += ` lg:grid-cols-${colsLg}`; if (colsXl) colClasses += ` xl:grid-cols-${colsXl}`; return colClasses; }; // Get responsive gap const getResponsiveGap = () => { if (gap === 'responsive') { return 'gap-2 xs:gap-3 sm:gap-4 md:gap-6 lg:gap-8'; } // Mobile-first gap scaling if (stackMobile) { return 'gap-3 sm:gap-4 md:gap-6 lg:gap-8'; } return getGapStyles(gap); }; return (
{children}
); } ); Grid.displayName = 'Grid'; // Grid Item Component export const GridItem = forwardRef( ( { colSpan, colSpanSm, colSpanMd, colSpanLg, colSpanXl, rowSpan, rowSpanSm, rowSpanMd, rowSpanLg, rowSpanXl, className = '', children, ...props }, ref ) => { return (
{children}
); } ); GridItem.displayName = 'GridItem'; // Export types for external use export type { GridProps, GridItemProps, GridCols, GridGap };