mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-23 22:25:09 -04:00
New: Replace react-tether with react-popper (#789)
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user