diff --git a/package.json b/package.json index f694c4c68..a96598931 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,6 @@ "jscodeshift": "^0.11.0", "mockdate": "^3.0.2", "plop": "^2.4.0", - "prop-types": "15.7.2", "react": "17.0.2", "react-color": "^2.18.1", "react-dom": "17.0.2", diff --git a/rollup.config.js b/rollup.config.js index ab3f7b3fe..6e9d2ee56 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -15,7 +15,6 @@ const PEER_DEPENDENCIES = { const GLOBALS = { ...PEER_DEPENDENCIES, - "prop-types": "PropTypes", "react-windowed-select": "components", "@babel/runtime/helpers/typeof": "typeof", "@babel/runtime/helpers/defineProperty": "defineProperty", @@ -54,7 +53,7 @@ const CORE_PLUGINS = [ commonjs({ /* include: include all items in node_modules folders (in entire monorepo) */ include: [/node_modules/], - /* namedExports: sometimes commonjs can't resolve named exports from certain libraries, + /* namedExports: sometimes commonjs can't resolve named exports from certain libraries, ex: import {exportName} from "package-name"; => exportName module not found in those cases, it needs to be added as ["package-name"]: "exportName" here */ namedExports: { diff --git a/src/BrandedNavBar/MobileMenu.tsx b/src/BrandedNavBar/MobileMenu.tsx index 3003d3990..41b1b9a23 100644 --- a/src/BrandedNavBar/MobileMenu.tsx +++ b/src/BrandedNavBar/MobileMenu.tsx @@ -8,7 +8,6 @@ import { BrandingText } from "../Branding"; import { DropdownLink, DropdownText } from "../DropdownMenu"; import { Icon } from "../Icon"; import { Link } from "../Link"; -import { LinkProps } from "../Link/Link"; import { addStyledProps } from "../StyledProps"; import NulogyLogo from "./NulogyLogo"; import { TriggerFunctionProps } from "./TriggerFunctionProps"; @@ -163,7 +162,7 @@ const getSubMenuHeading = (layer, name) => type ThemeColorObject = { textColor?: string; background?: string; - logoColor?: string; + logoColor?: "white" | "blue"; }; type MenuItem = { @@ -237,7 +236,7 @@ const BaseMobileMenu: React.FC> = ( }) => ( ); -BaseMobileMenu.propTypes = { - menuData: PropTypes.shape({ - primaryMenu: PropTypes.arrayOf(PropTypes.shape({})), - secondaryMenu: PropTypes.arrayOf(PropTypes.shape({})), - }), - subtext: PropTypes.string, - includeSubtext: PropTypes.bool, - closeMenu: PropTypes.func, - themeColorObject: PropTypes.shape(ThemeColorObjectPropTypes), -}; - BaseMobileMenu.defaultProps = { menuData: null, subtext: null, diff --git a/src/NavBar/NavBar.tsx b/src/NavBar/NavBar.tsx index c982f9495..6120dc660 100644 --- a/src/NavBar/NavBar.tsx +++ b/src/NavBar/NavBar.tsx @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; import styled from "styled-components"; import { themeGet } from "@styled-system/theme-get"; import ReactResizeDetector from "react-resize-detector"; @@ -120,22 +119,6 @@ const MediumNavBar: React.FC> = ({ ); }; -export const MenuDataPropTypes = { - primaryMenu: PropTypes.arrayOf(isValidMenuItem), - secondaryMenu: PropTypes.arrayOf(isValidMenuItem), - search: PropTypes.shape({ - onSubmit: PropTypes.func, - }), -}; - -MediumNavBar.propTypes = { - subtext: PropTypes.string, - brandingLinkHref: PropTypes.string, - menuData: PropTypes.shape(MenuDataPropTypes), - brandingLinkTo: PropTypes.string, - themeColor: PropTypes.oneOf(["blue", "white"]), -}; - MediumNavBar.defaultProps = { subtext: null, brandingLinkHref: "/", @@ -192,10 +175,6 @@ export const MenuIcon = ({ isOpen }) => { return ; }; -MenuIcon.propTypes = { - isOpen: PropTypes.bool, -}; - MenuIcon.defaultProps = { isOpen: false, }; @@ -219,13 +198,6 @@ const NavBar = (props) => ( ); -NavBar.propTypes = { - menuData: PropTypes.shape(MenuDataPropTypes), - className: PropTypes.string, - breakpointUpper: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - themeColor: PropTypes.oneOf(["blue", "white"]), -}; - NavBar.defaultProps = { menuData: null, className: undefined, diff --git a/src/NavBar/NavBarDropdownMenu.tsx b/src/NavBar/NavBarDropdownMenu.tsx index 60f215d93..9b21c031c 100644 --- a/src/NavBar/NavBarDropdownMenu.tsx +++ b/src/NavBar/NavBarDropdownMenu.tsx @@ -1,6 +1,5 @@ // @ts-nocheck import React from "react"; -import PropTypes from "prop-types"; import { Manager, Reference, Popper } from "react-popper"; import { DetectOutsideClick, withMenuState, PopperArrow } from "../utils"; import DropdownMenuContainer from "../DropdownMenu/DropdownMenuContainer"; @@ -129,22 +128,6 @@ class StatelessNavBarDropdownMenu extends React.Component { } /* eslint-enable react/destructuring-assignment */ -StatelessNavBarDropdownMenu.propTypes = { - children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, - trigger: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired, - menuState: PropTypes.shape({ - isOpen: PropTypes.bool, - openMenu: PropTypes.func, - closeMenu: PropTypes.func, - toggleMenu: PropTypes.func, - }).isRequired, - showArrow: PropTypes.bool, - placement: PropTypes.oneOf(["bottom-start", "right-start"]), - modifiers: PropTypes.shape({}), - triggerTogglesMenuState: PropTypes.bool, - dropdownMenuContainerEventHandlers: PropTypes.func, -}; - StatelessNavBarDropdownMenu.defaultProps = { showArrow: true, placement: "bottom-start", @@ -155,11 +138,6 @@ StatelessNavBarDropdownMenu.defaultProps = { const NavBarDropdownMenu = withMenuState(StatelessNavBarDropdownMenu); -NavBarDropdownMenu.propTypes = { - showDelay: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - hideDelay: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), -}; - NavBarDropdownMenu.defaultProps = { showDelay: "0", hideDelay: "100", diff --git a/src/NavBar/SmallNavBar.tsx b/src/NavBar/SmallNavBar.tsx index 0c082fc9d..429fa3245 100644 --- a/src/NavBar/SmallNavBar.tsx +++ b/src/NavBar/SmallNavBar.tsx @@ -1,6 +1,5 @@ // @ts-nocheck import React from "react"; -import PropTypes from "prop-types"; import { Branding } from "../Branding"; import { Flex } from "../Flex"; import theme from "../theme"; @@ -10,7 +9,6 @@ import MobileMenu from "./MobileMenu"; import { BrandingLink, getThemeColor, - MenuDataPropTypes, MenuIcon, MobileMenuTrigger, NavBarBackground, @@ -95,21 +93,6 @@ class SmallNavBarNoState extends React.Component { } } -SmallNavBarNoState.propTypes = { - menuState: PropTypes.shape({ - isOpen: PropTypes.bool, - toggleMenu: PropTypes.func, - closeMenu: PropTypes.func, - }).isRequired, - menuData: PropTypes.shape(MenuDataPropTypes), - subtext: PropTypes.string, - brandingLinkHref: PropTypes.string, - brandingLinkTo: PropTypes.string, - breakpointLower: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - width: PropTypes.number, - themeColor: PropTypes.oneOf(["blue", "white"]), -}; - SmallNavBarNoState.defaultProps = { menuData: null, subtext: null, diff --git a/src/NavBar/SubMenuTrigger.tsx b/src/NavBar/SubMenuTrigger.tsx index e4a332cb2..608511d47 100644 --- a/src/NavBar/SubMenuTrigger.tsx +++ b/src/NavBar/SubMenuTrigger.tsx @@ -1,6 +1,5 @@ import React from "react"; import styled from "styled-components"; -import PropTypes from "prop-types"; import theme from "../theme"; import { Icon } from "../Icon"; import NavBarDropdownMenu from "./NavBarDropdownMenu"; @@ -50,11 +49,6 @@ const SubMenuTriggerButton = React.forwardRef(({ )); -SubMenuTriggerButton.propTypes = { - name: PropTypes.string.isRequired, - isOpen: PropTypes.bool, -}; - SubMenuTriggerButton.defaultProps = { isOpen: false, }; @@ -83,12 +77,6 @@ const SubMenuTrigger = (props) => { ); }; -SubMenuTrigger.propTypes = { - name: PropTypes.string.isRequired, - menuData: PropTypes.arrayOf(PropTypes.shape({})), - onItemClick: PropTypes.func, -}; - SubMenuTrigger.defaultProps = { menuData: null, onItemClick: null, diff --git a/src/NavBar/isValidMenuItem.tsx b/src/NavBar/isValidMenuItem.tsx index 466596d72..e058cb3d7 100644 --- a/src/NavBar/isValidMenuItem.tsx +++ b/src/NavBar/isValidMenuItem.tsx @@ -1,5 +1,3 @@ -import PropTypes from "prop-types"; - const isValidMenuItem = function validArrayItem(arr, idx, componentName, location, propFullName) { const obj = arr[idx]; @@ -9,19 +7,6 @@ const isValidMenuItem = function validArrayItem(arr, idx, componentName, locatio ); } - PropTypes.checkPropTypes( - { - name: PropTypes.node.isRequired, - ariaLabel: PropTypes.string, - href: PropTypes.string, - items: PropTypes.arrayOf(isValidMenuItem), - render: PropTypes.func, - }, - obj, - propFullName, - componentName - ); - let numberOfDefiningKeys = 0; const definingKeys = ["href", "items", "render"]; const keys = Object.keys(obj); diff --git a/src/NavBarSearch/NavBarSearch.js b/src/NavBarSearch/NavBarSearch.js index 9e180c99a..6833d1688 100644 --- a/src/NavBarSearch/NavBarSearch.js +++ b/src/NavBarSearch/NavBarSearch.js @@ -1,6 +1,5 @@ import React from "react"; import styled from "styled-components"; -import PropTypes from "prop-types"; import { darken, transparentize } from "polished"; import { useTranslation } from "react-i18next"; import { Flex } from "../Flex"; @@ -73,11 +72,6 @@ const NavBarSearch = styled(BaseNavBarSearch)({ }, }); -BaseNavBarSearch.propTypes = { - name: PropTypes.string, - onSubmit: PropTypes.func, -}; - BaseNavBarSearch.defaultProps = { name: "global-search", onSubmit: () => {}, diff --git a/src/Overlay/Overlay.tsx b/src/Overlay/Overlay.tsx index cf70c12eb..980a50b12 100644 --- a/src/Overlay/Overlay.tsx +++ b/src/Overlay/Overlay.tsx @@ -2,28 +2,21 @@ import styled from "styled-components"; import { transparentize } from "polished"; import { Flex } from "../Flex"; import { FlexProps } from "../Flex/Flex"; -import { DefaultNDSThemeType } from "../theme.type"; -import CSSObject from "styled-components"; -type OverlayProps = FlexProps & { +interface Props extends FlexProps { dark?: boolean; - theme?: DefaultNDSThemeType; -}; +} -const Overlay: React.FC> = styled(Flex)( - ({ dark, theme }: OverlayProps) => ({ - top: 0, - left: 0, - right: 0, - bottom: 0, - zIndex: theme.zIndices.overlay, - backgroundColor: dark ? transparentize(0.5, theme.colors.blackBlue) : transparentize(0.05, theme.colors.white), - }) -); -Overlay.defaultProps = { +const Overlay = styled(Flex)(({ dark = false, theme }) => ({ position: "fixed", justifyContent: "center", alignItems: "center", - dark: false, -}; + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: theme.zIndices.overlay, + backgroundColor: dark ? transparentize(0.5, theme.colors.blackBlue) : transparentize(0.05, theme.colors.white), +})); + export default Overlay; diff --git a/src/Pagination/NextButton.tsx b/src/Pagination/NextButton.tsx index 242780fb6..e8e90b918 100644 --- a/src/Pagination/NextButton.tsx +++ b/src/Pagination/NextButton.tsx @@ -1,5 +1,4 @@ import React, { ReactNode } from "react"; -import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Icon } from "../Icon"; import PaginationButton from "./PaginationButton"; @@ -20,16 +19,4 @@ const NextButton = ({ disabled, onClick, label, ariaLabel }: NextButtonProps) => ); }; -NextButton.propTypes = { - disabled: PropTypes.bool, - onClick: PropTypes.func, - label: PropTypes.node, - ariaLabel: PropTypes.string, -}; - -NextButton.defaultProps = { - disabled: false, - onClick: null, -}; - export default NextButton; diff --git a/src/Pagination/Pagination.tsx b/src/Pagination/Pagination.tsx index aa84d3f35..73784a94c 100644 --- a/src/Pagination/Pagination.tsx +++ b/src/Pagination/Pagination.tsx @@ -1,5 +1,4 @@ import React, { ReactNode, RefObject } from "react"; -import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { flushSync } from "react-dom"; import { Flex } from "../Flex"; @@ -41,11 +40,11 @@ interface PaginationProps extends FlexProps { } function Pagination({ - currentPage, - totalPages, onNext, onPrevious, onSelectPage, + currentPage, + totalPages, nextAriaLabel, nextLabel, previousAriaLabel, @@ -127,28 +126,4 @@ function Pagination({ ); } -Pagination.propTypes = { - currentPage: PropTypes.number.isRequired, - totalPages: PropTypes.number.isRequired, - onNext: PropTypes.func, - onPrevious: PropTypes.func, - onSelectPage: PropTypes.func, - nextLabel: PropTypes.node, - nextAriaLabel: PropTypes.string, - previousLabel: PropTypes.node, - previousAriaLabel: PropTypes.string, - "aria-label": PropTypes.string, -}; - -Pagination.defaultProps = { - onNext: null, - onPrevious: null, - onSelectPage: null, - nextLabel: undefined, - nextAriaLabel: undefined, - previousLabel: undefined, - previousAriaLabel: undefined, - "aria-label": undefined, -}; - export default Pagination; diff --git a/src/Pagination/PreviousButton.tsx b/src/Pagination/PreviousButton.tsx index b95bd2599..d3c3ff693 100644 --- a/src/Pagination/PreviousButton.tsx +++ b/src/Pagination/PreviousButton.tsx @@ -1,5 +1,4 @@ import React, { ReactNode } from "react"; -import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Icon } from "../Icon"; import PaginationButton from "./PaginationButton"; @@ -11,7 +10,7 @@ type PreviousButtonProps = { ariaLabel: string; }; -const PreviousButton = ({ disabled, onClick, label, ariaLabel }: PreviousButtonProps) => { +const PreviousButton = ({ disabled = false, onClick = null, label, ariaLabel }: PreviousButtonProps) => { const { t } = useTranslation(); return ( @@ -20,16 +19,4 @@ const PreviousButton = ({ disabled, onClick, label, ariaLabel }: PreviousButtonP ); }; -PreviousButton.propTypes = { - disabled: PropTypes.bool, - onClick: PropTypes.func, - label: PropTypes.node, - ariaLabel: PropTypes.string, -}; - -PreviousButton.defaultProps = { - disabled: false, - onClick: null, -}; - export default PreviousButton; diff --git a/src/Popper/Popper.tsx b/src/Popper/Popper.tsx index 2c2c33e7b..d131c81dc 100644 --- a/src/Popper/Popper.tsx +++ b/src/Popper/Popper.tsx @@ -1,17 +1,20 @@ // @ts-nocheck -import React, { useState, useEffect, useRef } from "react"; +import React, { useState, useEffect, useRef, LegacyRef } from "react"; import { Manager, Reference, Popper as ReactPopperPopUp } from "react-popper"; import { useTranslation } from "react-i18next"; import { PopperArrow } from "../utils"; + const makeArray = (children) => { if (!Array.isArray(children)) { return [children]; } return children; }; -const wrapInFunction = (x) => (typeof x === "function" ? x : () => x); + +const wrapInFunction = (x: unknown) => (typeof x === "function" ? x : () => x); + type PopperProps = { - ref: any; + children?: React.ReactNode; popperPlacement?: string; defaultOpen?: boolean; showDelay?: string | number; @@ -27,24 +30,25 @@ type PopperProps = { openAriaLabel?: string; closeAriaLabel?: string; }; -const Popper: React.FC> = React.forwardRef( + +const Popper = React.forwardRef, PopperProps>( ( { - popperPlacement, - defaultOpen, id, - showDelay, - hideDelay, trigger, children, - openOnClick, - openOnHover, - modifiers, backgroundColor, borderColor, - showArrow, openAriaLabel, closeAriaLabel, + modifiers, + showDelay = "100", + hideDelay = "350", + defaultOpen = false, + popperPlacement = "bottom", + openOnClick = false, + openOnHover = true, + showArrow = true, }, popperRef ) => { @@ -209,19 +213,5 @@ const Popper: React.FC> = React.forwardRef( ); } ); -Popper.defaultProps = { - showDelay: "100", - hideDelay: "350", - defaultOpen: false, - popperPlacement: "bottom", - id: null, - openOnClick: false, - openOnHover: true, - modifiers: null, - backgroundColor: undefined, - borderColor: undefined, - showArrow: true, - openAriaLabel: undefined, - closeAriaLabel: undefined, -}; + export default Popper; diff --git a/src/Radio/Radio.tsx b/src/Radio/Radio.tsx index db27f325d..6dcf7f4c8 100644 --- a/src/Radio/Radio.tsx +++ b/src/Radio/Radio.tsx @@ -9,7 +9,7 @@ import { DefaultNDSThemeType } from "../theme.type"; import { getSubset, omitSubset } from "../utils/subset"; import { ComponentSize, useComponentSize } from "../NDSProvider/ComponentSizeContext"; -const radioStyle = (theme) => ({ +const radioStyle = (theme: DefaultNDSThemeType) => ({ checked: { disabled: { borderColor: theme.colors.lightGrey, @@ -113,8 +113,10 @@ type RadioProps = NativeInputProps & error?: boolean; }; -const Radio: React.FC> = forwardRef( - ({ className, labelText, disabled, checked, required, error, size, ...props }, ref) => { +type Ref = HTMLInputElement; + +const Radio = forwardRef( + ({ disabled = false, error = false, required = false, className, labelText, checked, size, ...props }, ref) => { const componentSize = useComponentSize(size); const spaceProps = getSubset(props, propTypes.space); const restProps = omitSubset(props, propTypes.space); @@ -144,14 +146,4 @@ const Radio: React.FC> = forwardRef( } ); -Radio.defaultProps = { - checked: undefined, - defaultChecked: undefined, - disabled: false, - error: false, - id: undefined, - className: undefined, - required: false, -}; - export default Radio; diff --git a/src/Radio/RadioGroup.tsx b/src/Radio/RadioGroup.tsx index f972d9054..7d77f92a5 100644 --- a/src/Radio/RadioGroup.tsx +++ b/src/Radio/RadioGroup.tsx @@ -1,38 +1,11 @@ import React, { useContext } from "react"; import { CSSObject, ThemeContext } from "styled-components"; - import { HelpText, RequirementText } from "../FieldLabel"; import { InlineValidation } from "../Validation"; import { Fieldset } from "../Form"; import { DefaultNDSThemeType } from "../theme.type"; import Radio from "./Radio"; -const labelTextStyles = (theme: DefaultNDSThemeType): CSSObject => ({ - fontSize: theme.fontSizes.small, - fontWeight: Number(theme.fontWeights.bold), - lineHeight: theme.lineHeights.smallTextBase, -}); - -const getRadioButtons = (props: any) => { - const radioButtons = React.Children.map(props.children, (radio) => { - const { value, disabled, required, onChange, ...radioProps } = radio.props; - return ( - - ); - }); - return radioButtons; -}; - interface RadioGroupProps { className?: string; id?: string; @@ -45,9 +18,13 @@ interface RadioGroupProps { children?: any; name?: string; disabled?: boolean; + defaultValue?: string; + checkedValue?: string; + default?: boolean; + onChange?: (e: React.ChangeEvent) => void; } -const RadioGroup = ({ +export default function RadioGroup({ className, id, errorMessage, @@ -56,7 +33,7 @@ const RadioGroup = ({ helpText, requirementText, ...props -}: RadioGroupProps) => { +}: RadioGroupProps) { const otherProps = { ...props, errorMessage, errorList }; const themeContext = useContext(ThemeContext); @@ -71,19 +48,31 @@ const RadioGroup = ({ ); -}; +} -RadioGroup.defaultProps = { - errorMessage: null, - errorList: null, - defaultValue: undefined, - checkedValue: undefined, - onChange: undefined, - className: undefined, - id: undefined, - helpText: null, - requirementText: null, - default: false, -}; +const labelTextStyles = (theme: DefaultNDSThemeType): CSSObject => ({ + fontSize: theme.fontSizes.small, + fontWeight: Number(theme.fontWeights.bold), + lineHeight: theme.lineHeights.smallTextBase, +}); -export default RadioGroup; +const getRadioButtons = (props: any) => { + const radioButtons = React.Children.map(props.children, (radio) => { + const { value, disabled, required, onChange, ...radioProps } = radio.props; + return ( + + ); + }); + + return radioButtons; +}; diff --git a/src/RangeContainer/RangeContainer.tsx b/src/RangeContainer/RangeContainer.tsx index 344bbcbdc..828db4418 100644 --- a/src/RangeContainer/RangeContainer.tsx +++ b/src/RangeContainer/RangeContainer.tsx @@ -14,16 +14,20 @@ type RangeContainerProps = { endComponent?: React.ReactNode; size?: ComponentSize; errorMessages?: (string | undefined)[]; + children?: React.ReactNode; }; -const RangeContainer: React.FC> = ({ - labelProps, +const RangeContainer = ({ startComponent, endComponent, errorMessages = [], + labelProps = { + ...FieldLabelDefaultProps, + labelText: "Range", + }, size, ...props -}) => { +}: RangeContainerProps) => { const spaceProps = getSubset(props, propTypes.space); const restProps = omitSubset(props, propTypes.space); @@ -45,14 +49,4 @@ const RangeContainer: React.FC> = ( ); }; -RangeContainer.defaultProps = { - labelProps: { - ...FieldLabelDefaultProps, - labelText: "Range", - }, - startComponent: null, - endComponent: null, - errorMessages: [], -}; - export default RangeContainer; diff --git a/src/Select/Select.tsx b/src/Select/Select.tsx index db67d1297..2b120975b 100644 --- a/src/Select/Select.tsx +++ b/src/Select/Select.tsx @@ -65,47 +65,12 @@ export type NDSSelectProps & CustomProps; -export const SelectDefaultProps = { - autocomplete: true, - disabled: undefined, - defaultValue: undefined, - error: undefined, - errorMessage: undefined, - errorList: undefined, - labelText: undefined, - helpText: undefined, - noOptionsMessage: undefined, - requirementText: undefined, - id: undefined, - initialIsOpen: undefined, - maxHeight: "248px", - menuPosition: "absolute" as MenuPosition, - menuPlacement: "bottom" as MenuPlacement, - multiselect: false, - name: undefined, - onBlur: undefined, - onChange: undefined, - placeholder: undefined, - required: false, - value: undefined, - className: undefined, - classNamePrefix: "ndsSelect", // a prefix is required in react-select top put classes on all buttons to apply style overrides - menuIsOpen: undefined, - onMenuOpen: undefined, - onMenuClose: undefined, - onInputChange: undefined, - components: undefined, - closeMenuOnSelect: true, -}; - const ReactSelect = React.forwardRef( >( { size, - autocomplete, options, labelText, - required, requirementText, helpText, disabled, @@ -114,8 +79,6 @@ const ReactSelect = React.forwardRef( error = !!(errorMessage || errorList), id, initialIsOpen, - maxHeight, - multiselect, onChange, placeholder, value, @@ -123,6 +86,14 @@ const ReactSelect = React.forwardRef( components, "aria-label": ariaLabel, windowThreshold = 300, + autocomplete = true, + maxHeight = "248px", + required = false, + menuPosition = "absolute" as MenuPosition, + menuPlacement = "bottom" as MenuPlacement, + multiselect, + classNamePrefix = "ndsSelect", + closeMenuOnSelect = true, ...props }: NDSSelectProps, ref @@ -190,6 +161,10 @@ const ReactSelect = React.forwardRef( }} aria-label={ariaLabel} options={options} + menuPosition={menuPosition} + menuPlacement={menuPlacement} + classNamePrefix={classNamePrefix} + closeMenuOnSelect={closeMenuOnSelect} {...props} /> @@ -243,10 +218,4 @@ function extractValue(options: NDSOptionType[] | NDSOptionType, isMulti: boolean } } -ReactSelect.defaultProps = { - ...SelectDefaultProps, - windowThreshold: 300, - filterOption: undefined, -}; - export default ReactSelect; diff --git a/src/StatusIndicator/StatusIndicator.tsx b/src/StatusIndicator/StatusIndicator.tsx index 541dfb7ff..adadcc709 100644 --- a/src/StatusIndicator/StatusIndicator.tsx +++ b/src/StatusIndicator/StatusIndicator.tsx @@ -57,28 +57,26 @@ interface Props extends SpaceProps, TypographyProps, FlexboxProps { type?: StatusIndicatorType; } -const StatusIndicator = styled.span(space, typography, flexbox, ({ theme, type }) => ({ - display: "inline-block", - fontWeight: theme.fontWeights.bold, - textTransform: "uppercase", - letterSpacing: ".05em", - borderRadius: theme.space.x1, - ...statusIndicatorStyles(theme)[type], -})); - -StatusIndicator.defaultProps = { - type: StatusIndicatorValues.neutral, - mt: "0", - mr: "0", - mb: "0", - ml: "0", - pt: "0", - pr: "x1", - pb: "0", - pl: "x1", - fontSize: "smaller", - lineHeight: "smallerText", - alignSelf: "center", -}; +const StatusIndicator = styled.span( + ({ theme, type = StatusIndicatorValues.neutral }) => ({ + margin: theme.space.none, + paddingTop: theme.space.none, + paddingRight: theme.space.x1, + paddingBottom: theme.space.none, + paddingLeft: theme.space.x1, + fontSize: theme.fontSizes.smaller, + lineHeight: theme.lineHeights.smallerText, + alignSelf: "center", + display: "inline-block", + fontWeight: theme.fontWeights.bold, + textTransform: "uppercase", + letterSpacing: ".05em", + borderRadius: theme.space.x1, + ...statusIndicatorStyles(theme)[type], + }), + space, + typography, + flexbox +); export default StatusIndicator; diff --git a/src/Switcher/Switch.tsx b/src/Switcher/Switch.tsx index 46dc37352..6a8197b19 100644 --- a/src/Switcher/Switch.tsx +++ b/src/Switcher/Switch.tsx @@ -1,6 +1,5 @@ import React from "react"; import styled from "styled-components"; -import PropTypes from "prop-types"; import { variant } from "styled-system"; import numberFromDimension from "../utils/numberFromDimension"; import { ComponentSize } from "../NDSProvider/ComponentSizeContext"; @@ -62,10 +61,4 @@ const SwitchButton = styled.button( }) ); -Switch.propTypes = { - children: PropTypes.node, - selected: PropTypes.bool, - value: PropTypes.string, -}; - export default Switch; diff --git a/src/Switcher/Switcher.tsx b/src/Switcher/Switcher.tsx index 66302c2a3..0c8a9a4ea 100644 --- a/src/Switcher/Switcher.tsx +++ b/src/Switcher/Switcher.tsx @@ -1,5 +1,4 @@ import React, { ReactElement } from "react"; -import PropTypes from "prop-types"; import { Box } from "../Box"; import FocusManager from "../utils/ts/FocusManager"; import type { ComponentSize } from "../NDSProvider/ComponentSizeContext"; @@ -63,10 +62,4 @@ const Switcher: React.FC> = ({ size, sele ); }; -Switcher.propTypes = { - children: PropTypes.arrayOf(PropTypes.element), - selected: PropTypes.string, - onChange: PropTypes.func, -}; - export default Switcher; diff --git a/src/Table/BaseTable.tsx b/src/Table/BaseTable.tsx index e1cf47638..077dd0876 100644 --- a/src/Table/BaseTable.tsx +++ b/src/Table/BaseTable.tsx @@ -1,12 +1,10 @@ import React from "react"; import styled from "styled-components"; -import PropTypes from "prop-types"; import { space } from "styled-system"; -import propTypes from "@styled-system/prop-types"; import TableHead from "./TableHead"; import TableBody from "./TableBody"; import TableFoot from "./TableFoot"; -import { rowsPropType, RowType, Columns } from "./Table.types"; +import { RowType, Columns } from "./Table.types"; export type BaseTableProps = { columns: Columns; @@ -34,19 +32,19 @@ const StyledTable = styled.table(space, { }); function BaseTable({ - columns, - rows, noRowsContent = "No records have been created for this table.", keyField = "id", - id, - loading, + loading = false, footerRows = [], rowHovers = true, - compact, - className, - stickyHeader, + compact = false, + stickyHeader = false, onRowMouseEnter = () => {}, onRowMouseLeave = () => {}, + columns, + rows, + id, + className, ...props }: BaseTableProps) { return ( @@ -70,35 +68,4 @@ function BaseTable({ ); } -BaseTable.propTypes = { - ...propTypes.space, - columns: PropTypes.any, - rows: PropTypes.any, - noRowsContent: PropTypes.string, - keyField: PropTypes.string, - id: PropTypes.string, - loading: PropTypes.bool, - footerRows: rowsPropType, - rowHovers: PropTypes.bool, - compact: PropTypes.bool, - className: PropTypes.string, - stickyHeader: PropTypes.bool, - onRowMouseEnter: PropTypes.func, - onRowMouseLeave: PropTypes.func, -}; - -BaseTable.defaultProps = { - noRowsContent: "No records have been created for this table.", - keyField: "id", - id: undefined, - loading: false, - footerRows: [], - rowHovers: true, - compact: false, - className: undefined, - stickyHeader: false, - onRowMouseEnter: () => {}, - onRowMouseLeave: () => {}, -}; - export default BaseTable; diff --git a/src/Table/SortingColumnHeader.tsx b/src/Table/SortingColumnHeader.tsx index bfc22f98b..3f0327a56 100644 --- a/src/Table/SortingColumnHeader.tsx +++ b/src/Table/SortingColumnHeader.tsx @@ -1,13 +1,27 @@ import React from "react"; -import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Text } from "../Type"; import { Flex } from "../Flex"; import { ControlIcon } from "../Button"; -const SortingColumnHeader = ({ onChange, label, ascending, active, ariaLabel }) => { +interface SortingColumnHeaderProps { + onChange?: React.MouseEventHandler; + ariaLabel?: string; + label?: string; + ascending?: boolean; + active?: boolean; +} + +function SortingColumnHeader({ + onChange, + label, + ariaLabel, + ascending = false, + active = false, +}: SortingColumnHeaderProps) { const { t } = useTranslation(); const defaultAriaLabel = ascending ? t("sort descending") : t("sort ascending"); + return ( {label} @@ -20,21 +34,6 @@ const SortingColumnHeader = ({ onChange, label, ascending, active, ariaLabel }) /> ); -}; - -SortingColumnHeader.propTypes = { - onChange: PropTypes.func.isRequired, - ariaLabel: PropTypes.string, - label: PropTypes.string, - ascending: PropTypes.bool, - active: PropTypes.bool, -}; - -SortingColumnHeader.defaultProps = { - ariaLabel: null, - label: null, - ascending: false, - active: false, -}; +} export default SortingColumnHeader; diff --git a/src/Table/StatefulTable.tsx b/src/Table/StatefulTable.tsx index 97bdb2e67..efcc9a373 100644 --- a/src/Table/StatefulTable.tsx +++ b/src/Table/StatefulTable.tsx @@ -1,10 +1,28 @@ import React, { Component } from "react"; +import propTypes from "@styled-system/prop-types"; import { Pagination } from "../Pagination"; -import { getSubset } from "../utils/subset"; +import { pick } from "../utils/subset"; import BaseTable, { BaseTableProps } from "./BaseTable"; import { addExpandableControl } from "./addExpandableControl"; import { addSelectableControl } from "./addSelectableControl"; +const propNames = [ + ...Object.keys(propTypes.space), + "columns", + "rows", + "noRowsContent", + "keyField", + "id", + "loading", + "footerRows", + "rowHovers", + "compact", + "className", + "stickyHeader", + "onRowMouseEnter", + "onRowMouseLeave", +]; + export type StatefulTableProps = BaseTableProps & { selectedRows?: string[]; onRowSelectionChange?: (...args: any[]) => any; @@ -36,9 +54,20 @@ type StatefulTableState = { currentPage: number; paginatedRows: any; }; + class StatefulTable extends Component, StatefulTableState> { static defaultProps = { - ...BaseTable.defaultProps, + noRowsContent: "No records have been created for this table.", + keyField: "id", + id: undefined, + loading: false, + footerRows: [], + rowHovers: true, + compact: false, + className: undefined, + stickyHeader: false, + onRowMouseEnter: () => {}, + onRowMouseLeave: () => {}, hasSelectableRows: false, selectedRows: [], isHeaderSelected: false, @@ -224,7 +253,7 @@ class StatefulTable extends Component diff --git a/src/Table/Table.tsx b/src/Table/Table.tsx index 18628d6de..3bbe048ab 100644 --- a/src/Table/Table.tsx +++ b/src/Table/Table.tsx @@ -43,6 +43,7 @@ function Table({ ); } + Table.SortingHeader = SortingColumnHeader; export default Table; diff --git a/src/Table/Table.types.ts b/src/Table/Table.types.ts index 49ed794f1..82b7920a8 100644 --- a/src/Table/Table.types.ts +++ b/src/Table/Table.types.ts @@ -1,5 +1,4 @@ import type { Key } from "react"; -import PropTypes from "prop-types"; export type RowType = any; @@ -23,29 +22,3 @@ export type ColumnType = { } & ({ key: Key; dataKey?: never | undefined } | { dataKey: Key; key?: never | undefined }); export type Columns = ColumnType[]; - -export const columnPropType = PropTypes.shape({ - align: PropTypes.oneOf(["right", "left", "center"]), - label: PropTypes.string, - dataKey: PropTypes.oneOf([PropTypes.string, PropTypes.number]), - key: PropTypes.oneOf([PropTypes.string, PropTypes.number]), - cellFormatter: PropTypes.func, - cellRenderer: PropTypes.func, - headerRenderer: PropTypes.func, - width: PropTypes.string, -}); - -export const rowPropType = PropTypes.objectOf( - PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - PropTypes.bool, - PropTypes.func, - PropTypes.node, - PropTypes.shape({}), - ]) -); - -export const columnsPropType = PropTypes.arrayOf(columnPropType); - -export const rowsPropType = PropTypes.arrayOf(rowPropType); diff --git a/src/Table/TableBody.tsx b/src/Table/TableBody.tsx index 1e92e2bb1..36beeabd8 100644 --- a/src/Table/TableBody.tsx +++ b/src/Table/TableBody.tsx @@ -1,9 +1,7 @@ import React from "react"; -import PropTypes from "prop-types"; import styled from "styled-components"; import { Box } from "../Box"; import { DefaultNDSThemeType } from "../theme.type"; -import { columnsPropType, rowPropType } from "./Table.types"; import TableCell from "./TableCell"; const StyledMessageContainer = styled(Box)(({ theme }) => ({ @@ -97,18 +95,6 @@ const TableBodyRow = ({ ); }; -TableBodyRow.propTypes = { - row: rowPropType.isRequired, - columns: columnsPropType.isRequired, - rowHovers: PropTypes.bool.isRequired, - compact: PropTypes.bool.isRequired, - rowClassName: PropTypes.string, -}; - -TableBodyRow.defaultProps = { - rowClassName: undefined, -}; - const TableMessageContainer = ({ colSpan, children }) => ( @@ -117,17 +103,8 @@ const TableMessageContainer = ({ colSpan, children }) => ( ); -TableMessageContainer.propTypes = { - colSpan: PropTypes.number.isRequired, - children: PropTypes.node.isRequired, -}; - const LoadingContent = ({ colSpan }) => Loading...; -LoadingContent.propTypes = { - colSpan: PropTypes.number.isRequired, -}; - type TableBodyProps = { rows: any[]; columns: any[]; diff --git a/src/Table/TableCell.tsx b/src/Table/TableCell.tsx index 17b57651f..d51bf69ad 100644 --- a/src/Table/TableCell.tsx +++ b/src/Table/TableCell.tsx @@ -1,9 +1,9 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import styled, { CSSObject } from "styled-components"; import { DefaultNDSThemeType } from "../theme.type"; type StyledTableCellProps = { - align?: any; + align?: CSSProperties["textAlign"]; compact?: boolean; theme?: DefaultNDSThemeType; }; @@ -21,14 +21,16 @@ const StyledTableCell: React.FC> = }; } ); + type TableCellProps = { column?: any; row?: any; colSpan?: number; - cellData?: object | React.ReactNode | boolean; + cellData?: Record | React.ReactNode | boolean; compact?: boolean; }; -const TableCell: React.FC> = ({ row, column, colSpan, cellData, compact }) => { + +const TableCell = ({ column = {}, row = {}, cellData = "", colSpan = undefined, compact = false }: TableCellProps) => { const cellRenderer = row.cellRenderer || column.cellRenderer; const { cellFormatter } = column; const isCustomCell = Boolean(cellRenderer); @@ -42,11 +44,5 @@ const TableCell: React.FC> = ({ row, col ); }; -TableCell.defaultProps = { - column: {}, - row: {}, - cellData: "", - colSpan: undefined, - compact: false, -}; + export default TableCell; diff --git a/src/Table/TableFoot.tsx b/src/Table/TableFoot.tsx index 88d6d47c9..b94aee96e 100644 --- a/src/Table/TableFoot.tsx +++ b/src/Table/TableFoot.tsx @@ -1,9 +1,8 @@ import React from "react"; -import PropTypes from "prop-types"; import styled from "styled-components"; import TableCell from "./TableCell"; import StyledTh from "./StyledTh"; -import { columnsPropType, rowsPropType, rowPropType, RowType, Columns } from "./Table.types"; +import { RowType, Columns } from "./Table.types"; const StyledFooterRow = styled.tr(({ theme }) => ({ "&:first-of-type": { @@ -48,19 +47,12 @@ const TableFooterRow = ({ row, columns, loading, compact }) => { ); }; -TableFooterRow.propTypes = { - row: rowPropType.isRequired, - columns: columnsPropType.isRequired, - loading: PropTypes.bool.isRequired, - compact: PropTypes.bool.isRequired, -}; - function TableFoot({ columns, rows, - keyField, - loading, - compact, + keyField = "id", + loading = false, + compact = false, }: { columns: Columns; rows: RowType[]; @@ -71,18 +63,4 @@ function TableFoot({ return {renderRows(rows, columns, keyField, loading, compact)}; } -TableFoot.propTypes = { - columns: columnsPropType.isRequired, - rows: rowsPropType.isRequired, - keyField: PropTypes.string, - loading: PropTypes.bool, - compact: PropTypes.bool, -}; - -TableFoot.defaultProps = { - keyField: "id", - loading: false, - compact: false, -}; - export default TableFoot; diff --git a/src/Table/addExpandableControl.tsx b/src/Table/addExpandableControl.tsx index e8b4b318e..5531a3568 100644 --- a/src/Table/addExpandableControl.tsx +++ b/src/Table/addExpandableControl.tsx @@ -1,13 +1,20 @@ import React from "react"; -import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { ControlIcon } from "../Button"; -import { rowPropType } from "./Table.types"; import { SELECTABLE_COLUMN_DATA_KEY } from "./addSelectableControl"; const EXPANDABLE_COLUMN_DATA_KEY = "expanded"; -const ExpandCell = ({ row, onRowExpansionChange }) => { +type Row = Record>; + +interface ExpandCellProps { + row: Row; + onRowExpansionChange: (row: Row) => void; + collapseAriaLabel?: string; + expandAriaLabel?: string; +} + +const ExpandCell = ({ row, onRowExpansionChange }: ExpandCellProps) => { const expandRowHandler = () => onRowExpansionChange(row); const { t } = useTranslation(); const collapseLabel = row.collapseAriaLabel || t("collapse row"); @@ -25,18 +32,6 @@ const ExpandCell = ({ row, onRowExpansionChange }) => { ); }; -ExpandCell.propTypes = { - row: rowPropType.isRequired, - onRowExpansionChange: PropTypes.func, - collapseAriaLabel: PropTypes.string, - expandAriaLabel: PropTypes.string, -}; - -ExpandCell.defaultProps = { - onRowExpansionChange: null, - collapseAriaLabel: undefined, - expandAriaLabel: undefined, -}; const expandCellRenderer = (onRowExpansionChange) => (props) => ; const addExpandableColumn = ({ columns, onRowExpansionChange }) => { diff --git a/src/Table/addSelectableControl.tsx b/src/Table/addSelectableControl.tsx index 66a3cdc15..81d304ac1 100644 --- a/src/Table/addSelectableControl.tsx +++ b/src/Table/addSelectableControl.tsx @@ -1,8 +1,6 @@ import React from "react"; -import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; import { Checkbox } from "../Checkbox"; -import { rowPropType } from "./Table.types"; export const SELECTABLE_COLUMN_DATA_KEY = "selected"; @@ -24,15 +22,6 @@ const SelectCell = ({ row, onSelectRow }) => { return ; }; -SelectCell.propTypes = { - row: rowPropType.isRequired, - onSelectRow: PropTypes.func, -}; - -SelectCell.defaultProps = { - onSelectRow: null, -}; - const selectCellRenderer = (onSelectRow) => (props) => ; export const addSelectableControl = ({ diff --git a/src/Tabs/Tab.tsx b/src/Tabs/Tab.tsx index 3a765f6cc..9a1abdf2d 100644 --- a/src/Tabs/Tab.tsx +++ b/src/Tabs/Tab.tsx @@ -101,12 +101,10 @@ type TabProps = TabButtonProps & { label?: React.ReactNode; }; -const Tab: React.FC> = React.forwardRef(({ label, ...props }, ref) => ( +const Tab = React.forwardRef(({ label, ...props }, ref) => ( {label} )); -Tab.defaultProps = { - label: null, -}; + export default Tab; diff --git a/src/Tabs/TabScrollIndicator.tsx b/src/Tabs/TabScrollIndicator.tsx index c35ac5888..30f24b1c4 100644 --- a/src/Tabs/TabScrollIndicator.tsx +++ b/src/Tabs/TabScrollIndicator.tsx @@ -1,9 +1,11 @@ -// @ts-nocheck import styled from "styled-components"; import React from "react"; import { useTranslation } from "react-i18next"; import { Icon } from "../Icon"; -const TabScrollIndicatorButton = styled.button(({ side, width, theme }) => ({ + +type Side = "left" | "right"; + +const TabScrollIndicatorButton = styled.button<{ side: Side; width: string | number }>(({ side, width, theme }) => ({ position: "absolute", color: theme.colors.black, top: 0, @@ -37,34 +39,38 @@ const TabScrollIndicatorButton = styled.button(({ side, width, theme }) => ({ opacity: ".5", }, })); -function preventFocusMovement(e) { - e.preventDefault(); -} + type TabScrollIndicatorProps = { - onClick?: (...args: any[]) => any; - side?: "left" | "right"; + onClick?: React.MouseEventHandler; + side?: Side; width?: string | number; ariaLabelLeft?: string; ariaLabelRight?: string; }; + const TabScrollIndicator: React.FC> = ({ - onClick, - side, + side = "left", + width = 40, ariaLabelLeft, ariaLabelRight, + onClick, ...props }) => { const { t } = useTranslation(); - const handleClick = () => { - onClick(side); - }; + const rightArrowLabel = ariaLabelRight || t("next"); const leftArrowLabel = ariaLabelLeft || t("previous"); + + function preventFocusMovement(event: React.MouseEvent) { + event.preventDefault(); + } + return ( ); }; -TabScrollIndicator.defaultProps = { - onClick: () => {}, - side: "left", - width: 40, - ariaLabelLeft: undefined, - ariaLabelRight: undefined, -}; + export default TabScrollIndicator; diff --git a/src/Tabs/TabScrollIndicators.js b/src/Tabs/TabScrollIndicators.js deleted file mode 100644 index 52c372c6f..000000000 --- a/src/Tabs/TabScrollIndicators.js +++ /dev/null @@ -1,178 +0,0 @@ -// @ts-nocheck -import styled from "styled-components"; -import PropTypes from "prop-types"; -import React from "react"; -import smoothscroll from "smoothscroll-polyfill"; -import TabScrollIndicator from "./TabScrollIndicator"; - -const TabScrollIndicatorContainer = styled.div(({ width, theme }) => ({ - position: "absolute", - width, - height: theme.space.x5, -})); - -class TabScrollIndicators extends React.Component { - constructor(props) { - super(props); - - this.state = { - contentHiddenLeft: this.contentHiddenLeft(), - contentHiddenRight: this.contentHiddenRight(), - }; - - this.handleIndicatorClick = this.handleIndicatorClick.bind(this); - this.getScrollLeftValueByTabIndex = this.getScrollLeftValueByTabIndex.bind(this); - this.contentHiddenLeft = this.contentHiddenLeft.bind(this); - this.contentHiddenRight = this.contentHiddenRight.bind(this); - this.handleScroll = this.handleScroll.bind(this); - this.handleResize = this.handleResize.bind(this); - } - - componentDidMount() { - this.conditionallyUpdateState(); - smoothscroll.polyfill(); - } - - getScrollLeftValueByTabIndex(index) { - const { tabRefs } = this.props; - let scrollLeftSum = 0; - for (let i = 0; i < index; i += 1) { - scrollLeftSum += tabRefs[i].offsetWidth; - } - return scrollLeftSum; - } - - contentHiddenRight() { - const { tabContainerRef } = this.props; - if (!tabContainerRef.current) { - return false; - } - return ( - tabContainerRef.current.scrollLeft + tabContainerRef.current.offsetWidth < tabContainerRef.current.scrollWidth - ); - } - - contentHiddenLeft() { - const { tabContainerRef } = this.props; - if (!tabContainerRef.current) { - return false; - } - return ( - tabContainerRef.current.scrollLeft !== 0 && - tabContainerRef.current.offsetWidth < tabContainerRef.current.scrollWidth - ); - } - - findLastVisibleTab() { - const { tabContainerRef, tabRefs, indicatorWidth } = this.props; - const rightMarker = tabContainerRef.current.scrollLeft + tabContainerRef.current.offsetWidth - indicatorWidth; - let scrollLeftSum = 0; - - for (let i = 0; i < tabRefs.length; i += 1) { - scrollLeftSum += tabRefs[i].offsetWidth; - if (rightMarker <= scrollLeftSum) { - return i; - } - } - return null; - } - - findFirstVisibleTab() { - const { tabContainerRef, tabRefs, indicatorWidth } = this.props; - const leftMarker = tabContainerRef.current.scrollLeft + indicatorWidth; - let scrollLeftSum = 0; - - for (let i = 0; i < tabRefs.length; i += 1) { - scrollLeftSum += tabRefs[i].offsetWidth; - if (leftMarker <= scrollLeftSum) { - return i; - } - } - return null; - } - - handleScroll() { - this.conditionallyUpdateState(); - } - - handleResize() { - this.setState({ - contentHiddenLeft: this.contentHiddenLeft(), - contentHiddenRight: this.contentHiddenRight(), - }); - } - - conditionallyUpdateState() { - const { contentHiddenLeft, contentHiddenRight } = this.state; - const currentContentHiddenLeft = this.contentHiddenLeft(); - const currentContentHiddenRight = this.contentHiddenRight(); - - if (currentContentHiddenLeft !== contentHiddenLeft) { - this.setState({ contentHiddenLeft: currentContentHiddenLeft }); - } - - if (currentContentHiddenRight !== contentHiddenRight) { - this.setState({ contentHiddenRight: currentContentHiddenRight }); - } - } - - handleIndicatorClick(side) { - const { tabRefs, tabContainerRef, indicatorWidth } = this.props; - - if (side === "right") { - const lastVisibleTab = this.findLastVisibleTab(); - const scrollLeft = this.getScrollLeftValueByTabIndex(lastVisibleTab) - indicatorWidth; - this.applyScrollLeft(scrollLeft); - } else { - const firstVisibleTab = this.findFirstVisibleTab(); - const scrollLeft = - this.getScrollLeftValueByTabIndex(firstVisibleTab) + - indicatorWidth + - tabRefs[firstVisibleTab].offsetWidth - - tabContainerRef.current.offsetWidth; - this.applyScrollLeft(scrollLeft); - } - } - - applyScrollLeft(scrollLeft) { - const { tabContainerRef } = this.props; - tabContainerRef.current.scroll({ left: scrollLeft, behavior: "smooth" }); - } - - render() { - const { tabContainerRef, indicatorWidth, children } = this.props; - const { contentHiddenLeft, contentHiddenRight } = this.state; - - return ( - <> - - {contentHiddenLeft && ( - - )} - {contentHiddenRight && ( - - )} - - {children({ - handleScroll: this.handleScroll, - handleResize: this.handleResize, - })} - - ); - } -} - -TabScrollIndicators.propTypes = { - children: PropTypes.func.isRequired, - tabRefs: PropTypes.arrayOf(PropTypes.shape({ offsetWidth: PropTypes.number })), - tabContainerRef: PropTypes.shape({ current: PropTypes.object }), - indicatorWidth: PropTypes.number, -}; - -TabScrollIndicators.defaultProps = { - tabRefs: undefined, - tabContainerRef: undefined, - indicatorWidth: 40, -}; - -export default TabScrollIndicators; diff --git a/src/Tabs/TabScrollIndicators.tsx b/src/Tabs/TabScrollIndicators.tsx index 20f630636..3101577e9 100644 --- a/src/Tabs/TabScrollIndicators.tsx +++ b/src/Tabs/TabScrollIndicators.tsx @@ -151,9 +151,11 @@ class TabScrollIndicators extends React.Component( ( { + disabled = false, + required = false, + rows = 3, errorMessage, errorList, error = !!(errorMessage || errorList), - required, labelText, requirementText, helpText, id, className, - rows, isResizeable = true, size, ...props @@ -61,6 +62,7 @@ const Textarea = forwardRef( rows={rows} isResizeable={isResizeable} size={componentSize} + disabled={disabled} {...restProps} /> @@ -70,17 +72,4 @@ const Textarea = forwardRef( } ); -Textarea.defaultProps = { - className: undefined, - id: undefined, - disabled: false, - errorMessage: undefined, - errorList: undefined, - required: false, - labelText: undefined, - helpText: undefined, - requirementText: undefined, - rows: 3, -}; - export default Textarea; diff --git a/src/TimePicker/TimePicker.tsx b/src/TimePicker/TimePicker.tsx index 31e45112b..783e25206 100644 --- a/src/TimePicker/TimePicker.tsx +++ b/src/TimePicker/TimePicker.tsx @@ -149,6 +149,7 @@ const TimePicker: React.FC> = forwardRe error, disabled, size, + ...props }, inputRef diff --git a/src/TimeRange/TimeRange.tsx b/src/TimeRange/TimeRange.tsx index 1af53e6cb..b04788a7c 100644 --- a/src/TimeRange/TimeRange.tsx +++ b/src/TimeRange/TimeRange.tsx @@ -40,8 +40,6 @@ const TimeRange = forwardRef( errorMessage, defaultStartTime, defaultEndTime, - disableRangeValidation, - labelProps, minTime, maxTime, interval, @@ -50,6 +48,11 @@ const TimeRange = forwardRef( endTimeProps, startTimeProps, size, + disableRangeValidation = false, + labelProps = { + ...FieldLabelDefaultProps, + labelText: DEFAULT_LABEL, + }, ...props }: TimeRangeProps, ref @@ -176,24 +179,4 @@ const TimeRange = forwardRef( } ); -TimeRange.defaultProps = { - timeFormat: undefined, - onRangeChange: null, - onStartTimeChange: null, - onEndTimeChange: null, - errorMessage: null, - defaultStartTime: null, - defaultEndTime: null, - disableRangeValidation: false, - labelProps: { - ...FieldLabelDefaultProps, - labelText: DEFAULT_LABEL, - }, - minTime: null, - maxTime: null, - interval: undefined, - startAriaLabel: undefined, - endAriaLabel: undefined, -}; - export default TimeRange; diff --git a/src/Toast/Toast.tsx b/src/Toast/Toast.tsx index 15b2211b6..02fdec9c2 100644 --- a/src/Toast/Toast.tsx +++ b/src/Toast/Toast.tsx @@ -33,12 +33,12 @@ export const toastAnimationConfig = { }; export const Toast = ({ - triggered, + triggered = false, + isCloseable = false, + showDuration = TOAST_SHOW_DURATION, onHide, onShow, - isCloseable, children, - showDuration, onHidden, zIndex, ...props @@ -139,13 +139,4 @@ export const Toast = ({ ); }; -Toast.defaultProps = { - triggered: false, - isCloseable: false, - showDuration: TOAST_SHOW_DURATION, - onShow: () => {}, - onHide: () => {}, - onHidden: () => {}, -}; - export default Toast; diff --git a/src/ToastContainer/ToastContainer.tsx b/src/ToastContainer/ToastContainer.tsx index 6633f683c..03db1cc8f 100644 --- a/src/ToastContainer/ToastContainer.tsx +++ b/src/ToastContainer/ToastContainer.tsx @@ -1,8 +1,8 @@ import React, { useEffect } from "react"; import { toast as _toast, Toaster, ToasterProps, useToasterStore } from "react-hot-toast"; import { useTheme } from "styled-components"; -import { TOAST_SHOW_DURATION } from "../Toast/Toast"; import numberFromDimension from "../utils/numberFromDimension"; +import { TOAST_SHOW_DURATION } from "../Toast/Toast"; import { ToastOptions } from "./ToastFunction"; type ToastContainerProps = { @@ -11,7 +11,15 @@ type ToastContainerProps = { toastOptions?: ToastOptions; } & Omit; -const ToastContainer = ({ gap, maxVisibleToasts, toastOptions, ...props }: ToastContainerProps) => { +const ToastContainer = ({ + gap, + position = "bottom-center", + reverseOrder = false, + containerClassName = "nds-toast-container", + toastOptions = { duration: TOAST_SHOW_DURATION }, + maxVisibleToasts = 8, + ...props +}: ToastContainerProps) => { const theme = useTheme(); const { toasts } = useToasterStore(); @@ -28,17 +36,12 @@ const ToastContainer = ({ gap, maxVisibleToasts, toastOptions, ...props }: Toast toastOptions={{ custom: { ...toastOptions }, }} + position={position} + reverseOrder={reverseOrder} + containerClassName={containerClassName} {...props} /> ); }; -ToastContainer.defaultProps = { - position: "bottom-center", - reverseOrder: false, - containerClassName: "nds-toast-container", - toastOptions: { duration: TOAST_SHOW_DURATION }, - maxVisibleToasts: 8, -}; - export default ToastContainer; diff --git a/src/Toggle/Toggle.tsx b/src/Toggle/Toggle.tsx index 5bb969d7c..b9c80184c 100644 --- a/src/Toggle/Toggle.tsx +++ b/src/Toggle/Toggle.tsx @@ -1,5 +1,4 @@ import React, { useState, useContext } from "react"; -import PropTypes from "prop-types"; import { ThemeContext } from "styled-components"; import { SpaceProps } from "styled-system"; import propTypes from "@styled-system/prop-types"; @@ -23,15 +22,10 @@ type MaybeToggleTitleProps = React.ComponentPropsWithRef<"div"> & { labelText?: string; requirementText?: string; helpText?: string; - children?: any; + children?: React.ReactNode; }; -const MaybeToggleTitle: React.FC> = ({ - labelText, - requirementText, - helpText, - children, - ...props -}) => { + +function MaybeToggleTitle({ labelText, requirementText, helpText, children, ...props }: MaybeToggleTitleProps) { const themeContext = useContext(ThemeContext); return labelText ? (
@@ -45,7 +39,7 @@ const MaybeToggleTitle: React.FC> ) : ( <>{children} ); -}; +} type BaseToggleProps = SpaceProps & { onChange?: (...args: any[]) => any; @@ -57,7 +51,7 @@ type BaseToggleProps = SpaceProps & { id?: string; className?: string; required?: boolean; - helpText?: any; + helpText?: string; labelText?: string; requirementText?: string; error?: boolean; @@ -93,6 +87,7 @@ const BaseToggle = ({ const componentSize = useComponentSize(size); const spaceProps = getSubset(props, propTypes.space); const restProps = omitSubset(props, propTypes.space); + return ( {}, - toggled: undefined, - disabled: false, - onText: undefined, - offText: undefined, - id: undefined, - className: undefined, - required: false, - helpText: undefined, - labelText: undefined, - requirementText: undefined, - error: false, - onClick: () => {}, -}; - type StatefulToggleProps = BaseToggleProps & { defaultToggled?: boolean; onClick?: boolean; @@ -159,16 +138,6 @@ const StatefulToggle = ({ defaultToggled, onClick, disabled, ...props }: Statefu return ; }; -StatefulToggle.propTypes = { - defaultToggled: PropTypes.bool, - onClick: PropTypes.func, -}; - -StatefulToggle.defaultProps = { - defaultToggled: undefined, - onClick: () => {}, -}; - type ToggleProps = StatefulToggleProps; const Toggle = ({ toggled, ...props }: ToggleProps) => diff --git a/src/Toggle/ToggleButton.tsx b/src/Toggle/ToggleButton.tsx index febf07ad8..eda84af01 100644 --- a/src/Toggle/ToggleButton.tsx +++ b/src/Toggle/ToggleButton.tsx @@ -8,9 +8,10 @@ import { default as theme } from "../theme"; import { AnimatedBox } from "../Box"; type SwitchProps = { + children?: React.ReactNode; disabled?: boolean; toggled?: boolean; - onClick?: (event: React.MouseEvent) => void; + onClick?: (event: React.MouseEvent) => void; }; type SliderProps = { @@ -48,23 +49,25 @@ const animationConfig: AnimationConfig = { scale: 1.08, }; -const Switch: React.FC> = ({ children, disabled, toggled, onClick }) => ( - - {children} - -); +function Switch({ children, disabled, toggled, onClick }: SwitchProps) { + return ( + + {children} + + ); +} const Slider: React.FC> = ({ disabled, children }) => ( > = React.forwardRef((props, ref) => { +const ToggleButton = React.forwardRef, ToggleButtonProps>((props, ref) => { const { disabled, defaultToggled, toggled } = props; const inputRef = useRef(null); @@ -137,9 +140,4 @@ const ToggleButton: React.FC> = React ); }); -ToggleButton.defaultProps = { - defaultToggled: undefined, - disabled: false, -}; - export default ToggleButton; diff --git a/src/Tooltip/Tooltip.tsx b/src/Tooltip/Tooltip.tsx index c90fd3736..1cc206789 100644 --- a/src/Tooltip/Tooltip.tsx +++ b/src/Tooltip/Tooltip.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { LegacyRef } from "react"; import { Popper } from "../Popper"; import { generateId } from "../utils"; import TooltipContainer from "./TooltipContainer"; @@ -26,8 +26,20 @@ export type TooltipProps = { children?: React.ReactNode; }; -const Tooltip: React.FC> = React.forwardRef( - ({ className, tooltip, maxWidth, children, placement, showDelay, hideDelay, defaultOpen }, ref) => ( +const Tooltip = React.forwardRef, TooltipProps>( + ( + { + showDelay = "100", + hideDelay = "350", + defaultOpen = false, + placement = "bottom", + maxWidth = "24em", + className, + tooltip, + children, + }, + ref + ) => ( > = React.forwardRe ) ); -Tooltip.defaultProps = { - showDelay: "100", - hideDelay: "350", - defaultOpen: false, - className: undefined, - placement: "bottom", - maxWidth: "24em", -}; - export default Tooltip; diff --git a/src/TruncatedText/MaybeTooltip.tsx b/src/TruncatedText/MaybeTooltip.tsx index 2b01d7127..dd72e2cd2 100644 --- a/src/TruncatedText/MaybeTooltip.tsx +++ b/src/TruncatedText/MaybeTooltip.tsx @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; import { Tooltip } from "../Tooltip"; import { TooltipProps } from "../Tooltip/Tooltip"; @@ -7,18 +6,8 @@ type MaybeTooltipProps = TooltipProps & { showTooltip?: boolean; }; -const MaybeTooltip = ({ children, showTooltip, ...props }: MaybeTooltipProps) => { +const MaybeTooltip = ({ children = "", showTooltip = true, ...props }: MaybeTooltipProps) => { return showTooltip ? {children} : <>{children}; }; -MaybeTooltip.propTypes = { - children: PropTypes.node, - showTooltip: PropTypes.bool, -}; - -MaybeTooltip.defaultProps = { - children: "", - showTooltip: true, -}; - export default MaybeTooltip; diff --git a/src/TruncatedText/TruncatedText.tsx b/src/TruncatedText/TruncatedText.tsx index d82dd26c9..8174bc403 100644 --- a/src/TruncatedText/TruncatedText.tsx +++ b/src/TruncatedText/TruncatedText.tsx @@ -1,37 +1,41 @@ import React from "react"; -import PropTypes from "prop-types"; import { Text } from "../Type"; import { TruncatedTextProps } from "./TruncatedTextProps"; import TruncatedTextFillWidth from "./TruncatedTextFillWidth"; import TruncatedTextMaxCharacters from "./TruncatedTextMaxCharacters"; -const TruncatedText = ({ fullWidth, children, ...props }: TruncatedTextProps) => +const TruncatedText = ({ + indicator = "...", + element = , + maxCharacters = 20, + fullWidth = false, + showTooltip = true, + "data-testid": dataTestId = "truncated-text", + children, + ...props +}: TruncatedTextProps) => fullWidth ? ( - {children} + + {children} + ) : ( - {children} + + {children} + ); -TruncatedText.propTypes = { - children: PropTypes.node, - indicator: PropTypes.string, - element: PropTypes.node, - maxCharacters: PropTypes.number, - showTooltip: PropTypes.bool, - fullWidth: PropTypes.bool, - "data-testid": PropTypes.string, - tooltipProps: PropTypes.shape({}), -}; - -TruncatedText.defaultProps = { - children: undefined, - indicator: "...", - element: , - maxCharacters: 20, - fullWidth: false, - showTooltip: true, - "data-testid": "truncated-text", - tooltipProps: undefined, -}; - export default TruncatedText; diff --git a/src/TruncatedText/TruncatedTextProps.ts b/src/TruncatedText/TruncatedTextProps.ts index ea02843d4..72074eb5d 100644 --- a/src/TruncatedText/TruncatedTextProps.ts +++ b/src/TruncatedText/TruncatedTextProps.ts @@ -1,10 +1,11 @@ +import { ReactElement } from "react"; import { TooltipProps } from "../Tooltip/Tooltip"; import { TextProps } from "../Type"; export interface TruncatedTextProps extends TextProps { children?: string; indicator?: string; - element?: any; + element?: ReactElement; maxCharacters?: number; showTooltip?: boolean; fullWidth?: boolean; diff --git a/src/Type/Text.tsx b/src/Type/Text.tsx index d47c83383..ba129cab7 100644 --- a/src/Type/Text.tsx +++ b/src/Type/Text.tsx @@ -1,4 +1,4 @@ -import styled, { CSSObject } from "styled-components"; +import styled from "styled-components"; import type { DefaultNDSThemeType } from "../theme.type"; import { addStyledProps, StyledProps } from "../StyledProps"; @@ -22,7 +22,7 @@ export type TextProps = React.HTMLAttributes & { } & StyledProps & { theme?: DefaultNDSThemeType }; const Text = styled.p( - ({ disabled, textTransform, inline, theme }): CSSObject => ({ + ({ disabled = false, textTransform, inline = false, theme }) => ({ textTransform, color: "currentColor", marginTop: 0, @@ -35,8 +35,4 @@ const Text = styled.p( addStyledProps ); -Text.defaultProps = { - inline: false, - disabled: false, -}; export default Text; diff --git a/src/Validation/InlineValidation.tsx b/src/Validation/InlineValidation.tsx index c6ae74252..4656dcfff 100644 --- a/src/Validation/InlineValidation.tsx +++ b/src/Validation/InlineValidation.tsx @@ -1,10 +1,10 @@ import React from "react"; import styled from "styled-components"; +import { SpaceProps } from "styled-system"; import { Text } from "../Type"; import { Icon } from "../Icon"; import { Flex } from "../Flex"; import mapErrorsToList from "./mapErrorsToList"; -import { SpaceProps } from "styled-system"; const Wrapper = styled.div(({ theme }) => ({ [`${Text}`]: { @@ -22,14 +22,14 @@ type InlineValidationProps = SpaceProps & { children?: React.ReactNode; }; -const InlineValidation: React.FC> = ({ +export default function InlineValidation({ className, errorMessage, errorList, children, ...boxProps -}) => - errorMessage || errorList ? ( +}: InlineValidationProps) { + return errorMessage || errorList ? ( @@ -39,11 +39,4 @@ const InlineValidation: React.FC> ) : null; - -InlineValidation.defaultProps = { - className: undefined, - errorMessage: undefined, - errorList: undefined, - children: undefined, -}; -export default InlineValidation; +} diff --git a/src/locales.const.ts b/src/locales.const.ts index 5871a4f1a..0aa7da795 100644 --- a/src/locales.const.ts +++ b/src/locales.const.ts @@ -11,7 +11,7 @@ export const NDS_TO_DATE_FN_LOCALES_MAP = { pt_BR: ptBR, ro_RO: ro, zh_CN: zhCN, -}; +} as const; export const ALL_NDS_LOCALES = [ { diff --git a/src/utils/DetectOutsideClick.js b/src/utils/DetectOutsideClick.js index 45f8b5c3a..126466ba4 100644 --- a/src/utils/DetectOutsideClick.js +++ b/src/utils/DetectOutsideClick.js @@ -1,7 +1,6 @@ import React from "react"; -import PropTypes from "prop-types"; -class DetectOutsideClick extends React.Component { +export default class DetectOutsideClick extends React.Component { constructor(props) { super(props); @@ -44,16 +43,3 @@ class DetectOutsideClick extends React.Component { return <>{children}; } } - -DetectOutsideClick.propTypes = { - onClick: PropTypes.func.isRequired, - clickRef: PropTypes.oneOfType([PropTypes.shape({}), PropTypes.arrayOf(PropTypes.shape({}))]), - children: PropTypes.node, -}; - -DetectOutsideClick.defaultProps = { - clickRef: null, - children: undefined, -}; - -export default DetectOutsideClick; diff --git a/src/utils/PopperArrow.tsx b/src/utils/PopperArrow.tsx index 70dabe8da..b05ca578a 100644 --- a/src/utils/PopperArrow.tsx +++ b/src/utils/PopperArrow.tsx @@ -1,5 +1,4 @@ import styled from "styled-components"; -import PropTypes from "prop-types"; import { PopperArrowProps as ReactPopperArrowProps } from "react-popper"; import theme from "../theme"; diff --git a/src/utils/PreventBodyElementScrolling.js b/src/utils/PreventBodyElementScrolling.js index 25becd0d4..cc340566f 100644 --- a/src/utils/PreventBodyElementScrolling.js +++ b/src/utils/PreventBodyElementScrolling.js @@ -1,8 +1,7 @@ import React from "react"; -import PropTypes from "prop-types"; import { disableBodyScroll, clearAllBodyScrollLocks } from "body-scroll-lock"; -class PreventBodyElementScrolling extends React.Component { +export default class PreventBodyElementScrolling extends React.Component { componentDidMount() { const { scrollableRef } = this.props; const refs = Array.isArray(scrollableRef) ? scrollableRef : [scrollableRef]; @@ -22,14 +21,3 @@ class PreventBodyElementScrolling extends React.Component { return <>{children}; } } - -PreventBodyElementScrolling.propTypes = { - children: PropTypes.node, - scrollableRef: PropTypes.oneOfType([PropTypes.shape({}), PropTypes.arrayOf(PropTypes.shape({}))]), -}; - -PreventBodyElementScrolling.defaultProps = { - children: null, - scrollableRef: null, -}; -export default PreventBodyElementScrolling; diff --git a/src/utils/ScrollIndicators.js b/src/utils/ScrollIndicators.js index c446502f0..c0b7dfc7a 100644 --- a/src/utils/ScrollIndicators.js +++ b/src/utils/ScrollIndicators.js @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; import { Icon } from "../Icon"; import theme from "../theme"; @@ -90,8 +89,4 @@ class ScrollIndicators extends React.Component { } /* eslint-enable react/destructuring-assignment */ -ScrollIndicators.propTypes = { - children: PropTypes.element.isRequired, -}; - export default ScrollIndicators; diff --git a/src/utils/localized-date-fns.js b/src/utils/localized-date-fns.js deleted file mode 100644 index d90f4ee0a..000000000 --- a/src/utils/localized-date-fns.js +++ /dev/null @@ -1,5 +0,0 @@ -import { format } from "date-fns"; -import { NDS_TO_DATE_FN_LOCALES_MAP } from "../locales.const"; - -export const localizedFormat = (date, stringFormat, ndsLocale) => - format(date, stringFormat, { locale: NDS_TO_DATE_FN_LOCALES_MAP[ndsLocale] }); diff --git a/src/utils/localized-date-fns.ts b/src/utils/localized-date-fns.ts new file mode 100644 index 000000000..abf799712 --- /dev/null +++ b/src/utils/localized-date-fns.ts @@ -0,0 +1,6 @@ +import { format } from "date-fns"; +import { NDS_TO_DATE_FN_LOCALES_MAP } from "../locales.const"; + +export function localizedFormat(date: number, dateFormat: string, ndsLocale: string): string { + return format(date, dateFormat, { locale: NDS_TO_DATE_FN_LOCALES_MAP[ndsLocale] }); +} diff --git a/src/utils/subset.js b/src/utils/subset.js index 73f04489b..ac6c61899 100644 --- a/src/utils/subset.js +++ b/src/utils/subset.js @@ -12,7 +12,7 @@ export const omitSubset = (o, propObj) => { }, {}); }; -const pick = (o, ...fields) => { +export const pick = (o, ...fields) => { const objectProps = Object.keys(o); return fields.reduce((a, x) => { if (objectProps.includes(x)) a[x] = o[x]; diff --git a/src/utils/withWindowDimensions.js b/src/utils/withWindowDimensions.js index d3ec59142..409bd465b 100644 --- a/src/utils/withWindowDimensions.js +++ b/src/utils/withWindowDimensions.js @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; class WindowDimensions extends React.Component { constructor(props) { @@ -32,15 +31,10 @@ class WindowDimensions extends React.Component { } } -WindowDimensions.propTypes = { - children: PropTypes.func.isRequired, -}; - -const withWindowDimensions = (Component) => (props) => - ( - - {(windowDimensions) => } - - ); +const withWindowDimensions = (Component) => (props) => ( + + {(windowDimensions) => } + +); export default withWindowDimensions; diff --git a/yarn.lock b/yarn.lock index 13e15d284..7a6e677e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16432,7 +16432,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@15.7.2, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==