diff --git a/src/components/datatable/BottomPanel.js b/src/components/datatable/BottomPanel.js
index 82a15c6e5..97a5018a5 100644
--- a/src/components/datatable/BottomPanel.js
+++ b/src/components/datatable/BottomPanel.js
@@ -8,6 +8,7 @@ import {
LAYERS_PANEL_WIDTH,
RIGHT_PANEL_WIDTH,
} from '../../constants/layout.js'
+import useKeyDown from '../../hooks/useKeyDown.js'
import { useWindowDimensions } from '../WindowDimensionsProvider.js'
import DataTable from './DataTable.js'
import ErrorBoundary from './ErrorBoundary.js'
@@ -37,6 +38,8 @@ const BottomPanel = () => {
const tableWidth = width - layersWidth - rightPanelWidth
const dataTableControlsHeight = 20
+ useKeyDown('Escape', () => dispatch(closeDataTable()), true)
+
return (
{
})
useEffect(() => {
- /* The combination of automtic table layout and virtual scrolling
+ /* The combination of automatic table layout and virtual scrolling
* causes a content shift when scrolling and filtering because the
* cells in the DOM have a different content length which causes the
* columns to have a different width. To avoid that we measure the
diff --git a/src/components/edit/thematic/ThematicDialog.js b/src/components/edit/thematic/ThematicDialog.js
index 978e6022a..88bb09a78 100644
--- a/src/components/edit/thematic/ThematicDialog.js
+++ b/src/components/edit/thematic/ThematicDialog.js
@@ -305,7 +305,6 @@ class ThematicDialog extends Component {
calculationError,
eventDataItemError,
programIndicatorError,
- // periodTypeError,
periodError,
orgUnitsError,
legendSetError,
diff --git a/src/components/interpretations/InterpretationsToggle.js b/src/components/interpretations/InterpretationsToggle.js
index a47cce286..d5b43ff48 100644
--- a/src/components/interpretations/InterpretationsToggle.js
+++ b/src/components/interpretations/InterpretationsToggle.js
@@ -5,6 +5,7 @@ import {
openInterpretationsPanel,
closeInterpretationsPanel,
} from '../../actions/ui.js'
+import useKeyDown from '../../hooks/useKeyDown.js'
const InterpretationsToggle = () => {
const interpretationsEnabled = useSelector((state) => Boolean(state.map.id))
@@ -21,6 +22,14 @@ const InterpretationsToggle = () => {
}
}, [dispatch, interpretationsOpen])
+ const onClose = useCallback(() => {
+ if (interpretationsOpen) {
+ dispatch(closeInterpretationsPanel())
+ }
+ }, [dispatch, interpretationsOpen])
+
+ useKeyDown('Escape', onClose, true)
+
return (
{
const { map, isPlugin } = context
const container = useMemo(() => document.createElement('div'), [])
+ useKeyDown('Escape', () => map.closePopup())
+
// Create and open popup on map
useEffect(() => {
container.className = className
diff --git a/src/components/orgunits/OrgUnitProfile.js b/src/components/orgunits/OrgUnitProfile.js
index 099908e8d..669e53191 100644
--- a/src/components/orgunits/OrgUnitProfile.js
+++ b/src/components/orgunits/OrgUnitProfile.js
@@ -4,6 +4,7 @@ import { CenteredContent, CircularLoader, IconCross24 } from '@dhis2/ui'
import React, { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { closeOrgUnitProfile } from '../../actions/orgUnits.js'
+import useKeyDown from '../../hooks/useKeyDown.js'
import Drawer from '../core/Drawer.js'
import OrgUnitData from './OrgUnitData.js'
import OrgUnitInfo from './OrgUnitInfo.js'
@@ -34,6 +35,8 @@ const OrgUnitProfile = () => {
}
}, [id, refetch])
+ useKeyDown('Escape', () => dispatch(closeOrgUnitProfile()))
+
if (!id) {
return null
}
diff --git a/src/hooks/useKeyDown.js b/src/hooks/useKeyDown.js
index 52bc9ae23..a17499b75 100644
--- a/src/hooks/useKeyDown.js
+++ b/src/hooks/useKeyDown.js
@@ -1,18 +1,42 @@
-import { useEffect } from 'react'
+import { useEffect, useRef } from 'react'
+
+const useKeyDown = (key, callback, longPress = false) => {
+ const timerRef = useRef(null)
-const useKeyDown = (key, callback) => {
useEffect(() => {
const handleKeyDown = (event) => {
if (event.key === key) {
- callback(event)
+ if (!longPress) {
+ callback(event)
+ } else {
+ // Start a timer for detecting long press
+ timerRef.current = setTimeout(() => {
+ callback(event)
+ }, 250) // Adjust delay for long press detection
+ }
+ }
+ }
+
+ const handleKeyUp = (event) => {
+ if (event.key === key && longPress) {
+ // Clear the timer if the key is released before the delay
+ clearTimeout(timerRef.current)
}
}
window.addEventListener('keydown', handleKeyDown)
+ window.addEventListener('keyup', handleKeyUp)
+
return () => {
window.removeEventListener('keydown', handleKeyDown)
+ window.removeEventListener('keyup', handleKeyUp)
}
- }, [key, callback])
+ }, [key, callback, longPress])
+
+ useEffect(() => {
+ // Cleanup on unmount
+ return () => clearTimeout(timerRef.current)
+ }, [])
}
export default useKeyDown