UNPKG

@evg-b/evg-ui

Version:

EVG-UI library inspired by Material Design.

529 lines (496 loc) 15.3 kB
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;