map • Lines: 1{"mappings":"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","sources":["packages/react-stately/src/numberfield/useNumberFieldState.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {clamp, snapValueToStep} from '../utils/number';\n\nimport {\n FocusableProps,\n HelpTextProps,\n InputBase,\n LabelableProps,\n RangeInputBase,\n TextInputBase,\n Validation,\n ValueBase\n} from '@react-types/shared';\nimport {FormValidationState, useFormValidationState} from '../form/useFormValidationState';\nimport {NumberFormatter, NumberParser} from '@internationalized/number';\nimport {useCallback, useMemo, useState} from 'react';\nimport {useControlledState} from '../utils/useControlledState';\n\nexport interface NumberFieldProps\n extends\n InputBase,\n Validation<number>,\n FocusableProps,\n TextInputBase,\n ValueBase<number>,\n RangeInputBase<number>,\n LabelableProps,\n HelpTextProps {\n /**\n * Formatting options for the value displayed in the number field.\n * This also affects what characters are allowed to be typed by the user.\n */\n formatOptions?: Intl.NumberFormatOptions;\n /**\n * Controls the behavior of the number field when the user blurs the field after editing. 'snap'\n * will clamp the value to the min/max values, and snap to the nearest step value. 'validate' will\n * not clamp the value, and will validate that the value is within the min/max range and on a\n * valid step.\n *\n * @default 'snap'\n */\n commitBehavior?: 'snap' | 'validate';\n}\n\nexport interface NumberFieldState extends FormValidationState {\n /**\n * The current text value of the input. Updated as the user types,\n * and formatted according to `formatOptions` on blur.\n */\n inputValue: string;\n /**\n * The currently parsed number value, or NaN if a valid number could not be parsed.\n * Updated based on the `inputValue` as the user types.\n */\n numberValue: number;\n /** The default value of the input. */\n defaultNumberValue: number;\n /** The minimum value of the number field. */\n minValue?: number;\n /** The maximum value of the number field. */\n maxValue?: number;\n /** Whether the current value can be incremented according to the maximum value and step. */\n canIncrement: boolean;\n /** Whether the current value can be decremented according to the minimum value and step. */\n canDecrement: boolean;\n /**\n * Validates a user input string according to the current locale and format options. Values can be\n * partially entered, and may be valid even if they cannot currently be parsed to a number. Can be\n * used to implement validation as a user types.\n */\n validate(value: string): boolean;\n /** Sets the current text value of the input. */\n setInputValue(val: string): void;\n /** Sets the number value. */\n setNumberValue(val: number): void;\n /**\n * Commits the current input value. The value is parsed to a number, clamped according to the\n * minimum and maximum values of the field, and snapped to the nearest step value. This will fire\n * the `onChange` prop with the new value, and if uncontrolled, update the `numberValue`.\n * Typically this is called when the field is blurred.\n *\n * @param value - The value to commit. If not provided, the current input value is used.\n */\n commit(value?: string): void;\n /** Increments the current input value to the next step boundary, and fires `onChange`. */\n increment(): void;\n /** Decrements the current input value to the next step boundary, and fires `onChange`. */\n decrement(): void;\n /** Sets the current value to the `maxValue` if any, and fires `onChange`. */\n incrementToMax(): void;\n /** Sets the current value to the `minValue` if any, and fires `onChange`. */\n decrementToMin(): void;\n}\n\nexport interface NumberFieldStateOptions extends NumberFieldProps {\n /**\n * The locale that should be used for parsing.\n *\n * @default 'en-US'\n */\n locale: string;\n}\n\n/**\n * Provides state management for a number field component. Number fields allow users to enter a\n * number, and increment or decrement the value using stepper buttons.\n */\nexport function useNumberFieldState(props: NumberFieldStateOptions): NumberFieldState {\n let {\n minValue,\n maxValue,\n step,\n formatOptions,\n value,\n defaultValue = NaN,\n onChange,\n locale,\n isDisabled,\n isReadOnly,\n commitBehavior = 'snap'\n } = props;\n\n if (value === null) {\n value = NaN;\n }\n\n let snapValue = useCallback(\n value => {\n return step === undefined || isNaN(step)\n ? clamp(value, minValue, maxValue)\n : snapValueToStep(value, minValue, maxValue, step);\n },\n [step, minValue, maxValue]\n );\n\n if (value !== undefined && !isNaN(value) && commitBehavior === 'snap') {\n value = snapValue(value);\n }\n\n if (!isNaN(defaultValue) && commitBehavior === 'snap') {\n defaultValue = snapValue(defaultValue);\n }\n\n let [numberValue, setNumberValue] = useControlledState<number>(\n value,\n isNaN(defaultValue) ? NaN : defaultValue,\n onChange\n );\n let [initialValue] = useState(numberValue);\n let [inputValue, setInputValue] = useState(() =>\n isNaN(numberValue) ? '' : new NumberFormatter(locale, formatOptions).format(numberValue)\n );\n\n let numberParser = useMemo(\n () => new NumberParser(locale, formatOptions),\n [locale, formatOptions]\n );\n let numberingSystem = useMemo(\n () => numberParser.getNumberingSystem(inputValue),\n [numberParser, inputValue]\n );\n let formatter = useMemo(\n () => new NumberFormatter(locale, {...formatOptions, numberingSystem}),\n [locale, formatOptions, numberingSystem]\n );\n let intlOptions = useMemo(() => formatter.resolvedOptions(), [formatter]);\n let format = useCallback(\n (value: number) => (isNaN(value) || value === null ? '' : formatter.format(value)),\n [formatter]\n );\n\n let validation = useFormValidationState({\n ...props,\n value: numberValue\n });\n\n let clampStep = step !== undefined && !isNaN(step) ? step : 1;\n if (intlOptions.style === 'percent' && (step === undefined || isNaN(step))) {\n clampStep = 0.01;\n }\n\n // Update the input value when the number value or format options change. This is done\n // in a useEffect so that the controlled behavior is correct and we only update the\n // textfield after prop changes.\n let [prevValue, setPrevValue] = useState(numberValue);\n let [prevLocale, setPrevLocale] = useState(locale);\n let [prevFormatOptions, setPrevFormatOptions] = useState(formatOptions);\n if (\n !Object.is(numberValue, prevValue) ||\n locale !== prevLocale ||\n !isEqualFormatOptions(formatOptions, prevFormatOptions)\n ) {\n setInputValue(format(numberValue));\n setPrevValue(numberValue);\n setPrevLocale(locale);\n setPrevFormatOptions(formatOptions);\n }\n\n let parsedValue = useMemo(() => numberParser.parse(inputValue), [numberParser, inputValue]);\n let commit = (overrideValue?: string) => {\n let newInputValue = overrideValue === undefined ? inputValue : overrideValue;\n let newParsedValue = parsedValue;\n if (overrideValue !== undefined) {\n newParsedValue = numberParser.parse(newInputValue);\n }\n // Set to empty state if input value is empty\n if (!newInputValue.length) {\n setNumberValue(NaN);\n setInputValue(value === undefined ? '' : format(numberValue));\n return;\n }\n\n // if it failed to parse, then reset input to formatted version of current number\n if (isNaN(newParsedValue)) {\n setInputValue(format(numberValue));\n return;\n }\n\n // Clamp to min and max, round to the nearest step, and round to specified number of digits\n let clampedValue = commitBehavior === 'snap' ? snapValue(newParsedValue) : newParsedValue;\n clampedValue = numberParser.parse(format(clampedValue));\n let shouldValidate = clampedValue !== numberValue;\n setNumberValue(clampedValue);\n\n // in a controlled state, the numberValue won't change, so we won't go back to our old input without help\n setInputValue(format(value === undefined ? clampedValue : numberValue));\n if (shouldValidate) {\n validation.commitValidation();\n }\n };\n\n let safeNextStep = (operation: '+' | '-', minMax: number = 0) => {\n let prev = parsedValue;\n\n if (isNaN(prev)) {\n // if the input is empty, start from the min/max value when incrementing/decrementing,\n // or zero if there is no min/max value defined.\n let newValue = isNaN(minMax) ? 0 : minMax;\n return snapValueToStep(newValue, minValue, maxValue, clampStep);\n } else {\n // otherwise, first snap the current value to the nearest step. if it moves in the direction\n // we're going, use that value, otherwise add the step and snap that value.\n let newValue = snapValueToStep(prev, minValue, maxValue, clampStep);\n if ((operation === '+' && newValue > prev) || (operation === '-' && newValue < prev)) {\n return newValue;\n }\n\n return snapValueToStep(\n handleDecimalOperation(operation, prev, clampStep),\n minValue,\n maxValue,\n clampStep\n );\n }\n };\n\n let increment = () => {\n let newValue = safeNextStep('+', minValue);\n\n // if we've arrived at the same value that was previously in the state, the\n // input value should be updated to match\n // ex type 4, press increment, highlight the number in the input, type 4 again, press increment\n // you'd be at 5, then incrementing to 5 again, so no re-render would happen and 4 would be left in the input\n if (newValue === numberValue) {\n setInputValue(format(newValue));\n }\n\n setNumberValue(newValue);\n validation.commitValidation();\n };\n\n let decrement = () => {\n let newValue = safeNextStep('-', maxValue);\n\n if (newValue === numberValue) {\n setInputValue(format(newValue));\n }\n\n setNumberValue(newValue);\n validation.commitValidation();\n };\n\n let incrementToMax = () => {\n if (maxValue != null) {\n setNumberValue(snapValueToStep(maxValue, minValue, maxValue, clampStep));\n validation.commitValidation();\n }\n };\n\n let decrementToMin = () => {\n if (minValue != null) {\n setNumberValue(minValue);\n validation.commitValidation();\n }\n };\n\n let canIncrement = useMemo(\n () =>\n !isDisabled &&\n !isReadOnly &&\n (isNaN(parsedValue) ||\n maxValue === undefined ||\n isNaN(maxValue) ||\n snapValueToStep(parsedValue, minValue, maxValue, clampStep) > parsedValue ||\n handleDecimalOperation('+', parsedValue, clampStep) <= maxValue),\n [isDisabled, isReadOnly, minValue, maxValue, clampStep, parsedValue]\n );\n\n let canDecrement = useMemo(\n () =>\n !isDisabled &&\n !isReadOnly &&\n (isNaN(parsedValue) ||\n minValue === undefined ||\n isNaN(minValue) ||\n snapValueToStep(parsedValue, minValue, maxValue, clampStep) < parsedValue ||\n handleDecimalOperation('-', parsedValue, clampStep) >= minValue),\n [isDisabled, isReadOnly, minValue, maxValue, clampStep, parsedValue]\n );\n\n let validate = (value: string) => numberParser.isValidPartialNumber(value, minValue, maxValue);\n\n return {\n ...validation,\n validate,\n increment,\n incrementToMax,\n decrement,\n decrementToMin,\n canIncrement,\n canDecrement,\n minValue,\n maxValue,\n numberValue: parsedValue,\n defaultNumberValue: isNaN(defaultValue) ? initialValue : defaultValue,\n setNumberValue,\n setInputValue,\n inputValue,\n commit\n };\n}\n\n// Shallow equality is sufficient here because all values in Intl.NumberFormatOptions are primitives.\nfunction isEqualFormatOptions(\n a: Intl.NumberFormatOptions | undefined,\n b: Intl.NumberFormatOptions | undefined\n) {\n if (a === b) {\n return true;\n }\n if (!a || !b) {\n return false;\n }\n let aKeys = Object.keys(a);\n let bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n for (let key of aKeys) {\n if (b[key] !== a[key]) {\n return false;\n }\n }\n return true;\n}\n\nfunction handleDecimalOperation(operator: '-' | '+', value1: number, value2: number): number {\n let result = operator === '+' ? value1 + value2 : value1 - value2;\n\n // Check if we have decimals\n if (value1 % 1 !== 0 || value2 % 1 !== 0) {\n const value1Decimal = value1.toString().split('.');\n const value2Decimal = value2.toString().split('.');\n const value1DecimalLength = (value1Decimal[1] && value1Decimal[1].length) || 0;\n const value2DecimalLength = (value2Decimal[1] && value2Decimal[1].length) || 0;\n const multiplier = Math.pow(10, Math.max(value1DecimalLength, value2DecimalLength));\n\n // Transform the decimals to integers based on the precision\n value1 = Math.round(value1 * multiplier);\n value2 = Math.round(value2 * multiplier);\n\n // Perform the operation on integers values to make sure we don't get a fancy decimal value\n result = operator === '+' ? value1 + value2 : value1 - value2;\n\n // Transform the integer result back to decimal\n result /= multiplier;\n }\n\n return result;\n}\n"],"names":[],"version":3,"file":"useNumberFieldState.cjs.map"}