/ |/ \ / \ / \ / | $$$$$$$$//$$$$$$ |$$$$$$$ |/$$$$$$ |$$$$$$$$/ $$ |__ $$ | $$ |$$ |__$$ |$$ | _$$/ $$ |__ $$ | $$ | $$ |$$ $$< $$ |/ |$$ | $$$$$/ $$ | $$ |$$$$$$$ |$$ |$$$$ |$$$$$/ $$ | $$ \__$$ |$$ | $$ |$$ \__$$ |$$ |_____ $$ | $$ $$/ $$ | $$ |$$ $$/ $$ | $$/ $$$$$$/ $$/ $$/ $$$$$$/ $$$$$$$$/
266 lines
9.0 KiB
TypeScript
266 lines
9.0 KiB
TypeScript
import { define } from 'forge'
|
|
import { theme } from './theme'
|
|
import { H2 } from './text'
|
|
import { RedBox, GreenBox, BlueBox } from './box'
|
|
import { Grid } from './grid'
|
|
import { Section } from './section'
|
|
|
|
export const VStack = define('VStack', {
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
|
|
variants: {
|
|
gap: {
|
|
0: { gap: 0 },
|
|
1: { gap: theme('spacing-1') },
|
|
2: { gap: theme('spacing-2') },
|
|
3: { gap: theme('spacing-3') },
|
|
4: { gap: theme('spacing-4') },
|
|
6: { gap: theme('spacing-6') },
|
|
8: { gap: theme('spacing-8') },
|
|
12: { gap: theme('spacing-12') },
|
|
},
|
|
v: {
|
|
start: { justifyContent: 'flex-start' },
|
|
center: { justifyContent: 'center' },
|
|
end: { justifyContent: 'flex-end' },
|
|
between: { justifyContent: 'space-between' },
|
|
around: { justifyContent: 'space-around' },
|
|
evenly: { justifyContent: 'space-evenly' },
|
|
},
|
|
h: {
|
|
start: { alignItems: 'flex-start' },
|
|
center: { alignItems: 'center' },
|
|
end: { alignItems: 'flex-end' },
|
|
stretch: { alignItems: 'stretch' },
|
|
baseline: { alignItems: 'baseline' },
|
|
},
|
|
wrap: {
|
|
flexWrap: 'wrap',
|
|
},
|
|
},
|
|
|
|
render({ props, parts: { Root } }) {
|
|
const { rows, style, ...rest } = props
|
|
const gridStyle = rows
|
|
? { display: 'grid', gridTemplateRows: rows.map((r: number) => `${r}fr`).join(' '), ...style }
|
|
: style
|
|
return <Root style={gridStyle} {...rest}>{props.children}</Root>
|
|
},
|
|
})
|
|
|
|
export const HStack = define('HStack', {
|
|
display: 'flex',
|
|
flexDirection: 'row',
|
|
|
|
variants: {
|
|
gap: {
|
|
0: { gap: 0 },
|
|
1: { gap: theme('spacing-1') },
|
|
2: { gap: theme('spacing-2') },
|
|
3: { gap: theme('spacing-3') },
|
|
4: { gap: theme('spacing-4') },
|
|
6: { gap: theme('spacing-6') },
|
|
8: { gap: theme('spacing-8') },
|
|
12: { gap: theme('spacing-12') },
|
|
},
|
|
h: {
|
|
start: { justifyContent: 'flex-start' },
|
|
center: { justifyContent: 'center' },
|
|
end: { justifyContent: 'flex-end' },
|
|
between: { justifyContent: 'space-between' },
|
|
around: { justifyContent: 'space-around' },
|
|
evenly: { justifyContent: 'space-evenly' },
|
|
},
|
|
v: {
|
|
start: { alignItems: 'flex-start' },
|
|
center: { alignItems: 'center' },
|
|
end: { alignItems: 'flex-end' },
|
|
stretch: { alignItems: 'stretch' },
|
|
baseline: { alignItems: 'baseline' },
|
|
},
|
|
wrap: {
|
|
flexWrap: 'wrap',
|
|
},
|
|
},
|
|
|
|
render({ props, parts: { Root } }) {
|
|
const { cols, style, ...rest } = props
|
|
const gridStyle = cols
|
|
? { display: 'grid', gridTemplateColumns: cols.map((c: number) => `${c}fr`).join(' '), ...style }
|
|
: style
|
|
return <Root style={gridStyle} {...rest}>{props.children}</Root>
|
|
},
|
|
})
|
|
|
|
type MainAxisOpts = 'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'
|
|
type CrossAxisOpts = 'start' | 'center' | 'end' | 'stretch' | 'baseline'
|
|
|
|
export const Test = () => {
|
|
const mainAxisOpts: MainAxisOpts[] = ['start', 'center', 'end', 'between', 'around', 'evenly']
|
|
const crossAxisOpts: CrossAxisOpts[] = ['start', 'center', 'end', 'stretch', 'baseline']
|
|
|
|
return (
|
|
<Section gap={8} style={{ padding: '16px' }}>
|
|
{/* HStack layout matrix */}
|
|
<VStack gap={2}>
|
|
<H2>HStack Layout</H2>
|
|
<div style={{ overflowX: 'auto' }}>
|
|
<Grid cols={7} gap={1} style={{ gridTemplateColumns: 'auto repeat(6, 1fr)' }}>
|
|
{/* Header row: blank + h labels */}
|
|
<div></div>
|
|
{mainAxisOpts.map((h) => (
|
|
<div key={h} style={{ fontSize: '14px', fontWeight: '500', textAlign: 'center' }}>
|
|
h: {h}
|
|
</div>
|
|
))}
|
|
|
|
{/* Each row: v label + HStack cells */}
|
|
{crossAxisOpts.map((v) => [
|
|
<div key={v} style={{ fontSize: '14px', fontWeight: '500' }}>
|
|
v: {v}
|
|
</div>,
|
|
...mainAxisOpts.map((h) => (
|
|
<HStack
|
|
key={`${h}-${v}`}
|
|
h={h}
|
|
v={v}
|
|
style={{ backgroundColor: '#f3f4f6', padding: '8px', height: '96px', border: '1px solid #9ca3af' }}
|
|
>
|
|
<RedBox>Aa</RedBox>
|
|
<GreenBox>Aa</GreenBox>
|
|
<BlueBox>Aa</BlueBox>
|
|
</HStack>
|
|
)),
|
|
])}
|
|
</Grid>
|
|
</div>
|
|
</VStack>
|
|
|
|
{/* VStack layout matrix */}
|
|
<VStack gap={2}>
|
|
<H2>VStack Layout</H2>
|
|
<div style={{ overflowX: 'auto' }}>
|
|
<Grid cols={6} gap={1} style={{ gridTemplateColumns: 'auto repeat(5, 1fr)' }}>
|
|
{/* Header row: blank + h labels */}
|
|
<div></div>
|
|
{crossAxisOpts.map((h) => (
|
|
<div key={h} style={{ fontSize: '14px', fontWeight: '500', textAlign: 'center' }}>
|
|
h: {h}
|
|
</div>
|
|
))}
|
|
|
|
{/* Each row: v label + VStack cells */}
|
|
{mainAxisOpts.map((v) => [
|
|
<div key={v} style={{ fontSize: '14px', fontWeight: '500' }}>
|
|
v: {v}
|
|
</div>,
|
|
...crossAxisOpts.map((h) => (
|
|
<VStack
|
|
key={`${h}-${v}`}
|
|
v={v}
|
|
h={h}
|
|
style={{ backgroundColor: '#f3f4f6', padding: '8px', height: '168px', border: '1px solid #9ca3af' }}
|
|
>
|
|
<RedBox>Aa</RedBox>
|
|
<GreenBox>Aa</GreenBox>
|
|
<BlueBox>Aa</BlueBox>
|
|
</VStack>
|
|
)),
|
|
])}
|
|
</Grid>
|
|
</div>
|
|
</VStack>
|
|
|
|
{/* Custom column sizing */}
|
|
<VStack gap={4}>
|
|
<H2>HStack with Custom Column Sizing</H2>
|
|
<VStack gap={4}>
|
|
<div>
|
|
<div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>
|
|
cols=[7, 3] (70%/30% split)
|
|
</div>
|
|
<HStack gap={4} cols={[7, 3]} style={{ backgroundColor: '#f3f4f6', padding: '16px' }}>
|
|
<div style={{ backgroundColor: '#bfdbfe', padding: '16px', textAlign: 'center' }}>
|
|
70% width
|
|
</div>
|
|
<div style={{ backgroundColor: '#fecaca', padding: '16px', textAlign: 'center' }}>
|
|
30% width
|
|
</div>
|
|
</HStack>
|
|
</div>
|
|
|
|
<div>
|
|
<div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>
|
|
cols=[2, 1] (66%/33% split)
|
|
</div>
|
|
<HStack gap={4} cols={[2, 1]} style={{ backgroundColor: '#f3f4f6', padding: '16px' }}>
|
|
<div style={{ backgroundColor: '#bbf7d0', padding: '16px', textAlign: 'center' }}>
|
|
2/3 width
|
|
</div>
|
|
<div style={{ backgroundColor: '#fef08a', padding: '16px', textAlign: 'center' }}>
|
|
1/3 width
|
|
</div>
|
|
</HStack>
|
|
</div>
|
|
|
|
<div>
|
|
<div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>
|
|
cols=[1, 2, 1] (25%/50%/25% split)
|
|
</div>
|
|
<HStack gap={4} cols={[1, 2, 1]} style={{ backgroundColor: '#f3f4f6', padding: '16px' }}>
|
|
<div style={{ backgroundColor: '#e9d5ff', padding: '16px', textAlign: 'center' }}>
|
|
25%
|
|
</div>
|
|
<div style={{ backgroundColor: '#bfdbfe', padding: '16px', textAlign: 'center' }}>
|
|
50%
|
|
</div>
|
|
<div style={{ backgroundColor: '#fbcfe8', padding: '16px', textAlign: 'center' }}>
|
|
25%
|
|
</div>
|
|
</HStack>
|
|
</div>
|
|
|
|
<div>
|
|
<div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>
|
|
cols=[7, 3] with maxWidth: 600px
|
|
</div>
|
|
<HStack gap={4} cols={[7, 3]} style={{ maxWidth: '600px', backgroundColor: '#f3f4f6', padding: '16px' }}>
|
|
<div style={{ backgroundColor: '#bfdbfe', padding: '16px', textAlign: 'center' }}>
|
|
70% of max 600px
|
|
</div>
|
|
<div style={{ backgroundColor: '#fecaca', padding: '16px', textAlign: 'center' }}>
|
|
30% of max 600px
|
|
</div>
|
|
</HStack>
|
|
</div>
|
|
</VStack>
|
|
</VStack>
|
|
|
|
{/* Custom row sizing */}
|
|
<VStack gap={4}>
|
|
<H2>VStack with Custom Row Sizing</H2>
|
|
<VStack gap={4}>
|
|
<div>
|
|
<div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>
|
|
rows=[2, 1] (2/3 and 1/3 height)
|
|
</div>
|
|
<VStack
|
|
gap={4}
|
|
rows={[2, 1]}
|
|
style={{ backgroundColor: '#f3f4f6', padding: '16px', height: '300px' }}
|
|
>
|
|
<div style={{ backgroundColor: '#bfdbfe', padding: '16px', textAlign: 'center' }}>
|
|
2/3 height
|
|
</div>
|
|
<div style={{ backgroundColor: '#fecaca', padding: '16px', textAlign: 'center' }}>
|
|
1/3 height
|
|
</div>
|
|
</VStack>
|
|
</div>
|
|
</VStack>
|
|
</VStack>
|
|
</Section>
|
|
)
|
|
}
|