diff --git a/.changeset/tasty-kangaroos-greet.md b/.changeset/tasty-kangaroos-greet.md new file mode 100644 index 0000000000..07b6efa2be --- /dev/null +++ b/.changeset/tasty-kangaroos-greet.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: add `onFrame` lifecycle function diff --git a/packages/svelte/src/index-client.js b/packages/svelte/src/index-client.js index 587d766233..34a9694a75 100644 --- a/packages/svelte/src/index-client.js +++ b/packages/svelte/src/index-client.js @@ -161,6 +161,32 @@ export function afterUpdate(fn) { init_update_callbacks(component_context).a.push(fn); } +/** + * The `onFrame` function schedules a callback to run on `requestAnimationFrame`. It must be called inside an effect (e.g. during component initialisation). + * + * `onFrame` does not run inside [server-side components](https://svelte.dev/docs/svelte/svelte-server#render). + * + * @template T + * @param {() => NotFunction | Promise> | (() => any)} fn + * @returns {void} + */ +export function onFrame(fn) { + onMount(() => { + let frame = -1; + + function next() { + frame = requestAnimationFrame(next); + fn(); + } + + next(); + + return () => { + cancelAnimationFrame(frame); + }; + }); +} + /** * Legacy-mode: Init callbacks object for onMount/beforeUpdate/afterUpdate * @param {ComponentContext} context diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index f6b5b21f80..c7eb847c01 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -408,6 +408,13 @@ declare module 'svelte' { * @deprecated Use [`$effect`](https://svelte.dev/docs/svelte/$effect) instead * */ export function afterUpdate(fn: () => void): void; + /** + * The `onFrame` function schedules a callback to run on `requestAnimationFrame`. It must be called inside an effect (e.g. during component initialisation). + * + * `onFrame` does not run inside [server-side components](https://svelte.dev/docs/svelte/svelte-server#render). + * + * */ + export function onFrame(fn: () => NotFunction | Promise> | (() => any)): void; /** * Synchronously flushes any pending state changes and those that result from it. * */ @@ -1671,6 +1678,7 @@ declare module 'svelte/motion' { * * * ``` + * @since 5.8.0 */ export class Spring { constructor(value: T, options?: SpringOpts);