diff --git a/package.json b/package.json
index 5f4f4e377..3d361a492 100644
--- a/package.json
+++ b/package.json
@@ -117,7 +117,7 @@
"moment": "^2.29.4",
"moment-timezone": "^0.5.34",
"prop-types": "^15.8.1",
- "react-overlays": "^4.1.1",
+ "react-overlays": "^5.2.0",
"uncontrollable": "^7.2.1"
},
"bugs": {
diff --git a/src/Month.js b/src/Month.js
index 2bf573da9..997f48fd8 100644
--- a/src/Month.js
+++ b/src/Month.js
@@ -9,8 +9,9 @@ import { notify } from './utils/helpers'
import getPosition from 'dom-helpers/position'
import * as animationFrame from 'dom-helpers/animationFrame'
-import Popup from './Popup'
-import Overlay from 'react-overlays/Overlay'
+/* import Popup from './Popup'
+import Overlay from 'react-overlays/Overlay' */
+import PopOverlay from './PopOverlay'
import DateContentRow from './DateContentRow'
import Header from './Header'
import DateHeader from './DateHeader'
@@ -204,11 +205,40 @@ class MonthView extends React.Component {
}
renderOverlay() {
- let overlay = (this.state && this.state.overlay) || {}
- let { accessors, localizer, components, getters, selected, popupOffset } =
- this.props
+ let overlay = this.state?.overlay ?? {}
+ let {
+ accessors,
+ localizer,
+ components,
+ getters,
+ selected,
+ popupOffset,
+ handleDragStart,
+ } = this.props
+
+ const onHide = () => this.setState({ overlay: null })
return (
+
+ )
+
+ /* return (
)}
- )
+ ) */
}
measureRowLimit() {
diff --git a/src/PopOverlay.js b/src/PopOverlay.js
new file mode 100644
index 000000000..3499bec62
--- /dev/null
+++ b/src/PopOverlay.js
@@ -0,0 +1,95 @@
+import React, { useRef } from 'react'
+import PropTypes from 'prop-types'
+import { Overlay } from 'react-overlays'
+import Popup from './Popup'
+
+function CalOverlay({
+ containerRef,
+ popupOffset = 5,
+ overlay,
+ accessors,
+ localizer,
+ components,
+ getters,
+ selected,
+ handleSelectEvent,
+ handleDoubleClickEvent,
+ handleKeyPressEvent,
+ handleDragStart,
+ onHide,
+ overlayDisplay,
+}) {
+ const popperRef = useRef(null)
+ if (!overlay.position) return null
+
+ let offset
+ if (!isNaN(popupOffset)) {
+ offset = { x: popupOffset, y: popupOffset }
+ }
+
+ const { position, events, date, end } = overlay
+ return (
+
+ {({ props }) => (
+
+ )}
+
+ )
+}
+
+const PopOverlay = React.forwardRef((props, ref) => (
+
+))
+
+PopOverlay.propTypes = {
+ popupOffset: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
+ ]),
+ overlay: PropTypes.shape({
+ position: PropTypes.object,
+ events: PropTypes.array,
+ date: PropTypes.instanceOf(Date),
+ end: PropTypes.instanceOf(Date),
+ }),
+ accessors: PropTypes.object.isRequired,
+ localizer: PropTypes.object.isRequired,
+ components: PropTypes.object.isRequired,
+ getters: PropTypes.object.isRequired,
+ selected: PropTypes.object,
+ handleSelectEvent: PropTypes.func,
+ handleDoubleClickEvent: PropTypes.func,
+ handleKeyPressEvent: PropTypes.func,
+ handleDragStart: PropTypes.func,
+ onHide: PropTypes.func,
+ overlayDisplay: PropTypes.func,
+}
+
+export default PopOverlay
diff --git a/src/Popup.js b/src/Popup.js
index a19fb3cf7..5d14d31f2 100644
--- a/src/Popup.js
+++ b/src/Popup.js
@@ -1,136 +1,125 @@
+import React, { useLayoutEffect } from 'react'
import PropTypes from 'prop-types'
-import React from 'react'
import getOffset from 'dom-helpers/offset'
-import getScrollTop from 'dom-helpers/scrollTop'
-import getScrollLeft from 'dom-helpers/scrollLeft'
+import useClickOutside from './hooks/useClickOutside'
import EventCell from './EventCell'
import { isSelected } from './utils/selection'
-class Popup extends React.Component {
- componentDidMount() {
- let { popupOffset = 5, popperRef } = this.props,
- { top, left, width, height } = getOffset(popperRef.current),
- viewBottom = window.innerHeight + getScrollTop(window),
- viewRight = window.innerWidth + getScrollLeft(window),
- bottom = top + height,
- right = left + width
-
- if (bottom > viewBottom || right > viewRight) {
- let topOffset, leftOffset
-
- if (bottom > viewBottom)
- topOffset = bottom - viewBottom + (popupOffset.y || +popupOffset || 0)
- if (right > viewRight)
- leftOffset = right - viewRight + (popupOffset.x || +popupOffset || 0)
+/**
+ * Changes to react-overlays cause issue with auto positioning,
+ * so we need to manually calculate the position of the popper,
+ * and constrain it to the Month container.
+ */
+function getPosition({ target, offset, container, box }) {
+ const { top, left, width, height } = getOffset(target)
+ const {
+ top: cTop,
+ left: cLeft,
+ width: cWidth,
+ height: cHeight,
+ } = getOffset(container)
+ const { width: bWidth, height: bHeight } = getOffset(box)
+ const viewBottom = cTop + cHeight
+ const viewRight = cLeft + cWidth
+ const bottom = top + bHeight
+ const right = left + bWidth
+ const { x, y } = offset
+ const topOffset = bottom > viewBottom ? top - bHeight - y : top + y + height
+ const leftOffset = right > viewRight ? left + x - bWidth + width : left + x
- this.setState({ topOffset, leftOffset }) //eslint-disable-line
- }
+ return {
+ topOffset,
+ leftOffset,
}
+}
- render() {
- let {
- events,
- selected,
- getters,
- accessors,
- components,
- onSelect,
- onDoubleClick,
- onKeyPress,
- slotStart,
- slotEnd,
- localizer,
- popperRef,
- } = this.props
-
- let { width } = this.props.position,
- topOffset = (this.state || {}).topOffset || 0,
- leftOffset = (this.state || {}).leftOffset || 0
-
- let style = {
- top: -topOffset,
- left: -leftOffset,
- minWidth: width + width / 2,
- }
+function Pop({
+ containerRef,
+ accessors,
+ getters,
+ selected,
+ components,
+ localizer,
+ position,
+ show,
+ events,
+ slotStart,
+ slotEnd,
+ onSelect,
+ onDoubleClick,
+ onKeyPress,
+ handleDragStart,
+ popperRef,
+ target,
+ offset,
+}) {
+ useClickOutside({ ref: popperRef, callback: show })
+ useLayoutEffect(() => {
+ const { topOffset, leftOffset } = getPosition({
+ target,
+ offset,
+ container: containerRef.current,
+ box: popperRef.current,
+ })
+ popperRef.current.style.top = `${topOffset}px`
+ popperRef.current.style.left = `${leftOffset}px`
+ }, [offset.x, offset.y, target])
- return (
-
-
- {localizer.format(slotStart, 'dayHeaderFormat')}
-
- {events.map((event, idx) => (
-
this.props.handleDragStart(event)}
- onDragEnd={() => this.props.show()}
- />
- ))}
-
- )
+ const { width } = position
+ const style = {
+ minWidth: width + width / 2,
}
+ return (
+
+
+ {localizer.format(slotStart, 'dayHeaderFormat')}
+
+ {events.map((event, idx) => (
+
handleDragStart(event)}
+ onDragEnd={() => show()}
+ />
+ ))}
+
+ )
}
+const Popup = React.forwardRef((props, ref) => (
+
+))
Popup.propTypes = {
- position: PropTypes.object,
- popupOffset: PropTypes.oneOfType([
- PropTypes.number,
- PropTypes.shape({
- x: PropTypes.number,
- y: PropTypes.number,
- }),
- ]),
- events: PropTypes.array,
- selected: PropTypes.object,
-
accessors: PropTypes.object.isRequired,
- components: PropTypes.object.isRequired,
getters: PropTypes.object.isRequired,
+ selected: PropTypes.object,
+ components: PropTypes.object.isRequired,
localizer: PropTypes.object.isRequired,
+ position: PropTypes.object.isRequired,
+ show: PropTypes.func.isRequired,
+ events: PropTypes.array.isRequired,
+ slotStart: PropTypes.instanceOf(Date).isRequired,
+ slotEnd: PropTypes.instanceOf(Date),
onSelect: PropTypes.func,
onDoubleClick: PropTypes.func,
onKeyPress: PropTypes.func,
handleDragStart: PropTypes.func,
- show: PropTypes.func,
- slotStart: PropTypes.instanceOf(Date),
- slotEnd: PropTypes.number,
- popperRef: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({ current: PropTypes.Element }),
- ]),
+ style: PropTypes.object,
+ offset: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
}
-
-/**
- * The Overlay component, of react-overlays, creates a ref that is passed to the Popup, and
- * requires proper ref forwarding to be used without error
- */
-export default React.forwardRef((props, ref) => (
-
-))
+export default Popup
diff --git a/src/hooks/useClickOutside.js b/src/hooks/useClickOutside.js
new file mode 100644
index 000000000..e25e0a651
--- /dev/null
+++ b/src/hooks/useClickOutside.js
@@ -0,0 +1,15 @@
+import { useEffect } from 'react'
+
+export default function useClickOutside({ ref, callback }) {
+ useEffect(() => {
+ const handleClickOutside = (e) => {
+ if (ref.current && !ref.current.contains(e.target)) {
+ callback()
+ }
+ }
+ document.addEventListener('mousedown', handleClickOutside)
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside)
+ }
+ }, [ref, callback])
+}
diff --git a/yarn.lock b/yarn.lock
index f5e3b0701..84cf95982 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1863,14 +1863,14 @@
pirates "^4.0.5"
source-map-support "^0.5.16"
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.0", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
version "7.17.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941"
integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.17.8", "@babel/runtime@^7.18.6":
+"@babel/runtime@^7.13.8", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580"
integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==
@@ -2803,15 +2803,15 @@
schema-utils "^3.0.0"
source-map "^0.7.3"
-"@popperjs/core@^2.5.3":
- version "2.11.2"
- resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
- integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==
+"@popperjs/core@^2.8.6":
+ version "2.11.5"
+ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
+ integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
-"@restart/hooks@^0.3.25":
- version "0.3.27"
- resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.3.27.tgz#91f356d66d4699a8cd8b3d008402708b6a9dc505"
- integrity sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw==
+"@restart/hooks@^0.4.7":
+ version "0.4.7"
+ resolved "https://registry.yarnpkg.com/@restart/hooks/-/hooks-0.4.7.tgz#d79ca6472c01ce04389fc73d4a79af1b5e33cd39"
+ integrity sha512-ZbjlEHcG+FQtpDPHd7i4FzNNvJf2enAwZfJbpM8CW7BhmOAbsHpZe3tsHwfQUrBuyrxWqPYp2x5UMnilWcY22A==
dependencies:
dequal "^2.0.2"
@@ -13022,18 +13022,18 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
-react-overlays@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-4.1.1.tgz#0060107cbe1c5171a744ccda3fbf0556d064bc5f"
- integrity sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==
+react-overlays@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-5.2.0.tgz#e7ebfdfdfbebd9d23cafd0bc2cac1d08abf1535b"
+ integrity sha512-dKZR/w6qeAsW0z0aIlwq/5H/M6o5T4RSlPnqIKqYVJ++rjoPSFcVggPhDWno8awZQsuMMtkjuksTbE8vOY0s9g==
dependencies:
- "@babel/runtime" "^7.12.1"
- "@popperjs/core" "^2.5.3"
- "@restart/hooks" "^0.3.25"
+ "@babel/runtime" "^7.13.8"
+ "@popperjs/core" "^2.8.6"
+ "@restart/hooks" "^0.4.7"
"@types/warning" "^3.0.0"
dom-helpers "^5.2.0"
prop-types "^15.7.2"
- uncontrollable "^7.0.0"
+ uncontrollable "^7.2.1"
warning "^4.0.3"
react-refresh@^0.11.0:
@@ -15065,7 +15065,7 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
-uncontrollable@^7.0.0, uncontrollable@^7.2.1:
+uncontrollable@^7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.2.1.tgz#1fa70ba0c57a14d5f78905d533cf63916dc75738"
integrity sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==