Skip to content

Commit 1b15cda

Browse files
authored
Tabs: Update subcomponents to accept full HTML element props (#55860)
1 parent e77f444 commit 1b15cda

File tree

7 files changed

+57
-136
lines changed

7 files changed

+57
-136
lines changed

packages/components/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
### Experimental
1010

1111
- `Tabs`: Add `focusable` prop to the `Tabs.TabPanel` sub-component ([#55287](https://github.com/WordPress/gutenberg/pull/55287))
12+
- `Tabs`: Update sub-components to accept relevant HTML element props ([#55860](https://github.com/WordPress/gutenberg/pull/55860))
1213

1314
### Enhancements
1415

packages/components/src/tabs/README.md

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,6 @@ The children elements, which should be a series of `Tabs.TabPanel` components.
159159

160160
- Required: No
161161

162-
###### `className`: `string`
163-
164-
The class name to apply to the tablist.
165-
166-
- Required: No
167-
- Default: ''
168-
169-
###### `style`: `React.CSSProperties`
170-
171-
Custom CSS styles for the tablist.
172-
173-
- Required: No
174-
175162
#### Tab
176163

177164
##### Props
@@ -182,24 +169,12 @@ The id of the tab, which is prepended with the `Tabs` instance ID.
182169

183170
- Required: Yes
184171

185-
###### `style`: `React.CSSProperties`
186-
187-
Custom CSS styles for the tab.
188-
189-
- Required: No
190-
191172
###### `children`: `React.ReactNode`
192173

193174
The children elements, generally the text to display on the tab.
194175

195176
- Required: No
196177

197-
###### `className`: `string`
198-
199-
The class name to apply to the tab.
200-
201-
- Required: No
202-
203178
###### `disabled`: `boolean`
204179

205180
Determines if the tab button should be disabled.
@@ -229,18 +204,6 @@ The id of the tabpanel, which is combined with the `Tabs` instance ID and the su
229204

230205
- Required: Yes
231206

232-
###### `className`: `string`
233-
234-
The class name to apply to the tabpanel.
235-
236-
- Required: No
237-
238-
###### `style`: `React.CSSProperties`
239-
240-
Custom CSS styles for the tab.
241-
242-
- Required: No
243-
244207
###### `focusable`: `boolean`
245208

246209
Determines whether or not the tabpanel element should be focusable. If `false`, pressing the tab key will skip over the tabpanel, and instead focus on the first focusable element in the panel (if there is one).

packages/components/src/tabs/tab.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import type { TabProps } from './types';
1111
import warning from '@wordpress/warning';
1212
import { TabsContext } from './context';
1313
import { Tab as StyledTab } from './styles';
14+
import type { WordPressComponentProps } from '../context';
1415

15-
export const Tab = forwardRef< HTMLButtonElement, TabProps >( function Tab(
16-
{ children, id, className, disabled, render, style },
17-
ref
18-
) {
16+
export const Tab = forwardRef<
17+
HTMLButtonElement,
18+
WordPressComponentProps< TabProps, 'button', false >
19+
>( function Tab( { children, id, disabled, render, ...otherProps }, ref ) {
1920
const context = useContext( TabsContext );
2021
if ( ! context ) {
2122
warning( '`Tabs.TabList` must be wrapped in a `Tabs` component.' );
@@ -28,10 +29,9 @@ export const Tab = forwardRef< HTMLButtonElement, TabProps >( function Tab(
2829
ref={ ref }
2930
store={ store }
3031
id={ instancedTabId }
31-
className={ className }
32-
style={ style }
3332
disabled={ disabled }
3433
render={ render }
34+
{ ...otherProps }
3535
>
3636
{ children }
3737
</StyledTab>

packages/components/src/tabs/tablist.tsx

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,26 @@ import { forwardRef } from '@wordpress/element';
1616
import type { TabListProps } from './types';
1717
import { useTabsContext } from './context';
1818
import { TabListWrapper } from './styles';
19+
import type { WordPressComponentProps } from '../context';
1920

20-
export const TabList = forwardRef< HTMLDivElement, TabListProps >(
21-
function TabList( { children, className, style }, ref ) {
22-
const context = useTabsContext();
23-
if ( ! context ) {
24-
warning( '`Tabs.TabList` must be wrapped in a `Tabs` component.' );
25-
return null;
26-
}
27-
const { store } = context;
28-
return (
29-
<Ariakit.TabList
30-
ref={ ref }
31-
style={ style }
32-
store={ store }
33-
className={ className }
34-
render={ <TabListWrapper /> }
35-
>
36-
{ children }
37-
</Ariakit.TabList>
38-
);
21+
export const TabList = forwardRef<
22+
HTMLDivElement,
23+
WordPressComponentProps< TabListProps, 'div', false >
24+
>( function TabList( { children, ...otherProps }, ref ) {
25+
const context = useTabsContext();
26+
if ( ! context ) {
27+
warning( '`Tabs.TabList` must be wrapped in a `Tabs` component.' );
28+
return null;
3929
}
40-
);
30+
const { store } = context;
31+
return (
32+
<Ariakit.TabList
33+
ref={ ref }
34+
store={ store }
35+
render={ <TabListWrapper /> }
36+
{ ...otherProps }
37+
>
38+
{ children }
39+
</Ariakit.TabList>
40+
);
41+
} );

packages/components/src/tabs/tabpanel.tsx

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,28 @@ import { TabPanel as StyledTabPanel } from './styles';
1616

1717
import warning from '@wordpress/warning';
1818
import { TabsContext } from './context';
19+
import type { WordPressComponentProps } from '../context';
1920

20-
export const TabPanel = forwardRef< HTMLDivElement, TabPanelProps >(
21-
function TabPanel(
22-
{ children, id, className, style, focusable = true },
23-
ref
24-
) {
25-
const context = useContext( TabsContext );
26-
if ( ! context ) {
27-
warning( '`Tabs.TabPanel` must be wrapped in a `Tabs` component.' );
28-
return null;
29-
}
30-
const { store, instanceId } = context;
31-
32-
return (
33-
<StyledTabPanel
34-
focusable={ focusable }
35-
ref={ ref }
36-
style={ style }
37-
store={ store }
38-
id={ `${ instanceId }-${ id }-view` }
39-
className={ className }
40-
>
41-
{ children }
42-
</StyledTabPanel>
43-
);
21+
export const TabPanel = forwardRef<
22+
HTMLDivElement,
23+
WordPressComponentProps< TabPanelProps, 'div', false >
24+
>( function TabPanel( { children, id, focusable = true, ...otherProps }, ref ) {
25+
const context = useContext( TabsContext );
26+
if ( ! context ) {
27+
warning( '`Tabs.TabPanel` must be wrapped in a `Tabs` component.' );
28+
return null;
4429
}
45-
);
30+
const { store, instanceId } = context;
31+
32+
return (
33+
<StyledTabPanel
34+
ref={ ref }
35+
store={ store }
36+
id={ `${ instanceId }-${ id }-view` }
37+
focusable={ focusable }
38+
{ ...otherProps }
39+
>
40+
{ children }
41+
</StyledTabPanel>
42+
);
43+
} );

packages/components/src/tabs/test/index.tsx

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,20 @@ import userEvent from '@testing-library/user-event';
77
/**
88
* WordPress dependencies
99
*/
10-
import { wordpress, category, media } from '@wordpress/icons';
1110
import { useState } from '@wordpress/element';
1211

1312
/**
1413
* Internal dependencies
1514
*/
1615
import Tabs from '..';
1716
import type { TabsProps } from '../types';
18-
import type { IconType } from '../../icon';
1917

2018
type Tab = {
2119
id: string;
2220
title: string;
2321
content: React.ReactNode;
2422
tab: {
2523
className?: string;
26-
icon?: IconType;
2724
disabled?: boolean;
2825
};
2926
tabpanel?: {
@@ -36,19 +33,19 @@ const TABS: Tab[] = [
3633
id: 'alpha',
3734
title: 'Alpha',
3835
content: 'Selected tab: Alpha',
39-
tab: { className: 'alpha-class', icon: wordpress },
36+
tab: { className: 'alpha-class' },
4037
},
4138
{
4239
id: 'beta',
4340
title: 'Beta',
4441
content: 'Selected tab: Beta',
45-
tab: { className: 'beta-class', icon: category },
42+
tab: { className: 'beta-class' },
4643
},
4744
{
4845
id: 'gamma',
4946
title: 'Gamma',
5047
content: 'Selected tab: Gamma',
51-
tab: { className: 'gamma-class', icon: media },
48+
tab: { className: 'gamma-class' },
5249
},
5350
];
5451

@@ -58,17 +55,15 @@ const TABS_WITH_DELTA: Tab[] = [
5855
id: 'delta',
5956
title: 'Delta',
6057
content: 'Selected tab: Delta',
61-
tab: { className: 'delta-class', icon: media },
58+
tab: { className: 'delta-class' },
6259
},
6360
];
6461

6562
const UncontrolledTabs = ( {
6663
tabs,
67-
showTabIcons = false,
6864
...props
6965
}: Omit< TabsProps, 'children' > & {
7066
tabs: Tab[];
71-
showTabIcons?: boolean;
7267
} ) => {
7368
return (
7469
<Tabs { ...props }>
@@ -79,9 +74,8 @@ const UncontrolledTabs = ( {
7974
id={ tabObj.id }
8075
className={ tabObj.tab.className }
8176
disabled={ tabObj.tab.disabled }
82-
icon={ showTabIcons ? tabObj.tab.icon : undefined }
8377
>
84-
{ showTabIcons ? null : tabObj.title }
78+
{ tabObj.title }
8579
</Tabs.Tab>
8680
) ) }
8781
</Tabs.TabList>
@@ -100,11 +94,9 @@ const UncontrolledTabs = ( {
10094

10195
const ControlledTabs = ( {
10296
tabs,
103-
showTabIcons = false,
10497
...props
10598
}: Omit< TabsProps, 'children' > & {
10699
tabs: Tab[];
107-
showTabIcons?: boolean;
108100
} ) => {
109101
const [ selectedTabId, setSelectedTabId ] = useState<
110102
string | undefined | null
@@ -126,9 +118,8 @@ const ControlledTabs = ( {
126118
id={ tabObj.id }
127119
className={ tabObj.tab.className }
128120
disabled={ tabObj.tab.disabled }
129-
icon={ showTabIcons ? tabObj.tab.icon : undefined }
130121
>
131-
{ showTabIcons ? null : tabObj.title }
122+
{ tabObj.title }
132123
</Tabs.Tab>
133124
) ) }
134125
</Tabs.TabList>

packages/components/src/tabs/types.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@
44
// eslint-disable-next-line no-restricted-imports
55
import type * as Ariakit from '@ariakit/react';
66

7-
/**
8-
* Internal dependencies
9-
*/
10-
import type { IconType } from '../icon';
11-
127
export type TabsContextProps =
138
| {
149
/**
@@ -78,37 +73,17 @@ export type TabListProps = {
7873
* The children elements, which should be a series of `Tabs.TabPanel` components.
7974
*/
8075
children?: React.ReactNode;
81-
/**
82-
* The class name to apply to the tablist.
83-
*/
84-
className?: string;
85-
/**
86-
* Custom CSS styles for the rendered tablist.
87-
*/
88-
style?: React.CSSProperties;
8976
};
9077

9178
export type TabProps = {
9279
/**
9380
* The id of the tab, which is prepended with the `Tabs` instanceId.
9481
*/
9582
id: string;
96-
/**
97-
* Custom CSS styles for the tab.
98-
*/
99-
style?: React.CSSProperties;
10083
/**
10184
* The children elements, generally the text to display on the tab.
10285
*/
10386
children?: React.ReactNode;
104-
/**
105-
* The class name to apply to the tab button.
106-
*/
107-
className?: string;
108-
/**
109-
* The icon used for the tab button.
110-
*/
111-
icon?: IconType;
11287
/**
11388
* Determines if the tab button should be disabled.
11489
*
@@ -131,14 +106,6 @@ export type TabPanelProps = {
131106
* A unique identifier for the tabpanel, which is used to generate a unique `id` for the underlying element.
132107
*/
133108
id: string;
134-
/**
135-
* The class name to apply to the tabpanel.
136-
*/
137-
className?: string;
138-
/**
139-
* Custom CSS styles for the rendered `TabPanel` component.
140-
*/
141-
style?: React.CSSProperties;
142109
/**
143110
* Determines whether or not the tabpanel element should be focusable.
144111
* If `false`, pressing the tab key will skip over the tabpanel, and instead

0 commit comments

Comments
 (0)