website refactor
This commit is contained in:
@@ -1,6 +1,18 @@
|
||||
import React, { ReactNode, ElementType } from 'react';
|
||||
import { Box, BoxProps, ResponsiveValue } from './Box';
|
||||
|
||||
/**
|
||||
* WARNING: DO NOT VIOLATE THE PURPOSE OF THIS PRIMITIVE.
|
||||
*
|
||||
* Stack is for flexbox-based layouts (stacking elements).
|
||||
*
|
||||
* - DO NOT add positioning props (absolute, top, zIndex).
|
||||
* - DO NOT add grid props.
|
||||
* - DO NOT add background/border props unless it's a specific styled stack.
|
||||
*
|
||||
* If you need a more specific layout, create a new component in apps/website/components.
|
||||
*/
|
||||
|
||||
type Spacing = 0 | 0.5 | 1 | 1.5 | 2 | 2.5 | 3 | 3.5 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | 64 | 72 | 80 | 96;
|
||||
|
||||
interface ResponsiveGap {
|
||||
@@ -20,7 +32,8 @@ interface ResponsiveSpacing {
|
||||
'2xl'?: Spacing;
|
||||
}
|
||||
|
||||
export interface StackProps<T extends ElementType> extends Omit<BoxProps<T>, 'children' | 'className' | 'gap'> {
|
||||
export interface StackProps<T extends ElementType> {
|
||||
as?: T;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
direction?: 'row' | 'col' | { base?: 'row' | 'col'; md?: 'row' | 'col'; lg?: 'row' | 'col' };
|
||||
@@ -28,7 +41,7 @@ export interface StackProps<T extends ElementType> extends Omit<BoxProps<T>, 'ch
|
||||
align?: 'start' | 'center' | 'end' | 'stretch' | 'baseline' | ResponsiveValue<'start' | 'center' | 'end' | 'stretch' | 'baseline'>;
|
||||
justify?: 'start' | 'center' | 'end' | 'between' | 'around' | ResponsiveValue<'start' | 'center' | 'end' | 'between' | 'around'>;
|
||||
wrap?: boolean;
|
||||
center?: boolean;
|
||||
// Spacing (allowed for layout)
|
||||
m?: Spacing | ResponsiveSpacing;
|
||||
mt?: Spacing | ResponsiveSpacing;
|
||||
mb?: Spacing | ResponsiveSpacing;
|
||||
@@ -41,11 +54,21 @@ export interface StackProps<T extends ElementType> extends Omit<BoxProps<T>, 'ch
|
||||
pr?: Spacing | ResponsiveSpacing;
|
||||
px?: Spacing | ResponsiveSpacing;
|
||||
py?: Spacing | ResponsiveSpacing;
|
||||
// Sizing (allowed for layout)
|
||||
w?: string | ResponsiveValue<string>;
|
||||
h?: string | ResponsiveValue<string>;
|
||||
minWidth?: string | ResponsiveValue<string>;
|
||||
maxWidth?: string | ResponsiveValue<string>;
|
||||
minHeight?: string | ResponsiveValue<string>;
|
||||
maxHeight?: string | ResponsiveValue<string>;
|
||||
// Basic styling (sometimes needed for containers)
|
||||
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
|
||||
// Flex item props
|
||||
flex?: number | string;
|
||||
flexGrow?: number;
|
||||
flexShrink?: number;
|
||||
alignSelf?: 'auto' | 'start' | 'end' | 'center' | 'stretch' | 'baseline';
|
||||
style?: React.CSSProperties;
|
||||
role?: string;
|
||||
'aria-label'?: string;
|
||||
'aria-live'?: 'polite' | 'assertive' | 'off';
|
||||
}
|
||||
|
||||
export function Stack<T extends ElementType = 'div'>({
|
||||
@@ -56,10 +79,14 @@ export function Stack<T extends ElementType = 'div'>({
|
||||
align,
|
||||
justify,
|
||||
wrap = false,
|
||||
center = false,
|
||||
m, mt, mb, ml, mr,
|
||||
p, pt, pb, pl, pr, px, py,
|
||||
w, h, minWidth, maxWidth, minHeight, maxHeight,
|
||||
rounded,
|
||||
flex,
|
||||
flexGrow,
|
||||
flexShrink,
|
||||
alignSelf,
|
||||
as,
|
||||
...props
|
||||
}: StackProps<T>) {
|
||||
@@ -150,16 +177,58 @@ export function Stack<T extends ElementType = 'div'>({
|
||||
className
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const { alignItems, justifyContent, ...restProps } = props as any;
|
||||
const getAlignItemsClass = (value: StackProps<ElementType>['align']) => {
|
||||
if (!value) return '';
|
||||
const map: Record<string, string> = { start: 'items-start', center: 'items-center', end: 'items-end', stretch: 'items-stretch', baseline: 'items-baseline' };
|
||||
if (typeof value === 'object') {
|
||||
const classes = [];
|
||||
if (value.base) classes.push(map[value.base]);
|
||||
if (value.sm) classes.push(`sm:${map[value.sm]}`);
|
||||
if (value.md) classes.push(`md:${map[value.md]}`);
|
||||
if (value.lg) classes.push(`lg:${map[value.lg]}`);
|
||||
if (value.xl) classes.push(`xl:${map[value.xl]}`);
|
||||
if (value['2xl']) classes.push(`2xl:${map[value['2xl']]}`);
|
||||
return classes.join(' ');
|
||||
}
|
||||
return map[value];
|
||||
};
|
||||
|
||||
const getJustifyContentClass = (value: StackProps<ElementType>['justify']) => {
|
||||
if (!value) return '';
|
||||
const map: Record<string, string> = { start: 'justify-start', center: 'justify-center', end: 'justify-end', between: 'justify-between', around: 'justify-around' };
|
||||
if (typeof value === 'object') {
|
||||
const classes = [];
|
||||
if (value.base) classes.push(map[value.base]);
|
||||
if (value.sm) classes.push(`sm:${map[value.sm]}`);
|
||||
if (value.md) classes.push(`md:${map[value.md]}`);
|
||||
if (value.lg) classes.push(`lg:${map[value.lg]}`);
|
||||
if (value.xl) classes.push(`xl:${map[value.xl]}`);
|
||||
if (value['2xl']) classes.push(`2xl:${map[value['2xl']]}`);
|
||||
return classes.join(' ');
|
||||
}
|
||||
return map[value];
|
||||
};
|
||||
|
||||
const layoutClasses = [
|
||||
getAlignItemsClass(align),
|
||||
getJustifyContentClass(justify)
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
return (
|
||||
<Box
|
||||
as={as}
|
||||
className={classes}
|
||||
alignItems={center ? 'center' : (align || alignItems)}
|
||||
justifyContent={center ? 'center' : (justify || justifyContent)}
|
||||
{...restProps}
|
||||
className={`${classes} ${layoutClasses}`}
|
||||
w={w}
|
||||
h={h}
|
||||
minWidth={minWidth}
|
||||
maxWidth={maxWidth}
|
||||
minHeight={minHeight}
|
||||
maxHeight={maxHeight}
|
||||
flex={flex}
|
||||
flexGrow={flexGrow}
|
||||
flexShrink={flexShrink}
|
||||
alignSelf={alignSelf}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user