Enhance Keyboard Navigation in Dashboard Contexts
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Introduced key handling improvements in ActionsContext to manage control key states more effectively. - Added keyboard navigation functionality in NavigationTabsContext, allowing users to cycle through tabs using Ctrl+Tab and select tabs with number keys. - Implemented cleanup for key event listeners to ensure proper state management and prevent memory leaks.
This commit is contained in:
parent
4f6f7cb881
commit
e7f3e2a6d4
@ -62,23 +62,27 @@ const ActionsProvider = ({ children }) => {
|
|||||||
const [ctrlDown, setCtrlDown] = useState(false)
|
const [ctrlDown, setCtrlDown] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const isHoldKey = (key) => key === 'Meta' || key === 'Control'
|
||||||
const handleKeyDown = (event) => {
|
const handleKeyDown = (event) => {
|
||||||
const key = event.key
|
if (isHoldKey(event.key)) {
|
||||||
if (key === 'Meta') {
|
|
||||||
setCtrlDown(true)
|
setCtrlDown(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleKeyUp = (event) => {
|
const handleKeyUp = (event) => {
|
||||||
const key = event.key
|
if (isHoldKey(event.key)) {
|
||||||
if (key === 'Meta') {
|
|
||||||
setCtrlDown(false)
|
setCtrlDown(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const clearHold = () => setCtrlDown(false)
|
||||||
window.addEventListener('keydown', handleKeyDown)
|
window.addEventListener('keydown', handleKeyDown)
|
||||||
window.addEventListener('keyup', handleKeyUp)
|
window.addEventListener('keyup', handleKeyUp)
|
||||||
|
window.addEventListener('blur', clearHold)
|
||||||
|
document.addEventListener('visibilitychange', clearHold)
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('keydown', handleKeyDown)
|
window.removeEventListener('keydown', handleKeyDown)
|
||||||
window.removeEventListener('keyup', handleKeyUp)
|
window.removeEventListener('keyup', handleKeyUp)
|
||||||
|
window.removeEventListener('blur', clearHold)
|
||||||
|
document.removeEventListener('visibilitychange', clearHold)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -242,9 +246,10 @@ const ActionsProvider = ({ children }) => {
|
|||||||
setCurrentObjectType,
|
setCurrentObjectType,
|
||||||
callAction,
|
callAction,
|
||||||
clearAction,
|
clearAction,
|
||||||
setOnModalOk
|
setOnModalOk,
|
||||||
|
ctrlDown
|
||||||
}),
|
}),
|
||||||
[callAction, clearAction, currentObject, currentObjectType]
|
[callAction, clearAction, currentObject, currentObjectType, ctrlDown]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -971,6 +971,59 @@ export const NavigationTabsProvider = ({ children }) => {
|
|||||||
})
|
})
|
||||||
}, [isElectron, onTabMovedAway, removeTab])
|
}, [isElectron, onTabMovedAway, removeTab])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isElectron) return undefined
|
||||||
|
|
||||||
|
const digitIndexFromEvent = (event) => {
|
||||||
|
const code = event.code || ''
|
||||||
|
if (code.startsWith('Digit')) {
|
||||||
|
const digit = Number(code.slice(5))
|
||||||
|
if (digit >= 1 && digit <= 9) return digit - 1
|
||||||
|
if (digit === 0) return 9
|
||||||
|
}
|
||||||
|
const key = event.key
|
||||||
|
if (key >= '1' && key <= '9') return Number(key) - 1
|
||||||
|
if (key === '0') return 9
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectTabAtIndex = (index) => {
|
||||||
|
const nextTab = tabsRef.current[index]
|
||||||
|
if (!nextTab) return
|
||||||
|
selectTab(nextTab.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cycleTab = (delta) => {
|
||||||
|
const current = tabsRef.current
|
||||||
|
if (current.length < 2) return
|
||||||
|
const activeIndex = current.findIndex(
|
||||||
|
(tab) => tab.id === activeTabIdRef.current
|
||||||
|
)
|
||||||
|
const fromIndex = activeIndex === -1 ? 0 : activeIndex
|
||||||
|
const nextIndex = (fromIndex + delta + current.length) % current.length
|
||||||
|
selectTab(current[nextIndex].id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
if (event.ctrlKey && event.key === 'Tab') {
|
||||||
|
event.preventDefault()
|
||||||
|
cycleTab(event.shiftKey ? -1 : 1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(event.metaKey || event.ctrlKey) || event.repeat) return
|
||||||
|
const index = digitIndexFromEvent(event)
|
||||||
|
if (index == null) return
|
||||||
|
event.preventDefault()
|
||||||
|
selectTabAtIndex(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handleKeyDown, true)
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('keydown', handleKeyDown, true)
|
||||||
|
}
|
||||||
|
}, [isElectron, selectTab])
|
||||||
|
|
||||||
const activeTab = useMemo(
|
const activeTab = useMemo(
|
||||||
() => tabs.find((tab) => tab.id === activeTabId) || null,
|
() => tabs.find((tab) => tab.id === activeTabId) || null,
|
||||||
[activeTabId, tabs]
|
[activeTabId, tabs]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user