@@ -4,97 +4,99 @@ import PropTypes from 'prop-types'
4
4
import React from 'react'
5
5
6
6
import {
7
- ModernAutoControlledComponent as Component ,
8
7
childrenUtils ,
9
8
createShorthandFactory ,
10
9
customPropTypes ,
11
10
getElementType ,
12
11
getUnhandledProps ,
12
+ useAutoControlledValue ,
13
+ useEventCallback ,
13
14
} from '../../lib'
14
15
import AccordionPanel from './AccordionPanel'
15
16
16
- const warnIfPropsAreInvalid = ( props , state ) => {
17
- const { exclusive } = props
18
- const { activeIndex } = state
19
-
20
- /* eslint-disable no-console */
21
- if ( exclusive && typeof activeIndex !== 'number' ) {
22
- console . error ( '`activeIndex` must be a number if `exclusive` is true' )
23
- } else if ( ! exclusive && ! _ . isArray ( activeIndex ) ) {
24
- console . error ( '`activeIndex` must be an array if `exclusive` is false' )
25
- }
26
- /* eslint-enable no-console */
17
+ /**
18
+ * @param {Boolean } exclusive
19
+ * @param {Number } activeIndex
20
+ * @param {Number } itemIndex
21
+ */
22
+ function isIndexActive ( exclusive , activeIndex , itemIndex ) {
23
+ return exclusive ? activeIndex === itemIndex : _ . includes ( activeIndex , itemIndex )
27
24
}
28
25
29
26
/**
30
- * An Accordion can contain sub-accordions.
27
+ * @param {Boolean } exclusive
28
+ * @param {Number } activeIndex
29
+ * @param {Number } itemIndex
31
30
*/
32
- export default class AccordionAccordion extends Component {
33
- getInitialAutoControlledState ( { exclusive } ) {
34
- return { activeIndex : exclusive ? - 1 : [ ] }
35
- }
36
-
37
- componentDidMount ( ) {
38
- if ( process . env . NODE_ENV !== 'production' ) {
39
- warnIfPropsAreInvalid ( this . props , this . state )
40
- }
31
+ function computeNewIndex ( exclusive , activeIndex , itemIndex ) {
32
+ if ( exclusive ) {
33
+ return itemIndex === activeIndex ? - 1 : itemIndex
41
34
}
42
35
43
- componentDidUpdate ( ) {
44
- if ( process . env . NODE_ENV !== 'production' ) {
45
- warnIfPropsAreInvalid ( this . props , this . state )
46
- }
36
+ // check to see if index is in array, and remove it, if not then add it
37
+ if ( _ . includes ( activeIndex , itemIndex ) ) {
38
+ return _ . without ( activeIndex , itemIndex )
47
39
}
48
40
49
- computeNewIndex = ( index ) => {
50
- const { exclusive } = this . props
51
- const { activeIndex } = this . state
52
-
53
- if ( exclusive ) return index === activeIndex ? - 1 : index
54
-
55
- // check to see if index is in array, and remove it, if not then add it
56
- return _ . includes ( activeIndex , index ) ? _ . without ( activeIndex , index ) : [ ...activeIndex , index ]
57
- }
41
+ return [ ...activeIndex , itemIndex ]
42
+ }
58
43
59
- handleTitleClick = ( e , titleProps ) => {
44
+ /**
45
+ * An Accordion can contain sub-accordions.
46
+ */
47
+ const AccordionAccordion = React . forwardRef ( function ( props , ref ) {
48
+ const { className, children, exclusive, panels } = props
49
+ const [ activeIndex , setActiveIndex ] = useAutoControlledValue ( {
50
+ state : props . activeIndex ,
51
+ defaultState : props . defaultActiveIndex ,
52
+ initialState : ( ) => ( exclusive ? - 1 : [ ] ) ,
53
+ } )
54
+
55
+ const classes = cx ( 'accordion' , className )
56
+ const rest = getUnhandledProps ( AccordionAccordion , props )
57
+ const ElementType = getElementType ( AccordionAccordion , props )
58
+
59
+ const handleTitleClick = useEventCallback ( ( e , titleProps ) => {
60
60
const { index } = titleProps
61
61
62
- this . setState ( { activeIndex : this . computeNewIndex ( index ) } )
63
- _ . invoke ( this . props , 'onTitleClick' , e , titleProps )
62
+ setActiveIndex ( computeNewIndex ( exclusive , activeIndex , index ) )
63
+ _ . invoke ( props , 'onTitleClick' , e , titleProps )
64
+ } )
65
+
66
+ if ( process . env . NODE_ENV !== 'production' ) {
67
+ React . useEffect ( ( ) => {
68
+ /* eslint-disable no-console */
69
+ if ( exclusive && typeof activeIndex !== 'number' ) {
70
+ console . error ( '`activeIndex` must be a number if `exclusive` is true' )
71
+ } else if ( ! exclusive && ! _ . isArray ( activeIndex ) ) {
72
+ console . error ( '`activeIndex` must be an array if `exclusive` is false' )
73
+ }
74
+ /* eslint-enable no-console */
75
+ } , [ exclusive , activeIndex ] )
64
76
}
65
77
66
- isIndexActive = ( index ) => {
67
- const { exclusive } = this . props
68
- const { activeIndex } = this . state
69
-
70
- return exclusive ? activeIndex === index : _ . includes ( activeIndex , index )
71
- }
78
+ return (
79
+ < ElementType { ...rest } className = { classes } ref = { ref } >
80
+ { childrenUtils . isNil ( children )
81
+ ? _ . map ( panels , ( panel , index ) =>
82
+ AccordionPanel . create ( panel , {
83
+ defaultProps : {
84
+ active : isIndexActive ( exclusive , activeIndex , index ) ,
85
+ index,
86
+ onTitleClick : handleTitleClick ,
87
+ } ,
88
+ } ) ,
89
+ )
90
+ : children }
91
+ </ ElementType >
92
+ )
93
+ } )
72
94
73
- render ( ) {
74
- const { className, children, panels } = this . props
75
-
76
- const classes = cx ( 'accordion' , className )
77
- const rest = getUnhandledProps ( AccordionAccordion , this . props )
78
- const ElementType = getElementType ( AccordionAccordion , this . props )
79
-
80
- return (
81
- < ElementType { ...rest } className = { classes } >
82
- { childrenUtils . isNil ( children )
83
- ? _ . map ( panels , ( panel , index ) =>
84
- AccordionPanel . create ( panel , {
85
- defaultProps : {
86
- active : this . isIndexActive ( index ) ,
87
- index,
88
- onTitleClick : this . handleTitleClick ,
89
- } ,
90
- } ) ,
91
- )
92
- : children }
93
- </ ElementType >
94
- )
95
- }
95
+ AccordionAccordion . defaultProps = {
96
+ exclusive : true ,
96
97
}
97
98
99
+ AccordionAccordion . displayName = 'AccordionAccordion'
98
100
AccordionAccordion . propTypes = {
99
101
/** An element type to render as (string or function). */
100
102
as : PropTypes . elementType ,
@@ -140,10 +142,6 @@ AccordionAccordion.propTypes = {
140
142
] ) ,
141
143
}
142
144
143
- AccordionAccordion . defaultProps = {
144
- exclusive : true ,
145
- }
146
-
147
- AccordionAccordion . autoControlledProps = [ 'activeIndex' ]
148
-
149
145
AccordionAccordion . create = createShorthandFactory ( AccordionAccordion , ( content ) => ( { content } ) )
146
+
147
+ export default AccordionAccordion
0 commit comments