@@ -796,6 +796,65 @@ const Hooks = {
796796 updateStrength ( ) ;
797797 } ,
798798 } ,
799+ CandidatesScroll : {
800+ mounted ( ) {
801+ this . handleEvent ( "scroll_to_candidate" , ( { index } ) => {
802+ const candidateElement = document . querySelector ( `#candidate-${ index } ` ) ;
803+ if ( candidateElement ) {
804+ candidateElement . scrollIntoView ( {
805+ behavior : "instant" ,
806+ block : "start" ,
807+ inline : "nearest"
808+ } ) ;
809+ }
810+ } ) ;
811+
812+ // Observe candidate elements to update current index based on scroll position
813+ this . setupScrollObserver ( ) ;
814+ } ,
815+
816+ setupScrollObserver ( ) {
817+ if ( this . observer ) {
818+ this . observer . disconnect ( ) ;
819+ }
820+
821+ this . observer = new IntersectionObserver (
822+ ( entries ) => {
823+ entries . forEach ( ( entry ) => {
824+ if ( entry . isIntersecting && entry . intersectionRatio > 0.5 ) {
825+ const candidateId = entry . target . id ;
826+ const index = candidateId . split ( '-' ) [ 1 ] ;
827+ if ( index !== undefined ) {
828+ // Update the sidebar selection without triggering a scroll
829+ this . pushEvent ( "update_current_index_silent" , { index : parseInt ( index ) } ) ;
830+ }
831+ }
832+ } ) ;
833+ } ,
834+ {
835+ root : null ,
836+ rootMargin : "-20% 0px -20% 0px" ,
837+ threshold : [ 0.5 ]
838+ }
839+ ) ;
840+
841+ // Observe all candidate elements
842+ document . querySelectorAll ( '[id^="candidate-"]' ) . forEach ( ( el ) => {
843+ this . observer . observe ( el ) ;
844+ } ) ;
845+ } ,
846+
847+ updated ( ) {
848+ // Re-setup observer when candidates are updated
849+ this . setupScrollObserver ( ) ;
850+ } ,
851+
852+ destroyed ( ) {
853+ if ( this . observer ) {
854+ this . observer . disconnect ( ) ;
855+ }
856+ } ,
857+ } ,
799858} satisfies Record < string , Partial < ViewHook > & Record < string , unknown > > ;
800859
801860// Accessible focus handling
0 commit comments