mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-30 12:09:08 +00:00
♿️(frontend) fix focus restore when switching side panels
restore trigger focus on panel switch while panel remains open
This commit is contained in:
@@ -177,17 +177,21 @@ export const SidePanel = () => {
|
|||||||
|
|
||||||
const asideRef = useRef<HTMLElement>(null)
|
const asideRef = useRef<HTMLElement>(null)
|
||||||
|
|
||||||
const panelManagesFocus = activePanelId === PanelId.CHAT
|
|
||||||
|
|
||||||
const focusAside = useCallback(() => {
|
const focusAside = useCallback(() => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
asideRef.current?.focus({ preventScroll: true })
|
asideRef.current?.focus({ preventScroll: true })
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useRestoreFocus(isSidePanelOpen && !panelManagesFocus, {
|
const handlePanelOpened = useCallback(() => {
|
||||||
onOpened: focusAside,
|
if (activePanelId === PanelId.CHAT) return
|
||||||
|
focusAside()
|
||||||
|
}, [activePanelId, focusAside])
|
||||||
|
|
||||||
|
useRestoreFocus(isSidePanelOpen, {
|
||||||
|
onOpened: handlePanelOpened,
|
||||||
preventScroll: true,
|
preventScroll: true,
|
||||||
|
activeKey: activePanelId,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -95,8 +95,13 @@ const ToolButton = ({
|
|||||||
|
|
||||||
export const Tools = () => {
|
export const Tools = () => {
|
||||||
const { data } = useConfig()
|
const { data } = useConfig()
|
||||||
const { openTranscript, openScreenRecording, activeSubPanelId, isToolsOpen } =
|
const {
|
||||||
useSidePanel()
|
openTranscript,
|
||||||
|
openScreenRecording,
|
||||||
|
activeSubPanelId,
|
||||||
|
isToolsOpen,
|
||||||
|
isSidePanelOpen,
|
||||||
|
} = useSidePanel()
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'moreTools' })
|
const { t } = useTranslation('rooms', { keyPrefix: 'moreTools' })
|
||||||
|
|
||||||
// Restore focus to the element that opened the Tools panel
|
// Restore focus to the element that opened the Tools panel
|
||||||
@@ -113,6 +118,7 @@ export const Tools = () => {
|
|||||||
},
|
},
|
||||||
restoreFocusRaf: true,
|
restoreFocusRaf: true,
|
||||||
preventScroll: true,
|
preventScroll: true,
|
||||||
|
shouldRestoreOnClose: () => !isSidePanelOpen,
|
||||||
})
|
})
|
||||||
|
|
||||||
const isTranscriptEnabled = useIsRecordingModeEnabled(
|
const isTranscriptEnabled = useIsRecordingModeEnabled(
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export function Chat({ ...props }: ChatProps) {
|
|||||||
const room = useRoomContext()
|
const room = useRoomContext()
|
||||||
const { send, chatMessages, isSending } = useChat()
|
const { send, chatMessages, isSending } = useChat()
|
||||||
|
|
||||||
const { isChatOpen } = useSidePanel()
|
const { isChatOpen, isSidePanelOpen } = useSidePanel()
|
||||||
const chatSnap = useSnapshot(chatStore)
|
const chatSnap = useSnapshot(chatStore)
|
||||||
|
|
||||||
// Keep track of the element that opened the chat so we can restore focus
|
// Keep track of the element that opened the chat so we can restore focus
|
||||||
@@ -51,6 +51,7 @@ export function Chat({ ...props }: ChatProps) {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
preventScroll: true,
|
preventScroll: true,
|
||||||
|
shouldRestoreOnClose: () => !isSidePanelOpen,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Use useParticipants hook to trigger a re-render when the participant list changes.
|
// Use useParticipants hook to trigger a re-render when the participant list changes.
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ export type RestoreFocusOptions = {
|
|||||||
onClosed?: () => void
|
onClosed?: () => void
|
||||||
restoreFocusRaf?: boolean
|
restoreFocusRaf?: boolean
|
||||||
preventScroll?: boolean
|
preventScroll?: boolean
|
||||||
|
/** When the panel stays open but its content changes, update the restore target. */
|
||||||
|
activeKey?: string | null
|
||||||
|
/** Return false to skip restoring focus on close (e.g. when switching to another panel). */
|
||||||
|
shouldRestoreOnClose?: () => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,9 +26,12 @@ export function useRestoreFocus(
|
|||||||
onClosed,
|
onClosed,
|
||||||
restoreFocusRaf = false,
|
restoreFocusRaf = false,
|
||||||
preventScroll = true,
|
preventScroll = true,
|
||||||
|
activeKey,
|
||||||
|
shouldRestoreOnClose,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
const prevIsOpenRef = useRef(false)
|
const prevIsOpenRef = useRef(false)
|
||||||
|
const prevActiveKeyRef = useRef(activeKey)
|
||||||
const triggerRef = useRef<HTMLElement | null>(null)
|
const triggerRef = useRef<HTMLElement | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -37,25 +44,41 @@ export function useRestoreFocus(
|
|||||||
onOpened?.()
|
onOpened?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Panel switched while staying open
|
||||||
|
if (wasOpen && isOpen && activeKey !== prevActiveKeyRef.current) {
|
||||||
|
const activeEl = document.activeElement as HTMLElement | null
|
||||||
|
triggerRef.current = resolveTrigger ? resolveTrigger(activeEl) : activeEl
|
||||||
|
onOpened?.()
|
||||||
|
}
|
||||||
|
|
||||||
// Just closed
|
// Just closed
|
||||||
if (wasOpen && !isOpen) {
|
if (wasOpen && !isOpen) {
|
||||||
const trigger = triggerRef.current
|
const trigger = triggerRef.current
|
||||||
if (trigger && document.contains(trigger)) {
|
const shouldRestore =
|
||||||
|
(shouldRestoreOnClose?.() ?? true) &&
|
||||||
|
trigger &&
|
||||||
|
document.contains(trigger)
|
||||||
|
|
||||||
|
if (shouldRestore) {
|
||||||
const focus = () => trigger.focus({ preventScroll })
|
const focus = () => trigger.focus({ preventScroll })
|
||||||
if (restoreFocusRaf) requestAnimationFrame(focus)
|
if (restoreFocusRaf) requestAnimationFrame(focus)
|
||||||
else focus()
|
else focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerRef.current = null
|
triggerRef.current = null
|
||||||
onClosed?.()
|
onClosed?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
prevIsOpenRef.current = isOpen
|
prevIsOpenRef.current = isOpen
|
||||||
|
prevActiveKeyRef.current = activeKey
|
||||||
}, [
|
}, [
|
||||||
isOpen,
|
isOpen,
|
||||||
|
activeKey,
|
||||||
onClosed,
|
onClosed,
|
||||||
onOpened,
|
onOpened,
|
||||||
preventScroll,
|
preventScroll,
|
||||||
resolveTrigger,
|
resolveTrigger,
|
||||||
restoreFocusRaf,
|
restoreFocusRaf,
|
||||||
|
shouldRestoreOnClose,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user