diff --git a/.cursor/plans/iterationdelay_preset_refactor_85bcd1fa.plan.md b/.cursor/plans/iterationdelay_preset_refactor_85bcd1fa.plan.md deleted file mode 100644 index 016cb4d8..00000000 --- a/.cursor/plans/iterationdelay_preset_refactor_85bcd1fa.plan.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -name: iterationDelay preset refactor -overview: Refactor all 13 ongoing presets so that `delay` (from `TimeAnimationOptions`) is passed through as actual WAAPI start delay, and a new `iterationDelay` preset parameter (on each namedEffect type) takes over the current "bake delay into keyframe offsets" behavior. -todos: - - id: types - content: 'Add `iterationDelay?: number` to all 13 ongoing namedEffect types in types.ts' - status: completed - - id: presets - content: Refactor all 13 ongoing preset files to use namedEffect.iterationDelay for keyframe-offset compression and pass through options.delay as actual start delay - status: completed - - id: tests - content: 'Update all 13 ongoing preset test files: move delay to iterationDelay in options, update assertions, add new tests for actual delay passthrough' - status: completed - - id: docs - content: Update docs in motion-presets/docs, motion/docs, and interact/docs to reflect new iterationDelay parameter and corrected delay semantics - status: completed - - id: rules - content: Update presets-main.md, ongoing-presets.md, and any interact rules that reference ongoing delay behavior - status: completed -isProject: false ---- - -# Refactor ongoing presets: `delay` to actual start delay, new `iterationDelay` parameter - -## Problem - -All 13 ongoing presets (except DVD) hijack `TimeAnimationOptions.delay` to simulate iteration delay. They: - -1. Compute `timingFactor = duration / (duration + delay)` via `getTimingFactor()` -2. Compress keyframe offsets into `[0, timingFactor]` -3. Return `delay: 0` and `duration: duration + delay` - -This means there is **no way** to set an actual WAAPI start delay on these presets. - -## Solution - -- `**delay`\*\* (from `TimeAnimationOptions`): pass through as actual WAAPI start delay -- `**iterationDelay`\*\* (new param on each `namedEffect` type): takes over the current keyframe-offset-compression behavior - -DVD is **excluded** -- it already uses `delay` as actual start delay and does not use `getTimingFactor`. - ---- - -## 1. Type definitions - -**File:** `[packages/motion-presets/src/types.ts](packages/motion-presets/src/types.ts)` - -Add `iterationDelay?: number` to each of these 13 types: - -`Bounce`, `Breathe`, `Cross`, `Flash`, `Flip`, `Fold`, `Jello`, `Poke`, `Pulse`, `Rubber`, `Spin`, `Swing`, `Wiggle` - -Example: - -```typescript -export type Spin = { - type: 'Spin'; - direction?: 'clockwise' | 'counter-clockwise'; - iterationDelay?: number; // new -}; -``` - ---- - -## 2. Preset implementations (13 files) - -**Directory:** `packages/motion-presets/src/library/ongoing/` - -**Files:** `Bounce.ts`, `Breathe.ts`, `Cross.ts`, `Flash.ts`, `Flip.ts`, `Fold.ts`, `Jello.ts`, `Poke.ts`, `Pulse.ts`, `Rubber.ts`, `Spin.ts`, `Swing.ts`, `Wiggle.ts` - -For each file, apply the same transformation pattern. Using **Spin.ts** as the canonical example: - -**Before:** - -```typescript -const duration = options.duration || 1; -const delay = options.delay || 0; -const timingFactor = getTimingFactor(duration, delay) as number; -// ... -return [ - { - ...options, - delay: 0, - duration: duration + delay, - keyframes: [{ offset: 0 /* ... */ }, { offset: timingFactor /* ... */ }], - }, -]; -``` - -**After:** - -```typescript -const duration = options.duration || 1; -const iterationDelay = namedEffect?.iterationDelay || 0; -const timingFactor = getTimingFactor(duration, iterationDelay) as number; -// ... -return [ - { - ...options, - duration: duration + iterationDelay, - keyframes: [{ offset: 0 /* ... */ }, { offset: timingFactor /* ... */ }], - }, -]; -``` - -Key changes per file: - -- Read `iterationDelay` from `namedEffect` (already destructured/cast in each preset) -- Remove `const delay = options.delay || 0` -- Remove `delay: 0` from returned object (let `...options` pass through the original `delay`) -- Replace `duration + delay` with `duration + iterationDelay` -- Replace `getTimingFactor(duration, delay)` with `getTimingFactor(duration, iterationDelay)` - -### Special cases - -**Swing.ts, Fold.ts, Breathe.ts** -- these presets use a **conditional keyframe sequence** when delay > 0 (switches to a decay-style FACTORS_SEQUENCE). Change the condition from `delay` to `iterationDelay`: - -```typescript -// Before -const keyframes = delay ? FACTORS_SEQUENCE.map(...) : [/* standard keyframes */]; - -// After -const keyframes = iterationDelay ? FACTORS_SEQUENCE.map(...) : [/* standard keyframes */]; -``` - -### `getNames` updates - -Each file's `getNames()` currently reads `options.delay!`. Change to read from `namedEffect`: - -```typescript -// Before -export function getNames(options: TimeAnimationOptions & AnimationExtraOptions) { - const timingFactor = getTimingFactor(options.duration!, options.delay!, true); - return [`motion-spin-${timingFactor}`]; -} - -// After -export function getNames(options: TimeAnimationOptions & AnimationExtraOptions) { - const iterationDelay = (options.namedEffect as Spin)?.iterationDelay || 0; - const timingFactor = getTimingFactor(options.duration!, iterationDelay, true); - return [`motion-spin-${timingFactor}`]; -} -``` - -(The `namedEffect` type cast varies per preset -- `Spin`, `Bounce`, etc.) - -**Fold.ts `getNames` special case** -- currently has an `if (!delay)` branch. Change to `if (!iterationDelay)`. - ---- - -## 3. Tests (13 + 1 files) - -**Directory:** `packages/motion-presets/src/library/ongoing/test/` - -**Files:** `Bounce.spec.ts`, `Breathe.spec.ts`, `Cross.spec.ts`, `DVD.spec.ts`, `Flash.spec.ts`, `Flip.spec.ts`, `Fold.spec.ts`, `Jello.spec.ts`, `Poke.spec.ts`, `Pulse.spec.ts`, `Rubber.spec.ts`, `Spin.spec.ts`, `Swing.spec.ts`, `Wiggle.spec.ts` - -For each test that currently passes `delay` in `TimeAnimationOptions`: - -- Move `delay` value into `namedEffect.iterationDelay` -- Remove `delay` from the outer options (or add a separate test with actual `delay`) -- Update assertions: `delay: 0` in expected result should now either be absent or reflect the actual start delay -- `duration: duration + delay` in assertions becomes `duration: duration + iterationDelay` -- Keyframe offset values (e.g., `0.67`, `0.8`) remain the same since the formula is unchanged -- **Add new test cases** that verify `delay` is passed through as actual start delay when both `delay` and `iterationDelay` are provided - -**DVD.spec.ts** -- no changes needed (DVD already uses delay correctly). - -Also check `packages/motion-presets/src/test/utils.spec.ts` -- `getTimingFactor` tests don't need changes (utility behavior unchanged). - ---- - -## 4. Documentation updates - -### motion-presets docs - -- `**[packages/motion-presets/docs/presets/ongoing/pulse.md](packages/motion-presets/docs/presets/ongoing/pulse.md)`\*\* -- Add `iterationDelay` parameter documentation and usage examples -- `**[packages/motion-presets/docs/presets/_template.md](packages/motion-presets/docs/presets/_template.md)`\*\* -- Add `iterationDelay` to ongoing preset template if applicable - -### motion docs - -- `**[packages/motion/docs/categories/ongoing-animations.md](packages/motion/docs/categories/ongoing-animations.md)`\*\* -- If it documents the delay-as-iteration-delay behavior, update to reflect the new `iterationDelay` param -- `**[packages/motion/docs/api/types.md](packages/motion/docs/api/types.md)**` -- If it documents `TimeAnimationOptions.delay` behavior for ongoing presets, update -- `**[packages/motion/docs/core-concepts.md](packages/motion/docs/core-concepts.md)**` -- If it documents delay semantics, verify accuracy - -### interact docs - -- `**[packages/interact/docs/guides/effects-and-animations.md](packages/interact/docs/guides/effects-and-animations.md)**` -- If it shows ongoing presets with delay, update examples -- `**[packages/interact/docs/api/types.md](packages/interact/docs/api/types.md)**` -- If it documents the ongoing delay pattern, update - -Docs that do NOT reference the ongoing delay pattern do not need changes. - ---- - -## 5. Rules updates - -### motion-presets rules - -- `**[packages/motion-presets/rules/presets/presets-main.md](packages/motion-presets/rules/presets/presets-main.md)**` -- Lines 64-65: `delay` is listed as "animation delay" in the animation options section. This is now correct for ongoing presets (actual start delay). Add `iterationDelay` documentation under a new "Ongoing-specific parameters" subsection or as a note. -- `**[packages/motion-presets/rules/presets/ongoing-presets.md](packages/motion-presets/rules/presets/ongoing-presets.md)**` -- Add `iterationDelay` parameter to each of the 13 ongoing preset parameter tables (not DVD). Include a brief explanation of what it does. - -### interact rules - -- `**[packages/interact/rules/viewenter.md](packages/interact/rules/viewenter.md)**`, `**[packages/interact/rules/click.md](packages/interact/rules/click.md)**`, `**[packages/interact/rules/hover.md](packages/interact/rules/hover.md)**`, `**[packages/interact/rules/integration.md](packages/interact/rules/integration.md)**`, `**[packages/interact/rules/full-lean.md](packages/interact/rules/full-lean.md)**` -- Review each for ongoing-preset delay examples. These files primarily deal with entrance/interaction triggers and use `delay` in the `TimeAnimationOptions` sense (which is now correct), so they likely need **no changes** unless they show ongoing preset examples with `delay` meaning iteration delay. - ---- - -## 6. Utility function - -`**[packages/motion-presets/src/utils.ts](packages/motion-presets/src/utils.ts)`\*\* -- `getTimingFactor(duration, delay)` does not need changes. Its interface is generic (two numbers). Callers will now pass `iterationDelay` instead of `delay`. - ---- - -## Summary of scope - -| Area | Files | Changes | -| ------- | ----- | --------------------------------------------- | -| Types | 1 | Add `iterationDelay` to 13 types | -| Presets | 13 | Refactor delay -> iterationDelay logic | -| Tests | 13 | Update test options and assertions | -| Docs | 5-7 | Update delay semantics and add iterationDelay | -| Rules | 2-3 | Add iterationDelay to parameter tables | -| Utility | 0 | No changes | diff --git a/.cursor/plans/motion_e2e_testing_8be14c4f.plan.md b/.cursor/plans/motion_e2e_testing_8be14c4f.plan.md deleted file mode 100644 index d7c5c3cd..00000000 --- a/.cursor/plans/motion_e2e_testing_8be14c4f.plan.md +++ /dev/null @@ -1,647 +0,0 @@ ---- -name: Motion E2E Testing -overview: 'Set up Playwright-based E2E test infrastructure for the @wix/motion package with dedicated test fixture pages. Tests run on-demand via the motion-e2e GitHub Actions workflow (not in the CI workflow). The plan covers named effects (WAAPI + CSS), keyframe effects (WAAPI + CSS), custom effects, play/reverse, play/pause, scroll-driven, pointer-driven, responsive, and selector scenarios.' -todos: - - id: install-playwright - content: Install Playwright dependencies and add scripts to packages/motion/package.json - status: pending - - id: playwright-config - content: Create playwright.config.ts in packages/motion with projects, webServer, and reporter settings - status: pending - - id: test-fixtures-vite - content: Create Vite config for test fixtures server in packages/motion/e2e/fixtures/ - status: pending - - id: test-fixtures-scroll - content: Create test fixture page for scroll-driven animations (view-enter, view-progress, scrub) - status: pending - - id: test-fixtures-pointer - content: Create test fixture page for pointer-driven animations (axis, composite) - status: pending - - id: test-fixtures-animation-group - content: Create test fixture page for AnimationGroup API (lifecycle, progress, callbacks) - status: pending - - id: test-fixtures-effects - content: 'Create test fixture page for effect types — named effects (WAAPI + CSS), keyframe effects (WAAPI + CSS), custom effects, play/reverse, and play/pause — with ad-hoc registered named effects' - status: pending - - id: test-fixtures-responsive - content: Create test fixture page for responsive conditions (breakpoints) - status: pending - - id: test-fixtures-selector - content: Create test fixture page for selector conditions (nth-child, list container) - status: pending - - id: test-utils - content: Create e2e/utils/ with animation, scroll, and pointer helper functions - status: pending - - id: page-objects - content: Create e2e/pages/ with page objects for each test fixture - status: pending - - id: scaffold-scroll - content: Create scroll-animations.spec.ts with test titles - status: pending - - id: scaffold-pointer - content: Create pointer-animations.spec.ts with test titles - status: pending - - id: scaffold-animation-group - content: Create animation-group.spec.ts with test titles - status: pending - - id: scaffold-effects - content: 'Create effects.spec.ts with test titles for named effects (WAAPI + CSS), keyframe effects (WAAPI + CSS), custom effects, play/reverse, and play/pause' - status: pending - - id: scaffold-responsive - content: Create responsive-conditions.spec.ts with test titles - status: pending - - id: scaffold-selector - content: Create selector-conditions.spec.ts with test titles - status: pending - - id: impl-scroll - content: Implement scroll-driven animations tests (view-enter, view-progress, scrub) - status: pending - - id: impl-pointer - content: Implement pointer-driven animations tests (axis, composite) - status: pending - - id: impl-animation-group - content: Implement AnimationGroup API tests (lifecycle, progress, callbacks) - status: pending - - id: impl-effects - content: 'Implement effects tests — named effects (WAAPI + CSS), keyframe effects (WAAPI + CSS), custom effects, play/reverse, play/pause' - status: pending - - id: impl-responsive - content: Implement responsive conditions tests (breakpoints, resize) - status: pending - - id: impl-selector - content: Implement selector conditions tests (nth-child, list container) - status: pending - - id: motion-e2e-workflow - content: Create dedicated .github/workflows/motion-e2e.yml workflow for on-demand E2E test runs (not in CI) - status: done -isProject: false ---- - -# E2E Test Infrastructure for @wix/motion - -## Context - -The `@wix/motion` package provides animation APIs for web applications: - -- **Core APIs**: `getWebAnimation()`, `getCSSAnimation()`, `getScrubScene()`, `getAnimation()` -- **AnimationGroup**: Class for managing animation groups with play/pause/reverse/cancel -- **Effect types**: - - **Named effects** — registered via `registerEffects()`, looked up by `namedEffect.type`, support both WAAPI (`web()`) and CSS (`style()`) code paths - - **Keyframe effects** — inline `keyframeEffect: { name, keyframes }`, synthesized into both WAAPI and CSS pipelines - - **Custom effects** — `customEffect: (element, progress) => void`, drives `CustomAnimation` for WAAPI (no CSS equivalent) -- **Triggers**: time-based, scroll-driven (`viewProgress`), and pointer-driven (`pointerMove`) -- **Conditions**: Media queries and CSS selectors - -Dedicated test fixture pages will be created within the motion package to serve as stable, focused test harnesses. - -### Ad-hoc Named Effect Registration - -Test fixtures that exercise named effects will **register their own ad-hoc effects** using `registerEffects()` rather than importing from `@wix/motion-presets`. This keeps E2E tests self-contained and decoupled from the presets package. Example pattern: - -```ts -import { registerEffects } from '@wix/motion'; - -registerEffects({ - TestFadeIn: { - getNames: () => ['test-fadeIn'], - web: (options) => [ - { ...options, name: 'test-fadeIn', easing: 'linear', keyframes: [{ offset: 0, opacity: 0 }] }, - ], - style: (options) => [ - { ...options, name: 'test-fadeIn', easing: 'linear', keyframes: [{ offset: 0, opacity: 0 }] }, - ], - }, - TestSlideIn: { - getNames: () => ['test-slideIn'], - web: (options) => [ - { - ...options, - name: 'test-slideIn', - easing: 'linear', - keyframes: [ - { offset: 0, transform: 'translateX(-100%)' }, - { offset: 1, transform: 'translateX(0)' }, - ], - }, - ], - style: (options) => [ - { - ...options, - name: 'test-slideIn', - easing: 'linear', - keyframes: [ - { offset: 0, transform: 'translateX(-100%)' }, - { offset: 1, transform: 'translateX(0)' }, - ], - }, - ], - }, -}); -``` - ---- - -## Phase 1: Infrastructure Setup - -### 1.1 Install Playwright Dependencies - -Add to `[packages/motion/package.json](packages/motion/package.json)`: - -```json -"devDependencies": { - "@playwright/test": "^1.52.0" -} -``` - -Add scripts: - -```json -"scripts": { - "test:e2e": "playwright test", - "test:e2e:ui": "playwright test --ui", - "test:e2e:fixtures": "vite --config e2e/fixtures/vite.config.ts" -} -``` - -### 1.2 Create Playwright Configuration - -Create `[packages/motion/playwright.config.ts](packages/motion/playwright.config.ts)`: - -- Base URL: `http://localhost:5174` (test fixtures dev server) -- Test directory: `e2e/tests/` -- Web server command: `yarn test:e2e:fixtures` -- Projects: Chromium, Firefox, WebKit -- Reporter: HTML + list -- Retries: 2 on CI - -### 1.3 Create Test Fixtures Server - -Create `[packages/motion/e2e/fixtures/vite.config.ts](packages/motion/e2e/fixtures/vite.config.ts)`: - -- Multi-page app with each fixture as an entry point -- Alias `@wix/motion` to local `src/` for testing against source -- Dev server on port 5174 - -### 1.4 Create Test Utilities - -Create `[packages/motion/e2e/utils/](packages/motion/e2e/utils/)` directory with: - -| File | Purpose | -| ---------------------- | -------------------------------------------------------------------------------------------- | -| `animation-helpers.ts` | Functions to wait for animations, check play states, measure progress, get computed styles | -| `scroll-helpers.ts` | Functions to scroll elements into view, simulate scroll gestures, calculate scroll positions | -| `pointer-helpers.ts` | Functions to simulate mouse movements, track pointer position within bounded areas | - -### 1.5 Create Page Objects - -Create `[packages/motion/e2e/pages/](packages/motion/e2e/pages/)` directory with: - -| File | Purpose | -| ------------------------- | ------------------------------------------------------------------------- | -| `base-fixture-page.ts` | Base page object with common fixture utilities, navigation, window access | -| `scroll-page.ts` | Page object for scroll animation fixture | -| `pointer-page.ts` | Page object for pointer animation fixture | -| `animation-group-page.ts` | Page object for AnimationGroup fixture | -| `effects-page.ts` | Page object for effects fixture (named, keyframe, custom) | -| `responsive-page.ts` | Page object for responsive conditions fixture | -| `selector-page.ts` | Page object for selector conditions fixture | - ---- - -## Phase 2: Test Fixtures Creation - -Create dedicated HTML/TypeScript pages for each test scenario. Each fixture: - -- Imports directly from `@wix/motion` source -- Exposes animation instances to `window` for test assertions -- Has data-testid attributes for reliable element selection -- Includes minimal styling focused on testability -- Registers ad-hoc named effects via `registerEffects()` where needed (no dependency on `@wix/motion-presets`) - -### 2.1 Scroll-Driven Animations Fixture - -File: `[packages/motion/e2e/fixtures/scroll.html](packages/motion/e2e/fixtures/scroll.html)` + `[scroll.ts](packages/motion/e2e/fixtures/scroll.ts)` - -Elements: - -- Tall scrollable container (2000px+) -- View-progress target with rangeStart/rangeEnd -- Multiple scroll cards for staggered testing - -Exposed globals: - -- `window.scrubScene`: Current ScrubScrollScene instance -- `window.getScrollProgress()`: Function to get current progress - -### 2.2 Pointer-Driven Animations Fixture - -File: `[packages/motion/e2e/fixtures/pointer.html](packages/motion/e2e/fixtures/pointer.html)` + `[pointer.ts](packages/motion/e2e/fixtures/pointer.ts)` - -Elements: - -- X-axis tracking element -- Y-axis tracking element -- Composite transform element (scaleX + scaleY) -- Bounded pointer area with known dimensions - -Exposed globals: - -- `window.pointerScene`: Current ScrubPointerScene instance -- `window.getPointerProgress()`: Function to get x/y progress - -### 2.3 AnimationGroup API Fixture - -File: `[packages/motion/e2e/fixtures/animation-group.html](packages/motion/e2e/fixtures/animation-group.html)` + `[animation-group.ts](packages/motion/e2e/fixtures/animation-group.ts)` - -Elements: - -- Multiple animated elements in a group -- Progress indicator element -- Play state display - -Exposed globals: - -- `window.animationGroup`: AnimationGroup instance -- `window.lifecycleEvents`: Array of recorded events -- Control functions: `window.play()`, `window.pause()`, `window.reverse()`, `window.cancel()` - -### 2.4 Effects Fixture (Named, Keyframe, Custom) - -File: `[packages/motion/e2e/fixtures/effects.html](packages/motion/e2e/fixtures/effects.html)` + `[effects.ts](packages/motion/e2e/fixtures/effects.ts)` - -This fixture is dedicated to testing all three effect types through both WAAPI and CSS code paths, plus play/reverse and play/pause playback controls. - -**Ad-hoc named effect registration** at fixture init: - -```ts -import { registerEffects, getWebAnimation, getCSSAnimation } from '@wix/motion'; - -// Register simple, deterministic named effects for testing -registerEffects({ - TestFadeIn: { - getNames: () => ['test-fadeIn'], - web: (options) => [ - { ...options, name: 'test-fadeIn', easing: 'linear', keyframes: [{ offset: 0, opacity: 0 }] }, - ], - style: (options) => [ - { ...options, name: 'test-fadeIn', easing: 'linear', keyframes: [{ offset: 0, opacity: 0 }] }, - ], - }, - TestScale: { - getNames: () => ['test-scale'], - web: (options) => [ - { - ...options, - name: 'test-scale', - easing: 'linear', - keyframes: [ - { offset: 0, transform: 'scale(0)' }, - { offset: 1, transform: 'scale(1)' }, - ], - }, - ], - style: (options) => [ - { - ...options, - name: 'test-scale', - easing: 'linear', - keyframes: [ - { offset: 0, transform: 'scale(0)' }, - { offset: 1, transform: 'scale(1)' }, - ], - }, - ], - }, -}); -``` - -Elements: - -- Named effect WAAPI target: element animated via `getWebAnimation()` with `namedEffect: { type: 'TestFadeIn' }` -- Named effect CSS target: element animated via `getCSSAnimation()` with `namedEffect: { type: 'TestScale' }` + applied CSS keyframes -- Keyframe effect WAAPI target: element animated via `getWebAnimation()` with `keyframeEffect: { name: 'kf-slide', keyframes: [...] }` -- Keyframe effect CSS target: element animated via `getCSSAnimation()` with `keyframeEffect: { name: 'kf-rotate', keyframes: [...] }` + applied CSS keyframes -- Custom effect target: element animated via `getWebAnimation()` with `customEffect: (el, progress) => { ... }` - -Exposed globals: - -- `window.namedWaapiGroup`: AnimationGroup from `getWebAnimation()` with named effect -- `window.namedCssData`: CSS animation data from `getCSSAnimation()` with named effect -- `window.keyframeWaapiGroup`: AnimationGroup from `getWebAnimation()` with keyframe effect -- `window.keyframeCssData`: CSS animation data from `getCSSAnimation()` with keyframe effect -- `window.customEffectGroup`: AnimationGroup from `getWebAnimation()` with custom effect -- `window.customEffectLog`: Array tracking `(element, progress)` calls from the custom effect function -- `window.runNamedWaapi()`: Trigger named effect via WAAPI -- `window.runNamedCss()`: Trigger named effect via CSS path -- `window.runKeyframeWaapi()`: Trigger keyframe effect via WAAPI -- `window.runKeyframeCss()`: Trigger keyframe effect via CSS path -- `window.runCustomEffect()`: Trigger custom effect via WAAPI - -### 2.5 Responsive Conditions Fixture - -File: `[packages/motion/e2e/fixtures/responsive.html](packages/motion/e2e/fixtures/responsive.html)` + `[responsive.ts](packages/motion/e2e/fixtures/responsive.ts)` - -Elements: - -- Desktop-only animation target (>1024px) -- Tablet animation target (768-1024px) -- Mobile animation target (<768px) -- Current breakpoint indicator - -Exposed globals: - -- `window.activeCondition`: Currently active media query condition -- `window.triggerAnimation()`: Function to trigger animations - -### 2.6 Selector Conditions Fixture - -File: `[packages/motion/e2e/fixtures/selector.html](packages/motion/e2e/fixtures/selector.html)` + `[selector.ts](packages/motion/e2e/fixtures/selector.ts)` - -Elements: - -- Grid of 10 elements for nth-child testing -- List container with child elements -- Selector indicator showing which condition matched - -Exposed globals: - -- `window.getMatchedSelectors()`: Function returning which elements matched - ---- - -## Phase 3: Test Scaffolding (Titles Only) - -Create test files with `describe` blocks and empty `test()` stubs. - -### 3.1 Scroll-Driven Animations Suite - -File: `[packages/motion/e2e/tests/scroll-animations.spec.ts](packages/motion/e2e/tests/scroll-animations.spec.ts)` - -``` -describe('Scroll-Driven Animations') - describe('View Progress Trigger') - - should animate based on scroll progress - - should respect rangeStart and rangeEnd boundaries - - should update progress on scroll direction change - describe('Scrub Scene') - - should create scrub scene with correct range offsets - - should report accurate progress percentage - - should handle destroy cleanup properly -``` - -### 3.2 Pointer-Driven Animations Suite - -File: `[packages/motion/e2e/tests/pointer-animations.spec.ts](packages/motion/e2e/tests/pointer-animations.spec.ts)` - -``` -describe('Pointer-Driven Animations') - describe('Pointer Move Trigger') - - should animate on x-axis based on horizontal mouse position - - should animate on y-axis based on vertical mouse position - - should handle axis switching dynamically - describe('Composite Operations') - - should apply composite add for independent transforms - - should handle scaleX/scaleY independently - describe('Mouse Animation Instance') - - should return correct progress values - - should handle destroy and cleanup -``` - -### 3.3 AnimationGroup API Suite - -File: `[packages/motion/e2e/tests/animation-group.spec.ts](packages/motion/e2e/tests/animation-group.spec.ts)` - -``` -describe('AnimationGroup API') - describe('Lifecycle Methods') - - should play animation and resolve ready promise - - should pause animation immediately - - should reverse animation direction - - should cancel animation and reset - describe('Progress Control') - - should set progress manually - - should report accurate progress percentage - - should handle setPlaybackRate - describe('Callbacks') - - should fire onFinish callback when animation completes - - should handle multiple onFinish subscribers -``` - -### 3.4 Effects Suite (Named, Keyframe, Custom + Playback) - -File: `[packages/motion/e2e/tests/effects.spec.ts](packages/motion/e2e/tests/effects.spec.ts)` - -``` -describe('Effect Types') - describe('Named Effects — WAAPI') - - should create AnimationGroup via getWebAnimation with registered named effect - - should apply correct keyframes from named effect web() method - - should animate element opacity/transform as defined by the named effect - describe('Named Effects — CSS') - - should generate CSS animation data via getCSSAnimation with registered named effect - - should produce correct keyframe name and CSS properties from style() method - - should return animation data with correct duration, easing, and keyframes - describe('Keyframe Effects — WAAPI') - - should create AnimationGroup via getWebAnimation with inline keyframeEffect - - should apply keyframeEffect keyframes to the element - - should respect keyframeEffect name as animation id - describe('Keyframe Effects — CSS') - - should generate CSS animation data via getCSSAnimation with inline keyframeEffect - - should produce correct CSS keyframe name from keyframeEffect.name - - should include keyframeEffect keyframes in CSS output - describe('Custom Effects') - - should create animation via getWebAnimation with customEffect function - - should call customEffect function with (element, progress) during playback - - should call customEffect with null progress on cancel - - should track progress updates through customEffect callback - describe('Playback — Play/Reverse') - - should play animation forward and then reverse it - - should return to initial state after reverse completes - describe('Playback — Play/Pause') - - should pause animation mid-playback and hold current state - - should resume from paused position when played again -``` - -### 3.5 Responsive Conditions Suite - -File: `[packages/motion/e2e/tests/responsive-conditions.spec.ts](packages/motion/e2e/tests/responsive-conditions.spec.ts)` - -``` -describe('Responsive Conditions') - describe('Desktop Breakpoint') - - should apply desktop effect above 1024px - - should not apply tablet/mobile effects - describe('Tablet Breakpoint') - - should apply tablet effect between 768px and 1024px - describe('Mobile Breakpoint') - - should apply mobile effect below 768px - describe('Dynamic Resize') - - should switch effects when viewport resizes -``` - -### 3.6 Selector Conditions Suite - -File: `[packages/motion/e2e/tests/selector-conditions.spec.ts](packages/motion/e2e/tests/selector-conditions.spec.ts)` - -``` -describe('Selector Conditions') - describe('nth-child Selectors') - - should apply pulse effect to even children - - should apply spin effect to odd children - describe('List Container') - - should animate all matching elements in container - - should respect viewEnter trigger for each element -``` - ---- - -## Phase 4: Test Implementation - -### 4.1 Implement Scroll-Driven Animations Tests - -- Navigate to scroll fixture page -- Implement view-progress tests with `page.mouse.wheel()` for scroll simulation -- Call `window.getScrollProgress()` to verify progress values -- Assert on element transform/opacity changes during scroll - -### 4.2 Implement Pointer-Driven Animations Tests - -- Navigate to pointer fixture page -- Implement axis tests using `page.mouse.move()` with coordinates -- Call `window.getPointerProgress()` to verify x/y progress -- Test composite operations by verifying independent transform values -- Use `getComputedStyle` to verify transform matrix - -### 4.3 Implement AnimationGroup API Tests - -- Navigate to animation-group fixture page -- Implement lifecycle tests calling `window.play()`, `window.pause()`, `window.reverse()`, `window.cancel()` -- Implement progress tests using `window.animationGroup.getProgress()` -- Assert on `window.lifecycleEvents` array for callback verification -- Test `window.animationGroup.finished` promise resolution - -### 4.4 Implement Effects Tests (Named, Keyframe, Custom + Playback) - -- Navigate to effects fixture page - -**Named effects — WAAPI:** - -- Call `window.runNamedWaapi()` to trigger `getWebAnimation()` with `namedEffect: { type: 'TestFadeIn' }` -- Assert that `window.namedWaapiGroup` is a valid AnimationGroup -- Verify the element's computed opacity changes from 0 to 1 -- Check `playState` transitions through `running` → `finished` - -**Named effects — CSS:** - -- Call `window.runNamedCss()` to trigger `getCSSAnimation()` with `namedEffect: { type: 'TestScale' }` -- Assert that `window.namedCssData` contains valid CSS animation data -- Verify the returned data includes the correct keyframe name (`test-scale`), duration, easing, and keyframes - -**Keyframe effects — WAAPI:** - -- Call `window.runKeyframeWaapi()` to trigger `getWebAnimation()` with `keyframeEffect: { name: 'kf-slide', keyframes: [...] }` -- Assert that `window.keyframeWaapiGroup` is a valid AnimationGroup -- Verify the element's computed transform changes according to keyframes - -**Keyframe effects — CSS:** - -- Call `window.runKeyframeCss()` to trigger `getCSSAnimation()` with `keyframeEffect: { name: 'kf-rotate', keyframes: [...] }` -- Assert that `window.keyframeCssData` contains valid CSS animation data -- Verify the CSS output includes `kf-rotate` keyframe name and correct keyframe values - -**Custom effects:** - -- Call `window.runCustomEffect()` to trigger `getWebAnimation()` with a `customEffect` function -- Assert that `window.customEffectLog` is populated with `(element, progress)` entries -- Verify progress values increase from 0 toward 1 during playback -- Cancel the animation and verify `customEffect` is called with `null` progress - -**Playback — Play/Reverse:** - -- Create an animation via `getWebAnimation()` (using any effect type), call `play()` -- Wait for partial playback, then call `reverse()` -- Assert element animates back toward its initial state -- Wait for `finished` and verify element returns to initial computed style values - -**Playback — Play/Pause:** - -- Create an animation via `getWebAnimation()`, call `play()` -- Wait for partial playback, then call `pause()` -- Record the element's computed style at the pause point -- Wait briefly and assert the computed style has not changed (animation is held) -- Call `play()` again and verify the animation resumes from the paused position - -### 4.5 Implement Responsive Conditions Tests - -- Navigate to responsive fixture page -- Use `page.setViewportSize()` to test breakpoints -- Assert on `window.activeCondition` for correct media query -- Call `window.triggerAnimation()` and verify correct effect applies -- Test dynamic resize behavior by changing viewport size - -### 4.6 Implement Selector Conditions Tests - -- Navigate to selector fixture page -- Scroll grid elements into view -- Call `window.getMatchedSelectors()` to verify selector matching -- Verify different animations apply based on `:nth-child` selector - ---- - -## File Structure - -``` -packages/motion/ - e2e/ - fixtures/ - vite.config.ts - index.html # Entry with links to all fixtures - scroll.html - scroll.ts - pointer.html - pointer.ts - animation-group.html - animation-group.ts - effects.html # Named (WAAPI+CSS), Keyframe (WAAPI+CSS), Custom effects, Play/Reverse, Play/Pause - effects.ts - responsive.html - responsive.ts - selector.html - selector.ts - styles.css # Shared minimal styles - pages/ - base-fixture-page.ts - scroll-page.ts - pointer-page.ts - animation-group-page.ts - effects-page.ts - responsive-page.ts - selector-page.ts - utils/ - animation-helpers.ts - scroll-helpers.ts - pointer-helpers.ts - tests/ - scroll-animations.spec.ts - pointer-animations.spec.ts - animation-group.spec.ts - effects.spec.ts # Named (WAAPI+CSS), Keyframe (WAAPI+CSS), Custom effects, Play/Reverse, Play/Pause - responsive-conditions.spec.ts - selector-conditions.spec.ts - playwright.config.ts -``` - ---- - -## GitHub Actions Workflow (On-Demand) - -E2E tests run via the dedicated `**motion-e2e**` workflow (`.github/workflows/motion-e2e.yml`), triggered **on-demand** via `workflow_dispatch` — they do **not** run in the CI workflow. - -The workflow: - -- Is triggered manually with a browser selection input (chromium / firefox / webkit / all) -- Checks out the repo, sets up Node + Yarn, installs dependencies -- Builds the motion package -- Caches and installs Playwright browsers -- Runs `npx playwright test` (with `--project` filter for single-browser runs) -- Uploads the Playwright HTML report as an artifact (retained 14 days) diff --git a/.cursor/plans/move_type_and_method_to_effects_7a587225.plan.md b/.cursor/plans/move_type_and_method_to_effects_7a587225.plan.md deleted file mode 100644 index e43f6b60..00000000 --- a/.cursor/plans/move_type_and_method_to_effects_7a587225.plan.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -name: Move type and method to effects -overview: Move the `type` property from `PointerTriggerParams` into `TimeEffect` (as `triggerType`) and `SequenceOptionsConfig` (as `triggerType`), move the `method` property from `StateParams` into `TransitionEffect` (as `stateAction`), then remove both now-empty param types. Update all handler logic, tests, and docs. -todos: - - id: types - content: 'Update type definitions in `types.ts`: add `triggerType` to `TimeEffect` and `SequenceOptionsConfig`, add `stateAction` to `TransitionEffect`, remove `StateParams` and `PointerTriggerParams`, update unions and interfaces' - status: completed - - id: effectHandlers - content: 'Update `effectHandlers.ts`: read `triggerType`/`stateAction` from effect instead of options parameter, remove options params' - status: completed - - id: eventTrigger - content: 'Update `eventTrigger.ts`: remove casts to StateParams/PointerTriggerParams, read from effect' - status: completed - - id: handlersIndex - content: 'Update `handlers/index.ts`: simplify `withEventTriggerConfig` options parameter' - status: completed - - id: controller - content: "Update `InteractionController.ts` and `InteractElement.ts`: replace `StateParams['method']` with `TransitionMethod`" - status: completed - - id: addSequences - content: 'Update `add.ts`: pass `triggerType` from `sequenceConfig` into synthetic effect in `_processSequences` and `_processSequencesForTarget`' - status: completed - - id: tests - content: 'Update test configs in `mini.spec.ts`, `web.spec.ts`, `react.spec.tsx`: move `params.type` to effect `triggerType` and `params.method` to effect `stateAction`' - status: completed - - id: demos - content: 'Update demo components: move `params.type` to sequence config `triggerType`' - status: completed - - id: docs - content: 'Update all documentation files: `types.md`, `interaction-controller.md`, `README.md`, `full-lean.md`, `click.md`, `MASTER-CLEANUP-PLAN.md`' - status: completed - - id: verify - content: Run build and tests to verify no regressions - status: completed -isProject: false ---- - -# Move `type` and `method` from Trigger Params to Effect Types - -## Summary of Current Design - -Currently, `PointerTriggerParams.type` and `StateParams.method` live on the trigger params object and are passed through the handler chain as part of `options`. The handler code in `eventTrigger.ts` and `effectHandlers.ts` casts `options` to the appropriate type and reads `.type` or `.method`. - -```mermaid -flowchart LR - Config["InteractConfig\nparams: { type | method }"] --> AddInteraction["addInteraction()\npasses params as options"] - AddInteraction --> Handler["eventTrigger.add()\ncasts options to\nStateParams | PointerTriggerParams"] - Handler --> TimeHandler["createTimeEffectHandler()\nreads options.type"] - Handler --> TransitionHandler["createTransitionHandler()\nreads options.method"] -``` - -## Target Design - -Move `type` and `method` onto the effect objects themselves, renamed to `triggerType` and `stateAction`. Handlers read from the `effect` parameter instead of `options`. - -```mermaid -flowchart LR - Config["InteractConfig\neffect: { triggerType | stateAction }"] --> AddInteraction["addInteraction()\npasses effect"] - AddInteraction --> Handler["eventTrigger.add()\nchecks effect for\ntransition vs time"] - Handler --> TimeHandler["createTimeEffectHandler()\nreads effect.triggerType"] - Handler --> TransitionHandler["createTransitionHandler()\nreads effect.stateAction"] -``` - ---- - -## 1. Type Definition Changes - -**File:** `[packages/interact/src/types.ts](packages/interact/src/types.ts)` - -- Add `triggerType?: ViewEnterType | 'state'` to `TimeEffect` (line 104) -- Add `stateAction?: TransitionMethod` to `TransitionEffect` (line 141) -- Add `triggerType?: ViewEnterType | 'state'` to `SequenceOptionsConfig` (line 169) -- needed because sequence interactions pass a synthetic empty effect to handlers and `triggerType` controls sequence play behavior -- **Remove** `StateParams` type (lines 51-53) -- **Remove** `PointerTriggerParams` type (lines 55-57) -- Update `EventTriggerParams` to `{ eventConfig: EventTriggerConfig }` (remove the `StateParams | PointerTriggerParams` union, line 59) -- Update `TriggerParams` union: remove `StateParams` and `PointerTriggerParams` entries (lines 79-84), leaving `ViewEnterParams | PointerMoveParams | AnimationEndParams` -- Update `InteractionParamsTypes`: change `hover`, `click`, `activate`, `interest` from `StateParams | PointerTriggerParams` to `Record` (or an empty object type `{}`) (lines 252-262) -- Replace all `StateParams['method']` references with `TransitionMethod`: - - `IInteractionController.toggleEffect` (line 231) - - `IInteractElement.toggleEffect` (line 248) -- Remove `StateParams` and `PointerTriggerParams` from the module's exports (they are re-exported via `export * from './types'`) - -## 2. Handler Logic Changes - -### `[packages/interact/src/handlers/effectHandlers.ts](packages/interact/src/handlers/effectHandlers.ts)` - -- `createTimeEffectHandler` (line 15): Remove `options: PointerTriggerParams` parameter. Read `triggerType` from `effect.triggerType` instead of `options.type` (line 38: `const type = effect.triggerType || 'alternate'`) -- `createTransitionHandler` (line 94): Remove `options: StateParams` parameter. Read `stateAction` from `effect.stateAction` instead of `options.method` (line 107: `const method = effect.stateAction || 'toggle'`). Update the destructured effect type to include `stateAction` from `TransitionEffect` -- Remove imports of `StateParams` and `PointerTriggerParams` - -### `[packages/interact/src/handlers/eventTrigger.ts](packages/interact/src/handlers/eventTrigger.ts)` - -- `addEventTriggerHandler` (line 109): Update to read `triggerType`/`stateAction` from the `effect` instead of casting `options` - - Line 131-138: Remove `options as StateParams` argument from `createTransitionHandler` call - - Line 140-149: Remove `options as PointerTriggerParams` argument from `createTimeEffectHandler` call; read `once` from `(effect as TimeEffect).triggerType === 'once'` - - Lines 183-187: Read `stateAction` from `(effect as TransitionEffect).stateAction` and `triggerType` from `(effect as TimeEffect).triggerType` instead of casting options -- Remove imports of `StateParams` and `PointerTriggerParams` - -### `[packages/interact/src/handlers/index.ts](packages/interact/src/handlers/index.ts)` - -- `withEventTriggerConfig` (line 21): Change `options: StateParams | PointerTriggerParams` to just accept whatever params remain (empty object for event triggers). Simplify the spread into `eventTrigger.add(source, target, effect, { eventConfig }, ...)` since there are no trigger-level params to forward -- Remove imports of `StateParams` and `PointerTriggerParams` - -## 3. Core Logic Changes - -### `[packages/interact/src/core/InteractionController.ts](packages/interact/src/core/InteractionController.ts)` - -- Change `import type { ..., StateParams }` to `import type { ..., TransitionMethod }` -- Update `toggleEffect` method signature (line 97): `method: StateParams['method']` becomes `method: TransitionMethod` - -### `[packages/interact/src/web/InteractElement.ts](packages/interact/src/web/InteractElement.ts)` - -- Change `import type { ..., StateParams }` to `import type { ..., TransitionMethod }` -- Update `toggleEffect` method signature (line 57): `method: StateParams['method']` becomes `method: TransitionMethod` - -### `[packages/interact/src/core/add.ts](packages/interact/src/core/add.ts)` - -- `_processSequences` (line 446-457): Instead of passing `{} as Effect`, pass `{ triggerType: sequenceConfig.triggerType } as Effect` (or `{}` if no triggerType). Remove reliance on `interaction.params` for the type info -- `_processSequencesForTarget` (line 536-547): Same change as above -- pass `{ triggerType: sequenceConfig.triggerType } as Effect` - -## 4. Config Format Migration - -The user-facing config changes from: - -```typescript -// Before -{ - trigger: 'click', - params: { type: 'alternate' }, - effects: [{ effectId: 'my-effect', duration: 500, namedEffect: {...} }], -} -{ - trigger: 'hover', - params: { method: 'toggle' }, - effects: [{ effectId: 'my-transition', transition: {...} }], -} -``` - -To: - -```typescript -// After -{ - trigger: 'click', - effects: [{ effectId: 'my-effect', duration: 500, namedEffect: {...}, triggerType: 'alternate' }], -} -{ - trigger: 'hover', - effects: [{ effectId: 'my-transition', transition: {...}, stateAction: 'toggle' }], -} -``` - -For sequences: - -```typescript -// Before -{ trigger: 'click', params: { type: 'alternate' }, sequences: [{ effects: [...] }] } - -// After -{ trigger: 'click', sequences: [{ triggerType: 'alternate', effects: [...] }] } -``` - -## 5. Test Updates - -### `[packages/interact/test/mini.spec.ts](packages/interact/test/mini.spec.ts)` - -- Lines ~116-120: Move `params: { type: 'alternate' }` into each effect as `triggerType: 'alternate'` -- Lines ~129-134: Move `params: { method: 'toggle' }` into each effect as `stateAction: 'toggle'` -- Lines ~142-146: Move `params: { type: 'alternate' }` into each effect as `triggerType: 'alternate'` -- Lines ~164-168: Move `params: { method: 'toggle' }` into each effect as `stateAction: 'toggle'` - -### `[packages/interact/test/web.spec.ts](packages/interact/test/web.spec.ts)` - -- Lines ~123-127: Move `params: { type: 'alternate' }` to effect `triggerType: 'alternate'` -- Lines ~136-140: Move `params: { method: 'toggle' }` to effect `stateAction: 'toggle'` -- Lines ~150-154: Move `params: { type: 'alternate' }` to effect `triggerType: 'alternate'` -- Lines ~171-175: Move `params: { method: 'toggle' }` to effect `stateAction: 'toggle'` -- Lines ~2695-2707: Move `params: { method: 'toggle' }` to effect `stateAction: 'toggle'` - -### `[packages/interact/test/react.spec.tsx](packages/interact/test/react.spec.tsx)` - -- Lines ~73-83: Move `params: { type: 'alternate' }` to effect `triggerType: 'alternate'` -- Lines ~86-96: Move `params: { type: 'alternate' }` to effect `triggerType: 'alternate'` - -## 6. Demo Updates - -- `[apps/demo/src/web/components/SequenceClickDemo.tsx](apps/demo/src/web/components/SequenceClickDemo.tsx)` (line 9): Move `params: { type: 'alternate' }` to sequence config: `sequences: [{ triggerType: 'alternate', ... }]` -- `[apps/demo/src/web/components/SequenceEasingComparison.tsx](apps/demo/src/web/components/SequenceEasingComparison.tsx)` (line 34): Same for `params: { type: 'repeat' }` → `triggerType: 'repeat'` -- `[apps/demo/src/react/components/SequenceClickDemo.tsx](apps/demo/src/react/components/SequenceClickDemo.tsx)` (line 10): Same -- `[apps/demo/src/react/components/SequenceEasingComparison.tsx](apps/demo/src/react/components/SequenceEasingComparison.tsx)` (line 35): Same - -## 7. Documentation Updates - -- `[packages/interact/docs/api/types.md](packages/interact/docs/api/types.md)`: Remove `StateParams` and `PointerTriggerParams` sections. Add `triggerType` to `TimeEffect` docs and `stateAction` to `TransitionEffect` docs. Update `TriggerParams`, `EventTriggerParams`, `InteractionParamsTypes` docs. Update `toggleEffect` signatures to use `TransitionMethod`. -- `[packages/interact/docs/api/interaction-controller.md](packages/interact/docs/api/interaction-controller.md)`: Update `toggleEffect` signature from `StateParams['method']` to `TransitionMethod` -- `[packages/interact/docs/api/README.md](packages/interact/docs/api/README.md)`: Remove link to `StateParams` -- `[packages/interact/rules/full-lean.md](packages/interact/rules/full-lean.md)`: Update type descriptions -- `[packages/interact/rules/click.md](packages/interact/rules/click.md)`: Update `StateParams` reference -- `[packages/interact/rules/MASTER-CLEANUP-PLAN.md](packages/interact/rules/MASTER-CLEANUP-PLAN.md)`: Update `StateParams.method` row - -## 8. Verification - -- Run `yarn build` to verify TypeScript compilation -- Run tests to ensure no regressions diff --git a/.cursor/plans/split_interact_types_module_c58ed2bc.plan.md b/.cursor/plans/split_interact_types_module_c58ed2bc.plan.md deleted file mode 100644 index 2a5b8387..00000000 --- a/.cursor/plans/split_interact_types_module_c58ed2bc.plan.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -name: Split interact types module -overview: Split the monolithic `types.ts` in `@wix/interact` into concern-based modules under a new `types/` directory, with an internal barrel (all types) and an external barrel (public API types only). -todos: - - id: create-triggers - content: Create `types/triggers.ts` with trigger-related types and the `RangeOffset` re-export - status: completed - - id: create-effects - content: Create `types/effects.ts` with effect shapes, animation options, and `@wix/motion` imports - status: completed - - id: create-config - content: Create `types/config.ts` with config, sequence, condition, and interaction types - status: completed - - id: create-controller - content: Create `types/controller.ts` with `IInteractionController` and `IInteractElement` - status: completed - - id: create-handlers - content: Create `types/handlers.ts` with handler module interfaces, state types, and `InteractOptions` - status: completed - - id: create-internal - content: Create `types/internal.ts` with `InteractCache` and `CreateTransitionCSSParams` - status: completed - - id: create-global - content: Create `types/global.ts` with the JSX global augmentation - status: completed - - id: create-internal-barrel - content: Create `types/index.ts` (internal barrel) re-exporting everything - status: completed - - id: create-external-barrel - content: Create `types/external.ts` (external barrel) with explicit public API re-exports - status: completed - - id: update-entry-points - content: Update `src/index.ts`, `src/react/index.ts`, `src/web/index.ts` to use `types/external` - status: completed - - id: delete-old-types - content: Delete the original `src/types.ts` file - status: completed - - id: verify-build - content: Run build and tests to verify nothing is broken - status: completed -isProject: false ---- - -# Split `@wix/interact` Types Module by Concern - -## Current State - -All 50+ types live in a single [types.ts](packages/interact/src/types.ts) file. Three public entry points (`src/index.ts`, `src/react/index.ts`, `src/web/index.ts`) blindly re-export everything via `export * from './types'`, making internal implementation types part of the public API. - -## Proposed Directory Structure - -Replace `packages/interact/src/types.ts` with a `types/` directory: - -``` -packages/interact/src/types/ - triggers.ts -- trigger kinds, params, and related union types - effects.ts -- effect definitions, animation options - config.ts -- top-level config, sequences, conditions, interactions - controller.ts -- IInteractionController, IInteractElement interfaces - handlers.ts -- handler module interfaces, handler state types - internal.ts -- cache, CSS generation params, and other implementation-only types - global.ts -- JSX global augmentation (declare global) - index.ts -- internal barrel: re-exports everything from all submodules - external.ts -- external barrel: re-exports only public API types -``` - -## Module Breakdown - -### `triggers.ts` -- Trigger definitions and parameters - -Types: `TriggerType`, `PointerMoveAxis`, `EventTriggerKind`, `EventTriggerConfigToggle`, `EventTriggerConfigEnterLeave`, `EventTriggerConfig`, `ViewEnterType`, `TransitionMethod`, `StateParams`, `PointerTriggerParams`, `EventTriggerParams`, `ViewEnterParams`, `PointerMoveParams`, `AnimationEndParams`, `TriggerParams` - -Re-exports `RangeOffset` from `@wix/motion` (used by effects but originates here as the only direct `@wix/motion` re-export). - -### `effects.ts` -- Effect shapes and animation options - -Types: `Fill` (unexported), `MotionKeyframeEffect` (unexported), `EffectEffectProperty` (unexported), `TimeEffect`, `ScrubEffect`, `TransitionOptions`, `StyleProperty`, `TransitionProperty`, `TransitionEffect`, `EffectBase`, `EffectRef`, `Effect`, `AnimationOptions` - -Imports `NamedEffect`, `RangeOffset`, `ScrubTransitionEasing`, `MotionAnimationOptions` from `@wix/motion`. - -### `config.ts` -- Top-level configuration types - -Types: `Condition`, `SequenceOptionsConfig`, `SequenceConfig`, `SequenceConfigRef`, `InteractionTrigger`, `Interaction`, `InteractConfig` - -Imports trigger and effect types from sibling modules. - -### `controller.ts` -- Controller and element interfaces - -Types: `IInteractionController`, `IInteractElement` - -Note: `IInteractionController` is referenced by the public `InteractOptions` type, so it must also be exported externally. - -### `handlers.ts` -- Handler module and state types (internal) - -Types: `InteractionParamsTypes`, `InteractionHandlerModule`, `ViewEnterHandlerModule`, `TriggerHandlerMap`, `HandlerObject`, `HandlerObjectMap`, `InteractOptions` - -Note: `InteractOptions` is used in the handler signatures but is also relevant to library consumers (passed to `add()`). It will be exported externally as well. - -### `internal.ts` -- Implementation-only types - -Types: `InteractCache`, `CreateTransitionCSSParams` - -These are never needed by library users. - -### `global.ts` -- JSX global augmentation - -Contains the `declare global` block for `JSX.IntrinsicElements['interact-element']`. Kept separate since it's a side-effect augmentation, not a named export. - -## Internal Barrel: `types/index.ts` - -Re-exports everything from all submodules: - -```typescript -export * from './triggers'; -export * from './effects'; -export * from './config'; -export * from './controller'; -export * from './handlers'; -export * from './internal'; -import './global'; -``` - -All internal source files (`core/`, `handlers/`, `web/`, `utils.ts`) will import from `../types` (resolves to `types/index.ts`), getting access to every type. No import paths inside the package need to change since `../types` still resolves correctly. - -## External Barrel: `types/external.ts` - -Explicitly re-exports only the types that form the public API. Organized by section with comments for documentation tooling: - -```typescript -// Triggers -export type { TriggerType, PointerMoveAxis, ViewEnterType, TransitionMethod, ... } from './triggers'; -export type { RangeOffset } from './triggers'; - -// Effects -export type { TimeEffect, ScrubEffect, Effect, EffectBase, EffectRef, ... } from './effects'; - -// Config -export type { InteractConfig, Interaction, InteractionTrigger, Condition, ... } from './config'; - -// Controller -export type { IInteractionController, IInteractElement } from './controller'; - -// Options -export type { InteractOptions } from './handlers'; -``` - -**Excluded from external:** `InteractCache`, `CreateTransitionCSSParams`, `InteractionHandlerModule`, `ViewEnterHandlerModule`, `TriggerHandlerMap`, `HandlerObject`, `HandlerObjectMap`, `InteractionParamsTypes`, and the non-exported internal types (`Fill`, `MotionKeyframeEffect`, `EffectEffectProperty`). - -## Entry Point Changes - -Update the three public entry points to use the external barrel instead of the internal one: - -- [src/index.ts](packages/interact/src/index.ts): `export * from './types'` becomes `export * from './types/external'` -- [src/react/index.ts](packages/interact/src/react/index.ts): `export * from '../types'` becomes `export * from '../types/external'` -- [src/web/index.ts](packages/interact/src/web/index.ts): `export * from '../types'` becomes `export * from '../types/external'` - -## Import Path Impact - -Internal imports like `import type { Effect } from '../types'` will continue to work unchanged because `../types` resolves to the `types/` directory's `index.ts`. No internal import paths need updating. - -## Verification - -- Build the project (`nvm use && yarn build`) and confirm no type errors -- Run tests (`yarn test`) to ensure nothing breaks -- Verify that the `dist/types/` output matches expectations (external barrel controls the public `.d.ts` surface)