Skip to content

Commit

Permalink
fix(component): preserve variant style on rerender (#203)
Browse files Browse the repository at this point in the history
Co-authored-by: Bobbie Goede <[email protected]>
  • Loading branch information
ZhouY11 and BobbieGoede authored Jun 22, 2024
1 parent 54971c6 commit 94ef364
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 4 deletions.
13 changes: 13 additions & 0 deletions src/utils/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
Variant,
} from '../types/variants'
import { useMotion } from '../useMotion'
import { variantToStyle } from './transform'

/**
* Type guard, checks if passed string is an existing preset
Expand Down Expand Up @@ -228,6 +229,18 @@ export function setupMotionComponent(
)
}

/**
* Vue reapplies all styles every render, include style properties and calculated initially styles get reapplied every render.
* To prevent this, reapply the current motion state styles in vnode updated lifecycle
*/
node.props.onVnodeUpdated = ({ el }) => {
const styles = variantToStyle(instances[index].state as Variant)

for (const [key, val] of Object.entries(styles)) {
(el as any).style[key] = val
}
}

return node
}

Expand Down
38 changes: 34 additions & 4 deletions tests/components.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { config, mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import { h, nextTick } from 'vue'
import { MotionPlugin } from '../src'
import { h, nextTick, ref } from 'vue'
import { MotionComponent, MotionPlugin } from '../src'
import MotionGroup from '../src/components/MotionGroup'
import { intersect } from './utils/intersectionObserver'
import { getTestComponent, useCompletionFn, waitForMockCalls } from './utils'
Expand All @@ -10,8 +10,8 @@ import { getTestComponent, useCompletionFn, waitForMockCalls } from './utils'
config.global.plugins.push(MotionPlugin)

describe.each([
{ t: 'directive', name: '`v-motion` directive' },
{ t: 'component', name: '`<Motion>` component' },
{ t: 'directive', name: '`v-motion` directive (shared tests)' },
{ t: 'component', name: '`<Motion>` component (shared tests)' },
])(`$name`, async ({ t }) => {
const TestComponent = getTestComponent(t)

Expand Down Expand Up @@ -136,6 +136,36 @@ describe.each([
})
})

describe('`<Motion>` component', async () => {
it('#202 - preserve variant style on rerender', async () => {
const counter = ref(0)

const wrapper = mount(
{ render: () => h(MotionComponent, null, () => counter.value) },
{
props: {
initial: { scale: 1 },
enter: { scale: 2 },
duration: 10,
},
},
)

const el = wrapper.element as HTMLDivElement
await nextTick()

// Renders enter
expect(el.style.transform).toEqual('scale(2) translateZ(0px)')

// Trigger rerender by updating slot variable
counter.value++
await nextTick()

// Variant style is preserved after rerender/update
expect(el.style.transform).toEqual('scale(2) translateZ(0px)')
})
})

describe('`<MotionGroup>` component', async () => {
it('child node can overwrite helpers', async () => {
const wrapper = mount({
Expand Down

0 comments on commit 94ef364

Please sign in to comment.