{"mappings":"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","sources":["packages/react-aria/src/numberfield/useNumberField.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 {announce} from '../live-announcer/LiveAnnouncer';\n\nimport {AriaButtonProps} from '../button/useButton';\nimport {AriaLabelingProps, DOMAttributes, DOMProps, GroupDOMAttributes, TextInputDOMEvents, TextInputDOMProps, ValidationResult} from '@react-types/shared';\nimport {chain} from '../utils/chain';\nimport {\n  type ClipboardEvent,\n  type ClipboardEventHandler,\n  InputHTMLAttributes,\n  LabelHTMLAttributes,\n  RefObject,\n  useCallback,\n  useMemo,\n  useState\n} from 'react';\nimport {filterDOMProps} from '../utils/filterDOMProps';\nimport {flushSync} from 'react-dom';\nimport {getActiveElement, getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport intlMessages from '../../intl/numberfield/*.json';\nimport {isAndroid, isIOS, isIPhone} from '../utils/platform';\nimport {mergeProps} from '../utils/mergeProps';\nimport {NumberFieldProps, NumberFieldState} from 'react-stately/useNumberFieldState';\nimport {privateValidationStateProp} from 'react-stately/private/form/useFormValidationState';\n// @ts-ignore\nimport {useFocus} from '../interactions/useFocus';\nimport {useFocusWithin} from '../interactions/useFocusWithin';\nimport {useFormattedTextField} from '../textfield/useFormattedTextField';\nimport {useFormReset} from '../utils/useFormReset';\nimport {useId} from '../utils/useId';\nimport {useLayoutEffect} from '../utils/useLayoutEffect';\nimport {useLocalizedStringFormatter} from '../i18n/useLocalizedStringFormatter';\nimport {useNumberFormatter} from '../i18n/useNumberFormatter';\nimport {useScrollWheel} from '../interactions/useScrollWheel';\nimport {useSpinButton} from '../spinbutton/useSpinButton';\n\nexport interface AriaNumberFieldProps extends NumberFieldProps, DOMProps, AriaLabelingProps, TextInputDOMEvents {\n  /** A custom aria-label for the decrement button. If not provided, the localized string \"Decrement\" is used. */\n  decrementAriaLabel?: string,\n  /** A custom aria-label for the increment button. If not provided, the localized string \"Increment\" is used. */\n  incrementAriaLabel?: string,\n  /**\n   * Enables or disables changing the value with scroll.\n   */\n  isWheelDisabled?: boolean\n}\n\nexport interface NumberFieldAria extends ValidationResult {\n  /** Props for the label element. */\n  labelProps: LabelHTMLAttributes<HTMLLabelElement>,\n  /** Props for the group wrapper around the input and stepper buttons. */\n  groupProps: GroupDOMAttributes,\n  /** Props for the input element. */\n  inputProps: InputHTMLAttributes<HTMLInputElement>,\n  /** Props for the increment button, to be passed to `useButton`. */\n  incrementButtonProps: AriaButtonProps,\n  /** Props for the decrement button, to be passed to `useButton`. */\n  decrementButtonProps: AriaButtonProps,\n  /** Props for the number field's description element, if any. */\n  descriptionProps: DOMAttributes,\n  /** Props for the number field's error message element, if any. */\n  errorMessageProps: DOMAttributes\n}\n\n/**\n * Provides the behavior and accessibility implementation for a number field component.\n * Number fields allow users to enter a number, and increment or decrement the value using stepper buttons.\n */\nexport function useNumberField(props: AriaNumberFieldProps, state: NumberFieldState, inputRef: RefObject<HTMLInputElement | null>): NumberFieldAria {\n  let {\n    id,\n    decrementAriaLabel,\n    incrementAriaLabel,\n    isDisabled,\n    isReadOnly,\n    isRequired,\n    minValue,\n    maxValue,\n    autoFocus,\n    label,\n    formatOptions,\n    onBlur = () => {},\n    onFocus,\n    onFocusChange,\n    onKeyDown,\n    onKeyUp,\n    description,\n    errorMessage,\n    isWheelDisabled,\n    ...otherProps\n  } = props;\n\n  let {\n    increment,\n    incrementToMax,\n    decrement,\n    decrementToMin,\n    numberValue,\n    inputValue,\n    commit,\n    commitValidation\n  } = state;\n\n  const stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/numberfield');\n  let commitAndAnnounce = useCallback(() => {\n    let oldValue = inputRef.current?.value ?? '';\n    // Set input value to normalized valid value\n    flushSync(() => {\n      commit();\n    });\n\n    if (inputRef.current?.value !== oldValue) {\n      announce(inputRef.current?.value ?? '', 'assertive');\n    }\n  }, [commit, inputRef]);\n\n  let inputId = useId(id);\n  let {focusProps} = useFocus({\n    onBlur() {\n      commitAndAnnounce();\n    }\n  });\n\n  let numberFormatter = useNumberFormatter(formatOptions);\n  let intlOptions = useMemo(() => numberFormatter.resolvedOptions(), [numberFormatter]);\n\n  // Replace negative textValue formatted using currencySign: 'accounting'\n  // with a textValue that can be announced using a minus sign.\n  let textValueFormatter = useNumberFormatter({...formatOptions, currencySign: undefined});\n  let textValue = useMemo(() => isNaN(numberValue) ? '' : textValueFormatter.format(numberValue), [textValueFormatter, numberValue]);\n\n  let {\n    spinButtonProps,\n    incrementButtonProps: incButtonProps,\n    decrementButtonProps: decButtonProps\n  } = useSpinButton(\n    {\n      isDisabled,\n      isReadOnly,\n      isRequired,\n      maxValue,\n      minValue,\n      onIncrement: increment,\n      onIncrementToMax: incrementToMax,\n      onDecrement: decrement,\n      onDecrementToMin: decrementToMin,\n      value: numberValue,\n      textValue\n    }\n  );\n\n  let [focusWithin, setFocusWithin] = useState(false);\n  let {focusWithinProps} = useFocusWithin({isDisabled, onFocusWithinChange: setFocusWithin});\n\n  let onWheel = useCallback((e) => {\n    // if on a trackpad, users can scroll in both X and Y at once, check the magnitude of the change\n    // if it's mostly in the X direction, then just return, the user probably doesn't mean to inc/dec\n    // this isn't perfect, events come in fast with small deltas and a part of the scroll may give a false indication\n    // especially if the user is scrolling near 45deg\n    if (Math.abs(e.deltaY) <= Math.abs(e.deltaX)) {\n      return;\n    }\n    if (e.deltaY > 0) {\n      increment();\n    } else if (e.deltaY < 0) {\n      decrement();\n    }\n  }, [decrement, increment]);\n  // If the input isn't supposed to receive input, disable scrolling.\n  let scrollingDisabled = isWheelDisabled || isDisabled || isReadOnly || !focusWithin;\n  useScrollWheel({onScroll: onWheel, isDisabled: scrollingDisabled}, inputRef);\n\n  // The inputMode attribute influences the software keyboard that is shown on touch devices.\n  // Browsers and operating systems are quite inconsistent about what keys are available, however.\n  // We choose between numeric and decimal based on whether we allow negative and fractional numbers,\n  // and based on testing on various devices to determine what keys are available in each inputMode.\n  let hasDecimals = (intlOptions.maximumFractionDigits ?? 0) > 0;\n  let hasNegative = (state.minValue === undefined || isNaN(state.minValue)) || state.minValue < 0;\n  let inputMode: TextInputDOMProps['inputMode'] = 'numeric';\n  if (isIPhone()) {\n    // iPhone doesn't have a minus sign in either numeric or decimal.\n    // Note this is only for iPhone, not iPad, which always has both\n    // minus and decimal in numeric.\n    if (hasNegative) {\n      inputMode = 'text';\n    } else if (hasDecimals) {\n      inputMode = 'decimal';\n    }\n  } else if (isAndroid()) {\n    // Android numeric has both a decimal point and minus key.\n    // decimal does not have a minus key.\n    if (hasNegative) {\n      inputMode = 'numeric';\n    } else if (hasDecimals) {\n      inputMode = 'decimal';\n    }\n  }\n\n  let onChange = value => {\n    if (state.validate(value)) {\n      state.setInputValue(value);\n    }\n  };\n\n  let onPaste: ClipboardEventHandler<HTMLInputElement> = (e: ClipboardEvent<HTMLInputElement>) => {\n    props.onPaste?.(e);\n    let inputElement = getEventTarget(e) as HTMLInputElement;\n    // we can only handle the case where the paste takes over the entire input, otherwise things get very complicated\n    // trying to calculate the new string based on what the paste is replacing and where in the source string it is\n    if (inputElement &&\n      ((inputElement.selectionEnd ?? -1) - (inputElement.selectionStart ?? 0)) === inputElement.value.length\n    ) {\n      e.preventDefault();\n      // commit so that the user gets to see what it formats to immediately\n      // paste happens before inputRef's value is updated, so have to prevent the default and do it ourselves\n      // spin button will then handle announcing the new value, this should work with controlled state as well\n      // because the announcement is done as a result of the new rendered input value if there is one\n      commit(e.clipboardData?.getData?.('text/plain')?.trim() ?? '');\n    }\n  };\n\n  let domProps = filterDOMProps(props);\n  let onKeyDownEnter = useCallback((e) => {\n    if (e.nativeEvent.isComposing) {\n      return;\n    }\n\n    if (e.key === 'Enter') {\n      flushSync(() => {\n        commit();\n      });\n      commitValidation();\n    } else {\n      e.continuePropagation();\n    }\n  }, [commit, commitValidation]);\n\n  let {isInvalid, validationErrors, validationDetails} = state.displayValidation;\n  let {labelProps, inputProps: textFieldProps, descriptionProps, errorMessageProps} = useFormattedTextField({\n    ...otherProps,\n    ...domProps,\n    // These props are added to a hidden input rather than the formatted textfield.\n    name: undefined,\n    form: undefined,\n    label,\n    autoFocus,\n    isDisabled,\n    isReadOnly,\n    isRequired,\n    validate: undefined,\n    [privateValidationStateProp]: state,\n    value: inputValue,\n    defaultValue: '!', // an invalid value so that form reset is ignored in onChange above\n    autoComplete: 'off',\n    'aria-label': props['aria-label'] || undefined,\n    'aria-labelledby': props['aria-labelledby'] || undefined,\n    id: inputId,\n    type: 'text', // Can't use type=\"number\" because then we can't have things like $ in the field.\n    inputMode,\n    onChange,\n    onBlur,\n    onFocus,\n    onFocusChange,\n    onKeyDown: useMemo(() => chain(onKeyDownEnter, onKeyDown), [onKeyDownEnter, onKeyDown]),\n    onKeyUp,\n    onPaste,\n    description,\n    errorMessage\n  }, state, inputRef);\n\n  useFormReset(inputRef, state.defaultNumberValue, state.setNumberValue);\n  useNativeValidation(state, props.validationBehavior, props.commitBehavior, inputRef, state.minValue, state.maxValue, props.step, state.numberValue);\n\n  let inputProps: InputHTMLAttributes<HTMLInputElement> = mergeProps(\n    spinButtonProps,\n    focusProps,\n    textFieldProps,\n    {\n      // override the spinbutton role, we can't focus a spin button with VO\n      role: null,\n      // ignore aria-roledescription on iOS so that required state will announce when it is present\n      'aria-roledescription': (!isIOS() ? stringFormatter.format('numberField') : null),\n      'aria-valuemax': null,\n      'aria-valuemin': null,\n      'aria-valuenow': null,\n      'aria-valuetext': null,\n      autoCorrect: 'off',\n      spellCheck: 'false'\n    }\n  );\n\n  if (props.validationBehavior === 'native') {\n    inputProps['aria-required'] = undefined;\n  }\n\n  let onButtonPressStart = (e) => {\n    // If focus is already on the input, keep it there so we don't hide the\n    // software keyboard when tapping the increment/decrement buttons.\n    if (getActiveElement() === inputRef.current) {\n      return;\n    }\n\n    // Otherwise, when using a mouse, move focus to the input.\n    // On touch, or with a screen reader, focus the button so that the software\n    // keyboard does not appear and the screen reader cursor is not moved off the button.\n    if (e.pointerType === 'mouse') {\n      inputRef.current?.focus();\n    } else {\n      e.target.focus();\n    }\n  };\n\n  // Determine the label for the increment and decrement buttons. There are 4 cases:\n  //\n  // 1. With a visible label that is a string: aria-label: `Increase ${props.label}`\n  // 2. With a visible label that is JSX: aria-label: 'Increase', aria-labelledby: '${incrementId} ${labelId}'\n  // 3. With an aria-label: aria-label: `Increase ${props['aria-label']}`\n  // 4. With an aria-labelledby: aria-label: 'Increase', aria-labelledby: `${incrementId} ${props['aria-labelledby']}`\n  //\n  // (1) and (2) could possibly be combined and both use aria-labelledby. However, placing the label in\n  // the aria-label string rather than using aria-labelledby gives more flexibility to translators to change\n  // the order or add additional words around the label if needed.\n  let fieldLabel = props['aria-label'] || (typeof props.label === 'string' ? props.label : '');\n  let ariaLabelledby: string | undefined;\n  if (!fieldLabel) {\n    ariaLabelledby = props.label != null ? labelProps.id : props['aria-labelledby'];\n  }\n\n  let incrementId = useId();\n  let decrementId = useId();\n\n  let incrementButtonProps: AriaButtonProps = mergeProps(incButtonProps, {\n    'aria-label': incrementAriaLabel || stringFormatter.format('increase', {fieldLabel}).trim(),\n    id: ariaLabelledby && !incrementAriaLabel ? incrementId : null,\n    'aria-labelledby': ariaLabelledby && !incrementAriaLabel ? `${incrementId} ${ariaLabelledby}` : null,\n    'aria-controls': inputId,\n    excludeFromTabOrder: true,\n    preventFocusOnPress: true,\n    allowFocusWhenDisabled: true,\n    isDisabled: !state.canIncrement,\n    onPressStart: onButtonPressStart\n  });\n\n  let decrementButtonProps: AriaButtonProps = mergeProps(decButtonProps, {\n    'aria-label': decrementAriaLabel || stringFormatter.format('decrease', {fieldLabel}).trim(),\n    id: ariaLabelledby && !decrementAriaLabel ? decrementId : null,\n    'aria-labelledby': ariaLabelledby && !decrementAriaLabel ? `${decrementId} ${ariaLabelledby}` : null,\n    'aria-controls': inputId,\n    excludeFromTabOrder: true,\n    preventFocusOnPress: true,\n    allowFocusWhenDisabled: true,\n    isDisabled: !state.canDecrement,\n    onPressStart: onButtonPressStart\n  });\n\n  return {\n    groupProps: {\n      ...focusWithinProps,\n      role: 'group',\n      'aria-disabled': isDisabled,\n      'aria-invalid': isInvalid ? 'true' : undefined\n    },\n    labelProps,\n    inputProps,\n    incrementButtonProps,\n    decrementButtonProps,\n    errorMessageProps,\n    descriptionProps,\n    isInvalid,\n    validationErrors,\n    validationDetails\n  };\n}\n\nlet numberInput: HTMLInputElement | null = null;\n\nfunction useNativeValidation(\n  state: NumberFieldState,\n  validationBehavior: 'native' | 'aria' | undefined,\n  commitBehavior: 'snap' | 'validate' | undefined,\n  inputRef: RefObject<HTMLInputElement | null>,\n  min: number | undefined,\n  max: number | undefined,\n  step: number | undefined,\n  value: number | undefined\n) {\n  useLayoutEffect(() => {\n    let input = inputRef.current;\n    if (commitBehavior !== 'validate' || state.realtimeValidation.isInvalid || !input || input.disabled) {\n      return;\n    }\n\n    // Create a native number input and use it to implement validation of min/max/step.\n    // This lets us get the native validation message provided by the browser instead of needing our own translations.\n    if (!numberInput && typeof document !== 'undefined') {\n      numberInput = document.createElement('input');\n      numberInput.type = 'number';\n    }\n\n    if (!numberInput) {\n      // For TypeScript.\n      return;\n    }\n    \n    numberInput.min = min != null && !isNaN(min) ? String(min) : '';\n    numberInput.max = max != null && !isNaN(max) ? String(max) : '';\n    numberInput.step = step != null && !isNaN(step) ? String(step) : '';\n    numberInput.value = value != null && !isNaN(value) ? String(value) : '';\n\n    // Merge validity with the visible text input (for other validations like required).\n    let valid = input.validity.valid && numberInput.validity.valid;\n    let validationMessage = input.validationMessage || numberInput.validationMessage;\n    let validity = {\n      isInvalid: !valid,\n      validationErrors: validationMessage ? [validationMessage] : [],\n      validationDetails: {\n        badInput: input.validity.badInput,\n        customError: input.validity.customError,\n        patternMismatch: input.validity.patternMismatch,\n        rangeOverflow: numberInput.validity.rangeOverflow,\n        rangeUnderflow: numberInput.validity.rangeUnderflow,\n        stepMismatch: numberInput.validity.stepMismatch,\n        tooLong: input.validity.tooLong,\n        tooShort: input.validity.tooShort,\n        typeMismatch: input.validity.typeMismatch,\n        valueMissing: input.validity.valueMissing,\n        valid\n      }\n    };\n\n    state.updateValidation(validity);\n\n    // Block form submission if validation behavior is native.\n    // This won't overwrite any user-defined validation message because we checked realtimeValidation above.\n    if (validationBehavior === 'native' && !numberInput.validity.valid) {\n      input.setCustomValidity(numberInput.validationMessage);\n    }\n  });\n}\n"],"names":[],"version":3,"file":"useNumberField.cjs.map"}