@axeptio/design-system
Version:
Design System for Axeptio
400 lines (364 loc) • 9.88 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import Icon from '../../Icon';
const Header = styled.div`
max-width: ${props => (props?.specialWidth ? props.specialWidth : 400)}px;
min-width: 100px;
width: ${props => (props.specialWidth ? props.specialWidth + 'px' : '100%')};
display: flex;
flex-direction: row;
justify-content: space-between;
margin-bottom: 5px;
`;
const Left = styled.span`
color: ${props => props.theme.colors.secondary};
font-family: ${props => props.theme.fonts.text};
font-weight: 600;
font-size: 15px;
`;
const Right = styled.span`
color: ${props => props.theme.colors.secondary};
font-family: ${props => props.theme.fonts.text};
font-size: 14px;
font-weight: 400;
`;
const Label = styled.span`
position: absolute;
user-select: none;
top: -6px;
left: 0px;
display: flex;
border-color: ${props => props.theme.colors.grey.v200};
width: 100%;
max-height: 100%;
color: ${props => props.theme.colors.secondary};
cursor: ${props => (props.disabled ? 'not-allowed' : 'text')};
transition:
color 0.2s ease 0s,
font-size 0.2s ease 0s,
line-height 0.2s ease 0s,
left 0.2s ease 0s,
width 0.2s ease 0s;
font-family: ${props => props.theme.fonts.text};
font-size: 12px;
line-height: 16px;
font-weight: 400;
z-index: 1;
&:before {
margin-right: 4px;
border-left: 2px solid transparent;
border-radius: 6px 0px;
}
&:after {
-webkit-box-flex: 1;
flex-grow: 1;
margin-left: 4px;
border-right: 2px solid transparent;
border-radius: 0px 6px;
}
&:before,
:after {
content: '';
display: block;
box-sizing: border-box;
margin-top: 6px;
top: -6px;
border-top: 2px solid ${props => (props.error ? props.theme.colors.red : props.theme.colors.grey.v200)};
min-width: 10px;
height: 8px;
pointer-events: none;
box-shadow: transparent 0px 1px inset;
transition:
border-color 0.2s ease 0s,
box-shadow 0.2s ease 0s;
}
`;
const Container = styled.label`
font-family: ${props => props.theme.fonts.text};
max-width: ${props => (props.specialWidth ? props.specialWidth : 400)}px;
width: ${props => (props.specialWidth ? props.specialWidth + 'px' : '100%')};
font-style: normal;
font-size: 14px;
line-height: 20px;
font-weight: 400;
position: relative;
display: inline-block;
min-width: 100px;
min-height: 44px;
outline: none;
display: ${props => (props.unit ? 'flex' : 'block')};
& :first-child:not(:focus):placeholder-shown + ${Label} {
font-size: inherit;
line-height: 56px;
width: calc(100% - ${props => (props.prefix ? props.prefix.length * 6 + 20 : props.icon ? 41 : 0)}px);
left: ${props => (props.prefix ? props.prefix.length * 6 + 20 : props.icon ? 41 : 0)}px;
}
& :not(:focus):placeholder-shown + ${Label} {
border-top-color: ${props => props.theme.colors.grey.v200};
}
& :first-child:not(:focus):placeholder-shown + ${Label}:after {
border-top-color: transparent;
}
& :first-child:not(:focus):placeholder-shown + ${Label}:before {
border-top-color: transparent;
}
`;
const InputUnit = styled.span.attrs({
className: 'InputUnit'
})`
z-index: 10;
position: relative;
display: flex;
align-items: center;
padding: 8px;
font-size: 14px;
font-family: ${props => props.theme.fonts.text};
color: ${props => (props.error ? props.theme.colors.red : props.theme.colors.grey.v200)};
background: ${props => props.theme.colors.white};
border: 2px solid ${props => (props.error ? props.theme.colors.red : props.theme.colors.grey.v200)};
border-left: none;
transition:
border 0.2s ease 0s,
box-shadow 0.2s ease 0s;
border-radius: 0 6px 6px 0;
`;
const Logo = styled.div`
position: absolute;
display: flex;
-webkit-box-align: center;
align-items: center;
cursor: ${props => (props.disabled ? 'not-allowed' : 'text')};
${props =>
!props.right
? `
left: ${props.prefix ? '4px' : '16px'};
width: 20px;
height: 20px;
top: 14px;
`
: `
right: ${props.suffix ? '4px' : '16px'};
width: 24px;
height: 24px;
top: 12px;
`}
${props =>
props.onClick &&
`
cursor: pointer;
`}
`;
const Root = styled.div`
font-family: ${props => props.theme.fonts.text};
box-sizing: border-box;
margin: 0px;
border-width: 2px;
border-style: solid;
cursor: ${props => (props.disabled ? 'not-allowed' : 'text')};
border-image: initial;
border-color: ${props =>
props.headerExist ? (props.error ? props.theme.colors.red : props.theme.colors.grey.v200) : 'transparent'}
${props => (props.error ? props.theme.colors.red : props.theme.colors.grey.v200)}
${props => (props.error ? props.theme.colors.red : props.theme.colors.grey.v200)};
border-radius: ${props => (props.unit ? '6px 0px 0px 6px' : '6px')};
width: 100%;
height: inherit;
color: ${props => props.theme.colors.secondary};
background-color: ${props => props.theme.colors.white};
font-family: inherit;
font-size: inherit;
line-height: inherit;
caret-color: ${props => props.theme.colors.secondary};
transition:
border 0.2s ease 0s,
box-shadow 0.2s ease 0s;
overflow: visible;
padding-top: 12px;
padding-right: 12px;
padding-bottom: 12px;
padding-left: ${props => (props.prefix ? `${props.prefix.length * 6 + 15}px` : props.icon ? '51px' : '13px')};
${props =>
props.disabled &&
`
background-color: ${props.theme.colors.grey['grey-50']};
opacity: 0.3;
`}
&:not(:focus):placeholder-shown {
border-top-color: ${props => (props.error ? props.theme.colors.red : props.theme.colors.grey.v200)};
}
&:focus {
border-color: ${props => (props.headerExist ? props.theme.colors.secondary : 'transparent')}
${props => props.theme.colors.secondary} ${props => props.theme.colors.secondary};
outline: none;
}
&:focus ~ ${InputUnit} {
border: 2px solid ${props => props.theme.colors.secondary};
border-left: transparent;
color: ${props => props.theme.colors.secondary};
}
&:focus + ${Label} {
color: ${props => props.theme.colors.secondary};
top: -6px;
}
&:focus + ${Label}:before {
border-top-color: ${props => props.theme.colors.secondary};
}
&:focus + ${Label}:after {
border-top-color: ${props => props.theme.colors.secondary};
}
`;
const Footer = styled.div.attrs({
className: 'footer'
})`
margin-top: 5px;
font-family: ${props => props.theme.fonts.text};
font-style: normal;
font-size: 14px;
line-height: 20px;
font-weight: 400;
color: ${props => props.theme.colors.red};
`;
const Prefix = styled.span`
font-family: ${props => props.theme.fonts.text};
font-style: normal;
font-size: 14px;
line-height: 20px;
font-weight: 400;
color: ${props => props.theme.colors.grey.v500};
background: ${props => props.theme.colors.grey.v200};
border-radius: 3px;
padding: 10px;
`;
const Encapsuled = styled.div`
display: flex;
flex-direction: column;
`;
const Input = ({
autoFocus,
label,
icon,
type,
disabled,
width,
value,
prefix,
unit,
error,
multiline,
header,
optionalText,
...props
}) => {
const headerExist = header.length !== 0 || optionalText.length !== 0;
const [passwordShow, setPasswordShow] = React.useState(false);
return (
<Encapsuled>
<Header specialWidth={width}>
<Left>{header}</Left>
<Right>{optionalText}</Right>
</Header>
<Container unit={unit} specialWidth={width} prefix={prefix} icon={icon}>
<Root
value={value}
error={error}
prefix={prefix}
unit={unit}
icon={icon}
name={label}
autoFocus={autoFocus}
headerExist={headerExist}
disabled={disabled}
placeholder={headerExist ? label : ' '}
type={type === 'password' && passwordShow ? 'text' : type}
labe={label}
as={multiline ? 'textarea' : 'input'}
onChange={e => {
props.onChange(e.target.value);
}}
/>
{headerExist ? null : (
<Label error={error} disabled={disabled}>
{label}
</Label>
)}
<Logo prefix={prefix} disabled={disabled}>
{prefix ? <Prefix>{prefix}</Prefix> : <Icon iconSize={20} name={icon} />}
</Logo>
{unit ? <InputUnit error={error}>{unit}</InputUnit> : null}
{type === 'password' && (
<Logo suffix={unit} right={true} disabled={disabled} onClick={() => setPasswordShow(v => !v)}>
<Icon iconSize={24} name={passwordShow ? 'View' : 'ViewOff'} />
</Logo>
)}
</Container>
<div>{error ? <Footer>{error}</Footer> : null}</div>
</Encapsuled>
);
};
Input.propTypes = {
/**
* disabled
*/
autoFocus: PropTypes.bool,
/**
* disabled
*/
disabled: PropTypes.bool,
/**
* Multiline textearea
*/
multiline: PropTypes.bool,
/**
* full Width
*/
width: PropTypes.number,
/**
* Type
*/
type: PropTypes.oneOf(['text', 'email', 'password', 'number', 'number', 'url']),
/**
* icon on the left
*/
icon: PropTypes.string,
/**
* header on the left
*/
header: PropTypes.string,
/**
* optionalText on the left
*/
optionalText: PropTypes.string,
/**
* Input contents
*/
label: PropTypes.string.isRequired,
/**
* Change event
*/
onChange: PropTypes.func,
/**
* value
*/
value: PropTypes.any,
/**
* prefix
*/
prefix: PropTypes.string,
/**
* unit
*/
unit: PropTypes.string,
/**
* error
*/
error: PropTypes.string
};
Input.defaultProps = {
type: 'text',
disabled: false,
label: '',
header: '',
optionalText: ''
};
export default Input;