import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { easeOut, easeSpring, motionPresets } from "../src/lib/motion/presets.ts"; const pageSource = readFileSync(new URL("../src/app/(app)/page.tsx", import.meta.url), "utf8"); const layoutSource = readFileSync(new URL("../src/app/layout.tsx", import.meta.url), "utf8"); test("every site-motion row is a preset and nothing else is invented", () => { assert.deepEqual(Object.keys(motionPresets).sort(), [ "chartType", "dateTurn", "dialog", "disclosure", "drawer", "listReorder", "localeSwitch", "numberChange", "pageEnter", "pageExit", "personSwitch", "press", "selectionFollow", "sendMessage", "sessionSwitch", "tabSwitch", "toast", ]); assert.deepEqual(easeOut, [0.22, 1, 0.36, 1]); assert.deepEqual(easeSpring, [0.34, 1.56, 0.64, 1]); assert.equal(motionPresets.press.duration, 0.12); assert.equal(motionPresets.pageEnter.duration, 0.28); assert.equal(motionPresets.pageEnter.distance, 16); assert.equal(motionPresets.pageExit.duration, 0.15); assert.equal(motionPresets.selectionFollow.duration, 0.26); assert.equal(motionPresets.tabSwitch.duration, 0.26); assert.equal(motionPresets.chartType.duration, 0.44); assert.equal(motionPresets.personSwitch.duration, 0.3); assert.equal(motionPresets.personSwitch.durationFollow, 0.8); assert.equal(motionPresets.dateTurn.duration, 0.26); assert.equal(motionPresets.sendMessage.duration, 0.26); assert.equal(motionPresets.sendMessage.direction, "from-composer"); assert.equal(motionPresets.sessionSwitch.duration, 0.2); assert.equal(motionPresets.sessionSwitch.direction, "crossfade"); assert.equal(motionPresets.listReorder.duration, 0.26); assert.equal(motionPresets.listReorder.durationExit, 0.28); assert.equal(motionPresets.dialog.duration, 0.22); assert.equal(motionPresets.dialog.durationExit, 0.16); assert.equal(motionPresets.dialog.scale, true); assert.equal(motionPresets.drawer.duration, 0.28); assert.equal(motionPresets.drawer.durationExit, 0.2); assert.equal(motionPresets.toast.duration, 0.32); assert.equal(motionPresets.toast.ease, easeSpring); assert.equal(motionPresets.numberChange.duration, 0.36); assert.equal(motionPresets.numberChange.reduced.instant, true); assert.equal(motionPresets.localeSwitch.duration, 0.32); assert.equal(motionPresets.localeSwitch.stagger, 0.04); assert.equal(motionPresets.disclosure.duration, 0.24); for (const preset of Object.values(motionPresets)) { assert.equal(preset.reduced.travel, false); assert.ok(preset.reduced.duration <= 0.15); if (preset !== motionPresets.toast) assert.equal(preset.ease, easeOut); } }); test("the home and the layout never import motion or a motion shell statically", () => { // 原值:本条还断言 lib/motion/provider.tsx(LazyMotion 外壳)的写法 // 新值:该外壳没有任何产品引用,issue #139 已删除;只留首页与 layout 的静态引用约束 // 原因:留着它,将来一引用 Motion 就回到首屏 // 原值:首页不得引用 motion/react、动效外壳和任何一个 store。 // 新值:首页仍不得静态引用 motion 或动效外壳;可以引用会话 store,不得引用另外三个。 // 原因:K2 把对话状态放进会话 store。动效仍按需加载,不进首页同步包。 assert.doesNotMatch(pageSource, /motion\/react|@\/lib\/motion\/provider/); assert.match(pageSource, /useSessionStore/); assert.doesNotMatch(pageSource, /usePeopleStore|useAccountStore|useUiStore/); assert.doesNotMatch(layoutSource, /motion\/react|@\/lib\/motion\/provider|@\/stores\//); });