/* * The MIT License (MIT) * * Copyright (c) 2015 - present Instructure, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import { InputHTMLAttributes } from 'react' import type { FormFieldProps, FormMessage } from '@instructure/ui-form-field/latest' import type { OtherHTMLAttributes } from '@instructure/shared-types' import type { WithStyleProps, ComponentStyle, Spacing } from '@instructure/emotion' import type { NewComponentTypes } from '@instructure/ui-themes' import type { InteractionType, WithDeterministicIdProps } from '@instructure/ui-react-utils' import { Renderable } from '@instructure/shared-types' type TextInputOwnProps = { /** * The form field label. */ renderLabel?: Renderable /** * Determines the underlying native HTML `` element's `type`. * * For more see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/url */ type?: 'text' | 'email' | 'url' | 'tel' | 'search' | 'password' /** * The id of the text input. One is generated if not supplied. */ id?: string /** * id for the label element. If empty, it's auto generated. * useful if you use `aria-labelledby={labelId}` to label something with the * label element. */ labelId?: string /** * the selected value (must be accompanied by an `onChange` prop) */ value?: string // TODO: controllable(PropTypes.string) /** * value to set on initial render */ defaultValue?: string /** * Specifies if interaction with the input is enabled, disabled, or readonly. * When "disabled", the input changes visibly to indicate that it cannot * receive user interactions. When "readonly" the input still cannot receive * user interactions but it keeps the same styles as if it were enabled. * Note: placeholder is only displayed when interaction is enabled. You can force it with forcePlaceholder prop * Note: error and success messages are hidden when interaction is not enabled. You can force them for readonly with the forceMessages prop */ interaction?: InteractionType /** * Array of objects with shape: `{ * text: React.ReactNode, * type: One of ['error', 'hint', 'success', 'screenreader-only'] * }` */ messages?: FormMessage[] /** * The size of the text input. */ size?: 'small' | 'medium' | 'large' /** * The text alignment of the input. */ textAlign?: 'start' | 'center' /** * The width of the input. */ width?: string /** * The width of the input (integer value 0 or higher), if a width is not explicitly * provided via the `width` prop. * * Only applicable if `display="inline-block"`. * * For more see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/size */ htmlSize?: number /** * The display of the root element. */ display?: 'inline-block' | 'block' /** * Prevents the default behavior of wrapping the input and rendered content * when available space is exceeded. */ shouldNotWrap?: boolean /** * Whether to apply a gap between the elements rendered via `renderBeforeInput` * (a CSS flex container), e.g. tags. * - `'default'`: no gap is applied between the elements. * - `'even'`: wrapped rows are evenly spaced with a vertical and horizontal gap. */ renderBeforeInputElementGap?: 'default' | 'even' /** * Html placeholder text to display when the input has no value. This should be hint text, not a label replacement. */ placeholder?: string /** * Whether or not the text input is required. */ isRequired?: boolean /** * Always displays placeholder when textInput is empty, regardless of interaction type */ forcePlaceholder?: boolean /** * Always displays `messages`, even when the interaction is `readonly`. */ forceMessages?: boolean /** * provides a reference to the underlying html root element */ elementRef?: (element: Element | null) => void /** * a function that provides a reference to the actual input element */ inputRef?: (inputElement: HTMLInputElement | null) => void /** * a function that provides a reference a parent of the input element */ inputContainerRef?: (element: HTMLSpanElement | null) => void /** * Content to display before the input text, such as an icon */ renderBeforeInput?: Renderable /** * Content to display after the input text, such as an icon */ renderAfterInput?: Renderable /** * Callback executed when the input fires a change event. * @param {Object} event - the event object * @param {string} value - the string value of the input */ onChange?: (event: React.ChangeEvent, value: string) => void /** * Callback fired when input loses focus. */ onBlur?: (event: React.FocusEvent) => void /** * Callback fired when input receives focus. */ onFocus?: (event: React.FocusEvent) => void /** * Valid values are `0`, `none`, `auto`, and Spacing token values, * see https://instructure.design/layout-spacing. Apply these values via * familiar CSS-like shorthand. For example, `margin="general.spaceMd auto"`. */ margin?: Spacing } type PropKeys = keyof TextInputOwnProps type AllowedPropKeys = Readonly> type TextInputProps = TextInputOwnProps & WithStyleProps, TextInputStyle> & OtherHTMLAttributes< TextInputOwnProps, InputHTMLAttributes > & // The component will handle pass this prop to FormField, but it shouldn't be // listed as a prop Pick & WithDeterministicIdProps type TextInputStyle = ComponentStyle< | 'textInput' | 'facade' | 'layout' | 'beforeElement' | 'afterElement' | 'inputLayout' > const allowedProps: AllowedPropKeys = [ 'renderLabel', 'type', 'id', 'labelId', 'value', 'defaultValue', 'interaction', 'messages', 'size', 'textAlign', 'width', 'htmlSize', 'display', 'shouldNotWrap', 'renderBeforeInputElementGap', 'placeholder', 'isRequired', 'forcePlaceholder', 'forceMessages', 'elementRef', 'inputRef', 'inputContainerRef', 'renderBeforeInput', 'renderAfterInput', 'onChange', 'onBlur', 'onFocus', 'margin' ] type TextInputStyleProps = { interaction: InteractionType success: boolean invalid: boolean beforeElementExists: boolean } export type { TextInputProps, TextInputStyleProps, TextInputStyle } export { allowedProps }