Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Alert/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react/require-default-props */
import React, {
useCallback,
useEffect,
Expand Down
28 changes: 7 additions & 21 deletions src/Card/BaseCard.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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>;
Expand Down Expand Up @@ -69,24 +75,4 @@ const BaseCard : BaseCardType = React.forwardRef<HTMLDivElement, Props>(
},
);

/* 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;
40 changes: 16 additions & 24 deletions src/Chip/ChipIcon.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLButtonElement> & MouseEventHandler<HTMLButtonElement>, alt: string }
| { onClick?: undefined, alt?: undefined }
| {
/** Callback for click and keyboard events on the icon button. */
onClick: KeyboardEventHandler<HTMLButtonElement> & MouseEventHandler<HTMLButtonElement>;
/** 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 (
Expand All @@ -35,20 +43,4 @@ function ChipIcon({
return <Icon src={src} className={className} size="sm" />;
}

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;
18 changes: 3 additions & 15 deletions src/Modal/ModalDialogHeader.tsx
Original file line number Diff line number Diff line change
@@ -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;
}

Expand All @@ -27,18 +29,4 @@ const ModalDialogHeader: HeaderType = React.forwardRef<HTMLDivElement, Props>(({
)
));

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;
200 changes: 79 additions & 121 deletions src/Overlay/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,168 +2,126 @@
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 <BaseOverlay {...props} />;
}
function OverlayTrigger(props: OverlayTriggerProps) {
return (
<BaseOverlayTrigger {...props}>
{props.children}
</BaseOverlayTrigger>
);
}

const triggerType = PropTypes.oneOf(TRIGGER_VARIANTS);

Overlay.propTypes = {
export interface ParagonOverlayProps extends OverlayProps {

Check failure on line 10 in src/Overlay/index.tsx

View workflow job for this annotation

GitHub Actions / tests

Interface 'ParagonOverlayProps' incorrectly extends interface '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 `<Fade>` transition,
* or a custom react-transition-group `<Transition>` 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 (
<BaseOverlay

Check failure on line 97 in src/Overlay/index.tsx

View workflow job for this annotation

GitHub Actions / tests

Type '{ children: OverlayChildren; container?: DOMContainer<HTMLElement> | undefined; onEnter?: ((node: HTMLElement, isAppearing: boolean) => any) | undefined; ... 16 more ...; transition: TransitionType; }' is not assignable to type 'Pick<Pick<OverlayProps, keyof OverlayProps> & Pick<InferProps<{ container: Requireable<any>; target: Requireable<any>; show: Requireable<...>; ... 11 more ...; placement: Requireable<...>; }>, never> & Pick<...>, "children" | ... 14 more ... | "onExiting">'.
placement={placement}
popperConfig={popperConfig}
rootClose={rootClose}
show={show}
transition={transition}
{...props}
/>
);
}

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 (
<BaseOverlayTrigger
defaultShow={defaultShow}
popperConfig={popperConfig}
trigger={trigger}
{...props}
>
{props.children}
</BaseOverlayTrigger>
);
}

export { OverlayTrigger };
export default Overlay;
Loading
Loading