diff --git a/src/Alert/index.tsx b/src/Alert/index.tsx index bbdb22b4978..6323ca0b67e 100644 --- a/src/Alert/index.tsx +++ b/src/Alert/index.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/require-default-props */ import React, { useCallback, useEffect, diff --git a/src/Card/BaseCard.tsx b/src/Card/BaseCard.tsx index d1c7eccebf5..0cfd62b237c 100644 --- a/src/Card/BaseCard.tsx +++ b/src/Card/BaseCard.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; import type { ComponentWithAsProp, BsPropsWithAs } from '../utils/types/bootstrap'; @@ -28,12 +27,19 @@ const textVariants = [ type ColorVariant = typeof colorVariants[number]; type TextVariant = typeof textVariants[number]; interface Props extends BsPropsWithAs { + /** Prefix for component CSS classes. */ prefix?: string; + /** Background color of the card. */ bgColor?: ColorVariant; + /** Text color of the card. */ textColor?: ColorVariant | TextVariant; + /** Border color of the card. */ borderColor?: ColorVariant; + /** Determines whether the card should render its children inside a `CardBody` wrapper. */ hasBody?: boolean; + /** Additional CSS class names to apply to the card element. */ className?: string; + /** The content to render inside the card. */ children: React.ReactNode; } type BaseCardType = ComponentWithAsProp<'div', Props>; @@ -69,24 +75,4 @@ const BaseCard : BaseCardType = React.forwardRef( }, ); -/* eslint-disable react/require-default-props */ -BaseCard.propTypes = { - /** Prefix for component CSS classes. */ - prefix: PropTypes.string, - /** Background color of the card. */ - bgColor: PropTypes.oneOf(colorVariants), - /** Text color of the card. */ - textColor: PropTypes.oneOf([...colorVariants, ...textVariants]), - /** Border color of the card. */ - borderColor: PropTypes.oneOf(colorVariants), - /** Determines whether the card should render its children inside a `CardBody` wrapper. */ - hasBody: PropTypes.bool, - /** Set a custom element for this component. */ - as: PropTypes.elementType, - /** Additional CSS class names to apply to the card element. */ - className: PropTypes.string, - /** The content to render inside the card. */ - children: PropTypes.node, -}; - export default BaseCard; diff --git a/src/Chip/ChipIcon.tsx b/src/Chip/ChipIcon.tsx index 8ef97ef1ee6..782f00259ed 100644 --- a/src/Chip/ChipIcon.tsx +++ b/src/Chip/ChipIcon.tsx @@ -1,22 +1,30 @@ import React, { KeyboardEventHandler, MouseEventHandler } from 'react'; -import PropTypes from 'prop-types'; import Icon from '../Icon'; import IconButton from '../IconButton'; import { STYLE_VARIANTS } from './constants'; export type ChipIconProps = { - className: string, - src: React.ComponentType, - variant: typeof STYLE_VARIANTS[keyof typeof STYLE_VARIANTS], - disabled?: boolean, + /** Additional CSS class name(s) to append to the base element. */ + className: string; + /** The icon component to render. */ + src: React.ComponentType; + /** The visual style variant of the chip icon. */ + variant?: typeof STYLE_VARIANTS[keyof typeof STYLE_VARIANTS]; + /** Whether the icon is in a disabled state. */ + disabled?: boolean; } & ( // Either _both_ onClick and alt are provided, or neither is: - | { onClick: KeyboardEventHandler & MouseEventHandler, alt: string } - | { onClick?: undefined, alt?: undefined } + | { + /** Callback for click and keyboard events on the icon button. */ + onClick: KeyboardEventHandler & MouseEventHandler; + /** Accessible label for the icon button. Required when `onClick` is provided. */ + alt: string; + } + | { onClick?: undefined; alt?: undefined } ); function ChipIcon({ - className, src, onClick, alt, variant, disabled, + className, src, onClick, alt, variant = STYLE_VARIANTS.LIGHT, disabled = false, }: ChipIconProps) { if (onClick) { return ( @@ -35,20 +43,4 @@ function ChipIcon({ return ; } -ChipIcon.propTypes = { - className: PropTypes.string.isRequired, - src: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired, - onClick: PropTypes.func, - alt: PropTypes.string, - variant: PropTypes.string, - disabled: PropTypes.bool, -}; - -ChipIcon.defaultProps = { - onClick: undefined, - alt: undefined, - variant: STYLE_VARIANTS.LIGHT, - disabled: false, -}; - export default ChipIcon; diff --git a/src/Modal/ModalDialogHeader.tsx b/src/Modal/ModalDialogHeader.tsx index 4abf15b6dc0..36ae1ce83a6 100644 --- a/src/Modal/ModalDialogHeader.tsx +++ b/src/Modal/ModalDialogHeader.tsx @@ -1,11 +1,13 @@ import React from 'react'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; import type { ComponentWithAsProp } from '../utils/types/bootstrap'; export interface Props { + /** Specifies the base element. */ as?: string; + /** Specifies the contents of the header. */ children: React.ReactNode; + /** Specifies class name to append to the base element. */ className?: string; } @@ -27,18 +29,4 @@ const ModalDialogHeader: HeaderType = React.forwardRef(({ ) )); -ModalDialogHeader.propTypes = { - /** Specifies the base element */ - as: PropTypes.elementType, - /** Specifies the contents of the header */ - children: PropTypes.node.isRequired, - /** Specifies class name to append to the base element */ - className: PropTypes.string, -}; - -ModalDialogHeader.defaultProps = { - as: 'div', - className: '', -}; - export default ModalDialogHeader; diff --git a/src/Overlay/index.tsx b/src/Overlay/index.tsx index 6c640f72391..6edf5e18bcb 100644 --- a/src/Overlay/index.tsx +++ b/src/Overlay/index.tsx @@ -2,168 +2,126 @@ import React from 'react'; import BaseOverlay, { type OverlayProps, type Placement } from 'react-bootstrap/Overlay'; import BaseOverlayTrigger, { type OverlayTriggerProps, type OverlayTriggerType } from 'react-bootstrap/OverlayTrigger'; import Fade from 'react-bootstrap/Fade'; -import PropTypes from 'prop-types'; -// Note: The only thing this file adds to the base component is propTypes validation. +// Note: The only thing this file adds to the base components is default prop values. // As more Paragon consumers adopt TypeScript, we could consider removing almost all of this code // and just re-export the Overlay and OverlayTrigger components from react-bootstrap unmodified. -const PLACEMENT_VARIANTS: Placement[] = [ - 'auto-start', - 'auto', - 'auto-end', - 'top-start', - 'top', - 'top-end', - 'right-start', - 'right', - 'right-end', - 'bottom-end', - 'bottom', - 'bottom-start', - 'left-end', - 'left', - 'left-start', -]; - -const TRIGGER_VARIANTS: OverlayTriggerType[] = [ - 'hover', - 'click', - 'focus', -]; - -function Overlay(props: OverlayProps) { - return ; -} -function OverlayTrigger(props: OverlayTriggerProps) { - return ( - - {props.children} - - ); -} - -const triggerType = PropTypes.oneOf(TRIGGER_VARIANTS); - -Overlay.propTypes = { +export interface ParagonOverlayProps extends OverlayProps { /** Specifies the content of the `Overlay`. */ - children: PropTypes.node.isRequired, + children: OverlayProps['children']; /** * A component instance, DOM node, or function that returns either. * The overlay will be positioned in relation to the target. */ - container: PropTypes.oneOfType([PropTypes.elementType, PropTypes.func]), + container?: OverlayProps['container']; /** Callback fired before the `Overlay` transitions in. */ - onEnter: PropTypes.func, + onEnter?: OverlayProps['onEnter']; /** Callback fired after the `Overlay` finishes transitioning in. */ - onEntered: PropTypes.func, + onEntered?: OverlayProps['onEntered']; /** Callback fired as the `Overlay` begins to transition in. */ - onEntering: PropTypes.func, - /** Callback fired right before the `Overlay` transitions out */ - onExit: PropTypes.func, + onEntering?: OverlayProps['onEntering']; + /** Callback fired right before the `Overlay` transitions out. */ + onExit?: OverlayProps['onExit']; /** Callback fired after the `Overlay` finishes transitioning out. */ - onExited: PropTypes.func, + onExited?: OverlayProps['onExited']; /** Callback fired as the Overlay begins to transition out. */ - onExiting: PropTypes.func, + onExiting?: OverlayProps['onExiting']; /** * A callback invoked by the overlay when it wishes to be hidden. * Required if `rootClose` is specified. */ - onHide: PropTypes.func, - /** The placement of the `Overlay` in relation to it's target. */ - placement: PropTypes.oneOf(PLACEMENT_VARIANTS), + onHide?: OverlayProps['onHide']; + /** The placement of the `Overlay` in relation to its target. */ + placement?: Placement; /** A set of popper options and props passed directly to `Popper`. */ - popperConfig: PropTypes.shape({}), + popperConfig?: OverlayProps['popperConfig']; /** Specify whether the overlay should trigger `onHide` when the user clicks outside the overlay. */ - rootClose: PropTypes.bool, - /** Specify event for triggering a “root close” toggle. */ - rootCloseEvent: PropTypes.oneOf(['click', 'mousedown']), + rootClose?: boolean; + /** Specify event for triggering a "root close" toggle. */ + rootCloseEvent?: OverlayProps['rootCloseEvent']; /** Set the visibility of the `Overlay`. */ - show: PropTypes.bool, - /** - * The visibility of the `Overlay`. `show` is a controlled prop so should - * be paired with `onToggle` to avoid breaking user interactions. - * - * Manually toggling show does not wait for delay to change the visibility. - * - * Controls `onToggle`. - */ - target: PropTypes.oneOfType([PropTypes.elementType, PropTypes.func]), + show?: boolean; + /** The target element the `Overlay` is positioned in relation to. */ + target?: OverlayProps['target']; /** * Animate the entering and exiting of the Overlay. `true` will use the `` transition, * or a custom react-transition-group `` component can be provided. */ - transition: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]), -}; + transition?: OverlayProps['transition']; +} -OverlayTrigger.propTypes = { +export interface ParagonOverlayTriggerProps extends OverlayTriggerProps { /** Specifies the content of the `OverlayTrigger`. */ - children: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired, + children: OverlayTriggerProps['children']; /** An element or text to overlay next to the target. */ - overlay: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired, + overlay: OverlayTriggerProps['overlay']; /** The initial visibility state of the `Overlay`. */ - defaultShow: PropTypes.bool, + defaultShow?: boolean; /** A millisecond delay amount to show and hide the `Overlay` once triggered. */ - delay: PropTypes.oneOfType([PropTypes.number, PropTypes.shape({})]), + delay?: OverlayTriggerProps['delay']; /** The initial flip state of the `Overlay`. */ - flip: PropTypes.bool, - onHide: PropTypes.func, + flip?: boolean; + /** Callback fired when the visibility of the overlay changes. */ + onHide?: OverlayTriggerProps['onHide']; /** * A callback that fires when the user triggers a change in tooltip visibility. * `onToggle` is called with the desired next show, and generally should be * passed back to the `show` prop. `onToggle` fires after the configured `delay`. - * - * Controls `show`. */ - onToggle: PropTypes.func, - /** The placement of the `Overlay` in relation to it's target. */ - placement: PropTypes.oneOf(PLACEMENT_VARIANTS), - /** A `Popper.js` config object passed to the the underlying popper instance. */ - popperConfig: PropTypes.shape({}), + onToggle?: OverlayTriggerProps['onToggle']; + /** The placement of the `Overlay` in relation to its target. */ + placement?: Placement; + /** A `Popper.js` config object passed to the underlying popper instance. */ + popperConfig?: OverlayTriggerProps['popperConfig']; /** - * The visibility of the `Overlay`. `show` is a controlled prop so should - * be paired with `onToggle` to avoid breaking user interactions. - * - * Manually toggling show does not wait for delay to change the visibility. - * - * Controls `onToggle`. + * The visibility of the `Overlay`. `show` is a controlled prop so should be + * paired with `onToggle` to avoid breaking user interactions. */ - show: PropTypes.bool, - target: PropTypes.instanceOf(EventTarget), + show?: boolean; + /** The target element the `Overlay` is positioned in relation to. */ + target?: OverlayTriggerProps['target']; /** Specify which action or actions trigger `Overlay` visibility. */ - trigger: PropTypes.oneOfType([triggerType, PropTypes.arrayOf(triggerType)]), -}; + trigger?: OverlayTriggerType | OverlayTriggerType[]; +} -Overlay.defaultProps = { - container: undefined, - onEnter: undefined, - onEntered: undefined, - onEntering: undefined, - onExit: undefined, - onExited: undefined, - onExiting: undefined, - onHide: undefined, - placement: 'top', - popperConfig: {}, - rootClose: false, - rootCloseEvent: undefined, - show: false, - target: undefined, - transition: Fade, -}; +function Overlay({ + placement = 'top', + popperConfig = {}, + rootClose = false, + show = false, + transition = Fade, + ...props +}: ParagonOverlayProps) { + return ( + + ); +} -OverlayTrigger.defaultProps = { - defaultShow: false, - delay: undefined, - flip: undefined, - onHide: undefined, - onToggle: undefined, - placement: undefined, - popperConfig: {}, - show: undefined, - target: undefined, - trigger: ['hover', 'focus'], -}; +function OverlayTrigger({ + defaultShow = false, + popperConfig = {}, + trigger = ['hover', 'focus'], + ...props +}: ParagonOverlayTriggerProps) { + return ( + + {props.children} + + ); +} export { OverlayTrigger }; export default Overlay; diff --git a/src/Tooltip/index.tsx b/src/Tooltip/index.tsx index 9d9131b4597..18e19496309 100644 --- a/src/Tooltip/index.tsx +++ b/src/Tooltip/index.tsx @@ -1,39 +1,25 @@ import React from 'react'; -import PropTypes from 'prop-types'; import classNames from 'classnames'; import BaseTooltip, { type TooltipProps as BaseTooltipProps } from 'react-bootstrap/Tooltip'; import { type Placement } from 'react-bootstrap/Overlay'; import type { ComponentWithAsProp } from '../utils/types/bootstrap'; interface TooltipProps extends BaseTooltipProps { + /** The visual style variant of the `Tooltip`. Use `'light'` for a light-themed tooltip. */ variant?: 'light'; } -const PLACEMENT_VARIANTS: Placement[] = [ - 'auto-start', - 'auto', - 'auto-end', - 'top-start', - 'top', - 'top-end', - 'right-start', - 'right', - 'right-end', - 'bottom-end', - 'bottom', - 'bottom-start', - 'left-end', - 'left', - 'left-start', -]; - const Tooltip: ComponentWithAsProp<'div', TooltipProps> = React.forwardRef(({ children, variant, + placement = 'right' as Placement, + bsPrefix = 'tooltip', ...props }, ref) => ( @@ -41,53 +27,4 @@ const Tooltip: ComponentWithAsProp<'div', TooltipProps> = React.forwardRef(({ )); -Tooltip.propTypes = { - ...BaseTooltip.propTypes, - /** An html id attribute, necessary for accessibility. */ - id: PropTypes.string.isRequired, - /** - * Sets the direction the `Tooltip` is positioned towards. - * - * This is generally provided by the `Overlay` component positioning the tooltip. - */ - placement: PropTypes.oneOf(PLACEMENT_VARIANTS), - /** - * An `Overlay` injected set of props for positioning the `Tooltip` arrow. - * - * This is generally provided by the `Overlay` component positioning the tooltip. - */ - arrowProps: PropTypes.shape({ - ref: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ current: PropTypes.element }), - ]), - style: PropTypes.shape({}), - }), - /** Whether the `Overlay` is shown. */ - show: PropTypes.bool, - /** A `Popper.js` config object passed to the the underlying popper instance. */ - popper: PropTypes.shape({}), - /** Overrides underlying component base CSS class name */ - bsPrefix: PropTypes.string, - /** Specifies the content of the `Tooltip` */ - children: PropTypes.node, - /** Specifies class name to append to the base element */ - className: PropTypes.string, - /** The visual style of the `Tooltip` */ - variant: PropTypes.string, -}; - -Tooltip.defaultProps = { - ...Tooltip.defaultProps, - id: undefined, - placement: 'right', - arrowProps: undefined, - show: undefined, - popper: undefined, - children: undefined, - className: undefined, - variant: undefined, - bsPrefix: 'tooltip', -}; - export default Tooltip;