+ menuOffset={menuOffset}
+ menuRef={node => {
+ this._tooltipEl = node;
+ }}>
this.handleMouse(evt)}
onFocus={evt => this.handleMouse(evt)}
onBlur={evt => this.handleMouse(evt)}
- onContextMenu={evt => this.handleMouse(evt)}
- ref={node => {
- this._tooltipEl = node;
- }}>
+ onContextMenu={evt => this.handleMouse(evt)}>
{children}
diff --git a/src/internal/FloatingMenu.js b/src/internal/FloatingMenu.js
index 0bdaef6162..e442703f4e 100644
--- a/src/internal/FloatingMenu.js
+++ b/src/internal/FloatingMenu.js
@@ -1,6 +1,6 @@
import warning from 'warning';
import PropTypes from 'prop-types';
-import React from 'react';
+import React, { createRef } from 'react';
import ReactDOM from 'react-dom';
import window from 'window-or-global';
@@ -32,8 +32,6 @@ export const DIRECTION_TOP = 'top';
export const DIRECTION_RIGHT = 'right';
export const DIRECTION_BOTTOM = 'bottom';
-const hasCreatePortal = typeof ReactDOM.createPortal === 'function';
-
/**
* @param {FloatingMenu~offset} [oldMenuOffset={}] The old value.
* @param {FloatingMenu~offset} [menuOffset={}] The new value.
@@ -115,6 +113,11 @@ class FloatingMenu extends React.Component {
*/
children: PropTypes.object,
+ /**
+ * The query selector indicating where the floating menu body should be placed.
+ */
+ target: PropTypes.func,
+
/**
* The position in the viewport of the trigger button.
*/
@@ -189,17 +192,10 @@ class FloatingMenu extends React.Component {
/**
* The cached refernce to the menu body.
- * @type {Element}
+ * @type {React.RefObject}
* @private
*/
- _menuBody = null;
-
- constructor(props) {
- super(props);
- if (typeof document !== 'undefined' && hasCreatePortal) {
- this.el = document.createElement('div');
- }
- }
+ _menuBody = createRef();
/**
* Calculates the position in the viewport of floating menu,
@@ -212,7 +208,7 @@ class FloatingMenu extends React.Component {
* @private
*/
_updateMenuSize = (prevProps = {}) => {
- const menuBody = this._menuBody;
+ const menuBody = this._menuBody.current;
warning(
menuBody,
'The DOM node for menu body for calculating its position is not available. Skipping...'
@@ -263,72 +259,29 @@ class FloatingMenu extends React.Component {
};
componentDidUpdate(prevProps) {
- if (!hasCreatePortal) {
- ReactDOM.render(this._getChildrenWithProps(), this._menuContainer);
- } else {
- this._updateMenuSize(prevProps);
- }
+ this._updateMenuSize(prevProps);
const { onPlace } = this.props;
if (
this._placeInProgress &&
this.state.floatingPosition &&
typeof onPlace === 'function'
) {
- onPlace(this._menuBody);
+ onPlace(this._menuBody.current);
this._placeInProgress = false;
}
}
componentDidMount() {
const { menuRef } = this.props;
- if (!hasCreatePortal) {
- this._menuContainer = document.createElement('div');
- document.body.appendChild(this._menuContainer);
- const style = {
- display: 'block',
- opacity: 0,
- };
- const childrenWithProps = React.cloneElement(this.props.children, {
- style,
- });
- ReactDOM.render(childrenWithProps, this._menuContainer, () => {
- this._menuBody = this._menuContainer.firstChild;
- this._updateMenuSize();
- ReactDOM.render(
- this._getChildrenWithProps(),
- this._menuContainer,
- () => {
- this._placeInProgress = true;
- menuRef && menuRef(this._menuBody);
- }
- );
- });
- } else {
- if (this.el && this.el.firstChild) {
- this._menuBody = this.el.firstChild;
- document.body.appendChild(this._menuBody);
- this._placeInProgress = true;
- menuRef && menuRef(this._menuBody);
- }
- this._updateMenuSize();
- }
+ this._placeInProgress = true;
+ menuRef && menuRef(this._menuBody.current);
+ this._updateMenuSize();
}
componentWillUnmount() {
const { menuRef } = this.props;
menuRef && menuRef(null);
this._placeInProgress = false;
- if (!hasCreatePortal) {
- const menuContainer = this._menuContainer;
- ReactDOM.unmountComponentAtNode(menuContainer);
- if (menuContainer && menuContainer.parentNode) {
- menuContainer.parentNode.removeChild(menuContainer);
- }
- this._menuContainer = null;
- } else if (this._menuBody) {
- // Moves the menu body back to the portal container so that React unmount code does not crash
- this.el.appendChild(this._menuBody);
- }
}
/**
@@ -351,6 +304,7 @@ class FloatingMenu extends React.Component {
top: '0px',
};
return React.cloneElement(children, {
+ ref: this._menuBody,
style: {
...styles,
...positioningStyle,
@@ -362,8 +316,12 @@ class FloatingMenu extends React.Component {
};
render() {
- if (typeof document !== 'undefined' && hasCreatePortal) {
- return ReactDOM.createPortal(this._getChildrenWithProps(), this.el);
+ if (typeof document !== 'undefined') {
+ const { target } = this.props;
+ return ReactDOM.createPortal(
+ this._getChildrenWithProps(),
+ !target ? document.body : target()
+ );
}
return null;
}