diff --git a/packages/design-system/src/components/Alert/Alert.tsx b/packages/design-system/src/components/Alert/Alert.tsx index 0c9fb08e74..6b5c0c6440 100644 --- a/packages/design-system/src/components/Alert/Alert.tsx +++ b/packages/design-system/src/components/Alert/Alert.tsx @@ -1,5 +1,4 @@ import { EVENT_CATEGORY, MAX_LENGTH, sendAnalyticsEvent } from '../analytics/SendAnalytics'; -// import PropTypes from 'prop-types'; import React from 'react'; import { alertSendsAnalytics } from '../flags'; import classNames from 'classnames'; @@ -9,22 +8,28 @@ import uniqueId from 'lodash.uniqueid'; /* eslint-disable camelcase */ // disable linting since prop names must be in snake case for integration with Blast export interface AnalyticsEventShape { - event_name?: string; - event_type?: string; - ga_eventAction?: string; - ga_eventCategory?: string; - ga_eventLabel?: string; + event_name: string; + event_type: string; + ga_eventAction: string; + ga_eventCategory: string; + ga_eventLabel: string; ga_eventType?: string; ga_eventValue?: string; - heading?: string; - type?: string; + heading: string; + type: string; + [additional_props: string]: unknown; } /* eslint-enable camelcase */ -interface AnalyticsObjectShape { +export interface AnalyticsObjectShape { onComponentDidMount?: boolean | AnalyticsEventShape; } +export type AlertHeadingLevel = '1' | '2' | '3' | '4' | '5' | '6'; + +export type AlertRole = 'alert' | 'alertdialog' | 'region' | 'status'; + +export type AlertVariation = 'error' | 'warn' | 'success'; export interface AlertProps { /** * Access a reference to the `alert` `div` element @@ -59,7 +64,7 @@ export interface AlertProps { /** * Heading type to override default `

`. */ - headingLevel?: '1' | '2' | '3' | '4' | '5' | '6'; + headingLevel?: AlertHeadingLevel; /** * Boolean to hide the `Alert` icon */ @@ -67,11 +72,11 @@ export interface AlertProps { /** * ARIA `role`, defaults to 'region' */ - role?: 'alert' | 'alertdialog' | 'region' | 'status'; + role?: AlertRole; /** * A string corresponding to the `Alert` variation classes (`error`, `warn`, `success`) */ - variation?: 'error' | 'warn' | 'success'; + variation?: AlertVariation; [key: string]: any; } @@ -89,7 +94,18 @@ const defaultAnalytics = (heading = '', variation = '') => ({ }, }); -export class Alert extends React.PureComponent { +// Omit props that we override with values from the Alert +type OmitAlertProps = 'role' | 'children' | 'className' | 'ref'; + +export class Alert extends React.PureComponent< + Omit, OmitAlertProps> & AlertProps, + any +> { + static defaultProps = { + role: 'region', + headingLevel: '2', + }; + constructor(props: AlertProps) { super(props); this.alertTextRef = null; @@ -114,7 +130,7 @@ export class Alert extends React.PureComponent { if (alertSendsAnalytics()) { const eventAction = 'onComponentDidMount'; - const eventHeading = this.props.heading || this.props.children; + const eventHeading: string | React.ReactNode = this.props.heading || this.props.children; /* Send analytics event for `error`, `warn`, `success` alert variations */ if (this.props.variation) { @@ -146,7 +162,7 @@ export class Alert extends React.PureComponent { eventHeadingText: string; heading(): React.ReactElement | void { - const { headingLevel = '2', heading } = this.props; + const { headingLevel, heading } = this.props; const Heading = `h${headingLevel}`; if (heading) { const headingProps = { @@ -167,7 +183,7 @@ export class Alert extends React.PureComponent { headingLevel, hideIcon, alertRef, - role = 'region', + role, variation, analytics, ...alertProps diff --git a/packages/design-system/src/components/ChoiceList/Choice.test.tsx b/packages/design-system/src/components/ChoiceList/Choice.test.tsx index 87df260cd1..57c5cfe641 100644 --- a/packages/design-system/src/components/ChoiceList/Choice.test.tsx +++ b/packages/design-system/src/components/ChoiceList/Choice.test.tsx @@ -1,4 +1,4 @@ -import Choice from './Choice'; +import Choice, { ChoiceProps, ChoiceType } from './Choice'; import FormLabel from '../FormLabel/FormLabel'; import React from 'react'; import { shallow } from 'enzyme'; @@ -6,12 +6,12 @@ import { shallow } from 'enzyme'; const defaultProps = { name: 'foo', value: 'boo', - type: 'checkbox', + type: 'checkbox' as ChoiceType, label: 'George Washington', }; function render(customProps = {}) { - const props = { ...defaultProps, ...customProps }; + const props: ChoiceProps = { ...defaultProps, ...customProps }; return { props, wrapper: shallow(), @@ -222,8 +222,8 @@ describe('Choice', () => { target: { checked: true }, }); - expect(data.props.onBlur.mock.calls.length).toBe(0); - expect(data.props.onChange.mock.calls.length).toBe(1); + expect(data.props.onBlur).toHaveBeenCalledTimes(0); + expect(data.props.onChange).toHaveBeenCalledTimes(1); }); it('updates state when uncontrolled component', () => { @@ -257,8 +257,8 @@ describe('Choice', () => { input.simulate('blur'); - expect(data.props.onBlur.mock.calls.length).toBe(1); - expect(data.props.onChange.mock.calls.length).toBe(0); + expect(data.props.onBlur).toHaveBeenCalledTimes(1); + expect(data.props.onChange).toHaveBeenCalledTimes(0); }); describe('uncheck event emitter', () => { diff --git a/packages/design-system/src/components/ChoiceList/Choice.tsx b/packages/design-system/src/components/ChoiceList/Choice.tsx index 9b2a476cca..273f51c3e4 100644 --- a/packages/design-system/src/components/ChoiceList/Choice.tsx +++ b/packages/design-system/src/components/ChoiceList/Choice.tsx @@ -4,6 +4,9 @@ import React from 'react'; import classNames from 'classnames'; import uniqueId from 'lodash.uniqueid'; +export type ChoiceSize = 'small'; +export type ChoiceType = 'checkbox' | 'radio'; +export type ChoiceValue = number | string; export interface ChoiceProps { /** * @hide-prop In order to be consistent with form elements, use `label` instead @@ -67,7 +70,7 @@ export interface ChoiceProps { * Applies the "inverse" UI theme */ inversed?: boolean; - size?: 'small'; + size?: ChoiceSize; /** * The `input` field's `name` attribute */ @@ -77,11 +80,11 @@ export interface ChoiceProps { /** * Sets the type to render `checkbox` fields or `radio` buttons */ - type: 'checkbox' | 'radio'; + type: ChoiceType; /** * The `input` `value` attribute */ - value: number | string; + value: ChoiceValue; } type OmitProps = diff --git a/packages/design-system/src/components/ChoiceList/ChoiceList.test.tsx b/packages/design-system/src/components/ChoiceList/ChoiceList.test.tsx index 8e7fe36c93..033d7a4ce0 100644 --- a/packages/design-system/src/components/ChoiceList/ChoiceList.test.tsx +++ b/packages/design-system/src/components/ChoiceList/ChoiceList.test.tsx @@ -1,5 +1,5 @@ +import ChoiceList, { ChoiceListType } from './ChoiceList'; import { mount, shallow } from 'enzyme'; -import ChoiceList from './ChoiceList'; import React from 'react'; function generateChoices(length) { @@ -22,7 +22,7 @@ function render(customProps = {}, choicesCount = 2, deep = true) { choices: generateChoices(choicesCount), label: 'Foo', name: 'spec-field', - type: 'radio', + type: 'radio' as ChoiceListType, }, ...customProps, }; diff --git a/packages/design-system/src/components/ChoiceList/ChoiceList.tsx b/packages/design-system/src/components/ChoiceList/ChoiceList.tsx index 64ce44a3c7..de6fb5c55d 100644 --- a/packages/design-system/src/components/ChoiceList/ChoiceList.tsx +++ b/packages/design-system/src/components/ChoiceList/ChoiceList.tsx @@ -4,9 +4,13 @@ import React from 'react'; import classNames from 'classnames'; import pick from 'lodash/pick'; +export type ChoiceListSize = 'small'; +export type ChoiceListType = 'checkbox' | 'radio'; +export type ChoiceListErrorPlacement = 'top' | 'bottom'; + // Omit props that we override with values from the ChoiceList type OmitChoiceProp = 'inversed' | 'name' | 'onBlur' | 'onChange' | 'size' | 'type' | 'inputRef'; -type ChoiceProps = Omit; +export type ChoiceProps = Omit; export interface ChoiceListProps { /** @@ -29,7 +33,7 @@ export interface ChoiceListProps { /** * Location of the error message relative to the field input */ - errorPlacement?: 'top' | 'bottom'; + errorPlacement?: ChoiceListErrorPlacement; /** * Additional hint text to display */ @@ -72,11 +76,11 @@ export interface ChoiceListProps { /** * Sets the size of the checkbox or radio button */ - size?: 'small'; + size?: ChoiceListSize; /** * Sets the type to render `checkbox` fields or `radio` buttons */ - type: 'checkbox' | 'radio'; + type: ChoiceListType; } export class ChoiceList extends React.PureComponent { diff --git a/packages/design-system/src/components/DateField/DateField.tsx b/packages/design-system/src/components/DateField/DateField.tsx index 9c74f688b7..3fe1cc956a 100644 --- a/packages/design-system/src/components/DateField/DateField.tsx +++ b/packages/design-system/src/components/DateField/DateField.tsx @@ -11,6 +11,7 @@ export type DateFieldMonthDefaultValue = string | number; export type DateFieldMonthValue = string | number; export type DateFieldYearDefaultValue = string | number; export type DateFieldYearValue = string | number; +export type DateFieldErrorPlacement = 'top' | 'bottom'; export interface DateFieldProps { /** @@ -39,7 +40,7 @@ export interface DateFieldProps { /** * Location of the error message relative to the field input */ - errorPlacement?: 'top' | 'bottom'; + errorPlacement?: DateFieldErrorPlacement; /** * Additional hint text to display above the individual month/day/year fields */ diff --git a/packages/design-system/src/components/Dropdown/Dropdown.tsx b/packages/design-system/src/components/Dropdown/Dropdown.tsx index 7dfe312ad9..ef03252bfe 100644 --- a/packages/design-system/src/components/Dropdown/Dropdown.tsx +++ b/packages/design-system/src/components/Dropdown/Dropdown.tsx @@ -5,6 +5,14 @@ import { errorPlacementDefault } from '../flags'; import omit from 'lodash/omit'; import pick from 'lodash/pick'; +export type DropdownDefaultValue = number | string; +export interface DropdownOptions { + label: React.ReactNode; + value: number | string; +} +export type DropdownSize = 'small' | 'medium'; +export type DropdownValue = number | string; +export type DropdownErrorPlacement = 'top' | 'bottom'; export interface DropdownProps { /** * Adds `aria-label` attribute. When using `aria-label`, `label` should be empty string. @@ -22,7 +30,7 @@ export interface DropdownProps { * Sets the initial selected state. Use this for an uncontrolled component; * otherwise, use the `value` property. */ - defaultValue?: number | string; + defaultValue?: DropdownDefaultValue; /** * Disables the entire field. */ @@ -35,7 +43,7 @@ export interface DropdownProps { /** * Location of the error message relative to the field input */ - errorPlacement?: 'top' | 'bottom'; + errorPlacement?: DropdownErrorPlacement; /** * Additional classes to be added to the select element */ @@ -75,10 +83,7 @@ export interface DropdownProps { /** * The list of options to be rendered. Provide an empty list if using custom options via the `children` prop. */ - options: { - label: React.ReactNode; - value: number | string; - }[]; + options: DropdownOptions[]; onBlur?: (...args: any[]) => any; onChange?: (...args: any[]) => any; /** @@ -88,12 +93,12 @@ export interface DropdownProps { /** * If the component renders a select, set the max-width of the input either to `'small'` or `'medium'`. */ - size?: 'small' | 'medium'; + size?: DropdownSize; /** * Sets the field's `value`. Use this in combination with `onChange` * for a controlled component; otherwise, set `defaultValue`. */ - value?: number | string; + value?: DropdownValue; } type OmitProps = diff --git a/packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap index be3849ba8d..2ad58d98a9 100644 --- a/packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap +++ b/packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap @@ -21,6 +21,7 @@ exports[`Table table caption scrollable true applies scroll table wrapper and cl scrollableNotice={

_types) attribute. If you are using `type=number` please use the numeric prop instead. */ diff --git a/packages/design-system/src/components/TextField/TextInput.tsx b/packages/design-system/src/components/TextField/TextInput.tsx index d582e52e8e..27b2142675 100644 --- a/packages/design-system/src/components/TextField/TextInput.tsx +++ b/packages/design-system/src/components/TextField/TextInput.tsx @@ -3,7 +3,11 @@ import Mask from './Mask'; import classNames from 'classnames'; export type TextInputDefaultValue = string | number; +export type TextInputMask = 'currency' | 'phone' | 'ssn' | 'zip'; +export type TextInputRows = number | string; +export type TextInputSize = 'small' | 'medium'; export type TextInputValue = string | number; +export type TextInputErrorPlacement = 'top' | 'bottom'; export interface TextInputProps { /** @@ -25,7 +29,7 @@ export interface TextInputProps { /** * Location of the error message relative to the field input */ - errorPlacement?: 'top' | 'bottom'; + errorPlacement?: TextInputErrorPlacement; /** * Additional classes to be added to the field element */ @@ -43,7 +47,7 @@ export interface TextInputProps { * you expect to be entered. Depending on the mask, the * field's appearance and functionality may be affected. */ - mask?: 'currency' | 'phone' | 'ssn' | 'zip'; + mask?: TextInputMask; /** * Whether or not the text field is a multiline text field */ @@ -63,12 +67,12 @@ export interface TextInputProps { * Optionally specify the number of visible text lines for the field. Only * applicable if this is a multiline field. */ - rows?: number | string; + rows?: TextInputRows; setRef?: (...args: any[]) => any; /** * Set the max-width of the input either to `'small'` or `'medium'`. */ - size?: 'small' | 'medium'; + size?: TextInputSize; /** * HTML `input` [type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#_types) attribute. If you are using `type=number` please use the numeric prop instead. */ @@ -80,7 +84,7 @@ export interface TextInputProps { value?: TextInputValue; } -export type OmitProps = 'size' | 'ref'; +type OmitProps = 'size' | 'ref'; /** * is an internal component used by , which wraps it and handles shared form UI like labels, error messages, etc