@mantine/core
Version:
React components library focused on usability, accessibility and developer experience
276 lines (272 loc) • 9.1 kB
JavaScript
'use client';
;
var React = require('react');
var cx = require('clsx');
var reactNumberFormat = require('react-number-format');
var hooks = require('@mantine/hooks');
var getSize = require('../../core/utils/get-size/get-size.cjs');
var createVarsResolver = require('../../core/styles-api/create-vars-resolver/create-vars-resolver.cjs');
var useResolvedStylesApi = require('../../core/styles-api/use-resolved-styles-api/use-resolved-styles-api.cjs');
var useStyles = require('../../core/styles-api/use-styles/use-styles.cjs');
require('../../core/MantineProvider/Mantine.context.cjs');
require('../../core/MantineProvider/default-theme.cjs');
require('../../core/MantineProvider/MantineProvider.cjs');
require('../../core/MantineProvider/MantineThemeProvider/MantineThemeProvider.cjs');
var useProps = require('../../core/MantineProvider/use-props/use-props.cjs');
require('../../core/Box/Box.cjs');
var factory = require('../../core/factory/factory.cjs');
require('../../core/DirectionProvider/DirectionProvider.cjs');
var InputBase = require('../InputBase/InputBase.cjs');
var UnstyledButton = require('../UnstyledButton/UnstyledButton.cjs');
var NumberInputChevron = require('./NumberInputChevron.cjs');
var NumberInput_module = require('./NumberInput.module.css.cjs');
const partialNegativeNumberPattern = /^-0(\.0*)?$/;
const leadingZerosPattern = /^-?0\d+$/;
function isValidNumber(value) {
return (typeof value === "number" ? value < Number.MAX_SAFE_INTEGER : !Number.isNaN(Number(value))) && !Number.isNaN(value);
}
function getDecrementedValue({ value, min, step = 1, allowNegative }) {
const nextValue = value - step;
if (min !== void 0 && nextValue < min) {
return min;
}
if (!allowNegative && nextValue < 0 && min === void 0) {
return value;
}
if (min !== void 0 && min >= 0 && nextValue <= min) {
return nextValue;
}
return nextValue;
}
function isInRange(value, min, max) {
if (value === void 0) {
return true;
}
const minValid = min === void 0 || value >= min;
const maxValid = max === void 0 || value <= max;
return minValid && maxValid;
}
const defaultProps = {
step: 1,
clampBehavior: "blur",
allowDecimal: true,
allowNegative: true,
startValue: 0
};
const varsResolver = createVarsResolver.createVarsResolver((_, { size }) => ({
controls: {
"--ni-chevron-size": getSize.getSize(size, "ni-chevron-size")
}
}));
const NumberInput = factory.factory((_props, ref) => {
const props = useProps.useProps("NumberInput", defaultProps, _props);
const {
className,
classNames,
styles,
unstyled,
vars,
onChange,
onValueChange,
value,
defaultValue,
max,
min,
step,
hideControls,
rightSection,
isAllowed,
clampBehavior,
onBlur,
allowDecimal,
decimalScale,
onKeyDown,
handlersRef,
startValue,
disabled,
rightSectionPointerEvents,
allowNegative,
readOnly,
size,
rightSectionWidth,
stepHoldInterval,
stepHoldDelay,
allowLeadingZeros,
...others
} = props;
const getStyles = useStyles.useStyles({
name: "NumberInput",
classes: NumberInput_module,
props,
classNames,
styles,
unstyled,
vars,
varsResolver
});
const { resolvedClassNames, resolvedStyles } = useResolvedStylesApi.useResolvedStylesApi({
classNames,
styles,
props
});
const [_value, setValue] = hooks.useUncontrolled({
value,
defaultValue,
onChange
});
const shouldUseStepInterval = stepHoldDelay !== void 0 && stepHoldInterval !== void 0;
const inputRef = React.useRef(null);
const onStepTimeoutRef = React.useRef(null);
const stepCountRef = React.useRef(0);
const handleValueChange = (payload, event) => {
if (event.source === "event") {
setValue(
isValidNumber(payload.floatValue) && !partialNegativeNumberPattern.test(payload.value) && !(allowLeadingZeros ? leadingZerosPattern.test(payload.value) : false) ? payload.floatValue : payload.value
);
}
onValueChange?.(payload, event);
};
const incrementRef = React.useRef();
incrementRef.current = () => {
if (typeof _value !== "number" || Number.isNaN(_value)) {
setValue(hooks.clamp(startValue, min, max));
} else if (max !== void 0) {
setValue(_value + step <= max ? _value + step : max);
} else {
setValue(_value + step);
}
};
const decrementRef = React.useRef();
decrementRef.current = () => {
if (typeof _value !== "number" || Number.isNaN(_value)) {
setValue(hooks.clamp(startValue, min, max));
} else {
setValue(getDecrementedValue({ value: _value, min, step, allowNegative }));
}
};
const handleKeyDown = (event) => {
onKeyDown?.(event);
if (readOnly) {
return;
}
if (event.key === "ArrowUp") {
event.preventDefault();
incrementRef.current();
}
if (event.key === "ArrowDown") {
event.preventDefault();
decrementRef.current();
}
};
hooks.assignRef(handlersRef, { increment: incrementRef.current, decrement: decrementRef.current });
const onStepHandleChange = (isIncrement) => {
if (isIncrement) {
incrementRef.current();
} else {
decrementRef.current();
}
stepCountRef.current += 1;
};
const onStepLoop = (isIncrement) => {
onStepHandleChange(isIncrement);
if (shouldUseStepInterval) {
const interval = typeof stepHoldInterval === "number" ? stepHoldInterval : stepHoldInterval(stepCountRef.current);
onStepTimeoutRef.current = window.setTimeout(() => onStepLoop(isIncrement), interval);
}
};
const onStep = (event, isIncrement) => {
event.preventDefault();
inputRef.current?.focus();
onStepHandleChange(isIncrement);
if (shouldUseStepInterval) {
onStepTimeoutRef.current = window.setTimeout(() => onStepLoop(isIncrement), stepHoldDelay);
}
};
const onStepDone = () => {
if (onStepTimeoutRef.current) {
window.clearTimeout(onStepTimeoutRef.current);
}
onStepTimeoutRef.current = null;
stepCountRef.current = 0;
};
const controls = /* @__PURE__ */ React.createElement("div", { ...getStyles("controls") }, /* @__PURE__ */ React.createElement(
UnstyledButton.UnstyledButton,
{
...getStyles("control"),
tabIndex: -1,
"aria-hidden": true,
disabled: disabled || typeof _value === "number" && max !== void 0 && _value >= max,
mod: { direction: "up" },
onMouseDown: (event) => event.preventDefault(),
onPointerDown: (event) => {
onStep(event, true);
},
onPointerUp: onStepDone,
onPointerLeave: onStepDone
},
/* @__PURE__ */ React.createElement(NumberInputChevron.NumberInputChevron, { direction: "up" })
), /* @__PURE__ */ React.createElement(
UnstyledButton.UnstyledButton,
{
...getStyles("control"),
tabIndex: -1,
"aria-hidden": true,
disabled: disabled || typeof _value === "number" && min !== void 0 && _value <= min,
mod: { direction: "down" },
onMouseDown: (event) => event.preventDefault(),
onPointerDown: (event) => {
onStep(event, false);
},
onPointerUp: onStepDone,
onPointerLeave: onStepDone
},
/* @__PURE__ */ React.createElement(NumberInputChevron.NumberInputChevron, { direction: "down" })
));
return /* @__PURE__ */ React.createElement(
InputBase.InputBase,
{
component: reactNumberFormat.NumericFormat,
allowNegative,
className: cx(NumberInput_module.root, className),
size,
...others,
readOnly,
disabled,
value: _value,
getInputRef: hooks.useMergedRef(ref, inputRef),
onValueChange: handleValueChange,
rightSection: hideControls || readOnly ? rightSection : rightSection || controls,
classNames: resolvedClassNames,
styles: resolvedStyles,
unstyled,
__staticSelector: "NumberInput",
decimalScale: allowDecimal ? decimalScale : 0,
onKeyDown: handleKeyDown,
rightSectionPointerEvents: rightSectionPointerEvents ?? (disabled ? "none" : void 0),
rightSectionWidth: rightSectionWidth ?? `var(--ni-right-section-width-${size || "sm"})`,
allowLeadingZeros,
onBlur: (event) => {
onBlur?.(event);
if (clampBehavior === "blur" && typeof _value === "number") {
const clampedValue = hooks.clamp(_value, min, max);
if (clampedValue !== _value) {
setValue(hooks.clamp(_value, min, max));
}
}
},
isAllowed: (val) => {
if (clampBehavior === "strict") {
if (isAllowed) {
return isAllowed(val) && isInRange(val.floatValue, min, max);
}
return isInRange(val.floatValue, min, max);
}
return isAllowed ? isAllowed(val) : true;
}
}
);
});
NumberInput.classes = { ...InputBase.InputBase.classes, ...NumberInput_module };
NumberInput.displayName = "@mantine/core/NumberInput";
exports.NumberInput = NumberInput;
//# sourceMappingURL=NumberInput.cjs.map