From fa713b837662693c007698e149b0dfc211e8a499 Mon Sep 17 00:00:00 2001 From: "radek.stary" Date: Fri, 28 Apr 2023 02:27:49 +0200 Subject: [PATCH] fixup! fixup! fixup! fixup! Rename JavaScript files to TypeScript files --- src/lib/components/Alert/Alert.test.tsx | 14 +- src/lib/components/Alert/Alert.tsx | 70 ++--- src/lib/components/Alert/Alert.types.ts | 31 +++ src/lib/components/Badge/Badge.test.tsx | 10 +- src/lib/components/Badge/Badge.tsx | 28 +- src/lib/components/Badge/Badge.types.ts | 18 ++ src/lib/components/Button/Button.test.tsx | 41 +-- src/lib/components/Button/Button.tsx | 139 ++-------- src/lib/components/Button/Button.types.ts | 78 ++++++ .../getRootLabelVisibilityClassName.ts | 15 +- .../helpers/getRootPriorityClassName.ts | 8 +- .../ButtonGroup/ButtonGroup.test.tsx | 18 +- .../components/ButtonGroup/ButtonGroup.tsx | 43 +-- .../ButtonGroup/ButtonGroup.types.ts | 45 ++++ .../ButtonGroup/ButtonGroupContext.ts | 3 +- src/lib/components/Card/Card.test.tsx | 24 +- src/lib/components/Card/Card.tsx | 45 +--- src/lib/components/Card/Card.types.ts | 52 ++++ src/lib/components/Card/CardBody.test.tsx | 6 +- src/lib/components/Card/CardBody.tsx | 11 +- src/lib/components/Card/CardFooter.test.tsx | 10 +- src/lib/components/Card/CardFooter.tsx | 16 +- .../CheckboxField/CheckboxField.test.tsx | 40 +-- .../CheckboxField/CheckboxField.tsx | 85 +----- .../CheckboxField/CheckboxField.types.ts | 49 ++++ .../FileInputField/FileInputField.test.tsx | 48 ++-- .../FileInputField/FileInputField.tsx | 101 ++----- .../FileInputField/FileInputField.types.tsx | 57 ++++ .../components/FormLayout/FormLayout.test.tsx | 24 +- src/lib/components/FormLayout/FormLayout.tsx | 57 +--- .../FormLayout/FormLayout.types.tsx | 80 ++++++ .../FormLayout/FormLayoutContext.ts | 2 +- .../FormLayout/FormLayoutCustomField.test.tsx | 32 +-- .../FormLayout/FormLayoutCustomField.tsx | 67 +---- src/lib/components/Grid/Grid.test.tsx | 18 +- src/lib/components/Grid/Grid.tsx | 189 +------------ src/lib/components/Grid/Grid.types.ts | 114 ++++++++ src/lib/components/Grid/GridSpan.test.tsx | 16 +- src/lib/components/Grid/GridSpan.tsx | 62 +---- ...generateResponsiveCustomProperties.test.ts | 6 +- .../generateResponsiveCustomProperties.ts | 13 +- src/lib/components/Modal/Modal.test.tsx | 51 ++-- src/lib/components/Modal/Modal.tsx | 109 ++------ src/lib/components/Modal/Modal.types.ts | 179 +++++++++++++ src/lib/components/Modal/ModalBody.test.tsx | 6 +- src/lib/components/Modal/ModalBody.tsx | 32 +-- .../Modal/ModalCloseButton.test.tsx | 10 +- src/lib/components/Modal/ModalCloseButton.tsx | 30 +-- .../components/Modal/ModalContent.test.tsx | 6 +- src/lib/components/Modal/ModalContent.tsx | 17 +- src/lib/components/Modal/ModalFooter.test.tsx | 10 +- src/lib/components/Modal/ModalFooter.tsx | 21 +- src/lib/components/Modal/ModalHeader.test.tsx | 10 +- src/lib/components/Modal/ModalHeader.tsx | 21 +- src/lib/components/Modal/ModalTitle.test.tsx | 6 +- src/lib/components/Modal/ModalTitle.tsx | 24 +- .../Modal/_helpers/getJustifyClassName.ts | 10 +- .../Modal/_helpers/getScrollingClassName.ts | 7 +- src/lib/components/Paper/Paper.test.tsx | 10 +- src/lib/components/Paper/Paper.tsx | 28 +- src/lib/components/Paper/Paper.types.ts | 18 ++ src/lib/components/Popover/Popover.test.tsx | 10 +- src/lib/components/Popover/Popover.tsx | 61 +---- src/lib/components/Popover/Popover.types.ts | 35 +++ .../Popover/PopoverWrapper.test.tsx | 10 +- src/lib/components/Popover/PopoverWrapper.tsx | 22 +- .../_helpers/getRootAlignmentClassName.ts | 8 +- .../Popover/_helpers/getRootSideClassName.ts | 9 +- src/lib/components/Radio/Radio.test.tsx | 40 +-- src/lib/components/Radio/Radio.tsx | 106 +------- src/lib/components/Radio/Radio.types.ts | 75 ++++++ .../components/ScrollView/ScrollView.test.tsx | 27 +- src/lib/components/ScrollView/ScrollView.tsx | 252 +++++------------- .../components/ScrollView/ScrollView.types.ts | 125 +++++++++ .../_helpers/getElementsPositionDifference.ts | 7 +- .../ScrollView/_hooks/useLoadResizeHook.ts | 13 +- .../_hooks/useScrollPositionHook.ts | 23 +- .../SelectField/SelectField.test.tsx | 75 +++--- .../components/SelectField/SelectField.tsx | 196 +++----------- .../SelectField/SelectField.types.ts | 118 ++++++++ .../SelectField/_components/Option/Option.tsx | 33 +-- src/lib/components/Table/Table.test.tsx | 14 +- src/lib/components/Table/Table.tsx | 45 +--- src/lib/components/Table/Table.types.ts | 80 ++++++ .../TableBodyCell/TableBodyCell.tsx | 33 +-- .../TableHeaderCell/TableHeaderCell.tsx | 37 +-- src/lib/components/Tabs/Tabs.test.tsx | 8 +- src/lib/components/Tabs/Tabs.tsx | 21 +- src/lib/components/Tabs/Tabs.types.ts | 53 ++++ src/lib/components/Tabs/TabsItem.test.tsx | 10 +- src/lib/components/Tabs/TabsItem.tsx | 48 +--- src/lib/components/Text/Text.test.tsx | 6 +- src/lib/components/Text/Text.tsx | 51 +--- src/lib/components/Text/Text.types.ts | 26 ++ .../Text/_helpers/getRootClampClassName.ts | 7 +- .../Text/_helpers/getRootHyphensClassName.ts | 7 +- .../_helpers/getRootWordWrappingClassName.ts | 7 +- src/lib/components/TextArea/TextArea.test.tsx | 56 ++-- src/lib/components/TextArea/TextArea.tsx | 106 ++------ src/lib/components/TextArea/TextArea.types.ts | 61 +++++ .../components/TextField/TextField.test.tsx | 56 ++-- src/lib/components/TextField/TextField.tsx | 130 ++------- .../components/TextField/TextField.types.ts | 70 +++++ src/lib/components/TextLink/TextLink.test.tsx | 6 +- src/lib/components/TextLink/TextLink.tsx | 15 +- src/lib/components/TextLink/TextLink.types.ts | 14 + src/lib/components/Toggle/Toggle.test.tsx | 40 +-- src/lib/components/Toggle/Toggle.tsx | 83 +----- src/lib/components/Toggle/Toggle.types.ts | 47 ++++ src/lib/components/Toolbar/Toolbar.test.tsx | 26 +- src/lib/components/Toolbar/Toolbar.tsx | 49 +--- src/lib/components/Toolbar/Toolbar.types.ts | 68 +++++ .../components/Toolbar/ToolbarGroup.test.tsx | 22 +- src/lib/components/Toolbar/ToolbarGroup.tsx | 38 +-- .../components/Toolbar/ToolbarItem.test.tsx | 10 +- src/lib/components/Toolbar/ToolbarItem.tsx | 26 +- .../Toolbar/_helpers/getAlignClassName.ts | 13 +- .../Toolbar/_helpers/getJustifyClassName.ts | 9 +- src/lib/{index.js => index.ts} | 0 src/lib/provider/RUIContext.tsx | 3 +- src/lib/provider/RUIProvider.tsx | 19 +- src/lib/provider/provider.types.ts | 14 + src/lib/provider/withGlobalProps.tsx | 33 +-- src/lib/utils/classNames.test.ts | 2 +- 124 files changed, 2499 insertions(+), 2605 deletions(-) create mode 100644 src/lib/components/Alert/Alert.types.ts create mode 100644 src/lib/components/Badge/Badge.types.ts create mode 100644 src/lib/components/Button/Button.types.ts create mode 100644 src/lib/components/ButtonGroup/ButtonGroup.types.ts create mode 100644 src/lib/components/Card/Card.types.ts create mode 100644 src/lib/components/CheckboxField/CheckboxField.types.ts create mode 100644 src/lib/components/FileInputField/FileInputField.types.tsx create mode 100644 src/lib/components/FormLayout/FormLayout.types.tsx create mode 100644 src/lib/components/Grid/Grid.types.ts create mode 100644 src/lib/components/Modal/Modal.types.ts create mode 100644 src/lib/components/Paper/Paper.types.ts create mode 100644 src/lib/components/Popover/Popover.types.ts create mode 100644 src/lib/components/Radio/Radio.types.ts create mode 100644 src/lib/components/ScrollView/ScrollView.types.ts create mode 100644 src/lib/components/SelectField/SelectField.types.ts create mode 100644 src/lib/components/Table/Table.types.ts create mode 100644 src/lib/components/Tabs/Tabs.types.ts create mode 100644 src/lib/components/Text/Text.types.ts create mode 100644 src/lib/components/TextArea/TextArea.types.ts create mode 100644 src/lib/components/TextField/TextField.types.ts create mode 100644 src/lib/components/TextLink/TextLink.types.ts create mode 100644 src/lib/components/Toggle/Toggle.types.ts create mode 100644 src/lib/components/Toolbar/Toolbar.types.ts rename src/lib/{index.js => index.ts} (100%) create mode 100644 src/lib/provider/provider.types.ts diff --git a/src/lib/components/Alert/Alert.test.tsx b/src/lib/components/Alert/Alert.test.tsx index 69d4338f..1a3ed006 100644 --- a/src/lib/components/Alert/Alert.test.tsx +++ b/src/lib/components/Alert/Alert.test.tsx @@ -6,9 +6,9 @@ import { within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { colorPropTest } from '../../../../../tests/propTests/colorPropTest'; -import defaultTranslations from '../../../translations/en'; -import { Alert } from '../Alert'; +import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import defaultTranslations from '../../translations/en'; +import { Alert } from './Alert'; const mandatoryProps = { children: 'content', @@ -16,12 +16,12 @@ const mandatoryProps = { }; describe('rendering', () => { - it.each([ + it.each([ [ { children:
content text
}, (rootElement) => expect(within(rootElement).getByText('content text')), ], - ...colorPropTest, + ...(colorPropTest as unknown as TestingProps[]), [ { icon: (
icon
) }, (rootElement) => expect(within(rootElement).getByText('icon')), @@ -29,7 +29,7 @@ describe('rendering', () => { [ { id: 'id', - onClose: () => {}, + onClose: () => { }, }, (rootElement) => { expect(rootElement).toHaveAttribute('id', 'id'); @@ -45,7 +45,7 @@ describe('rendering', () => { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); diff --git a/src/lib/components/Alert/Alert.tsx b/src/lib/components/Alert/Alert.tsx index 3138fda6..d0cb516c 100644 --- a/src/lib/components/Alert/Alert.tsx +++ b/src/lib/components/Alert/Alert.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React, { useContext } from 'react'; import { RUIContext, @@ -8,10 +7,11 @@ import { transferProps } from '../_helpers/transferProps'; import { classNames } from '../../utils/classNames'; import { getRootColorClassName } from '../_helpers/getRootColorClassName'; import styles from './Alert.scss'; +import { AlertProps } from './Alert.types'; -export const Alert = ({ +export const Alert: React.FunctionComponent = ({ children, - color, + color = 'note', icon, id, onClose, @@ -30,9 +30,9 @@ export const Alert = ({ role="alert" > {icon && ( -
- {icon} -
+
+ {icon} +
)}
{onClose && ( - + )}
); }; -Alert.defaultProps = { - color: 'note', - icon: null, - id: undefined, - onClose: null, -}; - -Alert.propTypes = { - /** - * Alert body. - */ - children: PropTypes.node.isRequired, - /** - * [Color variant](/foundation/colors#component-colors) to clarify importance and meaning of the alert. - */ - color: PropTypes.oneOf(['success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark']), - /** - * Optional element to be displayed next to the alert body. - */ - icon: PropTypes.node, - /** - * ID of the root HTML element. - * - * Also serves as base for ids of nested elements: - * * `__close` - * * `__content` - */ - id: PropTypes.string, - /** - * Function to call when the close button is clicked. If not provided, close buttons will be - * hidden. - */ - onClose: PropTypes.func, -}; - export const AlertWithGlobalProps = withGlobalProps(Alert, 'Alert'); export default AlertWithGlobalProps; + diff --git a/src/lib/components/Alert/Alert.types.ts b/src/lib/components/Alert/Alert.types.ts new file mode 100644 index 00000000..40053475 --- /dev/null +++ b/src/lib/components/Alert/Alert.types.ts @@ -0,0 +1,31 @@ +export interface AlertProps { + /** + * Rest of the props. + */ + [key: string]: unknown; + /** + * Alert Body + */ + children: React.ReactNode; + /** + * [Color variant] (/foundation/colors#component-colors) to clarify importance and meaning of the alert. + */ + color?: Color; + /** + * Optional element to be displayed next to the alert body. + */ + icon?: React.ReactNode; + /** + * ID of the root HTML element. + * + * Also serves as base for ids of nested elements: + * * `__close` + * * `__content` + */ + id?: string; + /** + * Function to call when the close button is clicked. If not provided, close buttons will be + * hidden. + */ + onClose?: () => void; +} diff --git a/src/lib/components/Badge/Badge.test.tsx b/src/lib/components/Badge/Badge.test.tsx index 821a8948..fafe9ac1 100644 --- a/src/lib/components/Badge/Badge.test.tsx +++ b/src/lib/components/Badge/Badge.test.tsx @@ -3,16 +3,16 @@ import { render, within, } from '@testing-library/react'; -import { colorPropTest } from '../../../../../tests/propTests/colorPropTest'; -import { Badge } from '../Badge'; +import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import { Badge } from './Badge'; const mandatoryProps = { label: 'label', }; describe('rendering', () => { - it.each([ - ...colorPropTest, + it.each([ + ...(colorPropTest as unknown as TestingProps[]), [ { label: 'label text' }, (rootElement) => expect(within(rootElement).getByText('label text')), @@ -33,6 +33,6 @@ describe('rendering', () => { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); diff --git a/src/lib/components/Badge/Badge.tsx b/src/lib/components/Badge/Badge.tsx index 36bd00c4..aacdf3e6 100644 --- a/src/lib/components/Badge/Badge.tsx +++ b/src/lib/components/Badge/Badge.tsx @@ -1,15 +1,15 @@ -import PropTypes from 'prop-types'; import React from 'react'; import { withGlobalProps } from '../../provider'; import { transferProps } from '../_helpers/transferProps'; import { classNames } from '../../utils/classNames'; import { getRootColorClassName } from '../_helpers/getRootColorClassName'; import styles from './Badge.scss'; +import { BadgeProps } from './Badge.types'; -export const Badge = ({ - color, +export const Badge: React.FunctionComponent = ({ + color = 'note', label, - priority, + priority = 'filled', ...restProps }) => (
); -Badge.defaultProps = { - color: 'note', - priority: 'filled', -}; - -Badge.propTypes = { - /** - * [Color variant](/foundation/colors#component-colors) to clarify importance and meaning of the badge. - */ - color: PropTypes.oneOf(['success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark']), - /** - * Text to be displayed. - */ - label: PropTypes.string.isRequired, - /** - * Visual priority to highlight or suppress the badge. - */ - priority: PropTypes.oneOf(['filled', 'outline']), -}; - export const BadgeWithGlobalProps = withGlobalProps(Badge, 'Badge'); export default BadgeWithGlobalProps; diff --git a/src/lib/components/Badge/Badge.types.ts b/src/lib/components/Badge/Badge.types.ts new file mode 100644 index 00000000..b209a7b7 --- /dev/null +++ b/src/lib/components/Badge/Badge.types.ts @@ -0,0 +1,18 @@ +export interface BadgeProps { + /** + * Rest of the props. + */ + [key: string]: unknown; + /** + * [Color variant](/foundation/colors#component-colors) to clarify importance and meaning of the badge. + */ + color?: Color; + /** + * Text to be displayed. + */ + label: string; + /** + * Visual priority to highlight or suppress the badge. + */ + priority?: Exclude; +} diff --git a/src/lib/components/Button/Button.test.tsx b/src/lib/components/Button/Button.test.tsx index 9e8ccc6e..ae6c1df3 100644 --- a/src/lib/components/Button/Button.test.tsx +++ b/src/lib/components/Button/Button.test.tsx @@ -6,22 +6,22 @@ import { } from '@testing-library/react'; import sinon from 'sinon'; import userEvent from '@testing-library/user-event'; -import { actionColorPropTest } from '../../../../../tests/propTests/actionColorPropTest'; -import { blockPropTest } from '../../../../../tests/propTests/blockPropTest'; -import { colorPropTest } from '../../../../../tests/propTests/colorPropTest'; -import { refPropTest } from '../../../../../tests/propTests/refPropTest'; -import { labelPropTest } from '../../../../../tests/propTests/labelPropTest'; -import { sizePropTest } from '../../../../../tests/propTests/sizePropTest'; -import { ButtonGroupContext } from '../../ButtonGroup'; -import { Button } from '../Button'; +import { actionColorPropTest } from '../../../../tests/propTests/actionColorPropTest'; +import { blockPropTest } from '../../../../tests/propTests/blockPropTest'; +import { colorPropTest } from '../../../../tests/propTests/colorPropTest'; +import { refPropTest } from '../../../../tests/propTests/refPropTest'; +import { labelPropTest } from '../../../../tests/propTests/labelPropTest'; +import { sizePropTest } from '../../../../tests/propTests/sizePropTest'; +import { ButtonGroupContext } from '../ButtonGroup'; +import { Button } from './Button'; const mandatoryProps = { label: 'label', }; describe('rendering', () => { - it.each([ - ...blockPropTest, + it.each([ + ...(blockPropTest as unknown as TestingProps[]), [ { disabled: true }, (rootElement) => expect(rootElement).toBeDisabled(), @@ -42,7 +42,7 @@ describe('rendering', () => { { priority: 'flat' }, (rootElement) => expect(rootElement).toHaveClass('isRootPriorityFlat'), ], - ...sizePropTest, + ...(sizePropTest as unknown as TestingProps[]), ])('renders with ButtonGroup props: "%s"', (testedProps, assert) => { const dom = render(( { )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); - it.each([ + it.each([ [ { afterLabel:
after label
}, (rootElement) => expect(within(rootElement).getByText('after label')), @@ -66,9 +66,9 @@ describe('rendering', () => { { beforeLabel:
before label
}, (rootElement) => expect(within(rootElement).getByText('before label')), ], - ...actionColorPropTest, - ...blockPropTest, - ...colorPropTest, + ...(actionColorPropTest as unknown as TestingProps[]), + ...(blockPropTest as unknown as TestingProps[]), + ...(colorPropTest as unknown as TestingProps[]), [ { disabled: true }, (rootElement) => expect(rootElement).toBeDisabled(), @@ -81,7 +81,7 @@ describe('rendering', () => { { endCorner:
corner text
}, (rootElement) => expect(within(rootElement).getByText('corner text')), ], - ...refPropTest(React.createRef()), + ...(refPropTest(React.createRef()) as unknown as TestingProps[]), [ { id: 'id' }, (rootElement) => { @@ -89,7 +89,7 @@ describe('rendering', () => { expect(within(rootElement).getByText('label')).toHaveAttribute('id', 'id__labelText'); }, ], - ...labelPropTest, + ...(labelPropTest as unknown as TestingProps[]), [ { labelVisibility: 'sm' }, (rootElement) => expect(rootElement).toHaveClass('hasLabelVisibleSm'), @@ -138,7 +138,7 @@ describe('rendering', () => { { priority: 'flat' }, (rootElement) => expect(rootElement).toHaveClass('isRootPriorityFlat'), ], - ...sizePropTest, + ...(sizePropTest as unknown as TestingProps[]), [ { startCorner:
corner text
}, (rootElement) => expect(within(rootElement).getByText('corner text')), @@ -151,7 +151,7 @@ describe('rendering', () => { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); @@ -169,3 +169,4 @@ describe('functionality', () => { expect(spy.calledOnce).toEqual(true); }); }); + diff --git a/src/lib/components/Button/Button.tsx b/src/lib/components/Button/Button.tsx index 1d39a9a7..59072823 100644 --- a/src/lib/components/Button/Button.tsx +++ b/src/lib/components/Button/Button.tsx @@ -1,40 +1,40 @@ -import PropTypes from 'prop-types'; import React, { useContext } from 'react'; -import { withGlobalProps } from '../../provider'; import { classNames } from '../../utils/classNames'; import { getRootColorClassName } from '../_helpers/getRootColorClassName'; import { getRootSizeClassName } from '../_helpers/getRootSizeClassName'; import { resolveContextOrProp } from '../_helpers/resolveContextOrProp'; import { transferProps } from '../_helpers/transferProps'; import { ButtonGroupContext } from '../ButtonGroup'; +import { withGlobalProps } from '../../provider'; import getRootLabelVisibilityClassName from './helpers/getRootLabelVisibilityClassName'; import getRootPriorityClassName from './helpers/getRootPriorityClassName'; import styles from './Button.scss'; +import { ButtonProps } from './Button.types'; -export const Button = React.forwardRef((props, ref) => { - const { - afterLabel, - beforeLabel, - block, - disabled, - endCorner, - feedbackIcon, - id, - label, - labelVisibility, - priority, - size, - startCorner, - color, - ...restProps - } = props; - +export const Button: React.FunctionComponent = React.forwardRef(({ + afterLabel, + beforeLabel, + block = false, + color = 'primary', + disabled = false, + endCorner, + feedbackIcon, + id, + label, + labelVisibility = 'xs', + priority = 'filled', + size = 'medium', + startCorner, + type = 'button', + ...restProps +}, ref) => { const context = useContext(ButtonGroupContext); return ( - /* No worries, `type` is always assigned correctly through props. */ - /* eslint-disable react/button-has-type */ - /* eslint-enable react/button-has-type */ ); }); -Button.defaultProps = { - afterLabel: null, - beforeLabel: null, - block: false, - color: 'primary', - disabled: false, - endCorner: null, - feedbackIcon: null, - id: undefined, - labelVisibility: 'xs', - priority: 'filled', - size: 'medium', - startCorner: null, - type: 'button', -}; - -Button.propTypes = { - /** - * Element to be displayed after label, eg. an icon. - */ - afterLabel: PropTypes.node, - /** - * Element to be displayed before label, eg. an icon. - */ - beforeLabel: PropTypes.node, - /** - * If `true`, the button will span the full width of its parent. - * - * Ignored if the component is rendered within `ButtonGroup` component - * as the value is inherited in such case. - */ - block: PropTypes.bool, - /** - * [Color variant](/foundation/colors#component-colors) to clarify importance and meaning of the button. - */ - color: PropTypes.oneOf( - ['primary', 'secondary', 'selected', 'success', 'warning', 'danger', 'help', 'info', 'note', 'light', 'dark'], - ), - /** - * If `true`, the button will be disabled. - * - * Ignored if the component is rendered within `ButtonGroup` component - * as the value is inherited in such case. - */ - disabled: PropTypes.bool, - /** - * Element to be displayed in the top right corner. - */ - endCorner: PropTypes.node, - /** - * Element to be displayed as a feedback icon on top of button label. When defined, it implies the - * button is in feedback state. - */ - feedbackIcon: PropTypes.node, - /** - * ID of the root HTML element. - * - * Also serves as base for ids of nested elements: - * * `__labelText` - */ - id: PropTypes.string, - /** - * Button label. - */ - label: PropTypes.string.isRequired, - /** - * Defines minimum breakpoint from which the button label will be visible. - */ - labelVisibility: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl', 'x2l', 'x3l', 'none']), - /** - * Visual priority to highlight or suppress the button. - * - * Ignored if the component is rendered within `ButtonGroup` component - * as the value is inherited in such case. - */ - priority: PropTypes.oneOf(['filled', 'outline', 'flat']), - /** - * Size of the button. - * - * Ignored if the component is rendered within `ButtonGroup` component - * as the value is inherited in such case. - */ - size: PropTypes.oneOf(['small', 'medium', 'large']), - /** - * Element to be displayed in the top left corner. - */ - startCorner: PropTypes.node, - /** - * Set the HTML `type` attribute of the `button` element. - */ - type: PropTypes.oneOf(['button', 'submit']), -}; - export const ButtonWithGlobalProps = withGlobalProps(Button, 'Button'); export default ButtonWithGlobalProps; diff --git a/src/lib/components/Button/Button.types.ts b/src/lib/components/Button/Button.types.ts new file mode 100644 index 00000000..bdefbbeb --- /dev/null +++ b/src/lib/components/Button/Button.types.ts @@ -0,0 +1,78 @@ +export interface ButtonProps { + /** + * Rest of the props. + */ + [key: string]: unknown; + /** + * Element to be displayed after label, eg. an icon. + */ + afterLabel?: React.ReactNode; + /** + * Element to be displayed before label, eg. an icon. + */ + beforeLabel?: React.ReactNode; + /** + * If `true`, the button will span the full width of its parent. + * + * Ignored if the component is rendered within `ButtonGroup` component + * as the value is inherited in such case. + */ + block?: boolean; + /** + * [Color variant](/foundation/colors#component-colors) to clarify importance and meaning of the button. + */ + color?: Color; + /** + * If `true`, the button will be disabled. + * + * Ignored if the component is rendered within `ButtonGroup` component + * as the value is inherited in such case. + */ + disabled?: boolean; + /** + * Element to be displayed in the top right corner. + */ + endCorner?: React.ReactNode; + /** + * Element to be displayed as a feedback icon on top of button label. When defined, it implies the + * button is in feedback state. + */ + feedbackIcon?: React.ReactNode; + /** + * ID of the root HTML element. + * + * Also serves as base for ids of nested elements: + * * `__labelText` + */ + id?: string; + /** + * Button label. + */ + label: string; + /** + * Defines minimum breakpoint from which the button label will be visible. + */ + labelVisibility?: Breakpoint; + /** + * Visual priority to highlight or suppress the button. + * + * Ignored if the component is rendered within `ButtonGroup` component + * as the value is inherited in such case. + */ + priority?: Priority; + /** + * Size of the button. + * + * Ignored if the component is rendered within `ButtonGroup` component + * as the value is inherited in such case. + */ + size?: Size; + /** + * Element to be displayed in the top left corner. + */ + startCorner?: React.ReactNode; + /** + * Set the HTML `type` attribute of the `button` element. + */ + type?: Type; +} diff --git a/src/lib/components/Button/helpers/getRootLabelVisibilityClassName.ts b/src/lib/components/Button/helpers/getRootLabelVisibilityClassName.ts index d468ce88..aa90c397 100644 --- a/src/lib/components/Button/helpers/getRootLabelVisibilityClassName.ts +++ b/src/lib/components/Button/helpers/getRootLabelVisibilityClassName.ts @@ -1,4 +1,15 @@ -export default (labelVisibility, styles) => { + +interface ExtendedStyles extends React.CSSProperties { + hasLabelHidden: string; + hasLabelVisibleLg: string; + hasLabelVisibleMd: string; + hasLabelVisibleSm: string; + hasLabelVisibleX2l: string; + hasLabelVisibleX3l: string; + hasLabelVisibleXl: string; +} + +const getLabelVisibilityClass = (labelVisibility: Breakpoint, styles: ExtendedStyles): string | null => { // Intentionally omitting `xs` which means label is visible on all screen sizes. if (labelVisibility === 'sm') { @@ -31,3 +42,5 @@ export default (labelVisibility, styles) => { return null; }; + +export default getLabelVisibilityClass; diff --git a/src/lib/components/Button/helpers/getRootPriorityClassName.ts b/src/lib/components/Button/helpers/getRootPriorityClassName.ts index 41017657..86a52fa1 100644 --- a/src/lib/components/Button/helpers/getRootPriorityClassName.ts +++ b/src/lib/components/Button/helpers/getRootPriorityClassName.ts @@ -1,4 +1,10 @@ -export default (priority, styles) => { +interface ExtendedStyles extends React.CSSProperties { + isRootPriorityFilled: string; + isRootPriorityFlat: string; + isRootPriorityOutline: string; +} + +export default (priority: Priority, styles: ExtendedStyles) => { if (priority === 'filled') { return styles.isRootPriorityFilled; } diff --git a/src/lib/components/ButtonGroup/ButtonGroup.test.tsx b/src/lib/components/ButtonGroup/ButtonGroup.test.tsx index 735f3bc9..4ecf18d5 100644 --- a/src/lib/components/ButtonGroup/ButtonGroup.test.tsx +++ b/src/lib/components/ButtonGroup/ButtonGroup.test.tsx @@ -3,19 +3,19 @@ import { render, within, } from '@testing-library/react'; -import { blockPropTest } from '../../../../../tests/propTests/blockPropTest'; -import { childrenEmptyPropTest } from '../../../../../tests/propTests/childrenEmptyPropTest'; -import { Button } from '../../Button'; -import { ButtonGroup } from '../ButtonGroup'; +import { blockPropTest } from '../../../../tests/propTests_in_javacript/blockPropTest'; +import { childrenEmptyPropTest } from '../../../../tests/propTests_in_javacript/childrenEmptyPropTest'; +import { Button } from '../Button'; +import { ButtonGroup } from '.'; const mandatoryProps = { - children:
); }; - -CardFooter.defaultProps = { - children: null, -}; - -CardFooter.propTypes = { - /** - * Card actions, usually buttons. - */ - children: PropTypes.node, -}; - export const CardFooterWithGlobalProps = withGlobalProps(CardFooter, 'CardFooter'); export default CardFooterWithGlobalProps; diff --git a/src/lib/components/CheckboxField/CheckboxField.test.tsx b/src/lib/components/CheckboxField/CheckboxField.test.tsx index f00d6911..8e6a0bc7 100644 --- a/src/lib/components/CheckboxField/CheckboxField.test.tsx +++ b/src/lib/components/CheckboxField/CheckboxField.test.tsx @@ -6,16 +6,16 @@ import { within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { disabledPropTest } from '../../../../../tests/propTests/disabledPropTest'; -import { refPropTest } from '../../../../../tests/propTests/refPropTest'; -import { helpTextPropTest } from '../../../../../tests/propTests/helpTextPropTest'; -import { formLayoutProviderTest } from '../../../../../tests/providerTests/formLayoutProviderTest'; -import { isLabelVisible } from '../../../../../tests/propTests/isLabelVisible'; -import { labelPropTest } from '../../../../../tests/propTests/labelPropTest'; -import { requiredPropTest } from '../../../../../tests/propTests/requiredPropTest'; -import { validationStatePropTest } from '../../../../../tests/propTests/validationStatePropTest'; -import { validationTextPropTest } from '../../../../../tests/propTests/validationTextPropTest'; -import { CheckboxField } from '../CheckboxField'; +import { disabledPropTest } from '../../../../tests/propTests/disabledPropTest'; +import { refPropTest } from '../../../../tests/propTests/refPropTest'; +import { helpTextPropTest } from '../../../../tests/propTests/helpTextPropTest'; +import { formLayoutProviderTest } from '../../../../tests/providerTests/formLayoutProviderTest'; +import { isLabelVisible } from '../../../../tests/propTests/isLabelVisible'; +import { labelPropTest } from '../../../../tests/propTests/labelPropTest'; +import { requiredPropTest } from '../../../../tests/propTests/requiredPropTest'; +import { validationStatePropTest } from '../../../../tests/propTests/validationStatePropTest'; +import { validationTextPropTest } from '../../../../tests/propTests/validationTextPropTest'; +import { CheckboxField } from './CheckboxField'; const mandatoryProps = { label: 'label', @@ -24,10 +24,10 @@ const mandatoryProps = { describe('rendering', () => { formLayoutProviderTest(); - it.each([ - ...disabledPropTest, - ...refPropTest(React.createRef()), - ...helpTextPropTest, + it.each([ + ...(disabledPropTest as unknown as TestingProps[]), + ...(refPropTest(React.createRef()) as unknown as TestingProps[]), + ...(helpTextPropTest as unknown as TestingProps[]), [ { helpText: 'help text', @@ -42,11 +42,11 @@ describe('rendering', () => { expect(within(rootElement).getByText('validation text')).toHaveAttribute('id', 'id__validationText'); }, ], - ...isLabelVisible, - ...labelPropTest, - ...requiredPropTest, - ...validationStatePropTest, - ...validationTextPropTest, + ...(isLabelVisible as unknown as TestingProps[]), + ...(labelPropTest as unknown as TestingProps[]), + ...(requiredPropTest as unknown as TestingProps[]), + ...(validationStatePropTest as unknown as TestingProps[]), + ...(validationTextPropTest as unknown as TestingProps[]), ])('renders with props: "%s"', (testedProps, assert) => { const dom = render(( { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); diff --git a/src/lib/components/CheckboxField/CheckboxField.tsx b/src/lib/components/CheckboxField/CheckboxField.tsx index 0ce6f715..48050cea 100644 --- a/src/lib/components/CheckboxField/CheckboxField.tsx +++ b/src/lib/components/CheckboxField/CheckboxField.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React, { useContext } from 'react'; import { withGlobalProps } from '../../provider'; import { classNames } from '../../utils/classNames'; @@ -6,20 +5,21 @@ import { getRootValidationStateClassName } from '../_helpers/getRootValidationSt import { transferProps } from '../_helpers/transferProps'; import { FormLayoutContext } from '../FormLayout'; import styles from './CheckboxField.scss'; +import { CheckboxFieldProps } from './CheckboxField.types'; -export const CheckboxField = React.forwardRef((props, ref) => { - const { - disabled, - helpText, - id, - isLabelVisible, - label, - labelPosition, - required, - validationState, - validationText, - ...restProps - } = props; +export const CheckboxField: React.FunctionComponent = React.forwardRef(({ + disabled = false, + helpText, + id, + isLabelVisible = true, + label, + labelPosition = 'after', + required = false, + validationState, + validationText, + ...restProps +}, ref) => { const context = useContext(FormLayoutContext); return ( @@ -76,63 +76,6 @@ export const CheckboxField = React.forwardRef((props, ref) => { ); }); -CheckboxField.defaultProps = { - disabled: false, - helpText: null, - id: undefined, - isLabelVisible: true, - labelPosition: 'after', - required: false, - validationState: null, - validationText: null, -}; - -CheckboxField.propTypes = { - /** - * If `true`, the input will be disabled. - */ - disabled: PropTypes.bool, - /** - * Optional help text. - */ - helpText: PropTypes.node, - /** - * ID of the `` HTML element. - * - * Also serves as base for ids of nested elements: - * * `__label` - * * `__labelText` - * * `__helpText` - * * `__validationText` - */ - id: PropTypes.string, - /** - * If `false`, the label will be visually hidden (but remains accessible by assistive - * technologies). - */ - isLabelVisible: PropTypes.bool, - /** - * Checkbox field label. - */ - label: PropTypes.string.isRequired, - /** - * Placement of the label relative to the input. - */ - labelPosition: PropTypes.oneOf(['before', 'after']), - /** - * If `true`, the input will be required. - */ - required: PropTypes.bool, - /** - * Alter the field to provide feedback based on validation result. - */ - validationState: PropTypes.oneOf(['invalid', 'valid', 'warning']), - /** - * Validation message to be displayed. - */ - validationText: PropTypes.node, -}; - export const CheckboxFieldWithGlobalProps = withGlobalProps(CheckboxField, 'CheckboxField'); export default CheckboxFieldWithGlobalProps; diff --git a/src/lib/components/CheckboxField/CheckboxField.types.ts b/src/lib/components/CheckboxField/CheckboxField.types.ts new file mode 100644 index 00000000..f1cd013e --- /dev/null +++ b/src/lib/components/CheckboxField/CheckboxField.types.ts @@ -0,0 +1,49 @@ +export interface CheckboxFieldProps { + /** + * Rest of the props. + */ + [key: string]: unknown; + /** + * If `true`, the input will be disabled. + */ + disabled?: boolean; + /** + * Optional help text. + */ + helpText?: React.ReactNode; + /** + * ID of the `` HTML element. + * + * Also serves as base for ids of nested elements: + * * `__label` + * * `__labelText` + * * `__helpText` + * * `__validationText` + */ + id?: string; + /** + * If `false`, the label will be visually hidden (but remains accessible by assistive + * technologies). + */ + isLabelVisible?: boolean; + /** + * Checkbox field label. + */ + label: string; + /** + * Placement of the label relative to the input. + */ + labelPosition?: Position; + /** + * If `true`, the input will be required. + */ + required?: boolean; + /** + * Alter the field to provide feedback based on validation result. + */ + validationState?: Validation; + /** + * Validation message to be displayed. + */ + validationText?: React.ReactNode; +} diff --git a/src/lib/components/FileInputField/FileInputField.test.tsx b/src/lib/components/FileInputField/FileInputField.test.tsx index a7e21f8f..36f9e6d0 100644 --- a/src/lib/components/FileInputField/FileInputField.test.tsx +++ b/src/lib/components/FileInputField/FileInputField.test.tsx @@ -6,18 +6,18 @@ import { within, } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { disabledPropTest } from '../../../../../tests/propTests/disabledPropTest'; -import { refPropTest } from '../../../../../tests/propTests/refPropTest'; -import { fullWidthPropTest } from '../../../../../tests/propTests/fullWidthPropTest'; -import { helpTextPropTest } from '../../../../../tests/propTests/helpTextPropTest'; -import { formLayoutProviderTest } from '../../../../../tests/providerTests/formLayoutProviderTest'; -import { isLabelVisible } from '../../../../../tests/propTests/isLabelVisible'; -import { labelPropTest } from '../../../../../tests/propTests/labelPropTest'; -import { layoutPropTest } from '../../../../../tests/propTests/layoutPropTest'; -import { requiredPropTest } from '../../../../../tests/propTests/requiredPropTest'; -import { validationStatePropTest } from '../../../../../tests/propTests/validationStatePropTest'; -import { validationTextPropTest } from '../../../../../tests/propTests/validationTextPropTest'; -import { FileInputField } from '../FileInputField'; +import { disabledPropTest } from '../../../../tests/propTests/disabledPropTest'; +import { refPropTest } from '../../../../tests/propTests/refPropTest'; +import { fullWidthPropTest } from '../../../../tests/propTests/fullWidthPropTest'; +import { helpTextPropTest } from '../../../../tests/propTests/helpTextPropTest'; +import { formLayoutProviderTest } from '../../../../tests/providerTests/formLayoutProviderTest'; +import { isLabelVisible } from '../../../../tests/propTests/isLabelVisible'; +import { labelPropTest } from '../../../../tests/propTests/labelPropTest'; +import { layoutPropTest } from '../../../../tests/propTests/layoutPropTest'; +import { requiredPropTest } from '../../../../tests/propTests/requiredPropTest'; +import { validationStatePropTest } from '../../../../tests/propTests/validationStatePropTest'; +import { validationTextPropTest } from '../../../../tests/propTests/validationTextPropTest'; +import { FileInputField } from './FileInputField'; const mandatoryProps = { label: 'label', @@ -26,11 +26,11 @@ const mandatoryProps = { describe('rendering', () => { formLayoutProviderTest(); - it.each([ - ...disabledPropTest, - ...refPropTest(React.createRef()), - ...fullWidthPropTest, - ...helpTextPropTest, + it.each([ + ...(disabledPropTest as unknown as TestingProps[]), + ...(refPropTest(React.createRef()) as unknown as TestingProps[]), + ...(fullWidthPropTest as unknown as TestingProps[]), + ...(helpTextPropTest as unknown as TestingProps[]), [ { helpText: 'help text', @@ -45,12 +45,12 @@ describe('rendering', () => { expect(rootElement).toHaveAttribute('id', 'id__label'); }, ], - ...isLabelVisible, - ...labelPropTest, - ...layoutPropTest, - ...requiredPropTest, - ...validationStatePropTest, - ...validationTextPropTest, + ...(isLabelVisible as unknown as TestingProps[]), + ...(labelPropTest as unknown as TestingProps[]), + ...(layoutPropTest as unknown as TestingProps[]), + ...(requiredPropTest as unknown as TestingProps[]), + ...(validationStatePropTest as unknown as TestingProps[]), + ...(validationTextPropTest as unknown as TestingProps[]), ])('renders with props: "%s"', (testedProps, assert) => { const dom = render(( { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); diff --git a/src/lib/components/FileInputField/FileInputField.tsx b/src/lib/components/FileInputField/FileInputField.tsx index 63993e4c..8461c5f3 100644 --- a/src/lib/components/FileInputField/FileInputField.tsx +++ b/src/lib/components/FileInputField/FileInputField.tsx @@ -1,5 +1,6 @@ -import PropTypes from 'prop-types'; -import React, { useContext } from 'react'; +import React, { + useContext, +} from 'react'; import { withGlobalProps } from '../../provider'; import { classNames } from '../../utils/classNames'; import { getRootValidationStateClassName } from '../_helpers/getRootValidationStateClassName'; @@ -7,22 +8,22 @@ import { resolveContextOrProp } from '../_helpers/resolveContextOrProp'; import { transferProps } from '../_helpers/transferProps'; import { FormLayoutContext } from '../FormLayout'; import styles from './FileInputField.scss'; +import { FileInputFieldProps } from './FileInputField.types'; -export const FileInputField = React.forwardRef((props, ref) => { - const { - disabled, - fullWidth, - helpText, - id, - isLabelVisible, - label, - layout, - required, - validationState, - validationText, - ...restProps - } = props; - +export const FileInputField: React.FunctionComponent = React.forwardRef(({ + disabled = false, + fullWidth = false, + helpText, + id, + isLabelVisible = true, + label, + layout = 'vertical', + required = false, + validationState, + validationText, + ...restProps +}, ref) => { const context = useContext(FormLayoutContext); return ( @@ -82,72 +83,6 @@ export const FileInputField = React.forwardRef((props, ref) => { ); }); -FileInputField.defaultProps = { - disabled: false, - fullWidth: false, - helpText: null, - id: undefined, - isLabelVisible: true, - layout: 'vertical', - required: false, - validationState: null, - validationText: null, -}; - -FileInputField.propTypes = { - /** - * If `true`, the input will be disabled. - */ - disabled: PropTypes.bool, - /** - * If `true`, the field will span the full width of its parent. - */ - fullWidth: PropTypes.bool, - /** - * Optional help text. - */ - helpText: PropTypes.node, - /** - * ID of the `` HTML element. - * - * Also serves as base for ids of nested elements: - * * `__label` - * * `__labelText` - * * `__helpText` - * * `__validationText` - */ - id: PropTypes.string, - /** - * If `false`, the label will be visually hidden (but remains accessible by assistive - * technologies). - */ - isLabelVisible: PropTypes.bool, - /** - * Text field label. - */ - label: PropTypes.string.isRequired, - /** - * Layout of the field. - * - * Ignored if the component is rendered within `FormLayout` component - * as the value is inherited in such case. - * - */ - layout: PropTypes.oneOf(['horizontal', 'vertical']), - /** - * If `true`, the input will be required. - */ - required: PropTypes.bool, - /** - * Alter the field to provide feedback based on validation result. - */ - validationState: PropTypes.oneOf(['invalid', 'valid', 'warning']), - /** - * Validation message to be displayed. - */ - validationText: PropTypes.node, -}; - export const FileInputFieldWithGlobalProps = withGlobalProps(FileInputField, 'FileInputField'); export default FileInputFieldWithGlobalProps; diff --git a/src/lib/components/FileInputField/FileInputField.types.tsx b/src/lib/components/FileInputField/FileInputField.types.tsx new file mode 100644 index 00000000..319f33e7 --- /dev/null +++ b/src/lib/components/FileInputField/FileInputField.types.tsx @@ -0,0 +1,57 @@ +export interface FileInputFieldProps { + /** + * Rest of the props. + */ + [key: string]: unknown; + /** + * If `true`, the input will be disabled. + */ + disabled?: boolean; + /** + * If `true`, the field will span the full width of its parent. + */ + fullWidth?: boolean; + /** + * Optional help text. + */ + helpText?: React.ReactNode; + /** + * ID of the `` HTML element. + * + * Also serves as base for ids of nested elements: + * * `__label` + * * `__labelText` + * * `__helpText` + * * __validationText + */ + id?: string; + /** + * If `false`, the label will be visually hidden (but remains accessible by assistive + * technologies). + */ + isLabelVisible?: boolean; + /** + * Text field label. + */ + label: string; + /** + * Layout of the field. + * + * Ignored if the component is rendered within `FormLayout` component + * as the value is inherited in such case. + * + */ + layout?: Layout; + /** + * If `true`, the input will be required. + */ + required?: boolean; + /** + * Alter the field to provide feedback based on validation result. + */ + validationState?: Validation; + /** + * * Validation message to be displayed. + */ + validationText?: React.ReactNode; +} diff --git a/src/lib/components/FormLayout/FormLayout.test.tsx b/src/lib/components/FormLayout/FormLayout.test.tsx index 02f577bd..5870c9ff 100644 --- a/src/lib/components/FormLayout/FormLayout.test.tsx +++ b/src/lib/components/FormLayout/FormLayout.test.tsx @@ -3,15 +3,15 @@ import { render, within, } from '@testing-library/react'; -import { childrenEmptyPropTest } from '../../../../../tests/propTests/childrenEmptyPropTest'; -import { CheckboxField } from '../../CheckboxField'; -import { Radio } from '../../Radio'; -import { SelectField } from '../../SelectField'; -import { TextArea } from '../../TextArea'; -import { TextField } from '../../TextField'; -import { Toggle } from '../../Toggle'; -import { FormLayout } from '../FormLayout'; -import { FormLayoutCustomField } from '../FormLayoutCustomField'; +import { childrenEmptyPropTest } from '../../../../tests/propTests/childrenEmptyPropTest'; +import { CheckboxField } from '../CheckboxField/CheckboxField'; +import { Radio } from '../Radio/Radio'; +import { SelectField } from '../SelectField/SelectField'; +import { TextArea } from '../TextArea/TextArea'; +import { TextField } from '../TextField/TextField'; +import { Toggle } from '../Toggle/Toggle'; +import { FormLayout } from './FormLayout'; +import { FormLayoutCustomField } from './FormLayoutCustomField'; const defaultProps = { children: content, @@ -26,7 +26,7 @@ describe('rendering', () => { expect(dom.container.firstChild).toBeNull(); }); - it.each([ + it.each([ [ { autoWidth: true }, (rootElement) => expect(rootElement).toHaveClass('isRootAutoWidth'), @@ -35,7 +35,7 @@ describe('rendering', () => { { autoWidth: false }, (rootElement) => expect(rootElement).not.toHaveClass('isRootAutoWidth'), ], - ...childrenEmptyPropTest, + ...(childrenEmptyPropTest as unknown as TestingProps[]), [ { children: other content text }, (rootElement) => expect(within(rootElement).getByText('other content text')), @@ -137,6 +137,6 @@ describe('rendering', () => { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); diff --git a/src/lib/components/FormLayout/FormLayout.tsx b/src/lib/components/FormLayout/FormLayout.tsx index 1839989a..95ef475c 100644 --- a/src/lib/components/FormLayout/FormLayout.tsx +++ b/src/lib/components/FormLayout/FormLayout.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React from 'react'; import { withGlobalProps } from '../../provider'; import { transferProps } from '../_helpers/transferProps'; @@ -6,10 +5,9 @@ import { classNames } from '../../utils/classNames'; import { isChildrenEmpty } from '../_helpers/isChildrenEmpty'; import { FormLayoutContext } from './FormLayoutContext'; import styles from './FormLayout.scss'; +import { FormLayoutProps } from './FormLayout.types'; -const PREDEFINED_LABEL_WIDTH_VALUES = ['auto', 'default', 'limited']; - -export const FormLayout = ({ +export const FormLayout: React.FunctionComponent = ({ autoWidth, children, fieldLayout, @@ -20,9 +18,12 @@ export const FormLayout = ({ return null; } - const hasCustomLabelWidth = !PREDEFINED_LABEL_WIDTH_VALUES.includes(labelWidth); + const PREDEFINED_LABEL_WIDTH_VALUES = ['auto', 'default', 'limited']; + + const hasCustomLabelWidth = !labelWidth + || !PREDEFINED_LABEL_WIDTH_VALUES.includes(labelWidth); - const fieldLayoutClass = (layout) => { + const fieldLayoutClass = (layout: FormLayoutProps['fieldLayout']) => { if (layout === 'horizontal') { return styles.isRootFieldLayoutHorizontal; } @@ -30,7 +31,7 @@ export const FormLayout = ({ return styles.isRootFieldLayoutVertical; }; - const labelWidthClass = (width) => { + const labelWidthClass = (width: FormLayoutProps['labelWidth']) => { if (hasCustomLabelWidth) { return styles.hasRootLabelWidthCustom; } @@ -55,7 +56,7 @@ export const FormLayout = ({ autoWidth && styles.isRootAutoWidth, fieldLayout === 'horizontal' && labelWidthClass(labelWidth), )} - {...hasCustomLabelWidth ? { style: { '--rui-custom-label-width': labelWidth } } : {}} + {...hasCustomLabelWidth ? { style: { '--rui-custom-label-width': labelWidth } as React.CSSProperties } : {}} > __field` + * * `__label` + */ + id?: string, + /** + * Size of contained form field used to properly align label. + */ + innerFieldSize?: Size, + /** + * Optional label of the field. + */ + label?: string, + /** + * Optional ID of labeled field to keep accessibility features. Only available if `label` is set. + */ + labelForId?: string, + /** + * If `true`, label will be styled as required. + */ + required?: boolean, + /** + * Alter the field to provide feedback based on validation result. + */ + validationState?: Validation, +} diff --git a/src/lib/components/FormLayout/FormLayoutContext.ts b/src/lib/components/FormLayout/FormLayoutContext.ts index cb7d6e33..19088c57 100644 --- a/src/lib/components/FormLayout/FormLayoutContext.ts +++ b/src/lib/components/FormLayout/FormLayoutContext.ts @@ -1,3 +1,3 @@ import React from 'react'; -export const FormLayoutContext = React.createContext(null); +export const FormLayoutContext = React.createContext(undefined); diff --git a/src/lib/components/FormLayout/FormLayoutCustomField.test.tsx b/src/lib/components/FormLayout/FormLayoutCustomField.test.tsx index 9e89ffab..fce97f0a 100644 --- a/src/lib/components/FormLayout/FormLayoutCustomField.test.tsx +++ b/src/lib/components/FormLayout/FormLayoutCustomField.test.tsx @@ -3,20 +3,20 @@ import { render, within, } from '@testing-library/react'; -import { childrenEmptyPropTest } from '../../../../../tests/propTests/childrenEmptyPropTest'; -import { fullWidthPropTest } from '../../../../../tests/propTests/fullWidthPropTest'; -import { labelPropTest } from '../../../../../tests/propTests/labelPropTest'; -import { requiredPropTest } from '../../../../../tests/propTests/requiredPropTest'; -import { validationStatePropTest } from '../../../../../tests/propTests/validationStatePropTest'; -import { FormLayoutContext } from '../FormLayoutContext'; -import { FormLayoutCustomField } from '../FormLayoutCustomField'; +import { childrenEmptyPropTest } from '../../../../tests/propTests/childrenEmptyPropTest'; +import { fullWidthPropTest } from '../../../../tests/propTests/fullWidthPropTest'; +import { labelPropTest } from '../../../../tests/propTests/labelPropTest'; +import { requiredPropTest } from '../../../../tests/propTests/requiredPropTest'; +import { validationStatePropTest } from '../../../../tests/propTests/validationStatePropTest'; +import { FormLayoutCustomField } from './FormLayoutCustomField'; +import { FormLayoutContext } from './FormLayoutContext'; const defaultProps = { children: 'content', }; describe('rendering', () => { - it.each([ + it.each([ [ { layout: 'vertical' }, (rootElement) => expect(rootElement).toHaveClass('isRootLayoutVertical'), @@ -34,11 +34,11 @@ describe('rendering', () => { )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); - it.each([ - ...childrenEmptyPropTest, + it.each([ + ...(childrenEmptyPropTest as unknown as TestingProps[]), [ { children:
other content text
}, (rootElement) => expect(within(rootElement).getByText('other content text')), @@ -51,7 +51,7 @@ describe('rendering', () => { { disabled: false }, (rootElement) => expect(rootElement).not.toHaveClass('isRootDisabled'), ], - ...fullWidthPropTest, + ...(fullWidthPropTest as unknown as TestingProps[]), [ { id: 'id', @@ -75,7 +75,7 @@ describe('rendering', () => { { innerFieldSize: 'large' }, (rootElement) => expect(rootElement).toHaveClass('isRootSizeLarge'), ], - ...labelPropTest, + ...(labelPropTest as unknown as TestingProps[]), [ { label: 'label', @@ -83,8 +83,8 @@ describe('rendering', () => { }, (rootElement) => expect(within(rootElement).getByText('label')).toHaveAttribute('for', 'label-for-id'), ], - ...requiredPropTest, - ...validationStatePropTest, + ...(requiredPropTest as unknown as TestingProps[]), + ...(validationStatePropTest as unknown as TestingProps[]), ])('renders with props: "%s"', (testedProps, assert) => { const dom = render(( { /> )); - assert(dom.container.firstChild); + assert(dom.container.firstChild as HTMLElement); }); }); diff --git a/src/lib/components/FormLayout/FormLayoutCustomField.tsx b/src/lib/components/FormLayout/FormLayoutCustomField.tsx index 1f966b28..93a53d81 100644 --- a/src/lib/components/FormLayout/FormLayoutCustomField.tsx +++ b/src/lib/components/FormLayout/FormLayoutCustomField.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React, { useContext } from 'react'; import { withGlobalProps } from '../../provider'; import { transferProps } from '../_helpers/transferProps'; @@ -8,8 +7,9 @@ import { getRootValidationStateClassName } from '../_helpers/getRootValidationSt import { isChildrenEmpty } from '../_helpers/isChildrenEmpty'; import { FormLayoutContext } from './FormLayoutContext'; import styles from './FormLayoutCustomField.scss'; +import { FormLayoutCustomFieldProps } from './FormLayout.types'; -const renderLabel = (id, label, labelForId) => { +const renderLabel = (id: FormLayoutCustomFieldProps['id'], label: FormLayoutCustomFieldProps['label'], labelForId: FormLayoutCustomFieldProps['labelForId']) => { if (labelForId && label) { return (