perf(movimento): sem tempo morto, vídeos regravados e 3D sem React Three Fiber
Legenda do mergulho até Projetos cobrir a cena; transição de página sem blur e com fundo escuro; foco no conteúdo ao trocar de página; listas com marcador e dois pesos de título; vídeos da SEV e da SC Plus regravados sem quadros brancos; scrub a 12-15 fps (-30%); vitrine com uma parada de Tab e setas, contador no celular e CSS sob demanda; âncoras num módulo só (fragment-nav); FramePulse com setInterval; CSS morto removido.
This commit is contained in:
1 parent
f8545cd442
commit
6ac87824f3
68 files changed
+5735
-3300
No files matched your search
@@ -4,10 +4,8 @@ import {
|
||||
anchorDuration,
|
||||
anchorTop,
|
||||
IDLE_SECONDS,
|
||||
isPlainPrimaryClick,
|
||||
JUMP_SCREENS,
|
||||
MAX_ANCHOR_SECONDS,
|
||||
samePageHashTarget,
|
||||
useCinematicScroll,
|
||||
} from "./useCinematicScroll";
|
||||
|
||||
@@ -183,102 +181,6 @@ describe("anchor travel", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("isPlainPrimaryClick", () => {
|
||||
const click = (init: MouseEventInit = {}) =>
|
||||
new MouseEvent("click", { cancelable: true, button: 0, ...init });
|
||||
|
||||
it("accepts a plain click of the main button", () => {
|
||||
expect(isPlainPrimaryClick(click())).toBe(true);
|
||||
});
|
||||
|
||||
it.each(["metaKey", "ctrlKey", "shiftKey", "altKey"] as const)(
|
||||
"refuses a click with %s held (new tab, selection)",
|
||||
(modifier) => {
|
||||
expect(isPlainPrimaryClick(click({ [modifier]: true }))).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([1, 2])("refuses mouse button %i", (button) => {
|
||||
expect(isPlainPrimaryClick(click({ button }))).toBe(false);
|
||||
});
|
||||
|
||||
it("refuses a click somebody else already cancelled", () => {
|
||||
const event = click();
|
||||
event.preventDefault();
|
||||
|
||||
expect(isPlainPrimaryClick(event)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("samePageHashTarget", () => {
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
function clickOn(markup: string, selector: string) {
|
||||
document.body.innerHTML = markup;
|
||||
const target = document.querySelector(selector) as Element;
|
||||
const event = new MouseEvent("click", { bubbles: true });
|
||||
Object.defineProperty(event, "target", { value: target });
|
||||
return event;
|
||||
}
|
||||
|
||||
it("finds the element a same-page #link points to", () => {
|
||||
const event = clickOn(
|
||||
`<a href="/#alvo">ir</a><section id="alvo"></section>`,
|
||||
"a",
|
||||
);
|
||||
|
||||
const hit = samePageHashTarget(event);
|
||||
|
||||
expect(hit?.hash).toBe("#alvo");
|
||||
expect(hit?.target.id).toBe("alvo");
|
||||
});
|
||||
|
||||
it("works from inside the link (the text, an icon)", () => {
|
||||
const event = clickOn(
|
||||
`<a href="/#alvo"><span id="inside">ir</span></a><section id="alvo"></section>`,
|
||||
"#inside",
|
||||
);
|
||||
|
||||
expect(samePageHashTarget(event)?.target.id).toBe("alvo");
|
||||
});
|
||||
|
||||
it.each([
|
||||
["another site", `<a href="https://example.com/#alvo">x</a>`],
|
||||
["another page of this site", `<a href="/outra#alvo">x</a>`],
|
||||
["no anchor", `<a href="/">x</a>`],
|
||||
["an empty anchor", `<a href="/#">x</a>`],
|
||||
["a new tab", `<a href="/#alvo" target="_blank">x</a>`],
|
||||
["an id that does not exist", `<a href="/#nada">x</a>`],
|
||||
["a malformed percent-encoding", `<a href="/#%E0%A4%A">x</a>`],
|
||||
["no link at all", `<p>x</p>`],
|
||||
])("returns null for %s", (_label, markup) => {
|
||||
const event = clickOn(
|
||||
`${markup}<section id="alvo"></section>`,
|
||||
markup.startsWith("<a") ? "a" : "p",
|
||||
);
|
||||
|
||||
expect(samePageHashTarget(event)).toBeNull();
|
||||
});
|
||||
|
||||
it("handles target=_self like a plain link", () => {
|
||||
const event = clickOn(
|
||||
`<a href="/#alvo" target="_self">x</a><section id="alvo"></section>`,
|
||||
"a",
|
||||
);
|
||||
|
||||
expect(samePageHashTarget(event)?.target.id).toBe("alvo");
|
||||
});
|
||||
|
||||
it("ignores a click whose target is not an element", () => {
|
||||
const event = new MouseEvent("click", { bubbles: true });
|
||||
Object.defineProperty(event, "target", { value: document });
|
||||
|
||||
expect(samePageHashTarget(event)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("anchorTop", () => {
|
||||
const scenes = () => {
|
||||
document.body.innerHTML = `
|
||||
@@ -467,6 +369,24 @@ describe("useCinematicScroll", () => {
|
||||
expect(lenis.raf).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("eases the anchor travel in and out: slow at both ends, exactly half way at the middle, from 0 to 1", async () => {
|
||||
await mount();
|
||||
const lenis = mockLenis[0];
|
||||
|
||||
act(() => {
|
||||
(document.querySelector('a[href="/#projects"]') as HTMLElement).click();
|
||||
});
|
||||
const { easing } = lenis.scrollTo.mock.calls[0][1] as {
|
||||
easing: (t: number) => number;
|
||||
};
|
||||
|
||||
expect(easing(0)).toBe(0);
|
||||
expect(easing(0.25)).toBeCloseTo(0.0625, 9);
|
||||
expect(easing(0.5)).toBeCloseTo(0.5, 9);
|
||||
expect(easing(0.75)).toBeCloseTo(0.9375, 9);
|
||||
expect(easing(1)).toBe(1);
|
||||
});
|
||||
|
||||
it("without Lenis (touch) a far anchor is an instant jump and a near one is a native smooth scroll", async () => {
|
||||
mockMedia(["(pointer: coarse)"]);
|
||||
await mount();
|
||||
|
||||
Reference in new issue
Block a user