diff --git a/src/components/input/inputContainer/inputContainer.test.tsx b/src/components/input/inputContainer/inputContainer.test.tsx index aead15619..da9022db6 100644 --- a/src/components/input/inputContainer/inputContainer.test.tsx +++ b/src/components/input/inputContainer/inputContainer.test.tsx @@ -43,6 +43,13 @@ describe(' component', () => { expect(screen.getByText(`[${inputLength}/${maxLength}]`)).toBeInTheDocument(); }); + it('adds a shake animation when the input length is equal to the max length property', () => { + const maxLength = 10; + const inputLength = 10; + render(createTestComponent({ maxLength, inputLength })); + expect(screen.getByText(`[${inputLength}/${maxLength}]`).className).toContain('shake'); + }); + it('renders the input alert when defined', () => { const alert = { message: 'input-alert-message', diff --git a/src/components/input/inputContainer/inputContainer.tsx b/src/components/input/inputContainer/inputContainer.tsx index 5d79b186c..285677279 100644 --- a/src/components/input/inputContainer/inputContainer.tsx +++ b/src/components/input/inputContainer/inputContainer.tsx @@ -53,6 +53,10 @@ export const InputContainer: React.FC = (props) => { variantToClassNames[processedVariant], ); + const counterClasses = classNames('text-sm font-normal leading-tight text-neutral-600', { + 'animate-shake': inputLength === maxLength, + }); + return (
{(label != null || helpText != null) && ( @@ -71,11 +75,7 @@ export const InputContainer: React.FC = (props) => { )}
{children}
{maxLength != null && ( -

+

[{inputLength}/{maxLength}]

)} diff --git a/src/components/input/useInputProps.test.ts b/src/components/input/useInputProps.test.ts index 4b2e8008b..5f1fec2f8 100644 --- a/src/components/input/useInputProps.test.ts +++ b/src/components/input/useInputProps.test.ts @@ -1,4 +1,5 @@ -import { renderHook } from '@testing-library/react'; +import { act, renderHook } from '@testing-library/react'; +import type { ChangeEvent } from 'react'; import { useInputProps } from './useInputProps'; describe('useInputProps hook', () => { @@ -8,14 +9,15 @@ describe('useInputProps hook', () => { variant: 'warning' as const, helpText: 'help-text', isOptional: true, - infoText: 'info-text', alert: { message: 'alert-message', variant: 'critical' as const }, className: 'container-classname', + maxLength: 10, }; const inputProps = { placeholder: 'input-placeholder', value: 'input-value', + maxLength: 10, }; const { result } = renderHook(() => useInputProps({ ...containerProps, ...inputProps })); @@ -36,7 +38,6 @@ describe('useInputProps hook', () => { const props = { isDisabled }; const { result } = renderHook(() => useInputProps(props)); expect(result.current.inputProps.disabled).toBeTruthy(); - expect(result.current.inputProps.className).toContain('cursor-not-allowed'); }); it('sets a random id to the input property when the id prop is not set', () => { @@ -44,4 +45,21 @@ describe('useInputProps hook', () => { expect(result.current.containerProps.id).toBeDefined(); expect(result.current.inputProps.id).toBeDefined(); }); + + it('tracks the current input length for the container props', () => { + const newValue = 'newValue'; + const changeEvent = { target: { value: newValue } } as ChangeEvent; + const { result } = renderHook(() => useInputProps({})); + expect(result.current.containerProps.inputLength).toEqual(0); + act(() => result.current.inputProps.onChange?.(changeEvent)); + expect(result.current.containerProps.inputLength).toEqual(newValue.length); + }); + + it('calls the onChange property on input value change', () => { + const onChange = jest.fn(); + const { result } = renderHook(() => useInputProps({ onChange })); + const changeEvent = { target: { value: '' } } as ChangeEvent; + act(() => result.current.inputProps.onChange?.(changeEvent)); + expect(onChange).toHaveBeenCalledWith(changeEvent); + }); });