@khanacademy/wonder-blocks-popover 3.2.7 → 3.2.9
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/CHANGELOG.md +19 -0
- package/dist/components/popover.d.ts +16 -0
- package/dist/es/index.js +74 -67
- package/dist/index.js +91 -83
- package/package.json +8 -8
- package/src/components/__tests__/popover.test.tsx +9 -5
- package/src/components/popover.tsx +73 -31
- package/tsconfig-build.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-popover
|
|
2
2
|
|
|
3
|
+
## 3.2.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 47d680f4: Removed usage of focus management in Popover component, in favor of a similar implementation that won't override custom keyboard navigation.
|
|
8
|
+
|
|
9
|
+
## 3.2.8
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 559e82d5: Update to build tooling, generating smaller output
|
|
14
|
+
- Updated dependencies [559e82d5]
|
|
15
|
+
- @khanacademy/wonder-blocks-core@6.4.3
|
|
16
|
+
- @khanacademy/wonder-blocks-icon-button@5.3.3
|
|
17
|
+
- @khanacademy/wonder-blocks-modal@5.1.8
|
|
18
|
+
- @khanacademy/wonder-blocks-tokens@1.3.1
|
|
19
|
+
- @khanacademy/wonder-blocks-tooltip@2.3.7
|
|
20
|
+
- @khanacademy/wonder-blocks-typography@2.1.14
|
|
21
|
+
|
|
3
22
|
## 3.2.7
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -81,6 +81,20 @@ type Props = AriaProps & Readonly<{
|
|
|
81
81
|
* Whether to show the popover tail or not. Defaults to true.
|
|
82
82
|
*/
|
|
83
83
|
showTail: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Optional property to enable the portal functionality of popover.
|
|
86
|
+
* This is very handy in cases where the Popover can't be easily
|
|
87
|
+
* injected into the DOM structure and requires portaling to
|
|
88
|
+
* the trigger location.
|
|
89
|
+
*
|
|
90
|
+
* Set to "true" by default.
|
|
91
|
+
*
|
|
92
|
+
* CAUTION: Turning off portal could cause some clipping issues
|
|
93
|
+
* especially around legacy code with usage of z-indexing,
|
|
94
|
+
* Use caution when turning this functionality off and ensure
|
|
95
|
+
* your content does not get clipped or hidden.
|
|
96
|
+
*/
|
|
97
|
+
portal?: boolean;
|
|
84
98
|
}>;
|
|
85
99
|
type State = Readonly<{
|
|
86
100
|
/**
|
|
@@ -99,6 +113,7 @@ type State = Readonly<{
|
|
|
99
113
|
type DefaultProps = Readonly<{
|
|
100
114
|
placement: Props["placement"];
|
|
101
115
|
showTail: Props["showTail"];
|
|
116
|
+
portal: Props["portal"];
|
|
102
117
|
}>;
|
|
103
118
|
/**
|
|
104
119
|
* Popovers provide additional information that is related to a particular
|
|
@@ -151,6 +166,7 @@ export default class Popover extends React.Component<Props, State> {
|
|
|
151
166
|
renderContent(uniqueId: string): PopoverContents;
|
|
152
167
|
renderPopper(uniqueId: string): React.ReactNode;
|
|
153
168
|
getHost(): Element | null | undefined;
|
|
169
|
+
renderPortal(uniqueId: string, opened: boolean): React.ReactNode;
|
|
154
170
|
render(): React.ReactNode;
|
|
155
171
|
}
|
|
156
172
|
export {};
|
package/dist/es/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _extends from '@babel/runtime/helpers/extends';
|
|
1
2
|
import * as React from 'react';
|
|
2
3
|
import * as ReactDOM from 'react-dom';
|
|
3
4
|
import { View, IDProvider, addStyle } from '@khanacademy/wonder-blocks-core';
|
|
@@ -9,21 +10,6 @@ import { HeadingSmall, Body } from '@khanacademy/wonder-blocks-typography';
|
|
|
9
10
|
import xIcon from '@phosphor-icons/core/regular/x.svg';
|
|
10
11
|
import IconButton from '@khanacademy/wonder-blocks-icon-button';
|
|
11
12
|
|
|
12
|
-
function _extends() {
|
|
13
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
14
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
15
|
-
var source = arguments[i];
|
|
16
|
-
for (var key in source) {
|
|
17
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
18
|
-
target[key] = source[key];
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return target;
|
|
23
|
-
};
|
|
24
|
-
return _extends.apply(this, arguments);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
13
|
const defaultContext = {
|
|
28
14
|
close: undefined,
|
|
29
15
|
placement: "top"
|
|
@@ -136,6 +122,49 @@ function isFocusable(element) {
|
|
|
136
122
|
return element.matches(FOCUSABLE_ELEMENTS);
|
|
137
123
|
}
|
|
138
124
|
|
|
125
|
+
class PopoverEventListener extends React.Component {
|
|
126
|
+
constructor(...args) {
|
|
127
|
+
super(...args);
|
|
128
|
+
this.state = {
|
|
129
|
+
isFirstClick: true
|
|
130
|
+
};
|
|
131
|
+
this._handleKeyup = e => {
|
|
132
|
+
if (e.key === "Escape") {
|
|
133
|
+
e.preventDefault();
|
|
134
|
+
e.stopPropagation();
|
|
135
|
+
this.props.onClose(true);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
this._handleClick = e => {
|
|
139
|
+
var _this$props$contentRe;
|
|
140
|
+
if (this.state.isFirstClick) {
|
|
141
|
+
this.setState({
|
|
142
|
+
isFirstClick: false
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const node = ReactDOM.findDOMNode((_this$props$contentRe = this.props.contentRef) == null ? void 0 : _this$props$contentRe.current);
|
|
147
|
+
if (node && !node.contains(e.target)) {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
e.stopPropagation();
|
|
150
|
+
const shouldReturnFocus = !isFocusable(e.target);
|
|
151
|
+
this.props.onClose(shouldReturnFocus);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
componentDidMount() {
|
|
156
|
+
window.addEventListener("keyup", this._handleKeyup);
|
|
157
|
+
window.addEventListener("click", this._handleClick);
|
|
158
|
+
}
|
|
159
|
+
componentWillUnmount() {
|
|
160
|
+
window.removeEventListener("keyup", this._handleKeyup);
|
|
161
|
+
window.removeEventListener("click", this._handleClick);
|
|
162
|
+
}
|
|
163
|
+
render() {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
139
168
|
class InitialFocus extends React.Component {
|
|
140
169
|
constructor(...args) {
|
|
141
170
|
super(...args);
|
|
@@ -341,49 +370,6 @@ class FocusManager extends React.Component {
|
|
|
341
370
|
}
|
|
342
371
|
}
|
|
343
372
|
|
|
344
|
-
class PopoverEventListener extends React.Component {
|
|
345
|
-
constructor(...args) {
|
|
346
|
-
super(...args);
|
|
347
|
-
this.state = {
|
|
348
|
-
isFirstClick: true
|
|
349
|
-
};
|
|
350
|
-
this._handleKeyup = e => {
|
|
351
|
-
if (e.key === "Escape") {
|
|
352
|
-
e.preventDefault();
|
|
353
|
-
e.stopPropagation();
|
|
354
|
-
this.props.onClose(true);
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
this._handleClick = e => {
|
|
358
|
-
var _this$props$contentRe;
|
|
359
|
-
if (this.state.isFirstClick) {
|
|
360
|
-
this.setState({
|
|
361
|
-
isFirstClick: false
|
|
362
|
-
});
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const node = ReactDOM.findDOMNode((_this$props$contentRe = this.props.contentRef) == null ? void 0 : _this$props$contentRe.current);
|
|
366
|
-
if (node && !node.contains(e.target)) {
|
|
367
|
-
e.preventDefault();
|
|
368
|
-
e.stopPropagation();
|
|
369
|
-
const shouldReturnFocus = !isFocusable(e.target);
|
|
370
|
-
this.props.onClose(shouldReturnFocus);
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
componentDidMount() {
|
|
375
|
-
window.addEventListener("keyup", this._handleKeyup);
|
|
376
|
-
window.addEventListener("click", this._handleClick);
|
|
377
|
-
}
|
|
378
|
-
componentWillUnmount() {
|
|
379
|
-
window.removeEventListener("keyup", this._handleKeyup);
|
|
380
|
-
window.removeEventListener("click", this._handleClick);
|
|
381
|
-
}
|
|
382
|
-
render() {
|
|
383
|
-
return null;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
373
|
class Popover extends React.Component {
|
|
388
374
|
constructor(...args) {
|
|
389
375
|
super(...args);
|
|
@@ -457,15 +443,13 @@ class Popover extends React.Component {
|
|
|
457
443
|
const {
|
|
458
444
|
initialFocusId,
|
|
459
445
|
placement,
|
|
460
|
-
showTail
|
|
446
|
+
showTail,
|
|
447
|
+
portal
|
|
461
448
|
} = this.props;
|
|
462
449
|
const {
|
|
463
450
|
anchorElement
|
|
464
451
|
} = this.state;
|
|
465
|
-
|
|
466
|
-
anchorElement: anchorElement,
|
|
467
|
-
initialFocusId: initialFocusId
|
|
468
|
-
}, React.createElement(TooltipPopper, {
|
|
452
|
+
const popperContent = React.createElement(TooltipPopper, {
|
|
469
453
|
anchorElement: anchorElement,
|
|
470
454
|
placement: placement
|
|
471
455
|
}, props => React.createElement(PopoverDialog, _extends({}, props, {
|
|
@@ -476,11 +460,34 @@ class Popover extends React.Component {
|
|
|
476
460
|
placement
|
|
477
461
|
}),
|
|
478
462
|
showTail: showTail
|
|
479
|
-
}), this.renderContent(uniqueId)))
|
|
463
|
+
}), this.renderContent(uniqueId)));
|
|
464
|
+
if (portal) {
|
|
465
|
+
return React.createElement(FocusManager, {
|
|
466
|
+
anchorElement: anchorElement,
|
|
467
|
+
initialFocusId: initialFocusId
|
|
468
|
+
}, popperContent);
|
|
469
|
+
} else {
|
|
470
|
+
return React.createElement(InitialFocus, {
|
|
471
|
+
initialFocusId: initialFocusId
|
|
472
|
+
}, popperContent);
|
|
473
|
+
}
|
|
480
474
|
}
|
|
481
475
|
getHost() {
|
|
482
476
|
return maybeGetPortalMountedModalHostElement(this.state.anchorElement) || document.body;
|
|
483
477
|
}
|
|
478
|
+
renderPortal(uniqueId, opened) {
|
|
479
|
+
if (!opened) {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
const {
|
|
483
|
+
portal
|
|
484
|
+
} = this.props;
|
|
485
|
+
const popperHost = this.getHost();
|
|
486
|
+
if (portal && popperHost) {
|
|
487
|
+
return ReactDOM.createPortal(this.renderPopper(uniqueId), popperHost);
|
|
488
|
+
}
|
|
489
|
+
return this.renderPopper(uniqueId);
|
|
490
|
+
}
|
|
484
491
|
render() {
|
|
485
492
|
const {
|
|
486
493
|
children,
|
|
@@ -491,7 +498,6 @@ class Popover extends React.Component {
|
|
|
491
498
|
opened,
|
|
492
499
|
placement
|
|
493
500
|
} = this.state;
|
|
494
|
-
const popperHost = this.getHost();
|
|
495
501
|
return React.createElement(PopoverContext.Provider, {
|
|
496
502
|
value: {
|
|
497
503
|
close: this.handleClose,
|
|
@@ -506,7 +512,7 @@ class Popover extends React.Component {
|
|
|
506
512
|
"aria-controls": uniqueId,
|
|
507
513
|
"aria-expanded": opened ? "true" : "false",
|
|
508
514
|
onClick: this.handleOpen
|
|
509
|
-
}, children),
|
|
515
|
+
}, children), this.renderPortal(uniqueId, opened))), dismissEnabled && opened && React.createElement(PopoverEventListener, {
|
|
510
516
|
onClose: this.handleClose,
|
|
511
517
|
contentRef: this.contentRef
|
|
512
518
|
}));
|
|
@@ -514,7 +520,8 @@ class Popover extends React.Component {
|
|
|
514
520
|
}
|
|
515
521
|
Popover.defaultProps = {
|
|
516
522
|
placement: "top",
|
|
517
|
-
showTail: true
|
|
523
|
+
showTail: true,
|
|
524
|
+
portal: true
|
|
518
525
|
};
|
|
519
526
|
|
|
520
527
|
class CloseButton extends React.Component {
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var _extends = require('@babel/runtime/helpers/extends');
|
|
5
6
|
var React = require('react');
|
|
6
7
|
var ReactDOM = require('react-dom');
|
|
7
8
|
var wonderBlocksCore = require('@khanacademy/wonder-blocks-core');
|
|
@@ -16,43 +17,29 @@ var IconButton = require('@khanacademy/wonder-blocks-icon-button');
|
|
|
16
17
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
17
18
|
|
|
18
19
|
function _interopNamespace(e) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
if (e && e.__esModule) return e;
|
|
21
|
+
var n = Object.create(null);
|
|
22
|
+
if (e) {
|
|
23
|
+
Object.keys(e).forEach(function (k) {
|
|
24
|
+
if (k !== 'default') {
|
|
25
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
26
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return e[k]; }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
28
31
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
n["default"] = e;
|
|
33
|
-
return Object.freeze(n);
|
|
32
|
+
}
|
|
33
|
+
n["default"] = e;
|
|
34
|
+
return Object.freeze(n);
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
|
|
36
38
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
37
39
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
|
|
38
40
|
var xIcon__default = /*#__PURE__*/_interopDefaultLegacy(xIcon);
|
|
39
41
|
var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
40
42
|
|
|
41
|
-
function _extends() {
|
|
42
|
-
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
43
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
44
|
-
var source = arguments[i];
|
|
45
|
-
for (var key in source) {
|
|
46
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
47
|
-
target[key] = source[key];
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return target;
|
|
52
|
-
};
|
|
53
|
-
return _extends.apply(this, arguments);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
43
|
const defaultContext = {
|
|
57
44
|
close: undefined,
|
|
58
45
|
placement: "top"
|
|
@@ -86,7 +73,7 @@ class PopoverAnchor extends React__namespace.Component {
|
|
|
86
73
|
});
|
|
87
74
|
return React__namespace.cloneElement(renderedChildren, sharedProps);
|
|
88
75
|
} else {
|
|
89
|
-
return React__namespace.cloneElement(children,
|
|
76
|
+
return React__namespace.cloneElement(children, _extends__default["default"]({}, children.props, sharedProps, {
|
|
90
77
|
onClick: children.props.onClick ? e => {
|
|
91
78
|
e.stopPropagation();
|
|
92
79
|
children.props.onClick();
|
|
@@ -165,6 +152,49 @@ function isFocusable(element) {
|
|
|
165
152
|
return element.matches(FOCUSABLE_ELEMENTS);
|
|
166
153
|
}
|
|
167
154
|
|
|
155
|
+
class PopoverEventListener extends React__namespace.Component {
|
|
156
|
+
constructor(...args) {
|
|
157
|
+
super(...args);
|
|
158
|
+
this.state = {
|
|
159
|
+
isFirstClick: true
|
|
160
|
+
};
|
|
161
|
+
this._handleKeyup = e => {
|
|
162
|
+
if (e.key === "Escape") {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
e.stopPropagation();
|
|
165
|
+
this.props.onClose(true);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
this._handleClick = e => {
|
|
169
|
+
var _this$props$contentRe;
|
|
170
|
+
if (this.state.isFirstClick) {
|
|
171
|
+
this.setState({
|
|
172
|
+
isFirstClick: false
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const node = ReactDOM__namespace.findDOMNode((_this$props$contentRe = this.props.contentRef) == null ? void 0 : _this$props$contentRe.current);
|
|
177
|
+
if (node && !node.contains(e.target)) {
|
|
178
|
+
e.preventDefault();
|
|
179
|
+
e.stopPropagation();
|
|
180
|
+
const shouldReturnFocus = !isFocusable(e.target);
|
|
181
|
+
this.props.onClose(shouldReturnFocus);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
componentDidMount() {
|
|
186
|
+
window.addEventListener("keyup", this._handleKeyup);
|
|
187
|
+
window.addEventListener("click", this._handleClick);
|
|
188
|
+
}
|
|
189
|
+
componentWillUnmount() {
|
|
190
|
+
window.removeEventListener("keyup", this._handleKeyup);
|
|
191
|
+
window.removeEventListener("click", this._handleClick);
|
|
192
|
+
}
|
|
193
|
+
render() {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
168
198
|
class InitialFocus extends React__namespace.Component {
|
|
169
199
|
constructor(...args) {
|
|
170
200
|
super(...args);
|
|
@@ -370,49 +400,6 @@ class FocusManager extends React__namespace.Component {
|
|
|
370
400
|
}
|
|
371
401
|
}
|
|
372
402
|
|
|
373
|
-
class PopoverEventListener extends React__namespace.Component {
|
|
374
|
-
constructor(...args) {
|
|
375
|
-
super(...args);
|
|
376
|
-
this.state = {
|
|
377
|
-
isFirstClick: true
|
|
378
|
-
};
|
|
379
|
-
this._handleKeyup = e => {
|
|
380
|
-
if (e.key === "Escape") {
|
|
381
|
-
e.preventDefault();
|
|
382
|
-
e.stopPropagation();
|
|
383
|
-
this.props.onClose(true);
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
this._handleClick = e => {
|
|
387
|
-
var _this$props$contentRe;
|
|
388
|
-
if (this.state.isFirstClick) {
|
|
389
|
-
this.setState({
|
|
390
|
-
isFirstClick: false
|
|
391
|
-
});
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
const node = ReactDOM__namespace.findDOMNode((_this$props$contentRe = this.props.contentRef) == null ? void 0 : _this$props$contentRe.current);
|
|
395
|
-
if (node && !node.contains(e.target)) {
|
|
396
|
-
e.preventDefault();
|
|
397
|
-
e.stopPropagation();
|
|
398
|
-
const shouldReturnFocus = !isFocusable(e.target);
|
|
399
|
-
this.props.onClose(shouldReturnFocus);
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
componentDidMount() {
|
|
404
|
-
window.addEventListener("keyup", this._handleKeyup);
|
|
405
|
-
window.addEventListener("click", this._handleClick);
|
|
406
|
-
}
|
|
407
|
-
componentWillUnmount() {
|
|
408
|
-
window.removeEventListener("keyup", this._handleKeyup);
|
|
409
|
-
window.removeEventListener("click", this._handleClick);
|
|
410
|
-
}
|
|
411
|
-
render() {
|
|
412
|
-
return null;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
403
|
class Popover extends React__namespace.Component {
|
|
417
404
|
constructor(...args) {
|
|
418
405
|
super(...args);
|
|
@@ -486,18 +473,16 @@ class Popover extends React__namespace.Component {
|
|
|
486
473
|
const {
|
|
487
474
|
initialFocusId,
|
|
488
475
|
placement,
|
|
489
|
-
showTail
|
|
476
|
+
showTail,
|
|
477
|
+
portal
|
|
490
478
|
} = this.props;
|
|
491
479
|
const {
|
|
492
480
|
anchorElement
|
|
493
481
|
} = this.state;
|
|
494
|
-
|
|
495
|
-
anchorElement: anchorElement,
|
|
496
|
-
initialFocusId: initialFocusId
|
|
497
|
-
}, React__namespace.createElement(wonderBlocksTooltip.TooltipPopper, {
|
|
482
|
+
const popperContent = React__namespace.createElement(wonderBlocksTooltip.TooltipPopper, {
|
|
498
483
|
anchorElement: anchorElement,
|
|
499
484
|
placement: placement
|
|
500
|
-
}, props => React__namespace.createElement(PopoverDialog,
|
|
485
|
+
}, props => React__namespace.createElement(PopoverDialog, _extends__default["default"]({}, props, {
|
|
501
486
|
"aria-describedby": `${uniqueId}-content`,
|
|
502
487
|
"aria-labelledby": `${uniqueId}-title`,
|
|
503
488
|
id: uniqueId,
|
|
@@ -505,11 +490,34 @@ class Popover extends React__namespace.Component {
|
|
|
505
490
|
placement
|
|
506
491
|
}),
|
|
507
492
|
showTail: showTail
|
|
508
|
-
}), this.renderContent(uniqueId)))
|
|
493
|
+
}), this.renderContent(uniqueId)));
|
|
494
|
+
if (portal) {
|
|
495
|
+
return React__namespace.createElement(FocusManager, {
|
|
496
|
+
anchorElement: anchorElement,
|
|
497
|
+
initialFocusId: initialFocusId
|
|
498
|
+
}, popperContent);
|
|
499
|
+
} else {
|
|
500
|
+
return React__namespace.createElement(InitialFocus, {
|
|
501
|
+
initialFocusId: initialFocusId
|
|
502
|
+
}, popperContent);
|
|
503
|
+
}
|
|
509
504
|
}
|
|
510
505
|
getHost() {
|
|
511
506
|
return wonderBlocksModal.maybeGetPortalMountedModalHostElement(this.state.anchorElement) || document.body;
|
|
512
507
|
}
|
|
508
|
+
renderPortal(uniqueId, opened) {
|
|
509
|
+
if (!opened) {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
const {
|
|
513
|
+
portal
|
|
514
|
+
} = this.props;
|
|
515
|
+
const popperHost = this.getHost();
|
|
516
|
+
if (portal && popperHost) {
|
|
517
|
+
return ReactDOM__namespace.createPortal(this.renderPopper(uniqueId), popperHost);
|
|
518
|
+
}
|
|
519
|
+
return this.renderPopper(uniqueId);
|
|
520
|
+
}
|
|
513
521
|
render() {
|
|
514
522
|
const {
|
|
515
523
|
children,
|
|
@@ -520,7 +528,6 @@ class Popover extends React__namespace.Component {
|
|
|
520
528
|
opened,
|
|
521
529
|
placement
|
|
522
530
|
} = this.state;
|
|
523
|
-
const popperHost = this.getHost();
|
|
524
531
|
return React__namespace.createElement(PopoverContext.Provider, {
|
|
525
532
|
value: {
|
|
526
533
|
close: this.handleClose,
|
|
@@ -535,7 +542,7 @@ class Popover extends React__namespace.Component {
|
|
|
535
542
|
"aria-controls": uniqueId,
|
|
536
543
|
"aria-expanded": opened ? "true" : "false",
|
|
537
544
|
onClick: this.handleOpen
|
|
538
|
-
}, children),
|
|
545
|
+
}, children), this.renderPortal(uniqueId, opened))), dismissEnabled && opened && React__namespace.createElement(PopoverEventListener, {
|
|
539
546
|
onClose: this.handleClose,
|
|
540
547
|
contentRef: this.contentRef
|
|
541
548
|
}));
|
|
@@ -543,7 +550,8 @@ class Popover extends React__namespace.Component {
|
|
|
543
550
|
}
|
|
544
551
|
Popover.defaultProps = {
|
|
545
552
|
placement: "top",
|
|
546
|
-
showTail: true
|
|
553
|
+
showTail: true,
|
|
554
|
+
portal: true
|
|
547
555
|
};
|
|
548
556
|
|
|
549
557
|
class CloseButton extends React__namespace.Component {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-popover",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.9",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@babel/runtime": "^7.18.6",
|
|
19
|
-
"@khanacademy/wonder-blocks-core": "^6.4.
|
|
20
|
-
"@khanacademy/wonder-blocks-icon-button": "^5.3.
|
|
21
|
-
"@khanacademy/wonder-blocks-modal": "^5.1.
|
|
22
|
-
"@khanacademy/wonder-blocks-tokens": "^1.3.
|
|
23
|
-
"@khanacademy/wonder-blocks-tooltip": "^2.3.
|
|
24
|
-
"@khanacademy/wonder-blocks-typography": "^2.1.
|
|
19
|
+
"@khanacademy/wonder-blocks-core": "^6.4.3",
|
|
20
|
+
"@khanacademy/wonder-blocks-icon-button": "^5.3.3",
|
|
21
|
+
"@khanacademy/wonder-blocks-modal": "^5.1.8",
|
|
22
|
+
"@khanacademy/wonder-blocks-tokens": "^1.3.1",
|
|
23
|
+
"@khanacademy/wonder-blocks-tooltip": "^2.3.7",
|
|
24
|
+
"@khanacademy/wonder-blocks-typography": "^2.1.14"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"@phosphor-icons/core": "^2.0.2",
|
|
@@ -32,6 +32,6 @@
|
|
|
32
32
|
"react-popper": "^2.0.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@khanacademy/wb-dev-build-settings": "^1.0.
|
|
35
|
+
"@khanacademy/wb-dev-build-settings": "^1.0.1"
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -621,14 +621,15 @@ describe("Popover", () => {
|
|
|
621
621
|
});
|
|
622
622
|
});
|
|
623
623
|
|
|
624
|
-
describe("keyboard navigation", () => {
|
|
625
|
-
it(
|
|
624
|
+
describe.each([true, false])("keyboard navigation", (portal) => {
|
|
625
|
+
it(`when portal=${portal}, should move focus to the first focusable element after popover is open`, async () => {
|
|
626
626
|
// Arrange
|
|
627
627
|
render(
|
|
628
628
|
<>
|
|
629
629
|
<Button>Prev focusable element outside</Button>
|
|
630
630
|
<Popover
|
|
631
631
|
onClose={jest.fn()}
|
|
632
|
+
portal={portal}
|
|
632
633
|
content={
|
|
633
634
|
<PopoverContent
|
|
634
635
|
title="Popover title"
|
|
@@ -667,13 +668,14 @@ describe("Popover", () => {
|
|
|
667
668
|
).toHaveFocus();
|
|
668
669
|
});
|
|
669
670
|
|
|
670
|
-
it(
|
|
671
|
+
it(`when portal=${portal}, should allow flowing focus correctly even if the popover remains open`, async () => {
|
|
671
672
|
// Arrange
|
|
672
673
|
render(
|
|
673
674
|
<>
|
|
674
675
|
<Button>Prev focusable element outside</Button>
|
|
675
676
|
<Popover
|
|
676
677
|
onClose={jest.fn()}
|
|
678
|
+
portal={portal}
|
|
677
679
|
content={
|
|
678
680
|
<PopoverContent
|
|
679
681
|
title="Popover title"
|
|
@@ -709,13 +711,14 @@ describe("Popover", () => {
|
|
|
709
711
|
).toHaveFocus();
|
|
710
712
|
});
|
|
711
713
|
|
|
712
|
-
it(
|
|
714
|
+
it(`when portal=${portal}, should allow circular navigation when the popover is open`, async () => {
|
|
713
715
|
// Arrange
|
|
714
716
|
render(
|
|
715
717
|
<>
|
|
716
718
|
<Button>Prev focusable element outside</Button>
|
|
717
719
|
<Popover
|
|
718
720
|
onClose={jest.fn()}
|
|
721
|
+
portal={portal}
|
|
719
722
|
content={
|
|
720
723
|
<PopoverContent
|
|
721
724
|
title="Popover title"
|
|
@@ -757,13 +760,14 @@ describe("Popover", () => {
|
|
|
757
760
|
).toHaveFocus();
|
|
758
761
|
});
|
|
759
762
|
|
|
760
|
-
it(
|
|
763
|
+
it(`when portal=${portal}, should allow navigating backwards when the popover is open`, async () => {
|
|
761
764
|
// Arrange
|
|
762
765
|
render(
|
|
763
766
|
<>
|
|
764
767
|
<Button>Prev focusable element outside</Button>
|
|
765
768
|
<Popover
|
|
766
769
|
onClose={jest.fn()}
|
|
770
|
+
portal={portal}
|
|
767
771
|
content={
|
|
768
772
|
<PopoverContent
|
|
769
773
|
title="Popover title"
|