feat: light a chapter when its heading crosses 60% of the viewport
This commit is contained in:
@@ -32,10 +32,17 @@ export interface ActivationLineInput {
|
||||
visualViewportHeight: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A chapter becomes current when its heading's top crosses this fraction of
|
||||
* the visual viewport, measured from the top. At 60% the chapter lights up as
|
||||
* its heading settles into the reading zone, not after it has been read.
|
||||
*/
|
||||
export const ACTIVATION_LINE_VH = 0.6;
|
||||
|
||||
export const activationLineDocumentY = (input: ActivationLineInput): number =>
|
||||
input.scrollY +
|
||||
input.visualViewportOffsetTop +
|
||||
input.visualViewportHeight * 0.35;
|
||||
input.visualViewportHeight * ACTIVATION_LINE_VH;
|
||||
|
||||
export interface DocumentEndInput {
|
||||
scrollY: number;
|
||||
|
||||
@@ -73,9 +73,9 @@ test("passive scrolling replaces a stable fragment without stealing focus", asyn
|
||||
if (heading === null) throw new Error("Missing experience heading");
|
||||
const headingDocumentTop =
|
||||
heading.getBoundingClientRect().top + window.scrollY;
|
||||
// Place the heading just beyond the 35% activation line. Scroll offsets
|
||||
// Place the heading just beyond the 60% activation line. Scroll offsets
|
||||
// are integer-rounded in Chromium, so exact boundary equality is brittle.
|
||||
window.scrollTo(0, headingDocumentTop - window.innerHeight * 0.34);
|
||||
window.scrollTo(0, headingDocumentTop - window.innerHeight * 0.59);
|
||||
});
|
||||
|
||||
await expect(page).toHaveURL(`${distUrl}/#experience`, { timeout: 2000 });
|
||||
|
||||
@@ -20,14 +20,14 @@ const headings: readonly SectionHeadingGeometry[] = [
|
||||
];
|
||||
|
||||
describe("active section selection", () => {
|
||||
it("places the activation line at a literal 35 percent of the visual viewport", () => {
|
||||
it("places the activation line at a literal 60 percent of the visual viewport", () => {
|
||||
expect(
|
||||
activationLineDocumentY({
|
||||
scrollY: 200,
|
||||
visualViewportOffsetTop: 25,
|
||||
visualViewportHeight: 1000,
|
||||
}),
|
||||
).toBe(575);
|
||||
).toBe(825);
|
||||
});
|
||||
|
||||
it("forces document end within exactly two CSS pixels using current geometry", () => {
|
||||
@@ -60,7 +60,7 @@ describe("active section selection", () => {
|
||||
).toBe("start");
|
||||
});
|
||||
|
||||
it("selects the last heading at or above the literal 35 percent activation line", () => {
|
||||
it("selects the last heading at or above the activation line", () => {
|
||||
expect(
|
||||
selectActiveSection({
|
||||
headings,
|
||||
|
||||
Reference in New Issue
Block a user