File size: 2,360 Bytes
5012205
 
 
 
 
 
 
 
d8c725b
5012205
 
 
 
 
d8c725b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5012205
d8c725b
 
 
 
 
 
 
 
 
 
 
 
 
 
5012205
 
d8c725b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5012205
 
d8c725b
5012205
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { useEffect, useRef, type RefObject } from 'react';

export function useScrollToBottom(): [
  RefObject<HTMLDivElement>,
  RefObject<HTMLDivElement>,
] {
  const containerRef = useRef<HTMLDivElement>(null);
  const endRef = useRef<HTMLDivElement>(null);
  const isUserScrollingRef = useRef(false);

  useEffect(() => {
    const container = containerRef.current;
    const end = endRef.current;

    if (!container || !end) return;

    // Initial scroll to bottom
    setTimeout(() => {
      end.scrollIntoView({ behavior: 'instant', block: 'end' });
    }, 100);

    // Track if user has manually scrolled up
    const handleScroll = () => {
      if (!container) return;
      
      const { scrollTop, scrollHeight, clientHeight } = container;
      const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
      
      // If user is scrolled up, mark as manually scrolling
      isUserScrollingRef.current = distanceFromBottom > 100;
    };

    // Handle mutations
    const observer = new MutationObserver((mutations) => {
      if (!container || !end) return;

      // Check if mutation is related to expand/collapse
      const isToggleSection = mutations.some(mutation => {
        // Check if the target or parent is a motion-div (expanded content)
        let target = mutation.target as HTMLElement;
        let isExpand = false;
        
        while (target && target !== container) {
          if (target.classList?.contains('motion-div')) {
            isExpand = true;
            break;
          }
          target = target.parentElement as HTMLElement;
        }
        return isExpand;
      });

      // Don't scroll for expand/collapse actions
      if (isToggleSection) return;

      // Only auto-scroll if user hasn't manually scrolled up
      if (!isUserScrollingRef.current) {
        // For new messages, use smooth scrolling
        end.scrollIntoView({ behavior: 'smooth', block: 'end' });
      }
    });

    observer.observe(container, {
      childList: true,
      subtree: true,
    });

    // Add scroll event listener
    container.addEventListener('scroll', handleScroll);

    return () => {
      observer.disconnect();
      container.removeEventListener('scroll', handleScroll);
    };
  }, []);

  return [containerRef, endRef] as [RefObject<HTMLDivElement>, RefObject<HTMLDivElement>];
}