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

Refactor EuiPopover to use new positioning service #948

Merged
merged 9 commits into from
Jun 29, 2018

Conversation

chandlerprall
Copy link
Contributor

Closes #873

Refactored EuiPopover to use portals and take advantage of the positioning service. The service had to be expanded to include an align parameter to allow shifting content into a given corner if there's room.

shifting popover content

@snide
Copy link
Contributor

snide commented Jun 27, 2018

Biggest thing I saw here was that i'd be nice if we can recalculate position on window resize. Right now if you resize the page while the popover is open, the popover retains its original position.

I don't consider this a blocker, and given a choice between our current functionality where this thing breaks and doesn't work in overflows, I'd rather see a follow up PR (if we think it would take awhile to fix) so that the main fix gets in quickly.

Either way I'd assume @cchaos or I would do a design PR as as a fast followup to fix the arrow coloring issue.

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

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

Code LGTM. I had a few small suggestions but I also noticed some bugs on the ContextMenu page.

I expected the first example to move above the button when the window was very short, but instead it stays below the button and gets clipped:

image

The last example appears over the button, even when there seems to be enough room below it:

image

let arrowStyles = {};
let arrowPosition = null;
if (node != null) {
// panel is coming into existance
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo: existence

'left': 'left'
};
function getPopoverPositionFromAnchorPosition(anchorPosition) {
const [, primaryPosition] = anchorPosition.match(/^(.*?)[A-Z]/);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not going to lie... I had to run this through regex101 to figure out what it was doing and understand how we're mapping anchor position to popover position.

I both like and dislike this code because it's clever. 😄 But I would really find something like this much more understandable:

const anchorPositionToPopoverPositionMap = {
  'upCenter': 'top',
  'upLeft': 'top',
  'upRight': 'top',
  'downCenter': 'bottom',
  'downLeft': 'bottom',
  'downRight': 'bottom',
  'leftCenter': 'left',
  'leftUp': 'left',
  'leftDown': 'left',
  'rightCenter': 'right',
  'rightUp': 'right',
  'rightDown': 'right',
};

function getPopoverPositionFromAnchorPosition(anchorPosition) {
  return anchorPositionToPopoverPositionMap[anchorPosition];
}

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I disagree about it being clever; I did consider doing something like this, but my preference for some kind of parsing vs. a lookup mapping is because the target information isn't correlated to the input, it is itself encoded in the input. Parsing it out enforces that relationship. I'll add a comment to each function describing what the regex is doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and I'll include tests for both!

@@ -22,9 +16,6 @@ export class EuiPortal extends Component {
} = this.props;

this.portalNode = document.createElement('div');
}

componentDidMount() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice!

@cjcenizal
Copy link
Contributor

Might be worth auditing the other examples for cases where popover is being used and making sure they look right.

@snide
Copy link
Contributor

snide commented Jun 28, 2018

Wierdly, I'm seeing times where the clicks on context menu items also dismiss the popover.

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

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

After talking this over with Chandler, I understand his perspective but I still disagree. That said, I don't feel strongly about this point so I give this code my LGTM. 😄

// extract the first positional word from anchorPosition:
// starts at the beginning (" ^ ") of anchorPosition and
// captures all of the characters (" (.*?) ") until the
// first capital letter (" [A-Z] ") is encountered
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the "why" (instead of "what") would be very helpful here too. Something like this:

// Pull out the part of the anchorPosition string that indicates cardinal position,
// e.g. "upCenter" -> "center", "leftUp" -> "up".

@cchaos
Copy link
Contributor

cchaos commented Jun 28, 2018

One thing I noticed real quick, is the positioning is still based on the .euiPopover versus the actual triggering element (button).

screen shot 2018-06-28 at 17 39 48 pm

@snide
Copy link
Contributor

snide commented Jun 28, 2018

@cchaos that's on us. It existed in the old one too. Has to do with the extra div. We can fix that in a follow up.

@chandlerprall
Copy link
Contributor Author

@cjcenizal the ContextMenu issues are related to that component's timing in rendering content vs. positioning the popover. When the popover is created, the context panel has a height of only 2 pixels, so the initial placement is correct. Then more content comes in which screws everything up. I'm going to pull this out into a separate issue because of that component's complexity, and I expect it to grow into a more general approach for handling dynamic child content.

}
};

buttonRef = node => this.button = node;
Copy link
Contributor

Choose a reason for hiding this comment

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

What's this for? I only see it being added a new div wrapper around the actual button.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's used to identify the bounding box of the anchor button (line 177)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh, ok the problem is that it's a div so it's block-level by default. We'll need to add display: inline-block to it.
screen shot 2018-06-28 at 18 12 15 pm

@cchaos
Copy link
Contributor

cchaos commented Jun 28, 2018

One more thing, if the page is horizontally scrolling it doesn't account for the scroll position:

screen shot 2018-06-28 at 17 46 48 pm

@chandlerprall
Copy link
Contributor Author

@cchaos I've added inline-block to the wrapping anchor div

@chandlerprall chandlerprall force-pushed the feature/enhanced-popover branch from 607f0a9 to 4215a8d Compare June 29, 2018 16:02
@chandlerprall
Copy link
Contributor Author

@cjcenizal fixed the problem where interacting with the popover would close it; issue was that the click outside detector wasn't respecting content rendered through a child portal, so I modified how the click detection works. Please review these changes & comments.

Copy link
Contributor

@snide snide left a comment

Choose a reason for hiding this comment

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

With the context menu fix I'm good with merging this. Tested it in multiple browsers.

Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

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

@chandlerprall Great solution to the onClickOutside problem! Code LGTM. Thanks for the very clear explanation in the comments.

@chandlerprall chandlerprall merged commit de26d2a into elastic:master Jun 29, 2018
@chandlerprall chandlerprall deleted the feature/enhanced-popover branch June 29, 2018 19:59
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.

4 participants