{"mappings":"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","sources":["packages/react-aria/src/textfield/useFormattedTextField.ts"],"sourcesContent":["/*\n * Copyright 2021 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 {AriaTextFieldProps, TextFieldAria, useTextField} from './useTextField';\nimport {getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {InputEventHandler, useEffect, useRef} from 'react';\nimport {mergeProps} from '../utils/mergeProps';\nimport {RefObject} from '@react-types/shared';\nimport {useEffectEvent} from '../utils/useEffectEvent';\n\ninterface FormattedTextFieldState {\n  validate: (val: string) => boolean,\n  setInputValue: (val: string) => void\n}\n\n\nfunction supportsNativeBeforeInputEvent() {\n  return typeof window !== 'undefined' &&\n    window.InputEvent &&\n    typeof InputEvent.prototype.getTargetRanges === 'function';\n}\n\nexport function useFormattedTextField(props: AriaTextFieldProps, state: FormattedTextFieldState, inputRef: RefObject<HTMLInputElement | null>): TextFieldAria {\n  // All browsers implement the 'beforeinput' event natively except Firefox\n  // (currently behind a flag as of Firefox 84). React's polyfill does not\n  // run in all cases that the native event fires, e.g. when deleting text.\n  // Use the native event if available so that we can prevent invalid deletions.\n  // We do not attempt to polyfill this in Firefox since it would be very complicated,\n  // the benefit of doing so is fairly minor, and it's going to be natively supported soon.\n  let onBeforeInputFallback = useEffectEvent((e: InputEvent) => {\n    let input = inputRef.current;\n    if (!input) {\n      return;\n    }\n\n    // Compute the next value of the input if the event is allowed to proceed.\n    // See https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes for a full list of input types.\n    let nextValue: string | null = null;\n    switch (e.inputType) {\n      case 'historyUndo':\n      case 'historyRedo':\n        // Explicitly allow undo/redo. e.data is null in this case, but there's no need to validate,\n        // because presumably the input would have already been validated previously.\n        return;\n      case 'insertLineBreak':\n        // Explicitly allow \"insertLineBreak\" event, to allow onSubmit for \"enter\" key. e.data is null in this case.\n        return;\n      case 'deleteContent':\n      case 'deleteByCut':\n      case 'deleteByDrag':\n        nextValue = input.value.slice(0, input.selectionStart!) + input.value.slice(input.selectionEnd!);\n        break;\n      case 'deleteContentForward':\n        // This is potentially incorrect, since the browser may actually delete more than a single UTF-16\n        // character. In reality, a full Unicode grapheme cluster consisting of multiple UTF-16 characters\n        // or code points may be deleted. However, in our currently supported locales, there are no such cases.\n        // If we support additional locales in the future, this may need to change.\n        nextValue = input.selectionEnd === input.selectionStart\n          ? input.value.slice(0, input.selectionStart!) + input.value.slice(input.selectionEnd! + 1)\n          : input.value.slice(0, input.selectionStart!) + input.value.slice(input.selectionEnd!);\n        break;\n      case 'deleteContentBackward':\n        nextValue = input.selectionEnd === input.selectionStart\n          ? input.value.slice(0, input.selectionStart! - 1) + input.value.slice(input.selectionStart!)\n          : input.value.slice(0, input.selectionStart!) + input.value.slice(input.selectionEnd!);\n        break;\n      case 'deleteSoftLineBackward':\n      case 'deleteHardLineBackward':\n        nextValue = input.value.slice(input.selectionStart!);\n        break;\n      default:\n        if (e.data != null) {\n          nextValue =\n            input.value.slice(0, input.selectionStart!) +\n            e.data +\n            input.value.slice(input.selectionEnd!);\n        }\n        break;\n    }\n\n    // If we did not compute a value, or the new value is invalid, prevent the event\n    // so that the browser does not update the input text, move the selection, or add to\n    // the undo/redo stack.\n    if (nextValue == null || !state.validate(nextValue)) {\n      e.preventDefault();\n    }\n  });\n\n  useEffect(() => {\n    if (!supportsNativeBeforeInputEvent() || !inputRef.current) {\n      return;\n    }\n\n    let input = inputRef.current;\n    input.addEventListener('beforeinput', onBeforeInputFallback, false);\n    return () => {\n      input.removeEventListener('beforeinput', onBeforeInputFallback, false);\n    };\n  }, [inputRef]);\n\n  let onBeforeInput: InputEventHandler<HTMLInputElement> | null = !supportsNativeBeforeInputEvent()\n    ? e => {\n      let nextValue =\n        getEventTarget(e).value.slice(0, getEventTarget(e).selectionStart!) +\n        e.data +\n        getEventTarget(e).value.slice(getEventTarget(e).selectionEnd!);\n\n      if (!state.validate(nextValue)) {\n        e.preventDefault();\n      }\n    }\n    : null;\n\n  let {labelProps, inputProps: textFieldProps, descriptionProps, errorMessageProps, ...validation} = useTextField(props, inputRef);\n\n  let compositionStartState = useRef<{value: string, selectionStart: number | null, selectionEnd: number | null} | null>(null);\n  return {\n    inputProps: mergeProps(\n      textFieldProps,\n      {\n        onBeforeInput,\n        onCompositionStart() {\n          // Chrome does not implement Input Events Level 2, which specifies the insertFromComposition\n          // and deleteByComposition inputType values for the beforeinput event. These are meant to occur\n          // at the end of a composition (e.g. Pinyin IME, Android auto correct, etc.), and crucially, are\n          // cancelable. The insertCompositionText and deleteCompositionText input types are not cancelable,\n          // nor would we want to cancel them because the input from the user is incomplete at that point.\n          // In Safari, insertFromComposition/deleteFromComposition will fire, however, allowing us to cancel\n          // the final composition result if it is invalid. As a fallback for Chrome and Firefox, which either\n          // don't support Input Events Level 2, or beforeinput at all, we store the state of the input when\n          // the compositionstart event fires, and undo the changes in compositionend (below) if it is invalid.\n          // Unfortunately, this messes up the undo/redo stack, but until insertFromComposition/deleteByComposition\n          // are implemented, there is no other way to prevent composed input.\n          // See https://bugs.chromium.org/p/chromium/issues/detail?id=1022204\n          let {value, selectionStart, selectionEnd} = inputRef.current!;\n          compositionStartState.current = {value, selectionStart, selectionEnd};\n        },\n        onCompositionEnd() {\n          if (inputRef.current && !state.validate(inputRef.current.value)) {\n            // Restore the input value in the DOM immediately so we can synchronously update the selection position.\n            // But also update the value in React state as well so it is correct for future updates.\n            let {value, selectionStart, selectionEnd} = compositionStartState.current!;\n            inputRef.current.value = value;\n            inputRef.current.setSelectionRange(selectionStart, selectionEnd);\n            state.setInputValue(value);\n          }\n        }\n      }\n    ),\n    labelProps,\n    descriptionProps,\n    errorMessageProps,\n    ...validation\n  };\n}\n"],"names":[],"version":3,"file":"useFormattedTextField.mjs.map"}