diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0cdcb59841f40f..d0889b460dbd05 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- `TabPanel`: add tabName prop for tab panel ([#46704](https://github.com/WordPress/gutenberg/pull/46704)). + ### Enhancements - `SearchControl`: polish metrics for `compact` size variant ([#54663](https://github.com/WordPress/gutenberg/pull/54663)). diff --git a/packages/components/src/tab-panel/README.md b/packages/components/src/tab-panel/README.md index 67b00c37679eca..bde377cdd26092 100644 --- a/packages/components/src/tab-panel/README.md +++ b/packages/components/src/tab-panel/README.md @@ -144,6 +144,14 @@ The name of the tab to be selected upon mounting of component. If this prop is n - Required: No - Default: none +#### tabName + +The name of the tab to be selected. + +- Type: `String` +- Required: No +- Default: none + #### selectOnMove When `true`, the tab will be selected when receiving focus (automatic tab activation). When `false`, the tab will be selected only when clicked (manual tab activation). See the [official W3C docs](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/) for more info. diff --git a/packages/components/src/tab-panel/index.tsx b/packages/components/src/tab-panel/index.tsx index 4fff7dc306b023..431ae52ce3e9ad 100644 --- a/packages/components/src/tab-panel/index.tsx +++ b/packages/components/src/tab-panel/index.tsx @@ -78,6 +78,7 @@ const UnforwardedTabPanel = ( tabs, selectOnMove = true, initialTabName, + tabName, orientation = 'horizontal', activeClass = 'is-active', onSelect, @@ -87,11 +88,11 @@ const UnforwardedTabPanel = ( const instanceId = useInstanceId( TabPanel, 'tab-panel' ); const prependInstanceId = useCallback( - ( tabName: string | undefined ) => { - if ( typeof tabName === 'undefined' ) { + ( tab: string | undefined ) => { + if ( typeof tab === 'undefined' ) { return; } - return `${ instanceId }-${ tabName }`; + return `${ instanceId }-${ tab }`; }, [ instanceId ] ); @@ -118,14 +119,14 @@ const UnforwardedTabPanel = ( }, orientation, selectOnMove, - defaultSelectedId: prependInstanceId( initialTabName ), + defaultSelectedId: prependInstanceId( tabName || initialTabName ), } ); const selectedTabName = extractTabName( tabStore.useState( 'selectedId' ) ); const setTabStoreSelectedId = useCallback( - ( tabName: string ) => { - tabStore.setState( 'selectedId', prependInstanceId( tabName ) ); + ( tab: string ) => { + tabStore.setState( 'selectedId', prependInstanceId( tab ) ); }, [ prependInstanceId, tabStore ] ); @@ -145,6 +146,13 @@ const UnforwardedTabPanel = ( } }, [ selectedTabName, initialTabName, onSelect, previousSelectedTabName ] ); + // handle selection of tabName + useEffect( () => { + if ( tabName ) { + setTabStoreSelectedId( tabName ); + } + }, [ tabName, setTabStoreSelectedId ] ); + // Handle selecting the initial tab. useLayoutEffect( () => { // If there's a selected tab, don't override it. @@ -190,6 +198,7 @@ const UnforwardedTabPanel = ( setTabStoreSelectedId( firstEnabledTab.name ); } }, [ tabs, selectedTab?.disabled, setTabStoreSelectedId, instanceId ] ); + return (
Selected tab: { tab.title }
, + tabs: [ + { + name: 'tab1', + title: 'Tab 1', + }, + { + name: 'tab2', + title: 'Tab 2', + }, + { + name: 'tab3', + title: 'Tab 3', + }, + ], + tabName: 'tab2', +}; + export const DisabledTab = Template.bind( {} ); DisabledTab.args = { children: ( tab ) =>Selected tab: { tab.title }
, diff --git a/packages/components/src/tab-panel/test/index.tsx b/packages/components/src/tab-panel/test/index.tsx index c07685935ce162..eb0d5f411f27e6 100644 --- a/packages/components/src/tab-panel/test/index.tsx +++ b/packages/components/src/tab-panel/test/index.tsx @@ -8,12 +8,14 @@ import userEvent from '@testing-library/user-event'; * WordPress dependencies */ import { wordpress, category, media } from '@wordpress/icons'; +import { useState, useEffect } from '@wordpress/element'; /** * Internal dependencies */ import TabPanel from '..'; import cleanupTooltip from '../../tooltip/test/utils'; +import type { TabPanelProps } from '../types'; const TABS = [ { @@ -33,16 +35,44 @@ const TABS = [ }, ]; +const UncontrolledTabPanel = ( { tabName, ...props }: TabPanelProps ) => { + return