diff --git a/packages/react-core/src/components/Popover/Popover.tsx b/packages/react-core/src/components/Popover/Popover.tsx index 6639ba58969..a5f0b7220b0 100644 --- a/packages/react-core/src/components/Popover/Popover.tsx +++ b/packages/react-core/src/components/Popover/Popover.tsx @@ -104,7 +104,7 @@ export interface PopoverProps { */ footerContent?: React.ReactNode | ((hide: () => void) => React.ReactNode); /** - * Header content + * Simple header content to be placed within a title. * If you want to close the popover after an action within the bodyContent, you can use the isVisible prop for manual control, * or you can provide a function which will receive a callback as an argument to hide the popover * i.e. headerContent={hide => } @@ -112,6 +112,12 @@ export interface PopoverProps { headerContent?: React.ReactNode | ((hide: () => void) => React.ReactNode); /** Sets the heading level to use for the popover header. Default is h6. */ headerComponent?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + /** @beta Icon to be displayed in the popover header **/ + headerIcon?: React.ReactNode; + /** @beta Severity variants for an alert popover. This modifies the color of the header to match the severity. */ + alertSeverityVariant?: 'default' | 'info' | 'warning' | 'success' | 'danger'; + /** @beta Text announced by screen reader when alert severity variant is set to indicate severity level */ + alertSeverityScreenReaderText?: string; /** Hides the popover when a click occurs outside (only works if isVisible is not controlled by the user) */ hideOnOutsideClick?: boolean; /** @@ -198,6 +204,14 @@ export interface PopoverProps { tippyProps?: Partial; } +const alertStyle = { + default: styles.modifiers.default, + info: styles.modifiers.info, + success: styles.modifiers.success, + warning: styles.modifiers.warning, + danger: styles.modifiers.danger +}; + export const Popover: React.FunctionComponent = ({ children, position = 'top', @@ -210,6 +224,9 @@ export const Popover: React.FunctionComponent = ({ bodyContent, headerContent = null, headerComponent = 'h6', + headerIcon = null, + alertSeverityVariant, + alertSeverityScreenReaderText, footerContent = null, appendTo = () => document.body, hideOnOutsideClick = true, @@ -253,6 +270,7 @@ export const Popover: React.FunctionComponent = ({ const transitionTimerRef = React.useRef(null); const showTimerRef = React.useRef(null); const hideTimerRef = React.useRef(null); + React.useEffect(() => { onMount(); }, []); @@ -383,6 +401,7 @@ export const Popover: React.FunctionComponent = ({ preventScrollOnDeactivate className={css( styles.popover, + alertSeverityVariant && alertStyle[alertSeverityVariant], hasNoPadding && styles.modifiers.noPadding, hasAutoWidth && styles.modifiers.widthAuto, className @@ -405,7 +424,13 @@ export const Popover: React.FunctionComponent = ({ {showClose && } {headerContent && ( - + {typeof headerContent === 'function' ? headerContent(hide) : headerContent} )} diff --git a/packages/react-core/src/components/Popover/PopoverBody.tsx b/packages/react-core/src/components/Popover/PopoverBody.tsx index e31bd35f852..28a7d4e8112 100644 --- a/packages/react-core/src/components/Popover/PopoverBody.tsx +++ b/packages/react-core/src/components/Popover/PopoverBody.tsx @@ -2,20 +2,23 @@ import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Popover/popover'; import { css } from '@patternfly/react-styles'; +export interface PopoverBodyProps extends React.HTMLProps { + /** Popover body id */ + id: string; + /** Popover body content */ + children: React.ReactNode; + /** Classes to be applied to the popover body. */ + className?: string; +} + export const PopoverBody: React.FunctionComponent = ({ children, id, + className, ...props }: PopoverBodyProps) => ( -
+
{children}
); PopoverBody.displayName = 'PopoverBody'; - -export interface PopoverBodyProps extends React.HTMLProps { - /** PopoverBody id */ - id: string; - /** PopoverBody content */ - children: React.ReactNode; -} diff --git a/packages/react-core/src/components/Popover/PopoverFooter.tsx b/packages/react-core/src/components/Popover/PopoverFooter.tsx index 90d2671e9dd..8643cbe5587 100644 --- a/packages/react-core/src/components/Popover/PopoverFooter.tsx +++ b/packages/react-core/src/components/Popover/PopoverFooter.tsx @@ -2,6 +2,13 @@ import * as React from 'react'; import styles from '@patternfly/react-styles/css/components/Popover/popover'; import { css } from '@patternfly/react-styles'; +export interface PopoverFooterProps extends React.HTMLProps { + /** Additional classes added to the Popover footer */ + className?: string; + /** Footer node */ + children: React.ReactNode; +} + export const PopoverFooter: React.FunctionComponent = ({ children, className = '', @@ -12,10 +19,3 @@ export const PopoverFooter: React.FunctionComponent = ({ ); PopoverFooter.displayName = 'PopoverFooter'; - -export interface PopoverFooterProps extends React.HTMLProps { - /** Additional classes added to the Popover Footer */ - className?: string; - /** Footer node */ - children: React.ReactNode; -} diff --git a/packages/react-core/src/components/Popover/PopoverHeader.tsx b/packages/react-core/src/components/Popover/PopoverHeader.tsx index 5c9ee65d36b..18c06911508 100644 --- a/packages/react-core/src/components/Popover/PopoverHeader.tsx +++ b/packages/react-core/src/components/Popover/PopoverHeader.tsx @@ -1,25 +1,53 @@ import * as React from 'react'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/Popover/popover'; import { Title, TitleSizes } from '../Title'; -import { PopoverContext } from './PopoverContext'; +import { PopoverHeaderIcon } from './PopoverHeaderIcon'; +import { PopoverHeaderText } from './PopoverHeaderText'; + +export interface PopoverHeaderProps extends Omit, 'size'> { + /** Content of the popover header. */ + children: React.ReactNode; + /** Indicates the header contains an icon. */ + icon?: React.ReactNode; + /** Class to be applied to the header. */ + className?: string; + /** Heading level of the header title */ + titleHeadingLevel?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; + /** Severity variants for an alert popover. This modifies the color of the header to match the severity. */ + alertSeverityVariant?: 'default' | 'info' | 'warning' | 'success' | 'danger'; + /** Id of the header */ + id?: string; + /** Text announced by screen reader when alert severity variant is set to indicate severity level */ + alertSeverityScreenReaderText?: string; +} export const PopoverHeader: React.FunctionComponent = ({ children, + icon, + className, + titleHeadingLevel = 'h6', + alertSeverityVariant, id, + alertSeverityScreenReaderText, ...props -}: PopoverHeaderProps) => ( - - {({ headerComponent }) => ( - - {children} - - )} - -); -PopoverHeader.displayName = 'PopoverHeader'; +}: PopoverHeaderProps) => { + const HeadingLevel = titleHeadingLevel; -export interface PopoverHeaderProps extends Omit, 'size'> { - /** popover id */ - id: string; - /** header node */ - children: React.ReactNode; -} + return icon || alertSeverityVariant ? ( +
+ + {icon && {icon}} + {alertSeverityVariant && alertSeverityScreenReaderText && ( + {alertSeverityScreenReaderText} + )} + {children} + +
+ ) : ( + + {children} + + ); +}; +PopoverHeader.displayName = 'PopoverHeader'; diff --git a/packages/react-core/src/components/Popover/PopoverHeaderIcon.tsx b/packages/react-core/src/components/Popover/PopoverHeaderIcon.tsx new file mode 100644 index 00000000000..1ec4b05c7fe --- /dev/null +++ b/packages/react-core/src/components/Popover/PopoverHeaderIcon.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/Popover/popover'; + +export interface PopoverHeaderIconProps extends React.HTMLProps { + /** Content of the header icon */ + children: React.ReactNode; + /** Class to be applied to the header icon */ + className?: string; +} + +export const PopoverHeaderIcon: React.FunctionComponent = ({ + children, + className, + ...props +}: PopoverHeaderIconProps) => ( + + {children} + +); +PopoverHeaderIcon.displayName = 'PopoverHeaderIcon'; diff --git a/packages/react-core/src/components/Popover/PopoverHeaderText.tsx b/packages/react-core/src/components/Popover/PopoverHeaderText.tsx new file mode 100644 index 00000000000..ef44d4b80c7 --- /dev/null +++ b/packages/react-core/src/components/Popover/PopoverHeaderText.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { css } from '@patternfly/react-styles'; +import styles from '@patternfly/react-styles/css/components/Popover/popover'; + +export interface PopoverHeaderTextProps extends React.HTMLProps { + /** Content of the header text */ + children: React.ReactNode; + /** Class to be applied to the header text */ + className?: string; +} + +export const PopoverHeaderText: React.FunctionComponent = ({ + children, + className, + ...props +}: PopoverHeaderTextProps) => ( + + {children} + +); +PopoverHeaderText.displayName = 'PopoverHeaderText'; diff --git a/packages/react-core/src/components/Popover/__tests__/Generated/__snapshots__/PopoverHeader.test.tsx.snap b/packages/react-core/src/components/Popover/__tests__/Generated/__snapshots__/PopoverHeader.test.tsx.snap index 425cf6c4f3f..bdbfe5886d3 100644 --- a/packages/react-core/src/components/Popover/__tests__/Generated/__snapshots__/PopoverHeader.test.tsx.snap +++ b/packages/react-core/src/components/Popover/__tests__/Generated/__snapshots__/PopoverHeader.test.tsx.snap @@ -1,7 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`PopoverHeader should match snapshot (auto-generated) 1`] = ` - - - + + <div> + ReactNode + </div> + `; diff --git a/packages/react-core/src/components/Popover/__tests__/__snapshots__/Popover.test.tsx.snap b/packages/react-core/src/components/Popover/__tests__/__snapshots__/Popover.test.tsx.snap index 14b3519fcbf..588cc5818b2 100644 --- a/packages/react-core/src/components/Popover/__tests__/__snapshots__/Popover.test.tsx.snap +++ b/packages/react-core/src/components/Popover/__tests__/__snapshots__/Popover.test.tsx.snap @@ -62,7 +62,10 @@ exports[`popover can close from content (uncontrolled) 1`] = ` onClose={[Function]} />
Popover header @@ -184,7 +187,10 @@ exports[`popover can have a custom minimum width 1`] = ` onClose={[Function]} />
Popover Header @@ -289,7 +295,10 @@ exports[`popover can specify position as object value 1`] = ` onClose={[Function]} />
Popover Header @@ -394,7 +403,10 @@ exports[`popover renders close-button, header and body 1`] = ` onClose={[Function]} />
Popover Header diff --git a/packages/react-core/src/components/Popover/examples/Popover.md b/packages/react-core/src/components/Popover/examples/Popover.md index 787601fd748..3d34b811135 100644 --- a/packages/react-core/src/components/Popover/examples/Popover.md +++ b/packages/react-core/src/components/Popover/examples/Popover.md @@ -5,6 +5,13 @@ cssPrefix: pf-c-popover propComponents: ['Popover'] --- +import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; +import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; +import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; +import BullhornIcon from '@patternfly/react-icons/dist/esm/icons/bullhorn-icon'; + ## Examples ### Basic @@ -222,13 +229,11 @@ class AdvancedPopover extends React.Component { this.setState({ position: event.target.value }); }} > - { - Object.values(PopoverPosition).map(position => ( - - )) - } + {Object.values(PopoverPosition).map(position => ( + + ))} + } + bodyContent={
Popovers are triggered by click rather than hover.
} + footerContent="Popover footer" + > + +
+
; +``` + +### Alert popover + +```ts isBeta +import React from 'react'; +import { Popover, Button } from '@patternfly/react-core'; +import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon'; +import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon'; +import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; +import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; + +const AlertPopover = () => { + const [alertSeverityVariant, setAlertSeverityVariant] = React.useState('default'); + const alertIcons = { + default: , + info: , + success: , + warning: , + danger: + }; + + return ( +
+
+ Alert variant: + +
+
+ Popovers are triggered by click rather than hover.
} + footerContent="Popover footer" + > + + +
+
+ ); +}; +``` diff --git a/packages/react-core/src/demos/BackToTop.md b/packages/react-core/src/demos/BackToTop.md index c5ae8f8795c..9340f4004dd 100644 --- a/packages/react-core/src/demos/BackToTop.md +++ b/packages/react-core/src/demos/BackToTop.md @@ -12,4 +12,4 @@ import DashboardWrapper from './examples/DashboardWrapper'; Note that `tabIndex={0}` is added to the scrolling `PageSection` of the page to allow keyboard users the ability to focus and scroll. ```js isFullscreen file="./examples/BackToTop/BackToTopNameDemo.tsx" -``` \ No newline at end of file +```