Skip to content

Commit 31abdab

Browse files
authored
[Layout foundations] Add LegacyStack component (#8240)
### WHY are these changes introduced? Resolves #8232 . Creating a `LegacyStack` component that is a duplicate of the existing `Stack` in light of upcoming work to replace this with the `AlphaStack` component. ### WHAT is this pull request doing? Adds `LegacyStack` to `polaris-react`. Adds `LegacyStack` page to style guide with examples and prop table. <!-- ℹ️ Delete the following for small / trivial changes --> ### How to 🎩 🖥 [Local development instructions](https://github.com/Shopify/polaris/blob/main/README.md#local-development) 🗒 [General tophatting guidelines](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md) 📄 [Changelog guidelines](https://github.com/Shopify/polaris/blob/main/.github/CONTRIBUTING.md#changelog) ### 🎩 checklist - [ ] Tested on [mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing) - [ ] Tested on [multiple browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers) - [ ] Tested for [accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md) - [ ] Updated the component's `README.md` with documentation changes - [x] [Tophatted documentation](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting%20documentation.md) changes in the style guide
1 parent bb8b551 commit 31abdab

20 files changed

+2340
-1685
lines changed

.changeset/calm-hats-cover.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@shopify/polaris': minor
3+
'polaris.shopify.com': minor
4+
---
5+
6+
Added `LegacyStack` component
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
.LegacyStack {
2+
// stylelint-disable-next-line -- Polaris component custom properties
3+
--pc-stack-spacing: var(--p-space-4);
4+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
5+
display: flex;
6+
flex-wrap: wrap;
7+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
8+
align-items: stretch;
9+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
10+
margin-top: calc(-1 * var(--pc-stack-spacing));
11+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
12+
margin-left: calc(-1 * var(--pc-stack-spacing));
13+
14+
> .Item {
15+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
16+
margin-top: var(--pc-stack-spacing);
17+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
18+
margin-left: var(--pc-stack-spacing);
19+
max-width: 100%;
20+
}
21+
}
22+
23+
.noWrap {
24+
flex-wrap: nowrap;
25+
}
26+
27+
.spacingNone {
28+
// stylelint-disable-next-line -- Polaris component custom properties
29+
--pc-stack-spacing: var(--p-space-0);
30+
}
31+
32+
.spacingExtraTight {
33+
// stylelint-disable-next-line -- Polaris component custom properties
34+
--pc-stack-spacing: var(--p-space-1);
35+
}
36+
37+
.spacingTight {
38+
// stylelint-disable-next-line -- Polaris component custom properties
39+
--pc-stack-spacing: var(--p-space-2);
40+
}
41+
42+
.spacingBaseTight {
43+
// stylelint-disable-next-line -- Polaris component custom properties
44+
--pc-stack-spacing: var(--p-space-3);
45+
}
46+
47+
.spacingLoose {
48+
// stylelint-disable-next-line -- Polaris component custom properties
49+
--pc-stack-spacing: var(--p-space-5);
50+
}
51+
52+
.spacingExtraLoose {
53+
// stylelint-disable-next-line -- Polaris component custom properties
54+
--pc-stack-spacing: var(--p-space-8);
55+
}
56+
57+
.distributionLeading {
58+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
59+
justify-content: flex-start;
60+
}
61+
62+
.distributionTrailing {
63+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
64+
justify-content: flex-end;
65+
}
66+
67+
.distributionCenter {
68+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
69+
justify-content: center;
70+
}
71+
72+
.distributionEqualSpacing {
73+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
74+
justify-content: space-between;
75+
}
76+
77+
.distributionFill > .Item {
78+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
79+
flex: 1 1 auto;
80+
}
81+
82+
.distributionFillEvenly > .Item {
83+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
84+
flex: 1 1 auto;
85+
86+
@supports (min-width: fit-content) {
87+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
88+
flex: 1 0 0%;
89+
min-width: fit-content;
90+
}
91+
}
92+
93+
.alignmentLeading {
94+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
95+
align-items: flex-start;
96+
}
97+
98+
.alignmentTrailing {
99+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
100+
align-items: flex-end;
101+
}
102+
103+
.alignmentCenter {
104+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
105+
align-items: center;
106+
}
107+
108+
.alignmentFill {
109+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
110+
align-items: stretch;
111+
}
112+
113+
.alignmentBaseline {
114+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
115+
align-items: baseline;
116+
}
117+
118+
.vertical {
119+
flex-direction: column;
120+
margin-left: var(--p-space-0);
121+
122+
> .Item {
123+
margin-left: var(--p-space-0);
124+
}
125+
}
126+
127+
.Item {
128+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
129+
flex: 0 0 auto;
130+
min-width: 0;
131+
}
132+
133+
.Item-fill {
134+
// stylelint-disable-next-line -- generated by polaris-migrator DO NOT COPY
135+
flex: 1 1 auto;
136+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import React from 'react';
2+
import type {ComponentMeta} from '@storybook/react';
3+
import {Badge, Text, LegacyStack} from '@shopify/polaris';
4+
5+
export default {
6+
component: LegacyStack,
7+
} as ComponentMeta<typeof LegacyStack>;
8+
9+
export function Default() {
10+
return (
11+
<LegacyStack>
12+
<Badge>Paid</Badge>
13+
<Badge>Processing</Badge>
14+
<Badge>Fulfilled</Badge>
15+
<Badge>Completed</Badge>
16+
</LegacyStack>
17+
);
18+
}
19+
20+
export function NonWrapping() {
21+
return (
22+
<LegacyStack wrap={false}>
23+
<Badge>Paid</Badge>
24+
<Badge>Processing</Badge>
25+
<Badge>Fulfilled</Badge>
26+
<Badge>Completed</Badge>
27+
</LegacyStack>
28+
);
29+
}
30+
31+
export function Spacing() {
32+
return (
33+
<LegacyStack spacing="loose">
34+
<Badge>Paid</Badge>
35+
<Badge>Fulfilled</Badge>
36+
</LegacyStack>
37+
);
38+
}
39+
40+
export function VerticalCentering() {
41+
return (
42+
<LegacyStack alignment="center">
43+
<Text variant="headingMd" as="h2">
44+
Order
45+
<br />
46+
#1136
47+
<br />
48+
was paid
49+
</Text>
50+
<Badge>Paid</Badge>
51+
<Badge>Fulfilled</Badge>
52+
</LegacyStack>
53+
);
54+
}
55+
56+
export function FillAvailableSpaceProportionally() {
57+
return (
58+
<LegacyStack distribution="fill">
59+
<Text variant="headingMd" as="h2">
60+
Order #1136
61+
</Text>
62+
<Badge>Paid</Badge>
63+
<Badge>Fulfilled</Badge>
64+
</LegacyStack>
65+
);
66+
}
67+
68+
export function WhereItemsFillSpaceEvenly() {
69+
return (
70+
<LegacyStack distribution="fillEvenly">
71+
<Text variant="headingMd" as="h2">
72+
Order #1136
73+
</Text>
74+
<Badge>Paid</Badge>
75+
<Badge>Fulfilled</Badge>
76+
</LegacyStack>
77+
);
78+
}
79+
80+
export function WhereASingleItemFillsTheRemainingSpace() {
81+
return (
82+
<LegacyStack>
83+
<LegacyStack.Item fill>
84+
<Text variant="headingMd" as="h2">
85+
Order #1136
86+
</Text>
87+
</LegacyStack.Item>
88+
<LegacyStack.Item>
89+
<Badge>Paid</Badge>
90+
</LegacyStack.Item>
91+
<LegacyStack.Item>
92+
<Badge>Fulfilled</Badge>
93+
</LegacyStack.Item>
94+
</LegacyStack>
95+
);
96+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React, {memo, NamedExoticComponent} from 'react';
2+
3+
import {classNames, variationName} from '../../utilities/css';
4+
import {elementChildren, wrapWithComponent} from '../../utilities/components';
5+
6+
import {Item} from './components';
7+
import styles from './LegacyStack.scss';
8+
9+
type Spacing =
10+
| 'extraTight'
11+
| 'tight'
12+
| 'baseTight'
13+
| 'loose'
14+
| 'extraLoose'
15+
| 'none';
16+
17+
type Alignment = 'leading' | 'trailing' | 'center' | 'fill' | 'baseline';
18+
19+
type Distribution =
20+
| 'equalSpacing'
21+
| 'leading'
22+
| 'trailing'
23+
| 'center'
24+
| 'fill'
25+
| 'fillEvenly';
26+
27+
export interface LegacyStackProps {
28+
/** Elements to display inside stack */
29+
children?: React.ReactNode;
30+
/** Wrap stack elements to additional rows as needed on small screens (Defaults to true) */
31+
wrap?: boolean;
32+
/** Stack the elements vertically */
33+
vertical?: boolean;
34+
/** Adjust spacing between elements */
35+
spacing?: Spacing;
36+
/** Adjust vertical alignment of elements */
37+
alignment?: Alignment;
38+
/** Adjust horizontal alignment of elements */
39+
distribution?: Distribution;
40+
}
41+
42+
export const LegacyStack = memo(function Stack({
43+
children,
44+
vertical,
45+
spacing,
46+
distribution,
47+
alignment,
48+
wrap,
49+
}: LegacyStackProps) {
50+
const className = classNames(
51+
styles.LegacyStack,
52+
vertical && styles.vertical,
53+
spacing && styles[variationName('spacing', spacing)],
54+
distribution && styles[variationName('distribution', distribution)],
55+
alignment && styles[variationName('alignment', alignment)],
56+
wrap === false && styles.noWrap,
57+
);
58+
59+
const itemMarkup = elementChildren(children).map((child, index) => {
60+
const props = {key: index};
61+
return wrapWithComponent(child, Item, props);
62+
});
63+
64+
return <div className={className}>{itemMarkup}</div>;
65+
}) as NamedExoticComponent<LegacyStackProps> & {
66+
Item: typeof Item;
67+
};
68+
69+
LegacyStack.Item = Item;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react';
2+
3+
import {classNames} from '../../../../utilities/css';
4+
import styles from '../../LegacyStack.scss';
5+
6+
export interface LegacyItemProps {
7+
/** Elements to display inside item */
8+
children?: React.ReactNode;
9+
/** Fill the remaining horizontal space in the stack with the item */
10+
fill?: boolean;
11+
/**
12+
* @default false
13+
*/
14+
}
15+
16+
export function Item({children, fill}: LegacyItemProps) {
17+
const className = classNames(styles.Item, fill && styles['Item-fill']);
18+
19+
return <div className={className}>{children}</div>;
20+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Item';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Item';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './LegacyStack';
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from 'react';
2+
import {mountWithApp} from 'tests/utilities';
3+
4+
import {LegacyStack} from '../LegacyStack';
5+
6+
describe('<LegacyStack />', () => {
7+
const renderChildren = () => [0, 1].map((i) => <div key={i}>Child {i}</div>);
8+
9+
it('renders its children', () => {
10+
const legacyStack = mountWithApp(
11+
<LegacyStack>{renderChildren()}</LegacyStack>,
12+
);
13+
14+
expect(legacyStack).toContainReactComponentTimes(LegacyStack.Item, 2);
15+
});
16+
});

polaris-react/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@ export type {
249249
LegacyCardSubsectionProps,
250250
} from './components/LegacyCard';
251251

252+
export {LegacyStack} from './components/LegacyStack';
253+
export type {LegacyStackProps} from './components/LegacyStack';
254+
252255
export {Link} from './components/Link';
253256
export type {LinkProps} from './components/Link';
254257

0 commit comments

Comments
 (0)