import React, { forwardRef } from 'react'; import styled from 'styled-components'; import cuid from 'cuid'; import isChromatic from 'chromatic/isChromatic'; import { Spacer } from '../../foundations/Layout'; import { filterGlobalProps, pxToRem } from '@lendi-ui/commons/utils'; import cleanNumericValue from './utils/cleanNumericValue'; // TODO: Refactor `ErrorText` `FieldLabel` `HelpText` import { ClearActionButton, ErrorText, FieldLabel, HelpText, InputBaseComponent, InputFieldBaseProps, InputProps, useClearAction, } from '../TextField'; interface NumericFieldProps extends InputFieldBaseProps { onValueChange?: (value?: number, name?: string) => void; } export type NumericFieldComponentProps = InputProps; const Input = styled(InputBaseComponent as any)<{ variant?: 'dollar'; hasRightItem?: boolean }>` padding-left: ${({ variant }) => (variant && variant === 'dollar' ? pxToRem(46) : pxToRem(16))}; padding-right: ${({ hasRightItem }) => (hasRightItem ? pxToRem(46) : pxToRem(16))}; `; const Wrapper = styled.div` position: relative; width: 100%; `; function NumericFieldComponent( { inputId, name, helpText, errorText, validationState, placeholder, ariaLabel, ariaLabelledBy, label, labelSuffix, inlineAction, isRequired, isDisabled, value, defaultValue, onChange, onValueChange, width = '100%', minWidth, maxWidth, maxCharCount, minCharCount, ...props }: NumericFieldComponentProps, ref: React.Ref ) { const globalProps = filterGlobalProps(props); const inputElId = isChromatic() ? '1' : inputId ?? cuid(); const helpTextId = isChromatic() ? '2' : cuid(); const errorTextId = isChromatic() ? '3' : cuid(); const hasError = errorText && validationState === 'invalid'; const handleOnChange = (event: React.ChangeEvent) => { const valueOnly = cleanNumericValue({ value: event.target.value }); event.target.value = valueOnly; onChange?.(event); if (valueOnly === '') { onValueChange?.(undefined, name); return; } onValueChange?.(Number(valueOnly), name); }; const { isCleared, handleChange, clearValue } = useClearAction(handleOnChange, ref, value?.toString()); const ariaDescribedBy = []; if (helpText) { ariaDescribedBy.push(helpTextId); } if (hasError) { ariaDescribedBy.push(errorTextId); } return ( {label && } 0 ? ariaDescribedBy.join(' ') : undefined} required={isRequired} disabled={isDisabled} maxLength={maxCharCount} minLength={minCharCount} value={value && isCleared ? '' : value} defaultValue={defaultValue} onChange={handleChange} ref={ref} hasRightItem={!!inlineAction} inputMode="numeric" /> {inlineAction === 'clear' && } {helpText && } {hasError && errorText && } ); } export const NumericField = forwardRef(NumericFieldComponent);