@evg-b/evg-ui
Version:
EVG-UI library inspired by Material Design.
529 lines (496 loc) • 15.3 kB
JavaScript
import _extends from '@babel/runtime/helpers/extends';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import React, { useRef, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles.js';
import Color from '../styles/Color/Color.js';
var styles = {
base: {
position: 'relative',
display: 'flex',
flexDirection: 'column',
paddingBottom: 20,
'--evg-text-field-color': function evgTextFieldColor(props) {
return props.color === 'default' ? props.Color.Contrast() : props.Color.Base();
},
'&[disabled] > $textField, &[disabled] > $textField > $input': {
cursor: 'default',
pointerEvents: ' none',
color: 'rgba(0, 0, 0, 0.26)'
},
'&[data-error]': {
'--evg-text-field-color': Color('red700').Base(),
'& > $outlined, & > $filled': {
borderColor: 'var(--evg-text-field-color)'
},
'& > $helperLine,& > $textField > $notched > $notchedNotch > $label': {
color: 'var(--evg-text-field-color)'
}
}
},
textField: {
position: 'relative',
minHeight: '56px',
backgroundColor: '#f5f5f5',
display: 'inline-flex',
alignItems: 'center',
boxSizing: 'border-box',
color: 'rgba(0,0,0,.6)'
},
input: {
height: '56px',
fontFamily: 'Roboto, sans-serif',
fontSize: '1rem',
fontWeight: 400,
lineHeight: '1.2',
textDecoration: 'inherit',
textTransform: 'inherit',
alignSelf: 'flex-end',
boxSizing: 'border-box',
width: '100%',
border: 'none',
background: 'none',
appearance: 'none',
caretColor: 'var(--evg-text-field-color)',
'&::placeholder': {
transition: 'opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)'
},
'&[data-islabel]::placeholder': {
opacity: 0
},
'&:focus': {
border: '0px',
outline: 0,
'&::placeholder': {
opacity: 1,
color: 'grey'
},
'& ~ $line': {
// активируем красную нижнюю линию
opacity: 1,
transform: 'scaleX(1)'
}
},
'&:focus ~ $notched > $notchedNotch > $label': {
color: 'var(--evg-text-field-color)'
},
// textarea
'&[rows]': {
height: 'auto',
resize: 'vertical',
padding: '0 16px 16px',
margin: '20px 1px 1px 0',
lineHeight: '1.75rem'
}
},
label: {
display: 'inline-block',
position: 'relative',
maxWidth: '133%',
lineHeight: '1.15rem',
pointerEvents: 'none',
transformOrigin: 'left top',
top: '1.05rem',
transition: 'transform 150ms cubic-bezier(0.4, 0, 0.2, 1),color 150ms cubic-bezier(0.4, 0, 0.2, 1)',
willChange: 'transform',
color: 'currentColor',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
cursor: 'text',
overflow: 'hidden'
},
round: {
'&$filled': {
borderRadius: '16px 16px 0 0'
},
'&$outlined > $input': {
paddingLeft: '32px'
},
'&$outlined > $notched > $notchedLeading': {
borderRadius: '28px 0 0 28px',
width: '28px'
},
'&$outlined > $notched > $notchedTrailing': {
borderRadius: '0 28px 28px 0'
},
'&$outlined > $notched > $notchedNotch': {
maxWidth: 'calc(100% - 44px * 2)'
}
},
leadingIcon: {
color: 'currentColor',
left: '16px',
top: '18px',
position: 'absolute',
'$textField > & ~ $input': {
paddingLeft: '48px'
},
'& ~ $notched > $notchedLeading': {
minWidth: '44px'
}
},
trailingIcon: {
color: 'currentColor',
right: '16px',
top: '18px',
position: 'absolute',
'$textField > & ~ $input': {
paddingRight: '48px'
},
'& ~ $notched > $notchedTrailing': {
minWidth: '44px'
}
},
inputFilled: {
padding: '20px 16px 6px',
'& ~ $notched > $notchedNotch,& ~ $notched[data-isempty] > $notchedNotch': {
paddingLeft: '4px'
},
'&:focus ~ $notched > $notchedNotch > $label,& ~ $notched[data-isempty] > $notchedNotch > $label': {
transform: 'translateY(-0.6rem) scale(.75)'
},
'& ~ $notched': {
borderColor: 'transparent'
}
},
inputOutlined: {
padding: '12px 16px 14px',
'&[data-islabel] ~ $notched > $notchedNotch,& ~ $notched[data-isempty] > $notchedNotch': {
paddingLeft: '4px'
},
'&:focus ~ $notched > $notchedNotch > $label,& ~ $notched[data-isempty] > $notchedNotch > $label': {
transform: 'translateY(-1.5rem) scale(.75)',
fontSize: '1rem'
},
'&:focus ~ $notched > $notchedNotch,& ~ $notched[data-isempty] > $notchedNotch': {
borderTop: 'none'
},
'&:focus ~ $notched': {
borderColor: 'var(--evg-text-field-color)'
},
'&:focus ~ $notched > $notchedLeading,&:focus ~ $notched > $notchedNotch,&:focus ~ $notched > $notchedTrailing': {
borderWidth: '2px'
}
},
line: {
position: 'absolute',
pointerEvents: 'none',
bottom: 0,
left: 0,
height: '2px',
width: '100%',
transform: 'scaleX(0)',
opacity: 0,
backgroundColor: 'var(--evg-text-field-color)',
transformOrigin: 'center',
transition: 'transform 100ms cubic-bezier(0.4, 0, 0.2, 1),opacity 100ms cubic-bezier(0.4, 0, 0.2, 1)'
},
fullWidth: {
width: '100%'
},
filled: {
borderBottom: '1px solid',
overflow: 'hidden',
borderRadius: '4px 4px 0 0',
'&:focus-within': {
borderColor: 'var(--evg-text-field-color)'
},
'&:before': {
content: '""',
position: 'absolute',
opacity: 0,
pointerEvents: 'none',
top: '-50%',
left: '-50%',
width: '200%',
height: '200%',
backgroundColor: 'rgba(0,0,0,.87)'
},
'&:hover:before': {
opacity: '.04'
},
'&:focus-within:before': {
opacity: '.12'
}
},
outlined: {
background: 'none',
borderColor: 'rgba(0,0,0,.38)',
'&:hover': {
borderColor: 'rgba(0,0,0,.87)'
}
},
helperLine: {
position: 'absolute',
width: '100%',
bottom: 0,
color: 'rgba(0,0,0,.6)',
paddingRight: '16px',
paddingLeft: '16px',
display: 'flex',
justifyContent: 'space-between',
fontSize: '.75rem',
lineHeight: '1.25rem',
fontWeight: 400,
letterSpacing: '.0333333333em',
textDecoration: 'inherit',
textTransform: 'inherit'
},
notched: {
display: 'flex',
position: 'absolute',
right: 0,
left: 0,
boxSizing: 'border-box',
width: '100%',
height: '100%',
pointerEvents: 'none',
borderColor: 'inherit'
},
notchedLeading: {
display: 'flex',
borderRadius: '4px 0 0 4px',
boxSizing: 'border-box',
borderTop: '1px solid',
borderTopColor: 'inherit',
borderBottom: '1px solid',
borderBottomColor: 'inherit',
borderLeft: '1px solid',
borderLeftColor: 'inherit',
borderRight: 'none',
width: '12px'
},
notchedNotch: {
boxSizing: 'border-box',
borderTop: '1px solid',
borderTopColor: 'inherit',
borderBottom: '1px solid',
borderBottomColor: 'inherit',
pointerEvents: 'none'
},
notchedTrailing: {
borderRadius: '0 4px 4px 0',
boxSizing: 'border-box',
borderTop: '1px solid',
borderTopColor: 'inherit',
borderBottom: '1px solid',
borderBottomColor: 'inherit',
borderRight: '1px solid',
borderRightColor: 'inherit',
borderLeft: 'none',
pointerEvents: 'none',
flexGrow: 1
}
};
/**
* Текстовые поля позволяют пользователям вводить и редактировать текст.
*/
var TextField = /*#__PURE__*/React.forwardRef(function TextField(props, ref) {
var _classNames2, _classNames3;
var classes = props.classes,
className = props.className;
props.children;
var component = props.component,
id = props.id;
props.color;
var placeholder = props.placeholder,
value = props.value,
_props$labelText = props.labelText,
LabelText = _props$labelText === void 0 ? '' : _props$labelText,
_props$helperText = props.helperText,
HelperText = _props$helperText === void 0 ? '' : _props$helperText,
outlined = props.outlined,
fullWidth = props.fullWidth,
round = props.round,
multiline = props.multiline,
error = props.error,
rows = props.rows,
maxCount = props.maxCount,
LeadingIcon = props.leadingIcon,
TrailingIcon = props.trailingIcon,
onChange = props.onChange,
otherProps = _objectWithoutProperties(props, ["classes", "className", "children", "component", "id", "color", "placeholder", "value", "labelText", "helperText", "outlined", "fullWidth", "round", "multiline", "error", "rows", "maxCount", "leadingIcon", "trailingIcon", "onChange"]);
var Input_ref = useRef();
Input_ref = ref || Input_ref;
var Component = multiline ? 'textarea' : component;
var _useState = useState(value),
_useState2 = _slicedToArray(_useState, 2),
inputValue = _useState2[0],
setInputValue = _useState2[1];
var notchedNotchWidthRef = useRef(null);
var multilineSettings = multiline ? {
rows: rows
} : null;
var leadingIcon = LeadingIcon && /*#__PURE__*/React.createElement("span", {
className: classes.leadingIcon
}, LeadingIcon);
var trailingIcon = TrailingIcon && /*#__PURE__*/React.createElement("span", {
className: classes.trailingIcon
}, TrailingIcon);
var labelText = LabelText && /*#__PURE__*/React.createElement("label", {
htmlFor: id,
className: classes.label
}, LabelText);
var helperText = HelperText && /*#__PURE__*/React.createElement("div", {
className: classes.helperLine
}, /*#__PURE__*/React.createElement("span", null, HelperText), maxCount !== 0 ? /*#__PURE__*/React.createElement("span", null, inputValue.length, "/", maxCount) : null);
var ActivIndicator = /*#__PURE__*/React.createElement("div", {
className: classes.line
});
var notchedOutlined = /*#__PURE__*/React.createElement("div", {
className: classes.notched,
"data-isempty": inputValue ? true : null
}, /*#__PURE__*/React.createElement("div", {
className: classes.notchedLeading
}), /*#__PURE__*/React.createElement("div", {
ref: notchedNotchWidthRef,
className: classes.notchedNotch
}, labelText), /*#__PURE__*/React.createElement("div", {
className: classes.notchedTrailing
}));
var handlerChange = function handlerChange(e) {
if (maxCount !== 0 && e.target.value.length > maxCount) {
e.target.value = inputValue;
} else {
onChange && onChange(e);
setInputValue(e.target.value);
}
};
var handleFocus = function handleFocus() {
var notchedNotchWidthRef_S = notchedNotchWidthRef.current;
var labelWidthNotched = notchedNotchWidthRef_S.getBoundingClientRect().width * 0.75 - 4;
if (notchedNotchWidthRef_S.style.width === '' && LabelText !== '') {
notchedNotchWidthRef_S.style.width = "".concat(labelWidthNotched + 8, "px");
}
};
var handleBlur = function handleBlur(e) {
var notchedNotchWidthRef_S = notchedNotchWidthRef.current;
if (e.target.value === '' && LabelText !== '') {
notchedNotchWidthRef_S.style.cssText = '';
}
};
useEffect(function () {
Input_ref.current.value = value;
setInputValue(value);
}, [value]);
return /*#__PURE__*/React.createElement("div", {
className: classNames(classes.base, _defineProperty({}, classes.fullWidth, fullWidth), className),
"data-error": error ? true : null,
disabled: otherProps.disabled
}, /*#__PURE__*/React.createElement("div", {
className: classNames(classes.textField, (_classNames2 = {}, _defineProperty(_classNames2, classes.filled, !outlined), _defineProperty(_classNames2, classes.outlined, outlined), _defineProperty(_classNames2, classes.round, round), _classNames2))
}, leadingIcon, trailingIcon, /*#__PURE__*/React.createElement(Component, _extends({
id: id,
name: "name",
type: "input",
ref: Input_ref,
className: classNames(classes.input, (_classNames3 = {}, _defineProperty(_classNames3, classes.inputFilled, !outlined), _defineProperty(_classNames3, classes.inputOutlined, outlined), _classNames3)),
"data-islabel": LabelText ? true : null,
placeholder: placeholder,
onChange: handlerChange,
onFocus: outlined ? handleFocus : null,
onBlur: outlined ? handleBlur : null
}, multilineSettings, otherProps)), notchedOutlined, !outlined ? ActivIndicator : null), helperText);
});
TextField.propTypes = {
/**
* Объект содержит jss стили компонента.
*/
classes: PropTypes.object,
/**
* Чтобы указать CSS классы, используйте этот атрибут.
*/
className: PropTypes.string,
/**
* Это свойство не реализуется.
*/
children: PropTypes.any,
/**
* Корневой узел. Это HTML элемент или компонент.
*/
component: PropTypes.elementType,
/**
* Название цвета в разных форматах.
*/
color: PropTypes.string,
/**
* id.
*/
id: PropTypes.string,
/**
* Текст внутри поля формы, который исчезает при получении фокуса.
*/
placeholder: PropTypes.string,
/**
* Value - number или string.
*/
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/**
* label текст.
*/
labelText: PropTypes.string,
/**
* Вспомогательный текст под TextField.
*/
helperText: PropTypes.string,
/**
* Если true, примет outlined вид.
*/
outlined: PropTypes.bool,
/**
* Если true, TextField займет всю ширину родителя.
*/
fullWidth: PropTypes.bool,
/**
* Круглые края TextField.
*/
round: PropTypes.bool,
/**
* Если true, включиться многострочный режим.
*/
multiline: PropTypes.bool,
/**
* Режим отображения ошибки.
*/
error: PropTypes.bool,
/**
* Количество строк в режиме multiline.
*/
rows: PropTypes.number,
/**
* Лимит текста в value.
*/
maxCount: PropTypes.number,
/**
* Контейнер элементов в начале.
*/
leadingIcon: PropTypes.node,
/**
* Контейнер элементов в конце.
*/
trailingIcon: PropTypes.node,
/**
* Вызывается при изменении состояния.
*/
onChange: PropTypes.func
};
TextField.defaultProps = {
id: 'nameInputEVG',
color: 'default',
component: 'input',
value: '',
placeholder: '',
outlined: false,
fullWidth: false,
round: false,
multiline: false,
error: false,
rows: 1,
maxCount: 0
};
TextField.displayName = 'TextFieldEVG';
var TextField$1 = withStyles(styles)(TextField);
export default TextField$1;