package.src.components.TextInput.TextInput.tsx Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of react-core Show documentation
Show all versions of react-core Show documentation
This library provides a set of common React components for use with the PatternFly reference implementation.
The newest version!
import * as React from 'react';
import styles from '@patternfly/react-styles/css/components/FormControl/form-control';
import { css } from '@patternfly/react-styles';
import { ValidatedOptions } from '../../helpers/constants';
import { trimLeft } from '../../helpers/util';
import { getDefaultOUIAId, getOUIAProps, OUIAProps } from '../../helpers';
import { getResizeObserver } from '../../helpers/resizeObserver';
import { FormControlIcon } from '../FormControl/FormControlIcon';
export enum TextInputTypes {
text = 'text',
date = 'date',
datetimeLocal = 'datetime-local',
email = 'email',
month = 'month',
number = 'number',
password = 'password',
search = 'search',
tel = 'tel',
time = 'time',
url = 'url'
}
export enum TextInputReadOnlyVariant {
default = 'default',
plain = 'plain'
}
export interface TextInputExpandedObj {
/** Flag to apply expanded styling. */
isExpanded: boolean;
/** Id of the element that the text input is controlling expansion of. */
ariaControls: string;
}
export interface TextInputProps
extends Omit, 'onChange' | 'onFocus' | 'onBlur' | 'disabled' | 'ref'>,
OUIAProps {
/** Additional classes added to the text input. */
className?: string;
/** Flag to show if the text input is disabled. */
isDisabled?: boolean;
/** @deprecated Flag to apply expanded styling. expandedProps should now be used instead. */
isExpanded?: boolean;
/** Prop to apply expanded styling to the text input and link it to the element it is controlling. This should be used when the input controls a menu and that menu is expandable. */
expandedProps?: TextInputExpandedObj;
/** Sets the input as readonly and determines the readonly styling. */
readOnlyVariant?: 'plain' | 'default';
/** Flag indicating whether the input is required */
isRequired?: boolean;
/** Value to indicate if the text input is modified to show that validation state.
* If set to success, text input will be modified to indicate valid state.
* If set to error, text input will be modified to indicate error state.
*/
validated?: 'success' | 'warning' | 'error' | 'default';
/** A callback for when the text input value changes. */
onChange?: (event: React.FormEvent, value: string) => void;
/** Type that the text input accepts. */
type?:
| 'text'
| 'date'
| 'datetime-local'
| 'email'
| 'month'
| 'number'
| 'password'
| 'search'
| 'tel'
| 'time'
| 'url';
/** Value of the text input. */
value?: string | number;
/** Placeholder of the text input when there is no value */
placeholder?: string;
/** Aria-label. The text input requires an associated id or aria-label. */
'aria-label'?: string;
/** @hide A reference object to attach to the text input box. */
innerRef?: React.RefObject;
/** @deprecated Use isStartTruncated instead. Trim text at start */
isLeftTruncated?: boolean;
/** Trim text at start */
isStartTruncated?: boolean;
/** Callback function when text input is focused */
onFocus?: (event?: any) => void;
/** Callback function when text input is blurred (focus leaves) */
onBlur?: (event?: any) => void;
/** Custom icon to render. If the validated prop is also passed, this will render an icon in addition to a validated icon. */
customIcon?: React.ReactNode;
/** Value to overwrite the randomly generated data-ouia-component-id.*/
ouiaId?: number | string;
/** Set the value of data-ouia-safe. Only set to true when the component is in a static state, i.e. no animations are occurring. At all other times, this value must be false. */
ouiaSafe?: boolean;
}
interface TextInputState {
ouiaStateId: string;
}
// eslint-disable-next-line patternfly-react/no-anonymous-functions
export class TextInputBase extends React.Component {
static displayName = 'TextInputBase';
static defaultProps: TextInputProps = {
'aria-label': null,
isRequired: false,
validated: 'default' as 'success' | 'warning' | 'error' | 'default',
isDisabled: false,
isExpanded: false,
type: TextInputTypes.text,
isLeftTruncated: false,
isStartTruncated: false,
onChange: (): any => undefined,
ouiaSafe: true
};
inputRef = React.createRef();
observer: any = () => {};
constructor(props: TextInputProps) {
super(props);
if (!props.id && !props['aria-label'] && !props['aria-labelledby']) {
// eslint-disable-next-line no-console
console.error('Text input:', 'Text input requires either an id or aria-label to be specified');
}
this.state = {
ouiaStateId: getDefaultOUIAId(TextInputBase.displayName)
};
}
handleChange = (event: React.FormEvent) => {
if (this.props.onChange) {
this.props.onChange(event, event.currentTarget.value);
}
};
componentDidMount() {
if (this.props.isLeftTruncated || this.props.isStartTruncated) {
const inputRef = this.props.innerRef || this.inputRef;
this.observer = getResizeObserver(inputRef.current, this.handleResize, true);
this.handleResize();
}
}
componentWillUnmount() {
if (this.props.isLeftTruncated || this.props.isStartTruncated) {
this.observer();
}
}
handleResize = () => {
const inputRef = this.props.innerRef || this.inputRef;
if (inputRef && inputRef.current) {
trimLeft(inputRef.current, String(this.props.value));
}
};
restoreText = () => {
const inputRef = this.props.innerRef || this.inputRef;
// restore the value
(inputRef.current as HTMLInputElement).value = String(this.props.value);
// make sure we still see the rightmost value to preserve cursor click position
inputRef.current.scrollLeft = inputRef.current.scrollWidth;
};
onFocus = (event?: any) => {
const { isLeftTruncated, isStartTruncated, onFocus } = this.props;
if (isLeftTruncated || isStartTruncated) {
this.restoreText();
}
onFocus && onFocus(event);
};
onBlur = (event?: any) => {
const { isLeftTruncated, isStartTruncated, onBlur } = this.props;
if (isLeftTruncated || isStartTruncated) {
this.handleResize();
}
onBlur && onBlur(event);
};
render() {
const {
innerRef,
className,
type,
value,
placeholder,
validated,
/* eslint-disable @typescript-eslint/no-unused-vars */
onChange,
onFocus,
onBlur,
isLeftTruncated,
isStartTruncated,
isExpanded,
expandedProps,
readOnly,
readOnlyVariant,
isRequired,
isDisabled,
customIcon,
ouiaId,
ouiaSafe,
...props
} = this.props;
const hasStatusIcon = ['success', 'error', 'warning'].includes(validated);
const ariaExpandedProps = expandedProps
? { 'aria-expanded': expandedProps?.isExpanded, 'aria-controls': expandedProps?.ariaControls, role: 'combobox' }
: {};
return (
{(customIcon || hasStatusIcon) && (
{customIcon && }
{hasStatusIcon && }
)}
);
}
private sanitizeInputValue = (value: string | number) =>
typeof value === 'string' ? value.replace(/\n/g, ' ') : value;
}
export const TextInput = React.forwardRef((props: TextInputProps, ref: React.Ref) => (
} />
));
TextInput.displayName = 'TextInput';