import { Box, InputAdornment, InputProps, TextField as MuiTextField, TextFieldProps, TextFieldSlotsAndSlotProps, Theme, Tooltip, Typography } from '@mui/material'; import { equals, isNil } from 'ramda'; import { forwardRef, useCallback } from 'react'; import { makeStyles } from 'tss-react/mui'; import { getNormalizedId } from '../../utils'; import useAutoSize from './useAutoSize'; const useStyles = makeStyles()((theme: Theme) => ({ autoSizeCompact: { paddingRight: theme.spacing(1), paddingTop: theme.spacing(0.6) }, compactLabel: { top: '-10px' }, compactLabelShrink: { top: '0px' }, hiddenText: { display: 'table', lineHeight: 0, transform: 'scaleY(0)' }, input: { fontSize: theme.typography.body1.fontSize }, inputBase: { display: 'inline-flex', justifyItems: 'start', paddingRight: theme.spacing(1) }, noLabelInput: { padding: theme.spacing(1) }, textField: { transition: theme.transitions.create(['width'], { duration: theme.transitions.duration.shortest }) }, transparent: { backgroundColor: 'transparent' } })); interface OptionalLabelInputAdornmentProps { children: React.ReactNode; label?: React.ReactNode; position: 'end' | 'start'; } const OptionalLabelInputAdornment = ({ label, position, children }: OptionalLabelInputAdornmentProps): JSX.Element => { const noMarginWhenNoLabel = !label && { style: { marginTop: 0 } }; return ( {children} ); }; type SizeVariant = 'large' | 'medium' | 'small' | 'compact'; export type TextProps = { EndAdornment?: React.FC | React.ReactNode; StartAdornment?: React.FC; ariaLabel?: string; autoSize?: boolean; autoSizeCustomPadding?: number; autoSizeDefaultWidth?: number; className?: string; containerClassName?: string; dataTestId?: string; debounced?: boolean; displayErrorInTooltip?: boolean; error?: string; externalValueForAutoSize?: string; open?: boolean; required?: boolean; size?: SizeVariant; transparent?: boolean; value?: string; textFieldSlotsAndSlotProps?: TextFieldSlotsAndSlotProps; forceUncontrolled?: boolean; } & Omit; const TextField = forwardRef( ( { StartAdornment, EndAdornment, label, error, ariaLabel, dataTestId, transparent = false, size, displayErrorInTooltip = false, className, autoSize = false, debounced = false, autoSizeDefaultWidth = 0, externalValueForAutoSize, autoSizeCustomPadding, defaultValue, required = false, containerClassName, type, textFieldSlotsAndSlotProps, forceUncontrolled, helperText, ...rest }: TextProps, ref: React.ForwardedRef ): JSX.Element => { const { classes, cx } = useStyles(); const { inputRef, width, changeInputValue, innerValue } = useAutoSize({ autoSize, autoSizeCustomPadding: equals(type, 'number') ? Math.max(6, autoSizeCustomPadding || 0) : autoSizeCustomPadding, autoSizeDefaultWidth, value: externalValueForAutoSize || rest.value }); const tooltipTitle = displayErrorInTooltip && !isNil(error) ? error : ''; const getValueProps = useCallback((): object => { if (debounced || forceUncontrolled) { return {}; } if (defaultValue) { return { defaultValue }; } return { value: innerValue }; }, [innerValue, debounced, defaultValue, forceUncontrolled]); return ( {EndAdornment ? ( typeof EndAdornment === 'function' ? ( ) : ( EndAdornment ) ) : ( ( textFieldSlotsAndSlotProps?.slotProps?.input as | Record | undefined )?.endAdornment )} ), startAdornment: StartAdornment && ( ), ...textFieldSlotsAndSlotProps?.slotProps?.input }, inputLabel: { classes: { root: cx(equals(size, 'compact') && classes.compactLabel), shrink: cx( equals(size, 'compact') && classes.compactLabelShrink ) } } }} sx={{ width: autoSize ? width : undefined, ...rest?.sx }} type={type} {...rest} /> {autoSize && ( {rest.value || externalValueForAutoSize || innerValue} )} ); } ); export default TextField;