@@ -27,6 +27,8 @@ export class Segment implements ComponentInterface {
2727 // Value before the segment is dragged
2828 private valueBeforeGesture ?: SegmentValue ;
2929
30+ private segmentViewEl ?: HTMLIonSegmentViewElement | null = null ;
31+
3032 @Element ( ) el ! : HTMLIonSegmentElement ;
3133
3234 @State ( ) activated = false ;
@@ -142,6 +144,12 @@ export class Segment implements ComponentInterface {
142144
143145 connectedCallback ( ) {
144146 this . emitStyle ( ) ;
147+
148+ this . segmentViewEl = this . getSegmentView ( ) ;
149+ }
150+
151+ disconnectedCallback ( ) {
152+ this . segmentViewEl = null ;
145153 }
146154
147155 componentWillLoad ( ) {
@@ -323,6 +331,60 @@ export class Segment implements ComponentInterface {
323331 }
324332 }
325333
334+ private getSegmentView ( ) {
335+ const buttons = this . getButtons ( ) ;
336+ // Get the first button with a contentId
337+ const firstContentId = buttons . find ( ( button : HTMLIonSegmentButtonElement ) => button . contentId ) ;
338+ // Get the segment content with an id matching the button's contentId
339+ const segmentContent = document . querySelector ( `ion-segment-content[id="${ firstContentId ?. contentId } "]` ) ;
340+ // Return the segment view for that matching segment content
341+ return segmentContent ?. closest ( 'ion-segment-view' ) ;
342+ }
343+
344+ @Listen ( 'ionSegmentViewScroll' , { target : 'body' } )
345+ handleSegmentViewScroll ( ev : CustomEvent ) {
346+ const dispatchedFrom = ev . target as HTMLElement ;
347+ const segmentViewEl = this . segmentViewEl as EventTarget ;
348+ const segmentEl = this . el ;
349+
350+ // Only update the indicator if the event was dispatched from the segment view
351+ // containing the segment contents that matches this segment's buttons
352+ if ( ev . composedPath ( ) . includes ( segmentViewEl ) || dispatchedFrom ?. contains ( segmentEl ) ) {
353+ const buttons = this . getButtons ( ) ;
354+
355+ // If no buttons are found or there is no value set then do nothing
356+ if ( ! buttons . length || this . value === undefined ) return ;
357+
358+ const index = buttons . findIndex ( ( button ) => button . value === this . value ) ;
359+ const current = buttons [ index ] ;
360+ const indicatorEl = this . getIndicator ( current ) ;
361+
362+ const { scrollDirection, scrollDistance } = ev . detail ;
363+
364+ // Transform the indicator element to match the scroll of the segment view.
365+ if ( indicatorEl ) {
366+ indicatorEl . style . transition = 'transform 0.3s ease-out' ;
367+
368+ // Get dimensions of the segment and the button
369+ const segmentRect = segmentEl . getBoundingClientRect ( ) ;
370+ const buttonRect = current . getBoundingClientRect ( ) ;
371+
372+ // Calculate the potential transform value based on scroll direction
373+ const transformValue = scrollDirection === 'left' ? - scrollDistance : scrollDistance ;
374+
375+ // Calculate the max allowed transformation (indicator should not move beyond the segment boundaries)
376+ const maxTransform = segmentRect . width - buttonRect . width ;
377+ const minTransform = 0 ;
378+
379+ // Clamp the transform value to ensure it doesn't go out of bounds
380+ const clampedTransform = Math . max ( minTransform , Math . min ( transformValue , maxTransform ) ) ;
381+
382+ // Apply the clamped transform value to the indicator element
383+ indicatorEl . style . transform = `translate3d(${ clampedTransform } px, 0, 0)` ;
384+ }
385+ }
386+ }
387+
326388 /**
327389 * Finds the related segment view and sets its current content
328390 * based on the selected segment button. This method
0 commit comments