import React, { forwardRef } from 'react'; import styled from 'styled-components'; import isChromatic from 'chromatic/isChromatic'; import cuid from 'cuid'; import { Spacer } from '../../foundations/Layout'; import Email from '../../assets/icons/Email'; import { filterGlobalProps, pxToRem } from '@lendi-ui/commons/utils'; import { InputBaseComponent } from './InputBase'; import { useClearAction, ClearActionButton } from './components/ClearAction'; import { ErrorText } from './components/ErrorText'; import { HelpText } from './components/HelpText'; import { FieldLabel } from './components/FieldLabel'; import type { InputFieldBaseProps, InputProps } from './InputBase'; import { useTheme } from '../../foundations/Theme'; interface TextFieldProps extends InputFieldBaseProps { variant?: 'text' | 'email'; /** * If the form field is asking for information that fits one of the options in the spec, use pass it here. This is _required when applicable_ for accessibility purposes. https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill-field */ autoComplete?: 'given-name' | 'additional-name' | 'family-name' | 'name'; } export type TextFieldComponentProps = InputProps; const Input = styled(InputBaseComponent as any)<{ hasRightItem?: boolean; hasLeftItem?: boolean; }>` padding-left: ${(props) => (props.hasLeftItem ? pxToRem(46) : pxToRem(16))}; padding-right: ${(props) => (props.hasRightItem ? pxToRem(46) : pxToRem(16))}; `; const Wrapper = styled.div` position: relative; width: 100%; `; const LeftIcon = styled.span` position: absolute; top: 12px; left: 12px; `; function TextFieldComponent( { inputId, name, variant = 'text', value, defaultValue, onChange, validationState, label, ariaLabel, ariaLabelledBy, labelSuffix, inlineAction, autoComplete, placeholder, helpText, errorText, isDisabled, isRequired, maxCharCount, minCharCount, width = '100%', minWidth, maxWidth, ...props }: TextFieldComponentProps, ref: React.Ref ) { const globalProps = filterGlobalProps(props); const { isCleared, handleChange, clearValue } = useClearAction(onChange, ref, value); const inputElId = isChromatic() ? '1' : inputId ?? cuid(); const helpTextId = isChromatic() ? '2' : cuid(); const errorTextId = isChromatic() ? '3' : cuid(); const hasError = errorText && validationState === 'invalid'; const theme = useTheme(); const ariaDescribedBy = []; if (helpText) { ariaDescribedBy.push(helpTextId); } if (hasError) { ariaDescribedBy.push(errorTextId); } return ( {label && } {variant === 'email' && ( )} 0 ? ariaDescribedBy.join(' ') : undefined} autoComplete={variant === 'email' ? 'email' : autoComplete} required={isRequired} disabled={isDisabled} maxLength={maxCharCount} minLength={minCharCount} hasLeftItem={variant === 'email'} hasRightItem={!!inlineAction} /> {inlineAction === 'clear' && } {helpText && } {hasError && errorText && } ); } export const TextField = forwardRef(TextFieldComponent);