@@ -16,6 +16,11 @@ import type {
16
16
import { STATUS_NONE , STEP_PREPARE , STEP_START } from './interface' ;
17
17
import { getTransitionName , supportTransition } from './util/motion' ;
18
18
19
+ export interface CSSMotionRef {
20
+ nativeElement : HTMLElement ;
21
+ inMotion : ( ) => boolean ;
22
+ }
23
+
19
24
export type CSSMotionConfig =
20
25
| boolean
21
26
| {
@@ -117,116 +122,121 @@ export function genCSSMotion(config: CSSMotionConfig) {
117
122
return ! ! ( props . motionName && transitionSupport && contextMotion !== false ) ;
118
123
}
119
124
120
- const CSSMotion = React . forwardRef < any , CSSMotionProps > ( ( props , ref ) => {
121
- const {
122
- // Default config
123
- visible = true ,
124
- removeOnLeave = true ,
125
-
126
- forceRender,
127
- children,
128
- motionName,
129
- leavedClassName,
130
- eventProps,
131
- } = props ;
132
-
133
- const { motion : contextMotion } = React . useContext ( Context ) ;
134
-
135
- const supportMotion = isSupportTransition ( props , contextMotion ) ;
136
-
137
- // Ref to the react node, it may be a HTMLElement
138
- const nodeRef = useRef < any > ( ) ;
139
-
140
- function getDomElement ( ) {
141
- return getDOM ( nodeRef . current ) as HTMLElement ;
142
- }
143
-
144
- const [ status , statusStep , statusStyle , mergedVisible ] = useStatus (
145
- supportMotion ,
146
- visible ,
147
- getDomElement ,
148
- props ,
149
- ) ;
150
-
151
- // Record whether content has rendered
152
- // Will return null for un-rendered even when `removeOnLeave={false}`
153
- const renderedRef = React . useRef ( mergedVisible ) ;
154
- if ( mergedVisible ) {
155
- renderedRef . current = true ;
156
- }
157
-
158
- // ====================== Refs ======================
159
- React . useImperativeHandle ( ref , ( ) => getDomElement ( ) ) ;
160
-
161
- // ===================== Render =====================
162
- let motionChildren : React . ReactNode ;
163
- const mergedProps = { ...eventProps , visible } ;
164
-
165
- if ( ! children ) {
166
- // No children
167
- motionChildren = null ;
168
- } else if ( status === STATUS_NONE ) {
169
- // Stable children
170
- if ( mergedVisible ) {
171
- motionChildren = children ( { ...mergedProps } , nodeRef ) ;
172
- } else if ( ! removeOnLeave && renderedRef . current && leavedClassName ) {
173
- motionChildren = children (
174
- { ...mergedProps , className : leavedClassName } ,
175
- nodeRef ,
176
- ) ;
177
- } else if ( forceRender || ( ! removeOnLeave && ! leavedClassName ) ) {
178
- motionChildren = children (
179
- { ...mergedProps , style : { display : 'none' } } ,
180
- nodeRef ,
181
- ) ;
182
- } else {
183
- motionChildren = null ;
184
- }
185
- } else {
186
- // In motion
187
- let statusSuffix : string ;
188
- if ( statusStep === STEP_PREPARE ) {
189
- statusSuffix = 'prepare' ;
190
- } else if ( isActive ( statusStep ) ) {
191
- statusSuffix = 'active' ;
192
- } else if ( statusStep === STEP_START ) {
193
- statusSuffix = 'start' ;
194
- }
125
+ const CSSMotion = React . forwardRef < CSSMotionRef , CSSMotionProps > (
126
+ ( props , ref ) => {
127
+ const {
128
+ // Default config
129
+ visible = true ,
130
+ removeOnLeave = true ,
195
131
196
- const motionCls = getTransitionName (
132
+ forceRender,
133
+ children,
197
134
motionName,
198
- `${ status } -${ statusSuffix } ` ,
199
- ) ;
135
+ leavedClassName,
136
+ eventProps,
137
+ } = props ;
138
+
139
+ const { motion : contextMotion } = React . useContext ( Context ) ;
140
+
141
+ const supportMotion = isSupportTransition ( props , contextMotion ) ;
200
142
201
- motionChildren = children (
202
- {
203
- ...mergedProps ,
204
- className : classNames ( getTransitionName ( motionName , status ) , {
205
- [ motionCls ] : motionCls && statusSuffix ,
206
- [ motionName as string ] : typeof motionName === 'string' ,
207
- } ) ,
208
- style : statusStyle ,
209
- } ,
210
- nodeRef ,
143
+ // Ref to the react node, it may be a HTMLElement
144
+ const nodeRef = useRef < any > ( ) ;
145
+
146
+ function getDomElement ( ) {
147
+ return getDOM ( nodeRef . current ) as HTMLElement ;
148
+ }
149
+
150
+ const [ status , statusStep , statusStyle , mergedVisible ] = useStatus (
151
+ supportMotion ,
152
+ visible ,
153
+ getDomElement ,
154
+ props ,
211
155
) ;
212
- }
213
156
214
- // Auto inject ref if child node not have `ref` props
215
- if ( React . isValidElement ( motionChildren ) && supportRef ( motionChildren ) ) {
216
- const originNodeRef = getNodeRef ( motionChildren ) ;
157
+ // Record whether content has rendered
158
+ // Will return null for un-rendered even when `removeOnLeave={false}`
159
+ const renderedRef = React . useRef ( mergedVisible ) ;
160
+ if ( mergedVisible ) {
161
+ renderedRef . current = true ;
162
+ }
163
+
164
+ // ====================== Refs ======================
165
+ React . useImperativeHandle ( ref , ( ) => ( {
166
+ nativeElement : getDomElement ( ) ,
167
+ inMotion : ( ) => status !== STATUS_NONE ,
168
+ } ) ) ;
169
+
170
+ // ===================== Render =====================
171
+ let motionChildren : React . ReactNode ;
172
+ const mergedProps = { ...eventProps , visible } ;
173
+
174
+ if ( ! children ) {
175
+ // No children
176
+ motionChildren = null ;
177
+ } else if ( status === STATUS_NONE ) {
178
+ // Stable children
179
+ if ( mergedVisible ) {
180
+ motionChildren = children ( { ...mergedProps } , nodeRef ) ;
181
+ } else if ( ! removeOnLeave && renderedRef . current && leavedClassName ) {
182
+ motionChildren = children (
183
+ { ...mergedProps , className : leavedClassName } ,
184
+ nodeRef ,
185
+ ) ;
186
+ } else if ( forceRender || ( ! removeOnLeave && ! leavedClassName ) ) {
187
+ motionChildren = children (
188
+ { ...mergedProps , style : { display : 'none' } } ,
189
+ nodeRef ,
190
+ ) ;
191
+ } else {
192
+ motionChildren = null ;
193
+ }
194
+ } else {
195
+ // In motion
196
+ let statusSuffix : string ;
197
+ if ( statusStep === STEP_PREPARE ) {
198
+ statusSuffix = 'prepare' ;
199
+ } else if ( isActive ( statusStep ) ) {
200
+ statusSuffix = 'active' ;
201
+ } else if ( statusStep === STEP_START ) {
202
+ statusSuffix = 'start' ;
203
+ }
204
+
205
+ const motionCls = getTransitionName (
206
+ motionName ,
207
+ `${ status } -${ statusSuffix } ` ,
208
+ ) ;
217
209
218
- if ( ! originNodeRef ) {
219
- motionChildren = React . cloneElement (
220
- motionChildren as React . ReactElement ,
210
+ motionChildren = children (
221
211
{
222
- ref : nodeRef ,
212
+ ...mergedProps ,
213
+ className : classNames ( getTransitionName ( motionName , status ) , {
214
+ [ motionCls ] : motionCls && statusSuffix ,
215
+ [ motionName as string ] : typeof motionName === 'string' ,
216
+ } ) ,
217
+ style : statusStyle ,
223
218
} ,
219
+ nodeRef ,
224
220
) ;
225
221
}
226
- }
227
222
228
- return motionChildren as React . ReactElement ;
229
- } ) ;
223
+ // Auto inject ref if child node not have `ref` props
224
+ if ( React . isValidElement ( motionChildren ) && supportRef ( motionChildren ) ) {
225
+ const originNodeRef = getNodeRef ( motionChildren ) ;
226
+
227
+ if ( ! originNodeRef ) {
228
+ motionChildren = React . cloneElement (
229
+ motionChildren as React . ReactElement ,
230
+ {
231
+ ref : nodeRef ,
232
+ } ,
233
+ ) ;
234
+ }
235
+ }
236
+
237
+ return motionChildren as React . ReactElement ;
238
+ } ,
239
+ ) ;
230
240
231
241
CSSMotion . displayName = 'CSSMotion' ;
232
242
0 commit comments