33import React from 'react' ;
44import PropTypes from 'prop-types' ;
55import ReactDOM from 'react-dom' ;
6- import EventListener from 'react-event-listener' ;
76import debounce from 'debounce' ; // < 1kb payload overhead when lodash/debounce is > 3kb.
87import { Transition } from 'react-transition-group' ;
9- import { setRef } from '../utils/reactHelpers' ;
8+ import { useForkRef } from '../utils/reactHelpers' ;
109import withTheme from '../styles/withTheme' ;
1110import { duration } from '../styles/transitions' ;
1211import { reflow , getTransitionProps } from '../transitions/utils' ;
@@ -16,8 +15,7 @@ const GUTTER = 24;
1615// Translate the node so he can't be seen on the screen.
1716// Later, we gonna translate back the node to his original location
1817// with `translate3d(0, 0, 0)`.`
19- function getTranslateValue ( props , node ) {
20- const { direction } = props ;
18+ function getTranslateValue ( direction , node ) {
2119 const rect = node . getBoundingClientRect ( ) ;
2220
2321 let transform ;
@@ -59,8 +57,8 @@ function getTranslateValue(props, node) {
5957 return `translateY(-${ rect . top + rect . height + GUTTER - offsetY } px)` ;
6058}
6159
62- export function setTranslateValue ( props , node ) {
63- const transform = getTranslateValue ( props , node ) ;
60+ export function setTranslateValue ( direction , node ) {
61+ const transform = getTranslateValue ( direction , node ) ;
6462
6563 if ( transform ) {
6664 node . style . webkitTransform = transform ;
@@ -72,65 +70,49 @@ export function setTranslateValue(props, node) {
7270 * The Slide transition is used by the [Drawer](/demos/drawers/) component.
7371 * It uses [react-transition-group](https://github.com/reactjs/react-transition-group) internally.
7472 */
75- class Slide extends React . Component {
76- mounted = false ;
77-
78- constructor ( ) {
79- super ( ) ;
80-
81- if ( typeof window !== 'undefined' ) {
82- this . handleResize = debounce ( ( ) => {
83- // Skip configuration where the position is screen size invariant.
84- if ( this . props . in || this . props . direction === 'down' || this . props . direction === 'right' ) {
85- return ;
86- }
87-
88- if ( this . childDOMNode ) {
89- setTranslateValue ( this . props , this . childDOMNode ) ;
90- }
91- } , 166 ) ; // Corresponds to 10 frames at 60 Hz.
92- }
93- }
94-
95- componentDidMount ( ) {
96- this . mounted = true ;
97-
98- // state.mounted handle SSR, once the component is mounted, we need
99- // to properly hide it.
100- if ( ! this . props . in ) {
101- // We need to set initial translate values of transition element
102- // otherwise component will be shown when in=false.
103- this . updatePosition ( ) ;
104- }
105- }
106-
107- componentDidUpdate ( prevProps ) {
108- if ( prevProps . direction !== this . props . direction && ! this . props . in ) {
109- // We need to update the position of the drawer when the direction change and
110- // when it's hidden.
111- this . updatePosition ( ) ;
112- }
113- }
114-
115- componentWillUnmount ( ) {
116- this . handleResize . clear ( ) ;
117- }
73+ function Slide ( props ) {
74+ const {
75+ children,
76+ direction,
77+ in : inProp ,
78+ onEnter,
79+ onEntering,
80+ onExit,
81+ onExited,
82+ style,
83+ theme,
84+ timeout,
85+ ...other
86+ } = props ;
87+
88+ const childrenRef = React . useRef ( ) ;
89+ /**
90+ * used in cloneElement(children, { ref: handleRef })
91+ */
92+ const handleOwnRef = React . useCallback ( ref => {
93+ // #StrictMode ready
94+ childrenRef . current = ReactDOM . findDOMNode ( ref ) ;
95+ } , [ ] ) ;
96+ const handleRef = useForkRef ( children . ref , handleOwnRef ) ;
11897
119- handleEnter = node => {
120- setTranslateValue ( this . props , node ) ;
98+ const handleEnter = ( ) => {
99+ const node = childrenRef . current ;
100+ setTranslateValue ( direction , node ) ;
121101 reflow ( node ) ;
122102
123- if ( this . props . onEnter ) {
124- this . props . onEnter ( node ) ;
103+ if ( onEnter ) {
104+ onEnter ( node ) ;
125105 }
126106 } ;
127107
128- handleEntering = node => {
129- const { theme } = this . props ;
130-
131- const transitionProps = getTransitionProps ( this . props , {
132- mode : 'enter' ,
133- } ) ;
108+ const handleEntering = ( ) => {
109+ const node = childrenRef . current ;
110+ const transitionProps = getTransitionProps (
111+ { timeout, style } ,
112+ {
113+ mode : 'enter' ,
114+ } ,
115+ ) ;
134116 node . style . webkitTransition = theme . transitions . create ( '-webkit-transform' , {
135117 ...transitionProps ,
136118 easing : theme . transitions . easing . easeOut ,
@@ -141,17 +123,19 @@ class Slide extends React.Component {
141123 } ) ;
142124 node . style . webkitTransform = 'translate(0, 0)' ;
143125 node . style . transform = 'translate(0, 0)' ;
144- if ( this . props . onEntering ) {
145- this . props . onEntering ( node ) ;
126+ if ( onEntering ) {
127+ onEntering ( node ) ;
146128 }
147129 } ;
148130
149- handleExit = node => {
150- const { theme } = this . props ;
151-
152- const transitionProps = getTransitionProps ( this . props , {
153- mode : 'exit' ,
154- } ) ;
131+ const handleExit = ( ) => {
132+ const node = childrenRef . current ;
133+ const transitionProps = getTransitionProps (
134+ { timeout, style } ,
135+ {
136+ mode : 'exit' ,
137+ } ,
138+ ) ;
155139 node . style . webkitTransition = theme . transitions . create ( '-webkit-transform' , {
156140 ...transitionProps ,
157141 easing : theme . transitions . easing . sharp ,
@@ -160,78 +144,82 @@ class Slide extends React.Component {
160144 ...transitionProps ,
161145 easing : theme . transitions . easing . sharp ,
162146 } ) ;
163- setTranslateValue ( this . props , node ) ;
147+ setTranslateValue ( direction , node ) ;
164148
165- if ( this . props . onExit ) {
166- this . props . onExit ( node ) ;
149+ if ( onExit ) {
150+ onExit ( node ) ;
167151 }
168152 } ;
169153
170- handleExited = node => {
154+ const handleExited = ( ) => {
155+ const node = childrenRef . current ;
171156 // No need for transitions when the component is hidden
172157 node . style . webkitTransition = '' ;
173158 node . style . transition = '' ;
174159
175- if ( this . props . onExited ) {
176- this . props . onExited ( node ) ;
160+ if ( onExited ) {
161+ onExited ( node ) ;
177162 }
178163 } ;
179164
180- /**
181- * used in cloneElement(children, { ref: handleRef })
182- */
183- handleRef = ref => {
184- // #StrictMode ready
185- this . childDOMNode = ReactDOM . findDOMNode ( ref ) ;
186- setRef ( this . props . children . ref , ref ) ;
187- } ;
165+ const updatePosition = React . useCallback ( ( ) => {
166+ if ( childrenRef . current ) {
167+ setTranslateValue ( direction , childrenRef . current ) ;
168+ }
169+ } , [ direction ] ) ;
170+
171+ React . useEffect ( ( ) => {
172+ // Skip configuration where the position is screen size invariant.
173+ if ( ! inProp && direction !== 'down' && direction !== 'right' ) {
174+ const handleResize = debounce ( ( ) => {
175+ if ( childrenRef . current ) {
176+ setTranslateValue ( direction , childrenRef . current ) ;
177+ }
178+ } , 166 ) ; // Corresponds to 10 frames at 60 Hz.
188179
189- updatePosition ( ) {
190- if ( this . childDOMNode ) {
191- setTranslateValue ( this . props , this . childDOMNode ) ;
180+ window . addEventListener ( 'resize' , handleResize ) ;
181+
182+ return ( ) => {
183+ handleResize . clear ( ) ;
184+ window . removeEventListener ( 'resize' , handleResize ) ;
185+ } ;
192186 }
193- }
194187
195- render ( ) {
196- const {
197- children,
198- direction,
199- in : inProp ,
200- onEnter,
201- onEntering,
202- onExit,
203- onExited,
204- style,
205- theme,
206- ...other
207- } = this . props ;
208-
209- return (
210- < EventListener target = "window" onResize = { this . handleResize } >
211- < Transition
212- onEnter = { this . handleEnter }
213- onEntering = { this . handleEntering }
214- onExit = { this . handleExit }
215- onExited = { this . handleExited }
216- appear
217- in = { inProp }
218- { ...other }
219- >
220- { ( state , childProps ) => {
221- return React . cloneElement ( children , {
222- ref : this . handleRef ,
223- style : {
224- visibility : state === 'exited' && ! inProp ? 'hidden' : undefined ,
225- ...style ,
226- ...children . props . style ,
227- } ,
228- ...childProps ,
229- } ) ;
230- } }
231- </ Transition >
232- </ EventListener >
233- ) ;
234- }
188+ return ( ) => { } ;
189+ } , [ direction , inProp ] ) ;
190+
191+ React . useEffect ( ( ) => {
192+ if ( ! inProp ) {
193+ // We need to update the position of the drawer when the direction change and
194+ // when it's hidden.
195+ updatePosition ( ) ;
196+ }
197+ } , [ inProp , updatePosition ] ) ;
198+
199+ return (
200+ < Transition
201+ onEnter = { handleEnter }
202+ onEntering = { handleEntering }
203+ onExit = { handleExit }
204+ onExited = { handleExited }
205+ appear
206+ in = { inProp }
207+ timeout = { timeout }
208+ { ...other }
209+ >
210+ { ( state , childProps ) => {
211+ return React . cloneElement ( children , {
212+ ref : handleRef ,
213+ style : {
214+ visibility : state === 'exited' && ! inProp ? 'hidden' : undefined ,
215+ ...style ,
216+ ...children . props . style ,
217+ } ,
218+ ...childProps ,
219+ } ) ;
220+ } }
221+ </ Transition >
222+ ) ;
235223}
236224
237225Slide . propTypes = {
0 commit comments