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 fns = require('../../shared/functions');
const React = require('react');
const Styled = require('styled-components'); const Styled = require('styled-components');
const { const Label = require('../form/label');
boxes, const LabelRow = require('../form/label-row');
colors const Msg = require('../form/msg');
} = constants; const Outlet = require('../form/outlet');
const View = require('../form/view');
const { const {
remcalc, rndId
} = fns; } = fns;
const { const {
baseBox default: styled
} = composers;
const {
default: styled,
css
} = Styled; } = Styled;
const successBakcground = css` const StyledInput = styled.input`
background-color: ${colors.brandSecondary}; ${Outlet}
background-image: url('./input-confirm.svg');
background-repeat: no-repeat;
background-position: 98% ${remcalc(20)};
`; `;
const defaultBackground = css` const Input = (props) => {
background-color: ${colors.brandSecondary}; const {
`; children,
id = rndId(),
label = '',
error = '',
warning = ''
} = props;
const Label = styled.label` const viewProps = [
color: ${props => props.error ? colors.alert : colors.fonts.regular} 'children',
`; 'style',
'className'
];
const InputField = styled.input` // reset props for <input />
${baseBox()}; 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'} const msgType = error ? 'error' : (warning ? 'warning' : null);
color: ${props => props.error ? colors.alert : colors.fonts.semibold}
display: block;
font-size: ${remcalc(16)};
padding: ${remcalc('15 18')};
visibility: visible;
width: 100%;
&:focus { const _msg = !(error || warning) ? null : (
border-color: ${boxes.border.checked}; <Msg type={msgType}>
outline: none; {error ? error : warning}
} </Msg>
`; );
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;
return ( return (
<div> <View className={props.className} style={props.style}>
<Label <LabelRow>
error={error}
htmlFor={id}
>
{_label} {_label}
</Label> {_msg}
{_error} </LabelRow>
<InputField <StyledInput {...newProps} />
aria-labelledby={labelledby} {children}
autoComplete={autoComplete} </View>
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>
); );
}; };
Input.propTypes = { Input.propTypes = {
autoComplete: React.PropTypes.string,
autoFocus: React.PropTypes.bool,
children: React.PropTypes.node, children: React.PropTypes.node,
className: React.PropTypes.string, className: React.PropTypes.string,
disabled: React.PropTypes.bool,
error: React.PropTypes.string, error: React.PropTypes.string,
form: React.PropTypes.string,
id: React.PropTypes.string, id: React.PropTypes.string,
inputMode: React.PropTypes.string,
label: 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, style: React.PropTypes.object,
success: React.PropTypes.bool, warning: React.PropTypes.string
tabIndex: React.PropTypes.string,
type: React.PropTypes.string,
value: React.PropTypes.string
}; };
module.exports = Input; module.exports = Input;

View File

@ -1,123 +1,91 @@
const fns = require('../../shared/functions'); const fns = require('../../shared/functions');
const composers = require('../../shared/composers');
const React = require('react'); const React = require('react');
const Styled = require('styled-components'); const Styled = require('styled-components');
const { const Label = require('../form/label');
rndId, const LabelRow = require('../form/label-row');
remcalc const Msg = require('../form/msg');
} = fns; const Outlet = require('../form/outlet');
const View = require('../form/view');
const { const {
pseudoEl rndId
} = composers; } = fns;
const { const {
default: styled default: styled
} = Styled; } = Styled;
// TODO: this should be a constant const defaultValue = rndId();
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 StyledSelect = styled.select` const StyledSelect = styled.select`
font-size: ${remcalc(16)}; ${Outlet}
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%;
}
}
`; `;
const Select = ({ const Select = (props) => {
autoFocus, const {
children, children,
className, disabled = false,
disabled, error = '',
form, id = rndId(),
id = rndId(), label = '',
label, multiple = false,
multiple, placeholder = '',
name, value = defaultValue,
required, warning = ''
selected } = props;
}) => {
return (
<div className={className}>
<StyledLabel htmlFor={id}>
{label}
</StyledLabel>
<SelectWrapper> const _label = !label.length ? null : (
<StyledSelect <Label htmlFor={id}>
autoFocus={autoFocus} {label}
disabled={disabled} </Label>
form={form} );
id={id}
label={label} const _placeholder = !placeholder ? null : (
multiple={multiple} <option disabled value={defaultValue}>
name={name} {placeholder}
required={required} </option>
selected={selected} );
>
{children} const msgType = error ? 'error' : (warning ? 'warning' : null);
</StyledSelect>
</SelectWrapper> const _msg = !(error || warning) ? null : (
</div> <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 = { Select.propTypes = {
autoFocus: React.PropTypes.bool,
children: React.PropTypes.node, children: React.PropTypes.node,
className: React.PropTypes.string,
disabled: React.PropTypes.bool, disabled: React.PropTypes.bool,
form: React.PropTypes.string, error: React.PropTypes.string,
id: React.PropTypes.string, id: React.PropTypes.string,
label: React.PropTypes.string, label: React.PropTypes.string,
multiple: React.PropTypes.bool, multiple: React.PropTypes.bool,
name: React.PropTypes.string, placeholder: React.PropTypes.string,
required: React.PropTypes.bool, value: React.PropTypes.string,
selected: React.PropTypes.bool warning: React.PropTypes.string
}; };
module.exports = Select; module.exports = Select;

View File

@ -5,22 +5,76 @@ const {
} = require('@kadira/storybook'); } = require('@kadira/storybook');
const Select = require('./'); const Select = require('./');
const Base = require('../base');
storiesOf('Select', module) storiesOf('Select', module)
.add('Default', () => ( .add('Default', () => (
<Select label='example select'> <Base>
<option>Apple</option> <Select label='Data Centers' placeholder='Select Location'>
<option>Banana</option> <option value="1">Amsterdam, EU</option>
<option>Pear</option> <option>San Francisco, USA</option>
<option>Orange</option> <option>Seoul, South Korea</option>
</Select> <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', () => ( .add('multiple', () => (
<Select label='example multiple select' multiple> <Base>
<option>1</option> <Select label='Data Centers' multiple>
<option>2</option> <option>Amsterdam, EU</option>
<option>3</option> <option>San Francisco, USA</option>
<option>4</option> <option>Seoul, South Korea</option>
<option>5</option> <option>Tokyo, Japan</option>
</Select> </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>
));