Skip to content

Commit b7b7292

Browse files
[Box] Add support for responsive padding (#7697)
### WHY are these changes introduced? Support #7354 by adding responsive padding to `Box` ### WHAT is this pull request doing? - Add a mixin for generating responsive custom properties - `Box` now accepts a spacing token or object with breakpoints that map to spacing tokens for padding ### How to 🎩 Box stories have been added with responsive spacing Co-authored-by: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com>
1 parent 3bc63f7 commit b7b7292

File tree

8 files changed

+205
-45
lines changed

8 files changed

+205
-45
lines changed

.changeset/small-gifts-hope.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris': minor
3+
---
4+
5+
Added support for responsive padding to `Box`

polaris-react/src/components/Box/Box.scss

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,32 @@
1+
@import '../../styles/common';
2+
13
.Box {
4+
@include responsive-props('box', 'padding', 'padding');
5+
@include responsive-props(
6+
'box',
7+
'padding-block-end',
8+
'padding-block-end',
9+
'padding'
10+
);
11+
@include responsive-props(
12+
'box',
13+
'padding-block-start',
14+
'padding-block-start',
15+
'padding'
16+
);
17+
@include responsive-props(
18+
'box',
19+
'padding-inline-start',
20+
'padding-inline-start',
21+
'padding'
22+
);
23+
@include responsive-props(
24+
'box',
25+
'padding-inline-end',
26+
'padding-inline-end',
27+
'padding'
28+
);
29+
230
--pc-box-shadow: initial;
331
--pc-box-background: initial;
432
--pc-box-border-radius: initial;
@@ -69,13 +97,6 @@
6997
max-width: var(--pc-box-max-width);
7098
overflow-x: var(--pc-box-overflow-x);
7199
overflow-y: var(--pc-box-overflow-y);
72-
padding-block-end: var(--pc-box-padding-block-end, var(--pc-box-padding));
73-
padding-inline-start: var(
74-
--pc-box-padding-inline-start,
75-
var(--pc-box-padding)
76-
);
77-
padding-inline-end: var(--pc-box-padding-inline-end, var(--pc-box-padding));
78-
padding-block-start: var(--pc-box-padding-block-start, var(--pc-box-padding));
79100
width: var(--pc-box-width);
80101
-webkit-overflow-scrolling: touch;
81102
}

polaris-react/src/components/Box/Box.stories.tsx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react';
22
import type {ComponentMeta} from '@storybook/react';
3-
import {Box, Icon} from '@shopify/polaris';
3+
import {AlphaStack, Box, Icon} from '@shopify/polaris';
44
import {PaintBrushMajor} from '@shopify/polaris-icons';
55

66
export default {
@@ -30,3 +30,44 @@ export function BoxWithBorderRadius() {
3030
</Box>
3131
);
3232
}
33+
34+
export function BoxWithResponsivePadding() {
35+
return (
36+
<AlphaStack>
37+
<Box background="surface" padding={{xs: '2', sm: '8'}} border="dark">
38+
<Icon source={PaintBrushMajor} color="base" />
39+
</Box>
40+
<Box
41+
background="surface"
42+
padding="2"
43+
paddingBlockStart={{xs: '4', sm: '10'}}
44+
border="dark"
45+
>
46+
<Icon source={PaintBrushMajor} color="base" />
47+
</Box>
48+
<Box
49+
background="surface"
50+
padding="2"
51+
paddingBlockEnd={{xs: '4', sm: '10'}}
52+
border="dark"
53+
>
54+
<Icon source={PaintBrushMajor} color="base" />
55+
</Box>
56+
<Box
57+
background="surface"
58+
padding="2"
59+
paddingInlineStart={{xs: '4', sm: '10'}}
60+
border="dark"
61+
>
62+
<Icon source={PaintBrushMajor} color="base" />
63+
</Box>
64+
<Box
65+
background="surface"
66+
paddingInlineEnd={{xs: '4', sm: '10'}}
67+
border="dark"
68+
>
69+
<Icon source={PaintBrushMajor} color="base" />
70+
</Box>
71+
</AlphaStack>
72+
);
73+
}

polaris-react/src/components/Box/Box.tsx

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import type {
1010
SpacingSpaceScale,
1111
} from '@shopify/polaris-tokens';
1212

13-
import {classNames, sanitizeCustomProperties} from '../../utilities/css';
13+
import {
14+
getResponsiveProps,
15+
ResponsiveProp,
16+
classNames,
17+
sanitizeCustomProperties,
18+
} from '../../utilities/css';
1419

1520
import styles from './Box.scss';
1621

@@ -42,6 +47,8 @@ export type BorderTokenAlias =
4247
| 'divider-on-dark'
4348
| 'transparent';
4449

50+
type Spacing = ResponsiveProp<SpacingSpaceScale>;
51+
4552
interface Border {
4653
blockStart: BorderTokenAlias;
4754
blockEnd: BorderTokenAlias;
@@ -75,13 +82,6 @@ interface BorderRadius {
7582
endEnd: BorderRadiusTokenScale;
7683
}
7784

78-
interface Spacing {
79-
blockStart: SpacingSpaceScale;
80-
blockEnd: SpacingSpaceScale;
81-
inlineStart: SpacingSpaceScale;
82-
inlineEnd: SpacingSpaceScale;
83-
}
84-
8585
interface BorderWidth {
8686
blockStart: ShapeBorderWidthScale;
8787
blockEnd: ShapeBorderWidthScale;
@@ -139,15 +139,15 @@ export interface BoxProps {
139139
/** Clip vertical content of children */
140140
overflowY?: Overflow;
141141
/** Spacing around children */
142-
padding?: SpacingSpaceScale;
142+
padding?: Spacing;
143143
/** Vertical start spacing around children */
144-
paddingBlockStart?: SpacingSpaceScale;
144+
paddingBlockStart?: Spacing;
145145
/** Vertical end spacing around children */
146-
paddingBlockEnd?: SpacingSpaceScale;
146+
paddingBlockEnd?: Spacing;
147147
/** Horizontal start spacing around children */
148-
paddingInlineStart?: SpacingSpaceScale;
148+
paddingInlineStart?: Spacing;
149149
/** Horizontal end spacing around children */
150-
paddingInlineEnd?: SpacingSpaceScale;
150+
paddingInlineEnd?: Spacing;
151151
/** Shadow */
152152
shadow?: DepthShadowAlias;
153153
/** Set width of container */
@@ -215,13 +215,6 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
215215
inlineEnd: borderInlineEndWidth,
216216
} as BorderWidth;
217217

218-
const paddings = {
219-
blockEnd: paddingBlockEnd,
220-
inlineStart: paddingInlineStart,
221-
inlineEnd: paddingInlineEnd,
222-
blockStart: paddingBlockStart,
223-
} as Spacing;
224-
225218
const style = {
226219
'--pc-box-color': color ? `var(--p-${color})` : undefined,
227220
'--pc-box-background': background ? `var(--p-${background})` : undefined,
@@ -273,19 +266,31 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
273266
'--pc-box-max-width': maxWidth,
274267
'--pc-box-overflow-x': overflowX,
275268
'--pc-box-overflow-y': overflowY,
276-
'--pc-box-padding': padding ? `var(--p-space-${padding})` : undefined,
277-
'--pc-box-padding-block-end': paddings.blockEnd
278-
? `var(--p-space-${paddings.blockEnd})`
279-
: undefined,
280-
'--pc-box-padding-inline-start': paddings.inlineStart
281-
? `var(--p-space-${paddings.inlineStart})`
282-
: undefined,
283-
'--pc-box-padding-inline-end': paddings.inlineEnd
284-
? `var(--p-space-${paddings.inlineEnd})`
285-
: undefined,
286-
'--pc-box-padding-block-start': paddings.blockStart
287-
? `var(--p-space-${paddings.blockStart})`
288-
: undefined,
269+
...getResponsiveProps('box', 'padding', 'space', padding),
270+
...getResponsiveProps(
271+
'box',
272+
'padding-block-end',
273+
'space',
274+
paddingBlockEnd,
275+
),
276+
...getResponsiveProps(
277+
'box',
278+
'padding-block-start',
279+
'space',
280+
paddingBlockStart,
281+
),
282+
...getResponsiveProps(
283+
'box',
284+
'padding-inline-start',
285+
'space',
286+
paddingInlineStart,
287+
),
288+
...getResponsiveProps(
289+
'box',
290+
'padding-inline-end',
291+
'space',
292+
paddingInlineEnd,
293+
),
289294
'--pc-box-shadow': shadow ? `var(--p-shadow-${shadow})` : undefined,
290295
'--pc-box-width': width,
291296
} as React.CSSProperties;

polaris-react/src/components/Box/tests/Box.test.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe('Box', () => {
7979

8080
expect(box).toContainReactComponent('div', {
8181
style: {
82-
'--pc-box-padding-inline-start': 'var(--p-space-2)',
82+
'--pc-box-padding-inline-start-xs': 'var(--p-space-2)',
8383
} as React.CSSProperties,
8484
});
8585
});
@@ -93,9 +93,22 @@ describe('Box', () => {
9393

9494
expect(box).toContainReactComponent('div', {
9595
style: {
96-
'--pc-box-padding': 'var(--p-space-1)',
97-
'--pc-box-padding-inline-start': 'var(--p-space-2)',
96+
'--pc-box-padding-xs': 'var(--p-space-1)',
97+
'--pc-box-padding-inline-start-xs': 'var(--p-space-2)',
9898
} as React.CSSProperties,
9999
});
100100
});
101+
102+
it('accepts padding based on breakpoints', () => {
103+
const box = mountWithApp(
104+
<Box padding={{xs: '2', md: '8'}}>{children}</Box>,
105+
);
106+
107+
expect(box).toContainReactComponent('div', {
108+
style: expect.objectContaining({
109+
'--pc-box-padding-md': 'var(--p-space-8)',
110+
'--pc-box-padding-xs': 'var(--p-space-2)',
111+
}) as React.CSSProperties,
112+
});
113+
});
101114
});

polaris-react/src/styles/_common.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
@import './shared/icons';
1616
@import './shared/layout';
1717
@import './shared/page';
18+
@import './shared/responsive-props';
1819
@import './shared/typography';
1920
@import './shared/interaction-state';
2021

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
@mixin responsive-props(
2+
$componentName,
3+
$componentProp,
4+
$declartionProp,
5+
$shorthandFallback: null
6+
) {
7+
--pc-#{$componentName}-#{$componentProp}-xs: initial;
8+
--pc-#{$componentName}-#{$componentProp}-sm: var(
9+
--pc-#{$componentName}-#{$componentProp}-xs
10+
);
11+
--pc-#{$componentName}-#{$componentProp}-md: var(
12+
--pc-#{$componentName}-#{$componentProp}-sm
13+
);
14+
--pc-#{$componentName}-#{$componentProp}-lg: var(
15+
--pc-#{$componentName}-#{$componentProp}-md
16+
);
17+
--pc-#{$componentName}-#{$componentProp}-xl: var(
18+
--pc-#{$componentName}-#{$componentProp}-lg
19+
);
20+
@if $shorthandFallback {
21+
#{$declartionProp}: var(
22+
--pc-#{$componentName}-#{$componentProp}-xs,
23+
var(--pc-#{$componentName}-#{$shorthandFallback}-xs)
24+
);
25+
26+
@media #{$p-breakpoints-sm-up} {
27+
#{$declartionProp}: var(
28+
--pc-#{$componentName}-#{$componentProp}-sm,
29+
var(--pc-#{$componentName}-#{$shorthandFallback}-sm)
30+
);
31+
}
32+
33+
@media #{$p-breakpoints-md-up} {
34+
#{$declartionProp}: var(
35+
--pc-#{$componentName}-#{$componentProp}-md,
36+
var(--pc-#{$componentName}-#{$shorthandFallback}-md)
37+
);
38+
}
39+
40+
@media #{$p-breakpoints-lg-up} {
41+
#{$declartionProp}: var(
42+
--pc-#{$componentName}-#{$componentProp}-lg,
43+
var(--pc-#{$componentName}-#{$shorthandFallback}-lg)
44+
);
45+
}
46+
47+
@media #{$p-breakpoints-xl-up} {
48+
#{$declartionProp}: var(
49+
--pc-#{$componentName}-#{$componentProp}-xl,
50+
var(--pc-#{$componentName}-#{$shorthandFallback}-xl)
51+
);
52+
}
53+
} @else {
54+
#{$declartionProp}: var(--pc-#{$componentName}-#{$componentProp}-xs);
55+
56+
@media #{$p-breakpoints-sm-up} {
57+
#{$declartionProp}: var(--pc-#{$componentName}-#{$componentProp}-sm);
58+
}
59+
60+
@media #{$p-breakpoints-md-up} {
61+
#{$declartionProp}: var(--pc-#{$componentName}-#{$componentProp}-md);
62+
}
63+
64+
@media #{$p-breakpoints-lg-up} {
65+
#{$declartionProp}: var(--pc-#{$componentName}-#{$componentProp}-lg);
66+
}
67+
68+
@media #{$p-breakpoints-xl-up} {
69+
#{$declartionProp}: var(--pc-#{$componentName}-#{$componentProp}-xl);
70+
}
71+
}
72+
}

polaris-react/src/utilities/css.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ export function getResponsiveProps(
3030
componentName: string,
3131
componentProp: string,
3232
tokenSubgroup: string,
33-
responsiveProp:
33+
responsiveProp?:
3434
| string
3535
| {
3636
[Breakpoint in BreakpointsAlias]?: string;
3737
},
3838
) {
39+
if (!responsiveProp) return {};
40+
3941
if (typeof responsiveProp === 'string') {
4042
return {
4143
[`--pc-${componentName}-${componentProp}-xs`]: `var(--p-${tokenSubgroup}-${responsiveProp})`,

0 commit comments

Comments
 (0)