-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DEVPROD-11363: Support scrolling to different sections on Build Infor…
…mation page (#425)
- Loading branch information
Showing
17 changed files
with
339 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { useEffect, useState } from "react"; | ||
|
||
const findTopmostVisibleElement = ({ | ||
elements, | ||
scrollTop, | ||
}: { | ||
elements: HTMLElement[]; | ||
scrollTop: number; | ||
}) => { | ||
let minDistance = Number.MAX_VALUE; | ||
let minDistanceId = ""; | ||
|
||
elements.forEach((el) => { | ||
const currDistance = Math.abs(scrollTop - el.offsetTop); | ||
if (currDistance < minDistance) { | ||
minDistance = currDistance; | ||
minDistanceId = el.id; | ||
} | ||
}); | ||
|
||
return minDistanceId; | ||
}; | ||
|
||
/** | ||
* `useTopmostVisibleElement` is used to track the ID of the element that is visible on the screen and closest | ||
* to the top of the element with scrollContainerId. | ||
* @param obj - object representing arguments to `useTopmostVisibleElement` hook | ||
* @param obj.elements - list of elements from which to determine the topmost visible element | ||
* @param obj.scrollContainerId - the ID of the scroll container. Referencing the scroll container is necessary | ||
* because the hook listens on the "scroll" event. | ||
* @returns the ID of the topmost visible element (string) | ||
*/ | ||
export const useTopmostVisibleElement = ({ | ||
elements, | ||
scrollContainerId, | ||
}: { | ||
elements: HTMLElement[]; | ||
scrollContainerId: string; | ||
}) => { | ||
const [topmostVisibleElementId, setTopmostVisibleElementId] = useState(""); | ||
|
||
useEffect(() => { | ||
const scrollElement = document.getElementById( | ||
scrollContainerId, | ||
) as HTMLElement; | ||
|
||
const handleScroll = () => { | ||
const id = findTopmostVisibleElement({ | ||
scrollTop: scrollElement.scrollTop, | ||
elements, | ||
}); | ||
setTopmostVisibleElementId(id); | ||
}; | ||
|
||
scrollElement.addEventListener("scroll", handleScroll); | ||
return () => { | ||
scrollElement.removeEventListener("scroll", handleScroll); | ||
}; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [elements]); | ||
|
||
return topmostVisibleElementId; | ||
}; |
51 changes: 51 additions & 0 deletions
51
apps/spruce/src/hooks/useTopmostVisibleElement/useTopmostVisibleElement.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { act, renderHook, render } from "@evg-ui/lib/test_utils"; | ||
import { useTopmostVisibleElement } from "."; | ||
|
||
describe("useTopmostVisibleElement", () => { | ||
const scrollPage = (scrollContainerId: string, height: number) => { | ||
act(() => { | ||
const scrollElement = document.getElementById( | ||
scrollContainerId, | ||
) as HTMLElement; | ||
scrollElement.scrollTop = height; | ||
scrollElement.dispatchEvent(new window.Event("scroll")); | ||
}); | ||
}; | ||
|
||
it("should correctly detect the topmost visible element", async () => { | ||
const scrollContainerId = "scroll-container-id"; | ||
|
||
render( | ||
<div id={scrollContainerId}> | ||
<span id="span-1" /> | ||
<span id="span-2" /> | ||
</div>, | ||
); | ||
|
||
// JSDom doesn't actually support layouting HTML so scroll/offset positions must be mocked. | ||
const firstRefElement = document.getElementById("span-1") as HTMLElement; | ||
vi.spyOn(firstRefElement, "offsetTop", "get").mockImplementation(() => 0); | ||
|
||
const secondRefElement = document.getElementById("span-2") as HTMLElement; | ||
vi.spyOn(secondRefElement, "offsetTop", "get").mockImplementation( | ||
() => 500, | ||
); | ||
|
||
const elements = Array.from( | ||
document.querySelectorAll("span"), | ||
) as HTMLElement[]; | ||
|
||
const { result } = renderHook(() => | ||
useTopmostVisibleElement({ | ||
elements, | ||
scrollContainerId, | ||
}), | ||
); | ||
|
||
scrollPage(scrollContainerId, 408); | ||
expect(result.current).toBe("span-2"); | ||
|
||
scrollPage(scrollContainerId, 121); | ||
expect(result.current).toBe("span-1"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.