/** @jsxRuntime classic */ /** @jsx jsx */ import { Children, Fragment, type ReactNode, isValidElement } from 'react' import { jsx } from '../emotion' import { useMediaQuery } from '../hooks/useMediaQuery' import { useTheme } from '../theme' import { type Theme } from '../types' import { forwardRefWithAs, mapResponsiveProp, getChildTag } from '../utils' import { Box, type BoxProps } from './Box' import { Divider } from './Divider' const alignment = { center: 'center', end: 'flex-end', start: 'flex-start', stretch: 'stretch', } const orientationMap = { horizontal: { flexDirection: 'row', marginProperty: 'marginLeft', dimension: 'width', }, vertical: { flexDirection: 'column', marginProperty: 'marginTop', dimension: 'height', }, } as const export type StackProps = { /** The value of the "align-items" property. */ align?: keyof typeof alignment /** Each element in the stack. */ children: ReactNode /** Causes items in the stack to be oriented horizontally, instead of vertically */ across?: boolean /** The placement, if any, of the dividing elements. */ dividers?: 'none' | 'around' | 'between' | 'start' | 'end' /** The size of the gap between each element in the stack. */ gap?: keyof Theme['spacing'] } & BoxProps export const Stack = forwardRefWithAs<'div', StackProps>( ({ across, align = 'stretch', children, dividers = 'none', gap = 'none', ...props }, ref) => { const { spacing } = useTheme() const { mq } = useMediaQuery() const orientation = across ? 'horizontal' : 'vertical' const { dimension, flexDirection, marginProperty } = orientationMap[orientation] const ChildWrapper = getChildTag(props.as) return ( * + *': { [marginProperty]: mapResponsiveProp(gap, spacing), }, })} {...props} > {['around', 'start'].includes(dividers) && } {Children.toArray(children) .filter(child => isValidElement(child)) .map((child, index) => { return ( {dividers !== 'none' && index ? : null} {/* wrap the child to avoid unwanted or unexpected "stretch" on things like buttons */} {child} ) })} {['around', 'end'].includes(dividers) && } ) } )