{"version":3,"file":"SlidingNumber.mjs","sources":["../../../src/components/trackpad/SlidingNumber.ts"],"sourcesContent":["import { ScrollSpring } from './ScrollSpring';\n\n/**\n * Options for configuring the SlidingNumber behavior\n */\nexport interface SlidingNumberOptions {\n    /** Whether to constrain the value between min and max. Default: true */\n    constrain?: boolean;\n    /** Percentage of overflow allowed when dragging beyond constraints. Default: 0 */\n    constrainPercent?: number;\n    /** Maximum speed the value can slide. Default: 400 */\n    maxSpeed?: number;\n    /** Custom easing function for constraint bouncing. Default: ScrollSpring */\n    ease?: ConstrainEase;\n}\n\n/**\n * Interface for custom easing functions used when bouncing against constraints\n */\nexport interface ConstrainEase {\n    /** Whether the easing has completed */\n    done: boolean;\n    /** Target value to ease towards */\n    to: number;\n    /** Initialize the easing with current state */\n    start(speed: number, pos: number, to: number): void;\n    /** Calculate next eased value */\n    update(): number;\n}\n\n/**\n * A utility class that manages sliding/scrolling number values with physics-based momentum and constraints.\n * Useful for implementing scrolling, slider controls, or any UI element that needs smooth, physics-based movement.\n *\n * Features:\n * - Momentum-based sliding with speed control\n * - Constraint boundaries with optional elastic overflow\n * - Customizable easing for constraint bouncing\n *\n * @example\n * ```typescript\n * // Create a sliding number for a scroll container\n * const slider = new SlidingNumber({\n *     constrain: true,\n *     maxSpeed: 400,\n *     constrainPercent: 0.2\n * });\n *\n * // Set the boundaries\n * slider.min = 0;\n * slider.max = -1000;\n *\n * // Handle drag start\n * onDragStart(e) {\n *     slider.grab(e.position);\n * }\n *\n * // Handle drag move\n * onDragMove(e) {\n *     slider.hold(e.position);\n * }\n *\n * // Update loop\n * ticker.add(() => {\n *     slider.slide();\n *     container.y = slider.value;\n * });\n * ```\n */\nexport class SlidingNumber {\n    protected position = 0;\n    /** The maximum speed at which the sliding number can move. */\n    public maxSpeed: number;\n    /** When dragging this number represents the percentage that will be allowed to move outside the min and max values. */\n    public constrainPercent: number;\n    /** Whether the sliding number is constrained to the min and max values. */\n    public constrain: boolean;\n    /** The minimum value the sliding number can take. */\n    public min = 0;\n    /** The maximum value the sliding number can take. */\n    public max = 0;\n\n    protected _ease: ConstrainEase;\n\n    protected _offset = 0;\n    protected _prev = 0;\n    protected _speed = 0;\n    protected _hasStopped: boolean = true;\n\n    protected _targetSpeed = 0;\n    protected _speedChecker = 0;\n    protected _grab = 0;\n    protected _activeEase: ConstrainEase | null = null;\n\n    constructor(options: SlidingNumberOptions = {}) {\n        this.constrain = options.constrain ?? true;\n        this.maxSpeed = options.maxSpeed ?? 400;\n        this._ease = options.ease ?? new ScrollSpring();\n        this.constrainPercent = options.constrainPercent ?? 0;\n    }\n\n    /**\n     * Sets the position of the sliding number.\n     * This will also reset the speed to 0.\n     * @param n The new position value.\n     */\n    set value(n: number) {\n        this._speed = 0;\n        this.position = n;\n    }\n\n    /**\n     * Gets the current position of the sliding number.\n     * @returns The current position value.\n     */\n    get value(): number {\n        return this.position;\n    }\n\n    /**\n     * Initiates a grab/drag operation at the specified offset\n     * @param offset The initial grab position\n     */\n    grab(offset: number): void {\n        this._grab = offset;\n        this._offset = this.position - offset;\n        this._speedChecker = 0;\n        this._targetSpeed = this._speed = 0;\n        this._hasStopped = false;\n    }\n\n    /**\n     * Updates the position while being held/dragged\n     * @param newPosition The new position from the input device\n     */\n    hold(newPosition: number): void {\n        this._speedChecker++;\n\n        this.position = newPosition + this._offset;\n\n        if (this._speedChecker > 1) {\n            this._targetSpeed = this.position - this._prev;\n        }\n\n        this._speed += (this._targetSpeed - this._speed) / 2;\n\n        if (this._speed > this.maxSpeed) this._speed = this.maxSpeed;\n        else if (this._speed < -this.maxSpeed) this._speed = -this.maxSpeed;\n\n        this._prev = this.position;\n\n        if (this.constrain) {\n            // If constrain percentage is less than 0 we want to not allow any movement\n            if (this.constrainPercent < 0) {\n                this.position = 0;\n                this._speed = 0;\n                this._hasStopped = true;\n            } else if (this.constrainPercent === 0) {\n                if (this.position > this.min) {\n                    this.position = this.min;\n                } else if (this.position < this.max) {\n                    this.position = this.max;\n                }\n            } else if (this.position > this.min) {\n                this.position -= (this.position - this.min) / (1 + this.constrainPercent);\n            } else if (this.position < this.max) {\n                this.position += (this.max - this.position) / (1 + this.constrainPercent);\n            }\n        }\n    }\n\n    /**\n     * Updates the sliding animation based on current momentum\n     * @param instant If true, snaps immediately to constraints without easing\n     */\n    slide(instant = false): void {\n        if (this._hasStopped) return;\n\n        if (this.constrain) {\n            this._updateConstrain(instant);\n        } else {\n            this._updateDefault();\n        }\n    }\n\n    protected _updateDefault(): void {\n        this._speed *= 0.9;\n        this.position += this._speed;\n\n        if ((this._speed < 0 ? this._speed * -1 : this._speed) < 0.01) {\n            this._hasStopped = true;\n        }\n\n        if (this.position > this.min) {\n            this.position = this.min;\n            this._hasStopped = true;\n        } else if (this.position < this.max) {\n            this.position = this.max;\n            this._hasStopped = true;\n        }\n    }\n\n    protected _updateConstrain(instant = false): void {\n        const max: number = this.max;\n\n        if (instant) {\n            if (this.position > this.min) {\n                this.position = this.min;\n            } else if (this.position < this.max) {\n                this.position = this.max;\n            }\n        } else if (this.position > this.min || this.position < max || this._activeEase) {\n            if (!this._activeEase) {\n                this._activeEase = this._ease;\n\n                if (this.position > this.min) {\n                    this._activeEase.start(this._speed, this.position, this.min);\n                } else {\n                    this._activeEase.start(this._speed, this.position, max);\n                }\n            }\n\n            this.position = this._activeEase.update();\n\n            if (this._activeEase.done) {\n                this.position = this._activeEase.to;\n                this._speed = 0;\n                this._activeEase = null;\n            }\n        } else {\n            this._updateDefault();\n        }\n    }\n}\n"],"names":[],"mappings":"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"}