Skip to content

Commit e87330f

Browse files
avelineaaronccasanovakyledurand
authored
Update AlphaStack (#7429)
### WHY are these changes introduced? Through the rebuilding of `ChoiceList` (#7354) I have found there are a few updates that would make `AlphaStack` more flexible. ### WHAT is this pull request doing? - Make `AlphaStack` polymorphic and allow it to be a `ul` or a `fieldset` in addition to a `div`. Both those elements are used to contain a list or group of elements that may require equal spacing. This allows `AlphaStack` to be used in those instances while still providing semantic markup. - Include some reset styles for when the `ul` element is set on `AlphaStack` to override default browser styling for `ul`. This removes margin and padding which makes sense since spacing should be handled by layout components. It also removes the default `ul` bullet. Is this too opinionated? Are there use cases where `AlphaStack` would be used for spacing items in a list with the default browser bullet? <img width="278" alt="Screen Shot 2022-10-17 at 3 00 12 PM" src="https://user-images.githubusercontent.com/3474483/196292082-c68d8c07-8d8b-4336-8a92-8e5363f04894.png">|<img width="249" alt="Screen Shot 2022-10-17 at 3 00 24 PM" src="https://user-images.githubusercontent.com/3474483/196292137-e906bc45-e7f6-4729-b2d9-09f2295380ac.png"> :----:|:----: Default `ul` styles|Reset `ul` styles - Update `AlphaStack` to allow responsive spacing. The `spacing` prop can now accept an object with a breakpoint and the spacing value. Co-authored-by: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com> Co-authored-by: Kyle Durand <6844391+kyledurand@users.noreply.github.com>
1 parent a9eff60 commit e87330f

File tree

7 files changed

+140
-16
lines changed

7 files changed

+140
-16
lines changed
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+
Update `AlphaStack` to be polymorphic, add list reset styles and allow spacing to change based on breakpoint

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,44 @@
1+
@import '../../styles/common';
2+
13
.AlphaStack {
4+
--pc-stack-spacing-xs: var(--p-space-4);
5+
--pc-stack-spacing-sm: var(--pc-stack-spacing-xs);
6+
--pc-stack-spacing-md: var(--pc-stack-spacing-sm);
7+
--pc-stack-spacing-lg: var(--pc-stack-spacing-md);
8+
--pc-stack-spacing-xl: var(--pc-stack-spacing-lg);
29
display: flex;
310
flex-direction: column;
411
align-items: var(--pc-stack-align);
5-
gap: var(--pc-stack-spacing);
12+
gap: var(--pc-stack-spacing-xs);
13+
14+
@media #{$p-breakpoints-sm-up} {
15+
gap: var(--pc-stack-spacing-sm);
16+
}
17+
18+
@media #{$p-breakpoints-md-up} {
19+
gap: var(--pc-stack-spacing-md);
20+
}
21+
22+
@media #{$p-breakpoints-lg-up} {
23+
gap: var(--pc-stack-spacing-lg);
24+
}
25+
26+
@media #{$p-breakpoints-xl-up} {
27+
gap: var(--pc-stack-spacing-xl);
28+
}
629

730
> * {
831
max-width: 100%;
932
}
1033
}
1134

35+
.listReset {
36+
list-style-type: none;
37+
margin-block-start: 0;
38+
margin-block-end: 0;
39+
padding-inline-start: 0;
40+
}
41+
1242
.fullWidth {
1343
> * {
1444
width: 100%;

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,14 @@ export function FullWidthChildren() {
6060
</AlphaStack>
6161
);
6262
}
63+
64+
export function ResponsiveSpacing() {
65+
return (
66+
<AlphaStack spacing={{xs: '4', md: '10'}}>
67+
<Badge>Paid</Badge>
68+
<Badge>Processing</Badge>
69+
<Badge>Fulfilled</Badge>
70+
<Badge>Completed</Badge>
71+
</AlphaStack>
72+
);
73+
}
Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
1-
import React from 'react';
1+
import React, {createElement} from 'react';
22
import type {SpacingSpaceScale} from '@shopify/polaris-tokens';
33

4-
import {classNames} from '../../utilities/css';
4+
import {
5+
classNames,
6+
sanitizeCustomProperties,
7+
getResponsiveProps,
8+
} from '../../utilities/css';
9+
import type {ResponsiveProp} from '../../utilities/css';
510

611
import styles from './AlphaStack.scss';
712

813
type Align = 'start' | 'end' | 'center';
914

15+
type Element = 'div' | 'ul' | 'ol' | 'fieldset';
16+
17+
type Spacing = ResponsiveProp<SpacingSpaceScale>;
18+
1019
export interface AlphaStackProps {
20+
/** HTML Element type */
21+
as?: Element;
1122
/** Elements to display inside stack */
1223
children?: React.ReactNode;
1324
/** Adjust vertical alignment of elements */
1425
align?: Align;
1526
/** Toggle elements to be full width */
1627
fullWidth?: boolean;
1728
/** Adjust spacing between elements */
18-
spacing?: SpacingSpaceScale;
29+
spacing?: Spacing;
1930
}
2031

2132
export const AlphaStack = ({
33+
as = 'div',
2234
children,
2335
align = 'start',
2436
fullWidth,
@@ -27,16 +39,20 @@ export const AlphaStack = ({
2739
const className = classNames(
2840
styles.AlphaStack,
2941
fullWidth && styles.fullWidth,
42+
as === 'ul' && styles.listReset,
3043
);
3144

3245
const style = {
3346
'--pc-stack-align': align ? `${align}` : '',
34-
...(spacing ? {'--pc-stack-spacing': `var(--p-space-${spacing})`} : {}),
47+
...getResponsiveProps('stack', 'spacing', 'space', spacing),
3548
} as React.CSSProperties;
3649

37-
return (
38-
<div className={className} style={style}>
39-
{children}
40-
</div>
50+
return createElement(
51+
as,
52+
{
53+
className,
54+
style: sanitizeCustomProperties(style),
55+
},
56+
children,
4157
);
4258
};

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ describe('<AlphaStack />', () => {
1717
const stack = mountWithApp(<AlphaStack>{children}</AlphaStack>);
1818

1919
expect(stack).toContainReactComponent('div', {
20-
style: {
20+
style: expect.objectContaining({
2121
'--pc-stack-align': 'start',
22-
'--pc-stack-spacing': 'var(--p-space-4)',
23-
} as React.CSSProperties,
22+
'--pc-stack-spacing-xs': 'var(--p-space-4)',
23+
}) as React.CSSProperties,
2424
});
2525
});
2626

@@ -32,10 +32,23 @@ describe('<AlphaStack />', () => {
3232
);
3333

3434
expect(stack).toContainReactComponent('div', {
35-
style: {
35+
style: expect.objectContaining({
3636
'--pc-stack-align': 'center',
37-
'--pc-stack-spacing': 'var(--p-space-10)',
38-
} as React.CSSProperties,
37+
'--pc-stack-spacing-xs': 'var(--p-space-10)',
38+
}) as React.CSSProperties,
39+
});
40+
});
41+
42+
it('accepts spacing based on breakpoints', () => {
43+
const stack = mountWithApp(
44+
<AlphaStack spacing={{xs: '2', md: '8'}}>{children}</AlphaStack>,
45+
);
46+
47+
expect(stack).toContainReactComponent('div', {
48+
style: expect.objectContaining({
49+
'--pc-stack-spacing-md': 'var(--p-space-8)',
50+
'--pc-stack-spacing-xs': 'var(--p-space-2)',
51+
}) as React.CSSProperties,
3952
});
4053
});
4154
});

polaris-react/src/utilities/css.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
import type {BreakpointsAlias} from '@shopify/polaris-tokens';
2+
13
type Falsy = boolean | undefined | null | 0;
24

5+
export type ResponsiveProp<T> =
6+
| T
7+
| {
8+
[Breakpoint in BreakpointsAlias]?: T;
9+
};
10+
311
export function classNames(...classes: (string | Falsy)[]) {
412
return classes.filter(Boolean).join(' ');
513
}
@@ -17,3 +25,27 @@ export function sanitizeCustomProperties(
1725

1826
return nonNullValues.length ? Object.fromEntries(nonNullValues) : undefined;
1927
}
28+
29+
export function getResponsiveProps(
30+
componentName: string,
31+
componentProp: string,
32+
tokenSubgroup: string,
33+
responsiveProp:
34+
| string
35+
| {
36+
[Breakpoint in BreakpointsAlias]?: string;
37+
},
38+
) {
39+
if (typeof responsiveProp === 'string') {
40+
return {
41+
[`--pc-${componentName}-${componentProp}-xs`]: `var(--p-${tokenSubgroup}-${responsiveProp})`,
42+
};
43+
}
44+
45+
return Object.fromEntries(
46+
Object.entries(responsiveProp).map(([breakpointAlias, aliasOrScale]) => [
47+
`--pc-${componentName}-${componentProp}-${breakpointAlias}`,
48+
`var(--p-${tokenSubgroup}-${aliasOrScale})`,
49+
]),
50+
);
51+
}

polaris-react/src/utilities/tests/css.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {classNames, variationName} from '../css';
1+
import {classNames, variationName, getResponsiveProps} from '../css';
22

33
describe('classNames', () => {
44
it('returns a single string from multiple classes', () => {
@@ -24,3 +24,20 @@ describe('variationName', () => {
2424
expect(variationName('size', 'medium')).toBe('sizeMedium');
2525
});
2626
});
27+
28+
describe('getResponsiveProps', () => {
29+
it('takes a string and returns the custom property', () => {
30+
expect(getResponsiveProps('stack', 'space', 'space', '4')).toMatchObject({
31+
'--pc-stack-space-xs': 'var(--p-space-4)',
32+
});
33+
});
34+
35+
it('takes an object with a breakpoint and value and returns the property for each breakpoint', () => {
36+
expect(
37+
getResponsiveProps('stack', 'space', 'space', {xs: '2', md: '8'}),
38+
).toMatchObject({
39+
'--pc-stack-space-xs': 'var(--p-space-2)',
40+
'--pc-stack-space-md': 'var(--p-space-8)',
41+
});
42+
});
43+
});

0 commit comments

Comments
 (0)