Skip to content

Add grid system components #198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
9 changes: 8 additions & 1 deletion src/components/Box/Box.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { render } from '@testing-library/react';
import * as React from 'react';
import { Colors } from '../../essentials';
import { Box } from './Box';
import { Box, BoxProps } from './Box';

describe('Box', () => {
it('renders without any props', () => {
Expand Down Expand Up @@ -33,4 +33,11 @@ describe('Box', () => {
render(<Box gridColumnGap={2} gridTemplateRows="1fr auto 10%" />).container.firstChild
).toMatchSnapshot();
});

it('accepts props spreading', () => {
const renderBox = (props: BoxProps) => <Box {...props} />;
expect(
render(renderBox({ backgroundColor: Colors.POSITIVE_GREEN_900 })).container.firstChild
).toMatchSnapshot();
});
});
6 changes: 3 additions & 3 deletions src/components/Box/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styled, { StyledComponentBase } from 'styled-components';
import styled from 'styled-components';
import {
background,
BackgroundProps,
Expand All @@ -24,13 +24,13 @@ interface BoxProps
extends SpaceProps,
LayoutProps,
PositionProps,
ColorProps,
Omit<ColorProps, 'color'>, // HACK: avoid collision of `color` prop
FlexboxProps,
GridProps,
BackgroundProps,
TextAlignProps {}

const Box: StyledComponentBase<'div', never, BoxProps, 'theme'> = styled.div.attrs({ theme })<BoxProps>`
const Box = styled.div.attrs({ theme })<BoxProps>`
${compose(space, layout, position, color, flexbox, grid, background, textAlign)}
`;

Expand Down
10 changes: 10 additions & 0 deletions src/components/Box/__snapshots__/Box.spec.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Box accepts props spreading 1`] = `
.c0 {
background-color: #069D4F;
}

<div
class="c0"
/>
`;

exports[`Box renders color 1`] = `
.c0 {
background-color: #069D4F;
Expand Down
5 changes: 2 additions & 3 deletions src/components/FilePicker/FilePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ComponentPropsWithoutRef, FC, useRef, useState } from 'react';
import React, { ComponentPropsWithoutRef, FC, MouseEventHandler, useRef, useState } from 'react';
import styled, { css } from 'styled-components';
import { MarginProps } from 'styled-system';
import { Colors, MediaQueries } from '../../essentials';
Expand Down Expand Up @@ -61,7 +61,6 @@ interface OutlinerProps extends BoxProps {
disabled: boolean;
error: boolean;
hasValidFile: boolean;
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}

// NOTE: we want to affect the color of only one icon SVG and not the ICON_FILE_FEEDBACK_COLOR
Expand Down Expand Up @@ -146,7 +145,7 @@ const FilePicker: FC<FilePickerProps> = ({
onFileChange(eventFile, e);
setFile(eventFile);
};
const onClickHandler = (e: React.MouseEvent<HTMLButtonElement>) => {
const onClickHandler: MouseEventHandler = e => {
// Avoid label trigger file selection twice
e.preventDefault();
// Avoid button trigger file selection twice
Expand Down
25 changes: 25 additions & 0 deletions src/components/Grid/Grid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { FC } from 'react';
import { Box, BoxProps } from '../Box/Box';

type ColumnSpan = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
type ColumnOffset = 'auto' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;

type RowProps = BoxProps;

const Row: FC<RowProps> = (props: RowProps) => (
<Box display="grid" gridTemplateColumns="repeat(12, 1fr)" gridColumnGap={3} {...props} />
);

interface ColumnProps extends BoxProps {
span?: ColumnSpan;
offset?: ColumnOffset;
}

const Column: FC<ColumnProps> = ({ span = 1, offset = 'auto', ...restProps }: ColumnProps) => {
const gridColumnStart = offset === 'auto' ? 'auto' : offset + 1;
const gridColumnEnd = `span ${span}`;

return <Box gridColumn={`${gridColumnStart} / ${gridColumnEnd}`} {...restProps} />;
};

export { Row, RowProps, Column, ColumnProps };
189 changes: 189 additions & 0 deletions src/components/Grid/docs/Grid.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
---
name: Grid System
menu: Components
route: /components/grid-system
---

import { Playground } from 'docz';
import { Button } from '../../Button/Button.tsx';
import { Headline } from '../../Headline/Headline.tsx';
import { Input } from '../../Input/Input.tsx';
import { Row, Column } from '../Grid.tsx';
import { StyledSystemLinks } from '../../../docs/StyledSystemLinks'
import { Text } from '../../Text/Text.tsx';
import { ColumnPropsTable } from './GridPropsTable';

# Grid System

The grid system is a set of components that can be used to create different layouts, composed of 12 vertical tracks of equal width.

## Properties

### Row

<StyledSystemLinks component="Row" supportedProps={ ['space', 'layout', 'position', 'color', 'flexbox', 'grid-layout', 'background'] }/>

### Column

<ColumnPropsTable /><br/>

<StyledSystemLinks component="Column" supportedProps={ ['space', 'layout', 'position', 'color', 'flexbox', 'grid-layout', 'background'] }/>

## Examples

The grid system is composed of 12 vertical tracks of equal width. Content can be placed in these tracks by using the `Row` and `Column` component.

<Playground>
<Row>
<Column bg="#f1f2f4" textAlign="center" p={1}>
1
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
2
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
3
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
4
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
5
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
6
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
7
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
8
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
9
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
10
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
11
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1}>
12
</Column>
</Row>
</Playground>

`Column`s can occupy more than one vertical track, by changing the `span` prop to a number between 1 and 12.

<Playground>
<Row mb={3}>
<Column bg="#f1f2f4" textAlign="center" p={1} span={2}>
1
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={2}>
2
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={2}>
3
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={2}>
4
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={2}>
5
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={2}>
6
</Column>
</Row>
<Row mb={3}>
<Column bg="#f1f2f4" textAlign="center" p={1} span={3}>
7
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={3}>
8
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={3}>
9
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={3}>
10
</Column>
</Row>
<Row mb={3}>
<Column bg="#f1f2f4" textAlign="center" p={1} span={4}>
11
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={4}>
12
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={4}>
13
</Column>
</Row>
<Row mb={3}>
<Column bg="#f1f2f4" textAlign="center" p={1} span={6}>
14
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={6}>
15
</Column>
</Row>
<Row>
<Column bg="#f1f2f4" textAlign="center" p={1} span={12}>
16
</Column>
</Row>
</Playground>

`Column`s can be given an offset, by changing the `offset` prop to a number between 0 and 11.

<Playground>
<Row>
<Column bg="#f1f2f4" textAlign="center" p={1} span={4}>
1
</Column>
<Column bg="#f1f2f4" textAlign="center" p={1} span={4} offset={8}>
2
</Column>
</Row>
</Playground>

The `Row` and `Column` components can be used to create different kinds of layouts, combining them with other components of the design system.

<Playground>
<Row mb={3}>
<Column span={12}>
<Headline as="h2">Create a free Business Account</Headline>
<Text as="p">
Make managing employee and guest travel easier. It only takes a couple
of minutes to get started!
</Text>
</Column>
</Row>
<Row mb={3}>
<Column span={6}>
<Input label="First Name" width="100%" />
</Column>
<Column span={6}>
<Input label="Last Name" width="100%" />
</Column>
</Row>
<Row mb={3}>
<Column span={6}>
<Input label="Email" width="100%" />
</Column>
<Column span={2}>
<Input label="Area Code" width="100%" />
</Column>
<Column span={4}>
<Input label="Phone Number" width="100%" />
</Column>
</Row>
<Row>
<Column span={6} offset={6}>
<Button width="100%">Sign up for FREE NOW for Business</Button>
</Column>
</Row>
</Playground>
21 changes: 21 additions & 0 deletions src/components/Grid/docs/GridPropsTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FC } from 'react';
import * as React from 'react';
import { PropsTable } from '../../../docs/PropsTable';

export const ColumnPropsTable: FC = () => {
const props = [
{
name: 'offset',
type: '"auto" | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11',
description: 'vertical track that the column starts at',
defaultValue: 'auto'
},
{
name: 'span',
type: '1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12',
description: 'amount of vertical tracks that the column should span',
defaultValue: '1'
}
];
return <PropsTable props={props} />;
};
12 changes: 9 additions & 3 deletions src/components/Search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import styled from 'styled-components';
import { Colors, Elevation } from '../../essentials';
import { CloseIcon, MagnifyingGlassIcon } from '../../icons/index';
import { useControlledState } from '../../utils/hooks/useControlledState';
import { Box } from '../Box/Box';
import { Box, BoxProps } from '../Box/Box';

import { Input } from '../Input/Input';

Expand All @@ -14,7 +14,9 @@ const ActiveStyle = `
color: ${Colors.ACTION_BLUE_900};
`;

const SearchResultsContainer = styled(Box)`
interface SearchResultsContainerProps extends BoxProps, Pick<SearchProps, 'inverted'> {}

const SearchResultsContainer = styled(Box)<SearchResultsContainerProps>`
position: absolute;
z-index: ${Elevation.SUGGESTIONS_LIST};
margin-top: 0.0625rem;
Expand All @@ -32,7 +34,11 @@ const ActiveBox = styled(Box)`
}
`;

const SearchInputContainer = styled(Box)`
interface SearchInputContainerProps extends BoxProps {
isInFocus: boolean;
}

const SearchInputContainer = styled(Box)<SearchInputContainerProps>`
box-sizing: border-box;
background: white;
border-radius: 0.25rem;
Expand Down
3 changes: 2 additions & 1 deletion src/essentials/theme.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DefaultTheme } from 'styled-components';
import { Colors, SemanticColors } from './Colors/Colors';
import { Spaces } from './Spaces/Spaces';
import { Breakpoints, MediaQueries } from './Breakpoints/Breakpoints';

const theme = {
const theme: DefaultTheme = {
breakpoints: Breakpoints,
colors: Colors,
// todo: rename semanticColors to colors in the next major release
Expand Down
35 changes: 35 additions & 0 deletions src/styled.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'styled-components';
import { BreakpointsArray, MediaQueries } from './essentials/Breakpoints/Breakpoints';
import { Colors, SemanticColors } from './essentials/Colors/Colors';
import { Spaces } from './essentials';

declare module 'styled-components' {
export interface DefaultTheme {
colors: typeof Colors;
semanticColors: typeof SemanticColors;
breakpoints: BreakpointsArray;
fontSizes: string[];
fontWeights: {
normal: number;
semibold: number;
bold: number;
};
fonts: {
normal: string;
monospace: string;
};
mediaQueries: typeof MediaQueries;
space: typeof Spaces;
radii: string[];
iconSizes: {
small: number;
medium: number;
large: number;
};
shadows: {
small: string;
medium: string;
large: string;
};
}
}