Skip to content

Commit

Permalink
Fix bug where a position: fixed popover content doesn't scroll (#1064)
Browse files Browse the repository at this point in the history
* Fix bug where a position: fixed popover content doesn't scroll

* changelog

* Add a repositionOnScroll prop to EuiPopover

* correct the changelog

* addressing PR feedback

* update changelog diff
  • Loading branch information
chandlerprall authored Aug 6, 2018
1 parent 30013e9 commit b98ab5b
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- Added `spacesApp` logo to `EuiIcon` set ([#1065](https://github.com/elastic/eui/pull/1065))
- Added `!default` to border SASS props ([#1079](https://github.com/elastic/eui/pull/1079))
- Added `repositionOnScroll` prop to `EuiPopover` which enables repositioning the popover when the window is scrolled. ([#1064](https://github.com/elastic/eui/pull/1064))

**Bug fixes**

Expand Down
20 changes: 20 additions & 0 deletions src-docs/src/views/popover/popover_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ import PopoverContainer from './popover_container';
const popoverContainerSource = require('!!raw-loader!./popover_container');
const popoverContainerHtml = renderToHtml(PopoverContainer);

import PopoverFixed from './popover_fixed';
const popoverFixedSource = require('!!raw-loader!./popover_fixed');
const popoverFixedHtml = renderToHtml(PopoverFixed);

export const PopoverExample = {
title: 'Popover',
Expand Down Expand Up @@ -204,5 +207,22 @@ export const PopoverExample = {
</div>
),
demo: <PopoverHTMLElementAnchor />,
}, {
title: 'Popover on a fixed element',
source: [{
type: GuideSectionTypes.JS,
code: popoverFixedSource,
}, {
type: GuideSectionTypes.HTML,
code: popoverFixedHtml,
}],
text: (
<div>
<p>
Popover content even works on <EuiCode>position: fixed;</EuiCode> elements.
</p>
</div>
),
demo: <PopoverFixed />,
}],
};
67 changes: 67 additions & 0 deletions src-docs/src/views/popover/popover_fixed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, {
Component,
} from 'react';

import {
EuiButton,
EuiPopover,
} from '../../../../src/components';

export default class PopoverContainer extends Component {
constructor(props) {
super(props);

this.state = {
isExampleShown: false,
isPopoverOpen: false,
};
}

toggleExample = () => this.setState(({ isExampleShown }) => ({ isExampleShown: !isExampleShown }))

onButtonClick = () => {
this.setState({
isPopoverOpen: !this.state.isPopoverOpen,
});
}

closePopover = () => {
this.setState({
isPopoverOpen: false,
});
}

setPanelRef = node => this.panel = node;

render() {
const button = (
<EuiButton
iconType="arrowDown"
iconSide="right"
onClick={this.onButtonClick}
style={{ background: 'white' }}
>
Show fixed popover
</EuiButton>
);

return (
<React.Fragment>
<EuiButton onClick={this.toggleExample}>Toggle Example</EuiButton>
{this.state.isExampleShown && (
<EuiPopover
button={button}
isOpen={this.state.isPopoverOpen}
closePopover={this.closePopover}
style={{ position: 'fixed', bottom: 50, right: 50 }}
repositionOnScroll={true}
>
<div>
This popover scrolls with the button element!
</div>
</EuiPopover>
)}
</React.Fragment>
);
}
}
16 changes: 16 additions & 0 deletions src/components/popover/popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ export class EuiPopover extends Component {
this.setState({ suppressingPopover: false, isOpening: true }); // eslint-disable-line react/no-did-mount-set-state
}

if (this.props.repositionOnScroll) {
window.addEventListener('scroll', this.positionPopover);
}

this.updateFocus();
}

Expand All @@ -169,6 +173,15 @@ export class EuiPopover extends Component {
});
}

// update scroll listener
if (prevProps.repositionOnScroll !== this.props.repositionOnScroll) {
if (this.props.repositionOnScroll) {
window.addEventListener('scroll', this.positionPopover);
} else {
window.removeEventListener('scroll', this.positionPopover);
}
}

// The popover is being closed.
if (prevProps.isOpen && !this.props.isOpen) {
// If the user has just closed the popover, queue up the removal of the content after the
Expand All @@ -184,6 +197,7 @@ export class EuiPopover extends Component {
}

componentWillUnmount() {
window.removeEventListener('scroll', this.positionPopover);
clearTimeout(this.closingTransitionTimeout);
}

Expand Down Expand Up @@ -420,6 +434,8 @@ EuiPopover.propTypes = {
PropTypes.node,
PropTypes.instanceOf(HTMLElement)
]),
/** When `true`, the popover's position is re-calculated when the user scrolls, this supports having fixed-position popover anchors. */
repositionOnScroll: PropTypes.bool,
};

EuiPopover.defaultProps = {
Expand Down

0 comments on commit b98ab5b

Please sign in to comment.