@ozen-ui/kit
Version:
React component library
146 lines (145 loc) • 10.6 kB
JavaScript
"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';