Files
meet/src/frontend/src/features/layout/components/PaginationControl.tsx
T
Cyril b498926353 ️(frontend) improve pagination control accessibility
Turn main-window pagination into a labelled nav landmark with a live
page counter for screen readers. Add pagination.label in all locales.
2026-06-29 16:51:09 +02:00

100 lines
2.5 KiB
TypeScript

import * as React from 'react'
import { createInteractingObservable } from '@livekit/components-core'
import { RiArrowLeftSLine, RiArrowRightSLine } from '@remixicon/react'
import { Button } from '@/primitives'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { css } from '@/styled-system/css'
export interface PaginationControlProps {
totalPageCount: number
nextPage: () => void
prevPage: () => void
currentPage: number
pagesContainer?: React.RefObject<HTMLElement>
}
export function PaginationControl({
totalPageCount,
nextPage,
prevPage,
currentPage,
pagesContainer: connectedElement,
}: PaginationControlProps) {
const { t } = useTranslation('rooms', { keyPrefix: 'pagination' })
const [interactive, setInteractive] = useState(false)
useEffect(() => {
let subscription:
| ReturnType<ReturnType<typeof createInteractingObservable>['subscribe']>
| undefined
if (connectedElement) {
subscription = createInteractingObservable(
connectedElement.current,
2000
).subscribe(setInteractive)
}
return () => {
if (subscription) {
subscription.unsubscribe()
}
}
}, [connectedElement])
if (totalPageCount <= 1) return null
return (
<nav
aria-label={t('label')}
className={css({
position: 'absolute',
bottom: '1rem',
left: '50%',
transform: 'translateX(-50%)',
alignItems: 'stretch',
backgroundColor: 'var(--lk-control-bg)',
borderRadius: 'var(--lk-border-radius)',
transition: 'opacity ease-in-out .15s',
display: 'none',
border: '1px solid',
borderColor: 'primaryDark.100',
overflow: 'hidden',
})}
style={{
display: interactive ? 'flex' : 'none',
}}
data-lk-user-interaction={interactive}
>
<Button
isDisabled={currentPage == 1}
onPress={prevPage}
size="xs"
variant="quaternaryText"
aria-label={t('previous')}
>
<RiArrowLeftSLine />
</Button>
<span
role="status"
className={css({
padding: '0.25rem 0.5rem',
})}
>
{t('count', {
currentPage,
totalPageCount,
})}
</span>
<Button
isDisabled={currentPage == totalPageCount}
onPress={nextPage}
size="xs"
variant="quaternaryText"
aria-label={t('next')}
>
<RiArrowRightSLine />
</Button>
</nav>
)
}