New: Replace react-tether with react-popper (#789)

This commit is contained in:
Qstick 2019-05-10 21:56:04 -04:00 committed by GitHub
parent 6ea7f97b16
commit cf40df7606
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 981 additions and 970 deletions

View file

@ -1,7 +1,3 @@
.tether {
z-index: 2000;
}
.menu {
position: relative;
}

View file

@ -1,32 +1,31 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import TetherComponent from 'react-tether';
import { Manager, Popper, Reference } from 'react-popper';
import getUniqueElememtId from 'Utilities/getUniqueElementId';
import { align } from 'Helpers/Props';
import Portal from 'Components/Portal';
import styles from './Menu.css';
const baseTetherOptions = {
skipMoveElement: true,
constraints: [
{
to: 'window',
attachment: 'together',
pin: true
const sharedPopperOptions = {
modifiers: {
preventOverflow: {
padding: 0
},
flip: {
padding: 0
}
]
}
};
const tetherOptions = {
const popperOptions = {
[align.RIGHT]: {
...baseTetherOptions,
attachment: 'top right',
targetAttachment: 'bottom right'
...sharedPopperOptions,
placement: 'bottom-end'
},
[align.LEFT]: {
...baseTetherOptions,
attachment: 'top left',
targetAttachment: 'bottom left'
...sharedPopperOptions,
placement: 'bottom-start'
}
};
@ -38,6 +37,9 @@ class Menu extends Component {
constructor(props, context) {
super(props, context);
this._scheduleUpdate = null;
this._menuButtonId = getUniqueElememtId();
this.state = {
isMenuOpen: false,
maxHeight: 0
@ -48,6 +50,12 @@ class Menu extends Component {
this.setMaxHeight();
}
componentDidUpdate() {
if (this._scheduleUpdate) {
this._scheduleUpdate();
}
}
componentWillUnmount() {
this._removeListener();
}
@ -60,22 +68,26 @@ class Menu extends Component {
return;
}
const menu = ReactDOM.findDOMNode(this.refs.menu);
const menuButton = document.getElementById(this._menuButtonId);
if (!menu) {
if (!menuButton) {
return;
}
const { bottom } = menu.getBoundingClientRect();
const { bottom } = menuButton.getBoundingClientRect();
const maxHeight = window.innerHeight - bottom;
return maxHeight;
}
setMaxHeight() {
this.setState({
maxHeight: this.getMaxHeight()
});
const maxHeight = this.getMaxHeight();
if (maxHeight !== this.state.maxHeight) {
this.setState({
maxHeight
});
}
}
_addListener() {
@ -99,14 +111,13 @@ class Menu extends Component {
// Listeners
onWindowClick = (event) => {
const menu = ReactDOM.findDOMNode(this.refs.menu);
const menuContent = ReactDOM.findDOMNode(this.refs.menuContent);
const menuButton = document.getElementById(this._menuButtonId);
if (!menu) {
if (!menuButton) {
return;
}
if ((!menu.contains(event.target) || menuContent.contains(event.target)) && this.state.isMenuOpen) {
if (!menuButton.contains(event.target) && this.state.isMenuOpen) {
this.setState({ isMenuOpen: false });
this._removeListener();
}
@ -116,8 +127,10 @@ class Menu extends Component {
this.setMaxHeight();
}
onWindowScroll = () => {
this.setMaxHeight();
onWindowScroll = (event) => {
if (this.state.isMenuOpen) {
this.setMaxHeight();
}
}
onMenuButtonPress = () => {
@ -158,35 +171,40 @@ class Menu extends Component {
}
);
const content = React.cloneElement(
childrenArray[1],
{
ref: 'menuContent',
alignMenu,
maxHeight,
isOpen: isMenuOpen
}
);
return (
<TetherComponent
classes={{
element: styles.tether
}}
{...tetherOptions[alignMenu]}
>
<div
ref="menu"
className={className}
>
{button}
</div>
<Manager>
<Reference>
{({ ref }) => (
<div
ref={ref}
id={this._menuButtonId}
className={className}
>
{button}
</div>
)}
</Reference>
{
isMenuOpen &&
content
}
</TetherComponent>
<Portal>
<Popper {...popperOptions[alignMenu]}>
{({ ref, style, scheduleUpdate }) => {
this._scheduleUpdate = scheduleUpdate;
return React.cloneElement(
childrenArray[1],
{
forwardedRef: ref,
style: {
...style,
maxHeight
},
isOpen: isMenuOpen
}
);
}}
</Popper>
</Portal>
</Manager>
);
}
}

View file

@ -1,4 +1,5 @@
.menuContent {
z-index: $popperZIndex;
display: flex;
flex-direction: column;
background-color: $toolbarMenuItemBackgroundColor;

View file

@ -10,30 +10,37 @@ class MenuContent extends Component {
render() {
const {
forwardedRef,
className,
children,
maxHeight
style,
isOpen
} = this.props;
return (
<div
ref={forwardedRef}
className={className}
style={{
maxHeight: maxHeight ? `${maxHeight}px` : undefined
}}
style={style}
>
<Scroller className={styles.scroller}>
{children}
</Scroller>
{
isOpen ?
<Scroller className={styles.scroller}>
{children}
</Scroller> :
null
}
</div>
);
}
}
MenuContent.propTypes = {
forwardedRef: PropTypes.func,
className: PropTypes.string,
children: PropTypes.node.isRequired,
maxHeight: PropTypes.number
style: PropTypes.object,
isOpen: PropTypes.bool
};
MenuContent.defaultProps = {

View file

@ -1,5 +1,6 @@
.separator {
overflow: hidden;
min-height: 1px;
height: 1px;
background-color: $themeDarkColor;
}