33import { tString , useLanguage } from '@/intl/client' ;
44import { tcls } from '@/lib/tailwind' ;
55import * as React from 'react' ;
6+ import { useScrollListener } from '../hooks/useScrollListener' ;
67import { Button } from './Button' ;
78
89/**
@@ -46,63 +47,61 @@ export function ScrollContainer(props: ScrollContainerProps) {
4647
4748 const language = useLanguage ( ) ;
4849
49- React . useEffect ( ( ) => {
50+ useScrollListener ( ( ) => {
5051 const container = containerRef . current ;
5152 if ( ! container ) {
5253 return ;
5354 }
5455
55- // Update scroll position on scroll using requestAnimationFrame
56- const scrollListener : EventListener = ( ) => {
57- requestAnimationFrame ( ( ) => {
58- setScrollPosition (
59- orientation === 'horizontal' ? container . scrollLeft : container . scrollTop
60- ) ;
61- } ) ;
62- } ;
63- container . addEventListener ( 'scroll' , scrollListener ) ;
56+ setScrollPosition (
57+ orientation === 'horizontal' ? container . scrollLeft : container . scrollTop
58+ ) ;
59+ } , containerRef ) ;
60+
61+ React . useEffect ( ( ) => {
62+ const container = containerRef . current ;
63+ if ( ! container ) {
64+ return ;
65+ }
6466
6567 // Update max scroll position using resize observer
66- const resizeObserver = new ResizeObserver ( ( entries ) => {
67- const containerEntry = entries . find ( ( i ) => i . target === containerRef . current ) ;
68- if ( containerEntry ) {
68+ const ro = new ResizeObserver ( ( entries ) => {
69+ const [ entry ] = entries ;
70+ if ( entry ) {
6971 setScrollSize (
7072 orientation === 'horizontal'
71- ? containerEntry . target . scrollWidth - containerEntry . target . clientWidth - 1
72- : containerEntry . target . scrollHeight -
73- containerEntry . target . clientHeight -
74- 1
73+ ? entry . target . scrollWidth - entry . target . clientWidth - 1
74+ : entry . target . scrollHeight - entry . target . clientHeight - 1
7575 ) ;
7676 }
7777 } ) ;
78- resizeObserver . observe ( container ) ;
7978
80- return ( ) => {
81- container . removeEventListener ( 'scroll' , scrollListener ) ;
82- resizeObserver . disconnect ( ) ;
83- } ;
79+ ro . observe ( container ) ;
80+
81+ return ( ) => ro . disconnect ( ) ;
8482 } , [ orientation ] ) ;
8583
86- // Scroll to the active item
8784 React . useEffect ( ( ) => {
8885 const container = containerRef . current ;
89- if ( ! container || ! activeId ) {
86+ if ( ! container ) {
9087 return ;
9188 }
92- const activeItem = container . querySelector ( `# ${ CSS . escape ( activeId ) } ` ) ;
93- if ( activeItem ) {
94- activeItem . scrollIntoView ( {
95- inline : 'center' ,
96- block : 'center' ,
97- } ) ;
89+ if ( ! activeId ) {
90+ return ;
91+ }
92+ const activeItem = document . getElementById ( activeId ) ;
93+ if ( ! activeItem || ! container . contains ( activeItem ) ) {
94+ return ;
9895 }
96+ scrollToElementInContainer ( activeItem , container ) ;
9997 } , [ activeId ] ) ;
10098
10199 const scrollFurther = ( ) => {
102100 const container = containerRef . current ;
103101 if ( ! container ) {
104102 return ;
105103 }
104+
106105 container . scrollTo ( {
107106 top : orientation === 'vertical' ? scrollPosition + container . clientHeight : undefined ,
108107 left : orientation === 'horizontal' ? scrollPosition + container . clientWidth : undefined ,
@@ -115,6 +114,7 @@ export function ScrollContainer(props: ScrollContainerProps) {
115114 if ( ! container ) {
116115 return ;
117116 }
117+
118118 container . scrollTo ( {
119119 top : orientation === 'vertical' ? scrollPosition - container . clientHeight : undefined ,
120120 left : orientation === 'horizontal' ? scrollPosition - container . clientWidth : undefined ,
@@ -194,3 +194,25 @@ export function ScrollContainer(props: ScrollContainerProps) {
194194 </ div >
195195 ) ;
196196}
197+
198+ /**
199+ * Scroll to an element in a container.
200+ */
201+ function scrollToElementInContainer ( element : HTMLElement , container : HTMLElement ) {
202+ const containerRect = container . getBoundingClientRect ( ) ;
203+ const rect = element . getBoundingClientRect ( ) ;
204+
205+ return container . scrollTo ( {
206+ top :
207+ container . scrollTop +
208+ ( rect . top - containerRect . top ) -
209+ container . clientHeight / 2 +
210+ rect . height / 2 ,
211+ left :
212+ container . scrollLeft +
213+ ( rect . left - containerRect . left ) -
214+ container . clientWidth / 2 +
215+ rect . width / 2 ,
216+ behavior : 'smooth' ,
217+ } ) ;
218+ }
0 commit comments