From 27aa7daa914b0b5b25e07823f72f9cc689977f6a Mon Sep 17 00:00:00 2001 From: Persephone Flores <34418758+hp0844182@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:05:10 +0800 Subject: [PATCH 1/2] fix: whilePress and whileHover are not working when using variants --- .../src/features/animation/animation.ts | 2 +- playground/nuxt/pages/test.vue | 297 +++++++++++++----- 2 files changed, 220 insertions(+), 79 deletions(-) diff --git a/packages/motion/src/features/animation/animation.ts b/packages/motion/src/features/animation/animation.ts index 250642c8..1080c1dc 100644 --- a/packages/motion/src/features/animation/animation.ts +++ b/packages/motion/src/features/animation/animation.ts @@ -228,7 +228,7 @@ export class AnimationFeature extends Feature { // If current node is a variant node, merge the control node's variant if (this.state.visualElement.isVariantNode) { const controlVariant = resolveVariant(this.state.context[name], variants, customValue) - resolvedVariant = controlVariant ? Object.assign(controlVariant || {}, resolvedVariant) : variant + resolvedVariant = controlVariant ? Object.assign(controlVariant || {}, resolvedVariant) : Object.assign(variant, resolvedVariant) } if (!resolvedVariant) return diff --git a/playground/nuxt/pages/test.vue b/playground/nuxt/pages/test.vue index c54e38f2..41f49e17 100644 --- a/playground/nuxt/pages/test.vue +++ b/playground/nuxt/pages/test.vue @@ -1,93 +1,234 @@ From f9d07973790e28084e7d01b0d4f1b677042181d5 Mon Sep 17 00:00:00 2001 From: Persephone Flores <34418758+hp0844182@users.noreply.github.com> Date: Sat, 27 Sep 2025 23:59:41 +0800 Subject: [PATCH 2/2] test: add hover tests --- packages/motion/README.md | 107 +-------- playground/vite/src/views/gestures/hover.vue | 234 +++++++++++++++++++ tests/variant.spec.ts | 89 ++++++- 3 files changed, 323 insertions(+), 107 deletions(-) mode change 100644 => 120000 packages/motion/README.md create mode 100644 playground/vite/src/views/gestures/hover.vue diff --git a/packages/motion/README.md b/packages/motion/README.md deleted file mode 100644 index ac39e3cf..00000000 --- a/packages/motion/README.md +++ /dev/null @@ -1,106 +0,0 @@ -

- Motion logo -

-

Motion for Vue

- -
- -

- - - - - - - - - -

- -
-
-
- -Motion for Vue is an open source, production-ready library that’s designed for all creative developers. - -It's the only animation library with a hybrid engine, combining the power of JavaScript animations with the performance of native browser APIs. - -It looks like this: - -```jsx - -``` - -It does all this: - -- Springs -- Keyframes -- Layout animations -- Shared layout animations -- Gestures (drag/tap/hover) -- Scroll animations -- SVG paths -- Exit animations -- Server-side rendering -- Independent transforms -- Orchestrate animations across components -- CSS variables - -...and a whole lot more. - -## Get started - -### πŸ‡ Quick start - -Install `motion-v` via your package manager: - -``` -npm install motion-v -``` - -Then import the `motion` component: - -```vue - - - -``` - -### πŸ’Ž Contribute - -- Want to contribute to Motion? Our [contributing guide](https://github.com/motiondivision/motion-vue/blob/master/CONTRIBUTING.md) has you covered. -- [Join our discord ](https://discord.com/invite/dCBuRgdNDG) - -### πŸ‘©πŸ»β€βš–οΈ License - -- Motion for Vue is MIT licensed. - -## ✨ Sponsors - -Motion is sustainable thanks to the kind support of its sponsors. - -### Partners - -#### Framer - -Motion powers Framer animations, the web builder for creative pros. Design and ship your dream site. Zero code, maximum speed. - - - Framer - - -### Platinum - -Syntax.fm Tailwind Emil Kowalski Linear - -### Gold - -Vercel Liveblocks Luma - -### Silver - -Frontend.fyi Statamic Firecrawl Puzzmo Build UI Hover diff --git a/packages/motion/README.md b/packages/motion/README.md new file mode 120000 index 00000000..fe840054 --- /dev/null +++ b/packages/motion/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/playground/vite/src/views/gestures/hover.vue b/playground/vite/src/views/gestures/hover.vue new file mode 100644 index 00000000..41f49e17 --- /dev/null +++ b/playground/vite/src/views/gestures/hover.vue @@ -0,0 +1,234 @@ + + + + + diff --git a/tests/variant.spec.ts b/tests/variant.spec.ts index 13061666..8ebf83fc 100644 --- a/tests/variant.spec.ts +++ b/tests/variant.spec.ts @@ -1,7 +1,10 @@ import { expect, test } from '@playwright/test' // This test assumes the Vite dev server is running and the route is /dynamic-variant - +const pointerOptions = { + isPrimary: true, + pointerId: 1, +} test.describe('Variant', () => { test('should animate opacity when variant changes', async ({ page }) => { await page.goto('/dynamic-variant') @@ -18,4 +21,88 @@ test.describe('Variant', () => { await page.waitForTimeout(250) await expect(motionBtn).toHaveCSS('opacity', '1') }) + + test('should animate scale correctly on hover and press with variants', async ({ page }) => { + await page.goto('/gestures/hover') + + // Wait for initial animation to complete + await page.waitForTimeout(500) + + // Open the navigation menu first + await page.click('.toggle-container') + await page.waitForTimeout(300) + + // Get the first list item + const firstItem = page.locator('.list-item').first() + + // Check initial scale (should be 1 or close to 1) + const initialTransform = await firstItem.evaluate(el => + window.getComputedStyle(el).transform, + ) + + // Hover over the item - should scale to 1.1 + await firstItem.hover() + await page.waitForTimeout(200) + + const hoverTransform = await firstItem.evaluate(el => + window.getComputedStyle(el).transform, + ) + + // Extract scale value from transform matrix + const getScaleFromTransform = (transform: string) => { + if (transform === 'none') + return 1 + const matrix = transform.match(/matrix\(([^)]+)\)/) + if (matrix) { + const values = matrix[1].split(',').map(n => parseFloat(n.trim())) + return Math.round(values[0] * 100) / 100 // scaleX value, rounded to 2 decimals + } + return 1 + } + + const initialScale = getScaleFromTransform(initialTransform) + const hoverScale = getScaleFromTransform(hoverTransform) + + // Verify hover scale is approximately 1.1 + expect(hoverScale).toBeCloseTo(1.1, 1) + expect(hoverScale).toBeGreaterThan(initialScale) + + // Press the item while hovering - should scale to 0.95 + // Start press + await firstItem.dispatchEvent('pointerdown', pointerOptions) + await page.waitForTimeout(300) + + const pressTransform = await firstItem.evaluate(el => + window.getComputedStyle(el).transform, + ) + const pressScale = getScaleFromTransform(pressTransform) + + // Verify press scale is approximately 0.95 + expect(pressScale).toBeCloseTo(0.95, 1) + expect(pressScale).toBeLessThan(initialScale) + + // // Release press - should return to hover scale + await firstItem.dispatchEvent('pointerup', pointerOptions) + await page.waitForTimeout(300) + + const afterPressTransform = await firstItem.evaluate(el => + window.getComputedStyle(el).transform, + ) + const afterPressScale = getScaleFromTransform(afterPressTransform) + + // // Should return to hover scale (1.1) + expect(afterPressScale).toBeCloseTo(1.1, 1) + + // // Move mouse away - should return to initial scale + await page.mouse.move(0, 0) + await page.waitForTimeout(300) + + const finalTransform = await firstItem.evaluate(el => + window.getComputedStyle(el).transform, + ) + const finalScale = getScaleFromTransform(finalTransform) + + // // Should return to initial scale (1.0) + expect(finalScale).toBeCloseTo(1.0, 1) + }) })