UNPKG

@ozen-ui/kit

Version:

React component library

146 lines (145 loc) 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InputNumber = exports.cnInputNumber = void 0; var tslib_1 = require("tslib"); require("./InputNumber.css"); var react_1 = tslib_1.__importStar(require("react")); var icons_1 = require("@ozen-ui/icons"); var useBoolean_1 = require("../../hooks/useBoolean"); var useControlled_1 = require("../../hooks/useControlled"); var useEventListener_1 = require("../../hooks/useEventListener"); var useInterval_1 = require("../../hooks/useInterval"); var useMultiRef_1 = require("../../hooks/useMultiRef"); var useThemeProps_1 = require("../../hooks/useThemeProps"); var classname_1 = require("../../utils/classname"); var FieldControl_1 = require("../FieldControl"); var FieldHint_1 = require("../FieldHint"); var FieldIcon_1 = require("../FieldIcon"); var FieldInput_1 = require("../FieldInput"); var FieldLabel_1 = require("../FieldLabel"); var Fieldset_1 = require("../Fieldset"); var IconButtonNext_1 = require("../IconButtonNext"); var constants_1 = require("./constants"); var utils_1 = require("./utils"); exports.cnInputNumber = (0, classname_1.cn)('InputNumber'); exports.InputNumber = (0, react_1.forwardRef)(function (inProps, ref) { var props = (0, useThemeProps_1.useThemeProps)({ props: inProps, name: 'InputNumber', }); var _a = props.size, size = _a === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_SIZE : _a, _b = props.step, step = _b === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_STEP : _b, _c = props.autoFocus, autoFocus = _c === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_AUTO_FOCUS : _c, _d = props.error, error = _d === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_ERROR : _d, _e = props.required, required = _e === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_REQUIRED : _e, _f = props.disabled, disabled = _f === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_DISABLED : _f, _g = props.fullWidth, fullWidth = _g === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_FULL_WIDTH : _g, _h = props.defaultValue, defaultValue = _h === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_VALUE : _h, _j = props.min, min = _j === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_MIN : _j, _k = props.max, max = _k === void 0 ? constants_1.INPUT_NUMBER_DEFAULT_MAX : _k, label = props.label, placeholder = props.placeholder, id = props.id, name = props.name, renderLeft = props.renderLeft, renderRight = props.renderRight, hint = props.hint, className = props.className, inputProps = props.inputProps, valueProp = props.value, onChange = props.onChange, labelRef = props.labelRef, labelProps = props.labelProps, bodyProps = props.bodyProps, hintProps = props.hintProps, incrementButtonText = props.incrementButtonText, decrementButtonText = props.decrementButtonText, other = tslib_1.__rest(props, ["size", "step", "autoFocus", "error", "required", "disabled", "fullWidth", "defaultValue", "min", "max", "label", "placeholder", "id", "name", "renderLeft", "renderRight", "hint", "className", "inputProps", "value", "onChange", "labelRef", "labelProps", "bodyProps", "hintProps", "incrementButtonText", "decrementButtonText"]); var _l = tslib_1.__read((0, useBoolean_1.useBoolean)(false), 2), focused = _l[0], _m = _l[1], onFocus = _m.on, offFocus = _m.off; var _o = tslib_1.__read((0, react_1.useState)(null), 2), timeoutId = _o[0], setTimeoutId = _o[1]; var _p = tslib_1.__read((0, react_1.useState)(null), 2), countDirection = _p[0], setCountDirection = _p[1]; var _q = tslib_1.__read((0, useControlled_1.useControlled)({ value: valueProp, name: 'InputNumber', state: 'value', defaultValue: defaultValue, }), 2), valueState = _q[0], setValueState = _q[1]; var bodyInnerRef = (0, react_1.useRef)(null); var fieldInnerRef = (0, react_1.useRef)(null); var filled = (0, utils_1.isValidValue)(valueState); var handleChange = function (event) { if (disabled) return; var valueAsNumber = event.target.valueAsNumber; var value = (0, utils_1.isValidValue)(valueAsNumber) ? valueAsNumber : ''; setValueState(value); onChange === null || onChange === void 0 ? void 0 : onChange(event, { id: id, name: name, value: value }); }; var startCount = function (countDirection) { var timeoutId = setTimeout(function () { setCountDirection(countDirection); }, 300); setTimeoutId(timeoutId); }; var handleMouseDown = function (countDirection) { return function (e) { var nextValue = (0, utils_1.getValue)({ min: min, max: max, step: step, countDirection: countDirection, value: valueState, }); setValueState(nextValue); onChange === null || onChange === void 0 ? void 0 : onChange(e, { id: id, name: name, value: nextValue }); startCount(countDirection); }; }; var handleMouseUp = function () { if (timeoutId) { clearTimeout(timeoutId); } setCountDirection(null); setTimeoutId(null); }; var handleFocus = function (event) { var _a; onFocus(); (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(inputProps, event); }; var handleBlur = function (event) { var _a; offFocus(); (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(inputProps, event); }; /* В некоторых браузерах input[type=number] позволяет вводить * буквенные символы, поэтому мы вручную отключаем подобное поведение. */ var handleKeyDown = function (event) { var _a; if ((0, utils_1.isInputInvalid)(event)) { event.preventDefault(); } (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(inputProps, event); }; /* Хук useEventListener необходим для того, чтобы при нажатии на кнопку мыши * внутри HTML-элемента label — фокус не переходил на body или на цель нажатия кнопки мыши. * Если же нажатие кнопки происходит на самом HTML-элементе input, то мы ничего не делаем, * так как в противном случае мы сломаем возможность выделять текст для копирования. */ (0, useEventListener_1.useEventListener)({ element: bodyInnerRef, eventName: 'mousedown', handler: function (e) { var _a; if (e.target !== fieldInnerRef.current) { e.preventDefault(); (_a = fieldInnerRef.current) === null || _a === void 0 ? void 0 : _a.focus(); } }, }); (0, useEventListener_1.useEventListener)({ active: focused, eventName: 'mouseup', handler: handleMouseUp, }); (0, useInterval_1.useInterval)(function () { if (countDirection) { var value = (0, utils_1.getValue)({ min: min, max: max, step: step, countDirection: countDirection, value: valueState, }); setValueState(value); onChange === null || onChange === void 0 ? void 0 : onChange(null, { id: id, name: name, value: value }); } }, countDirection ? 100 : null); return (react_1.default.createElement(FieldControl_1.FieldControl, tslib_1.__assign({ size: size, error: error, filled: filled, focused: focused, disabled: disabled, required: required, fullWidth: fullWidth }, other, { ref: ref, className: (0, exports.cnInputNumber)({ size: size }, [className]) }), react_1.default.createElement("label", tslib_1.__assign({}, bodyProps, { className: (0, exports.cnInputNumber)('Body'), ref: (0, useMultiRef_1.useMultiRef)([bodyProps === null || bodyProps === void 0 ? void 0 : bodyProps.ref, bodyInnerRef]) }), react_1.default.createElement(FieldIcon_1.FieldIcon, { icon: renderLeft }), react_1.default.createElement("div", { className: (0, exports.cnInputNumber)('FieldContainer') }, react_1.default.createElement(FieldLabel_1.FieldLabel, tslib_1.__assign({}, labelProps, { ref: (0, useMultiRef_1.useMultiRef)([labelProps === null || labelProps === void 0 ? void 0 : labelProps.ref, labelRef]), className: (0, exports.cnInputNumber)('Label', [labelProps === null || labelProps === void 0 ? void 0 : labelProps.className]) }), label), react_1.default.createElement(FieldInput_1.FieldInput, tslib_1.__assign({ id: id, min: min, max: max, step: step, name: name, type: "number", value: valueState, autoFocus: autoFocus, placeholder: placeholder }, inputProps, { onBlur: handleBlur, onFocus: handleFocus, onChange: handleChange, onKeyDown: handleKeyDown, ref: (0, useMultiRef_1.useMultiRef)([inputProps === null || inputProps === void 0 ? void 0 : inputProps.ref, fieldInnerRef]), className: (0, exports.cnInputNumber)('Field', [inputProps === null || inputProps === void 0 ? void 0 : inputProps.className]) }))), react_1.default.createElement(FieldIcon_1.FieldIcon, { icon: renderRight }), react_1.default.createElement("span", { className: (0, exports.cnInputNumber)('Controls') }, react_1.default.createElement(IconButtonNext_1.IconButton, { size: size, type: "button", tabIndex: -1, variant: "ghost", icon: icons_1.SortUpIcon, disabled: disabled, "aria-label": incrementButtonText, className: (0, exports.cnInputNumber)('Increment'), onMouseDown: handleMouseDown('increment') }), react_1.default.createElement(IconButtonNext_1.IconButton, { size: size, tabIndex: -1, type: "button", variant: "ghost", icon: icons_1.SortDownIcon, disabled: disabled, "aria-label": decrementButtonText, className: (0, exports.cnInputNumber)('Decrement'), onMouseDown: handleMouseDown('decrement') })), react_1.default.createElement(Fieldset_1.Fieldset, { className: (0, exports.cnInputNumber)('Fieldset') })), react_1.default.createElement(FieldHint_1.FieldHint, tslib_1.__assign({}, hintProps), hint))); }); exports.InputNumber.displayName = 'InputNumber';