/* * Copyright 2020 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ import AlertMedium from '@spectrum-icons/ui/AlertMedium'; import CheckmarkMedium from '@spectrum-icons/ui/CheckmarkMedium'; import {classNames, createFocusableRef} from '@react-spectrum/utils'; import {Field} from '@react-spectrum/label'; // @ts-ignore import intlMessages from '../intl/*.json'; import {mergeProps, useId} from '@react-aria/utils'; import {PressEvents, RefObject, ValidationResult} from '@react-types/shared'; import React, {cloneElement, forwardRef, HTMLAttributes, InputHTMLAttributes, LabelHTMLAttributes, ReactElement, Ref, TextareaHTMLAttributes, useImperativeHandle, useRef} from 'react'; import {SpectrumTextFieldProps, TextFieldRef} from '@react-types/textfield'; import styles from '@adobe/spectrum-css-temp/components/textfield/vars.css'; import {useFocusRing} from '@react-aria/focus'; import {useHover} from '@react-aria/interactions'; import {useLocalizedStringFormatter} from '@react-aria/i18n'; interface TextFieldBaseProps extends Omit, PressEvents, Partial { wrapperChildren?: ReactElement | ReactElement[], inputClassName?: string, validationIconClassName?: string, multiLine?: boolean, labelProps?: LabelHTMLAttributes, inputProps: InputHTMLAttributes | TextareaHTMLAttributes, descriptionProps?: HTMLAttributes, errorMessageProps?: HTMLAttributes, inputRef?: RefObject, loadingIndicator?: ReactElement, isLoading?: boolean, disableFocusRing?: boolean } export const TextFieldBase = forwardRef(function TextFieldBase(props: TextFieldBaseProps, ref: Ref>) { let { validationState = props.isInvalid ? 'invalid' : null, icon, isQuiet = false, isDisabled, multiLine, autoFocus, inputClassName, wrapperChildren, labelProps, inputProps, descriptionProps, errorMessageProps, inputRef: userInputRef, isLoading, loadingIndicator, validationIconClassName, disableFocusRing } = props; let {hoverProps, isHovered} = useHover({isDisabled}); let domRef = useRef(null); let defaultInputRef = useRef(null); let inputRef = userInputRef || defaultInputRef; // Expose imperative interface for ref useImperativeHandle(ref, () => ({ ...createFocusableRef(domRef, inputRef), select() { if (inputRef.current) { inputRef.current.select(); } }, getInputElement() { return inputRef.current; } })); let ElementType: React.ElementType = multiLine ? 'textarea' : 'input'; let isInvalid = validationState === 'invalid' && !isDisabled; if (icon) { let UNSAFE_className = classNames( styles, icon.props && (icon.props as any).UNSAFE_className, 'spectrum-Textfield-icon' ); icon = cloneElement(icon, { UNSAFE_className, size: 'S' } as any); } let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-spectrum/textfield'); let validId = useId(); let validationIcon = isInvalid ? : ; let validation = cloneElement(validationIcon, { UNSAFE_className: classNames( styles, 'spectrum-Textfield-validationIcon', validationIconClassName ) }); // Add validation icon IDREF to aria-describedby when validationState is valid let inputPropsAriaDescribedBy = inputProps['aria-describedby']; if ( !isInvalid && validationState === 'valid' && !isLoading && !isDisabled && (!inputPropsAriaDescribedBy || !inputPropsAriaDescribedBy.includes(validId)) ) { inputProps['aria-describedby'] = [inputPropsAriaDescribedBy, validId].join(' ').trim(); } let {focusProps, isFocusVisible} = useFocusRing({ isTextInput: true, autoFocus }); let textField = (
{icon} {validationState && !isLoading && !isDisabled ? validation : null} {isLoading && loadingIndicator} {wrapperChildren}
); return ( {textField} ); });