From 47077346bdd62ba0ce084c281dce6b07b2b7ac50 Mon Sep 17 00:00:00 2001 From: thyhjwb6 Date: Fri, 12 Jun 2020 09:22:18 +0100 Subject: [PATCH] feat(NumberInput): Add ability to append unit --- .../src/components/NumberInput/Input.tsx | 2 +- .../NumberInput/NumberInput.stories.tsx | 10 +++ .../NumberInput/NumberInput.test.tsx | 66 +++++++++++++++++++ .../components/NumberInput/NumberInput.tsx | 35 ++++++++-- .../src/components/NumberInput/constants.ts | 7 +- .../src/components/NumberInput/index.ts | 1 + 6 files changed, 115 insertions(+), 6 deletions(-) diff --git a/packages/react-component-library/src/components/NumberInput/Input.tsx b/packages/react-component-library/src/components/NumberInput/Input.tsx index 5cfd88f730..0cd91403b6 100644 --- a/packages/react-component-library/src/components/NumberInput/Input.tsx +++ b/packages/react-component-library/src/components/NumberInput/Input.tsx @@ -11,7 +11,7 @@ interface InputProps { onInputBlur: (event: React.FormEvent) => void onInputFocus: () => void placeholder?: string - value?: number + value?: number | string } export const Input: React.FC = ({ diff --git a/packages/react-component-library/src/components/NumberInput/NumberInput.stories.tsx b/packages/react-component-library/src/components/NumberInput/NumberInput.stories.tsx index 7c3232a395..e98a6ff3fa 100644 --- a/packages/react-component-library/src/components/NumberInput/NumberInput.stories.tsx +++ b/packages/react-component-library/src/components/NumberInput/NumberInput.stories.tsx @@ -7,6 +7,7 @@ import { IconBrightnessHigh } from '@royalnavy/icon-library' import { Button } from '../Button' import { NumberInput } from './NumberInput' import { withFormik } from '../../enhancers/withFormik' +import { UNIT_POSITION } from './constants' const stories = storiesOf('Number Input', module) const examples = storiesOf('Number Input/Examples', module) @@ -77,6 +78,15 @@ examples.add('Value', () => ( )) +examples.add('Unit', () => ( + +)) + examples.add('Formik', () => { const NumberInputForm = () => { interface Data { diff --git a/packages/react-component-library/src/components/NumberInput/NumberInput.test.tsx b/packages/react-component-library/src/components/NumberInput/NumberInput.test.tsx index 3db4160841..2f362c32f7 100644 --- a/packages/react-component-library/src/components/NumberInput/NumberInput.test.tsx +++ b/packages/react-component-library/src/components/NumberInput/NumberInput.test.tsx @@ -417,4 +417,70 @@ describe('NumberInput', () => { }) }) }) + + describe('when there is a unit', () => { + beforeEach(() => { + wrapper = render( + + ) + }) + + it('should set the value', () => { + const input = wrapper.getByTestId( + 'number-input-input' + ) as HTMLInputElement + expect(input.value).toEqual('1000 m') + }) + + describe('and the increase button is clicked', () => { + beforeEach(() => { + wrapper.getByTestId('number-input-increase').click() + }) + + it('should increase the value by 1', () => { + const input = wrapper.getByTestId( + 'number-input-input' + ) as HTMLInputElement + expect(input.value).toEqual('1001 m') + }) + + it('should call the onChange callback', () => { + expect(onChangeSpy).toHaveBeenCalledTimes(1) + expect(onChangeSpy).toHaveBeenCalledWith({ + target: { + name: 'number-input', + value: 1001, + }, + }) + }) + + describe('and the decrease button is clicked', () => { + beforeEach(() => { + wrapper.getByTestId('number-input-decrease').click() + }) + + it('should decrease the value by 1', () => { + const input = wrapper.getByTestId( + 'number-input-input' + ) as HTMLInputElement + expect(input.value).toEqual('1000 m') + }) + + it('should call the onChange callback', () => { + expect(onChangeSpy).toHaveBeenCalledTimes(2) + expect(onChangeSpy).toHaveBeenCalledWith({ + target: { + name: 'number-input', + value: 1000, + }, + }) + }) + }) + }) + }) }) diff --git a/packages/react-component-library/src/components/NumberInput/NumberInput.tsx b/packages/react-component-library/src/components/NumberInput/NumberInput.tsx index 58232d508c..fd35fc1262 100644 --- a/packages/react-component-library/src/components/NumberInput/NumberInput.tsx +++ b/packages/react-component-library/src/components/NumberInput/NumberInput.tsx @@ -5,11 +5,14 @@ import isNil from 'lodash/isNil' import { v4 as uuidv4 } from 'uuid' import { EndAdornment } from './EndAdornment' +import { Footnote } from './Footnote' import { Input } from './Input' import { StartAdornment } from './StartAdornment' import { useFocus } from './useFocus' import { useValue } from './useValue' -import { Footnote } from './Footnote' +import { UNIT_POSITION } from './constants' + +type UnitPosition = typeof UNIT_POSITION.AFTER export interface NumberInputProps { autoFocus?: boolean @@ -27,9 +30,31 @@ export interface NumberInputProps { placeholder?: string startAdornment?: React.ReactNode | string step?: number + unit?: string + unitPosition?: UnitPosition value?: number } +function formatValue( + displayValue: number, + unit: string, + unitPosition: UnitPosition +) { + if (isNil(displayValue)) { + return null + } + + if (unit) { + return `${displayValue} ${unit}` + } + + return displayValue +} + +function getNewValue(event: React.FormEvent, unit: string) { + return parseInt(event.currentTarget.value, 10) +} + export const NumberInput: React.FC = ({ className, footnote, @@ -45,6 +70,8 @@ export const NumberInput: React.FC = ({ placeholder = '', startAdornment, step = 1, + unit, + unitPosition = UNIT_POSITION.AFTER, value, ...rest }) => { @@ -62,14 +89,14 @@ export const NumberInput: React.FC = ({ function onInputBlurSetCommittedValue(event: FormEvent) { setNextValue(null) - const newValue = parseInt(event.currentTarget.value, 10) + const newValue = getNewValue(event, unit) setCommittedValueIfWithinRange(max, min, name, onChange)(event, newValue) onInputBlur(event) } function onInputChange(event: React.ChangeEvent) { - const newValue = parseInt(event.currentTarget.value, 10) + const newValue = getNewValue(event, unit) if (isFinite(newValue)) { setNextValue(newValue) } @@ -90,7 +117,7 @@ export const NumberInput: React.FC = ({ onInputBlur={onInputBlurSetCommittedValue} onInputFocus={onInputFocus} placeholder={placeholder} - value={displayValue} + value={formatValue(displayValue, unit, unitPosition)} {...rest} /> diff --git a/packages/react-component-library/src/components/NumberInput/constants.ts b/packages/react-component-library/src/components/NumberInput/constants.ts index e79d135f2b..72b0d727cd 100644 --- a/packages/react-component-library/src/components/NumberInput/constants.ts +++ b/packages/react-component-library/src/components/NumberInput/constants.ts @@ -3,4 +3,9 @@ const END_ADORNMENT_TYPE = { INCREASE: 'increase', } as const -export { END_ADORNMENT_TYPE } +const UNIT_POSITION = { + AFTER: 'after', + BEFORE: 'before', +} as const + +export { END_ADORNMENT_TYPE, UNIT_POSITION } diff --git a/packages/react-component-library/src/components/NumberInput/index.ts b/packages/react-component-library/src/components/NumberInput/index.ts index 89e782f10f..1cf37b6d52 100644 --- a/packages/react-component-library/src/components/NumberInput/index.ts +++ b/packages/react-component-library/src/components/NumberInput/index.ts @@ -1 +1,2 @@ +export * from './constants' export * from './NumberInput'