Skip to content
Merged
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
29 changes: 27 additions & 2 deletions packages/react-core/src/components/Popover/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,20 @@ 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 => <Button onClick={() => hide()}>Close</Button>}
*/
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;
/**
Expand Down Expand Up @@ -198,6 +204,14 @@ export interface PopoverProps {
tippyProps?: Partial<TippyProps>;
}

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<PopoverProps> = ({
children,
position = 'top',
Expand All @@ -210,6 +224,9 @@ export const Popover: React.FunctionComponent<PopoverProps> = ({
bodyContent,
headerContent = null,
headerComponent = 'h6',
headerIcon = null,
alertSeverityVariant,
alertSeverityScreenReaderText,
footerContent = null,
appendTo = () => document.body,
hideOnOutsideClick = true,
Expand Down Expand Up @@ -253,6 +270,7 @@ export const Popover: React.FunctionComponent<PopoverProps> = ({
const transitionTimerRef = React.useRef(null);
const showTimerRef = React.useRef(null);
const hideTimerRef = React.useRef(null);

React.useEffect(() => {
onMount();
}, []);
Expand Down Expand Up @@ -383,6 +401,7 @@ export const Popover: React.FunctionComponent<PopoverProps> = ({
preventScrollOnDeactivate
className={css(
styles.popover,
alertSeverityVariant && alertStyle[alertSeverityVariant],
hasNoPadding && styles.modifiers.noPadding,
hasAutoWidth && styles.modifiers.widthAuto,
className
Expand All @@ -405,7 +424,13 @@ export const Popover: React.FunctionComponent<PopoverProps> = ({
<PopoverContent>
{showClose && <PopoverCloseButton onClose={closePopover} aria-label={closeBtnAriaLabel} />}
{headerContent && (
<PopoverHeader id={`popover-${uniqueId}-header`}>
<PopoverHeader
id={`popover-${uniqueId}-header`}
icon={headerIcon}
alertSeverityVariant={alertSeverityVariant}
alertSeverityScreenReaderText={alertSeverityScreenReaderText || `${alertSeverityVariant} alert:`}
titleHeadingLevel={headerComponent}
>
{typeof headerContent === 'function' ? headerContent(hide) : headerContent}
</PopoverHeader>
)}
Expand Down
19 changes: 11 additions & 8 deletions packages/react-core/src/components/Popover/PopoverBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement> {
/** 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<PopoverBodyProps> = ({
children,
id,
className,
...props
}: PopoverBodyProps) => (
<div className={css(styles.popoverBody)} id={id} {...props}>
<div className={css(styles.popoverBody, className)} id={id} {...props}>
{children}
</div>
);
PopoverBody.displayName = 'PopoverBody';

export interface PopoverBodyProps extends React.HTMLProps<HTMLDivElement> {
/** PopoverBody id */
id: string;
/** PopoverBody content */
children: React.ReactNode;
}
14 changes: 7 additions & 7 deletions packages/react-core/src/components/Popover/PopoverFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLDivElement> {
/** Additional classes added to the Popover footer */
className?: string;
/** Footer node */
children: React.ReactNode;
}

export const PopoverFooter: React.FunctionComponent<PopoverFooterProps> = ({
children,
className = '',
Expand All @@ -12,10 +19,3 @@ export const PopoverFooter: React.FunctionComponent<PopoverFooterProps> = ({
</footer>
);
PopoverFooter.displayName = 'PopoverFooter';

export interface PopoverFooterProps extends React.HTMLProps<HTMLDivElement> {
/** Additional classes added to the Popover Footer */
className?: string;
/** Footer node */
children: React.ReactNode;
}
62 changes: 45 additions & 17 deletions packages/react-core/src/components/Popover/PopoverHeader.tsx
Original file line number Diff line number Diff line change
@@ -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<React.HTMLProps<HTMLHeadingElement>, '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<PopoverHeaderProps> = ({
children,
icon,
className,
titleHeadingLevel = 'h6',
alertSeverityVariant,
id,
alertSeverityScreenReaderText,
...props
}: PopoverHeaderProps) => (
<PopoverContext.Consumer>
{({ headerComponent }) => (
<Title headingLevel={headerComponent} size={TitleSizes.md} id={id} {...props}>
{children}
</Title>
)}
</PopoverContext.Consumer>
);
PopoverHeader.displayName = 'PopoverHeader';
}: PopoverHeaderProps) => {
const HeadingLevel = titleHeadingLevel;

export interface PopoverHeaderProps extends Omit<React.HTMLProps<HTMLDivElement>, 'size'> {
/** popover id */
id: string;
/** header node */
children: React.ReactNode;
}
return icon || alertSeverityVariant ? (
<header className={css('pf-c-popover__header', className)} id={id} {...props}>
<HeadingLevel className={css(styles.popoverTitle, icon && styles.modifiers.icon)}>
{icon && <PopoverHeaderIcon>{icon}</PopoverHeaderIcon>}
{alertSeverityVariant && alertSeverityScreenReaderText && (
<span className="pf-u-screen-reader">{alertSeverityScreenReaderText}</span>
)}
<PopoverHeaderText>{children}</PopoverHeaderText>
</HeadingLevel>
</header>
) : (
<Title headingLevel={titleHeadingLevel} size={TitleSizes.md} id={id} className={className} {...props}>
{children}
</Title>
);
};
PopoverHeader.displayName = 'PopoverHeader';
21 changes: 21 additions & 0 deletions packages/react-core/src/components/Popover/PopoverHeaderIcon.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLSpanElement> {
/** Content of the header icon */
children: React.ReactNode;
/** Class to be applied to the header icon */
className?: string;
}

export const PopoverHeaderIcon: React.FunctionComponent<PopoverHeaderIconProps> = ({
children,
className,
...props
}: PopoverHeaderIconProps) => (
<span className={css(styles.popoverTitleIcon, className)} {...props}>
{children}
</span>
);
PopoverHeaderIcon.displayName = 'PopoverHeaderIcon';
21 changes: 21 additions & 0 deletions packages/react-core/src/components/Popover/PopoverHeaderText.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLDivElement> {
/** Content of the header text */
children: React.ReactNode;
/** Class to be applied to the header text */
className?: string;
}

export const PopoverHeaderText: React.FunctionComponent<PopoverHeaderTextProps> = ({
children,
className,
...props
}: PopoverHeaderTextProps) => (
<span className={css(styles.popoverTitleText, className)} {...props}>
{children}
</span>
);
PopoverHeaderText.displayName = 'PopoverHeaderText';
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`PopoverHeader should match snapshot (auto-generated) 1`] = `
<ContextConsumer>
<Component />
</ContextConsumer>
<Title
headingLevel="h6"
id="string"
size="md"
>
<div>
ReactNode
</div>
</Title>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ exports[`popover can close from content (uncontrolled) 1`] = `
onClose={[Function]}
/>
<PopoverHeader
alertSeverityScreenReaderText="undefined alert:"
icon={null}
id="popover-test-header"
titleHeadingLevel="h6"
>
<div>
Popover header
Expand Down Expand Up @@ -184,7 +187,10 @@ exports[`popover can have a custom minimum width 1`] = `
onClose={[Function]}
/>
<PopoverHeader
alertSeverityScreenReaderText="undefined alert:"
icon={null}
id="popover-test-header"
titleHeadingLevel="h6"
>
<div>
Popover Header
Expand Down Expand Up @@ -289,7 +295,10 @@ exports[`popover can specify position as object value 1`] = `
onClose={[Function]}
/>
<PopoverHeader
alertSeverityScreenReaderText="undefined alert:"
icon={null}
id="popover-test-header"
titleHeadingLevel="h6"
>
<div>
Popover Header
Expand Down Expand Up @@ -394,7 +403,10 @@ exports[`popover renders close-button, header and body 1`] = `
onClose={[Function]}
/>
<PopoverHeader
alertSeverityScreenReaderText="undefined alert:"
icon={null}
id="popover-test-header"
titleHeadingLevel="h6"
>
<div>
Popover Header
Expand Down
Loading