Skip to content
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] fix(Popover): work around react-popper bug, fix React 18 compat #6458

Merged
merged 4 commits into from
Oct 12, 2023

Conversation

adidahiya
Copy link
Contributor

@adidahiya adidahiya commented Oct 12, 2023

Fixes #6203

Checklist

  • Includes tests
  • Update (code) documentation

Changes proposed in this pull request:

fix(Popover): adjust target ref behavior to work around react-popper innerRef bug, fixing React 18 strict mode compatibility

Reviewers should focus on:

No regressions in Popover, table draggable interactions, ResizeSensor

Screenshot

@adidahiya
Copy link
Contributor Author

[core] fix(Popover): work around react-popper bug, React 18 compat

Build artifact links for this commit: documentation | landing | table | demo

This is an automated comment from the deploy-preview CircleCI job.

Comment on lines 83 to 86
// if we're provided a ref to the child already, we don't need to attach one ourselves
if (this.props.targetRef !== undefined) {
return onlyChild;
}
Copy link
Contributor Author

@adidahiya adidahiya Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it turns out that this change to accept both RefObject and RefCallback broke all Popovers with children that are not DOM elements, such as <Suggest> which renders an <InputGroup> child. here's what happens:

  1. ResizeSensor gets a ref callback as its targetRef
  2. ResizeSensor is not able to peek into this ref callback (like it could with .current on ref objects) to get the DOM element, so it must create its own ref
  3. ResizeSensor's own ref can only attach to its direct child, which may not be a native DOM element
  4. ResizeSensor returns this non-DOM element value to Popover#targetRef at runtime, thereby setting Popover#targetElement to an invalid type (e.g. InputGroup inside a Suggest, instead of HTMLInputElement)
  5. the page crashes because:
    i. Popover code which expects this.targetElement to be a DOM node fails (e.g. element.closest())
    ii. popper.js fails because it doesn't have access to a valid DOM node

thus, targetRef can only accept a RefObject type, which must be provided if the child is a non-native DOM element node

@adidahiya
Copy link
Contributor Author

Fix tests, add comments

Build artifact links for this commit: documentation | landing | table | demo

This is an automated comment from the deploy-preview CircleCI job.

@adidahiya
Copy link
Contributor Author

fix tests, only create ResizeObserver on mount

Build artifact links for this commit: documentation | landing | table | demo

This is an automated comment from the deploy-preview CircleCI job.

@adidahiya adidahiya merged commit dba1623 into develop Oct 12, 2023
12 checks passed
@adidahiya adidahiya deleted the ad/fix-popover-ref branch October 12, 2023 18:15
@@ -89,6 +90,7 @@ export class ResizeSensor extends AbstractPureComponent<ResizeSensorProps> {
}

public componentDidMount() {
this.observer = new ResizeObserver(entries => this.props.onResize?.(entries));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this caused a runtime error in some test environments like jsdom where ResizeObserver is undefined. apparently components still get mounted in jsdom, whoops. I will fix the regression ASAP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[v5] Popover doesn't close when clicked outside in React 18 StrictMode
1 participant