UNPKG

@hhgtech/hhg-components

Version:
427 lines (408 loc) • 17.5 kB
'use strict'; var tslib_es6 = require('./tslib.es6-af09a0ba.js'); var React = require('react'); var core = require('@mantine/core'); var classNames = require('classnames'); var dayjs = require('dayjs'); var index$1 = require('./index-04864074.js'); var react = require('@emotion/react'); var styled = require('@emotion/styled'); var miscTheme = require('./miscTheme.js'); var index = require('./index-ec32050c.js'); var Locale = require('./Locale-eb0da538.js'); var index$2 = require('./index-d4ad3f79.js'); function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefault(React); var classNames__default = /*#__PURE__*/_interopDefault(classNames); var dayjs__default = /*#__PURE__*/_interopDefault(dayjs); var styled__default = /*#__PURE__*/_interopDefault(styled); const KEYCODE = { BACKSPACE: 8, SPACEBAR: 32, ZERO: 48, }; const PATTERN_NUMBER = /^([0-9]*)$/; const INPUT_DATE_PLACEHOLDER = { DD: 'Day', MM: 'Month', YYYY: 'Year', }; const INPUT_DATE_FORMAT_TYPING = { DD: (day, cb) => { if (!day) { cb === null || cb === void 0 ? void 0 : cb(''); return ''; } const dayNumber = parseInt(day); if (dayNumber > 31) { cb === null || cb === void 0 ? void 0 : cb(day[0]); return day[0]; } /** Day cannot be over number 31 */ if (dayNumber >= 4) { const dayString = String(dayNumber).padStart(2, '0'); cb === null || cb === void 0 ? void 0 : cb(dayString); return dayString; } cb === null || cb === void 0 ? void 0 : cb(day); return day; }, MM: (month, cb) => { if (!month) { cb === null || cb === void 0 ? void 0 : cb(''); return ''; } const monthNumber = parseInt(month); if (monthNumber > 12) { cb === null || cb === void 0 ? void 0 : cb(month[0]); return month[0]; } /** Month cannot be over number 12 */ if (monthNumber >= 2) { const monthString = String(monthNumber).padStart(2, '0'); cb === null || cb === void 0 ? void 0 : cb(monthString); return monthString; } cb === null || cb === void 0 ? void 0 : cb(month); return month; }, YYYY: (year, cb) => { if (!year) { cb === null || cb === void 0 ? void 0 : cb(''); return ''; } cb === null || cb === void 0 ? void 0 : cb(year); return year; }, }; const INPUT_DATE_DEFAULT_DISABLED = [false, true, true]; const getInputDateInputDisabled = (valueString) => { return valueString.map((_, index) => { if (index === 0) { return false; } if (index !== 0 && !!valueString[index - 1]) { return false; } return true; }); }; const cssInputNotShrink = react.css ` max-width: 100%; // color: ${miscTheme.theme.colors.gray800}; // font-size: var(--input-font-size, 16px); // font-weight: 400; // line-height: calc(var(--input-height, 56px) * 24 / 56); opacity: 0; transition: 0.3s linear opacity; vertical-align: middle; &::placeholder { color: transparent; font-weight: 400; } `; const cssInputShrink = react.css ` opacity: 1; line-height: calc(var(--input-height, 56px) * 24 / 56); transition: 0.3 linear opacity; `; const cssPlaceholderNotShrink = react.css ` position: absolute; top: calc(var(--input-height, 56px) / 2); left: var(--input-padding, 16px); letter-spacing: -0.3px; transform: translateY(-50%); transition: 0.125s linear all; vertical-align: middle; `; const cssPlaceholderShrink = react.css ` top: calc(var(--input-height, 56px) * 7 / 56); line-height: calc(var(--input-height, 56px) * 18 / 56); transform: translateY(0); transition: 0.125s linear all; `; const StyledInputDate = styled__default["default"].div ` --input-gap: 8px; --input-height: 56px; --input-max-width: 320px; --input-font-size: 15px; --input-line-height: 24px; --input-padding-x: 16px; --input-padding-y: 16px; --input-border-radius: 8px; --input-border-color: ${miscTheme.theme.colors.gray200}; display: flex; gap: var(--input-gap, 8px); max-width: var(--input-max-width, 320px); font-weight: 400; * { box-sizing: border-box; } .input_date-input_container { position: relative; display: flex; align-items: center; width: 100%; height: var(--input-height, 56px); max-width: calc((100% / 3) - (var(--input-gap, 8px) * 2 / 3)); line-height: var(--input-line-height, 24px); padding: var(--input-padding-y, 16px) var(--input-padding-x, 16px); border-radius: var(--input-border-radius, 8px); border: 1px solid var(--input-border-color, ${miscTheme.theme.colors.gray200}); .input_date-input_placeholder { ${cssPlaceholderNotShrink} } .input_date-input { ${cssInputNotShrink} } &:has([disabled]) { pointer-events: none; } &.input_date-input_shrink { --input-padding-y: 7px; align-items: flex-end; .input_date-input_placeholder { ${cssPlaceholderShrink} } .input_date-input { ${cssInputShrink} } } &.input_date-input_active { border-color: ${miscTheme.theme.colors.primary600}; box-shadow: 0px 0px 5px ${miscTheme.theme.colors.primary400}; transition: 0.25s linear all; } &.input_date-input_error { border-color: ${miscTheme.theme.colors.red600}; } } `; // eslint-disable-next-line @typescript-eslint/no-var-requires const customParseFormat = require('dayjs/plugin/customParseFormat'); dayjs__default["default"].extend(customParseFormat); const { BACKSPACE, SPACEBAR, ZERO } = KEYCODE; const formatInputDateValue = (value, format) => { if (typeof value === 'undefined') { return null; } if (typeof value === 'string') { const dayInJS = dayjs__default["default"](value, format, true); if (dayInJS.isValid()) { return dayInJS.toDate(); } return null; } const dayInJS = dayjs__default["default"](value); if (dayInJS.isValid()) { return dayInJS.toDate(); } return null; }; const formatInputDateValueString = (value, format) => { if (!value) { return [undefined, undefined, undefined]; } const dayInJS = dayjs__default["default"](value); return dayInJS.format(format).split('/'); }; const InputDate = React.forwardRef((props, ref) => { const { id, name, locale = Locale.LOCALE.Vietnam, className, style, defaultValue: defaultValueProps, value: valueProps, onChange: onChangeProps, error, disabled: disabledProps, labelTuples, placeholderTuples, onFocus, onBlur, autoComplete = 'off' } = props, restProps = tslib_es6.__rest(props, ["id", "name", "locale", "className", "style", "defaultValue", "value", "onChange", "error", "disabled", "labelTuples", "placeholderTuples", "onFocus", "onBlur", "autoComplete"]); const [activeInput, setActiveInput] = React.useState(-1); const inputRef = React.useRef([]); const [value, setValue] = React.useState(formatInputDateValue(defaultValueProps || valueProps, index.ISO_FORMAT[locale].dateFormat)); const [valueString, setValueString] = React.useState(['', '', '']); const [disabled, setDisabled] = React.useState(() => getInputDateInputDisabled(formatInputDateValueString(defaultValueProps || valueProps, index.ISO_FORMAT[locale].dateFormat))); const { dateFormat } = React.useMemo(() => { return (index.ISO_FORMAT === null || index.ISO_FORMAT === void 0 ? void 0 : index.ISO_FORMAT[locale]) || index.ISO_FORMAT['vi-VN']; }, [locale]); const orders = React.useMemo(() => dateFormat.split('/'), [dateFormat]); const defaultValue = React.useMemo(() => formatInputDateValueString(defaultValueProps, dateFormat), [defaultValueProps, dateFormat]); const label = React.useMemo(() => orders.map((keyOrd, idx) => (labelTuples === null || labelTuples === void 0 ? void 0 : labelTuples[idx]) || INPUT_DATE_PLACEHOLDER[keyOrd]), [labelTuples]); const placeholder = React.useMemo(() => orders.map((keyOrd, idx) => (placeholderTuples === null || placeholderTuples === void 0 ? void 0 : placeholderTuples[idx]) || keyOrd), [placeholderTuples]); const focusPrevInput = React.useCallback(() => { var _a, _b; if (activeInput === 0 || activeInput === -1) { return; } const curInput = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a[activeInput]; if (curInput) { curInput.blur(); } const prevInput = (_b = inputRef.current) === null || _b === void 0 ? void 0 : _b[activeInput - 1]; if (prevInput) { prevInput.focus(); } }, [activeInput]); const focusNextInput = React.useCallback(() => { var _a, _b; if (activeInput === orders.length - 1) { return; } const curInput = (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a[activeInput]; if (curInput) { curInput.blur(); } const nextInput = (_b = inputRef.current) === null || _b === void 0 ? void 0 : _b[activeInput + 1]; if (nextInput) { nextInput.focus(); } }, [activeInput, orders]); const changeCodeAtFocus = React.useCallback(() => { let count = 0; function changeFocus() { const target = inputRef.current[activeInput]; const nextTarget = inputRef.current[activeInput + 1]; const disabledNext = disabled[activeInput + 1]; if (!nextTarget || count === 1) { return; } if (disabledNext) { requestAnimationFrame(changeFocus); count++; } if (target.value.length === target.maxLength) { focusNextInput(); } } requestAnimationFrame(changeFocus); }, [...disabled, activeInput, focusNextInput]); const onChange = React.useCallback((valStr) => { const valString = valStr || valueString; const dayString = orders .map((_, index) => { const val = valString[index]; return val; }) .filter(Boolean) .join('/'); const dayInJS = dayjs__default["default"](dayString, dateFormat, true); if (dayInJS.isValid()) { setValue(dayInJS.toDate()); onChangeProps === null || onChangeProps === void 0 ? void 0 : onChangeProps(dayInJS.toDate(), dayString); } else { setValue(null); onChangeProps === null || onChangeProps === void 0 ? void 0 : onChangeProps(dayString, dayString); } }, [orders, dateFormat, ...valueString]); const inputOnChange = React.useCallback((index) => ((e) => { const val = e.target.value; const valString = [...valueString]; if (!val) { valString[index] = ''; setValueString(valString); onChange(valString); if (index === 0) { setDisabled(INPUT_DATE_DEFAULT_DISABLED); } return; } if (!val.trim().match(PATTERN_NUMBER)) { return; } const inputType = orders[index]; INPUT_DATE_FORMAT_TYPING[inputType](val, (newVal) => { valString[index] = newVal; setDisabled(getInputDateInputDisabled(valString)); setValueString(valString); changeCodeAtFocus(); }); onChange(valString); }), [...valueString, orders, changeCodeAtFocus, onChange]); const inputOnFocus = React.useCallback((e) => { const target = e.target; const inputIndex = inputRef.current.findIndex((input) => input === target); if (inputIndex !== -1) { setActiveInput(inputIndex); } /** Focus on the first input */ if (inputIndex === 0) { onFocus === null || onFocus === void 0 ? void 0 : onFocus(e); } }, [...valueString, orders, onFocus]); const inputOnBlur = React.useCallback((e) => { setActiveInput(-1); const target = e.target; const inputIndex = inputRef.current.findIndex((input) => input === target); if (inputIndex !== -1) { const newVal = target.value; const valString = [...valueString]; if (newVal !== '') { valString[inputIndex] = String(newVal).padStart(target.maxLength, '0'); setDisabled(getInputDateInputDisabled(valString)); setValueString(valString); onChange(valString); } } /** Blur on (the third input) or (the first input and the second input with valueString not null or current input empty) */ if (inputIndex === 2 || (inputIndex === 0 && (!(valueString === null || valueString === void 0 ? void 0 : valueString[0]) || valueString.every(Boolean))) || (inputIndex === 1 && (!(valueString === null || valueString === void 0 ? void 0 : valueString[1]) || valueString.every(Boolean)))) { requestAnimationFrame(() => { onBlur === null || onBlur === void 0 ? void 0 : onBlur(e); }); } }, [...valueString, activeInput, orders, value, onBlur]); // Handle cases of backspace, delete, left arrow, right arrow, space const inputOnKeyDown = React.useCallback((e) => { const target = inputRef.current[activeInput]; if (target.value === '0' && (e.keyCode === ZERO || e.key === '0')) { e.preventDefault(); } if (e.keyCode === BACKSPACE || e.key === 'Backspace') { if (!target.value) { focusPrevInput(); } } if (e.keyCode === SPACEBAR || e.key === ' ' || e.key === 'Spacebar' || e.key === 'Space') { e.preventDefault(); } }, [activeInput, focusPrevInput, focusNextInput]); const onClick = React.useCallback((e) => { const target = e.target; const targetIndex = inputRef.current.findIndex((input) => input === target); if (targetIndex === -1) { const focusIndex = valueString.join('') !== '' ? inputRef.current.length - 1 : 0; inputRef.current[focusIndex].focus(); setActiveInput(focusIndex); return; } inputRef.current[targetIndex].focus(); setActiveInput(targetIndex); }, [...valueString, inputRef.current, defaultValue]); React.useEffect(() => { setValue(formatInputDateValue(valueProps, dateFormat)); }, [valueProps, dateFormat]); React.useEffect(() => { if (value) { const valueStringUpdated = formatInputDateValueString(value, dateFormat); setValueString(valueStringUpdated); setDisabled(getInputDateInputDisabled(valueStringUpdated)); } }, [value, dateFormat]); React.useImperativeHandle(ref, () => inputRef.current[0], []); return (React__default["default"].createElement(StyledInputDate, Object.assign({ className: className, style: style, onClick: onClick }, restProps), orders.map((inputName, idxOrd) => { const inputLabel = label[idxOrd]; const inputDefaultValue = defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue[idxOrd]; const inputValue = valueString[idxOrd]; const inputDisabled = disabled[idxOrd]; const inputPlaceholder = placeholder[idxOrd]; const inputMaxLength = inputName.length; return (React__default["default"].createElement(core.Box, { key: inputName, className: classNames__default["default"]('input_date-input_container', { 'input_date-input_active': activeInput === idxOrd, 'input_date-input_shrink': !!inputValue, 'input_date-input_error': error, }), sx: (theme) => ({ input: Object.assign(Object.assign({}, index$1.GlobalTextStyleNew(theme)[index$1.CustomStylesType.LEADGEN].p2), { fontWeight: index$1.FontWeight.halfBold, color: theme.colors.gray[9] }), }) }, React__default["default"].createElement(index$2.Text, { className: 'input_date-input_placeholder', as: "span", size: !!inputValue ? 'p3' : 'p2', variant: "secondary", weight: "halfBold" }, inputLabel), React__default["default"].createElement("input", { ref: (ref) => (inputRef.current[idxOrd] = ref), name: `${id || ''}-${name || ''}-${inputName}`, type: "text", inputMode: "numeric", defaultValue: inputDefaultValue, value: inputValue, maxLength: inputMaxLength, disabled: disabledProps || inputDisabled, placeholder: inputPlaceholder, onChange: inputOnChange(idxOrd), onBlur: inputOnBlur, onFocus: inputOnFocus, onKeyDown: inputOnKeyDown, className: "input_date-input", autoComplete: autoComplete }))); }))); }); exports.InputDate = InputDate;