Files
klz-cables.com/components/ui/Container.tsx
2025-12-29 18:18:48 +01:00

140 lines
3.7 KiB
TypeScript

import React, { forwardRef, ReactNode, HTMLAttributes } from 'react';
import { cn } from '../../lib/utils';
import { getViewport } from '../../lib/responsive';
// Container props interface
interface ContainerProps extends HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
maxWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full';
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'responsive';
centered?: boolean;
fluid?: boolean;
safeArea?: boolean;
responsivePadding?: boolean;
}
// Helper function to get max-width styles
const getMaxWidthStyles = (maxWidth: ContainerProps['maxWidth']) => {
switch (maxWidth) {
case 'xs':
return 'max-w-xs';
case 'sm':
return 'max-w-sm';
case 'md':
return 'max-w-md';
case 'lg':
return 'max-w-lg';
case 'xl':
return 'max-w-xl';
case '2xl':
return 'max-w-2xl';
case '3xl':
return 'max-w-3xl';
case '4xl':
return 'max-w-4xl';
case '5xl':
return 'max-w-5xl';
case '6xl':
return 'max-w-6xl';
case 'full':
return 'max-w-full';
default:
return 'max-w-6xl';
}
};
// Helper function to get padding styles
const getPaddingStyles = (padding: ContainerProps['padding'], responsivePadding?: boolean) => {
if (padding === 'responsive' || responsivePadding) {
return 'px-4 xs:px-5 sm:px-6 md:px-8 lg:px-10 xl:px-12 2xl:px-16';
}
switch (padding) {
case 'none':
return 'px-0';
case 'sm':
return 'px-3 xs:px-4 sm:px-5';
case 'md':
return 'px-4 xs:px-5 sm:px-6 md:px-8';
case 'lg':
return 'px-4 xs:px-5 sm:px-6 md:px-8 lg:px-10';
case 'xl':
return 'px-4 xs:px-5 sm:px-6 md:px-8 lg:px-10 xl:px-12';
case '2xl':
return 'px-4 xs:px-5 sm:px-6 md:px-8 lg:px-10 xl:px-12 2xl:px-16';
default:
return 'px-4 xs:px-5 sm:px-6 md:px-8 lg:px-10';
}
};
// Main Container Component
export const Container = forwardRef<HTMLDivElement, ContainerProps>(
(
{
maxWidth = '6xl',
padding = 'md',
centered = true,
fluid = false,
safeArea = false,
responsivePadding = false,
className = '',
children,
...props
},
ref
) => {
// Get responsive padding if needed
const getResponsivePadding = () => {
if (!responsivePadding && padding !== 'responsive') return getPaddingStyles(padding, false);
if (typeof window === 'undefined') return getPaddingStyles('md', true);
const viewport = getViewport();
// Mobile-first responsive padding
if (viewport.isMobile) {
return 'px-4 xs:px-5 sm:px-6';
}
if (viewport.isTablet) {
return 'px-5 sm:px-6 md:px-8 lg:px-10';
}
if (viewport.isDesktop) {
return 'px-6 md:px-8 lg:px-10 xl:px-12';
}
return 'px-6 md:px-8 lg:px-10 xl:px-12 2xl:px-16';
};
return (
<div
ref={ref}
className={cn(
// Base container styles
'w-full',
// Centering
centered && 'mx-auto',
// Max width
!fluid && getMaxWidthStyles(maxWidth),
// Padding (responsive or static)
responsivePadding || padding === 'responsive' ? getResponsivePadding() : getPaddingStyles(padding, false),
// Safe area for mobile notch
safeArea && 'safe-area-p',
// Mobile-optimized max width
'mobile:max-w-full',
// Custom classes
className
)}
// Add role for accessibility
role="region"
{...props}
>
{children}
</div>
);
}
);
Container.displayName = 'Container';
// Export types for external use
export type { ContainerProps };