From 099cc0516bfcad422124bac80712026636e840d2 Mon Sep 17 00:00:00 2001 From: Amelle El Bakkal Date: Fri, 24 Nov 2023 11:56:33 +0100 Subject: [PATCH] =?UTF-8?q?feat(US-209):=20WIP=20ajoute=20lien=20=C3=A9vit?= =?UTF-8?q?ement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/layouts/Layout.tsx | 70 ++++++++++++++++++++++++++++---- tests/components/Layout.test.tsx | 8 ++++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/components/layouts/Layout.tsx b/components/layouts/Layout.tsx index a2baf1542..b32f62c1e 100644 --- a/components/layouts/Layout.tsx +++ b/components/layouts/Layout.tsx @@ -4,9 +4,18 @@ import { apm } from '@elastic/apm-rum' import dynamic from 'next/dynamic' +import Link from 'next/link' import { useRouter } from 'next/router' import { useTheme } from 'next-themes' -import React, { ReactElement, useEffect, useRef, useState } from 'react' +import React, { + forwardRef, + ReactElement, + Ref, + useEffect, + useImperativeHandle, + useRef, + useState, +} from 'react' import AppHead from 'components/AppHead' import { MODAL_ROOT_ID } from 'components/Modal' @@ -54,12 +63,29 @@ export default function Layout({ children }: LayoutProps) { const containerRef = useRef(null) const mainRef = useRef(null) + const skipLinkRefContainer = useRef(null) + const mainRefContainer = useRef(null) const [hasMessageNonLu, setHasMessageNonLu] = useState(false) const pageCouranteEstMessagerie = router.pathname === '/messagerie' const withChat = !withoutChat + function focusOnMain() { + const findFirstFocusableElement = (element) => { + const focusableElements = element.querySelectorAll( + 'button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"], [role="tablist"])' + ) + return focusableElements[0] + } + if (mainRef.current) { + const firstFocusableElement = findFirstFocusableElement(mainRef.current) + if (firstFocusableElement) { + firstFocusableElement.focus() + } + } + } + useEffect(() => { // https://dev.to/admitkard/mobile-issue-with-100vh-height-100-100vh-3-solutions-3nae function resizeContainerToInnerHeight() { @@ -75,10 +101,6 @@ export default function Layout({ children }: LayoutProps) { window.removeEventListener('resize', resizeContainerToInnerHeight, true) }, []) - useEffect(() => { - if (mainRef.current) mainRef.current.scrollTo(0, 0) - }, [router.asPath, mainRef]) - useEffect(() => { if (!conseiller) { Promise.all([ @@ -116,9 +138,16 @@ export default function Layout({ children }: LayoutProps) { } }, [conseiller, conseiller?.structure, setTheme]) + useEffect(() => { + if (skipLinkRefContainer.current) { + skipLinkRefContainer.current.focus() + } + }, [skipLinkRefContainer, router.pathname]) + return ( <> + {!conseiller && } @@ -134,7 +163,7 @@ export default function Layout({ children }: LayoutProps) {
-
+
@@ -197,3 +230,26 @@ export default function Layout({ children }: LayoutProps) { ) } + +const LienEvitement = forwardRef( + (props: { onClick: () => void }, forwardedRef: Ref) => { + const { onClick } = props + const ref = useRef(null) + + useImperativeHandle(forwardedRef, () => ref.current as HTMLSpanElement) + + return ( + + + Aller au contenu + + + ) + } +) + +LienEvitement.displayName = 'LienEvitement' diff --git a/tests/components/Layout.test.tsx b/tests/components/Layout.test.tsx index b5fdf24dd..1f15f494c 100644 --- a/tests/components/Layout.test.tsx +++ b/tests/components/Layout.test.tsx @@ -105,6 +105,13 @@ describe('', () => { }) }) + it("affiche le lien d'évitement", () => { + // Then + expect( + screen.getByRole('link', { name: 'Aller au contenu' }) + ).toHaveAttribute('href', '#contenu') + }) + it('affiche le titre de la page', () => { // Then expect( @@ -118,6 +125,7 @@ describe('', () => { it('contient la région (landmark) main', () => { expect(screen.getByRole('main')).toBeInTheDocument() + expect(screen.getByRole('main')).toHaveAttribute('id', 'contenu') }) it("affiche le fil d'ariane", () => {