pull/14862/merge
José Pablo Ramírez Vargas 3 months ago committed by GitHub
commit 010dd2974e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -20,6 +20,18 @@ export interface Spring<T> extends Readable<T> {
stiffness: number; stiffness: number;
} }
/**
* Defines the primitive data types that Spring and Tween objects can calculate on.
*/
export type MotionPrimitive = number | Date;
/**
* Defines the type of objects Spring and Tween objects can work on.
*/
export interface MotionRecord {
[x: string]: MotionPrimitive | MotionRecord | (MotionPrimitive | MotionRecord)[];
}
/** /**
* A wrapper for a value that behaves in a spring-like fashion. Changes to `spring.target` will cause `spring.current` to * A wrapper for a value that behaves in a spring-like fashion. Changes to `spring.target` will cause `spring.current` to
* move towards it over time, taking account of the `spring.stiffness` and `spring.damping` parameters. * move towards it over time, taking account of the `spring.stiffness` and `spring.damping` parameters.
@ -36,7 +48,7 @@ export interface Spring<T> extends Readable<T> {
* ``` * ```
* @since 5.8.0 * @since 5.8.0
*/ */
export class Spring<T> { export class Spring<T extends MotionRecord[string]> {
constructor(value: T, options?: SpringOpts); constructor(value: T, options?: SpringOpts);
/** /**
@ -53,7 +65,7 @@ export class Spring<T> {
* </script> * </script>
* ``` * ```
*/ */
static of<U>(fn: () => U, options?: SpringOpts): Spring<U>; static of<U extends MotionRecord[string]>(fn: () => U, options?: SpringOpts): Spring<U>;
/** /**
* Sets `spring.target` to `value` and returns a `Promise` that resolves if and when `spring.current` catches up to it. * Sets `spring.target` to `value` and returns a `Promise` that resolves if and when `spring.current` catches up to it.

@ -1,6 +1,6 @@
/** @import { Task } from '#client' */ /** @import { Task } from '#client' */
/** @import { SpringOpts, SpringUpdateOpts, TickContext } from './private.js' */ /** @import { SpringOpts, SpringUpdateOpts, TickContext } from './private.js' */
/** @import { Spring as SpringStore } from './public.js' */ /** @import { MotionRecord, Spring as SpringStore } from './public.js' */
import { writable } from '../store/shared/index.js'; import { writable } from '../store/shared/index.js';
import { loop } from '../internal/client/loop.js'; import { loop } from '../internal/client/loop.js';
import { raf } from '../internal/client/timing.js'; import { raf } from '../internal/client/timing.js';
@ -58,7 +58,7 @@ function tick_spring(ctx, last_value, current_value, target_value) {
* The spring function in Svelte creates a store whose value is animated, with a motion that simulates the behavior of a spring. This means when the value changes, instead of transitioning at a steady rate, it "bounces" like a spring would, depending on the physics parameters provided. This adds a level of realism to the transitions and can enhance the user experience. * The spring function in Svelte creates a store whose value is animated, with a motion that simulates the behavior of a spring. This means when the value changes, instead of transitioning at a steady rate, it "bounces" like a spring would, depending on the physics parameters provided. This adds a level of realism to the transitions and can enhance the user experience.
* *
* @deprecated Use [`Spring`](https://svelte.dev/docs/svelte/svelte-motion#Spring) instead * @deprecated Use [`Spring`](https://svelte.dev/docs/svelte/svelte-motion#Spring) instead
* @template [T=any] * @template {MotionRecord[string]} [T=any]
* @param {T} [value] * @param {T} [value]
* @param {SpringOpts} [opts] * @param {SpringOpts} [opts]
* @returns {SpringStore<T>} * @returns {SpringStore<T>}
@ -164,7 +164,7 @@ export function spring(value, opts = {}) {
* <input type="range" bind:value={spring.target} /> * <input type="range" bind:value={spring.target} />
* <input type="range" bind:value={spring.current} disabled /> * <input type="range" bind:value={spring.current} disabled />
* ``` * ```
* @template T * @template {MotionRecord[string]} T
* @since 5.8.0 * @since 5.8.0
*/ */
export class Spring { export class Spring {
@ -172,9 +172,10 @@ export class Spring {
#damping = source(0.8); #damping = source(0.8);
#precision = source(0.01); #precision = source(0.01);
#current = source(/** @type {T} */ (undefined)); #current;
#target = source(/** @type {T} */ (undefined)); #target;
// @ts-expect-error Undefined doesn't satisfy the constraint of T.
#last_value = /** @type {T} */ (undefined); #last_value = /** @type {T} */ (undefined);
#last_time = 0; #last_time = 0;
@ -192,7 +193,8 @@ export class Spring {
* @param {SpringOpts} [options] * @param {SpringOpts} [options]
*/ */
constructor(value, options = {}) { constructor(value, options = {}) {
this.#current.v = this.#target.v = value; this.#current = source(value);
this.#target = source(value);
if (typeof options.stiffness === 'number') this.#stiffness.v = clamp(options.stiffness, 0, 1); if (typeof options.stiffness === 'number') this.#stiffness.v = clamp(options.stiffness, 0, 1);
if (typeof options.damping === 'number') this.#damping.v = clamp(options.damping, 0, 1); if (typeof options.damping === 'number') this.#damping.v = clamp(options.damping, 0, 1);
@ -212,7 +214,7 @@ export class Spring {
* const spring = Spring.of(() => number); * const spring = Spring.of(() => number);
* </script> * </script>
* ``` * ```
* @template U * @template {MotionRecord[string]} U
* @param {() => U} fn * @param {() => U} fn
* @param {SpringOpts} [options] * @param {SpringOpts} [options]
*/ */

@ -1,5 +1,5 @@
/** @import { Task } from '../internal/client/types' */ /** @import { Task } from '../internal/client/types' */
/** @import { Tweened } from './public' */ /** @import { MotionRecord, Tweened } from './public' */
/** @import { TweenedOptions } from './private' */ /** @import { TweenedOptions } from './private' */
import { writable } from '../store/shared/index.js'; import { writable } from '../store/shared/index.js';
import { raf } from '../internal/client/timing.js'; import { raf } from '../internal/client/timing.js';
@ -171,11 +171,15 @@ export function tweened(value, defaults = {}) {
* <input type="range" bind:value={tween.target} /> * <input type="range" bind:value={tween.target} />
* <input type="range" bind:value={tween.current} disabled /> * <input type="range" bind:value={tween.current} disabled />
* ``` * ```
* @template T *
* Refer to the `MotionRecord` type to understand all possible value types that Tween can handle.
* @template {MotionRecord[string]} T
* @since 5.8.0 * @since 5.8.0
*/ */
export class Tween { export class Tween {
// @ts-expect-error Undefined doesn't satisfy the constraint of T.
#current = source(/** @type {T} */ (undefined)); #current = source(/** @type {T} */ (undefined));
// @ts-expect-error Undefined doesn't satisfy the constraint of T.
#target = source(/** @type {T} */ (undefined)); #target = source(/** @type {T} */ (undefined));
/** @type {TweenedOptions<T>} */ /** @type {TweenedOptions<T>} */
@ -206,7 +210,9 @@ export class Tween {
* const tween = Tween.of(() => number); * const tween = Tween.of(() => number);
* </script> * </script>
* ``` * ```
* @template U *
* Refer to the `MotionRecord` type to understand all possible value types that Tween can handle.
* @template {MotionRecord[string]} U
* @param {() => U} fn * @param {() => U} fn
* @param {TweenedOptions<U>} [options] * @param {TweenedOptions<U>} [options]
*/ */

Loading…
Cancel
Save