refactor Input and Select

This commit is contained in:
Sérgio Ramos 2017-01-16 19:44:08 +00:00
parent bd1ff8171a
commit 8ac2a7c60f
8 changed files with 328 additions and 238 deletions

View File

@ -0,0 +1,23 @@
const Column = require('../column');
const React = require('react');
const Row = require('../row');
const LabelRow = (props) => {
const labels = React.Children.map(props.children, (children) => (
<Column md={6} xs={12}>
{children}
</Column>
));
return (
<Row>
{labels}
</Row>
);
};
LabelRow.propTypes = {
children: React.PropTypes.node
};
module.exports = LabelRow;

View File

@ -0,0 +1,24 @@
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const {
colors
} = constants;
const {
remcalc
} = fns;
const {
default: styled
} = Styled;
module.exports = styled.label`
width: 100%;
font-size: ${remcalc(16)};
font-weight: 600;
font-style: normal;
font-stretch: normal;
color: ${colors.brandSecondaryColor};
`;

View File

@ -0,0 +1,29 @@
const constants = require('../../shared/constants');
const Label = require('./label');
const match = require('../../shared/match');
const Styled = require('styled-components');
const {
breakpoints,
colors
} = constants;
const {
default: styled
} = Styled;
const color = match.prop({
warning: colors.inputWarning,
error: colors.inputError,
//disabled: colors.brandInactiveColor
})('type');
module.exports = styled(Label)`
color: ${color};
${breakpoints.medium`
float: right;
text-align: right;
`}
`;

View File

@ -0,0 +1,67 @@
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const Styled = require('styled-components');
const {
colors,
boxes
} = constants;
const {
remcalc
} = fns;
const {
css
} = Styled;
const colorWithDisabled = (props) => props.disabled
? colors.brandInactiveColor
: colors.fonts.regular;
const colorWithDefaultValue = (props) => props.value === props.defaultValue
? colors.brandInactiveColor
: colorWithDisabled(props);
const color = (props) => props.defaultValue
? colorWithDefaultValue(props)
: colorWithDisabled(props);
const height = (props) => !props.multiple
? remcalc(48)
: 'auto';
const paddingTop = (props) => props.multiple
? remcalc(20)
: remcalc(13);
module.exports = css`
box-sizing: border-box;
width: 100%;
height: ${height};
margin-bottom: ${remcalc(8)};
margin-top: ${remcalc(8)};
padding: ${paddingTop} ${remcalc(18)};
border-radius: ${boxes.borderRadius};
background-color: ${colors.brandPrimaryColor};
box-shadow: ${boxes.insetShaddow};
border: ${boxes.border.unchecked};
font-size: ${remcalc(16)};
line-height: normal !important;
font-weight: normal;
font-style: normal;
font-stretch: normal;
color: ${color};
appearance: none;
outline: 0;
&:focus {
border-color: ${colors.brandPrimary};
outline: 0;
}
`;

View File

@ -0,0 +1,7 @@
const Styled = require('styled-components');
const {
default: styled
} = Styled;
module.exports = styled.div``;

View File

@ -1,162 +1,80 @@
const React = require('react');
const composers = require('../../shared/composers');
const constants = require('../../shared/constants');
const fns = require('../../shared/functions');
const React = require('react');
const Styled = require('styled-components');
const {
boxes,
colors
} = constants;
const Label = require('../form/label');
const LabelRow = require('../form/label-row');
const Msg = require('../form/msg');
const Outlet = require('../form/outlet');
const View = require('../form/view');
const {
remcalc,
rndId
} = fns;
const {
baseBox
} = composers;
const {
default: styled,
css
default: styled
} = Styled;
const successBakcground = css`
background-color: ${colors.brandSecondary};
background-image: url('./input-confirm.svg');
background-repeat: no-repeat;
background-position: 98% ${remcalc(20)};
const StyledInput = styled.input`
${Outlet}
`;
const defaultBackground = css`
background-color: ${colors.brandSecondary};
`;
const Input = (props) => {
const {
children,
id = rndId(),
label = '',
error = '',
warning = ''
} = props;
const Label = styled.label`
color: ${props => props.error ? colors.alert : colors.fonts.regular}
`;
const viewProps = [
'children',
'style',
'className'
];
const InputField = styled.input`
${baseBox()};
// reset props for <input />
const newProps = Object.keys(props).reduce((sum, key) => ({
...sum,
[key]: viewProps.indexOf(key) < 0 ? props[key] : null
}),{});
${props => props.success ? successBakcground : defaultBackground }
const _label = !label.length ? null : (
<Label htmlFor={id}>
{label}
</Label>
);
border-color: ${props => props.error ? colors.alert : 'auto'}
color: ${props => props.error ? colors.alert : colors.fonts.semibold}
display: block;
font-size: ${remcalc(16)};
padding: ${remcalc('15 18')};
visibility: visible;
width: 100%;
const msgType = error ? 'error' : (warning ? 'warning' : null);
&:focus {
border-color: ${boxes.border.checked};
outline: none;
}
`;
const Error = styled.span`
float: right;
color: ${colors.alert};
font-size: ${remcalc(14)};
`;
const Input = ({
autoComplete,
autoFocus,
children,
className,
disabled = false,
error,
form,
id,
inputMode,
label,
labelledby,
list,
name,
onChange,
pattern,
placeholder,
readOnly,
required,
selectionDirection,
spellCheck,
style,
success,
tabIndex,
type,
value
}) => {
const _label = label || children;
const _children = label && children ? children : null;
const _error = error ? (<Error>{error}</Error>) : null;
const _msg = !(error || warning) ? null : (
<Msg type={msgType}>
{error ? error : warning}
</Msg>
);
return (
<div>
<Label
error={error}
htmlFor={id}
>
<View className={props.className} style={props.style}>
<LabelRow>
{_label}
</Label>
{_error}
<InputField
aria-labelledby={labelledby}
autoComplete={autoComplete}
autoFocus={autoFocus}
disabled={disabled}
error={error}
form={form}
id={id}
inputMode={inputMode}
list={list}
name={name}
onChange={onChange}
pattern={pattern}
placeholder={placeholder}
readOnly={readOnly}
required={required}
selectionDirection={selectionDirection}
spellCheck={spellCheck}
success={success}
tabIndex={tabIndex}
type={type}
value={value}
/>
{_children}
</div>
{_msg}
</LabelRow>
<StyledInput {...newProps} />
{children}
</View>
);
};
Input.propTypes = {
autoComplete: React.PropTypes.string,
autoFocus: React.PropTypes.bool,
children: React.PropTypes.node,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
error: React.PropTypes.string,
form: React.PropTypes.string,
id: React.PropTypes.string,
inputMode: React.PropTypes.string,
label: React.PropTypes.string,
labelledby: React.PropTypes.string,
list: React.PropTypes.string,
name: React.PropTypes.string,
onChange: React.PropTypes.func,
pattern: React.PropTypes.string,
placeholder: React.PropTypes.string,
readOnly: React.PropTypes.bool,
required: React.PropTypes.bool,
selectionDirection: React.PropTypes.string,
spellCheck: React.PropTypes.bool,
style: React.PropTypes.object,
success: React.PropTypes.bool,
tabIndex: React.PropTypes.string,
type: React.PropTypes.string,
value: React.PropTypes.string
warning: React.PropTypes.string
};
module.exports = Input;

View File

@ -1,123 +1,91 @@
const fns = require('../../shared/functions');
const composers = require('../../shared/composers');
const React = require('react');
const Styled = require('styled-components');
const {
rndId,
remcalc
} = fns;
const Label = require('../form/label');
const LabelRow = require('../form/label-row');
const Msg = require('../form/msg');
const Outlet = require('../form/outlet');
const View = require('../form/view');
const {
pseudoEl
} = composers;
rndId
} = fns;
const {
default: styled
} = Styled;
// TODO: this should be a constant
const StyledLabel = styled.div`
color: #464646;
`;
const SelectWrapper = styled.div`
position: relative;
display: inline-block;
&:after {
border-left: ${remcalc(5)} solid transparent;
border-right: ${remcalc(5)} solid transparent;
border-bottom: ${remcalc(5)} solid black;
${pseudoEl({
top: remcalc(25),
right: remcalc(20)
})}
}
`;
const defaultValue = rndId();
const StyledSelect = styled.select`
font-size: ${remcalc(16)};
min-width: ${remcalc(288)};
min-height: ${remcalc(54)};
border-radius: ${remcalc(4)};
padding-left: ${remcalc(20)};
background-color: #FFFFFF;
box-shadow: inset 0 ${remcalc(3)} 0 0 rgba(0, 0, 0, 0.05);
border: solid ${remcalc(1)} #D8D8D8;
-webkit-appearance: none;
&:before {
${pseudoEl()}
}
/* select[multiple] is valid CSS syntax - not added to lint library yet */
/* stylelint-disable */
&[multiple] {
/* stylelint-enable */
padding-left: 0;
padding-right: 0;
& option {
padding-left: ${remcalc(15)};
padding-right: ${remcalc(15)};
width: 100%;
}
}
${Outlet}
`;
const Select = ({
autoFocus,
children,
className,
disabled,
form,
id = rndId(),
label,
multiple,
name,
required,
selected
}) => {
return (
<div className={className}>
<StyledLabel htmlFor={id}>
{label}
</StyledLabel>
const Select = (props) => {
const {
children,
disabled = false,
error = '',
id = rndId(),
label = '',
multiple = false,
placeholder = '',
value = defaultValue,
warning = ''
} = props;
<SelectWrapper>
<StyledSelect
autoFocus={autoFocus}
disabled={disabled}
form={form}
id={id}
label={label}
multiple={multiple}
name={name}
required={required}
selected={selected}
>
{children}
</StyledSelect>
</SelectWrapper>
</div>
const _label = !label.length ? null : (
<Label htmlFor={id}>
{label}
</Label>
);
const _placeholder = !placeholder ? null : (
<option disabled value={defaultValue}>
{placeholder}
</option>
);
const msgType = error ? 'error' : (warning ? 'warning' : null);
const _msg = !(error || warning) ? null : (
<Msg type={msgType}>
{error ? error : warning}
</Msg>
);
return (
<View {...props} id=''>
<LabelRow>
{_label}
{_msg}
</LabelRow>
<StyledSelect
defaultValue={defaultValue}
disabled={disabled}
id={id}
multiple={multiple}
placeholder={placeholder}
value={_placeholder ? value : undefined}
>
{_placeholder}
{children}
</StyledSelect>
</View>
);
};
Select.propTypes = {
autoFocus: React.PropTypes.bool,
children: React.PropTypes.node,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
form: React.PropTypes.string,
error: React.PropTypes.string,
id: React.PropTypes.string,
label: React.PropTypes.string,
multiple: React.PropTypes.bool,
name: React.PropTypes.string,
required: React.PropTypes.bool,
selected: React.PropTypes.bool
placeholder: React.PropTypes.string,
value: React.PropTypes.string,
warning: React.PropTypes.string
};
module.exports = Select;

View File

@ -5,22 +5,76 @@ const {
} = require('@kadira/storybook');
const Select = require('./');
const Base = require('../base');
storiesOf('Select', module)
.add('Default', () => (
<Select label='example select'>
<option>Apple</option>
<option>Banana</option>
<option>Pear</option>
<option>Orange</option>
</Select>
<Base>
<Select label='Data Centers' placeholder='Select Location'>
<option value="1">Amsterdam, EU</option>
<option>San Francisco, USA</option>
<option>Seoul, South Korea</option>
<option>Tokyo, Japan</option>
</Select>
</Base>
))
.add('disabled', () => (
<Base>
<Select
disabled
label='Data Centers'
placeholder='Select Location'
value='2'
>
<option value="1">Amsterdam, EU</option>
<option>San Francisco, USA</option>
<option>Seoul, South Korea</option>
<option>Tokyo, Japan</option>
</Select>
</Base>
))
.add('selected', () => (
<Base>
<Select
label='Data Centers'
placeholder='Select Location'
value='2'
>
<option value="1">Amsterdam, EU</option>
<option>San Francisco, USA</option>
<option>Seoul, South Korea</option>
<option>Tokyo, Japan</option>
</Select>
</Base>
))
.add('multiple', () => (
<Select label='example multiple select' multiple>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Select>
));
<Base>
<Select label='Data Centers' multiple>
<option>Amsterdam, EU</option>
<option>San Francisco, USA</option>
<option>Seoul, South Korea</option>
<option>Tokyo, Japan</option>
</Select>
</Base>
))
.add('warning', () => (
<Base>
<Select label='Data Centers' warning='Be warned!'>
<option>Amsterdam, EU</option>
<option>San Francisco, USA</option>
<option>Seoul, South Korea</option>
<option>Tokyo, Japan</option>
</Select>
</Base>
))
.add('error', () => (
<Base>
<Select error='How dare you?!' label='Data Centers'>
<option>Amsterdam, EU</option>
<option>San Francisco, USA</option>
<option>Seoul, South Korea</option>
<option>Tokyo, Japan</option>
</Select>
</Base>
));