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)
|
||||
|
||||
useEffect(() => {
|
||||
const isHoldKey = (key) => key === 'Meta' || key === 'Control'
|
||||
const handleKeyDown = (event) => {
|
||||
const key = event.key
|
||||
if (key === 'Meta') {
|
||||
if (isHoldKey(event.key)) {
|
||||
setCtrlDown(true)
|
||||
}
|
||||
}
|
||||
const handleKeyUp = (event) => {
|
||||
const key = event.key
|
||||
if (key === 'Meta') {
|
||||
if (isHoldKey(event.key)) {
|
||||
setCtrlDown(false)
|
||||
}
|
||||
}
|
||||
const clearHold = () => setCtrlDown(false)
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
window.addEventListener('keyup', handleKeyUp)
|
||||
window.addEventListener('blur', clearHold)
|
||||
document.addEventListener('visibilitychange', clearHold)
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown)
|
||||
window.removeEventListener('keyup', handleKeyUp)
|
||||
window.removeEventListener('blur', clearHold)
|
||||
document.removeEventListener('visibilitychange', clearHold)
|
||||
}
|
||||
}, [])
|
||||
|
||||
@ -242,9 +246,10 @@ const ActionsProvider = ({ children }) => {
|
||||
setCurrentObjectType,
|
||||
callAction,
|
||||
clearAction,
|
||||
setOnModalOk
|
||||
setOnModalOk,
|
||||
ctrlDown
|
||||
}),
|
||||
[callAction, clearAction, currentObject, currentObjectType]
|
||||
[callAction, clearAction, currentObject, currentObjectType, ctrlDown]
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@ -971,6 +971,59 @@ export const NavigationTabsProvider = ({ children }) => {
|
||||
})
|
||||
}, [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(
|
||||
() => tabs.find((tab) => tab.id === activeTabId) || null,
|
||||
[activeTabId, tabs]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user