diff --git a/src/Popover/Popover.test.jsx b/src/Popover/Popover.test.tsx similarity index 100% rename from src/Popover/Popover.test.jsx rename to src/Popover/Popover.test.tsx diff --git a/src/Popover/index.jsx b/src/Popover/index.jsx deleted file mode 100644 index 07be9806a00..00000000000 --- a/src/Popover/index.jsx +++ /dev/null @@ -1,118 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import BasePopover from 'react-bootstrap/Popover'; -import BasePopoverTitle from 'react-bootstrap/PopoverTitle'; -import BasePopoverContent from 'react-bootstrap/PopoverContent'; - -const PLACEMENT_VARIANTS = [ - 'auto', - 'top', - 'bottom', - 'left', - 'right', -]; - -const Popover = React.forwardRef(({ - children, - variant, - ...props -}, ref) => ( - - {children} - -)); - -function PopoverTitle(props) { - return ; -} -function PopoverContent(props) { - return ; -} - -const commonPropTypes = { - /** Specifies the base element */ - as: PropTypes.elementType, - /** Overrides underlying component base CSS class name */ - bsPrefix: PropTypes.string, -}; - -PopoverTitle.propTypes = commonPropTypes; -PopoverContent.propTypes = commonPropTypes; - -Popover.propTypes = { - ...BasePopover.propTypes, - /** An html id attribute, necessary for accessibility. */ - id: PropTypes.string.isRequired, - /** - * Sets the direction the Popover is positioned towards. - * - * This is generally provided by the `Overlay` component positioning the popover. - */ - placement: PropTypes.oneOf(PLACEMENT_VARIANTS), - /** - * When this prop is set, it creates a `Popover` with - * a `Popover.Title` inside passing the children directly to it. - */ - title: PropTypes.string, - /** - * An `Overlay` injected set of props for positioning the popover arrow. - * - * This is generally provided by the `Overlay` component positioning the popover. - */ - arrowProps: PropTypes.shape({ - ref: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ current: PropTypes.element }), - ]), - style: PropTypes.shape({}), - }), - /** - * When this prop is set, it creates a `Popover` with - * a `Popover.Content` inside passing the children directly to it. - */ - content: PropTypes.bool, - /** A `Popper.js` config object passed to the the underlying popper instance. */ - popper: PropTypes.shape({}), - /** Whether the `Overlay` is shown. */ - show: PropTypes.bool, - /** Specifies the content of the `Overlay` */ - children: PropTypes.node, - /** Specifies class name to append to the base element */ - className: PropTypes.string, - /** The visual style of the `Overlay` */ - variant: PropTypes.string, -}; - -Popover.defaultProps = { - ...BasePopover.defaultProps, - placement: 'right', - title: undefined, - arrowProps: undefined, - content: undefined, - popper: undefined, - show: undefined, - children: undefined, - className: undefined, - variant: undefined, -}; - -PopoverTitle.defaultProps = { - as: 'div', - bsPrefix: 'popover-header', -}; - -PopoverContent.defaultProps = { - as: 'div', - bsPrefix: 'popover-body', -}; - -Popover.Title = PopoverTitle; -Popover.Content = PopoverContent; - -export { PopoverTitle, PopoverContent }; -export default Popover; diff --git a/src/Popover/index.tsx b/src/Popover/index.tsx new file mode 100644 index 00000000000..d1a30d0d8bd --- /dev/null +++ b/src/Popover/index.tsx @@ -0,0 +1,119 @@ +import React from 'react'; +import classNames from 'classnames'; +import BasePopover from 'react-bootstrap/Popover'; +import BasePopoverTitle from 'react-bootstrap/PopoverTitle'; +import BasePopoverContent from 'react-bootstrap/PopoverContent'; +import { ArrowProps } from 'react-bootstrap/esm/Overlay'; + +type PlacementVariant = 'auto' | 'top' | 'bottom' | 'left' | 'right'; + +interface PopoverProps { + /** An html id attribute, necessary for accessibility. */ + id: string; + /** + * Sets the direction the Popover is positioned towards. + * + * This is generally provided by the `Overlay` component positioning the popover. + */ + placement?: PlacementVariant; + /** + * When this prop is set, it creates a `Popover` with + * a `Popover.Title` inside passing the children directly to it. + */ + title?: string; + /** + * An `Overlay` injected set of props for positioning the popover arrow. + * + * This is generally provided by the `Overlay` component positioning the popover. + */ + arrowProps?: ArrowProps; + /** + * When this prop is set, it creates a `Popover` with + * a `Popover.Content` inside passing the children directly to it. + */ + content?: boolean; + /** A `Popper.js` config object passed to the the underlying popper instance. */ + popper?: Record; + /** Whether the `Overlay` is shown. */ + show?: boolean; + /** Specifies the content of the `Overlay` */ + children?: React.ReactNode; + /** Specifies class name to append to the base element */ + className?: string; + /** The visual style of the `Overlay` */ + variant?: string; + /** Specifies the base element */ + as?: React.ElementType; + /** Overrides underlying component base CSS class name */ + bsPrefix?: string; +} + +interface PopoverSubcomponentProps { + /** Specifies the base element */ + as?: React.ElementType; + /** Overrides underlying component base CSS class name */ + bsPrefix?: string; + /** Specifies class name to append to the base element */ + className?: string; + /** Specifies the content of the component */ + children?: React.ReactNode; +} + +const Popover = React.forwardRef(({ + children, + variant, + placement = 'right', + title, + arrowProps, + content, + popper, + show, + className, + ...props +}, ref) => ( + + {children} + +)); + +function PopoverTitle({ + as = 'div', + bsPrefix = 'popover-header', + ...props +}: PopoverSubcomponentProps) { + return ; +} + +function PopoverContent({ + as = 'div', + bsPrefix = 'popover-body', + ...props +}: PopoverSubcomponentProps) { + return ; +} + +Popover.displayName = 'Popover'; +PopoverTitle.displayName = 'Popover.Title'; +PopoverContent.displayName = 'Popover.Content'; + +// Create the compound component with proper typing +const PopoverWithSubcomponents = Object.assign(Popover, { + Title: PopoverTitle, + Content: PopoverContent, +}) as typeof Popover & { + Title: typeof PopoverTitle; + Content: typeof PopoverContent; +}; + +export { PopoverTitle, PopoverContent }; +export default PopoverWithSubcomponents; diff --git a/src/index.ts b/src/index.ts index 7e11e26a8c4..614f730f72b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ export { default as ModalContext } from './Modal/ModalContext'; export { default as ModalDialog } from './Modal/ModalDialog'; export { default as ModalLayer } from './Modal/ModalLayer'; export { default as Overlay, OverlayTrigger } from './Overlay'; +export { default as Popover, PopoverTitle, PopoverContent } from './Popover'; export { default as Portal } from './Modal/Portal'; export { default as Spinner } from './Spinner'; export { default as Stack } from './Stack'; @@ -146,8 +147,6 @@ export { // @ts-ignore: has yet to be converted to TypeScript } from './Pagination'; // @ts-ignore: has yet to be converted to TypeScript -export { default as Popover, PopoverTitle, PopoverContent } from './Popover'; -// @ts-ignore: has yet to be converted to TypeScript export { default as ProgressBar } from './ProgressBar'; // @ts-ignore: has yet to be converted to TypeScript export { default as ProductTour } from './ProductTour';