Skip to content

Commit

Permalink
feat: add ability to switch display unit
Browse files Browse the repository at this point in the history
  • Loading branch information
icelam committed Jun 20, 2020
1 parent 2e95fc4 commit da57994
Show file tree
Hide file tree
Showing 13 changed files with 3,219 additions and 2,071 deletions.
4,534 changes: 2,469 additions & 2,065 deletions design/px2em.ai

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/components/Buttons/__test__/Button.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('Button', () => {
expect(wrapper.find('button.action-button').text()).toEqual(disabledButtonText);
expect(wrapper.find('button.action-button')).toHaveStyleRule('opacity', '0.5', { modifier: ':disabled' });
expect(wrapper.find('button.action-button')).toHaveStyleRule('cursor', 'not-allowed', { modifier: ':disabled' });
expect(wrapper).toMatchSnapshot();
});

it('should trigger function when clicking on button', () => {
Expand Down
51 changes: 51 additions & 0 deletions src/components/Buttons/__test__/__snapshots__/Button.test.jsx.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Button should display disabled button with button text 1`] = `
.c0 {
display: inline-block;
border: none;
border-radius: 0;
box-shadow: none;
background-color: #828b8e;
color: #ffffff;
padding: 0.625rem 3.75rem;
margin: 0 0 1.875rem 0;
font-size: 1rem;
font-family: inherit;
-webkit-text-decoration: none;
text-decoration: none;
text-align: center;
white-space: nowrap;
cursor: pointer;
outline: none;
}
.c0:hover {
background-color: #98a2a5;
}
.c0:disabled {
opacity: 0.5;
cursor: not-allowed;
}
<Button
disabled={true}
onClick={[MockFunction]}
>
<styled.button
className="action-button"
disabled={true}
onClick={[MockFunction]}
type="button"
>
<button
className="c0 action-button"
disabled={true}
onClick={[MockFunction]}
type="button"
>
Disabled Button Text
</button>
</styled.button>
</Button>
`;

exports[`Button should render 1`] = `
.c0 {
display: inline-block;
Expand Down
96 changes: 96 additions & 0 deletions src/components/Switches/Switch.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { memo } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const SwitchWrapper = styled.div`
margin: 0.25rem 0;
`;

const SwitchLabel = styled.span`
font-size: 0.875rem;
color: ${({ theme: { color } }) => color.secondaryTextColor};
margin: 0 0.3125rem 0 0;
`;

const SwitchButton = styled.button`
display: inline-block;
border: 0.0625rem solid ${({ theme: { color } }) => color.switchButtonBorder};
border-radius: 0;
box-shadow: none;
background-color: ${({ selected, theme: { color } }) => (
selected
? color.switchButtonActiveBackgroundColor
: color.switchButtonBackgroundColor
)};
color: ${({ selected, theme: { color } }) => (
selected
? color.switchButtonActiveTextColor
: color.switchButtonTextColor
)};
padding: 0.3125rem 0.875rem;
margin: 0 0 0 -0.0625rem;
font-size: 0.875rem;
font-family: inherit;
text-decoration: none;
text-align: center;
white-space: nowrap;
cursor: pointer;
outline: none;
${({ buttonWidth }) => buttonWidth && `min-width: ${buttonWidth};`}
`;

const Switch = ({
label, value, onChange, options, buttonWidth
}) => {
const handleChange = (selectedValue) => {
onChange(selectedValue);
};

return (
<SwitchWrapper className="switch">
{label && <SwitchLabel className="switch__label">Unit:</SwitchLabel>}
{
options && Array.isArray(options) && options.map(({
label: optionLabel, value: optionValue
}) => (
<SwitchButton
className="switch__button"
key={optionValue}
selected={optionValue === value}
onClick={() => { handleChange(optionValue); }}
buttonWidth={buttonWidth}
>
{optionLabel}
</SwitchButton>
))
}
</SwitchWrapper>
);
};

Switch.propTypes = {
label: PropTypes.string,
value: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.bool
]),
onChange: PropTypes.func.isRequired,
options: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.bool
]).isRequired
})).isRequired,
buttonWidth: PropTypes.string
};

Switch.defaultProps = {
label: undefined,
value: '',
buttonWidth: undefined
};

export default memo(Switch);
93 changes: 93 additions & 0 deletions src/components/Switches/__test__/Switch.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import { themes } from '@styles';
import { mountWithProvider } from '../../../../jest.utils';
import Switch from '../Switch';

const options1 = [
{ label: 'em', value: 'em' },
{ label: 'rem', value: 'rem' }
];

const options2 = [
{ label: '1', value: 1 },
{ label: '2', value: 2 },
{ label: '3', value: 3 },
{ label: '4', value: 4 }
];

const onChange = jest.fn();

afterEach(() => {
onChange.mockClear();
});

describe('Switch', () => {
it('should render', () => {
const wrapper = mountWithProvider(<Switch onChange={onChange} value="em" options={options1} label="Unit: " />);
expect(wrapper.find('div.switch')).toHaveLength(1);
expect(wrapper.find('div.switch span.switch__label')).toHaveLength(1);
expect(wrapper.find('div.switch button.switch__button')).toHaveLength(2);
expect(wrapper).toMatchSnapshot();
});

it('should display switch with label and 2 options', () => {
const label = 'Unit: ';
const wrapper = mountWithProvider(
<Switch onChange={onChange} options={options1} label={label} />
);
expect(wrapper.find('div.switch span.switch__label')).toHaveLength(1);
expect(wrapper.find('div.switch span.switch__label').text()).toEqual(label.trim());
expect(wrapper.find('div.switch button.switch__button')).toHaveLength(2);
expect(wrapper.find('div.switch button.switch__button').at(0).text()).toEqual(options1[0].label);
expect(wrapper.find('div.switch button.switch__button').at(1).text()).toEqual(options1[1].label);
});

it('should display switch without label and 4 options', () => {
const wrapper = mountWithProvider(<Switch onChange={onChange} options={options2} />);
expect(wrapper.find('div.switch span.switch__label')).toHaveLength(0);
expect(wrapper.find('div.switch button.switch__button')).toHaveLength(4);
expect(wrapper.find('div.switch button.switch__button').at(0).text()).toEqual(options2[0].label);
expect(wrapper.find('div.switch button.switch__button').at(1).text()).toEqual(options2[1].label);
expect(wrapper.find('div.switch button.switch__button').at(2).text()).toEqual(options2[2].label);
expect(wrapper.find('div.switch button.switch__button').at(3).text()).toEqual(options2[3].label);
expect(wrapper).toMatchSnapshot();
});

it('should be able to highlight selected value', () => {
const wrapper = mountWithProvider(<Switch onChange={onChange} value="rem" options={options1} />);
const {
dark: {
color: {
switchButtonBackgroundColor,
switchButtonTextColor,
switchButtonActiveBackgroundColor,
switchButtonActiveTextColor
}
}
} = themes;
expect(wrapper.find('div.switch button.switch__button').at(0))
.toHaveStyleRule('background-color', switchButtonBackgroundColor);
expect(wrapper.find('div.switch button.switch__button').at(0))
.toHaveStyleRule('color', switchButtonTextColor);
expect(wrapper.find('div.switch button.switch__button').at(1))
.toHaveStyleRule('background-color', switchButtonActiveBackgroundColor);
expect(wrapper.find('div.switch button.switch__button').at(1))
.toHaveStyleRule('color', switchButtonActiveTextColor);
expect(wrapper).toMatchSnapshot();
});

it('should be able to define minimum button width', () => {
const wrapper = mountWithProvider(<Switch onChange={onChange} options={options1} buttonWidth="2.5rem" />);
expect(wrapper.find('div.switch button.switch__button').at(0)).toHaveStyleRule('min-width', '2.5rem');
expect(wrapper.find('div.switch button.switch__button').at(1)).toHaveStyleRule('min-width', '2.5rem');
expect(wrapper).toMatchSnapshot();
});

it('should trigger onChange when clicking on switch buttons', () => {
const wrapper = mountWithProvider(<Switch onChange={onChange} value="rem" options={options1} />);
wrapper.find('div.switch button.switch__button').at(0).simulate('click');
expect(onChange).toHaveBeenCalledTimes(1);
wrapper.find('div.switch button.switch__button').at(1).simulate('click');
expect(onChange).toHaveBeenCalledTimes(2);
});
});

0 comments on commit da57994

Please sign in to comment.