diff --git a/package.json b/package.json
index 5f7b46c629..b7e3e20f55 100644
--- a/package.json
+++ b/package.json
@@ -124,9 +124,10 @@
"keycode": "^2.2.0",
"prop-types": "^15.6.1",
"prop-types-extra": "^1.0.1",
- "react-overlays": "^0.9.3",
+ "react-is": "^18.3.1",
+ "react-overlays": "^5.2.0",
"react-prop-types": "^0.4.0",
- "react-transition-group": "^2.0.0",
+ "react-transition-group": "^4.4.0",
"uncontrollable": "^5.0.0",
"warning": "^3.0.0"
},
diff --git a/patches/react-overlays+0.9.3.patch b/patches/react-overlays+0.9.3.patch
deleted file mode 100644
index 5539968862..0000000000
--- a/patches/react-overlays+0.9.3.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-diff --git a/node_modules/react-overlays/lib/Modal.js b/node_modules/react-overlays/lib/Modal.js
-index 9fbba3b..c876341 100644
---- a/node_modules/react-overlays/lib/Modal.js
-+++ b/node_modules/react-overlays/lib/Modal.js
-@@ -576,7 +576,7 @@ var _initialiseProps = function _initialiseProps() {
- };
-
- this.handleDocumentKeyDown = function (e) {
-- if (_this2.props.keyboard && e.keyCode === 27 && _this2.isTopModal()) {
-+ if (_this2.props.keyboard && (e.keyCode === 27 || e.key === 'Escape') && _this2.isTopModal()) {
- if (_this2.props.onEscapeKeyDown) {
- _this2.props.onEscapeKeyDown(e);
- }
-@@ -586,7 +586,7 @@ var _initialiseProps = function _initialiseProps() {
- };
-
- this.handleDocumentKeyUp = function (e) {
-- if (_this2.props.keyboard && e.keyCode === 27 && _this2.isTopModal()) {
-+ if (_this2.props.keyboard && (e.keyCode === 27 || e.key === 'Escape') && _this2.isTopModal()) {
- if (_this2.props.onEscapeKeyUp) {
- _this2.props.onEscapeKeyUp(e);
- }
-diff --git a/node_modules/react-overlays/lib/RootCloseWrapper.js b/node_modules/react-overlays/lib/RootCloseWrapper.js
-index 683e1cf..c561092 100644
---- a/node_modules/react-overlays/lib/RootCloseWrapper.js
-+++ b/node_modules/react-overlays/lib/RootCloseWrapper.js
-@@ -115,7 +115,7 @@ var RootCloseWrapper = function (_React$Component) {
- return;
- }
-
-- if (e.keyCode === escapeKeyCode && _this.props.onRootClose) {
-+ if ((e.keyCode === escapeKeyCode || e.key === 'Escape') && _this.props.onRootClose) {
- _this.props.onRootClose(e);
- }
- };
diff --git a/patches/react-overlays+5.2.1.patch b/patches/react-overlays+5.2.1.patch
new file mode 100644
index 0000000000..3789e904b2
--- /dev/null
+++ b/patches/react-overlays+5.2.1.patch
@@ -0,0 +1,52 @@
+diff --git a/node_modules/react-overlays/cjs/Modal.js b/node_modules/react-overlays/cjs/Modal.js
+index 2247ad0..71c9f4a 100644
+--- a/node_modules/react-overlays/cjs/Modal.js
++++ b/node_modules/react-overlays/cjs/Modal.js
+@@ -215,7 +215,7 @@ var Modal = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
+ }
+ });
+ var handleDocumentKeyDown = (0, _useEventCallback["default"])(function (e) {
+- if (keyboard && e.keyCode === 27 && modal.isTopModal()) {
++ if (keyboard && (e.keyCode === 27 || e.key === 'Escape') && modal.isTopModal()) {
+ onEscapeKeyDown == null ? void 0 : onEscapeKeyDown(e);
+
+ if (!e.defaultPrevented) {
+diff --git a/node_modules/react-overlays/cjs/useRootClose.js b/node_modules/react-overlays/cjs/useRootClose.js
+index 3fc40a7..cc16674 100644
+--- a/node_modules/react-overlays/cjs/useRootClose.js
++++ b/node_modules/react-overlays/cjs/useRootClose.js
+@@ -66,7 +66,7 @@ function useRootClose(ref, onRootClose, _temp) {
+ }
+ });
+ var handleKeyUp = (0, _useEventCallback["default"])(function (e) {
+- if (e.keyCode === escapeKeyCode) {
++ if (e.keyCode === escapeKeyCode || e.key === 'Escape') {
+ onClose(e);
+ }
+ });
+diff --git a/node_modules/react-overlays/esm/Modal.js b/node_modules/react-overlays/esm/Modal.js
+index 42f79e4..a12ebac 100644
+--- a/node_modules/react-overlays/esm/Modal.js
++++ b/node_modules/react-overlays/esm/Modal.js
+@@ -193,7 +193,7 @@ var Modal = /*#__PURE__*/forwardRef(function (_ref, ref) {
+ }
+ });
+ var handleDocumentKeyDown = useEventCallback(function (e) {
+- if (keyboard && e.keyCode === 27 && modal.isTopModal()) {
++ if (keyboard && (e.keyCode === 27 || e.key === 'Escape') && modal.isTopModal()) {
+ onEscapeKeyDown == null ? void 0 : onEscapeKeyDown(e);
+
+ if (!e.defaultPrevented) {
+diff --git a/node_modules/react-overlays/esm/useRootClose.js b/node_modules/react-overlays/esm/useRootClose.js
+index 8c7882c..30d0d56 100644
+--- a/node_modules/react-overlays/esm/useRootClose.js
++++ b/node_modules/react-overlays/esm/useRootClose.js
+@@ -53,7 +53,7 @@ function useRootClose(ref, onRootClose, _temp) {
+ }
+ });
+ var handleKeyUp = useEventCallback(function (e) {
+- if (e.keyCode === escapeKeyCode) {
++ if (e.keyCode === escapeKeyCode || e.key === 'Escape') {
+ onClose(e);
+ }
+ });
diff --git a/src/CarouselItem.js b/src/CarouselItem.js
index 4c7d0eeda1..e4a11abbf8 100644
--- a/src/CarouselItem.js
+++ b/src/CarouselItem.js
@@ -1,7 +1,6 @@
import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
import transition from 'dom-helpers/transition';
const propTypes = {
@@ -29,6 +28,7 @@ class CarouselItem extends React.Component {
direction: null
};
+ this.containerRef = React.createRef();
this.isUnmounted = false;
}
@@ -43,7 +43,7 @@ class CarouselItem extends React.Component {
const prevActive = prevProps.active;
if (!active && prevActive) {
- transition.end(ReactDOM.findDOMNode(this), this.handleAnimateOutEnd);
+ transition.end(this.containerRef.current, this.handleAnimateOutEnd);
}
if (active !== prevActive) {
@@ -99,7 +99,13 @@ class CarouselItem extends React.Component {
classes[this.state.direction] = true;
}
- return
;
+ return (
+
+ );
}
}
diff --git a/src/Collapse.js b/src/Collapse.js
index 6d181aeec0..3fe186808e 100644
--- a/src/Collapse.js
+++ b/src/Collapse.js
@@ -11,6 +11,8 @@ import Transition, {
import capitalize from './utils/capitalize';
import createChainedFunction from './utils/createChainedFunction';
+import { getElementRef, makeMergedRef } from './utils/mergeRefs';
+import withRef from './utils/withRef';
const MARGINS = {
height: ['marginTop', 'marginBottom'],
@@ -134,6 +136,12 @@ const defaultProps = {
};
class Collapse extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.childRef = React.createRef();
+ }
+
getDimension() {
return typeof this.props.dimension === 'function'
? this.props.dimension()
@@ -146,31 +154,34 @@ class Collapse extends React.Component {
}
/* -- Expanding -- */
- handleEnter = elem => {
- elem.style[this.getDimension()] = '0';
+ handleEnter = () => {
+ this.childRef.current.style[this.getDimension()] = '0';
};
- handleEntering = elem => {
+ handleEntering = () => {
const dimension = this.getDimension();
- elem.style[dimension] = this._getScrollDimensionValue(elem, dimension);
+ this.childRef.current.style[dimension] = this._getScrollDimensionValue(
+ this.childRef.current,
+ dimension
+ );
};
- handleEntered = elem => {
- elem.style[this.getDimension()] = null;
+ handleEntered = () => {
+ this.childRef.current.style[this.getDimension()] = null;
};
/* -- Collapsing -- */
- handleExit = elem => {
+ handleExit = () => {
const dimension = this.getDimension();
- elem.style[dimension] = `${this.props.getDimensionValue(
+ this.childRef.current.style[dimension] = `${this.props.getDimensionValue(
dimension,
- elem
+ this.childRef.current
)}px`;
- triggerBrowserReflow(elem);
+ triggerBrowserReflow(this.childRef.current);
};
- handleExiting = elem => {
- elem.style[this.getDimension()] = '0';
+ handleExiting = () => {
+ this.childRef.current.style[this.getDimension()] = '0';
};
render() {
@@ -188,19 +199,34 @@ class Collapse extends React.Component {
delete props.dimension;
delete props.getDimensionValue;
- const handleEnter = createChainedFunction(this.handleEnter, onEnter);
+ const handleEnter = createChainedFunction(
+ this.handleEnter,
+ withRef(onEnter, this.childRef)
+ );
const handleEntering = createChainedFunction(
this.handleEntering,
- onEntering
+ withRef(onEntering, this.childRef)
);
- const handleEntered = createChainedFunction(this.handleEntered, onEntered);
- const handleExit = createChainedFunction(this.handleExit, onExit);
- const handleExiting = createChainedFunction(this.handleExiting, onExiting);
+ const handleEntered = createChainedFunction(
+ this.handleEntered,
+ withRef(onEntered, this.childRef)
+ );
+ const handleExit = createChainedFunction(
+ this.handleExit,
+ withRef(onExit, this.childRef)
+ );
+ const handleExiting = createChainedFunction(
+ this.handleExiting,
+ withRef(onExiting, this.childRef)
+ );
+
+ const ref = makeMergedRef([this.childRef, getElementRef(children)]);
return (
React.cloneElement(children, {
...innerProps,
+ ref,
className: classNames(
className,
children.props.className,
diff --git a/src/Dropdown.js b/src/Dropdown.js
index 1fd68d3c4a..f5db1aaae2 100644
--- a/src/Dropdown.js
+++ b/src/Dropdown.js
@@ -3,7 +3,6 @@ import activeElement from 'dom-helpers/activeElement';
import contains from 'dom-helpers/query/contains';
import React, { cloneElement } from 'react';
import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
import all from 'prop-types-extra/lib/all';
import elementType from 'prop-types-extra/lib/elementType';
import isRequiredForA11y from 'prop-types-extra/lib/isRequiredForA11y';
@@ -16,6 +15,7 @@ import { bsClass as setBsClass, prefix } from './utils/bootstrapUtils';
import createChainedFunction from './utils/createChainedFunction';
import { exclusiveRoles, requiredRoles } from './utils/PropTypes';
import ValidComponentChildren from './utils/ValidComponentChildren';
+import { getElementRef, makeMergedRef } from './utils/mergeRefs';
const TOGGLE_ROLE = DropdownToggle.defaultProps.bsRole;
const MENU_ROLE = DropdownMenu.defaultProps.bsRole;
@@ -123,6 +123,7 @@ class Dropdown extends React.Component {
this.handleClose = this.handleClose.bind(this);
this._focusInDropdown = false;
+ this.containerRef = React.createRef();
this.lastOpenEventType = null;
}
@@ -133,7 +134,7 @@ class Dropdown extends React.Component {
UNSAFE_componentWillUpdate(nextProps) {
if (!nextProps.open && this.props.open) {
this._focusInDropdown = contains(
- ReactDOM.findDOMNode(this.menu),
+ this.containerRef.current.querySelector('[role=menu]'),
activeElement(document)
);
}
@@ -158,7 +159,9 @@ class Dropdown extends React.Component {
}
focus() {
- const toggle = ReactDOM.findDOMNode(this.toggle);
+ const toggle = this.containerRef.current.querySelector(
+ '[role=button][aria-haspopup]'
+ );
if (toggle && toggle.focus) {
toggle.focus();
@@ -237,11 +240,12 @@ class Dropdown extends React.Component {
}
renderMenu(child, { id, onSelect, rootCloseEvent, ...props }) {
- let ref = c => {
- this.menu = c;
- };
-
- ref = createChainedFunction(child.ref, ref);
+ const ref = makeMergedRef([
+ el => {
+ this.menu = el;
+ },
+ getElementRef(child)
+ ]);
return cloneElement(child, {
...props,
@@ -259,15 +263,8 @@ class Dropdown extends React.Component {
}
renderToggle(child, props) {
- let ref = c => {
- this.toggle = c;
- };
-
- ref = createChainedFunction(child.ref, ref);
-
return cloneElement(child, {
...props,
- ref,
bsClass: prefix(props, 'toggle'),
onClick: createChainedFunction(child.props.onClick, this.handleClick),
onKeyDown: createChainedFunction(
@@ -311,31 +308,33 @@ class Dropdown extends React.Component {
// underlying component, to allow it to render size and style variants.
return (
-
- {ValidComponentChildren.map(children, child => {
- switch (child.props.bsRole) {
- case TOGGLE_ROLE:
- return this.renderToggle(child, {
- id,
- disabled,
- open,
- role,
- bsClass
- });
- case MENU_ROLE:
- return this.renderMenu(child, {
- id,
- open,
- pullRight,
- bsClass,
- onSelect,
- rootCloseEvent
- });
- default:
- return child;
- }
- })}
-
+
+
+ {ValidComponentChildren.map(children, child => {
+ switch (child.props.bsRole) {
+ case TOGGLE_ROLE:
+ return this.renderToggle(child, {
+ id,
+ disabled,
+ open,
+ role,
+ bsClass
+ });
+ case MENU_ROLE:
+ return this.renderMenu(child, {
+ id,
+ open,
+ pullRight,
+ bsClass,
+ onSelect,
+ rootCloseEvent
+ });
+ default:
+ return child;
+ }
+ })}
+
+
);
}
}
diff --git a/src/DropdownMenu.js b/src/DropdownMenu.js
index 8d4d9fad87..7beaeba0c6 100644
--- a/src/DropdownMenu.js
+++ b/src/DropdownMenu.js
@@ -1,8 +1,7 @@
import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
-import RootCloseWrapper from 'react-overlays/lib/RootCloseWrapper';
+import { useRootClose } from 'react-overlays';
import {
bsClass,
@@ -33,10 +32,12 @@ class DropdownMenu extends React.Component {
this.handleRootClose = this.handleRootClose.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
+
+ this.menuRef = React.createRef();
}
getFocusableMenuItems() {
- const node = ReactDOM.findDOMNode(this);
+ const node = this.menuRef.current;
if (!node) {
return [];
}
@@ -117,8 +118,10 @@ class DropdownMenu extends React.Component {
disabled={!open}
onRootClose={this.handleRootClose}
event={rootCloseEvent}
+ menuRef={this.menuRef}
>
{
+ const childRef = useRef(null);
+
+ const setChildRef = useMergedRef([childRef, getElementRef(children), ref]);
+
+ // Transition doesn't pass the node as the first parameter of these callbacks when nodeRef is used,
+ // so we add that ourselves to keep the API for Fade consistent
+ const callbacks = {
+ onEnter: useMemo(() => withRef(onEnter, childRef), [onEnter]),
+ onEntering: useMemo(() => withRef(onEntering, childRef), [onEntering]),
+ onEntered: useMemo(() => withRef(onEntered, childRef), [onEntered]),
+ onExit: useMemo(() => withRef(onExit, childRef), [onExit]),
+ onExiting: useMemo(() => withRef(onExiting, childRef), [onExiting]),
+ onExited: useMemo(() => withRef(onExited, childRef), [onExited])
+ };
return (
-
+
{(status, innerProps) =>
React.cloneElement(children, {
...innerProps,
+ ref: setChildRef,
className: classNames(
'fade',
className,
@@ -94,9 +129,9 @@ class Fade extends React.Component {
);
}
-}
+);
+Fade.displayName = 'Fade';
Fade.propTypes = propTypes;
-Fade.defaultProps = defaultProps;
export default Fade;
diff --git a/src/Modal.js b/src/Modal.js
index c643d6dc25..943cac0bb4 100644
--- a/src/Modal.js
+++ b/src/Modal.js
@@ -5,10 +5,8 @@ import canUseDOM from 'dom-helpers/util/inDOM';
import getScrollbarSize from 'dom-helpers/util/scrollbarSize';
import React from 'react';
import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
-import BaseModal from 'react-overlays/lib/Modal';
-import isOverflowing from 'react-overlays/lib/utils/isOverflowing';
-import elementType from 'prop-types-extra/lib/elementType';
+import isOverflowing from 'react-overlays/isOverflowing';
+import BaseModal from 'react-overlays/Modal';
import Fade from './Fade';
import Body from './ModalBody';
@@ -38,6 +36,11 @@ const propTypes = {
*/
backdropClassName: PropTypes.string,
+ /**
+ * Add optional styles to .modal-backdrop
+ */
+ backdropStyle: PropTypes.object,
+
/**
* Close the modal when escape key is pressed
*/
@@ -48,13 +51,6 @@ const propTypes = {
*/
animation: PropTypes.bool,
- /**
- * A Component type that provides the modal content Markup. This is a useful
- * prop when you want to use your own styles and markup to create a custom
- * modal component.
- */
- dialogComponentClass: elementType,
-
/**
* When `true` The modal will automatically shift focus to itself when it
* opens, and replace it to the last focused element when it closes.
@@ -115,28 +111,33 @@ const propTypes = {
/**
* Callback fired after the Modal finishes transitioning out
*/
- onExited: PropTypes.func,
-
- /**
- * @private
- */
- container: BaseModal.propTypes.container
+ onExited: PropTypes.func
};
const defaultProps = {
- ...BaseModal.defaultProps,
- animation: true,
- dialogComponentClass: ModalDialog
+ show: false,
+ backdrop: true,
+ keyboard: true,
+ autoFocus: true,
+ enforceFocus: true,
+ restoreFocus: true,
+ onHide: function onHide() {},
+ renderBackdrop: function renderBackdrop(props) {
+ return ;
+ },
+ animation: true
};
/* eslint-disable no-use-before-define, react/no-multi-comp */
-function DialogTransition(props) {
- return ;
-}
+const DialogTransition = React.forwardRef((props, ref) => (
+
+));
+DialogTransition.displayName = 'DialogTransition';
-function BackdropTransition(props) {
- return ;
-}
+const BackdropTransition = React.forwardRef((props, ref) => (
+
+));
+BackdropTransition.displayName = 'BackdropTransition';
/* eslint-enable no-use-before-define */
@@ -200,13 +201,11 @@ class Modal extends React.Component {
return;
}
- const dialogNode = this._modal.getDialogElement();
+ const dialogNode = this._modal.dialog;
const dialogHeight = dialogNode.scrollHeight;
const document = ownerDocument(dialogNode);
- const bodyIsOverflowing = isOverflowing(
- ReactDOM.findDOMNode(this.props.container || document.body)
- );
+ const bodyIsOverflowing = isOverflowing(document.body);
const modalIsOverflowing =
dialogHeight > document.documentElement.clientHeight;
@@ -228,9 +227,9 @@ class Modal extends React.Component {
const {
backdrop,
backdropClassName,
+ backdropStyle,
animation,
show,
- dialogComponentClass: Dialog,
className,
style,
children, // Just in case this get added to BaseModal propTypes.
@@ -253,24 +252,39 @@ class Modal extends React.Component {
transition={animation ? DialogTransition : undefined}
backdrop={backdrop}
backdropTransition={animation ? BackdropTransition : undefined}
- backdropClassName={classNames(
- prefix(props, 'backdrop'),
- backdropClassName,
- inClassName
+ renderBackdrop={backdropProps => (
+
+ )}
+ renderDialog={renderProps => (
+
+ {children}
+
)}
onEntering={createChainedFunction(onEntering, this.handleEntering)}
onExited={createChainedFunction(onExited, this.handleExited)}
- >
-
-
+ />
);
}
diff --git a/src/ModalDialog.js b/src/ModalDialog.js
index 34b0b5a5a3..c8306ebe16 100644
--- a/src/ModalDialog.js
+++ b/src/ModalDialog.js
@@ -2,15 +2,11 @@ import classNames from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';
-import {
- bsClass,
- bsSizes,
- getClassSet,
- prefix,
- splitBsProps
-} from './utils/bootstrapUtils';
+import { getClassSet, prefix, splitBsProps } from './utils/bootstrapUtils';
import { Size } from './utils/StyleConfig';
+const SIZES = [Size.LARGE, Size.SMALL];
+
const propTypes = {
/**
* A css class to apply to the Modal dialog DOM node.
@@ -20,20 +16,31 @@ const propTypes = {
/**
* A method to run for the mousedown event on the dialog.
*/
- handleDialogMouseDown: PropTypes.func
+ handleDialogMouseDown: PropTypes.func,
+
+ bsClass: PropTypes.string,
+ bsSize: PropTypes.oneOf(SIZES)
};
-class ModalDialog extends React.Component {
- render() {
- const {
+const ModalDialog = React.forwardRef(
+ (
+ {
dialogClassName,
className,
style,
children,
handleDialogMouseDown,
+ bsClass = 'modal',
+ bsSize,
...props
- } = this.props;
- const [bsProps, elementProps] = splitBsProps(props);
+ },
+ ref
+ ) => {
+ const [bsProps, elementProps] = splitBsProps({
+ ...props,
+ bsClass,
+ bsSize
+ });
const bsClassName = prefix(bsProps);
@@ -47,6 +54,7 @@ class ModalDialog extends React.Component {
return (
);
}
-}
+);
+ModalDialog.displayName = 'ModalDialog';
ModalDialog.propTypes = propTypes;
+ModalDialog.SIZES = SIZES;
-export default bsClass('modal', bsSizes([Size.LARGE, Size.SMALL], ModalDialog));
+export default ModalDialog;
diff --git a/src/Nav.js b/src/Nav.js
index 9b20a2476e..439a4172c6 100644
--- a/src/Nav.js
+++ b/src/Nav.js
@@ -1,7 +1,6 @@
import classNames from 'classnames';
import React, { cloneElement, useContext } from 'react';
import PropTypes from 'prop-types';
-import ReactDOM from 'react-dom';
import all from 'prop-types-extra/lib/all';
import warning from 'warning';
@@ -98,6 +97,12 @@ const defaultProps = {
};
class Nav extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.containerRef = React.createRef();
+ }
+
componentDidUpdate() {
if (!this._needsRefocus) {
return;
@@ -115,7 +120,7 @@ class Nav extends React.Component {
const childrenArray = ValidComponentChildren.toArray(children);
const activeChildIndex = childrenArray.indexOf(activeChild);
- const childNodes = ReactDOM.findDOMNode(this).children;
+ const childNodes = this.containerRef.current.children;
const activeNode = childNodes && childNodes[activeChildIndex];
if (!activeNode || !activeNode.firstChild) {
@@ -309,6 +314,7 @@ class Nav extends React.Component {
return (
- {child}
+
+ {({ arrowProps, placement, props: overlayProps }) => {
+ const positionTop =
+ overlayProps && overlayProps.style && overlayProps.style.top;
+ const positionLeft =
+ overlayProps && overlayProps.style && overlayProps.style.left;
+
+ // Passing the positionX and arrowOffsetX props is redundant with the style props,
+ // but it matches how react-overlays used to behave.
+ return React.cloneElement(child, {
+ ...overlayProps,
+ placement,
+ positionTop,
+ positionLeft,
+ arrowOffsetTop:
+ arrowProps && arrowProps.style && arrowProps.style.top,
+ arrowOffsetLeft:
+ arrowProps && arrowProps.style && arrowProps.style.left,
+ arrowRef: arrowProps.ref,
+ arrowStyle: arrowProps.style,
+ style: {
+ ...child.props.style,
+ ...overlayProps.style,
+ left: positionLeft,
+ top: positionTop
+ }
+ });
+ }}
);
}
diff --git a/src/OverlayTrigger.js b/src/OverlayTrigger.js
index 3adda67446..ba40324d0c 100644
--- a/src/OverlayTrigger.js
+++ b/src/OverlayTrigger.js
@@ -115,6 +115,8 @@ class OverlayTrigger extends React.Component {
this.state = {
show: props.defaultOverlayShown
};
+
+ this.triggerRef = React.createRef();
}
componentWillUnmount() {
@@ -207,7 +209,7 @@ class OverlayTrigger extends React.Component {
{...props}
show={this.state.show}
onHide={this.handleHide}
- target={this}
+ target={this.triggerRef}
>
{overlay}
@@ -292,7 +294,9 @@ class OverlayTrigger extends React.Component {
return (
<>
- {cloneElement(child, triggerProps)}
+
+ {cloneElement(child, triggerProps)}
+
{ReactDOM.createPortal(this.makeOverlay(overlay, props), document.body)}
>
);
diff --git a/src/Popover.js b/src/Popover.js
index 8b78ceef3c..b69772ccd8 100644
--- a/src/Popover.js
+++ b/src/Popover.js
@@ -49,25 +49,24 @@ const propTypes = {
title: PropTypes.node
};
-const defaultProps = {
- placement: 'right'
-};
-
-class Popover extends React.Component {
- render() {
- const {
- placement,
+const Popover = React.forwardRef(
+ (
+ {
+ placement = 'right',
positionTop,
positionLeft,
arrowOffsetTop,
arrowOffsetLeft,
+ arrowRef,
+ arrowStyle,
title,
className,
style,
children,
...props
- } = this.props;
-
+ },
+ ref
+ ) => {
const [bsProps, elementProps] = splitBsProps(props);
const classes = {
@@ -82,19 +81,21 @@ class Popover extends React.Component {
...style
};
- const arrowStyle = {
+ const combinedArrowStyle = {
top: arrowOffsetTop,
- left: arrowOffsetLeft
+ left: arrowOffsetLeft,
+ ...arrowStyle
};
return (
-
+
{title &&
{title}
}
@@ -102,9 +103,8 @@ class Popover extends React.Component {
);
}
-}
+);
Popover.propTypes = propTypes;
-Popover.defaultProps = defaultProps;
export default bsClass('popover', Popover);
diff --git a/src/TabPane.js b/src/TabPane.js
index 08895bdb2b..14334790cf 100644
--- a/src/TabPane.js
+++ b/src/TabPane.js
@@ -91,6 +91,8 @@ class TabPane extends React.Component {
this.handleExited = this.handleExited.bind(this);
this.in = false;
+
+ this.paneRef = React.createRef();
}
componentDidMount() {
@@ -220,6 +222,7 @@ class TabPane extends React.Component {
const pane = (
{pane}
diff --git a/src/Tooltip.js b/src/Tooltip.js
index 5a9a7cdaa4..aa07909d9f 100644
--- a/src/Tooltip.js
+++ b/src/Tooltip.js
@@ -44,24 +44,23 @@ const propTypes = {
arrowOffsetLeft: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
};
-const defaultProps = {
- placement: 'right'
-};
-
-class Tooltip extends React.Component {
- render() {
- const {
- placement,
+const Tooltip = React.forwardRef(
+ (
+ {
+ placement = 'right',
positionTop,
positionLeft,
arrowOffsetTop,
arrowOffsetLeft,
+ arrowRef,
+ arrowStyle,
className,
style,
children,
...props
- } = this.props;
-
+ },
+ ref
+ ) => {
const [bsProps, elementProps] = splitBsProps(props);
const classes = {
@@ -75,27 +74,32 @@ class Tooltip extends React.Component {
...style
};
- const arrowStyle = {
+ const combinedArrowStyle = {
top: arrowOffsetTop,
- left: arrowOffsetLeft
+ left: arrowOffsetLeft,
+ ...arrowStyle
};
return (
);
}
-}
-
+);
+Tooltip.displayName = 'Tooltip';
Tooltip.propTypes = propTypes;
-Tooltip.defaultProps = defaultProps;
export default bsClass('tooltip', Tooltip);
diff --git a/src/utils/bootstrapUtils.js b/src/utils/bootstrapUtils.js
index 5735d17a21..da59292407 100644
--- a/src/utils/bootstrapUtils.js
+++ b/src/utils/bootstrapUtils.js
@@ -1,6 +1,7 @@
// TODO: The publicly exposed parts of this should be in lib/BootstrapUtils.
import invariant from 'invariant';
+import { isValidElementType } from 'react-is';
import PropTypes from 'prop-types';
import { SIZE_MAP } from './StyleConfig';
@@ -8,9 +9,12 @@ import { SIZE_MAP } from './StyleConfig';
function curry(fn) {
return (...args) => {
let last = args[args.length - 1];
- if (typeof last === 'function') {
+ if (typeof last !== 'string' && isValidElementType(last)) {
+ // Supports calling curry(...args, Component)
return fn(...args);
}
+
+ // Supports calling curry(...args)(Component)
return Component => fn(...args, Component);
};
}
diff --git a/src/utils/mergeRefs.js b/src/utils/mergeRefs.js
new file mode 100644
index 0000000000..0497882706
--- /dev/null
+++ b/src/utils/mergeRefs.js
@@ -0,0 +1,41 @@
+import React, { useCallback } from 'react';
+
+const hasRefProp = parseInt(React.version, 10) >= 19;
+
+/**
+ * Given any number of React ref callbacks or ref objects, returns a new ref callback
+ * that sets all of the provided refs. This result isn't memoized, so useMergedRef
+ * should be preferred.
+ */
+export function makeMergedRef(refs) {
+ return el => {
+ refs.forEach(ref => {
+ if (typeof ref === 'function') {
+ ref(el);
+ } else if (ref != null) {
+ ref.current = el;
+ }
+ });
+ };
+}
+
+/**
+ * Given any number of React ref callbacks or ref objects, returns a new ref callback
+ * that sets all of the provided refs.
+ */
+export function useMergedRef(refs) {
+ return useCallback(makeMergedRef(refs), refs);
+}
+
+/**
+ * Given a React element, returns the ref of that object in a way that's compatible
+ * with different React versions.
+ */
+export function getElementRef(reactElement) {
+ if (!reactElement) {
+ return null;
+ }
+
+ // Accessing reactElement.ref prints a warning in React 19 and will likely be removed eventually
+ return hasRefProp ? reactElement.props.ref : reactElement.ref;
+}
diff --git a/src/utils/withRef.js b/src/utils/withRef.js
new file mode 100644
index 0000000000..2871a09b54
--- /dev/null
+++ b/src/utils/withRef.js
@@ -0,0 +1,6 @@
+/**
+ * Given a function, returns that function with the first parameter set to the referenced element.
+ */
+export default function withRef(callback, ref) {
+ return callback ? (...args) => callback(ref.current, ...args) : undefined;
+}
diff --git a/test/DropdownSpec.js b/test/DropdownSpec.js
index 314e937bdc..cc05ffaa74 100644
--- a/test/DropdownSpec.js
+++ b/test/DropdownSpec.js
@@ -408,7 +408,6 @@ describe('
', () => {
outerRef.dropdown.menu.should.exist;
outerRef.toggle.should.exist;
- outerRef.dropdown.toggle.should.exist;
});
describe('focusable state', () => {
diff --git a/test/FadeSpec.js b/test/FadeSpec.js
index 8f7e1f87da..6a50c9d74b 100644
--- a/test/FadeSpec.js
+++ b/test/FadeSpec.js
@@ -21,21 +21,22 @@ describe('Fade', () => {
});
it('Should default to hidden', () => {
- let instance;
- render(
- (instance = element)}>Panel content
- );
+ render(Panel content);
- assert.ok(instance.fade.props.in === false);
+ assert.equal(screen.getByText('Panel content').className, 'fade');
});
- it('Should always have the "fade" class', () => {
+ it('Should forward its ref to the child element', () => {
let instance;
render(
(instance = element)}>Panel content
);
- assert.ok(instance.fade.props.in === false);
+ assert.equal(instance.fade, screen.getByText('Panel content'));
+ });
+
+ it('Should always have the "fade" class', () => {
+ render(Panel content);
assert.equal(screen.getByText('Panel content').className, 'fade');
});
@@ -51,7 +52,7 @@ describe('Fade', () => {
done();
}
- assert.ok(instance.fade.props.in === false);
+ assert.equal(screen.getByText('Panel content').className, 'fade');
act(() => {
instance.setState({ in: true, onEntering });
diff --git a/test/ModalSpec.js b/test/ModalSpec.js
index ba3948f4c3..d004a798e0 100644
--- a/test/ModalSpec.js
+++ b/test/ModalSpec.js
@@ -20,7 +20,7 @@ describe('', () => {
);
- assert.ok(instance._modal.getDialogElement().querySelector('strong'));
+ assert.ok(instance._modal.dialog.querySelector('strong'));
});
it('Should close the modal when the modal dialog is clicked', done => {
@@ -35,7 +35,7 @@ describe('', () => {
);
- const dialog = instance._modal.getDialogElement();
+ const dialog = instance._modal.dialog;
userEvent.click(dialog);
});
@@ -54,7 +54,7 @@ describe('', () => {
);
- const dialog = instance._modal.getDialogElement();
+ const dialog = instance._modal.dialog;
userEvent.click(dialog);
@@ -74,15 +74,13 @@ describe('', () => {
);
- const button = instance._modal
- .getDialogElement()
- .getElementsByClassName('close')[0];
+ const button = instance._modal.dialog.getElementsByClassName('close')[0];
userEvent.click(button);
});
it('Should close the modal when the escape key is pressed with keyboard=true', async () => {
- const handleHide = sinon.spy();
+ const handleHide = sinon.spy(() => {});
render(
@@ -125,7 +123,7 @@ describe('', () => {
);
- const dialog = instance._modal.getDialogElement();
+ const dialog = instance._modal.dialog;
assert.ok(dialog.className.match(/\bmymodal\b/));
});
@@ -144,7 +142,7 @@ describe('', () => {
);
- const modal = instance._modal.getDialogElement();
+ const modal = instance._modal.dialog;
assert.ok(modal.className.match(/\bmymodal\b/));
assert.ok(modal.children[0].className.match(/\bmymodal-dialog\b/));
@@ -180,9 +178,9 @@ describe('', () => {
);
- const dialog = instance._modal
- .getDialogElement()
- .getElementsByClassName('modal-dialog')[0];
+ const dialog = instance._modal.dialog.getElementsByClassName(
+ 'modal-dialog'
+ )[0];
assert.ok(dialog.className.match(/\bmodal-sm\b/));
});
@@ -201,7 +199,7 @@ describe('', () => {
);
- const dialog = instance._modal.getDialogElement();
+ const dialog = instance._modal.dialog;
assert.ok(dialog.style.top === '1000px');
});
@@ -220,35 +218,11 @@ describe('', () => {
);
- const dialog = instance._modal
- .getDialogElement()
- .querySelector('.modal-dialog');
+ const dialog = instance._modal.dialog.querySelector('.modal-dialog');
assert.ok(dialog.className.match(/\btestCss\b/));
});
- it('Should use dialogComponentClass', () => {
- const noOp = () => {};
-
- function CustomDialog() {
- return ;
- }
-
- let instance;
- render(
- (instance = element)}
- show
- dialogComponentClass={CustomDialog}
- onHide={noOp}
- >
- Message
-
- );
-
- assert.equal(instance._modal.getDialogElement().className, 'custom-dialog');
- });
-
it('Should pass transition callbacks to Transition', done => {
let count = 0;
const increment = () => {
diff --git a/test/OverlayTriggerSpec.js b/test/OverlayTriggerSpec.js
index 3ae8166cbc..23c8232114 100644
--- a/test/OverlayTriggerSpec.js
+++ b/test/OverlayTriggerSpec.js
@@ -1,7 +1,6 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import PropTypes from 'prop-types';
-import React from 'react';
+import React, { useContext, useEffect } from 'react';
import OverlayTrigger from '../src/OverlayTrigger';
import Popover from '../src/Popover';
@@ -9,9 +8,11 @@ import Tooltip from '../src/Tooltip';
describe('', () => {
// Swallow extra props.
- const Div = ({ className, children }) => (
- {children}
- );
+ const Div = React.forwardRef(({ className, children }, ref) => (
+
+ {children}
+
+ ));
it('Should create OverlayTrigger element', () => {
render(
@@ -140,31 +141,36 @@ describe('', () => {
});
it('Should forward requested context', async () => {
- const contextTypes = {
- key: PropTypes.string
- };
+ const TestContext = React.createContext(undefined);
+ TestContext.displayName = 'TestContext';
const contextSpy = sinon.spy();
- class ContextReader extends React.Component {
- render() {
- contextSpy(this.context.key);
- return ;
- }
- }
+ const ContextReader = React.forwardRef((props, ref) => {
+ const context = useContext(TestContext);
+ const contextValue = context.key;
+ useEffect(
+ () => {
+ contextSpy(contextValue);
+ },
+ [contextValue]
+ );
- ContextReader.contextTypes = contextTypes;
+ return ;
+ });
+ ContextReader.displayName = 'ContextReader';
class ContextHolder extends React.Component {
render() {
return (
- }>
-
-
+
+ }>
+
+
+
);
}
}
- ContextHolder.childContextTypes = contextTypes;
render();
const overlayTrigger = screen.getByText('button');
@@ -290,7 +296,7 @@ describe('', () => {
}
return (
-
+
original
@@ -299,9 +305,13 @@ describe('
', () => {
}
}
+ const WrappedReplacedOverlay = React.forwardRef((props, ref) => (
+
+ ));
+
render(
}
+ overlay={}
trigger="click"
rootClose
>
diff --git a/test/index.js b/test/index.js
index adaa3351d2..3b8d18f81c 100644
--- a/test/index.js
+++ b/test/index.js
@@ -26,11 +26,6 @@ beforeEach(() => {
return;
}
- if (msg.includes('findDOMNode')) {
- // @hmhealey This is removed in React 19
- return;
- }
-
console.error.threw = true;
throw new Error(msg);
});
diff --git a/yarn.lock b/yarn.lock
index 80ea5abf38..3f1524ae8b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -796,18 +796,16 @@
core-js "^2.5.7"
regenerator-runtime "^0.12.0"
-"@babel/runtime@^7.1.2":
- version "7.18.9"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
- integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
- dependencies:
- regenerator-runtime "^0.13.4"
-
"@babel/runtime@^7.12.5":
version "7.28.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473"
integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==
+"@babel/runtime@^7.13.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.8.7":
+ version "7.29.7"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768"
+ integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==
+
"@babel/template@7.0.0-beta.51":
version "7.0.0-beta.51"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.51.tgz#9602a40aebcf357ae9677e2532ef5fc810f5fbff"
@@ -944,6 +942,18 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
+"@popperjs/core@^2.11.6":
+ version "2.11.8"
+ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
+ integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
+
+"@restart/hooks@^0.4.7":
+ version "0.4.16"
+ resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.4.16.tgz#95ae8ac1cc7e2bd4fed5e39800ff85604c6d59fb"
+ integrity sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==
+ dependencies:
+ dequal "^2.0.3"
+
"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
@@ -1030,6 +1040,18 @@
dependencies:
undici-types "~7.10.0"
+"@types/react@>=16.9.11":
+ version "19.2.17"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.17.tgz#dccac365baa0f1734ec270ff4b51c89465e8dc7f"
+ integrity sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==
+ dependencies:
+ csstype "^3.2.2"
+
+"@types/warning@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.4.tgz#ebc0c83180dc83994d902bbd51ab0af8a445b1f9"
+ integrity sha512-CqN8MnISMwQbLJXO3doBAV4Yw9hx9/Pyr2rZ78+NfaCnhyRA/nKrpyk6E7mKw17ZOaQdLpK9GiUjrqLzBlN3sg==
+
"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
version "1.14.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6"
@@ -2180,6 +2202,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
+csstype@^3.0.2, csstype@^3.2.2:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a"
+ integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==
+
custom-event@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425"
@@ -2373,16 +2400,17 @@ dom-accessibility-api@^0.5.9:
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453"
integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
-dom-helpers@^3.2.0, dom-helpers@^3.2.1, dom-helpers@^3.3.1:
+dom-helpers@^3.2.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
-dom-helpers@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
- integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
+dom-helpers@^5.0.1, dom-helpers@^5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
+ integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
- "@babel/runtime" "^7.1.2"
+ "@babel/runtime" "^7.8.7"
+ csstype "^3.0.2"
dom-serialize@^2.2.1:
version "2.2.1"
@@ -5191,13 +5219,22 @@ prop-types-extra@^1.0.1:
react-is "^16.3.2"
warning "^3.0.0"
-prop-types@^15.5.10, prop-types@^15.6.1, prop-types@^15.6.2:
+prop-types@^15.6.1, prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
dependencies:
loose-envify "^1.3.1"
object-assign "^4.1.1"
+prop-types@^15.7.2:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
@@ -5316,6 +5353,11 @@ react-dom@^18.3.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
+react-is@^16.13.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
react-is@^16.3.2:
version "16.4.2"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.2.tgz#84891b56c2b6d9efdee577cc83501dfc5ecead88"
@@ -5329,17 +5371,19 @@ react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
-react-overlays@^0.9.3:
- version "0.9.3"
- resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.9.3.tgz#5bac8c1e9e7e057a125181dee2d784864dd62902"
- integrity sha512-u2T7nOLnK+Hrntho4p0Nxh+BsJl0bl4Xuwj/Y0a56xywLMetgAfyjnDVrudLXsNcKGaspoC+t3C1V80W9QQTdQ==
- dependencies:
- classnames "^2.2.5"
- dom-helpers "^3.2.1"
- prop-types "^15.5.10"
- prop-types-extra "^1.0.1"
- react-transition-group "^2.2.1"
- warning "^3.0.0"
+react-overlays@^5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-5.2.1.tgz#49dc007321adb6784e1f212403f0fb37a74ab86b"
+ integrity sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==
+ dependencies:
+ "@babel/runtime" "^7.13.8"
+ "@popperjs/core" "^2.11.6"
+ "@restart/hooks" "^0.4.7"
+ "@types/warning" "^3.0.0"
+ dom-helpers "^5.2.0"
+ prop-types "^15.7.2"
+ uncontrollable "^7.2.1"
+ warning "^4.0.3"
react-prop-types@^0.4.0:
version "0.4.0"
@@ -5364,24 +5408,15 @@ react-test-renderer@^18.3.1:
react-shallow-renderer "^16.15.0"
scheduler "^0.23.2"
-react-transition-group@^2.0.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.4.0.tgz#1d9391fabfd82e016f26fabd1eec329dbd922b5a"
+react-transition-group@^4.4.0:
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
+ integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
dependencies:
- dom-helpers "^3.3.1"
- loose-envify "^1.3.1"
- prop-types "^15.6.2"
- react-lifecycles-compat "^3.0.4"
-
-react-transition-group@^2.2.1:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
- integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
- dependencies:
- dom-helpers "^3.4.0"
+ "@babel/runtime" "^7.5.5"
+ dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
- react-lifecycles-compat "^3.0.4"
react@^18.3.1:
version "18.3.1"
@@ -5462,11 +5497,6 @@ regenerator-runtime@^0.12.0:
version "0.12.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
-regenerator-runtime@^0.13.4:
- version "0.13.9"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
- integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
-
regenerator-transform@^0.13.3:
version "0.13.3"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb"
@@ -6402,6 +6432,16 @@ uncontrollable@^5.0.0:
dependencies:
invariant "^2.2.4"
+uncontrollable@^7.2.1:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738"
+ integrity sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==
+ dependencies:
+ "@babel/runtime" "^7.6.3"
+ "@types/react" ">=16.9.11"
+ invariant "^2.2.4"
+ react-lifecycles-compat "^3.0.4"
+
undici-types@~7.10.0:
version "7.10.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350"
@@ -6553,6 +6593,13 @@ warning@^3.0.0:
dependencies:
loose-envify "^1.0.0"
+warning@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
+ integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
+ dependencies:
+ loose-envify "^1.0.0"
+
watchpack@^2.4.1:
version "2.4.4"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.4.tgz#473bda72f0850453da6425081ea46fc0d7602947"