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

Commit

Permalink
feat(Switch): Style Updates (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathewmorris authored Sep 6, 2019
1 parent b9378ba commit 40eeffb
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 82 deletions.
2 changes: 1 addition & 1 deletion .storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const GlobalStyle = createGlobalStyle`
addParameters({
options: {
theme,
panelPosition: 'right'
panelPosition: 'bottom'
},
});

Expand Down
151 changes: 78 additions & 73 deletions src/Form/Switch.js
Original file line number Diff line number Diff line change
@@ -1,110 +1,115 @@
import React from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';
import { css } from 'styled-components';
import { createComponent } from '../utils';
import { createEasyInput } from './EasyInput';

const SwitchContain = styled.label`
position: relative;
display: inline-block;
width: ${p => p.size * 2}px;
height: ${p => p.size + p.inset}px;
`;

const SwitchInput = styled.input`
display: none;
`;

const SwitchThumb = styled.span`
${({
variant,
size,
inset,
on,
theme,
backgroundColor = theme.colors[variant] || theme.colors[theme.variants[variant]],
}) => css`
border-radius: 34px;
const SwitchThumb = createComponent({
name: 'SwitchThumb',
as: 'i',
style: ({ trackInset, thumbSize, value }) => css`
border-radius: ${thumbSize * 2}px;
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
transition: 0.3s;
background-color: ${on ? backgroundColor : theme.colors.greyDark};
left: 0;
height: ${thumbSize - trackInset * 2}px;
width: ${thumbSize - trackInset * 2}px;
background-color: white;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1), 0px 4px 4px rgba(0, 0, 0, 0.1);
transition: all 0.3s cubic-bezier(0.125, 0.85, 0.3, 1.125);
${value &&
css`
transform: translateX(${thumbSize}px);
`};
`,
});

const SwitchTrack = createComponent({
name: 'SwitchTrack',
as: 'label',
style: ({ theme, trackColor, thumbSize, trackInset, value }) => css`
position: relative;
display: inline-block;
cursor: pointer;
width: ${thumbSize * 2}px;
height: ${thumbSize}px;
background: ${value ? theme.colors[trackColor] : 'transparent'};
border: ${trackInset}px solid ${value ? theme.colors[trackColor] : theme.colors.grey};
border-radius: ${thumbSize * 2}px;
transition: background-color 0.2s, border-color 0.2s;
&:before {
border-radius: 100%;
position: absolute;
content: '';
height: ${size}px;
width: ${size}px;
left: ${inset / 2}px;
bottom: ${inset / 2}px;
background-color: white;
transition: 0.3s;
${on &&
css`
transform: translateX(${size - inset}px);
`};
&:active {
${SwitchThumb} {
transform: translateX(${value ? thumbSize - trackInset * 3 : 0}px);
width: ${thumbSize + trackInset}px;
}
}
`};
`;
`,
});

const SwitchInput = createComponent({
name: 'SwitchInput',
as: 'input',
style: css`
display: none;
`,
});

export class Switch extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
trackColor: PropTypes.string,
trackInset: PropTypes.number,
thumbSize: PropTypes.number,
value: PropTypes.bool,
size: PropTypes.number,
inset: PropTypes.number,
variant: PropTypes.string,
};

static defaultProps = {
value: false,
variant: 'primary',
size: 16,
inset: 8,
trackColor: 'primary',
trackInset: 2,
thumbSize: 24,
};

state = {
on: this.props.value || false,
value: !!this.props.value,
};

componentDidUpdate(prevProps) {
// update switch state based on props passed in
if ('value' in this.props) {
if (this.props.value !== this.state.on && this.props.value !== prevProps.value) {
this.update(this.props);
}
static getDerivedStateFromProps(props, state) {
if (props.value !== undefined && props.value !== state.value) {
return {
value: props.value,
};
}
}

update(newProps) {
this.setState({ on: newProps.value });
return null;
}

handleChange = () => {
const { onChange, name } = this.props;
const { on } = this.state;

this.setState({ on: !on }, () => {
// only pass an update if onChange is defined
if (typeof onChange === 'function') {
this.props.onChange(name, this.state.on);
}
});
if (typeof onChange === 'function') {
onChange(name, !this.state.value);
} else {
this.setState(state => ({ value: !state.value }));
}
};

render() {
const { name, size, variant, inset, ...props } = this.props;
const { on } = this.state;
const { name, thumbSize, trackInset, ...props } = this.props;
const { value } = this.state;
const sharedProps = {
value,
thumbSize,
trackInset,
};

return (
<SwitchContain {...props} size={size} inset={inset}>
<SwitchInput name={name} type="checkbox" on={on} onChange={this.handleChange} />
<SwitchThumb variant={variant} size={size} on={on} inset={inset} />
</SwitchContain>
<SwitchTrack {...props} {...sharedProps}>
<SwitchInput name={name} type="checkbox" onChange={this.handleChange} />
<SwitchThumb {...sharedProps} />
</SwitchTrack>
);
}
}
Expand Down
11 changes: 3 additions & 8 deletions src/Form/Switch.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,8 @@ export default {
component: Switch,
};

const defaultProps = {
id: 'switch',
name: 'switch',
};

export const Basic = () => <Switch {...defaultProps} />;
export const Basic = () => <Switch />;

export const Colors = () => <Switch {...defaultProps} variant="red" />;
export const Colors = () => <Switch trackColor="red" />;

export const Sizes = () => <Switch {...defaultProps} size={64} inset={8} />;
export const Sizes = () => <Switch thumbSize={32} trackInset={4} />;

0 comments on commit 40eeffb

Please sign in to comment.