diff --git a/.changeset/tween-solid2-migration.md b/.changeset/tween-solid2-migration.md new file mode 100644 index 000000000..6778ff81d --- /dev/null +++ b/.changeset/tween-solid2-migration.md @@ -0,0 +1,16 @@ +--- +"@solid-primitives/tween": major +--- + +Migrate to Solid.js v2.0 (beta.10) + +## Breaking Changes + +**Peer dependency**: `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10` are now required. + +### `@solid-primitives/tween` + +- `isServer` now imported from `@solidjs/web` (not `solid-js/web`) +- `createEffect` updated to the two-argument compute/apply form required by Solid 2.0 — the removed `on()` helper is no longer used +- Cleanup (cancelling the in-flight `requestAnimationFrame`) is now returned from the apply function instead of calling `onCleanup` +- `current()` snapshot at tween start is now read inside `untrack()` to silence strict-mode warnings about untracked reads in apply callbacks diff --git a/packages/tween/README.md b/packages/tween/README.md index cda1eed7c..a299d27cd 100644 --- a/packages/tween/README.md +++ b/packages/tween/README.md @@ -19,6 +19,8 @@ npm install @solid-primitives/tween yarn add @solid-primitives/tween ``` +Requires `solid-js@^2.0.0-beta.10` and `@solidjs/web@^2.0.0-beta.10`. + ## How to use it ```ts diff --git a/packages/tween/package.json b/packages/tween/package.json index 85466947d..d0a9c4b52 100644 --- a/packages/tween/package.json +++ b/packages/tween/package.json @@ -47,10 +47,12 @@ "test:ssr": "pnpm run vitest --mode ssr" }, "peerDependencies": { - "solid-js": "^1.6.12" + "@solidjs/web": "^2.0.0-beta.10", + "solid-js": "^2.0.0-beta.10" }, "typesVersions": {}, "devDependencies": { - "solid-js": "^1.9.7" + "@solidjs/web": "2.0.0-beta.10", + "solid-js": "2.0.0-beta.10" } } diff --git a/packages/tween/src/index.ts b/packages/tween/src/index.ts index 0146c77b9..fa5b2c90c 100644 --- a/packages/tween/src/index.ts +++ b/packages/tween/src/index.ts @@ -1,5 +1,5 @@ -import { createSignal, createEffect, onCleanup, on } from "solid-js"; -import { isServer } from "solid-js/web"; +import { createSignal, createEffect, untrack } from "solid-js"; +import { isServer } from "@solidjs/web"; export type TweenProps = { duration?: number; @@ -53,17 +53,15 @@ export default function createTween( } createEffect( - on( - target, - () => { - start = performance.now(); - startValue = current(); - delta = target() - startValue; - cancelId = requestAnimationFrame(tick); - onCleanup(() => cancelAnimationFrame(cancelId)); - }, - { defer: true }, - ), + () => target(), + newTarget => { + start = performance.now(); + startValue = untrack(current); + delta = newTarget - startValue; + cancelId = requestAnimationFrame(tick); + return () => cancelAnimationFrame(cancelId); + }, + { defer: true }, ); return current; diff --git a/packages/tween/test/index.test.ts b/packages/tween/test/index.test.ts index 38af13f75..cc056349b 100644 --- a/packages/tween/test/index.test.ts +++ b/packages/tween/test/index.test.ts @@ -1,4 +1,4 @@ -import { createRoot, createSignal } from "solid-js"; +import { createRoot, createSignal, flush } from "solid-js"; import { describe, expect, it, vi, afterEach } from "vitest"; import createTween from "../src/index.js"; @@ -47,9 +47,11 @@ describe("animation", () => { expect(tweened()).toBe(0); setSource(100); - expect(tweened()).toBe(0); + flush(); // run the effect, register RAF + expect(tweened()).toBe(0); // RAF hasn't fired yet - _flush_raf(start + 200); + _flush_raf(start + 200); // elapsed >= duration(100), setCurrent(target()) + flush(); // commit the signal write expect(tweened()).toBe(100); dispose(); @@ -66,18 +68,23 @@ describe("animation", () => { const start = performance.now(); setValue(100); + flush(); // run the effect expect(tweened()).toBe(0); _flush_raf(start + 25); + flush(); expect(tweened()).toBeCloseTo(25, 0); _flush_raf(start + 50); + flush(); expect(tweened()).toBeCloseTo(50, 0); _flush_raf(start + 75); + flush(); expect(tweened()).toBeCloseTo(75, 0); _flush_raf(start + 100); + flush(); expect(tweened()).toBeCloseTo(100, 0); dispose(); @@ -94,18 +101,23 @@ describe("animation", () => { const start = performance.now(); setValue(100); + flush(); // run the effect expect(tweened()).toBe(0); _flush_raf(start + 25); + flush(); expect(tweened()).toBeCloseTo(6.25, 0); _flush_raf(start + 50); + flush(); expect(tweened()).toBeCloseTo(25, 0); _flush_raf(start + 75); + flush(); expect(tweened()).toBeCloseTo(56.25, 0); _flush_raf(start + 100); + flush(); expect(tweened()).toBeCloseTo(100, 0); dispose(); @@ -122,12 +134,15 @@ describe("animation", () => { const start = performance.now(); setValue(100); + flush(); // run the effect, register RAF _flush_raf(start + 600); + flush(); expect(tweened()).toBeCloseTo(60, 0); setValue(0); - + flush(); // cleanup old RAF, run effect with new target, register RAF _flush_raf(start + 500); + flush(); expect(tweened()).toBeCloseTo(30, 0); dispose(); diff --git a/packages/tween/test/server.test.ts b/packages/tween/test/server.test.ts new file mode 100644 index 000000000..638d9ce2d --- /dev/null +++ b/packages/tween/test/server.test.ts @@ -0,0 +1,19 @@ +import { describe, test, expect } from "vitest"; +import { createSignal } from "solid-js"; +import createTween from "../src/index.js"; + +describe("createTween", () => { + test("doesn't break in SSR", () => { + const [value] = createSignal(42); + const tweened = createTween(value, { duration: 100 }); + expect(tweened()).toBe(42); + }); + + test("returns the target signal on SSR", () => { + const [value, setValue] = createSignal(0); + const tweened = createTween(value, {}); + expect(tweened()).toBe(0); + setValue(100); + expect(tweened()).toBe(100); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f59c63a9c..c48cfe591 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -966,9 +966,12 @@ importers: packages/tween: devDependencies: + '@solidjs/web': + specifier: 2.0.0-beta.10 + version: 2.0.0-beta.10(solid-js@2.0.0-beta.10) solid-js: - specifier: ^1.9.7 - version: 1.9.7 + specifier: 2.0.0-beta.10 + version: 2.0.0-beta.10 packages/upload: dependencies: