import { Component } from 'react'; import TextField from '@mui/material/TextField'; function normalizeSx(s) { if (!s || typeof s !== 'object' || Array.isArray(s)) return s; const bg = s.bgcolor ?? s.backgroundColor; if (bg && bg !== 'transparent') { const { bgcolor: _bg, backgroundColor: _bgc, ...rest } = s; return { ...rest, bgcolor: 'transparent', '& .MuiInputBase-root': { bgcolor: bg, ...(typeof rest['& .MuiInputBase-root'] === 'object' ? rest['& .MuiInputBase-root'] : {}), }, }; } return s; } function resolveSx(s) { if (!s) return undefined; if (Array.isArray(s)) return s.map(resolveSx); return normalizeSx(s); } /** * TextInput: * Reusable Class Component wrapping MUI TextField with the harmonized * style of EANs (small outlined, shrink label by default, transparent root) * and complete suppression of browser autocomplete/autofill popups. */ export default class TextInput extends Component { state = { // Starting as readOnly prevents Chrome/Safari/Firefox from attaching autofill popup listeners readOnly: true, }; handleFocus = (e) => { if (this.state.readOnly && !this.props.readOnly && !this.props.slotProps?.htmlInput?.readOnly) { this.setState({ readOnly: false }); } if (this.props.onFocus) { this.props.onFocus(e); } }; handleMouseDown = (e) => { if (this.state.readOnly && !this.props.readOnly && !this.props.slotProps?.htmlInput?.readOnly) { this.setState({ readOnly: false }); } if (this.props.onMouseDown) { this.props.onMouseDown(e); } }; render() { const { slotProps, inputProps, InputProps, InputLabelProps, inputRef, label, size = 'small', onFocus, onMouseDown, readOnly: propReadOnly, sx, ...rest } = this.props; const isSelect = Boolean(rest.select); const isAutocomplete = Boolean(inputProps?.['aria-autocomplete'] || rest['aria-autocomplete']); const effectiveReadOnly = (isSelect || isAutocomplete) ? (propReadOnly ?? slotProps?.htmlInput?.readOnly ?? inputProps?.readOnly ?? false) : (propReadOnly ?? slotProps?.htmlInput?.readOnly ?? inputProps?.readOnly ?? this.state.readOnly); const { inputProps: nestedFromInputProps, ...cleanInputProps } = InputProps || {}; const { inputProps: nestedFromSlotInput, ...cleanSlotInput } = slotProps?.input || {}; const rawResolvedInputProps = (InputProps || slotProps?.input) ? { ...cleanSlotInput, ...cleanInputProps, startAdornment: (slotProps?.input?.startAdornment && InputProps?.startAdornment) ? <>{slotProps.input.startAdornment}{InputProps.startAdornment} : (InputProps?.startAdornment ?? slotProps?.input?.startAdornment), endAdornment: (slotProps?.input?.endAdornment && InputProps?.endAdornment) ? <>{InputProps.endAdornment}{slotProps.input.endAdornment} : (InputProps?.endAdornment ?? slotProps?.input?.endAdornment), } : undefined; const htmlInput = isSelect ? { readOnly: effectiveReadOnly, ...slotProps?.htmlInput, ...nestedFromSlotInput, ...nestedFromInputProps, ...inputProps, } : { autoComplete: 'one-time-code', autoCorrect: 'off', autoCapitalize: 'off', spellCheck: false, 'aria-autocomplete': 'none', 'data-lpignore': 'true', 'data-1p-ignore': 'true', 'data-bwignore': 'true', 'data-form-type': 'other', readOnly: effectiveReadOnly, ...slotProps?.htmlInput, ...nestedFromSlotInput, ...nestedFromInputProps, ...inputProps, }; const resolvedInputProps = rawResolvedInputProps; const { input: _unusedInput, ...restSlotProps } = (slotProps || {}); const hasLabelProps = Boolean(label || InputLabelProps || slotProps?.inputLabel); const mergedSlotProps = { ...restSlotProps, ...(resolvedInputProps ? { input: resolvedInputProps } : {}), ...(hasLabelProps ? { inputLabel: { ...(label ? { shrink: true } : {}), ...InputLabelProps, ...slotProps?.inputLabel, }, } : {}), htmlInput, }; return ( ); } } export { TextInput };