@@ -9,33 +9,28 @@ import PropTypes from 'prop-types';
99import React , {
1010 Children ,
1111 cloneElement ,
12- isValidElement ,
1312 useContext ,
1413 useEffect ,
1514 useRef ,
1615 useState ,
1716 type HTMLAttributes ,
18- type KeyboardEvent ,
19- type MouseEvent ,
2017 type ReactElement ,
2118} from 'react' ;
2219import classNames from 'classnames' ;
2320import { deprecate } from '../../prop-types/deprecate' ;
2421import { LayoutConstraint } from '../Layout' ;
25- import { composeEventHandlers } from '../../tools/events' ;
26- import { getNextIndex , matches , keys } from '../../internal/keyboard' ;
22+ import { getNextIndex , match , keys } from '../../internal/keyboard' ;
2723import { PrefixContext } from '../../internal/usePrefix' ;
2824import { isComponentElement } from '../../internal' ;
29- import { IconSwitch } from '../Switch' ;
25+ import { IconSwitch , Switch } from '../Switch' ;
3026import type { SwitchEventHandlersParams } from '../Switch/Switch' ;
3127
3228export interface ContentSwitcherProps
3329 extends Omit < HTMLAttributes < HTMLElement > , 'onChange' > {
3430 /**
3531 * Pass in Switch components to be rendered in the ContentSwitcher
3632 */
37- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
38- children ?: ReactElement < any > [ ] ;
33+ children ?: ReactElement | ReactElement [ ] ;
3934
4035 /**
4136 * Specify an optional className to be added to the container node
@@ -118,23 +113,19 @@ export const ContentSwitcher = ({
118113 }
119114 } ;
120115
121- const isKeyboardEvent = (
122- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
123- event : any
124- ) : event is KeyboardEvent < HTMLButtonElement > | globalThis . KeyboardEvent =>
125- event && typeof event === 'object' && 'key' in event ;
116+ const hasKey = (
117+ event : SwitchEventHandlersParams
118+ ) : event is SwitchEventHandlersParams & { key : string | number } =>
119+ typeof event === 'object' && event !== null && 'key' in event ;
126120
127- const handleChildChange = (
128- event : SwitchEventHandlersParams &
129- ( KeyboardEvent < HTMLButtonElement > | MouseEvent < HTMLButtonElement > )
130- ) => {
121+ const handleChildChange = ( event : SwitchEventHandlersParams ) => {
131122 if ( typeof event . index === 'undefined' ) return ;
132123
133124 const { index } = event ;
134125
135126 if (
136- isKeyboardEvent ( event ) &&
137- matches ( event , [ keys . ArrowRight , keys . ArrowLeft ] )
127+ hasKey ( event ) &&
128+ ( match ( event . key , keys . ArrowRight ) || match ( event . key , keys . ArrowLeft ) )
138129 ) {
139130 const nextIndex = getNextIndex ( event . key , index , childrenArray . length ) ;
140131
@@ -147,7 +138,10 @@ export const ContentSwitcher = ({
147138
148139 setSelectedIndex ( nextIndex ) ;
149140
150- if ( isValidElement < SwitchEventHandlersParams > ( child ) ) {
141+ if (
142+ isComponentElement ( child , Switch ) ||
143+ isComponentElement ( child , IconSwitch )
144+ ) {
151145 onChange ( {
152146 ...event ,
153147 index : nextIndex ,
@@ -158,7 +152,9 @@ export const ContentSwitcher = ({
158152 }
159153 } else if (
160154 selectedIndex !== index &&
161- ( isKeyboardEvent ( event ) ? matches ( event , [ keys . Enter , keys . Space ] ) : true )
155+ ( hasKey ( event )
156+ ? match ( event . key , keys . Enter ) || match ( event . key , keys . Space )
157+ : true )
162158 ) {
163159 setSelectedIndex ( index ) ;
164160 focusSwitch ( index ) ;
@@ -185,23 +181,32 @@ export const ContentSwitcher = ({
185181 className = { classes }
186182 role = "tablist"
187183 onChange = { undefined } >
188- { children &&
189- Children . map ( children , ( child , index ) =>
190- cloneElement ( child , {
191- index,
192- onClick : composeEventHandlers ( [
193- handleChildChange ,
194- child . props . onClick ,
195- ] ) ,
196- onKeyDown : composeEventHandlers ( [
197- handleChildChange ,
198- child . props . onKeyDown ,
199- ] ) ,
200- selected : index === selectedIndex ,
201- ref : handleItemRef ( index ) ,
202- size,
203- } )
204- ) }
184+ { Children . map ( children , ( child , index ) => {
185+ if (
186+ ! isComponentElement ( child , Switch ) &&
187+ ! isComponentElement ( child , IconSwitch )
188+ )
189+ return child ;
190+
191+ const sharedProps = {
192+ index,
193+ onClick : ( event : SwitchEventHandlersParams ) => {
194+ handleChildChange ( event ) ;
195+ child . props . onClick ?.( event ) ;
196+ } ,
197+ onKeyDown : ( event : SwitchEventHandlersParams ) => {
198+ handleChildChange ( event ) ;
199+ child . props . onKeyDown ?.( event ) ;
200+ } ,
201+ selected : index === selectedIndex ,
202+ ref : handleItemRef ( index ) ,
203+ } ;
204+
205+ return cloneElement ( child , {
206+ ...sharedProps ,
207+ ...( isComponentElement ( child , IconSwitch ) ? { size } : { } ) ,
208+ } ) ;
209+ } ) }
205210 </ LayoutConstraint >
206211 ) ;
207212} ;
0 commit comments