@@ -4,97 +4,99 @@ import PropTypes from 'prop-types'
44import React from 'react'
55
66import {
7- ModernAutoControlledComponent as Component ,
87 childrenUtils ,
98 createShorthandFactory ,
109 customPropTypes ,
1110 getElementType ,
1211 getUnhandledProps ,
12+ useAutoControlledValue ,
13+ useEventCallback ,
1314} from '../../lib'
1415import AccordionPanel from './AccordionPanel'
1516
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 )
2724}
2825
2926/**
30- * An Accordion can contain sub-accordions.
27+ * @param {Boolean } exclusive
28+ * @param {Number } activeIndex
29+ * @param {Number } itemIndex
3130 */
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
4134 }
4235
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 )
4739 }
4840
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+ }
5843
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 ) => {
6060 const { index } = titleProps
6161
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 ] )
6476 }
6577
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+ } )
7294
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 ,
9697}
9798
99+ AccordionAccordion . displayName = 'AccordionAccordion'
98100AccordionAccordion . propTypes = {
99101 /** An element type to render as (string or function). */
100102 as : PropTypes . elementType ,
@@ -140,10 +142,6 @@ AccordionAccordion.propTypes = {
140142 ] ) ,
141143}
142144
143- AccordionAccordion . defaultProps = {
144- exclusive : true ,
145- }
146-
147- AccordionAccordion . autoControlledProps = [ 'activeIndex' ]
148-
149145AccordionAccordion . create = createShorthandFactory ( AccordionAccordion , ( content ) => ( { content } ) )
146+
147+ export default AccordionAccordion
0 commit comments