1
- import React , { FC , RefObject , HTMLAttributes , useState , useEffect , useRef } from 'react'
1
+ import React , { forwardRef , HTMLAttributes , useState , useEffect , useRef } from 'react'
2
2
import PropTypes from 'prop-types'
3
3
import classNames from 'classnames'
4
4
@@ -8,132 +8,135 @@ export interface CCarouselProps extends HTMLAttributes<HTMLDivElement> {
8
8
*/
9
9
className ?: string
10
10
/**
11
- * Inner ref of main element . [docs]
11
+ * Set 'animate' variable for created context . [docs]
12
12
*
13
- * @type RefObject<HTMLDivElement> | {():void}
13
+ * @type boolean
14
14
*/
15
- innerRef ?: RefObject < HTMLDivElement > | { ( ) : void } // TODO: check
15
+ animate ?: boolean
16
16
/**
17
- * index of the active item. [docs]
17
+ * The amount of time to delay between automatically cycling an item. If false, carousel will not automatically cycle . [docs]
18
18
*
19
- * @type number
19
+ * @type boolean | number
20
20
*/
21
- activeIndex ?: number
21
+ interval : boolean | number
22
22
/**
23
- * Slide starts on beginning . [docs]
23
+ * index of the active item . [docs]
24
24
*
25
25
* @type number
26
26
*/
27
- autoSlide ?: number
27
+ index ?: number
28
28
/**
29
- * Set 'animate' variable for created context . [docs]
29
+ * On slide change callback . [docs]
30
30
*
31
- * @type boolean
31
+ * @type (a:number|string|null)=>void
32
32
*/
33
- animate ?: boolean
33
+ onSlideChange ?: ( a : number | string | null ) => void
34
34
/**
35
35
* On slide change callback. [docs]
36
36
*
37
- * @type (a:number|string|null)=>void
37
+ * @type 'slide' | 'crossfade'
38
+ * @default 'slide'
38
39
*/
39
- onSlideChange ?: ( a : number | string | null ) => void
40
+ transition ?: 'slide' | 'crossfade'
40
41
}
41
42
42
43
interface DataType {
43
44
timeout ?: null | ReturnType < typeof setTimeout >
44
45
}
45
46
46
47
export interface ContextType {
47
- itemNumber : number
48
+ itemsNumber : number
48
49
state : [ number | null , number , string ?]
49
50
animating : boolean
50
51
animate ?: boolean
51
- setItemNumber : ( a : number ) => void
52
+ setItemsNumber : ( a : number ) => void
52
53
setAnimating : ( a : boolean ) => void
53
54
setState : ( a : [ number | null , number , string ?] ) => void
54
55
}
55
56
56
57
//
57
58
58
59
export const Context = React . createContext < ContextType > ( {
59
- itemNumber : 0 ,
60
+ itemsNumber : 0 ,
60
61
state : [ null , 0 ] ,
61
62
animating : false ,
62
- setItemNumber : ( _ ) => { } ,
63
+ setItemsNumber : ( _ ) => { } ,
63
64
setAnimating : ( _ ) => { } ,
64
65
setState : ( _ ) => { } ,
65
66
} )
66
67
67
- export const CCarousel : FC < CCarouselProps > = ( {
68
- className,
69
- children,
70
- innerRef,
71
- autoSlide,
72
- activeIndex = 0 ,
73
- animate,
74
- onSlideChange,
75
- ...rest
76
- } ) => {
77
- const [ state , setState ] = useState < [ number | null , number , string ?] > ( [ null , activeIndex ] )
78
- const [ itemNumber , setItemNumber ] = useState < number > ( 0 )
79
- const [ animating , setAnimating ] = useState < boolean > ( false )
68
+ export const CCarousel = forwardRef < HTMLDivElement , CCarouselProps > (
69
+ (
70
+ { className, children, index = 0 , animate = true , interval = 5000 , onSlideChange, transition, ...rest } ,
71
+ ref ,
72
+ ) => {
73
+ const [ state , setState ] = useState < [ number | null , number , string ?] > ( [ null , index ] )
74
+ const [ itemsNumber , setItemsNumber ] = useState < number > ( 0 )
75
+ const [ animating , setAnimating ] = useState < boolean > ( false )
80
76
81
- let data = useRef < DataType > ( { } ) . current
77
+ let data = useRef < DataType > ( { } ) . current
82
78
83
- const setNext = ( ) => {
84
- reset ( )
85
- if ( autoSlide ) {
86
- data . timeout = setTimeout ( ( ) => nextItem ( ) , autoSlide )
79
+ const cycle = ( ) => {
80
+ pause ( )
81
+ if ( typeof interval === 'number' ) {
82
+ data . timeout = setTimeout ( ( ) => nextItem ( ) , interval )
83
+ }
84
+ }
85
+ const pause = ( ) => data . timeout && clearTimeout ( data . timeout )
86
+ const nextItem = ( ) => {
87
+ if ( typeof state [ 1 ] === 'number' )
88
+ setState ( [ state [ 1 ] , itemsNumber === state [ 1 ] + 1 ? 0 : state [ 1 ] + 1 , 'next' ] )
87
89
}
88
- }
89
- const reset = ( ) => data . timeout && clearTimeout ( data . timeout )
90
- const nextItem = ( ) => {
91
- if ( typeof state [ 1 ] === 'number' )
92
- setState ( [ state [ 1 ] , itemNumber === state [ 1 ] + 1 ? 0 : state [ 1 ] + 1 , 'next' ] )
93
- }
94
90
95
- useEffect ( ( ) => {
96
- setState ( [ state [ 1 ] , activeIndex ] )
97
- } , [ activeIndex ] )
91
+ useEffect ( ( ) => {
92
+ setState ( [ state [ 1 ] , index ] )
93
+ } , [ index ] )
98
94
99
- useEffect ( ( ) => {
100
- onSlideChange && onSlideChange ( state [ 1 ] )
101
- setNext ( )
102
- return ( ) => {
103
- reset ( )
104
- }
105
- } , [ state ] )
95
+ useEffect ( ( ) => {
96
+ onSlideChange && onSlideChange ( state [ 1 ] )
97
+ cycle ( )
98
+ return ( ) => {
99
+ pause ( )
100
+ }
101
+ } , [ state ] )
106
102
107
- // render
103
+ // render
108
104
109
- const classes = classNames ( 'carousel' , className )
105
+ const _className = classNames (
106
+ 'carousel slide' ,
107
+ transition === 'crossfade' && 'carousel-fade' ,
108
+ className
109
+ )
110
110
111
- return (
112
- < div className = { classes } onMouseEnter = { reset } onMouseLeave = { setNext } { ...rest } ref = { innerRef } >
113
- < Context . Provider
114
- value = { {
115
- state,
116
- setState,
117
- animate,
118
- itemNumber,
119
- setItemNumber,
120
- animating,
121
- setAnimating,
122
- } }
123
- >
124
- { children }
125
- </ Context . Provider >
126
- </ div >
127
- )
128
- }
111
+ return (
112
+ < div className = { _className } onMouseEnter = { pause } onMouseLeave = { cycle } { ...rest } ref = { ref } >
113
+ < Context . Provider
114
+ value = { {
115
+ state,
116
+ setState,
117
+ animate,
118
+ itemsNumber,
119
+ setItemsNumber,
120
+ animating,
121
+ setAnimating,
122
+ } }
123
+ >
124
+ { children }
125
+ </ Context . Provider >
126
+ </ div >
127
+ )
128
+ } ,
129
+ )
129
130
130
131
CCarousel . propTypes = {
131
- activeIndex : PropTypes . number ,
132
132
animate : PropTypes . bool ,
133
- autoSlide : PropTypes . number ,
134
133
children : PropTypes . node ,
135
134
className : PropTypes . string ,
136
- innerRef : PropTypes . any , // TODO: check
135
+ index : PropTypes . number ,
136
+ interval : PropTypes . oneOfType ( [
137
+ PropTypes . bool ,
138
+ PropTypes . number
139
+ ] ) . isRequired ,
137
140
onSlideChange : PropTypes . func ,
138
141
}
139
142
0 commit comments