-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Core] Rerender popovers when content resizes #2718
Changes from 9 commits
2b4c3c8
15ae92c
6394932
94078b7
3788f2a
ca0de37
fdfd8a3
6510801
a9838d8
53d42af
294e219
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import classNames from "classnames"; | |
import { ModifierFn } from "popper.js"; | ||
import * as React from "react"; | ||
import { Manager, Popper, PopperChildrenProps, Reference, ReferenceChildrenProps } from "react-popper"; | ||
import ResizeObserver from "resize-observer-polyfill"; | ||
|
||
import { AbstractPureComponent } from "../../common/abstractPureComponent"; | ||
import * as Classes from "../../common/classes"; | ||
|
@@ -127,6 +128,12 @@ export class Popover extends AbstractPureComponent<IPopoverProps, IPopoverState> | |
// element on the same page. | ||
private lostFocusOnSamePage = true; | ||
|
||
// ResizeObserver instance to monitor for content size changes on the popover | ||
private popperObserver: ResizeObserver; | ||
|
||
// Reference to the Poppper.scheduleUpdate() function, this changes every time the popper is mounted | ||
private popperScheduleUpdate: () => void; | ||
|
||
private refHandlers = { | ||
popover: (ref: HTMLElement) => { | ||
this.popoverElement = ref; | ||
|
@@ -201,6 +208,7 @@ export class Popover extends AbstractPureComponent<IPopoverProps, IPopoverState> | |
|
||
public componentDidMount() { | ||
this.updateDarkParent(); | ||
this.popperObserver = new ResizeObserver(() => this.popperScheduleUpdate && this.popperScheduleUpdate()); | ||
} | ||
|
||
public componentWillReceiveProps(nextProps: IPopoverProps) { | ||
|
@@ -221,10 +229,19 @@ export class Popover extends AbstractPureComponent<IPopoverProps, IPopoverState> | |
|
||
public componentDidUpdate() { | ||
this.updateDarkParent(); | ||
|
||
if (this.popoverElement instanceof HTMLElement) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. our convention for this check on refs is |
||
// Clear active observations to avoid the list growing. | ||
this.popperObserver.disconnect(); | ||
|
||
// Ensure our observer has an up-to-date reference to popoverElement | ||
this.popperObserver.observe(this.popoverElement); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. clear the observer before observing new elements. this will quickly result in a long list of watched elements, many of which may not be in the DOM. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @giladgray I've opted to just recreate the observer completely, does this seem reasonable you? |
||
} | ||
} | ||
|
||
public componentWillUnmount() { | ||
super.componentWillUnmount(); | ||
this.popperObserver.disconnect(); | ||
} | ||
|
||
protected validateProps(props: IPopoverProps & { children?: React.ReactNode }) { | ||
|
@@ -267,6 +284,9 @@ export class Popover extends AbstractPureComponent<IPopoverProps, IPopoverState> | |
const { usePortal, interactionKind } = this.props; | ||
const { transformOrigin } = this.state; | ||
|
||
// Need to update our reference to this on every render as it will change. | ||
this.popperScheduleUpdate = popperProps.scheduleUpdate; | ||
|
||
const popoverHandlers: HTMLDivProps = { | ||
// always check popover clicks for dismiss class | ||
onClick: this.handlePopoverClick, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
finally, let's be typesafe and avoid coercion. use our
safeInvoke
util here.