Skip to content

Commit aa7a5f6

Browse files
author
Andrey Okonetchnikov
committed
Improve Stack
1 parent 99615ef commit aa7a5f6

File tree

2 files changed

+42
-27
lines changed

2 files changed

+42
-27
lines changed

packages/components/src/primitives/Stack.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
```tsx
44
<Stack gap={4}>
5-
<Box p={3} bg="primary">
5+
<Box p={3} bg="primary" width={"100%"}>
66
Item 1
77
</Box>
8-
<Box p={3} bg="primary">
8+
<Box p={3} bg="primary" width={"50%"}>
99
Item 2
1010
</Box>
11-
<Box p={3} bg="primary">
11+
<Box p={3} bg="primary" width={"25%"}>
1212
Item 3
1313
</Box>
1414
</Stack>
@@ -51,7 +51,7 @@ Stack respects flex props (but overrides margins) set on children elements:
5151
```tsx
5252
<Stack
5353
as="nav"
54-
gap={[1, 2, 4]}
54+
gap={[4, 3, 2]}
5555
direction={["vertical", "horizontal"]}
5656
wrap={[true, false, true]}
5757
p={4}
@@ -62,18 +62,15 @@ Stack respects flex props (but overrides margins) set on children elements:
6262
<Button>Drink coffee</Button>
6363
<Button>Buy pizza</Button>
6464
<Button>Großes Frühstück essen</Button>
65+
<Button>Code</Button>
6566
<Button>Drink coffee</Button>
6667
<Button>Buy pizza</Button>
6768
<Button>Großes Frühstück essen</Button>
69+
<Button>Code</Button>
6870
<Button>Drink coffee</Button>
6971
<Button>Buy pizza</Button>
7072
<Button>Großes Frühstück essen</Button>
71-
<Button>Drink coffee</Button>
72-
<Button>Buy pizza</Button>
73-
<Button>Großes Frühstück essen</Button>
74-
<Button>Drink coffee</Button>
75-
<Button>Buy pizza</Button>
76-
<Button>Großes Frühstück essen</Button>
73+
<Button>Code</Button>
7774
</Stack>
7875
```
7976

@@ -84,7 +81,7 @@ import { Heading, Stack, Text } from "../"
8481
;<Stack gap={4} p={4} border="thin" borderColor="muted">
8582
<Heading>Please fill the form</Heading>
8683
<Stack
87-
direction="horizontal"
84+
direction={["vertical", "horizontal"]}
8885
gap={3}
8986
pt={4}
9087
borderTop="thin"
@@ -94,11 +91,15 @@ import { Heading, Stack, Text } from "../"
9491
<Input name="item1" placeholder="Item 2" flexGrow={1} />
9592
<Button>Submit</Button>
9693
</Stack>
97-
<Stack gap={2} direction="horizontal" alignItems="baseline">
94+
<Stack
95+
gap={2}
96+
direction={["vertical", "horizontal"]}
97+
alignItems="baseline"
98+
>
9899
<Text variant="primary">
99100
By submitting this form you're accepting our terms.
100101
</Text>
101-
<Text variant="tertiary">The text must be aligned.</Text>
102+
<Text variant="tertiary">The text must be on the baseline.</Text>
102103
</Stack>
103104
</Stack>
104105
```

packages/components/src/primitives/Stack.tsx

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from "react"
22
import styled from "styled-components"
3-
import { ResponsiveValue, system } from "styled-system"
3+
import { ResponsiveValue, system, TLengthStyledSystem } from "styled-system"
44
import { Flex } from "../"
55
import { BoxProps } from "./Box"
6-
import theme, { Theme } from "../theme"
6+
import { Theme } from "../theme"
77

8-
type SpaceValue = keyof typeof theme.space
8+
type SpaceValue = number
99
type DirectionValue = "vertical" | "horizontal"
1010

1111
type StackBaseProps = Omit<BoxProps, "wrap"> & {
@@ -29,6 +29,9 @@ type StackProps = StackBaseProps & {
2929
as?: React.ElementType
3030
}
3131

32+
const toPx = (value: TLengthStyledSystem): string =>
33+
typeof value === "number" ? `${value}px` : value
34+
3235
const StackBase: React.FC<StackBaseProps> = styled(
3336
({ gap, direction, wrap, ...props }: StackProps) => <Flex {...props} />
3437
)<StackBaseProps>(
@@ -39,30 +42,41 @@ const StackBase: React.FC<StackBaseProps> = styled(
3942
// By using double && we increase specificity of this CSS selector
4043
property: "&&" as any,
4144
scale: "space",
42-
// And here instead of the value for the property we return an object
4345
// @ts-ignore solves the undefined is not assignable to string[]
4446
transform: (value: SpaceValue, scale: Theme["space"]) => {
45-
const gap = scale ? scale[value] : 0
47+
const gapValue = toPx(scale[value])
48+
// And here instead of the value for the property we return an object
4649
return {
50+
"--gap": gapValue,
4751
position: "relative",
48-
width: `calc(100% + ${gap})`,
49-
marginTop: `calc(-1 * ${gap})`,
50-
marginLeft: `calc(-1 * ${gap})`,
52+
width: `calc(100% + var(--gap))`,
53+
marginTop: `calc(-1 * var(--gap))`,
54+
marginLeft: `var(--root-ml)`,
5155
"> *": {
52-
marginTop: gap,
53-
marginLeft: gap
56+
marginTop: `var(--gap)`,
57+
marginLeft: `var(--child-ml)`
5458
}
5559
}
5660
}
5761
},
58-
direction: {
59-
property: "flexDirection",
60-
transform: (value: DirectionValue) => (value === "vertical" ? "column" : "row")
61-
},
6262
wrap: {
6363
property: "flexWrap",
6464
transform: (value: boolean) => (value ? "wrap" : "nowrap")
6565
}
66+
}),
67+
// Because we are using `property: "&&" in both cases, putting them into one `system` call
68+
// will produce conflicts and break for the case when both `gap` and `direction` are arrays.
69+
system({
70+
direction: {
71+
property: "&&" as any,
72+
transform: (value: DirectionValue) => {
73+
return {
74+
"--root-ml": value === "vertical" ? 0 : "calc(-1 * var(--gap))",
75+
"--child-ml": value === "vertical" ? 0 : "var(--gap)",
76+
flexDirection: value === "vertical" ? "column" : "row"
77+
}
78+
}
79+
}
6680
})
6781
)
6882

0 commit comments

Comments
 (0)