Skip to content

Commit

Permalink
Refactor(web-react): Move away from the defaultProps
Browse files Browse the repository at this point in the history
  * Support for defaultProps will be removed from function components in a future major release.
  * Use JavaScript default parameters instead.
  • Loading branch information
literat committed Apr 16, 2024
1 parent e8a7f73 commit ac4cd95
Show file tree
Hide file tree
Showing 21 changed files with 158 additions and 103 deletions.
14 changes: 10 additions & 4 deletions packages/web-react/src/components/Alert/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ import { Icon } from '../Icon';
import { useAlertIcon } from './useAlertIcon';
import { useAlertStyleProps } from './useAlertStyleProps';

const defaultProps = {
const defaultProps: Partial<SpiritAlertProps> = {
color: 'success',
isCentered: false,
elementType: 'div',
};

export const Alert = <T extends ElementType = 'div', E = void>(props: SpiritAlertProps<T, E>): JSX.Element => {
const { elementType: ElementTag = 'div', children, color, iconName, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const {
elementType: ElementTag = defaultProps.elementType as ElementType,
children,
color,
iconName,
...restProps
} = propsWithDefaults;
const { classProps, props: modifiedProps } = useAlertStyleProps({ color, ...restProps });
const { styleProps, props: otherProps } = useStyleProps(modifiedProps);
const alertIconName = useAlertIcon({ color, iconName, ...otherProps });
Expand All @@ -36,6 +44,4 @@ export const Alert = <T extends ElementType = 'div', E = void>(props: SpiritAler
);
};

Alert.defaultProps = defaultProps;

export default Alert;
14 changes: 10 additions & 4 deletions packages/web-react/src/components/Breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ import { SpiritBreadcrumbsProps } from '../../types';
import BreadcrumbsItem from './BreadcrumbsItem';
import { useBreadcrumbsStyleProps } from './useBreadcrumbsStyleProps';

const defaultProps = {
const defaultProps: Partial<SpiritBreadcrumbsProps> = {
elementType: 'nav',
items: [],
};

export const Breadcrumbs = <T extends ElementType = 'nav'>(props: SpiritBreadcrumbsProps<T>): JSX.Element => {
const { children, elementType: ElementTag = 'nav', goBackTitle, items, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const {
children,
elementType: ElementTag = defaultProps.elementType as ElementType,
goBackTitle,
items,
...restProps
} = propsWithDefaults;
const { classProps, props: modifiedProps } = useBreadcrumbsStyleProps({ ...restProps });
const { styleProps, props: otherProps } = useStyleProps(modifiedProps);

Expand Down Expand Up @@ -44,6 +52,4 @@ export const Breadcrumbs = <T extends ElementType = 'nav'>(props: SpiritBreadcru
);
};

Breadcrumbs.defaultProps = defaultProps;

export default Breadcrumbs;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const defaultProps = {
};

export const BreadcrumbsItem = (props: SpiritBreadcrumbsItemProps) => {
const { children, href, isCurrent, iconNameStart, iconNameEnd, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const { children, href, isCurrent, iconNameStart, iconNameEnd, ...restProps } = propsWithDefaults;
const { classProps, props: otherProps } = useBreadcrumbsStyleProps({ ...restProps });
const { styleProps, props: transferProps } = useStyleProps(otherProps);

Expand All @@ -38,6 +39,4 @@ export const BreadcrumbsItem = (props: SpiritBreadcrumbsItemProps) => {
);
};

BreadcrumbsItem.defaultProps = defaultProps;

export default BreadcrumbsItem;
12 changes: 8 additions & 4 deletions packages/web-react/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import { Spinner } from '../Spinner';
import { useButtonAriaProps } from './useButtonAriaProps';
import { useButtonStyleProps } from './useButtonStyleProps';

const defaultProps = {
const defaultProps: Partial<SpiritButtonProps> = {
color: 'primary',
isBlock: false,
isDisabled: false,
isLoading: false,
isSquare: false,
size: 'medium',
type: 'button',
elementType: 'button',
};

/* We need an exception for components exported with forwardRef */
Expand All @@ -22,7 +23,12 @@ const _Button = <T extends ElementType = 'button', C = void, S = void>(
props: SpiritButtonProps<T, C, S>,
ref: ForwardedRef<HTMLButtonElement>,
) => {
const { elementType: ElementTag = 'button', children, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const {
elementType: ElementTag = defaultProps.elementType as ElementType,
children,
...restProps
} = propsWithDefaults;

const { buttonProps } = useButtonAriaProps(restProps);
const { classProps, props: modifiedProps } = useButtonStyleProps(restProps);
Expand All @@ -44,6 +50,4 @@ const _Button = <T extends ElementType = 'button', C = void, S = void>(

export const Button = forwardRef<HTMLButtonElement, SpiritButtonProps<ElementType>>(_Button);

Button.defaultProps = defaultProps;

export default Button;
14 changes: 9 additions & 5 deletions packages/web-react/src/components/ButtonLink/ButtonLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import React, { ElementType, ForwardedRef, forwardRef } from 'react';
import { useStyleProps } from '../../hooks';
import { SpiritButtonLinkProps } from '../../types';
import { Spinner } from '../Spinner';
import { useButtonLinkStyleProps } from './useButtonLinkStyleProps';
import { useButtonLinkAriaProps } from './useButtonLinkAriaProps';
import { useButtonLinkStyleProps } from './useButtonLinkStyleProps';

const defaultProps = {
const defaultProps: Partial<SpiritButtonLinkProps> = {
color: 'primary',
elementType: 'a',
isBlock: false,
isDisabled: false,
isLoading: false,
Expand All @@ -21,7 +22,12 @@ const _ButtonLink = <T extends ElementType = 'a', C = void, S = void>(
props: SpiritButtonLinkProps<T, C, S>,
ref: ForwardedRef<HTMLAnchorElement>,
) => {
const { elementType: ElementTag = 'a', children, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const {
elementType: ElementTag = defaultProps.elementType as ElementType,
children,
...restProps
} = propsWithDefaults;

const { buttonLinkProps } = useButtonLinkAriaProps(restProps);
const { classProps, props: modifiedProps } = useButtonLinkStyleProps(restProps);
Expand All @@ -43,6 +49,4 @@ const _ButtonLink = <T extends ElementType = 'a', C = void, S = void>(

export const ButtonLink = forwardRef<HTMLAnchorElement, SpiritButtonLinkProps<ElementType>>(_ButtonLink);

ButtonLink.defaultProps = defaultProps;

export default ButtonLink;
13 changes: 9 additions & 4 deletions packages/web-react/src/components/Collapse/Collapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,21 @@ const transitioningStyles = {
exited: '',
};

const defaultProps = {
const defaultProps: Partial<SpiritCollapseProps> = {
elementType: 'div',
isOpen: false,
collapsibleToBreakpoint: undefined,
transitionDuration: TRANSITION_DURATION,
};

const Collapse = (props: SpiritCollapseProps) => {
const { elementType: ElementTag = 'div', children, transitionDuration = TRANSITION_DURATION, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const {
elementType: ElementTag = defaultProps.elementType as React.ElementType,
children,
transitionDuration = TRANSITION_DURATION,
...restProps
} = propsWithDefaults;

const rootElementRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
const collapseElementRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
Expand Down Expand Up @@ -59,6 +66,4 @@ const Collapse = (props: SpiritCollapseProps) => {
);
};

Collapse.defaultProps = defaultProps;

export default Collapse;
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const defaultProps = {
};

const UncontrolledCollapse = (props: SpiritUncontrolledCollapseProps) => {
const { children, hideOnCollapse, renderTrigger, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const { children, hideOnCollapse, renderTrigger, ...restProps } = propsWithDefaults;
const { isOpen, toggleHandler } = useCollapse(restProps.isOpen);
const { ariaProps } = useCollapseAriaProps({ ...restProps, isOpen });

Expand Down Expand Up @@ -41,6 +42,4 @@ const UncontrolledCollapse = (props: SpiritUncontrolledCollapseProps) => {
);
};

UncontrolledCollapse.defaultProps = defaultProps;

export default UncontrolledCollapse;
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import '@testing-library/jest-dom';
import { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
import UncontrolledCollapse from '../UncontrolledCollapse';

describe('UncontrolledCollapse', () => {
Expand Down
7 changes: 3 additions & 4 deletions packages/web-react/src/components/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ const defaultProps = {
};

export const Dropdown = (props: SpiritDropdownProps) => {
const propsWithDefaults = { ...defaultProps, ...props };
const {
/** @deprecated ID will be made a required user input in the next major version. */
id = Math.random().toString(36).slice(2, 7),
children,
enableAutoClose,
fullWidthMode,
onAutoClose,
placement = defaultProps.placement,
placement,
renderTrigger,
...rest
} = props;
} = propsWithDefaults;

const dropdownRef = useRef(null);
const triggerRef = useRef();
Expand Down Expand Up @@ -87,6 +88,4 @@ export const Dropdown = (props: SpiritDropdownProps) => {
);
};

Dropdown.defaultProps = defaultProps;

export default Dropdown;
25 changes: 11 additions & 14 deletions packages/web-react/src/components/Field/HelperText.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import React, { ElementType, useEffect } from 'react';
import { RegisterType } from './useAriaIds';
import { HelperTextProps } from './types';

interface Props {
helperText: React.ReactNode;
className?: string;
elementType?: ElementType;
id?: string;
registerAria?: RegisterType;
}

const defaultProps = {
const defaultProps: Partial<HelperTextProps> = {
className: undefined,
elementType: 'div',
id: undefined,
registerAria: undefined,
};

const HelperText = (props: Props) => {
const { helperText, className, elementType: ElementTag = 'div', id, registerAria } = props;
const HelperText = <T extends ElementType = 'div'>(props: HelperTextProps<T>) => {
const propsWithDefaults = { ...defaultProps, ...props };
const {
helperText,
className,
elementType: ElementTag = defaultProps.elementType as ElementType,
id,
registerAria,
} = propsWithDefaults;

useEffect(() => {
registerAria?.({ add: id });
Expand All @@ -38,6 +37,4 @@ const HelperText = (props: Props) => {
return null;
};

HelperText.defaultProps = defaultProps;

export default HelperText;
25 changes: 11 additions & 14 deletions packages/web-react/src/components/Field/ValidationText.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import React, { ElementType, useEffect } from 'react';
import { ValidationTextProp } from '../../types';
import { RegisterType } from './useAriaIds';
import { ValidationTextProps } from './types';

export interface ValidationTextProps extends ValidationTextProp {
className?: string;
elementType?: ElementType;
id?: string;
registerAria?: RegisterType;
}

const defaultProps = {
const defaultProps: Partial<ValidationTextProps> = {
className: undefined,
elementType: 'div',
id: undefined,
registerAria: undefined,
};

export const ValidationText = (props: ValidationTextProps) => {
const { className, validationText, elementType: ElementTag = 'div', id, registerAria } = props;
export const ValidationText = <T extends ElementType = 'div'>(props: ValidationTextProps<T>) => {
const propsWithDefaults = { ...defaultProps, ...props };
const {
className,
validationText,
elementType: ElementTag = defaultProps.elementType as ElementType,
id,
registerAria,
} = propsWithDefaults;

useEffect(() => {
registerAria?.({ add: id });
Expand All @@ -44,6 +43,4 @@ export const ValidationText = (props: ValidationTextProps) => {
return null;
};

ValidationText.defaultProps = defaultProps;

export default ValidationText;
24 changes: 24 additions & 0 deletions packages/web-react/src/components/Field/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ElementType, JSXElementConstructor, ReactNode } from 'react';
import { ValidationTextProp } from '../../types';
import { RegisterType } from './useAriaIds';

export interface FieldElementTypeProps<T extends ElementType = 'div'> {
/**
* The HTML element or React element used to render the pill, e.g. 'div', 'span'.
*
* @default 'div'
*/
elementType?: T | JSXElementConstructor<unknown>;
}

export interface FieldProps<T extends ElementType = 'div'> extends FieldElementTypeProps<T> {
className?: string;
id?: string;
registerAria?: RegisterType;
}

export interface HelperTextProps<T extends ElementType = 'div'> extends FieldProps<T> {
helperText: ReactNode;
}

export interface ValidationTextProps<T extends ElementType = 'div'> extends FieldProps<T>, ValidationTextProp {}
12 changes: 8 additions & 4 deletions packages/web-react/src/components/Heading/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import { useStyleProps } from '../../hooks';
import { SpiritHeadingProps } from '../../types';
import { useHeadingStyleProps } from './useHeadingStyleProps';

const defaultProps = {
const defaultProps: Partial<SpiritHeadingProps> = {
size: 'medium',
elementType: 'div',
};

export const Heading = <T extends ElementType = 'div', S = void>(props: SpiritHeadingProps<T, S>): JSX.Element => {
const { elementType: ElementTag = 'div', children, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const {
elementType: ElementTag = defaultProps.elementType as ElementType,
children,
...restProps
} = propsWithDefaults;
const { classProps, props: modifiedProps } = useHeadingStyleProps(restProps);
const { styleProps, props: otherProps } = useStyleProps(modifiedProps);

Expand All @@ -20,6 +26,4 @@ export const Heading = <T extends ElementType = 'div', S = void>(props: SpiritHe
);
};

Heading.defaultProps = defaultProps;

export default Heading;
6 changes: 2 additions & 4 deletions packages/web-react/src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const defaultProps = {
/* We need an exception for components exported with forwardRef */
/* eslint no-underscore-dangle: ['error', { allow: ['_Icon'] }] */
export const _Icon = (props: IconProps, ref: ForwardedRef<SVGSVGElement>) => {
const { boxSize, name, title, ariaHidden, ...restProps } = props;
const propsWithDefaults = { ...defaultProps, ...props };
const { boxSize, name, title, ariaHidden, ...restProps } = propsWithDefaults;
let icon = useIcon(name);
const { styleProps, props: otherProps } = useStyleProps(restProps);

Expand Down Expand Up @@ -39,7 +40,4 @@ export const _Icon = (props: IconProps, ref: ForwardedRef<SVGSVGElement>) => {
};

export const Icon = forwardRef<SVGSVGElement, IconProps>(_Icon);

Icon.defaultProps = defaultProps;

export default Icon;
Loading

0 comments on commit ac4cd95

Please sign in to comment.