Skip to content

Commit 9096c4f

Browse files
authored
Merge pull request #190 from motiondivision/feat/hook-comp
feat: useScroll supports VueInstance for container/target
2 parents 7091d24 + 0791f61 commit 9096c4f

File tree

17 files changed

+505
-439
lines changed

17 files changed

+505
-439
lines changed

.cursorignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

.cursorrules

Lines changed: 0 additions & 37 deletions
This file was deleted.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434
"test:e2e:report": "playwright show-report"
3535
},
3636
"dependencies": {
37+
"@vueuse/core": "^13.5.0",
3738
"vite": "^5.4.8",
38-
"vue": "^3.4.38"
39+
"vue": "^3.5.17"
3940
},
4041
"devDependencies": {
4142
"@antfu/eslint-config": "^2.27.3",

packages/motion/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,12 @@
7070
"pub:release": "pnpm publish --access public"
7171
},
7272
"peerDependencies": {
73+
"@vueuse/core": "^10.0.0",
7374
"vue": ">=3.0.0"
7475
},
7576
"dependencies": {
76-
"@vueuse/core": "^10.0.0",
7777
"framer-motion": "12.22.0",
7878
"hey-listen": "^1.0.8",
7979
"motion-dom": "12.22.0"
80-
},
81-
"devDependencies": {
82-
"vue": "3.4.38"
8380
}
8481
}

packages/motion/src/components/animate-presence/use-pop-layout.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ export function usePopLayout(props: AnimatePresenceProps) {
99
function addPopStyle(state: MotionState) {
1010
if (props.mode !== 'popLayout')
1111
return
12-
const parent = state.element.offsetParent
12+
const element = state.element as HTMLElement
13+
const parent = element.offsetParent
1314
const parentWidth
1415
= parent instanceof HTMLElement ? parent.offsetWidth || 0 : 0
1516
const size = {
16-
height: state.element.offsetHeight || 0,
17-
width: state.element.offsetWidth || 0,
18-
top: state.element.offsetTop,
19-
left: state.element.offsetLeft,
17+
height: element.offsetHeight || 0,
18+
width: element.offsetWidth || 0,
19+
top: element.offsetTop,
20+
left: element.offsetLeft,
2021
right: 0,
2122
}
2223
size.right = parentWidth - size.width - size.left

packages/motion/src/components/animate-presence/use-presence.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { onMounted } from 'vue'
22
import { useMotionElm } from '@/components/hooks/use-motion-elm'
33

4-
export const presenceMeasure = new Map<HTMLElement, boolean>()
4+
export const presenceMeasure = new Map<HTMLElement | SVGElement, boolean>()
55
export function usePresence() {
66
const motionElement = useMotionElm()
77
onMounted(() => {

packages/motion/src/components/hooks/use-motion-elm.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
1+
import { type MaybeComputedElementRef, unrefElement } from '@vueuse/core'
12
import { getCurrentInstance, onMounted } from 'vue'
23

34
/**
45
* Get the actual motion element, skipping text and comment nodes
56
* @param el - The HTML element to check
67
* @returns The first non-text/comment element
78
*/
8-
export function getMotionElement(el: HTMLElement) {
9-
if (el?.nodeType === 3 || el?.nodeType === 8)
10-
return getMotionElement(el.nextSibling as HTMLElement)
9+
export function getMotionElement(el: HTMLElement | SVGElement | null): HTMLElement | SVGElement | undefined {
10+
if (!el)
11+
return undefined
12+
13+
if (el.nodeType === 3 || el.nodeType === 8) {
14+
return getMotionElement(el.nextSibling as HTMLElement | SVGElement | null)
15+
}
1116

1217
return el
1318
}
1419

20+
/**
21+
* Get the actual element, skipping text and comment nodes
22+
* @param target - The element to check
23+
* @returns The first non-text/comment element
24+
*/
25+
export function getElement(target: MaybeComputedElementRef) {
26+
return getMotionElement(unrefElement(target))
27+
}
28+
1529
/**
1630
* Hook to get the motion element of current component instance
1731
* @returns Function that returns the motion element
1832
*/
1933
export function useMotionElm() {
2034
const instance = getCurrentInstance().proxy
2135
const motionElement = {
22-
value: null as HTMLElement | null,
36+
value: null as HTMLElement | SVGElement | null,
2337
}
2438
onMounted(() => {
2539
motionElement.value = getMotionElement(instance.$el)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const mountedLayoutIds = new Set<string>()
2525
export class MotionState {
2626
public readonly id: string
2727
public type: 'html' | 'svg'
28-
public element: HTMLElement | null = null
28+
public element: HTMLElement | SVGElement | null = null
2929
// Parent reference for handling component tree relationships
3030
public parent?: MotionState
3131
public options: Options & {
@@ -130,7 +130,7 @@ export class MotionState {
130130
}
131131

132132
// Mount motion state to DOM element, handles parent-child relationships
133-
mount(element: HTMLElement, options: Options, notAnimate = false) {
133+
mount(element: HTMLElement | SVGElement, options: Options, notAnimate = false) {
134134
invariant(
135135
Boolean(element),
136136
'Animation state must be mounted with valid Element',

packages/motion/src/types/common.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Component, DefineComponent, ExtractPropTypes, ExtractPublicPropTypes, IntrinsicElementAttributes } from 'vue'
1+
import type { Component, DefineComponent, ExtractPropTypes, ExtractPublicPropTypes, IntrinsicElementAttributes, MaybeRef } from 'vue'
22

33
export type ComponentProps<T> = T extends DefineComponent<
44
ExtractPropTypes<infer Props>,
@@ -10,3 +10,7 @@ export type ComponentProps<T> = T extends DefineComponent<
1010

1111
export type ElementType = keyof IntrinsicElementAttributes
1212
export type AsTag = keyof IntrinsicElementAttributes | ({} & string) | Component // any other string
13+
14+
export type ToRefs<T> = {
15+
[K in keyof T]: MaybeRef<T[K]>
16+
}

packages/motion/src/utils/use-in-view.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import type { Ref } from 'vue'
2-
import { isRef, ref, unref, watch } from 'vue'
2+
import { ref, unref, watchEffect } from 'vue'
33
import type { Options } from '@/types/state'
44
import { inView } from 'framer-motion/dom'
5+
import type { MaybeRef } from '@vueuse/core'
56

67
export function useInView<T extends Element = any>(
78
domRef: Ref<T | null>,
8-
options?: Options['inViewOptions'] | Ref<Options['inViewOptions']>,
9+
options?: MaybeRef<Options['inViewOptions']>,
910
) {
1011
const isInView = ref(false)
1112

12-
watch([domRef, () => isRef(options) ? options.value : options], (_v1, _v2, onCleanup) => {
13+
watchEffect((onCleanup) => {
1314
const realOptions = unref(options) || {}
1415
const { once } = realOptions
1516
if (!domRef.value || (once && isInView.value)) {
@@ -28,7 +29,7 @@ export function useInView<T extends Element = any>(
2829
cleanup()
2930
})
3031
}, {
31-
immediate: true,
32+
flush: 'post',
3233
})
3334

3435
return isInView

0 commit comments

Comments
 (0)