UNPKG

@gravity-ui/uikit

Version:

Gravity UI base styling and components

146 lines (145 loc) 6.83 kB
'use client'; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NumberInput = void 0; const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const React = tslib_1.__importStar(require("react")); const constants_1 = require("../../constants.js"); const hooks_1 = require("../../hooks/index.js"); const private_1 = require("../../hooks/private/index.js"); const TextInput_1 = require("../controls/TextInput/index.js"); const utils_1 = require("../controls/utils.js"); const cn_1 = require("../utils/cn.js"); const NumericArrows_1 = require("./NumericArrows/NumericArrows.js"); const utils_2 = require("./utils.js"); require("./NumberInput.css"); const b = (0, cn_1.block)('number-input'); function getStringValue(value) { return value === null ? '' : String(value); } exports.NumberInput = React.forwardRef(function NumberInput({ endContent, defaultValue: externalDefaultValue, ...props }, ref) { const { value: externalValue, onChange: handleChange, onUpdate: externalOnUpdate, min: externalMin, max: externalMax, shiftMultiplier: externalShiftMultiplier = 10, step: externalStep, size = 'm', view = 'normal', disabled, hiddenControls, validationState, onBlur, onKeyDown, allowDecimal = false, className, } = props; const { min, max, step: baseStep, value: internalValue, defaultValue, shiftMultiplier, } = (0, utils_2.getInternalState)({ min: externalMin, max: externalMax, step: externalStep, shiftMultiplier: externalShiftMultiplier, allowDecimal, value: externalValue, defaultValue: externalDefaultValue, }); const [value, setValue] = (0, hooks_1.useControlledState)(internalValue, defaultValue ?? null, externalOnUpdate); const [inputValue, setInputValue] = React.useState(getStringValue(value)); React.useEffect(() => { const stringPropsValue = getStringValue(value); setInputValue((currentInputValue) => { if (!(0, utils_2.areStringRepresentationOfNumbersEqual)(currentInputValue, stringPropsValue)) { return stringPropsValue; } return currentInputValue; }); }, [value]); const clamp = !(allowDecimal && !externalStep); const safeValue = value ?? 0; const state = (0, utils_1.getInputControlState)(validationState); const canIncrementNumber = safeValue < (max ?? Number.MAX_SAFE_INTEGER); const canDecrementNumber = safeValue > (min ?? Number.MIN_SAFE_INTEGER); const innerControlRef = React.useRef(null); const fieldRef = (0, private_1.useFormResetHandler)({ initialValue: value, onReset: setValue, }); const handleRef = (0, hooks_1.useForkRef)(props.controlRef, innerControlRef, fieldRef); const handleValueDelta = (e, direction) => { const step = e.shiftKey ? shiftMultiplier * baseStep : baseStep; const deltaWithSign = direction === 'up' ? step : -step; if (direction === 'up' ? canIncrementNumber : canDecrementNumber) { const newValue = (0, utils_2.clampToNearestStepValue)({ value: safeValue + deltaWithSign, step: baseStep, min, max, direction, }); setValue?.(newValue); setInputValue(newValue.toString()); } }; const handleKeyDown = (e) => { if (e.key === constants_1.KeyCode.ARROW_DOWN) { e.preventDefault(); handleValueDelta(e, 'down'); } else if (e.key === constants_1.KeyCode.ARROW_UP) { e.preventDefault(); handleValueDelta(e, 'up'); } else if (e.key === constants_1.KeyCode.HOME) { e.preventDefault(); if (min !== undefined) { setValue?.(min); setInputValue(min.toString()); } } else if (e.key === constants_1.KeyCode.END) { e.preventDefault(); if (max !== undefined) { const newValue = (0, utils_2.clampToNearestStepValue)({ value: max, step: baseStep, min, max, }); setValue?.(newValue); setInputValue(newValue.toString()); } } onKeyDown?.(e); }; const handleBlur = (e) => { if (clamp && value !== null) { const clampedValue = (0, utils_2.clampToNearestStepValue)({ value, step: baseStep, min, max, }); if (value !== clampedValue) { setValue?.(clampedValue); } setInputValue(clampedValue.toString()); } onBlur?.(e); }; const handleUpdate = (v) => { setInputValue(v); const preparedStringValue = (0, utils_2.getPossibleNumberSubstring)(v, allowDecimal); (0, utils_2.updateCursorPosition)(innerControlRef, v, preparedStringValue); const { valid, value: parsedNumberValue } = (0, utils_2.getParsedValue)(preparedStringValue); if (valid && parsedNumberValue !== value) { setValue?.(parsedNumberValue); } }; const handleInput = (e) => { const preparedStringValue = (0, utils_2.getPossibleNumberSubstring)(e.currentTarget.value, allowDecimal); (0, utils_2.updateCursorPosition)(innerControlRef, e.currentTarget.value, preparedStringValue); }; return ((0, jsx_runtime_1.jsx)(TextInput_1.TextInput, { ...props, className: b({ size, view, state }, className), controlProps: { onInput: handleInput, ...props.controlProps, role: 'spinbutton', inputMode: allowDecimal ? 'decimal' : 'numeric', pattern: props.controlProps?.pattern ?? (0, utils_2.getInputPattern)(allowDecimal, false), 'aria-valuemin': props.min, 'aria-valuemax': props.max, 'aria-valuenow': value === null ? undefined : value, }, controlRef: handleRef, value: inputValue, onChange: handleChange, onUpdate: handleUpdate, onKeyDown: handleKeyDown, onBlur: handleBlur, ref: ref, endContent: (0, jsx_runtime_1.jsxs)(React.Fragment, { children: [endContent, hiddenControls ? null : ((0, jsx_runtime_1.jsx)(NumericArrows_1.NumericArrows, { className: b('arrows'), size: size, disabled: disabled, onUpClick: (e) => { innerControlRef.current?.focus(); handleValueDelta(e, 'up'); }, onDownClick: (e) => { innerControlRef.current?.focus(); handleValueDelta(e, 'down'); } }))] }) })); }); //# sourceMappingURL=NumberInput.js.map