Repository: ionic-team/ionic-framework
File: core/src/components/segment-view/segment-view.tsx (TypeScript)

Code before:
  @Element() el!: HTMLElement;

  /**
   * If `true`, the segment view cannot be interacted with.
   */
  @Prop() disabled = false;

  /**
   * @internal
   *
   * If `true`, the segment view is scrollable.
   * If `false`, pointer events will be disabled. This is to prevent issues with
   * quickly scrolling after interacting with a segment button.
   */
  @State() isManualScroll?: boolean;

  /**
   * Emitted when the segment view is scrolled.
   */
  @Event() ionSegmentViewScroll!: EventEmitter<SegmentViewScrollEvent>;

  @Listen('scroll')
  handleScroll(ev: Event) {
    const { scrollLeft, scrollWidth, clientWidth } = ev.target as HTMLElement;
    const isRTL = window.getComputedStyle(this.el).direction === 'rtl';
    const scrollRatio = (isRTL ? -1 : 1) * (scrollLeft / (scrollWidth - clientWidth));

    this.ionSegmentViewScroll.emit({
      scrollRatio,
      isManualScroll: this.isManualScroll ?? true,
    });

    // Reset the timeout to check for scroll end
    this.resetScrollEndTimeout();
  }

  /**
   * Handle touch start event to know when the user is actively dragging the segment view.
   */
  @Listen('touchstart')
  handleScrollStart() {
    if (this.scrollEndTimeout) {
      clearTimeout(this.scrollEndTimeout);
      this.scrollEndTimeout = null;
    }

    this.isTouching = true;
  }

  /**
   * Handle touch end event to know when the user is no longer dragging the segment view.

Review comment (refactor):
Please normalize the scroll position using our normal conventions. 

Example: 
```typescript
const max = scrollWidth - clientWidth; 
const logical = isRTL(this.el) ? (max - scrollLeft) : scrollLeft; 
const scrollRatio = max > 0 ? clamp(0, logical / max, 1) : 0;
```

 This avoids negatives, handles RTL consistently, and keeps `nextIndex` in-bounds. You can import isRTL from `@utils/rtl` and clamp from `@utils/helpers` for consistency with other components.

Code after:

  @Element() el!: HTMLElement;

  /**
   * If `true`, the segment view cannot be interacted with.
   */
  @Prop() disabled = false;

  /**
   * @internal
   *
   * If `true`, the segment view is scrollable.
   * If `false`, pointer events will be disabled. This is to prevent issues with
   * quickly scrolling after interacting with a segment button.
   */
  @State() isManualScroll?: boolean;

  /**
   * Emitted when the segment view is scrolled.
   */
  @Event() ionSegmentViewScroll!: EventEmitter<SegmentViewScrollEvent>;

  @Listen('scroll')
  handleScroll(ev: Event) {
    const { scrollLeft, scrollWidth, clientWidth } = ev.target as HTMLElement;
    const max = scrollWidth - clientWidth;
    const scrollRatio = (isRTL(this.el) ? -1 : 1) * (scrollLeft / max);

    this.ionSegmentViewScroll.emit({
      scrollRatio,
      isManualScroll: this.isManualScroll ?? true,
    });

    // Reset the timeout to check for scroll end
    this.resetScrollEndTimeout();
  }

  /**
   * Handle touch start event to know when the user is actively dragging the segment view.
   */
  @Listen('touchstart')
  handleScrollStart() {
    if (this.scrollEndTimeout) {
      clearTimeout(this.scrollEndTimeout);
      this.scrollEndTimeout = null;
    }

    this.isTouching = true;
  }

  /**