Skip to content

Commit 0b9fa93

Browse files
authored
Merge pull request #181 from motiondivision/fix/motion-config
fix: rename reduceMotion to reducedMotion and update related types
2 parents 36fa0e7 + 6462ba2 commit 0b9fa93

File tree

13 files changed

+71
-82
lines changed

13 files changed

+71
-82
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
2+
import { mount } from '@vue/test-utils'
3+
import { motionValue } from 'framer-motion/dom'
4+
import { defineComponent, nextTick } from 'vue'
5+
import MotionConfig from '@/components/motion-config/MotionConfig.vue'
6+
import { Motion } from '@/components/motion'
7+
8+
describe('reducedMotion', () => {
9+
it('reducedMotion always', async () => {
10+
const scale = motionValue(1)
11+
const wrapper = mount(defineComponent({
12+
setup() {
13+
return () => (
14+
<MotionConfig reducedMotion="always">
15+
<Motion animate={{ scale: 0.5 }} style={{ scale }} />
16+
</MotionConfig>
17+
)
18+
},
19+
}))
20+
await nextTick()
21+
await new Promise(resolve => setTimeout(resolve, 20))
22+
expect(scale.get()).toBe(0.5)
23+
})
24+
})

packages/motion/src/components/motion-config/MotionConfig.vue

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,28 @@
22
import { computed } from 'vue'
33
import type { MotionConfigProps } from './types'
44
import { defaultConfig, provideMotionConfig, useMotionConfig } from './context'
5+
import { isDef } from '@vueuse/core'
6+
import { warning } from 'hey-listen'
57
68
defineOptions({
79
name: 'MotionConfig',
810
inheritAttrs: false,
911
})
1012
11-
const props = withDefaults(defineProps<MotionConfigProps>(), {
12-
reduceMotion: defaultConfig.reduceMotion,
13+
const props = withDefaults(defineProps<MotionConfigProps & { reducedMotion?: 'user' | 'never' | 'always' }>(), {
14+
reducedMotion: ({ reduceMotion }) => {
15+
if (isDef(reduceMotion)) {
16+
warning(false, '`reduceMotion` is deprecated. Use `reducedMotion` instead.')
17+
return reduceMotion
18+
}
19+
return defaultConfig.reducedMotion
20+
},
1321
})
1422
1523
const parentConfig = useMotionConfig()
1624
const config = computed(() => ({
1725
transition: props.transition ?? parentConfig.value.transition,
18-
reduceMotion: props.reduceMotion ?? parentConfig.value.reduceMotion,
26+
reducedMotion: props.reducedMotion ?? parentConfig.value.reducedMotion,
1927
nonce: props.nonce ?? parentConfig.value.nonce,
2028
inViewOptions: props.inViewOptions ?? parentConfig.value.inViewOptions,
2129
}))

packages/motion/src/components/motion-config/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { type ComputedRef, computed } from 'vue'
66
* Default motion configuration
77
*/
88
export const defaultConfig: MotionConfigState = {
9-
reduceMotion: 'never',
9+
reducedMotion: 'never',
1010
transition: undefined,
1111
nonce: undefined,
1212
}

packages/motion/src/components/motion-config/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ import type { Options } from '@/types'
66
export interface MotionConfigState {
77
/** Default transition settings for animations */
88
transition?: Options['transition']
9-
/** Controls motion reduction based on user preference or explicit setting */
9+
/**
10+
* @deprecated Use `reducedMotion` instead
11+
*/
1012
reduceMotion?: 'user' | 'never' | 'always'
13+
/** Controls motion reduction based on user preference or explicit setting */
14+
reducedMotion?: 'user' | 'never' | 'always'
1115
/** Custom nonce for CSP compliance with inline styles */
1216
nonce?: string
1317
/** Options for the inView prop */

packages/motion/src/components/motion/types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import type { Feature } from '@/features'
21
import type { AsTag, ComponentProps, Options, SVGAttributesWithMotionValues, SetMotionValueType } from '@/types'
32
import type { IntrinsicElementAttributes } from 'vue'
43

5-
export interface MotionProps<T extends AsTag = 'div', K = unknown> extends Options<K> {
4+
export interface MotionProps<T extends AsTag = 'div', K = unknown> extends Omit<Options<K>, 'motionConfig' | 'layoutGroup'> {
65
as?: T
76
asChild?: boolean
87
hover?: Options['hover']
@@ -15,7 +14,7 @@ export interface MotionProps<T extends AsTag = 'div', K = unknown> extends Optio
1514
whileInView?: Options['whileInView']
1615
whileFocus?: Options['whileFocus']
1716
forwardMotionProps?: boolean
18-
features?: Feature[]
17+
// features?: Feature[]
1918
ignoreStrict?: boolean
2019
}
2120
type __VLS_PrettifyLocal<T> = {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export function useMotionState(props: MotionProps) {
3333
*/
3434
if (
3535
process.env.NODE_ENV !== 'production'
36+
// @ts-expect-error
3637
&& props.features?.length
3738
&& lazyMotionContext.strict
3839
) {

packages/motion/src/components/motion/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export function createMotionComponent(
111111
},
112112
name: name ? `motion.${name}` : 'Motion',
113113
setup(props, { slots }) {
114-
const { getProps, getAttrs, state } = useMotionState(props as MotionProps)
114+
const { getProps, getAttrs, state } = useMotionState(props as any)
115115
/**
116116
* Vue reapplies all styles every render, include style properties and calculated initially styles get reapplied every render.
117117
* To prevent this, reapply the current motion state styles in vnode updated lifecycle
@@ -159,7 +159,7 @@ export function createMotionComponent(
159159
}
160160

161161
type MotionNameSpace = {
162-
[K in keyof IntrinsicElementAttributes]: DefineComponent<Omit<MotionProps<K, unknown>, 'as' | 'asChild'> & MotionHTMLAttributes<K>, 'create'>
162+
[K in keyof IntrinsicElementAttributes]: DefineComponent<Omit<MotionProps<K, unknown>, 'as' | 'asChild' | 'motionConfig' | 'layoutGroup'> & MotionHTMLAttributes<K>, 'create'>
163163
} & MotionCompProps
164164

165165
export function createMotionComponentWithFeatures(

packages/motion/src/features/animation/animation.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { isDef } from '@vueuse/core'
1212
import type { VisualElement } from 'framer-motion'
1313
import { animate, noop } from 'framer-motion/dom'
1414
import { createVisualElement } from '@/state/create-visual-element'
15+
import { prefersReducedMotion } from 'framer-motion/dist/es/utils/reduced-motion/state.mjs'
1516

1617
const STATE_TYPES = ['initial', 'animate', 'whileInView', 'whileHover', 'whilePress', 'whileDrag', 'whileFocus', 'exit'] as const
1718
export type StateType = typeof STATE_TYPES[number]
@@ -40,8 +41,9 @@ export class AnimationFeature extends Feature {
4041
...this.state.baseTarget,
4142
},
4243
},
43-
reducedMotionConfig: this.state.options.motionConfig.reduceMotion,
44+
reducedMotionConfig: this.state.options.motionConfig.reducedMotion,
4445
})
46+
4547
this.state.animateUpdates = this.animateUpdates
4648
if (this.state.isMounted())
4749
this.state.startAnimation()
@@ -62,6 +64,10 @@ export class AnimationFeature extends Feature {
6264
isFallback,
6365
isExit,
6466
} = {}) => {
67+
// check if the user has reduced motion
68+
const { reducedMotion } = this.state.options.motionConfig
69+
this.state.visualElement.shouldReduceMotion = reducedMotion === 'always' || (reducedMotion === 'user' && !!prefersReducedMotion.current)
70+
6571
const prevTarget = this.state.target
6672
this.state.target = { ...this.state.baseTarget }
6773
let animationOptions: $Transition = {}

packages/motion/src/framer-motion.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,8 @@ declare module 'framer-motion/dist/es/render/utils/setters.mjs' {
6767

6868
export const setTarget: (visualElement: VisualElement, definition: any) => void
6969
}
70+
71+
declare module 'framer-motion/dist/es/utils/reduced-motion/state.mjs' {
72+
export const prefersReducedMotion: { current: boolean }
73+
export const hasReducedMotionListener: { current: boolean }
74+
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ export class MotionState {
119119
this.visualElement?.update({
120120
...this.options as any,
121121
whileTap: this.options.whilePress,
122-
reducedMotionConfig: this.options.motionConfig.reduceMotion,
123122
}, {
124123
isPresent: !doneCallbacks.has(this.element),
125124
} as any)

0 commit comments

Comments
 (0)