From 2f4e165d1b2ab355707c310e23f42de5e8a5cadd Mon Sep 17 00:00:00 2001 From: Shaneeza Date: Thu, 2 Dec 2021 16:02:54 -0500 Subject: [PATCH 01/14] update text input to include size variants --- packages/text-input/README.md | 1 + packages/text-input/src/TextInput.spec.tsx | 17 +++++- packages/text-input/src/TextInput.story.tsx | 1 + packages/text-input/src/TextInput.tsx | 61 ++++++++++++++++++++- 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/text-input/README.md b/packages/text-input/README.md index 9d4c3b463d..f3832b42b6 100644 --- a/packages/text-input/README.md +++ b/packages/text-input/README.md @@ -83,6 +83,7 @@ return ( | `className` | `string` | Adds a className to the class attribute. | `''` | | `type` | `'email'`, `'password'`, `'search'`, `'text'`, `'url'`, `'tel'`, `'number'` | Sets type for TextInput | `'text'` | | `darkMode` | `boolean` | Determines whether or not the component will appear in dark mode. | `false` | +| `sizeVariant` | `'xsmall'`, `'small'`, `'medium'`, `'default'`, `'large'`, | Determines the size of the text and input height. | `default` | | ... | native `input` attributes | Any other props will be spread on the root `input` element | | ### Special Case: Aria Labels diff --git a/packages/text-input/src/TextInput.spec.tsx b/packages/text-input/src/TextInput.spec.tsx index 6ad9902867..4014edeaa1 100644 --- a/packages/text-input/src/TextInput.spec.tsx +++ b/packages/text-input/src/TextInput.spec.tsx @@ -7,7 +7,7 @@ import { } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { axe } from 'jest-axe'; -import TextInput, { State } from './TextInput'; +import TextInput, { State, SizeVariant } from './TextInput'; const error = 'This is the error message'; const validEmail = 'test.email@mongodb.com'; @@ -222,6 +222,21 @@ describe('packages/text-input', () => { }); }); + describe('when the "sizeVariant" is "large"', () => { + test('check if font-size is 18px', () => { + const { label } = renderTextInput({ + value: validEmail, + sizeVariant: SizeVariant.Large, + optional: true, + ...defaultProps, + }); + + expect((label)).toHaveStyle({ + fontSize: '18px', + }); + }); + }); + /* eslint-disable jest/expect-expect, jest/no-disabled-tests */ describe.skip('types behave as expected', () => { test('TextInput throws error when neither aria-labelledby or label is supplied', () => { diff --git a/packages/text-input/src/TextInput.story.tsx b/packages/text-input/src/TextInput.story.tsx index 4b50428f1f..f8011819a2 100644 --- a/packages/text-input/src/TextInput.story.tsx +++ b/packages/text-input/src/TextInput.story.tsx @@ -45,6 +45,7 @@ storiesOf('TextInput', module) errorMessage={text('Error Message', 'This is an error message')} darkMode={darkMode} handleValidation={value => console.log(`handleValidation ${value}`)} + sizeVariant={select('Size Variant', ['xsmall', 'small', 'medium', 'default', 'large'], 'default')} /> diff --git a/packages/text-input/src/TextInput.tsx b/packages/text-input/src/TextInput.tsx index a66b6a9c6c..6bfb2b91f8 100644 --- a/packages/text-input/src/TextInput.tsx +++ b/packages/text-input/src/TextInput.tsx @@ -39,6 +39,16 @@ const Mode = { type Mode = typeof Mode[keyof typeof Mode]; +export const SizeVariant = { + XSmall: 'xsmall', + Small: 'small', + Medium: 'medium', + Default: 'default', + Large: 'large', +} as const; + +type SizeVariant = typeof SizeVariant[keyof typeof SizeVariant]; + interface TextInputProps extends HTMLElementProps<'input', HTMLInputElement> { /** * id associated with the TextInput component. @@ -107,6 +117,8 @@ interface TextInputProps extends HTMLElementProps<'input', HTMLInputElement> { handleValidation?: (value: string) => void; ['aria-labelledby']?: string; + + sizeVariant?: SizeVariant; } type AriaLabels = 'label' | 'aria-labelledby'; @@ -229,6 +241,40 @@ const interactionRingColor: Record> = { }, }; +interface SizeSet { + inputHeight: number; + text: number; + lineHeight: number; +} + +const sizeSets: Record = { + [SizeVariant.XSmall]: { + inputHeight: 22, + text: 14, + lineHeight: 20, + }, + [SizeVariant.Small]: { + inputHeight: 28, + text: 14, + lineHeight: 20, + }, + [SizeVariant.Default]: { + inputHeight: 36, + text: 14, + lineHeight: 20, + }, + [SizeVariant.Medium]: { + inputHeight: 36, + text: 16, + lineHeight: 20, + }, + [SizeVariant.Large]: { + inputHeight: 48, + text: 18, + lineHeight: 22, + }, +}; + function getStatefulInputStyles({ state, optional, @@ -291,6 +337,7 @@ function getStatefulInputStyles({ * @param props.value The current value of the input field. If a value is passed to this prop, component will be controlled by consumer. * @param props.className className supplied to the TextInput container. * @param props.darkMode determines whether or not the component appears in dark mode. + * @param props.sizeVariant determines the size of the text and the height of the input. */ const TextInput: React.ComponentType< React.PropsWithRef @@ -310,6 +357,7 @@ const TextInput: React.ComponentType< value: controlledValue, className, darkMode = false, + sizeVariant = SizeVariant.Small, 'aria-labelledby': ariaLabelledby, handleValidation, ...rest @@ -321,6 +369,7 @@ const TextInput: React.ComponentType< const [uncontrolledValue, setValue] = useState(''); const value = isControlled ? controlledValue : uncontrolledValue; const id = useIdAllocator({ prefix: 'textinput', id: propsId }); + const sizeSet = sizeSets[sizeVariant]; // Validation const validation = useValidation(handleValidation); @@ -356,12 +405,17 @@ const TextInput: React.ComponentType< return (
{label && ( -