Repository: sst/opentui
File: packages/core/src/renderables/ScrollBar.ts (TypeScript)

Code before:
        }, 200)
      }, 500)
    }

    this.endArrow.onMouseUp = (event) => {
      event.preventDefault()
      clearInterval(endArrowMouseTimeout!)
    }
  }

  public set arrowOptions(options: ScrollBarOptions["arrowOptions"]) {
    Object.assign(this.startArrow, options)
    Object.assign(this.endArrow, options)
    this.requestRender()
  }

  public set thumbOptions(options: ScrollBarOptions["thumbOptions"]) {
    Object.assign(this.slider, { thumbColor: options?.backgroundColor })
    this.requestRender()
  }

  public set trackOptions(options: ScrollBarOptions["trackOptions"]) {
    Object.assign(this.slider, { trackColor: options?.backgroundColor })
    this.requestRender()
  }

  private updateSliderFromScrollState(): void {
    const trackSize = this.orientation === "vertical" ? this.slider.height : this.slider.width
    const scrollRange = Math.max(0, this._scrollSize - this._viewportSize)

    if (scrollRange === 0) {
      this.slider.thumbSize = trackSize
      this.slider.thumbPosition = 0
    } else {
      const sizeRatio = this._viewportSize / this._scrollSize
      this.slider.thumbSize = Math.max(1, Math.round(sizeRatio * trackSize))

      const positionRatio = this._scrollPosition / scrollRange
      this.slider.thumbPosition = Math.max(0, Math.min(1, positionRatio))
    }
  }

  public scrollBy(delta: number, unit: ScrollUnit = "absolute"): void {
    const multiplier =
      unit === "viewport"
        ? this.viewportSize
        : unit === "content"
          ? this.scrollSize
          : unit === "step"
            ? (this.scrollStep ?? 1)
            : 1

Review comment (suggestion):
these are just mapping single values `trackOptions.backgroundColor` to `trackColor: value` we could cut the middle out and just replace `trackOptions.backgroundColor` with `trackColor` ? same for the other

Code after:
    }

    this.endArrow.onMouseUp = (event) => {
      event.preventDefault()
      clearInterval(endArrowMouseTimeout!)
    }
  }

  public set arrowOptions(options: ScrollBarOptions["arrowOptions"]) {
    Object.assign(this.startArrow, options)
    Object.assign(this.endArrow, options)
    this.requestRender()
  }

  public set trackOptions(options: ScrollBarOptions["trackOptions"]) {
    Object.assign(this.slider, options)
    this.requestRender()
  }

  private updateSliderFromScrollState(): void {
    const trackSize = this.orientation === "vertical" ? this.slider.height : this.slider.width
    const scrollRange = Math.max(0, this._scrollSize - this._viewportSize)

    if (scrollRange === 0) {
      this.slider.thumbSize = trackSize
      this.slider.thumbPosition = 0
    } else {
      const sizeRatio = this._viewportSize / this._scrollSize
      this.slider.thumbSize = Math.max(1, Math.round(sizeRatio * trackSize))

      const positionRatio = this._scrollPosition / scrollRange
      this.slider.thumbPosition = Math.max(0, Math.min(1, positionRatio))
    }
  }

  public scrollBy(delta: number, unit: ScrollUnit = "absolute"): void {
    const multiplier =
      unit === "viewport"
        ? this.viewportSize
        : unit === "content"
          ? this.scrollSize
          : unit === "step"
            ? (this.scrollStep ?? 1)
            : 1

    const resolvedDelta = multiplier * delta
    this.scrollPosition += resolvedDelta
  }

  private recalculateVisibility(): void {
    if (!this._manualVisibility) {