pstream is dead; long live pstream
taciturnaxolotl.github.io/pstream-ng/
1/**
2 * Scrolls an element into view with configurable options
3 * @param selector - CSS selector string, Element, or null
4 * @param options - Scroll options
5 * @returns void (always returns, even if element not found)
6 */
7export function scrollToElement(
8 selector: string | Element | null,
9 options?: {
10 behavior?: ScrollBehavior;
11 block?: ScrollLogicalPosition;
12 inline?: ScrollLogicalPosition;
13 offset?: number; // Additional offset in pixels (positive = scroll down more)
14 delay?: number; // Delay in milliseconds before scrolling (useful when element needs to render)
15 },
16): void {
17 const {
18 behavior = "smooth",
19 block = "start",
20 inline = "nearest",
21 offset = 0,
22 delay = 0,
23 } = options || {};
24
25 const scroll = (): void => {
26 let element: Element | null = null;
27
28 if (selector === null) {
29 return;
30 }
31
32 if (typeof selector === "string") {
33 element = document.querySelector(selector);
34 } else {
35 element = selector;
36 }
37
38 if (!element) {
39 return;
40 }
41
42 if (offset === 0) {
43 // Use native scrollIntoView when no offset is needed
44 element.scrollIntoView({ behavior, block, inline });
45 return;
46 }
47
48 // Custom scroll with offset
49 const elementRect = element.getBoundingClientRect();
50 const absoluteElementTop = elementRect.top + window.pageYOffset;
51 const offsetPosition = absoluteElementTop - offset;
52
53 window.scrollTo({
54 top: offsetPosition,
55 behavior,
56 });
57 };
58
59 if (delay > 0) {
60 setTimeout(() => {
61 scroll();
62 }, delay);
63 return;
64 }
65
66 scroll();
67}
68
69/**
70 * Scrolls to an element by hash (useful for hash navigation)
71 * @param hash - Hash string (with or without #)
72 * @param options - Scroll options
73 * @returns void (always returns, even if element not found)
74 */
75export function scrollToHash(
76 hash: string,
77 options?: {
78 behavior?: ScrollBehavior;
79 block?: ScrollLogicalPosition;
80 inline?: ScrollLogicalPosition;
81 offset?: number;
82 delay?: number;
83 },
84): void {
85 const normalizedHash = hash.startsWith("#") ? hash : `#${hash}`;
86 scrollToElement(normalizedHash, options);
87}