generated from timlrx/tailwind-nextjs-starter-blog
-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.tsx
103 lines (82 loc) · 2.77 KB
/
index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { omit, omitBy } from 'lodash-es'
import { isValidMotionProp, type motion } from 'framer-motion'
import { htmlElements, svgElements } from './support-elements'
import type { FramerMotionModules } from '@/hooks/framer-motion'
import { useFramerMotion } from '@/hooks/framer-motion'
export interface LazyFramerMotionAction<Dom extends HTMLElement = any> {
getDom: () => Dom | null
}
export interface LazyFramerMotionChildrenProps<Dom extends HTMLElement = any>
extends Omit<FramerMotionModules, 'motion'> {
m: typeof motion
domRef: React.RefObject<Dom>
fallbackDom: React.ReactNode
}
export interface LazyFramerMotionFallbackProps<Dom extends HTMLElement = any> {
m: typeof motion
domRef: React.RefObject<Dom>
}
export interface LazyFramerMotionProps<Dom extends HTMLElement = any> {
/**
* Render fallback only, you can use it for:
*
* - Debug for fallback dom
* - Wait some state ready to use
* - No others modules deps, except `motion` module
*/
fallbackOnly?: boolean
fallback?:
| React.ReactNode
| ((props: LazyFramerMotionFallbackProps<Dom>) => React.ReactNode)
actionRef?: React.RefObject<LazyFramerMotionAction<Dom>>
children?: (props: LazyFramerMotionChildrenProps) => JSX.Element
}
function LazyFramerMotion<Dom extends HTMLElement = any>(
props: LazyFramerMotionProps,
) {
const { fallback, fallbackOnly, actionRef, children } = props
const { ready, modules } = useFramerMotion()
const fallbackRef = useRef<Dom>(null)
const renderRef = useRef<Dom>(null)
useImperativeHandle(actionRef, () => {
return {
getDom: () => {
return renderRef.current || fallbackRef.current
},
}
})
const m: typeof motion = useMemo(() => {
if (ready) {
return modules.motion
}
const fallbackMotion = {} as typeof motion
;[...htmlElements, ...svgElements].forEach((item) => {
// eslint-disable-next-line react/no-nested-components
function FallbackMotionElement(_props: any, ref: any) {
const props: any = omitBy(_props, (_, key) => {
if (key === 'style') {
return false
}
return isValidMotionProp(key)
})
return createElement(item, { ref, ...props })
}
const component = forwardRef<any, any>(FallbackMotionElement)
component.displayName = item
fallbackMotion[item] = component as any
})
return fallbackMotion
}, [modules?.motion, ready])
const restModules = omit(modules, 'motion')
const fallbackDom
= typeof fallback === 'function'
? fallback?.({ m, domRef: fallbackRef })
: fallback
if (ready && !fallbackOnly) {
return (
<>{children?.({ ...restModules, m, domRef: renderRef, fallbackDom })}</>
)
}
return <>{fallbackDom}</>
}
export default LazyFramerMotion