fix(navegacao): foco em âncora de outra página, vitrine acessível e 3D mais leve
Foco cai no destino ao chegar de outra página; âncoras ignoram ?tipo=; movimento reduzido salta em todos os cliques; cronômetro da janela ampliada; degradê no topo de Projetos e legendas do mergulho com intervalos testados; vitrine acima da barra de cookies e com 2 paradas por projeto; reel-list.css no global; 3D montado em tarefas curtas, limitado a ~30 qps e estático com WebGL por software; pôsteres da vitrine de 330 para 158 KB; SC Plus regravado; scripts sem funções acima de complexidade 10.
This commit is contained in:
1 parent
9e2d65a926
commit
204ebd5fa5
49 files changed
+2197
-606
No files matched your search
@@ -43,6 +43,45 @@ describe("useFocusOnNavigation", () => {
|
||||
expect(focus).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe("with a #hash in the URL (from /privacidade to /#contact)", () => {
|
||||
afterEach(() => {
|
||||
window.history.replaceState(null, "", "/");
|
||||
});
|
||||
|
||||
function mountContact() {
|
||||
const contact = document.createElement("section");
|
||||
contact.id = "contact";
|
||||
contact.tabIndex = -1;
|
||||
document.body.append(contact);
|
||||
return contact;
|
||||
}
|
||||
|
||||
it("leaves the focus to the anchor target when the new page has it", () => {
|
||||
const main = mountMain();
|
||||
const contact = mountContact();
|
||||
const focus = jest.spyOn(main, "focus");
|
||||
const { rerender } = render(<Probe pathname="/privacidade" />);
|
||||
|
||||
window.history.replaceState(null, "", "/#contact");
|
||||
contact.focus({ preventScroll: true });
|
||||
rerender(<Probe pathname="/" />);
|
||||
|
||||
expect(focus).not.toHaveBeenCalled();
|
||||
expect(contact).toHaveFocus();
|
||||
});
|
||||
|
||||
it("still focuses #main-content when the hash points to nothing on the new page", () => {
|
||||
const main = mountMain();
|
||||
mountContact();
|
||||
const { rerender } = render(<Probe pathname="/privacidade" />);
|
||||
|
||||
window.history.replaceState(null, "", "/#nada");
|
||||
rerender(<Probe pathname="/" />);
|
||||
|
||||
expect(main).toHaveFocus();
|
||||
});
|
||||
});
|
||||
|
||||
it("still tells a navigation from the first load when the component remounts (first segment changed)", () => {
|
||||
const main = mountMain();
|
||||
const first = render(<Probe pathname="/" />);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { elementForHash } from "@/app/components/cinematic/fragment-nav";
|
||||
|
||||
/**
|
||||
* Caminho já exibido neste documento. Fica fora do componente porque o template da raiz remonta quando o primeiro
|
||||
@@ -17,12 +18,15 @@ export function resetFocusOnNavigation() {
|
||||
* Depois de uma troca de página no navegador (o `pathname` mudou), o foco vai para o contêiner do conteúdo
|
||||
* (`#main-content`, o mesmo destino do link "Pular"): leitor de tela e teclado seguem da página nova, não do link
|
||||
* clicado na antiga. Sem rolar a página (preventScroll) e sem nada na carga inicial, que não tem página anterior.
|
||||
* Quando a URL traz um `#id` que existe na página nova (de /privacidade para /#contact), o foco é do destino da
|
||||
* âncora (quem chega a ele dá o foco); o contêiner não o toma, para o Tab seguir dali.
|
||||
*/
|
||||
export function useFocusOnNavigation(pathname: string) {
|
||||
useEffect(() => {
|
||||
const previous = shownPath;
|
||||
shownPath = pathname;
|
||||
if (previous === null || previous === pathname) return;
|
||||
if (elementForHash(window.location.hash)) return;
|
||||
document.getElementById("main-content")?.focus({ preventScroll: true });
|
||||
}, [pathname]);
|
||||
}
|
||||
Reference in new issue
Block a user