@khanacademy/wonder-blocks-popover 6.0.7 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import _extends from '@babel/runtime/helpers/extends';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import * as ReactDOM from 'react-dom';
4
4
  import { View, Id, addStyle } from '@khanacademy/wonder-blocks-core';
@@ -11,753 +11,26 @@ import { actionStyles } from '@khanacademy/wonder-blocks-styles';
11
11
  import xIcon from '@phosphor-icons/core/regular/x.svg';
12
12
  import IconButton from '@khanacademy/wonder-blocks-icon-button';
13
13
 
14
- const defaultContext = {
15
- close: undefined,
16
- placement: "top"
17
- };
18
- const PopoverContext = React.createContext(defaultContext);
19
- PopoverContext.displayName = "PopoverContext";
14
+ const defaultContext={close:undefined,placement:"top"};const PopoverContext=React.createContext(defaultContext);PopoverContext.displayName="PopoverContext";
20
15
 
21
- class PopoverAnchor extends React.Component {
22
- componentDidMount() {
23
- const anchorNode = ReactDOM.findDOMNode(this);
24
- if (anchorNode) {
25
- this.props.anchorRef(anchorNode);
26
- }
27
- }
28
- render() {
29
- const {
30
- children,
31
- id,
32
- onClick,
33
- "aria-controls": ariaControls,
34
- "aria-expanded": ariaExpanded
35
- } = this.props;
36
- const sharedProps = {
37
- id: id,
38
- "aria-controls": ariaControls,
39
- "aria-expanded": ariaExpanded
40
- };
41
- if (typeof children === "function") {
42
- const renderedChildren = children({
43
- open: onClick
44
- });
45
- return React.cloneElement(renderedChildren, sharedProps);
46
- } else {
47
- return React.cloneElement(children, _extends({}, children.props, sharedProps, {
48
- onClick: children.props.onClick ? e => {
49
- e.stopPropagation();
50
- children.props.onClick();
51
- onClick();
52
- } : onClick
53
- }));
54
- }
55
- }
56
- }
16
+ class PopoverAnchor extends React.Component{componentDidMount(){const anchorNode=ReactDOM.findDOMNode(this);if(anchorNode){this.props.anchorRef(anchorNode);}}render(){const{children,id,onClick,"aria-controls":ariaControls,"aria-expanded":ariaExpanded}=this.props;const sharedProps={id:id,"aria-controls":ariaControls,"aria-expanded":ariaExpanded};if(typeof children==="function"){const renderedChildren=children({open:onClick});return React.cloneElement(renderedChildren,sharedProps)}else {return React.cloneElement(children,{...children.props,...sharedProps,onClick:children.props.onClick?e=>{e.stopPropagation();children.props.onClick();onClick();}:onClick})}}}
57
17
 
58
- class PopoverDialog extends React.Component {
59
- componentDidUpdate(prevProps) {
60
- if (prevProps.placement !== this.props.placement) {
61
- this.props.onUpdate(this.props.placement);
62
- }
63
- }
64
- render() {
65
- const {
66
- placement,
67
- children,
68
- id,
69
- isReferenceHidden,
70
- updateBubbleRef,
71
- updateTailRef,
72
- tailOffset,
73
- style,
74
- showTail,
75
- "aria-describedby": ariaDescribedby,
76
- "aria-labelledby": ariaLabelledBy,
77
- "aria-label": ariaLabel
78
- } = this.props;
79
- const contentProps = children.props;
80
- const color = contentProps.color;
81
- return React.createElement(React.Fragment, null, React.createElement(View, {
82
- "aria-label": ariaLabel,
83
- "aria-describedby": ariaDescribedby,
84
- "aria-labelledby": ariaLabelledBy,
85
- id: id,
86
- role: "dialog",
87
- ref: updateBubbleRef,
88
- "data-placement": placement,
89
- style: [isReferenceHidden && styles$2.hide, styles$2[`content-${placement}`], style]
90
- }, children, React.createElement(TooltipTail, {
91
- show: showTail,
92
- color: color,
93
- updateRef: updateTailRef,
94
- placement: placement,
95
- offset: tailOffset
96
- })));
97
- }
98
- }
99
- const styles$2 = StyleSheet.create({
100
- hide: {
101
- pointerEvents: "none",
102
- opacity: 0,
103
- backgroundColor: "transparent",
104
- color: "transparent"
105
- },
106
- "content-top": {
107
- flexDirection: "column"
108
- },
109
- "content-right": {
110
- flexDirection: "row-reverse"
111
- },
112
- "content-bottom": {
113
- flexDirection: "column-reverse"
114
- },
115
- "content-left": {
116
- flexDirection: "row"
117
- }
118
- });
18
+ class PopoverDialog extends React.Component{componentDidUpdate(prevProps){if(prevProps.placement!==this.props.placement){this.props.onUpdate(this.props.placement);}}render(){const{placement,children,id,isReferenceHidden,updateBubbleRef,updateTailRef,tailOffset,style,showTail,"aria-describedby":ariaDescribedby,"aria-labelledby":ariaLabelledBy,"aria-label":ariaLabel}=this.props;const contentProps=children.props;const color=contentProps.color;return jsx(React.Fragment,{children:jsxs(View,{"aria-label":ariaLabel,"aria-describedby":ariaDescribedby,"aria-labelledby":ariaLabelledBy,id:id,role:"dialog",ref:updateBubbleRef,"data-placement":placement,style:[isReferenceHidden&&styles$2.hide,styles$2[`content-${placement}`],style],children:[children,jsx(TooltipTail,{show:showTail,color:color,updateRef:updateTailRef,placement:placement,offset:tailOffset})]})})}}const styles$2=StyleSheet.create({hide:{pointerEvents:"none",opacity:0,backgroundColor:"transparent",color:"transparent"},"content-top":{flexDirection:"column"},"content-right":{flexDirection:"row-reverse"},"content-bottom":{flexDirection:"column-reverse"},"content-left":{flexDirection:"row"}});
119
19
 
120
- const FOCUSABLE_ELEMENTS = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
121
- function findFocusableNodes(root) {
122
- return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS));
123
- }
124
- function isFocusable(element) {
125
- return element.matches(FOCUSABLE_ELEMENTS);
126
- }
20
+ const FOCUSABLE_ELEMENTS='button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';function findFocusableNodes(root){return Array.from(root.querySelectorAll(FOCUSABLE_ELEMENTS))}function isFocusable(element){return element.matches(FOCUSABLE_ELEMENTS)}
127
21
 
128
- class PopoverEventListener extends React.Component {
129
- constructor(...args) {
130
- super(...args);
131
- this.state = {
132
- isFirstClick: true
133
- };
134
- this._handleKeyup = e => {
135
- if (e.key === "Escape") {
136
- e.preventDefault();
137
- e.stopPropagation();
138
- this.props.onClose(true);
139
- }
140
- };
141
- this._handleClick = e => {
142
- var _this$props$contentRe;
143
- if (this.state.isFirstClick) {
144
- this.setState({
145
- isFirstClick: false
146
- });
147
- return;
148
- }
149
- const node = ReactDOM.findDOMNode((_this$props$contentRe = this.props.contentRef) == null ? void 0 : _this$props$contentRe.current);
150
- if (node && !node.contains(e.target)) {
151
- e.preventDefault();
152
- e.stopPropagation();
153
- const shouldReturnFocus = !isFocusable(e.target);
154
- this.props.onClose(shouldReturnFocus);
155
- }
156
- };
157
- }
158
- componentDidMount() {
159
- window.addEventListener("keyup", this._handleKeyup);
160
- window.addEventListener("click", this._handleClick);
161
- }
162
- componentWillUnmount() {
163
- window.removeEventListener("keyup", this._handleKeyup);
164
- window.removeEventListener("click", this._handleClick);
165
- }
166
- render() {
167
- return null;
168
- }
169
- }
22
+ class PopoverEventListener extends React.Component{componentDidMount(){window.addEventListener("keyup",this._handleKeyup);window.addEventListener("click",this._handleClick);}componentWillUnmount(){window.removeEventListener("keyup",this._handleKeyup);window.removeEventListener("click",this._handleClick);}render(){return null}constructor(...args){super(...args),this.state={isFirstClick:true},this._handleKeyup=e=>{if(e.key==="Escape"){e.preventDefault();e.stopPropagation();this.props.onClose(true);}},this._handleClick=e=>{if(this.state.isFirstClick){this.setState({isFirstClick:false});return}const node=ReactDOM.findDOMNode(this.props.contentRef?.current);if(node&&!node.contains(e.target)){e.preventDefault();e.stopPropagation();const shouldReturnFocus=!isFocusable(e.target);this.props.onClose(shouldReturnFocus);}};}}
170
23
 
171
- class InitialFocus extends React.Component {
172
- constructor(...args) {
173
- super(...args);
174
- this.setInitialFocusableElement = node => {
175
- const firstFocusableElement = this.maybeGetInitialFocusElement(node) || this.maybeGetFirstFocusableElement(node) || node;
176
- if (firstFocusableElement === node) {
177
- node.tabIndex = -1;
178
- }
179
- setTimeout(() => {
180
- firstFocusableElement.focus();
181
- }, 0);
182
- };
183
- }
184
- componentDidMount() {
185
- const node = ReactDOM.findDOMNode(this);
186
- if (!node) {
187
- return;
188
- }
189
- this.setInitialFocusableElement(node);
190
- }
191
- maybeGetInitialFocusElement(node) {
192
- const {
193
- initialFocusId
194
- } = this.props;
195
- if (!initialFocusId) {
196
- return null;
197
- }
198
- return node.querySelector(`#${initialFocusId}`);
199
- }
200
- maybeGetFirstFocusableElement(node) {
201
- const focusableElements = findFocusableNodes(node);
202
- if (!focusableElements.length) {
203
- return null;
204
- }
205
- return focusableElements[0];
206
- }
207
- render() {
208
- return this.props.children;
209
- }
210
- }
24
+ class InitialFocus extends React.Component{componentDidMount(){const node=ReactDOM.findDOMNode(this);if(!node){return}this.setInitialFocusableElement(node);}maybeGetInitialFocusElement(node){const{initialFocusId}=this.props;if(!initialFocusId){return null}return node.querySelector(`#${initialFocusId}`)}maybeGetFirstFocusableElement(node){const focusableElements=findFocusableNodes(node);if(!focusableElements.length){return null}return focusableElements[0]}render(){return this.props.children}constructor(...args){super(...args),this.setInitialFocusableElement=node=>{const firstFocusableElement=this.maybeGetInitialFocusElement(node)||this.maybeGetFirstFocusableElement(node)||node;if(firstFocusableElement===node){node.tabIndex=-1;}setTimeout(()=>{firstFocusableElement.focus();},this.props.delay||0);};}}
211
25
 
212
- class FocusManager extends React.Component {
213
- constructor(...args) {
214
- super(...args);
215
- this.nextElementAfterPopover = void 0;
216
- this.rootNode = void 0;
217
- this.elementsThatCanBeFocusableInsidePopover = [];
218
- this.firstFocusableElementInPopover = null;
219
- this.lastFocusableElementInPopover = null;
220
- this.addEventListeners = () => {
221
- const {
222
- anchorElement
223
- } = this.props;
224
- if (anchorElement) {
225
- anchorElement.addEventListener("keydown", this.handleKeydownPreviousFocusableElement);
226
- }
227
- if (this.rootNode) {
228
- this.elementsThatCanBeFocusableInsidePopover = findFocusableNodes(this.rootNode);
229
- this.firstFocusableElementInPopover = this.elementsThatCanBeFocusableInsidePopover[0];
230
- this.lastFocusableElementInPopover = this.elementsThatCanBeFocusableInsidePopover[this.elementsThatCanBeFocusableInsidePopover.length - 1];
231
- }
232
- this.nextElementAfterPopover = this.getNextFocusableElement();
233
- if (!this.nextElementAfterPopover) {
234
- window.addEventListener("blur", () => {
235
- this.changeFocusabilityInsidePopover(true);
236
- });
237
- }
238
- if (this.firstFocusableElementInPopover) {
239
- this.firstFocusableElementInPopover.addEventListener("keydown", this.handleKeydownFirstFocusableElement);
240
- }
241
- if (this.lastFocusableElementInPopover) {
242
- this.lastFocusableElementInPopover.addEventListener("keydown", this.handleKeydownLastFocusableElement);
243
- }
244
- if (this.nextElementAfterPopover) {
245
- this.nextElementAfterPopover.addEventListener("keydown", this.handleKeydownNextFocusableElement);
246
- }
247
- };
248
- this.handleKeydownFirstFocusableElement = e => {
249
- if (e.key === "Tab" && e.shiftKey) {
250
- var _this$props$anchorEle;
251
- e.preventDefault();
252
- (_this$props$anchorEle = this.props.anchorElement) == null || _this$props$anchorEle.focus();
253
- }
254
- };
255
- this.handleKeydownLastFocusableElement = e => {
256
- if (this.nextElementAfterPopover && e.key === "Tab" && !e.shiftKey) {
257
- var _this$nextElementAfte;
258
- e.preventDefault();
259
- (_this$nextElementAfte = this.nextElementAfterPopover) == null || _this$nextElementAfte.focus();
260
- }
261
- };
262
- this.getNextFocusableElement = () => {
263
- const {
264
- anchorElement
265
- } = this.props;
266
- if (!anchorElement) {
267
- return;
268
- }
269
- const focusableElements = findFocusableNodes(document);
270
- const focusableElementsOutside = focusableElements.filter(element => {
271
- const index = this.elementsThatCanBeFocusableInsidePopover.indexOf(element);
272
- return index < 0;
273
- });
274
- const anchorIndex = focusableElementsOutside.indexOf(anchorElement);
275
- if (anchorIndex >= 0 && anchorIndex !== focusableElementsOutside.length - 1) {
276
- const nextElementIndex = anchorIndex < focusableElementsOutside.length - 1 ? anchorIndex + 1 : 0;
277
- return focusableElementsOutside[nextElementIndex];
278
- }
279
- return;
280
- };
281
- this.getComponentRootNode = node => {
282
- if (!node) {
283
- return;
284
- }
285
- const rootNode = ReactDOM.findDOMNode(node);
286
- if (!rootNode) {
287
- throw new Error("Assertion error: root node should exist after mount");
288
- }
289
- this.rootNode = rootNode;
290
- };
291
- this.handleFocusPreviousFocusableElement = () => {
292
- if (this.props.anchorElement) {
293
- this.props.anchorElement.focus();
294
- }
295
- };
296
- this.changeFocusabilityInsidePopover = (enabled = true) => {
297
- const tabIndex = enabled ? "0" : "-1";
298
- this.elementsThatCanBeFocusableInsidePopover.forEach(element => {
299
- element.setAttribute("tabIndex", tabIndex);
300
- });
301
- };
302
- this.handleFocusNextFocusableElement = () => {
303
- if (this.nextElementAfterPopover) {
304
- this.nextElementAfterPopover.focus();
305
- }
306
- };
307
- this.handleKeydownPreviousFocusableElement = e => {
308
- if (e.key === "Tab" && !e.shiftKey) {
309
- var _this$firstFocusableE;
310
- e.preventDefault();
311
- (_this$firstFocusableE = this.firstFocusableElementInPopover) == null || _this$firstFocusableE.focus();
312
- }
313
- };
314
- this.handleKeydownNextFocusableElement = e => {
315
- if (e.key === "Tab" && e.shiftKey) {
316
- var _this$lastFocusableEl;
317
- e.preventDefault();
318
- (_this$lastFocusableEl = this.lastFocusableElementInPopover) == null || _this$lastFocusableEl.focus();
319
- }
320
- };
321
- }
322
- componentDidMount() {
323
- this.addEventListeners();
324
- }
325
- componentDidUpdate() {
326
- this.removeEventListeners();
327
- this.addEventListeners();
328
- }
329
- componentWillUnmount() {
330
- this.changeFocusabilityInsidePopover(true);
331
- this.removeEventListeners();
332
- }
333
- removeEventListeners() {
334
- const {
335
- anchorElement
336
- } = this.props;
337
- if (anchorElement) {
338
- anchorElement.removeEventListener("keydown", this.handleKeydownPreviousFocusableElement);
339
- }
340
- if (!this.nextElementAfterPopover) {
341
- window.removeEventListener("blur", () => {
342
- this.changeFocusabilityInsidePopover(true);
343
- });
344
- }
345
- if (this.firstFocusableElementInPopover) {
346
- this.firstFocusableElementInPopover.removeEventListener("keydown", this.handleKeydownFirstFocusableElement);
347
- }
348
- if (this.lastFocusableElementInPopover) {
349
- this.lastFocusableElementInPopover.removeEventListener("keydown", this.handleKeydownLastFocusableElement);
350
- }
351
- if (this.nextElementAfterPopover) {
352
- this.nextElementAfterPopover.removeEventListener("keydown", this.handleKeydownNextFocusableElement);
353
- }
354
- }
355
- render() {
356
- const {
357
- children
358
- } = this.props;
359
- return (React.createElement("div", {
360
- ref: this.getComponentRootNode,
361
- onClick: () => {
362
- this.changeFocusabilityInsidePopover(true);
363
- },
364
- onFocus: () => {
365
- this.changeFocusabilityInsidePopover(true);
366
- },
367
- onBlur: () => {
368
- this.changeFocusabilityInsidePopover(false);
369
- }
370
- }, React.createElement(InitialFocus, {
371
- initialFocusId: this.props.initialFocusId
372
- }, children))
373
- );
374
- }
375
- }
26
+ class FocusManager extends React.Component{componentDidMount(){this.addEventListeners();}componentDidUpdate(){this.removeEventListeners();this.addEventListeners();}componentWillUnmount(){this.changeFocusabilityInsidePopover(true);this.removeEventListeners();}removeEventListeners(){const{anchorElement}=this.props;if(anchorElement){anchorElement.removeEventListener("keydown",this.handleKeydownPreviousFocusableElement);}if(!this.nextElementAfterPopover){window.removeEventListener("blur",()=>{this.changeFocusabilityInsidePopover(true);});}if(this.firstFocusableElementInPopover){this.firstFocusableElementInPopover.removeEventListener("keydown",this.handleKeydownFirstFocusableElement);}if(this.lastFocusableElementInPopover){this.lastFocusableElementInPopover.removeEventListener("keydown",this.handleKeydownLastFocusableElement);}if(this.nextElementAfterPopover){this.nextElementAfterPopover.removeEventListener("keydown",this.handleKeydownNextFocusableElement);}}render(){const{children}=this.props;return jsx("div",{ref:this.getComponentRootNode,onClick:()=>{this.changeFocusabilityInsidePopover(true);},onFocus:()=>{this.changeFocusabilityInsidePopover(true);},onBlur:()=>{this.changeFocusabilityInsidePopover(false);},children:jsx(InitialFocus,{initialFocusId:this.props.initialFocusId,delay:this.props.initialFocusDelay,children:children})})}constructor(...args){super(...args),this.elementsThatCanBeFocusableInsidePopover=[],this.firstFocusableElementInPopover=null,this.lastFocusableElementInPopover=null,this.addEventListeners=()=>{const{anchorElement}=this.props;if(anchorElement){anchorElement.addEventListener("keydown",this.handleKeydownPreviousFocusableElement);}if(this.rootNode){this.elementsThatCanBeFocusableInsidePopover=findFocusableNodes(this.rootNode);this.firstFocusableElementInPopover=this.elementsThatCanBeFocusableInsidePopover[0];this.lastFocusableElementInPopover=this.elementsThatCanBeFocusableInsidePopover[this.elementsThatCanBeFocusableInsidePopover.length-1];}this.nextElementAfterPopover=this.getNextFocusableElement();if(!this.nextElementAfterPopover){window.addEventListener("blur",()=>{this.changeFocusabilityInsidePopover(true);});}if(this.firstFocusableElementInPopover){this.firstFocusableElementInPopover.addEventListener("keydown",this.handleKeydownFirstFocusableElement);}if(this.lastFocusableElementInPopover){this.lastFocusableElementInPopover.addEventListener("keydown",this.handleKeydownLastFocusableElement);}if(this.nextElementAfterPopover){this.nextElementAfterPopover.addEventListener("keydown",this.handleKeydownNextFocusableElement);}},this.handleKeydownFirstFocusableElement=e=>{if(e.key==="Tab"&&e.shiftKey){e.preventDefault();this.props.anchorElement?.focus();}},this.handleKeydownLastFocusableElement=e=>{if(this.nextElementAfterPopover&&e.key==="Tab"&&!e.shiftKey){e.preventDefault();this.nextElementAfterPopover?.focus();}},this.getNextFocusableElement=()=>{const{anchorElement}=this.props;if(!anchorElement){return}const focusableElements=findFocusableNodes(document);const focusableElementsOutside=focusableElements.filter(element=>{const index=this.elementsThatCanBeFocusableInsidePopover.indexOf(element);return index<0});const anchorIndex=focusableElementsOutside.indexOf(anchorElement);if(anchorIndex>=0&&anchorIndex!==focusableElementsOutside.length-1){const nextElementIndex=anchorIndex<focusableElementsOutside.length-1?anchorIndex+1:0;return focusableElementsOutside[nextElementIndex]}return},this.getComponentRootNode=node=>{if(!node){return}const rootNode=ReactDOM.findDOMNode(node);if(!rootNode){throw new Error("Assertion error: root node should exist after mount")}this.rootNode=rootNode;},this.handleFocusPreviousFocusableElement=()=>{if(this.props.anchorElement){this.props.anchorElement.focus();}},this.changeFocusabilityInsidePopover=(enabled=true)=>{const tabIndex=enabled?"0":"-1";this.elementsThatCanBeFocusableInsidePopover.forEach(element=>{element.setAttribute("tabIndex",tabIndex);});},this.handleFocusNextFocusableElement=()=>{if(this.nextElementAfterPopover){this.nextElementAfterPopover.focus();}},this.handleKeydownPreviousFocusableElement=e=>{if(e.key==="Tab"&&!e.shiftKey){e.preventDefault();this.firstFocusableElementInPopover?.focus();}},this.handleKeydownNextFocusableElement=e=>{if(e.key==="Tab"&&e.shiftKey){e.preventDefault();this.lastFocusableElementInPopover?.focus();}};}}
376
27
 
377
- class Popover extends React.Component {
378
- constructor(...args) {
379
- super(...args);
380
- this.state = {
381
- opened: !!this.props.opened,
382
- placement: this.props.placement
383
- };
384
- this.contentRef = React.createRef();
385
- this.maybeReturnFocus = () => {
386
- const {
387
- anchorElement
388
- } = this.state;
389
- const {
390
- closedFocusId
391
- } = this.props;
392
- if (closedFocusId) {
393
- const focusElement = ReactDOM.findDOMNode(document.getElementById(closedFocusId));
394
- focusElement == null || focusElement.focus();
395
- return;
396
- }
397
- if (anchorElement) {
398
- anchorElement.focus();
399
- }
400
- };
401
- this.handleClose = (shouldReturnFocus = true) => {
402
- this.setState({
403
- opened: false
404
- }, () => {
405
- var _this$props$onClose, _this$props;
406
- (_this$props$onClose = (_this$props = this.props).onClose) == null || _this$props$onClose.call(_this$props);
407
- if (shouldReturnFocus) {
408
- this.maybeReturnFocus();
409
- }
410
- });
411
- };
412
- this.handleOpen = () => {
413
- if (this.props.dismissEnabled && this.state.opened) {
414
- this.handleClose(true);
415
- } else {
416
- this.setState({
417
- opened: true
418
- });
419
- }
420
- };
421
- this.updateRef = actualRef => {
422
- if (actualRef && this.state.anchorElement !== actualRef) {
423
- this.setState({
424
- anchorElement: actualRef
425
- });
426
- }
427
- };
428
- }
429
- static getDerivedStateFromProps(props, state) {
430
- return {
431
- opened: typeof props.opened === "boolean" ? props.opened : state.opened
432
- };
433
- }
434
- renderContent(uniqueId) {
435
- const {
436
- content
437
- } = this.props;
438
- const popoverContents = typeof content === "function" ? content({
439
- close: this.handleClose
440
- }) : content;
441
- return React.cloneElement(popoverContents, {
442
- ref: this.contentRef,
443
- uniqueId
444
- });
445
- }
446
- renderPopper(uniqueId) {
447
- const {
448
- initialFocusId,
449
- placement,
450
- showTail,
451
- portal,
452
- "aria-label": ariaLabel,
453
- "aria-describedby": ariaDescribedBy,
454
- rootBoundary,
455
- viewportPadding
456
- } = this.props;
457
- const {
458
- anchorElement
459
- } = this.state;
460
- const describedBy = ariaDescribedBy || `${uniqueId}-content`;
461
- const ariaLabelledBy = ariaLabel ? undefined : `${uniqueId}-title`;
462
- const popperContent = React.createElement(TooltipPopper, {
463
- anchorElement: anchorElement,
464
- placement: placement,
465
- rootBoundary: rootBoundary,
466
- viewportPadding: viewportPadding
467
- }, props => React.createElement(PopoverDialog, _extends({}, props, {
468
- "aria-label": ariaLabel,
469
- "aria-describedby": describedBy,
470
- "aria-labelledby": ariaLabelledBy,
471
- id: uniqueId,
472
- onUpdate: placement => this.setState({
473
- placement
474
- }),
475
- showTail: showTail
476
- }), this.renderContent(uniqueId)));
477
- if (portal) {
478
- return React.createElement(FocusManager, {
479
- anchorElement: anchorElement,
480
- initialFocusId: initialFocusId
481
- }, popperContent);
482
- } else {
483
- return (React.createElement(InitialFocus, {
484
- initialFocusId: initialFocusId
485
- }, popperContent)
486
- );
487
- }
488
- }
489
- getHost() {
490
- return maybeGetPortalMountedModalHostElement(this.state.anchorElement) || document.body;
491
- }
492
- renderPortal(uniqueId, opened) {
493
- if (!opened) {
494
- return null;
495
- }
496
- const {
497
- portal
498
- } = this.props;
499
- const popperHost = this.getHost();
500
- if (portal && popperHost) {
501
- return ReactDOM.createPortal(this.renderPopper(uniqueId), popperHost);
502
- }
503
- return this.renderPopper(uniqueId);
504
- }
505
- render() {
506
- const {
507
- children,
508
- dismissEnabled,
509
- id
510
- } = this.props;
511
- const {
512
- opened,
513
- placement
514
- } = this.state;
515
- return React.createElement(PopoverContext.Provider, {
516
- value: {
517
- close: this.handleClose,
518
- placement: placement
519
- }
520
- }, React.createElement(Id, {
521
- id: id
522
- }, uniqueId => React.createElement(React.Fragment, null, React.createElement(PopoverAnchor, {
523
- anchorRef: this.updateRef,
524
- id: `${uniqueId}-anchor`,
525
- "aria-controls": uniqueId,
526
- "aria-expanded": opened ? "true" : "false",
527
- onClick: this.handleOpen
528
- }, children), this.renderPortal(uniqueId, opened))), dismissEnabled && opened && React.createElement(PopoverEventListener, {
529
- onClose: this.handleClose,
530
- contentRef: this.contentRef
531
- }));
532
- }
533
- }
534
- Popover.defaultProps = {
535
- placement: "top",
536
- showTail: true,
537
- portal: true,
538
- rootBoundary: "viewport"
539
- };
28
+ class Popover extends React.Component{static getDerivedStateFromProps(props,state){return {opened:typeof props.opened==="boolean"?props.opened:state.opened}}renderContent(uniqueId){const{content}=this.props;const popoverContents=typeof content==="function"?content({close:this.handleClose}):content;return React.cloneElement(popoverContents,{ref:this.contentRef,uniqueId})}renderPopper(uniqueId){const{initialFocusId,placement,showTail,portal,"aria-label":ariaLabel,"aria-describedby":ariaDescribedBy,rootBoundary,viewportPadding,initialFocusDelay}=this.props;const{anchorElement}=this.state;const describedBy=ariaDescribedBy||`${uniqueId}-content`;const ariaLabelledBy=ariaLabel?undefined:`${uniqueId}-title`;const popperContent=jsx(TooltipPopper,{anchorElement:anchorElement,placement:placement,rootBoundary:rootBoundary,viewportPadding:viewportPadding,children:props=>jsx(PopoverDialog,{...props,"aria-label":ariaLabel,"aria-describedby":describedBy,"aria-labelledby":ariaLabelledBy,id:uniqueId,onUpdate:placement=>this.setState({placement}),showTail:showTail,children:this.renderContent(uniqueId)})});if(portal){return jsx(FocusManager,{anchorElement:anchorElement,initialFocusId:initialFocusId,initialFocusDelay:initialFocusDelay,children:popperContent})}else {return jsx(InitialFocus,{initialFocusId:initialFocusId,delay:initialFocusDelay,children:popperContent})}}getHost(){return maybeGetPortalMountedModalHostElement(this.state.anchorElement)||document.body}renderPortal(uniqueId,opened){if(!opened){return null}const{portal}=this.props;const popperHost=this.getHost();if(portal&&popperHost){return ReactDOM.createPortal(this.renderPopper(uniqueId),popperHost)}return this.renderPopper(uniqueId)}render(){const{children,dismissEnabled,id}=this.props;const{opened,placement}=this.state;return jsxs(PopoverContext.Provider,{value:{close:this.handleClose,placement:placement},children:[jsx(Id,{id:id,children:uniqueId=>jsxs(React.Fragment,{children:[jsx(PopoverAnchor,{anchorRef:this.updateRef,id:`${uniqueId}-anchor`,"aria-controls":uniqueId,"aria-expanded":opened?"true":"false",onClick:this.handleOpen,children:children}),this.renderPortal(uniqueId,opened)]})}),dismissEnabled&&opened&&jsx(PopoverEventListener,{onClose:this.handleClose,contentRef:this.contentRef})]})}constructor(...args){super(...args),this.state={opened:!!this.props.opened,placement:this.props.placement},this.contentRef=React.createRef(),this.maybeReturnFocus=()=>{const{anchorElement}=this.state;const{closedFocusId}=this.props;if(closedFocusId){const focusElement=ReactDOM.findDOMNode(document.getElementById(closedFocusId));focusElement?.focus();return}if(anchorElement){anchorElement.focus();}},this.handleClose=(shouldReturnFocus=true)=>{this.setState({opened:false},()=>{this.props.onClose?.();if(shouldReturnFocus){this.maybeReturnFocus();}});},this.handleOpen=()=>{if(this.props.dismissEnabled&&this.state.opened){this.handleClose(true);}else {this.setState({opened:true});}},this.updateRef=actualRef=>{if(actualRef&&this.state.anchorElement!==actualRef){this.setState({anchorElement:actualRef});}};}}Popover.defaultProps={placement:"top",showTail:true,portal:true,rootBoundary:"viewport"};
540
29
 
541
- class CloseButton extends React.Component {
542
- render() {
543
- const {
544
- "aria-label": ariaLabel,
545
- style,
546
- testId
547
- } = this.props;
548
- return React.createElement(PopoverContext.Consumer, null, ({
549
- close
550
- }) => {
551
- return React.createElement(IconButton, {
552
- icon: xIcon,
553
- "aria-label": ariaLabel,
554
- onClick: close,
555
- kind: "tertiary",
556
- actionType: "neutral",
557
- style: style,
558
- testId: testId
559
- });
560
- });
561
- }
562
- }
563
- CloseButton.defaultProps = {
564
- "aria-label": "Close Popover"
565
- };
30
+ class CloseButton extends React.Component{render(){const{"aria-label":ariaLabel,style,testId}=this.props;return jsx(PopoverContext.Consumer,{children:({close})=>{return jsx(IconButton,{icon:xIcon,"aria-label":ariaLabel,onClick:close,kind:"tertiary",actionType:"neutral",style:style,testId:testId})}})}}CloseButton.defaultProps={"aria-label":"Close Popover"};
566
31
 
567
- class PopoverContentCore extends React.Component {
568
- render() {
569
- const {
570
- "aria-label": ariaLabel,
571
- children,
572
- closeButtonLight,
573
- closeButtonLabel,
574
- closeButtonVisible,
575
- style,
576
- testId
577
- } = this.props;
578
- return React.createElement(View, {
579
- testId: testId,
580
- style: [styles$1.content, style],
581
- "aria-label": ariaLabel
582
- }, closeButtonVisible && React.createElement(CloseButton, {
583
- "aria-label": closeButtonLabel,
584
- style: [styles$1.closeButton, closeButtonLight && actionStyles.inverse],
585
- testId: `${testId || "popover"}-close-btn`
586
- }), children);
587
- }
588
- }
589
- PopoverContentCore.defaultProps = {
590
- closeButtonLight: false,
591
- closeButtonVisible: false
592
- };
593
- const styles$1 = StyleSheet.create({
594
- content: {
595
- borderRadius: border.radius.radius_040,
596
- border: `solid 1px ${semanticColor.border.primary}`,
597
- backgroundColor: semanticColor.surface.primary,
598
- boxShadow: `0 ${spacing.xSmall_8}px ${spacing.xSmall_8}px 0 ${color.offBlack8}`,
599
- margin: 0,
600
- maxWidth: spacing.medium_16 * 18,
601
- padding: spacing.large_24,
602
- overflow: "hidden",
603
- justifyContent: "center"
604
- },
605
- closeButton: {
606
- margin: 0,
607
- position: "absolute",
608
- right: spacing.xxxSmall_4,
609
- top: spacing.xxxSmall_4,
610
- zIndex: 1
611
- }
612
- });
32
+ class PopoverContentCore extends React.Component{render(){const{"aria-label":ariaLabel,children,closeButtonLight,closeButtonLabel,closeButtonVisible,style,testId}=this.props;return jsxs(View,{testId:testId,style:[styles$1.content,style],"aria-label":ariaLabel,children:[closeButtonVisible&&jsx(CloseButton,{"aria-label":closeButtonLabel,style:[styles$1.closeButton,closeButtonLight&&actionStyles.inverse],testId:`${testId||"popover"}-close-btn`}),children]})}}PopoverContentCore.defaultProps={closeButtonLight:false,closeButtonVisible:false};const styles$1=StyleSheet.create({content:{borderRadius:border.radius.radius_040,border:`solid 1px ${semanticColor.border.primary}`,backgroundColor:semanticColor.surface.primary,boxShadow:`0 ${spacing.xSmall_8}px ${spacing.xSmall_8}px 0 ${color.offBlack8}`,margin:0,maxWidth:spacing.medium_16*18,padding:spacing.large_24,overflow:"hidden",justifyContent:"center"},closeButton:{margin:0,position:"absolute",right:spacing.xxxSmall_4,top:spacing.xxxSmall_4,zIndex:1}});
613
33
 
614
- const StyledImg = addStyle("img");
615
- class PopoverContent extends React.Component {
616
- constructor(...args) {
617
- super(...args);
618
- this.maybeRenderImage = ({
619
- placement
620
- }) => {
621
- const {
622
- image
623
- } = this.props;
624
- if (!image) {
625
- return null;
626
- }
627
- return React.createElement(View, {
628
- style: [styles.image, placement === "bottom" && styles.imageToBottom]
629
- }, image);
630
- };
631
- this.maybeRenderIcon = () => {
632
- const {
633
- icon,
634
- iconAlt
635
- } = this.props;
636
- if (!icon) {
637
- return null;
638
- }
639
- return React.createElement(View, {
640
- style: styles.iconContainer
641
- }, typeof icon !== "string" ? icon : React.createElement(StyledImg, {
642
- src: icon,
643
- style: styles.icon,
644
- alt: iconAlt || ""
645
- }));
646
- };
647
- this.maybeRenderActions = close => {
648
- const {
649
- actions
650
- } = this.props;
651
- if (!actions) {
652
- return null;
653
- }
654
- return React.createElement(View, {
655
- style: styles.actions
656
- }, typeof actions === "function" ? actions({
657
- close: close
658
- }) : actions);
659
- };
660
- }
661
- componentDidMount() {
662
- const {
663
- icon,
664
- image
665
- } = this.props;
666
- if (image && icon) {
667
- throw new Error("'image' and 'icon' cannot be used at the same time. You can fix this by either removing 'image' or 'icon' from your instance.");
668
- }
669
- }
670
- validateProps({
671
- placement
672
- }) {
673
- if (this.props.image && (placement === "left" || placement === "right")) {
674
- throw new Error("'image' can only be vertically placed. You can fix this by either changing `placement` to `top` or `bottom` or removing the `image` prop inside `content`.");
675
- }
676
- }
677
- render() {
678
- const {
679
- closeButtonLabel,
680
- closeButtonVisible,
681
- content,
682
- icon,
683
- image,
684
- style,
685
- title,
686
- testId,
687
- uniqueId
688
- } = this.props;
689
- return React.createElement(PopoverContext.Consumer, null, ({
690
- close,
691
- placement
692
- }) => {
693
- this.validateProps({
694
- close,
695
- placement
696
- });
697
- return React.createElement(PopoverContentCore, {
698
- closeButtonLight: image && placement === "top",
699
- closeButtonLabel: closeButtonLabel,
700
- closeButtonVisible: closeButtonVisible,
701
- style: style,
702
- testId: testId
703
- }, React.createElement(View, {
704
- style: !!icon && styles.withIcon
705
- }, this.maybeRenderImage({
706
- placement
707
- }), this.maybeRenderIcon(), React.createElement(View, {
708
- style: styles.text
709
- }, React.createElement(HeadingSmall, {
710
- id: `${uniqueId}-title`,
711
- style: styles.title
712
- }, title), React.createElement(Body, {
713
- id: `${uniqueId}-content`
714
- }, content))), this.maybeRenderActions(close));
715
- });
716
- }
717
- }
718
- PopoverContent.defaultProps = {
719
- closeButtonVisible: false
720
- };
721
- const styles = StyleSheet.create({
722
- actions: {
723
- marginTop: spacing.large_24,
724
- flexDirection: "row",
725
- alignItems: "center",
726
- justifyContent: "flex-end"
727
- },
728
- text: {
729
- justifyContent: "center"
730
- },
731
- title: {
732
- marginBottom: spacing.xSmall_8
733
- },
734
- iconContainer: {
735
- alignItems: "center",
736
- justifyContent: "center",
737
- height: spacing.xxxLarge_64,
738
- width: spacing.xxxLarge_64,
739
- minWidth: spacing.xxxLarge_64,
740
- marginRight: spacing.medium_16,
741
- overflow: "hidden"
742
- },
743
- icon: {
744
- width: "100%"
745
- },
746
- withIcon: {
747
- flexDirection: "row"
748
- },
749
- image: {
750
- marginBottom: spacing.large_24,
751
- marginLeft: -spacing.large_24,
752
- marginRight: -spacing.large_24,
753
- marginTop: -spacing.large_24,
754
- width: `calc(100% + ${spacing.large_24 * 2}px)`
755
- },
756
- imageToBottom: {
757
- marginBottom: -spacing.large_24,
758
- marginTop: spacing.large_24,
759
- order: 1
760
- }
761
- });
34
+ const StyledImg=addStyle("img");class PopoverContent extends React.Component{componentDidMount(){const{icon,image}=this.props;if(image&&icon){throw new Error("'image' and 'icon' cannot be used at the same time. You can fix this by either removing 'image' or 'icon' from your instance.")}}validateProps({placement}){if(this.props.image&&(placement==="left"||placement==="right")){throw new Error("'image' can only be vertically placed. You can fix this by either changing `placement` to `top` or `bottom` or removing the `image` prop inside `content`.")}}render(){const{closeButtonLabel,closeButtonVisible,content,icon,image,style,title,testId,uniqueId}=this.props;return jsx(PopoverContext.Consumer,{children:({close,placement})=>{this.validateProps({close,placement});return jsxs(PopoverContentCore,{closeButtonLight:image&&placement==="top",closeButtonLabel:closeButtonLabel,closeButtonVisible:closeButtonVisible,style:style,testId:testId,children:[jsxs(View,{style:!!icon&&styles.withIcon,children:[this.maybeRenderImage({placement}),this.maybeRenderIcon(),jsxs(View,{style:styles.text,children:[jsx(HeadingSmall,{id:`${uniqueId}-title`,style:styles.title,children:title}),jsx(Body,{id:`${uniqueId}-content`,children:content})]})]}),this.maybeRenderActions(close)]})}})}constructor(...args){super(...args),this.maybeRenderImage=({placement})=>{const{image}=this.props;if(!image){return null}return jsx(View,{style:[styles.image,placement==="bottom"&&styles.imageToBottom],children:image})},this.maybeRenderIcon=()=>{const{icon,iconAlt}=this.props;if(!icon){return null}return jsx(View,{style:styles.iconContainer,children:typeof icon!=="string"?icon:jsx(StyledImg,{src:icon,style:styles.icon,alt:iconAlt||""})})},this.maybeRenderActions=close=>{const{actions}=this.props;if(!actions){return null}return jsx(View,{style:styles.actions,children:typeof actions==="function"?actions({close:close}):actions})};}}PopoverContent.defaultProps={closeButtonVisible:false};const styles=StyleSheet.create({actions:{marginTop:spacing.large_24,flexDirection:"row",alignItems:"center",justifyContent:"flex-end"},text:{justifyContent:"center"},title:{marginBottom:spacing.xSmall_8},iconContainer:{alignItems:"center",justifyContent:"center",height:spacing.xxxLarge_64,width:spacing.xxxLarge_64,minWidth:spacing.xxxLarge_64,marginRight:spacing.medium_16,overflow:"hidden"},icon:{width:"100%"},withIcon:{flexDirection:"row"},image:{marginBottom:spacing.large_24,marginLeft:-spacing.large_24,marginRight:-spacing.large_24,marginTop:-spacing.large_24,width:`calc(100% + ${spacing.large_24*2}px)`},imageToBottom:{marginBottom:-spacing.large_24,marginTop:spacing.large_24,order:1}});
762
35
 
763
36
  export { Popover, PopoverContent, PopoverContentCore };