UNPKG

10.8 kBJavaScriptView Raw
1import { __rest } from "tslib";
2/* eslint-disable no-console */
3import * as React from 'react';
4import { KEY_CODES } from '../../helpers/constants';
5import styles from '@patternfly/react-styles/css/components/Popover/popover';
6import { css } from '@patternfly/react-styles';
7import { PopoverContext } from './PopoverContext';
8import { PopoverContent } from './PopoverContent';
9import { PopoverBody } from './PopoverBody';
10import { PopoverHeader } from './PopoverHeader';
11import { PopoverFooter } from './PopoverFooter';
12import { PopoverCloseButton } from './PopoverCloseButton';
13import { PopoverArrow } from './PopoverArrow';
14import popoverMaxWidth from '@patternfly/react-tokens/dist/esm/c_popover_MaxWidth';
15import popoverMinWidth from '@patternfly/react-tokens/dist/esm/c_popover_MinWidth';
16import { FocusTrap } from '../../helpers';
17import { Popper, getOpacityTransition } from '../../helpers/Popper/Popper';
18import { getUniqueId } from '../../helpers/util';
19export var PopoverPosition;
20(function (PopoverPosition) {
21 PopoverPosition["auto"] = "auto";
22 PopoverPosition["top"] = "top";
23 PopoverPosition["bottom"] = "bottom";
24 PopoverPosition["left"] = "left";
25 PopoverPosition["right"] = "right";
26 PopoverPosition["topStart"] = "top-start";
27 PopoverPosition["topEnd"] = "top-end";
28 PopoverPosition["bottomStart"] = "bottom-start";
29 PopoverPosition["bottomEnd"] = "bottom-end";
30 PopoverPosition["leftStart"] = "left-start";
31 PopoverPosition["leftEnd"] = "left-end";
32 PopoverPosition["rightStart"] = "right-start";
33 PopoverPosition["rightEnd"] = "right-end";
34})(PopoverPosition || (PopoverPosition = {}));
35const alertStyle = {
36 default: styles.modifiers.default,
37 info: styles.modifiers.info,
38 success: styles.modifiers.success,
39 warning: styles.modifiers.warning,
40 danger: styles.modifiers.danger
41};
42export const Popover = (_a) => {
43 var { children, position = 'top', enableFlip = true, className = '', isVisible = null, shouldClose = () => null, shouldOpen = () => null, 'aria-label': ariaLabel = '', bodyContent, headerContent = null, headerComponent = 'h6', headerIcon = null, alertSeverityVariant, alertSeverityScreenReaderText, footerContent = null, appendTo = () => document.body, hideOnOutsideClick = true, onHide = () => null, onHidden = () => null, onShow = () => null, onShown = () => null, onMount = () => null, zIndex = 9999, minWidth = popoverMinWidth && popoverMinWidth.value, maxWidth = popoverMaxWidth && popoverMaxWidth.value, closeBtnAriaLabel = 'Close', showClose = true, distance = 25,
44 // For every initial starting position, there are 3 escape positions
45 flipBehavior = ['top', 'right', 'bottom', 'left', 'top', 'right', 'bottom'], animationDuration = 300, id, withFocusTrap: propWithFocusTrap, boundary, tippyProps, reference, hasNoPadding = false, hasAutoWidth = false } = _a, rest = __rest(_a, ["children", "position", "enableFlip", "className", "isVisible", "shouldClose", "shouldOpen", 'aria-label', "bodyContent", "headerContent", "headerComponent", "headerIcon", "alertSeverityVariant", "alertSeverityScreenReaderText", "footerContent", "appendTo", "hideOnOutsideClick", "onHide", "onHidden", "onShow", "onShown", "onMount", "zIndex", "minWidth", "maxWidth", "closeBtnAriaLabel", "showClose", "distance", "flipBehavior", "animationDuration", "id", "withFocusTrap", "boundary", "tippyProps", "reference", "hasNoPadding", "hasAutoWidth"]);
46 if (process.env.NODE_ENV !== 'production') {
47 boundary !== undefined &&
48 console.warn('The Popover boundary prop has been deprecated. If you want to constrain the popper to a specific element use the appendTo prop instead.');
49 tippyProps !== undefined && console.warn('The Popover tippyProps prop has been deprecated and is no longer used.');
50 }
51 // could make this a prop in the future (true | false | 'toggle')
52 // const hideOnClick = true;
53 const uniqueId = id || getUniqueId();
54 const triggerManually = isVisible !== null;
55 const [visible, setVisible] = React.useState(false);
56 const [opacity, setOpacity] = React.useState(0);
57 const [focusTrapActive, setFocusTrapActive] = React.useState(Boolean(propWithFocusTrap));
58 const transitionTimerRef = React.useRef(null);
59 const showTimerRef = React.useRef(null);
60 const hideTimerRef = React.useRef(null);
61 React.useEffect(() => {
62 onMount();
63 }, []);
64 React.useEffect(() => {
65 if (triggerManually) {
66 if (isVisible) {
67 show();
68 }
69 else {
70 hide();
71 }
72 }
73 }, [isVisible, triggerManually]);
74 const show = (withFocusTrap) => {
75 onShow();
76 if (transitionTimerRef.current) {
77 clearTimeout(transitionTimerRef.current);
78 }
79 if (hideTimerRef.current) {
80 clearTimeout(hideTimerRef.current);
81 }
82 showTimerRef.current = setTimeout(() => {
83 setVisible(true);
84 setOpacity(1);
85 propWithFocusTrap !== false && withFocusTrap && setFocusTrapActive(true);
86 onShown();
87 }, 0);
88 };
89 const hide = () => {
90 onHide();
91 if (showTimerRef.current) {
92 clearTimeout(showTimerRef.current);
93 }
94 hideTimerRef.current = setTimeout(() => {
95 setVisible(false);
96 setOpacity(0);
97 setFocusTrapActive(false);
98 transitionTimerRef.current = setTimeout(() => {
99 onHidden();
100 }, animationDuration);
101 }, 0);
102 };
103 const positionModifiers = {
104 top: styles.modifiers.top,
105 bottom: styles.modifiers.bottom,
106 left: styles.modifiers.left,
107 right: styles.modifiers.right,
108 'top-start': styles.modifiers.topLeft,
109 'top-end': styles.modifiers.topRight,
110 'bottom-start': styles.modifiers.bottomLeft,
111 'bottom-end': styles.modifiers.bottomRight,
112 'left-start': styles.modifiers.leftTop,
113 'left-end': styles.modifiers.leftBottom,
114 'right-start': styles.modifiers.rightTop,
115 'right-end': styles.modifiers.rightBottom
116 };
117 const hasCustomMinWidth = minWidth !== popoverMinWidth.value;
118 const hasCustomMaxWidth = maxWidth !== popoverMaxWidth.value;
119 const onDocumentKeyDown = (event) => {
120 if (event.keyCode === KEY_CODES.ESCAPE_KEY && visible) {
121 if (triggerManually) {
122 shouldClose(null, hide, event);
123 }
124 else {
125 hide();
126 }
127 }
128 };
129 const onDocumentClick = (event, triggerElement, popperElement) => {
130 if (hideOnOutsideClick && visible) {
131 // check if we clicked within the popper, if so don't do anything
132 const isChild = popperElement && popperElement.contains(event.target);
133 if (isChild) {
134 // clicked within the popper
135 return;
136 }
137 if (triggerManually) {
138 shouldClose(null, hide, event);
139 }
140 else {
141 hide();
142 }
143 }
144 };
145 const onTriggerClick = (event) => {
146 if (triggerManually) {
147 if (visible) {
148 shouldClose(null, hide, event);
149 }
150 else {
151 shouldOpen(show, event);
152 }
153 }
154 else {
155 if (visible) {
156 hide();
157 }
158 else {
159 show(true);
160 }
161 }
162 };
163 const onContentMouseDown = () => {
164 if (focusTrapActive) {
165 setFocusTrapActive(false);
166 }
167 };
168 const closePopover = (event) => {
169 event.stopPropagation();
170 if (triggerManually) {
171 shouldClose(null, hide, event);
172 }
173 else {
174 hide();
175 }
176 };
177 const content = (React.createElement(FocusTrap, Object.assign({ active: focusTrapActive, focusTrapOptions: {
178 returnFocusOnDeactivate: true,
179 clickOutsideDeactivates: true,
180 fallbackFocus: () => {
181 // If the popover's trigger is focused but scrolled out of view,
182 // FocusTrap will throw an error when the Enter button is used on the trigger.
183 // That is because the Popover is hidden when its trigger is out of view.
184 // Provide a fallback in that case.
185 let node = null;
186 if (document && document.activeElement) {
187 node = document.activeElement;
188 }
189 return node;
190 }
191 }, preventScrollOnDeactivate: true, className: css(styles.popover, alertSeverityVariant && alertStyle[alertSeverityVariant], hasNoPadding && styles.modifiers.noPadding, hasAutoWidth && styles.modifiers.widthAuto, className), role: "dialog", "aria-modal": "true", "aria-label": headerContent ? undefined : ariaLabel, "aria-labelledby": headerContent ? `popover-${uniqueId}-header` : undefined, "aria-describedby": `popover-${uniqueId}-body`, onMouseDown: onContentMouseDown, style: {
192 minWidth: hasCustomMinWidth ? minWidth : null,
193 maxWidth: hasCustomMaxWidth ? maxWidth : null,
194 opacity,
195 transition: getOpacityTransition(animationDuration)
196 } }, rest),
197 React.createElement(PopoverArrow, null),
198 React.createElement(PopoverContent, null,
199 showClose && React.createElement(PopoverCloseButton, { onClose: closePopover, "aria-label": closeBtnAriaLabel }),
200 headerContent && (React.createElement(PopoverHeader, { id: `popover-${uniqueId}-header`, icon: headerIcon, alertSeverityVariant: alertSeverityVariant, alertSeverityScreenReaderText: alertSeverityScreenReaderText || `${alertSeverityVariant} alert:`, titleHeadingLevel: headerComponent }, typeof headerContent === 'function' ? headerContent(hide) : headerContent)),
201 React.createElement(PopoverBody, { id: `popover-${uniqueId}-body` }, typeof bodyContent === 'function' ? bodyContent(hide) : bodyContent),
202 footerContent && (React.createElement(PopoverFooter, { id: `popover-${uniqueId}-footer` }, typeof footerContent === 'function' ? footerContent(hide) : footerContent)))));
203 return (React.createElement(PopoverContext.Provider, { value: { headerComponent } },
204 React.createElement(Popper, { trigger: children, reference: reference, popper: content, popperMatchesTriggerWidth: false, appendTo: appendTo, isVisible: visible, positionModifiers: positionModifiers, distance: distance, placement: position, onTriggerClick: onTriggerClick, onDocumentClick: onDocumentClick, onDocumentKeyDown: onDocumentKeyDown, enableFlip: enableFlip, zIndex: zIndex, flipBehavior: flipBehavior })));
205};
206Popover.displayName = 'Popover';
207//# sourceMappingURL=Popover.js.map
\No newline at end of file