Skip to content

Commit 36fa0e7

Browse files
authored
Merge pull request #180 from motiondivision/fix/variant
fix: dynamic variant update didn't trigger update
2 parents 16e0591 + a431010 commit 36fa0e7

File tree

4 files changed

+56
-32
lines changed

4 files changed

+56
-32
lines changed

packages/motion/src/state/motion-state.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { MotionStateContext, Options } from '@/types'
22
import { invariant } from 'hey-listen'
33
import type { DOMKeyframesDefinition, VisualElement } from 'framer-motion'
44
import { cancelFrame, frame, noop } from 'framer-motion/dom'
5-
import { isAnimateChanged, isSVGElement, resolveVariant } from '@/state/utils'
5+
import { isSVGElement, resolveVariant } from '@/state/utils'
66
import type { Feature, StateType } from '@/features'
77
import { FeatureManager } from '@/features'
88
import type { PresenceContext } from '@/components/animate-presence/presence'
@@ -212,14 +212,11 @@ export class MotionState {
212212

213213
// Update motion state with new options
214214
update(options: Options) {
215-
const hasAnimateChange = isAnimateChanged(this.options, options)
216215
this.updateOptions(options)
217216
// Update features in parent-to-child order
218217
this.featureManager.update()
219218

220-
if (hasAnimateChange) {
221-
this.startAnimation()
222-
}
219+
this.startAnimation()
223220
}
224221

225222
// Set animation state active status and propagate to children

packages/motion/src/state/utils.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -133,30 +133,3 @@ const svgElementSet = new Set(svgElements)
133133
export function isSVGElement(as: AsTag): as is SVGElements {
134134
return svgElementSet.has(as as SVGElements)
135135
}
136-
137-
export function isAnimateChanged(oldOptions: Options, newOptions: Options): boolean {
138-
const oldAnimate = oldOptions.animate
139-
const newAnimate = newOptions.animate
140-
if (oldAnimate === newAnimate)
141-
return false
142-
if (!oldAnimate || !newAnimate) {
143-
return true
144-
}
145-
146-
if (typeof oldAnimate === 'object' || typeof newAnimate === 'object') {
147-
// Compare object keys and values
148-
const oldKeys = Object.keys(oldAnimate)
149-
const newKeys = Object.keys(newAnimate)
150-
151-
if (oldKeys.length !== newKeys.length)
152-
return true
153-
return oldKeys.some((key) => {
154-
if (key === 'transition')
155-
return false
156-
const oldVal = oldAnimate[key]
157-
const newVal = newAnimate[key]
158-
return oldVal !== newVal
159-
})
160-
}
161-
return oldAnimate !== newAnimate
162-
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
// Use local alias for dev, not 'motion-vue'
4+
import { motion } from 'motion-v'
5+
6+
const show = ref(true)
7+
const toggle = () => (show.value = !show.value)
8+
const variants = {
9+
initial: { y: 20, opacity: 0 },
10+
visible: { y: 0, opacity: 1 },
11+
hidden: { y: 0, opacity: 0.25 },
12+
}
13+
</script>
14+
15+
<template>
16+
<div style="padding: 40px">
17+
<button
18+
data-testid="toggle-btn"
19+
@click="toggle"
20+
>
21+
Toggle
22+
</button>
23+
<motion.button
24+
data-testid="motion-btn"
25+
initial="initial"
26+
:variants="variants"
27+
:while-in-view="show ? 'visible' : 'hidden'"
28+
style="width: 120px; height: 40px; margin-top: 20px"
29+
>
30+
CLICK ME
31+
</motion.button>
32+
</div>
33+
</template>

tests/variant.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { expect, test } from '@playwright/test'
2+
3+
// This test assumes the Vite dev server is running and the route is /dynamic-variant
4+
5+
test.describe('Variant', () => {
6+
test('should animate opacity when variant changes', async ({ page }) => {
7+
await page.goto('/dynamic-variant')
8+
const motionBtn = page.locator('[data-testid="motion-btn"]')
9+
// Initial: visible
10+
await expect(motionBtn).toHaveCSS('opacity', '1')
11+
// Click toggle
12+
await page.click('[data-testid="toggle-btn"]')
13+
// After: hidden
14+
await page.waitForTimeout(250)
15+
await expect(motionBtn).toHaveCSS('opacity', '0.25')
16+
// Click toggle again
17+
await page.click('[data-testid="toggle-btn"]')
18+
await page.waitForTimeout(250)
19+
await expect(motionBtn).toHaveCSS('opacity', '1')
20+
})
21+
})

0 commit comments

Comments
 (0)