forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseScrollEdges.ts
More file actions
54 lines (45 loc) · 1.76 KB
/
Copy pathuseScrollEdges.ts
File metadata and controls
54 lines (45 loc) · 1.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
'use client';
import { useCallback, useEffect, useRef, useState } from 'react';
import { scrollEdgesOf, type ScrollEdges } from '@/lib/scrollEdges';
/**
* Whether a scroller has content hidden above or below the visible area.
*
* Fades that mark "there is more this way" have to be told when there isn't:
* a top fade sitting over the first message, or a bottom fade over the last
* one, dims content for no reason and reads as a rendering fault rather than
* as an affordance.
*/
export function useScrollEdges<T extends HTMLElement>(): {
ref: React.RefObject<T | null>;
edges: ScrollEdges;
} {
const ref = useRef<T>(null);
// Both true at rest: an empty or unscrollable list has no hidden content in
// either direction, so neither fade should show before the first measure.
const [edges, setEdges] = useState<ScrollEdges>({ atTop: true, atBottom: true });
const measure = useCallback(() => {
const node = ref.current;
if (!node) return;
const next = scrollEdgesOf(node);
setEdges((prev) =>
prev.atTop === next.atTop && prev.atBottom === next.atBottom ? prev : next,
);
}, []);
useEffect(() => {
const node = ref.current;
if (!node) return;
measure();
node.addEventListener('scroll', measure, { passive: true });
// Content arriving changes whether there is anything to scroll to, and it
// arrives without a scroll event — a streaming reply grows the transcript
// under a stationary scroll position.
const observer = new ResizeObserver(measure);
observer.observe(node);
for (const child of Array.from(node.children)) observer.observe(child);
return () => {
node.removeEventListener('scroll', measure);
observer.disconnect();
};
}, [measure]);
return { ref, edges };
}