diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 21d968568374b4..9eed4f0765e1fb 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -9,6 +9,7 @@ ### New Feature - `TabPanel`: support manual tab activation ([#46004](https://github.com/WordPress/gutenberg/pull/46004)). +- `TabPanel`: support disabled prop for tab buttons ([#46471](https://github.com/WordPress/gutenberg/pull/46471)). - `BaseControl`: Add `useBaseControlProps` hook to help generate id-releated props ([#46170](https://github.com/WordPress/gutenberg/pull/46170)). ### Bug Fix diff --git a/packages/components/src/tab-panel/README.md b/packages/components/src/tab-panel/README.md index 860bd9604b2d86..67b00c37679eca 100644 --- a/packages/components/src/tab-panel/README.md +++ b/packages/components/src/tab-panel/README.md @@ -121,6 +121,7 @@ An array of objects containing the following properties: - `title`:`(string)` Defines the translated text for the tab. - `className`:`(string)` Optional. Defines the class to put on the tab. - `icon`:`(ReactNode)` Optional. When set, displays the icon in place of the tab title. The title is then rendered as an aria-label and tooltip. +- `disabled`:`(boolean)` Optional. Determines if the tab should be disabled or selectable. > > **Note:** Other fields may be added to the object and accessed from the child function if desired. diff --git a/packages/components/src/tab-panel/index.tsx b/packages/components/src/tab-panel/index.tsx index fce688089a55c0..ff194b76a1179c 100644 --- a/packages/components/src/tab-panel/index.tsx +++ b/packages/components/src/tab-panel/index.tsx @@ -20,7 +20,6 @@ import type { WordPressComponentProps } from '../ui/context'; const TabButton = ( { tabId, - onClick, children, selected, ...rest @@ -30,7 +29,7 @@ const TabButton = ( { tabIndex={ selected ? null : -1 } aria-selected={ selected } id={ tabId } - onClick={ onClick } + __experimentalIsFocusable { ...rest } > { children } @@ -106,10 +105,24 @@ export function TabPanel( { const selectedId = `${ instanceId }-${ selectedTab?.name ?? 'none' }`; useEffect( () => { - if ( ! selectedTab?.name && tabs.length > 0 ) { - handleTabSelection( initialTabName || tabs[ 0 ].name ); + const firstEnabledTab = tabs.find( ( tab ) => ! tab.disabled ); + const initialTab = tabs.find( ( tab ) => tab.name === initialTabName ); + if ( ! selectedTab?.name && firstEnabledTab ) { + handleTabSelection( + initialTab && ! initialTab.disabled + ? initialTab.name + : firstEnabledTab.name + ); + } else if ( selectedTab?.disabled && firstEnabledTab ) { + handleTabSelection( firstEnabledTab.name ); } - }, [ tabs, selectedTab?.name, initialTabName, handleTabSelection ] ); + }, [ + tabs, + selectedTab?.name, + selectedTab?.disabled, + initialTabName, + handleTabSelection, + ] ); return (
Selected tab: { tab.title }
, + tabs: [ + { + name: 'tab1', + title: 'Tab 1', + disabled: true, + }, + { + name: 'tab2', + title: 'Tab 2', + }, + { + name: 'tab3', + title: 'Tab 3', + }, + ], +}; diff --git a/packages/components/src/tab-panel/test/index.tsx b/packages/components/src/tab-panel/test/index.tsx index 0d3a30e991ea3f..a9e399de9d8a99 100644 --- a/packages/components/src/tab-panel/test/index.tsx +++ b/packages/components/src/tab-panel/test/index.tsx @@ -160,6 +160,95 @@ describe( 'TabPanel', () => { expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' ); } ); + it( 'should disable the tab when `disabled` is true', async () => { + const user = setupUser(); + const mockOnSelect = jest.fn(); + + render( +