@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
|
@@ -16,8 +16,9 @@ import PopoverContentCore from "./popover-content-core";
|
|
|
16
16
|
import PopoverContext from "./popover-context";
|
|
17
17
|
import PopoverAnchor from "./popover-anchor";
|
|
18
18
|
import PopoverDialog from "./popover-dialog";
|
|
19
|
-
import FocusManager from "./focus-manager";
|
|
20
19
|
import PopoverEventListener from "./popover-event-listener";
|
|
20
|
+
import InitialFocus from "./initial-focus";
|
|
21
|
+
import FocusManager from "./focus-manager";
|
|
21
22
|
|
|
22
23
|
type PopoverContents =
|
|
23
24
|
| React.ReactElement<React.ComponentProps<typeof PopoverContent>>
|
|
@@ -101,6 +102,20 @@ type Props = AriaProps &
|
|
|
101
102
|
* Whether to show the popover tail or not. Defaults to true.
|
|
102
103
|
*/
|
|
103
104
|
showTail: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Optional property to enable the portal functionality of popover.
|
|
107
|
+
* This is very handy in cases where the Popover can't be easily
|
|
108
|
+
* injected into the DOM structure and requires portaling to
|
|
109
|
+
* the trigger location.
|
|
110
|
+
*
|
|
111
|
+
* Set to "true" by default.
|
|
112
|
+
*
|
|
113
|
+
* CAUTION: Turning off portal could cause some clipping issues
|
|
114
|
+
* especially around legacy code with usage of z-indexing,
|
|
115
|
+
* Use caution when turning this functionality off and ensure
|
|
116
|
+
* your content does not get clipped or hidden.
|
|
117
|
+
*/
|
|
118
|
+
portal?: boolean;
|
|
104
119
|
}>;
|
|
105
120
|
|
|
106
121
|
type State = Readonly<{
|
|
@@ -121,6 +136,7 @@ type State = Readonly<{
|
|
|
121
136
|
type DefaultProps = Readonly<{
|
|
122
137
|
placement: Props["placement"];
|
|
123
138
|
showTail: Props["showTail"];
|
|
139
|
+
portal: Props["portal"];
|
|
124
140
|
}>;
|
|
125
141
|
|
|
126
142
|
/**
|
|
@@ -150,6 +166,7 @@ export default class Popover extends React.Component<Props, State> {
|
|
|
150
166
|
static defaultProps: DefaultProps = {
|
|
151
167
|
placement: "top",
|
|
152
168
|
showTail: true,
|
|
169
|
+
portal: true,
|
|
153
170
|
};
|
|
154
171
|
|
|
155
172
|
/**
|
|
@@ -255,33 +272,44 @@ export default class Popover extends React.Component<Props, State> {
|
|
|
255
272
|
}
|
|
256
273
|
|
|
257
274
|
renderPopper(uniqueId: string): React.ReactNode {
|
|
258
|
-
const {initialFocusId, placement, showTail} = this.props;
|
|
275
|
+
const {initialFocusId, placement, showTail, portal} = this.props;
|
|
259
276
|
const {anchorElement} = this.state;
|
|
260
277
|
|
|
261
|
-
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
278
|
+
const popperContent = (
|
|
279
|
+
<TooltipPopper anchorElement={anchorElement} placement={placement}>
|
|
280
|
+
{(props: PopperElementProps) => (
|
|
281
|
+
<PopoverDialog
|
|
282
|
+
{...props}
|
|
283
|
+
aria-describedby={`${uniqueId}-content`}
|
|
284
|
+
aria-labelledby={`${uniqueId}-title`}
|
|
285
|
+
id={uniqueId}
|
|
286
|
+
onUpdate={(placement) => this.setState({placement})}
|
|
287
|
+
showTail={showTail}
|
|
288
|
+
>
|
|
289
|
+
{this.renderContent(uniqueId)}
|
|
290
|
+
</PopoverDialog>
|
|
291
|
+
)}
|
|
292
|
+
</TooltipPopper>
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
if (portal) {
|
|
296
|
+
return (
|
|
297
|
+
<FocusManager
|
|
267
298
|
anchorElement={anchorElement}
|
|
268
|
-
|
|
299
|
+
initialFocusId={initialFocusId}
|
|
269
300
|
>
|
|
270
|
-
{
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
</TooltipPopper>
|
|
283
|
-
</FocusManager>
|
|
284
|
-
);
|
|
301
|
+
{popperContent}
|
|
302
|
+
</FocusManager>
|
|
303
|
+
);
|
|
304
|
+
} else {
|
|
305
|
+
return (
|
|
306
|
+
// Ensures the user is focused on the first available element
|
|
307
|
+
// when popover is rendered without the focus manager.
|
|
308
|
+
<InitialFocus initialFocusId={initialFocusId}>
|
|
309
|
+
{popperContent}
|
|
310
|
+
</InitialFocus>
|
|
311
|
+
);
|
|
312
|
+
}
|
|
285
313
|
}
|
|
286
314
|
|
|
287
315
|
getHost(): Element | null | undefined {
|
|
@@ -295,10 +323,29 @@ export default class Popover extends React.Component<Props, State> {
|
|
|
295
323
|
);
|
|
296
324
|
}
|
|
297
325
|
|
|
326
|
+
renderPortal(uniqueId: string, opened: boolean) {
|
|
327
|
+
if (!opened) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const {portal} = this.props;
|
|
332
|
+
const popperHost = this.getHost();
|
|
333
|
+
|
|
334
|
+
// Attach the popover to a Portal
|
|
335
|
+
if (portal && popperHost) {
|
|
336
|
+
return ReactDOM.createPortal(
|
|
337
|
+
this.renderPopper(uniqueId),
|
|
338
|
+
popperHost,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Otherwise, append the dialog next to the trigger element
|
|
343
|
+
return this.renderPopper(uniqueId);
|
|
344
|
+
}
|
|
345
|
+
|
|
298
346
|
render(): React.ReactNode {
|
|
299
347
|
const {children, dismissEnabled, id} = this.props;
|
|
300
348
|
const {opened, placement} = this.state;
|
|
301
|
-
const popperHost = this.getHost();
|
|
302
349
|
|
|
303
350
|
return (
|
|
304
351
|
<PopoverContext.Provider
|
|
@@ -319,12 +366,7 @@ export default class Popover extends React.Component<Props, State> {
|
|
|
319
366
|
>
|
|
320
367
|
{children}
|
|
321
368
|
</PopoverAnchor>
|
|
322
|
-
{
|
|
323
|
-
opened &&
|
|
324
|
-
ReactDOM.createPortal(
|
|
325
|
-
this.renderPopper(uniqueId),
|
|
326
|
-
popperHost,
|
|
327
|
-
)}
|
|
369
|
+
{this.renderPortal(uniqueId, opened)}
|
|
328
370
|
</React.Fragment>
|
|
329
371
|
)}
|
|
330
372
|
</IDProvider>
|