Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions packages/components/.storybook/decorators/LayoutDecorator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { DecoratorFunction } from '@storybook/addons';
import React from 'react';
import styled from 'styled-components';

const ColoredChildren = styled.div`
& > div > * {
--color: rgb(103, 126, 208);
background: var(--color);
min-height: 4em;
min-width: 4em;
}
& > div > *:nth-child(6n + 2) {
--color: rgb(217, 103, 219);
}
& > div > *:nth-child(6n + 3) {
--color: rgb(77, 214, 115);
}
& > div > *:nth-child(6n + 4) {
--color: rgb(248, 110, 91);
}
& > div > *:nth-child(6n + 5) {
--color: rgb(94, 204, 211);
}
& > div > *:nth-child(6n + 6) {
--color: rgb(0, 35, 208);
}
& > div > *:nth-child(6n + 7) {
--color: rgb(224, 174, 72);
}
`;

export const LayoutDecorator: DecoratorFunction = story => (
<ColoredChildren>{story()}</ColoredChildren>
);
1 change: 1 addition & 0 deletions packages/components/.storybook/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './ThemeDecorator';
export * from './LayoutDecorator';
135 changes: 135 additions & 0 deletions packages/components/src/components/Grid/grid.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import React from 'react';
import { LayoutDecorator } from '../../../.storybook/decorators';

import { Grid, Column, Row } from '.';

export default {
title: 'components/Grid',
component: Grid,
decorators: [LayoutDecorator],
};

// replace the text inside with Text variants when available
export const Span = () => (
<Grid>
<Column span={4}>span 4</Column>
<Column span={4}>span 4</Column>
<Column span={4}>span 4</Column>
</Grid>
);

export const ZeroGap = () => (
<Grid columnGap={0}>
<Column span={4}>span 4</Column>
<Column span={4}>span 4</Column>
<Column span={4}>span 4</Column>
</Grid>
);

export const StartAndEnd = () => (
<Grid>
<Column start={1} end={4}>
1 to 4
</Column>
<Column start={6} end={7}>
6-7
</Column>
<Column start={9} end={12}>
9 to 12
</Column>
</Grid>
);

export const Mixed = () => (
<Grid>
<Column>.</Column>
<Column span={3}>span 3</Column>
<Column>.</Column>
<Column start={7} end={8}>
7-8
</Column>
<Column start={11}>11</Column>
</Grid>
);

export const Overflow = () => (
<Grid>
<Column span={12}>span 12</Column>
<Column span={6}>span 6</Column>
<Column span={6}>span 6</Column>
</Grid>
);

export const ResponsiveSpan = () => (
<Grid>
<Column span={[12, 6]}>span [12, 6]</Column>
<Column span={[12, 6]}>span [12 , 6]</Column>
<Column span={12}>span 12</Column>
</Grid>
);

export const ResponsiveStart = () => (
<Grid>
<Column start={[1, 1, 2]} span={[12, 6, 4]}>
one
</Column>
<Column start={[1, 7, 8]} span={[12, 6, 4]}>
two
</Column>
</Grid>
);

export const Sidebar = () => (
<Grid>
<Column span={[0, 4]}>sidebar</Column>
<Column span={[12, 8]}>main</Column>
</Grid>
);

export const WithRow = () => (
<Grid>
<Row>header</Row>
<Row>
<Column span={[12, 2]}>sidebar</Column>
<Column span={[12, 10]}>main</Column>
</Row>
<Row>
<Column start={[0, 5]} span={[12, 4]}>
footer
</Column>
</Row>
</Grid>
);

export const NestedGrid = () => (
<Grid>
<Row>header</Row>
<Column span={[12, 12, 2]}>menu</Column>
<Column span={[12, 12, 10]}>
<Grid>
<Column span={[12, 6, 6]}>left</Column>
<Column span={[12, 6, 6]}>right</Column>
<Column span={12}>footer</Column>
</Grid>
</Column>
</Grid>
);

/* eslint-disable react/no-array-index-key */
export const ImageGallery = () => (
<Grid>
{new Array(12).fill(true).map((value, index) => (
<Column
span={[6, 4, 3]}
key={index}
style={{
height: 150,
width: '100%',
backgroundSize: 'cover',
backgroundImage: `url(https://i.picsum.photos/id/${index +
100}/200/200.jpg)`,
}}
/>
))}
</Grid>
);
48 changes: 48 additions & 0 deletions packages/components/src/components/Grid/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import styled from 'styled-components';
import css from '@styled-system/css';

const fontSize = 1; // rem = 16px
const lineHeight = fontSize * 1.5;

export const Grid = styled.div<{ columnGap?: number; rowGap?: number }>(
({ columnGap, rowGap }) =>
css({
display: 'grid',
gridTemplateColumns: 'repeat(12, 1fr)', // always 12 columns
gridColumnGap:
(typeof columnGap !== 'undefined' ? columnGap : lineHeight * 2) + 'rem',
gridRowGap: (typeof rowGap !== 'undefined' ? rowGap : lineHeight) + 'rem',
})
);

// todo: end and span cant be together
// valid combinations are
// start | start + end | start + span | span
// span + end is also possible but not implemented here
export const Column = styled.div<{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const Column = styled.div<{
type ColumnEnd = number | number[];
type ColumnSpan = number | number[];
type ColumnStart = number | Array<number | string>;
type ColumnProps =
| { end: ColumnEnd; start: ColumnStart; }
| { span: ColumnSpan; }
| { span: ColumnSpan; start: ColumnStart; }
| { start: ColumnStart; };
export const Column = styled.div<ColumnProps>(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this improve?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implementing the Props like you said in your comments 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. Implementing it this way would give errors on the missing prop in each, right?

repro (see end prop): https://codesandbox.io/s/funny-pare-zswfv

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • This is not a blocker, so I'm merging the PR but will continue to improve the types

start?: number;
end?: number;
span?: number;
}>(({ start, end, span }) => {
const styles: {
gridColumnStart?: number | Array<number | string>;
gridColumnEnd?: number | string | Array<number> | Array<string>;
} = {};

if (Array.isArray(start)) styles.gridColumnStart = start.map(s => s);
else if (start) styles.gridColumnStart = start;

if (Array.isArray(end)) styles.gridColumnEnd = end.map(s => s + 1);
else if (end) styles.gridColumnEnd = end + 1;

if (Array.isArray(span)) styles.gridColumnEnd = span.map(s => 'span ' + s);
else if (span) styles.gridColumnEnd = 'span ' + span;

return css(styles);
});

export const Row = styled(Grid).attrs({ span: 12 })(
css({
gridColumnEnd: 'span 12',
})
);
20 changes: 20 additions & 0 deletions packages/components/src/components/Stack/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import styled from 'styled-components';
import css from '@styled-system/css';

export const Stack = styled.div<{
gap?: number; // theme.space token
direction?: 'horizontal' | 'vertical';
justify?: string;
align?: string;
}>(({ gap = 0, direction = 'horizontal', justify, align }) =>
css({
display: 'flex',
flexDirection: direction === 'horizontal' ? 'row' : 'column',
justifyContent: justify,
alignItems: align,

'> *:not(:last-child)': {
[direction === 'horizontal' ? 'marginRight' : 'marginBottom']: gap,
},
})
);
40 changes: 40 additions & 0 deletions packages/components/src/components/Stack/stack.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import { LayoutDecorator } from '../../../.storybook/decorators';

import { Stack } from '.';

export default {
title: 'components/Stack',
component: Stack,
decorators: [LayoutDecorator],
};

// replace the text inside with Text variants when available
export const Defaults = () => (
<Stack style={{ height: 100, background: '#343434' }}>
<div />
<div />
</Stack>
);

export const WithGap = () => (
<Stack gap={4} style={{ height: 100, background: '#343434' }}>
<div />
<div>spacing token as gap</div>
<div />
</Stack>
);

export const Justify = () => (
<Stack justify="space-around" style={{ height: 100, background: '#343434' }}>
<div />
<div />
</Stack>
);

export const Align = () => (
<Stack align="center" style={{ height: 100, background: '#343434' }}>
<div />
<div />
</Stack>
);