Skip to content

Commit b76ea5f

Browse files
committed
wrestle with types
1 parent 72a309b commit b76ea5f

File tree

5 files changed

+159
-82
lines changed

5 files changed

+159
-82
lines changed

packages/svelte/src/motion/private.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ export interface SpringOpts {
1616
}
1717

1818
export interface SpringUpdateOpts {
19+
/**
20+
* @deprecated Only use this for the spring store; does nothing when set on the Spring class
21+
*/
1922
hard?: any;
23+
/**
24+
* @deprecated Only use this for the spring store; does nothing when set on the Spring class
25+
*/
2026
soft?: string | number | boolean;
2127
}
2228

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,83 @@
11
import { Readable } from '../store/public.js';
2-
import { SpringUpdateOpts, TweenedOptions, Updater } from './private.js';
2+
import { SpringUpdateOpts, TweenedOptions, Updater, SpringOpts } from './private.js';
33

4-
export interface SpringStore<T> extends Readable<T> {
5-
set: (new_value: T, opts?: SpringUpdateOpts) => Promise<void>;
4+
// TODO we do declaration merging here in order to not have a breaking change (renaming the Spring interface)
5+
// this means both the Spring class and the Spring interface are merged into one with some things only
6+
// existing on one side. In Svelte 6, remove the type definition and move the jsdoc onto the class in spring.js
7+
8+
export interface Spring<T> extends Readable<T> {
9+
set(new_value: T, opts?: SpringUpdateOpts): Promise<void>;
10+
/**
11+
* @deprecated Only exists on the Spring store
12+
*/
613
update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>;
714
precision: number;
815
damping: number;
916
stiffness: number;
1017
}
1118

12-
export interface TweenedStore<T> extends Readable<T> {
19+
/**
20+
* A wrapper for a value that behaves in a spring-like fashion. Changes to `spring.target` will cause `spring.current` to
21+
* move towards it over time, taking account of the `spring.stiffness` and `spring.damping` parameters.
22+
*
23+
* ```svelte
24+
* <script>
25+
* import { Spring } from 'svelte/motion';
26+
*
27+
* const spring = new Spring(0);
28+
* </script>
29+
*
30+
* <input type="range" bind:value={spring.target} />
31+
* <input type="range" bind:value={spring.current} disabled />
32+
* ```
33+
*/
34+
export class Spring<T> {
35+
constructor(value: T, options?: SpringOpts);
36+
37+
/**
38+
* Create a spring whose value is bound to the return value of `fn`. This must be called
39+
* inside an effect root (for example, during component initialisation).
40+
*
41+
* ```svelte
42+
* <script>
43+
* import { Spring } from 'svelte/motion';
44+
*
45+
* let { number } = $props();
46+
*
47+
* const spring = Spring.of(() => number);
48+
* </script>
49+
* ```
50+
*/
51+
static of<U>(fn: () => U, options?: SpringOpts): Spring<U>;
52+
53+
/**
54+
* Sets `spring.target` to `value` and returns a `Promise` that resolves if and when `spring.current` catches up to it.
55+
*
56+
* If `options.instant` is `true`, `spring.current` immediately matches `spring.target`.
57+
*
58+
* If `options.preserveMomentum` is provided, the spring will continue on its current trajectory for
59+
* the specified number of milliseconds. This is useful for things like 'fling' gestures.
60+
*/
61+
set(value: T, options?: { instant?: boolean; preserveMomentum?: number }): Promise<void>;
62+
63+
damping: number;
64+
precision: number;
65+
stiffness: number;
66+
/**
67+
* The end value of the spring.
68+
* This property only exists on the Spring class.
69+
*/
70+
target: T;
71+
/**
72+
* The current value of the spring.
73+
* This property only exists on the Spring class.
74+
*/
75+
get current(): T;
76+
}
77+
78+
export interface Tweened<T> extends Readable<T> {
1379
set(value: T, opts?: TweenedOptions<T>): Promise<void>;
1480
update(updater: Updater<T>, opts?: TweenedOptions<T>): Promise<void>;
1581
}
1682

17-
export * from './index.js';
83+
export { spring, tweened, Tween } from './index.js';

packages/svelte/src/motion/spring.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @import { Task } from '#client' */
22
/** @import { SpringOpts, SpringUpdateOpts, TickContext } from './private.js' */
3-
/** @import { SpringStore } from './public.js' */
3+
/** @import { Spring as SpringStore } from './public.js' */
44
import { writable } from '../store/shared/index.js';
55
import { loop } from '../internal/client/loop.js';
66
import { raf } from '../internal/client/timing.js';
@@ -182,7 +182,7 @@ export class Spring {
182182

183183
/**
184184
* @param {T} value
185-
* @param {{ stiffness?: number, damping?: number, precision?: number }} [options]
185+
* @param {SpringOpts} [options]
186186
*/
187187
constructor(value, options = {}) {
188188
this.#current.v = this.#target.v = value;
@@ -207,7 +207,7 @@ export class Spring {
207207
* ```
208208
* @template U
209209
* @param {() => U} fn
210-
* @param {{ stiffness?: number, damping?: number, precision?: number }} [options]
210+
* @param {SpringOpts} [options]
211211
*/
212212
static of(fn, options) {
213213
const spring = new Spring(fn(), options);

packages/svelte/src/motion/tweened.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @import { Task } from '../internal/client/types' */
2-
/** @import { TweenedStore } from './public' */
2+
/** @import { Tweened } from './public' */
33
/** @import { TweenedOptions } from './private' */
44
import { writable } from '../store/shared/index.js';
55
import { raf } from '../internal/client/timing.js';
@@ -82,7 +82,7 @@ function get_interpolator(a, b) {
8282
* @template T
8383
* @param {T} [value]
8484
* @param {TweenedOptions<T>} [defaults]
85-
* @returns {TweenedStore<T>}
85+
* @returns {Tweened<T>}
8686
*/
8787
export function tweened(value, defaults = {}) {
8888
const store = writable(value);

packages/svelte/types/index.d.ts

Lines changed: 77 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,15 +1637,81 @@ declare module 'svelte/legacy' {
16371637
}
16381638

16391639
declare module 'svelte/motion' {
1640-
export interface SpringStore<T> extends Readable<T> {
1641-
set: (new_value: T, opts?: SpringUpdateOpts) => Promise<void>;
1640+
// TODO we do declaration merging here in order to not have a breaking change (renaming the Spring interface)
1641+
// this means both the Spring class and the Spring interface are merged into one with some things only
1642+
// existing on one side. In Svelte 6, remove the type definition and move the jsdoc onto the class in spring.js
1643+
1644+
export interface Spring<T> extends Readable<T> {
1645+
set(new_value: T, opts?: SpringUpdateOpts): Promise<void>;
1646+
/**
1647+
* @deprecated Only exists on the Spring store
1648+
*/
16421649
update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>;
16431650
precision: number;
16441651
damping: number;
16451652
stiffness: number;
16461653
}
16471654

1648-
export interface TweenedStore<T> extends Readable<T> {
1655+
/**
1656+
* A wrapper for a value that behaves in a spring-like fashion. Changes to `spring.target` will cause `spring.current` to
1657+
* move towards it over time, taking account of the `spring.stiffness` and `spring.damping` parameters.
1658+
*
1659+
* ```svelte
1660+
* <script>
1661+
* import { Spring } from 'svelte/motion';
1662+
*
1663+
* const spring = new Spring(0);
1664+
* </script>
1665+
*
1666+
* <input type="range" bind:value={spring.target} />
1667+
* <input type="range" bind:value={spring.current} disabled />
1668+
* ```
1669+
*/
1670+
export class Spring<T> {
1671+
constructor(value: T, options?: SpringOpts);
1672+
1673+
/**
1674+
* Create a spring whose value is bound to the return value of `fn`. This must be called
1675+
* inside an effect root (for example, during component initialisation).
1676+
*
1677+
* ```svelte
1678+
* <script>
1679+
* import { Spring } from 'svelte/motion';
1680+
*
1681+
* let { number } = $props();
1682+
*
1683+
* const spring = Spring.of(() => number);
1684+
* </script>
1685+
* ```
1686+
*/
1687+
static of<U>(fn: () => U, options?: SpringOpts): Spring<U>;
1688+
1689+
/**
1690+
* Sets `spring.target` to `value` and returns a `Promise` that resolves if and when `spring.current` catches up to it.
1691+
*
1692+
* If `options.instant` is `true`, `spring.current` immediately matches `spring.target`.
1693+
*
1694+
* If `options.preserveMomentum` is provided, the spring will continue on its current trajectory for
1695+
* the specified number of milliseconds. This is useful for things like 'fling' gestures.
1696+
*/
1697+
set(value: T, options?: { instant?: boolean; preserveMomentum?: number }): Promise<void>;
1698+
1699+
damping: number;
1700+
precision: number;
1701+
stiffness: number;
1702+
/**
1703+
* The end value of the spring.
1704+
* This property only exists on the Spring class.
1705+
*/
1706+
target: T;
1707+
/**
1708+
* The current value of the spring.
1709+
* This property only exists on the Spring class.
1710+
*/
1711+
get current(): T;
1712+
}
1713+
1714+
export interface Tweened<T> extends Readable<T> {
16491715
set(value: T, opts?: TweenedOptions<T>): Promise<void>;
16501716
update(updater: Updater<T>, opts?: TweenedOptions<T>): Promise<void>;
16511717
}
@@ -1671,7 +1737,13 @@ declare module 'svelte/motion' {
16711737
}
16721738

16731739
interface SpringUpdateOpts {
1740+
/**
1741+
* @deprecated Only use this for the spring store; does nothing when set on the Spring class
1742+
*/
16741743
hard?: any;
1744+
/**
1745+
* @deprecated Only use this for the spring store; does nothing when set on the Spring class
1746+
*/
16751747
soft?: string | number | boolean;
16761748
}
16771749

@@ -1688,80 +1760,13 @@ declare module 'svelte/motion' {
16881760
*
16891761
* @deprecated Use [`Spring`](https://svelte.dev/docs/svelte/svelte-motion#Spring) instead
16901762
* */
1691-
export function spring<T = any>(value?: T | undefined, opts?: SpringOpts | undefined): SpringStore<T>;
1692-
/**
1693-
* A wrapper for a value that behaves in a spring-like fashion. Changes to `spring.target` will cause `spring.current` to
1694-
* move towards it over time, taking account of the `spring.stiffness` and `spring.damping` parameters.
1695-
*
1696-
* ```svelte
1697-
* <script>
1698-
* import { Spring } from 'svelte/motion';
1699-
*
1700-
* const spring = new Spring(0);
1701-
* </script>
1702-
*
1703-
* <input type="range" bind:value={spring.target} />
1704-
* <input type="range" bind:value={spring.current} disabled />
1705-
* ```
1706-
* */
1707-
export class Spring<T> {
1708-
/**
1709-
* Create a spring whose value is bound to the return value of `fn`. This must be called
1710-
* inside an effect root (for example, during component initialisation).
1711-
*
1712-
* ```svelte
1713-
* <script>
1714-
* import { Spring } from 'svelte/motion';
1715-
*
1716-
* let { number } = $props();
1717-
*
1718-
* const spring = Spring.of(() => number);
1719-
* </script>
1720-
* ```
1721-
*
1722-
*/
1723-
static of<U>(fn: () => U, options?: {
1724-
stiffness?: number;
1725-
damping?: number;
1726-
precision?: number;
1727-
} | undefined): Spring<U>;
1728-
1729-
constructor(value: T, options?: {
1730-
stiffness?: number;
1731-
damping?: number;
1732-
precision?: number;
1733-
} | undefined);
1734-
/**
1735-
* Sets `spring.target` to `value` and returns a `Promise` that resolves if and when `spring.current` catches up to it.
1736-
*
1737-
* If `options.instant` is `true`, `spring.current` immediately matches `spring.target`.
1738-
*
1739-
* If `options.preserveMomentum` is provided, the spring will continue on its current trajectory for
1740-
* the specified number of milliseconds. This is useful for things like 'fling' gestures.
1741-
*
1742-
*
1743-
*/
1744-
set(value: T, options?: {
1745-
instant?: boolean;
1746-
preserveMomentum?: number;
1747-
} | undefined): Promise<unknown>;
1748-
get current(): T;
1749-
set damping(v: number);
1750-
get damping(): number;
1751-
set precision(v: number);
1752-
get precision(): number;
1753-
set stiffness(v: number);
1754-
get stiffness(): number;
1755-
set target(v: T);
1756-
get target(): T;
1757-
#private;
1758-
}
1763+
export function spring<T = any>(value?: T | undefined, opts?: SpringOpts | undefined): Spring<T>;
17591764
/**
17601765
* A tweened store in Svelte is a special type of store that provides smooth transitions between state values over time.
17611766
*
17621767
* @deprecated Use [`Tween`](https://svelte.dev/docs/svelte/svelte-motion#Tween) instead
17631768
* */
1764-
export function tweened<T>(value?: T | undefined, defaults?: TweenedOptions<T> | undefined): TweenedStore<T>;
1769+
export function tweened<T>(value?: T | undefined, defaults?: TweenedOptions<T> | undefined): Tweened<T>;
17651770
/**
17661771
* A wrapper for a value that tweens smoothly to its target value. Changes to `tween.target` will cause `tween.current` to
17671772
* move towards it over time, taking account of the `delay`, `duration` and `easing` options.

0 commit comments

Comments
 (0)