This commit is contained in:
lebaudantoine
2026-01-28 16:35:19 +01:00
parent 180da8d433
commit 2d448cffd7
5 changed files with 54 additions and 41 deletions
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next'
import { useMemo } from 'react'
import { useEffect, useMemo, useRef } from 'react'
import { VStack } from '@/styled-system/jsx'
import { css } from '@/styled-system/css'
import { RiCheckLine, RiFileCopyLine } from '@remixicon/react'
@@ -9,16 +9,24 @@ import { useRoomData } from '../hooks/useRoomData'
import { formatPinCode } from '../../utils/telephony'
import { useTelephony } from '../hooks/useTelephony'
import { useCopyRoomToClipboard } from '../hooks/useCopyRoomToClipboard'
import { useSidePanel } from '../hooks/useSidePanel'
import { useRestoreFocus } from '@/hooks/useRestoreFocus'
import { useSidePanelRef } from '../hooks/useSidePanelRef'
import { useSidePanelTriggers } from '../hooks/useSidePanelTriggers'
const useFocusOnOpen = ({ ref, key }) => {
useEffect(() => {
requestAnimationFrame(() => {
const panel = ref.current
if (panel) {
const firstButton = panel.querySelector<HTMLElement>(key)
if (firstButton) {
firstButton.focus({ preventScroll: true })
}
}
})
}, [])
}
export const Info = () => {
const { t } = useTranslation('rooms', { keyPrefix: 'info' })
const { isInfoOpen } = useSidePanel()
const panelRef = useSidePanelRef()
const { getTrigger } = useSidePanelTriggers()
const panelRef = useRef()
const data = useRoomData()
const roomUrl = getRouteUrl('room', data?.slug)
@@ -31,26 +39,7 @@ export const Info = () => {
const { isCopied, copyRoomToClipboard } = useCopyRoomToClipboard(data)
// Restore focus to the element that opened the Info panel
useRestoreFocus(isInfoOpen, {
resolveTrigger: (activeEl) => getTrigger('info') ?? activeEl,
// Focus the first focusable element when the panel opens
onOpened: () => {
requestAnimationFrame(() => {
const panel = panelRef.current
if (panel) {
const firstButton = panel.querySelector<HTMLElement>(
'[data-attr="copy-info-sidepanel"]'
)
if (firstButton) {
firstButton.focus({ preventScroll: true })
}
}
})
},
restoreFocusRaf: true,
preventScroll: true,
})
useFocusOnOpen({ ref: panelRef, key: '[data-attr="copy-info-sidepanel"]' })
return (
<Div
@@ -60,6 +49,7 @@ export const Info = () => {
flexGrow={1}
flexDirection="column"
alignItems="start"
ref={panelRef}
>
<VStack alignItems="start">
<Text
@@ -206,7 +206,7 @@ const SidePanelContent = () => {
<Panel isOpen={isAdminOpen} keepAlive={true}>
<Admin />
</Panel>
<Panel isOpen={isInfoOpen} keepAlive={true}>
<Panel isOpen={isInfoOpen}>
<Info />
</Panel>
</StyledSidePanel>
@@ -1,4 +1,4 @@
import { useCallback } from 'react'
import { useCallback, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { RiInformationLine } from '@remixicon/react'
import { css } from '@/styled-system/css'
@@ -14,14 +14,17 @@ export const InfoToggle = ({
const { t } = useTranslation('rooms', { keyPrefix: 'controls.info' })
const { isInfoOpen, toggleInfo } = useSidePanel()
const { setTrigger } = useSidePanelTriggers()
// const { setTrigger } = useSidePanelTriggers()
const tooltipLabel = isInfoOpen ? 'open' : 'closed'
const setInfoTriggerRef = useCallback(
(el: HTMLElement | null) => {
setTrigger('info', el)
},
[setTrigger]
)
const wip = useRef<HTMLElement | null>()
// const setInfoTriggerRef = useCallback(
// (el: HTMLElement | null) => {
// setTrigger('info', el)
// },
// [setTrigger]
// )
return (
<div
@@ -36,9 +39,9 @@ export const InfoToggle = ({
aria-label={t(tooltipLabel)}
tooltip={t(tooltipLabel)}
isSelected={isInfoOpen}
ref={setInfoTriggerRef}
ref={wip}
onPress={(e) => {
toggleInfo()
toggleInfo(wip)
onPress?.(e)
}}
data-attr={`controls-info-${tooltipLabel}`}
@@ -1,5 +1,6 @@
import { useSnapshot } from 'valtio'
import { ref, useSnapshot } from 'valtio'
import { layoutStore } from '@/stores/layout'
import { useEffect } from 'react'
export enum PanelId {
PARTICIPANTS = 'participants',
@@ -56,8 +57,13 @@ export const useSidePanel = () => {
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
}
const toggleInfo = () => {
const toggleInfo = (wip) => {
layoutStore.activePanelId = isInfoOpen ? null : PanelId.INFO
if (!isInfoOpen) {
layoutStore.genericRef = ref(wip)
}
if (layoutSnap.activeSubPanelId) layoutStore.activeSubPanelId = null
}
@@ -71,6 +77,18 @@ export const useSidePanel = () => {
layoutStore.activePanelId = PanelId.TOOLS
}
useEffect(() => {
if (!layoutSnap.activePanelId) {
console.log('$$prout closing')
const trigger = layoutSnap?.genericRef?.current
console.log(trigger)
if (trigger) {
trigger.focus({ preventScroll: true })
trigger.setAttribute('data-restore-focus-visible', '')
}
}
}, [layoutSnap.activePanelId, layoutSnap?.genericRef])
return {
activePanelId,
activeSubPanelId,
+2
View File
@@ -10,6 +10,7 @@ type State = {
showSubtitles: boolean
activePanelId: PanelId | null
activeSubPanelId: SubPanelId | null
genericRef: HTMLElement | null
}
export const layoutStore = proxy<State>({
@@ -18,4 +19,5 @@ export const layoutStore = proxy<State>({
showSubtitles: false,
activePanelId: null,
activeSubPanelId: null,
genericRef: null,
})