Skip to content
This repository has been archived by the owner on Oct 6, 2020. It is now read-only.

Commit

Permalink
feat: Grid components (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
jadenlemmon authored and kylealwyn committed Aug 2, 2018
1 parent 30a6371 commit e31bde6
Show file tree
Hide file tree
Showing 13 changed files with 461 additions and 56 deletions.
13 changes: 12 additions & 1 deletion docs/theme.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ Refractal comes with a default theme. You can override any of these configuratio
lg: 14,
xl: 16,
},
breakpoints: [386, 768, 1024],
breakpoints: [386, 768, 1024, 1440],
grid: {
containerMaxWidth: 1000,
gutter: 15,
columns: 12,
sizes: {
xs: 386,
sm: 768,
md: 1024,
lg: 1440,
},
},
};
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"license": "MIT",
"scripts": {
"clean": "rimraf lib",
"watch": "yarn rollup --watch",
"build": "npm-run-all clean rollup",
"docs": "yarn docz dev",
"docs:build": "rimraf dist && yarn docz build",
Expand Down
31 changes: 1 addition & 30 deletions src/Form/Radio.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,35 +63,6 @@ Form Radio component. Different sizes are available.
}}
</Playground>

### Radio Group sizes
<Playground>
{() => {
const radioValues = [
{
id: 1,
value: 'radio1',
name: 'radio1',
label: 'Radio 1',
},
{
id: 2,
value: 'radio2',
name: 'radio2',
label: 'Radio 2',
},
];
return (
<React.Fragment>
<RadioGroup size="xs" name="radio" id="radio" choices={radioValues} />
<RadioGroup size="sm" name="radio" id="radio" choices={radioValues} />
<RadioGroup size="md" name="radio" id="radio" choices={radioValues} />
<RadioGroup size="lg" name="radio" id="radio" choices={radioValues} />
<RadioGroup size="xl" name="radio" id="radio" choices={radioValues} />
</React.Fragment>
)
}}
</Playground>

### Radio Group colors
<Playground>
{() => {
Expand All @@ -110,7 +81,7 @@ Form Radio component. Different sizes are available.
},
];
return (
<RadioGroup variant="info" name="radio" id="radio" choices={radioValues} />
<RadioGroup color="green" name="radio" id="radio" choices={radioValues} />
)
}}
</Playground>
46 changes: 25 additions & 21 deletions src/Form/RadioGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,45 @@ export default class RadioGroup extends Component {
name: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
color: PropTypes.string,
size: PropTypes.string,
choices: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.string,
disabled: PropTypes.bool,
})
),
variant: PropTypes.string,
size: PropTypes.string,
};

static defaultProps = {
choices: [],
onChange() {},
variant: 'primary',
color: 'primary',
size: 'md',
};

state = {
selected: this.props.value || null,
value: this.props.value || null,
};

handleChange = field => {
// Bail out if value is the same
if (this.state.selected === field) {
return;
componentDidUpdate() {
if (this.props.value !== undefined && this.props.value !== this.state.value) {
this.handleChange(null, this.props.value);
}
}

this.setState({
selected: field,
});
handleChange = (field, value) => {
// Bail out if value is the same
if (this.state.value === value) return;

this.setState({ value });

this.props.onChange(this.props.name, field);
this.props.onChange(this.props.name, value);
};

render() {
const { choices, error, horizontal, label, variant, size } = this.props;
const { choices, error, horizontal, label, name, color, size } = this.props;

return (
<StyledRadioGroup>
Expand All @@ -62,21 +64,23 @@ export default class RadioGroup extends Component {
<Flex flexDirection={horizontal ? 'row' : 'column'}>
{choices.length &&
choices.map(choice => {
const { value = choice.id } = choice;
const { value = choice.id, label: choiceLabel } = choice;
const key = `RadioButton-${name}-${value}`;

return (
<Checkbox
id={key}
key={key}
name={key}
horizontal={horizontal}
size={size}
variant={variant}
id={`RadioButton${value}`}
key={`RadioButton${value}`}
name={choice.name}
label={choice.label}
value={this.state.selected === choice.name}
onChange={this.handleChange}
color={color}
label={choiceLabel}
value={this.state.value}
valueTrue={value}
iconOn="radiobox-marked"
iconOff="radiobox-blank"
onChange={this.handleChange}
/>
);
})}
Expand Down
97 changes: 97 additions & 0 deletions src/Grid/Column.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import { head } from 'lodash';
import PropTypes from 'prop-types';
import { css } from 'styled-components';
import Flex from '../Flex';
import { createComponent } from '../utils';

const getWidthPercent = (width, columns) => `${(width / columns) * 100}%`;

const getColumnWidth = (width, columns) =>
width / columns !== 1
? css`
display: block;
flex-basis: ${getWidthPercent(width, columns)};
max-width: ${getWidthPercent(width, columns)};
`
: css`
max-width: 100%;
width: 100%;
flex: auto;
`;

const getPadding = p => {
if (p.collapse) return 0;
return p.gutter ? p.gutter / 2 : p.theme.grid.gutter / 2;
};

const getOffset = (offset, columns) => css`
margin-left: ${offset === 0 ? 0 : getWidthPercent(offset, columns)};
`;

const StyledColumn = createComponent({
name: 'Column',
as: Flex,
}).extend`
box-sizing: border-box;
flex: 1 0 auto;
padding-left: ${getPadding}px;
padding-right: ${getPadding}px;
${p => {
const sizes = Object.keys(p.theme.grid.sizes);
const mediaQueries = sizes.filter(size => !!p[size]).map(
size =>
// if smallest breakpoint no query needed
size === head(sizes)
? css`
${getColumnWidth(p[size], p.theme.grid.columns)};
${p[`${size}Offset`] && getOffset(p[`${size}Offset`], p.theme.grid.columns)};
`
: // all other breakpoints use a media query
css`
@media (min-width: ${p.theme.grid.sizes[size]}px) {
${getColumnWidth(p[size], p.theme.grid.columns)};
${p[`${size}Offset`] !== undefined && getOffset(p[`${size}Offset`], p.theme.grid.columns)};
}
`
);
return css`
order: ${p.order ? p.order : 'initial'};
${mediaQueries};
`;
}}
`;

const Column = props => <StyledColumn {...props} />;

Column.propTypes = {
/**
* Lay row out vertically
*/
vertical: PropTypes.number,

/**
* Margin between columns
*/
gutter: PropTypes.number,

/**
* Reverse the order of the columns
*/
reverse: PropTypes.bool,

/**
* Collapse columns by removing gutters
*/
collapse: PropTypes.bool,
};

Column.defaultProps = {
vertical: false,
reverse: false,
collapse: false,
};

export default Column;
96 changes: 96 additions & 0 deletions src/Grid/Column.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
menu: Grid
name: Column
---

import { Playground, PropsTable } from 'docz';

import Container from './Container';
import Row from './Row';
import Column from './Column';
import ExampleBox from './ExampleBox'

# Column

## Properties

<PropsTable of={Column} />

#### Equal Widths
<Playground>
<Container>
<Row>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
</Row>
</Container>
</Playground>

### One column set width
<Playground>
<Container>
<Row>
<Column xs={8}>
<ExampleBox>Column</ExampleBox>
</Column>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
</Row>
</Container>
</Playground>

### Different widths for different breakpoints
<Playground>
<Container>
<Row>
<Column xs={8} sm={12} md={6} lg={12}>
<ExampleBox>Column</ExampleBox>
</Column>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
<Column>
<ExampleBox>Column</ExampleBox>
</Column>
</Row>
</Container>
</Playground>

### Column ordering
<Playground>
<Container>
<Row>
<Column order={12}>
<ExampleBox>1</ExampleBox>
</Column>
<Column>
<ExampleBox>2</ExampleBox>
</Column>
<Column>
<ExampleBox>3</ExampleBox>
</Column>
</Row>
</Container>
</Playground>

### Column offsets
<Playground>
<Container>
<Row>
<Column xs={4} xsOffset={2}>
<ExampleBox>1</ExampleBox>
</Column>
</Row>
</Container>
</Playground>
31 changes: 31 additions & 0 deletions src/Grid/Container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import PropTypes from 'prop-types';
import Box from '../Box';
import { createComponent } from '../utils';

const getPadding = p => (p.gutter ? p.gutter / 2 : p.theme.grid.gutter / 2);

const StyledContainer = createComponent({
name: 'Container',
as: Box,
}).extend`
margin-left: auto;
margin-right: auto;
max-width: ${p => (p.fluid ? '100%' : `${p.maxWidth || p.theme.grid.containerMaxWidth}px`)};
padding-left: ${getPadding}px;
padding-right: ${getPadding}px;
`;

StyledContainer.displayName = 'Container';

const Container = ({ children, gutter, maxWidth, fluid }) => (
<StyledContainer fluid={fluid} gutter={gutter} maxWidth={maxWidth}>
{React.Children.map(children, child => React.cloneElement(child, { gutter }))}
</StyledContainer>
);

Container.propTypes = {
gutter: PropTypes.number,
};

export default Container;
Loading

0 comments on commit e31bde6

Please sign in to comment.