Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storybook: Add TabbedSidebar stories and improve docs #68118

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions packages/block-editor/src/components/tabbed-sidebar/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
# Tabbed Panel
# TabbedSidebar

The `TabbedPanel` component is used to create the secondary panels in the editor.
The `TabbedSidebar` component is used to create secondary panels in the editor with tabbed navigation.

## Development guidelines

This acts as a wrapper for the `Tabs` component, but adding conventions that can be shared between all secondary panels, for example:
This acts as a wrapper for the `Tabs` component, adding conventions that can be shared between all secondary panels, including:

- A close button
- Tabs that fill the panel
- Custom scollbars
- Custom scrollbars

### Usage

Renders a block alignment toolbar with alignments options.

```jsx
import { TabbedSidebar } from '@wordpress/components';
import { TabbedSidebar } from '@wordpress/block-editor';

const MyTabbedSidebar = () => (
<TabbedSidebar
tabs={ [
{
name: 'slug-1',
title: _x( 'Title 1', 'context' ),
panel: <PanelContents>,
panel: <PanelContents />,
panelRef: useRef('an-optional-ref'),
},
{
Expand All @@ -35,6 +33,8 @@ const MyTabbedSidebar = () => (
onClose={ onClickCloseButton }
onSelect={ onSelectTab }
defaultTabId="slug-1"
selectedTab="slug-1"
closeButtonLabel="Close sidebar"
ref={ tabsRef }
/>
);
Expand All @@ -47,30 +47,41 @@ const MyTabbedSidebar = () => (
- **Type:** `String`
- **Default:** `undefined`

This is passed to the `Tabs` component so it can handle the tab to select by default when it component renders.
The ID of the tab to be selected by default when the component renders.

### `onClose`

- **Type:** `Function`

The function that is called when the close button is clicked.
Function called when the close button is clicked.

### `onSelect`

- **Type:** `Function`

This is passed to the `Tabs` component - it will be called when a tab has been selected. It is passed the selected tab's ID as an argument.
Function called when a tab is selected. Receives the selected tab's ID as an argument.

### `selectedTab`

- **Type:** `String`
- **Default:** `undefined`

This is passed to the `Tabs` component - it will display this tab as selected.
The ID of the currently selected tab.

### `tabs`

- **Type:** `Array`
- **Default:** `undefined`

An array of tabs which will be rendered as `TabList` and `TabPanel` components.
Array of tab objects. Each tab should have:

- `name` (string): Unique identifier for the tab
- `title` (string): Display title for the tab
- `panel` (React.Node): Content to display in the tab panel
- `panelRef` (React.Ref, optional): Reference to the tab panel element

#### `closeButtonLabel`

- **Type:** `String`

Accessibility label for the close button.
38 changes: 38 additions & 0 deletions packages/block-editor/src/components/tabbed-sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,44 @@ import { unlock } from '../../lock-unlock';

const { Tabs } = unlock( componentsPrivateApis );

/**
* A component that creates a tabbed sidebar with a close button.
*
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/tabbed-sidebar/README.md
*
* @example
* ```jsx
* function MyTabbedSidebar() {
* return (
* <TabbedSidebar
* tabs={ [
* {
* name: 'tab1',
* title: 'Settings',
* panel: <PanelContents />,
* }
* ] }
* onClose={ () => {} }
* onSelect={ () => {} }
* defaultTabId="tab1"
* selectedTab="tab1"
* closeButtonLabel="Close sidebar"
* />
* );
* }
* ```
*
* @param {Object} props Component props.
* @param {string} [props.defaultTabId] The ID of the tab to be selected by default when the component renders.
* @param {Function} props.onClose Function called when the close button is clicked.
* @param {Function} props.onSelect Function called when a tab is selected. Receives the selected tab's ID as an argument.
* @param {string} props.selectedTab The ID of the currently selected tab.
* @param {Array} props.tabs Array of tab objects. Each tab should have: name (string), title (string),
* panel (React.Node), and optionally panelRef (React.Ref).
* @param {string} props.closeButtonLabel Accessibility label for the close button.
* @param {Object} ref Forward ref to the tabs list element.
* @return {Element} The tabbed sidebar component.
*/
function TabbedSidebar(
{ defaultTabId, onClose, onSelect, selectedTab, tabs, closeButtonLabel },
ref
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import TabbedSidebar from '../';

const meta = {
title: 'BlockEditor/TabbedSidebar',
component: TabbedSidebar,
Sukhendu2002 marked this conversation as resolved.
Show resolved Hide resolved
tags: [ 'status-private' ],
parameters: {
docs: {
canvas: { sourceState: 'shown' },
description: {
component:
'A component that creates a tabbed sidebar with a close button.',
},
},
},
argTypes: {
defaultTabId: {
control: { type: null },
table: {
type: { summary: 'string' },
},
description:
'The ID of the tab to be selected by default when the component renders.',
},
onClose: {
action: 'onClose',
control: { type: null },
table: {
type: { summary: 'function' },
},
description: 'Function called when the close button is clicked.',
},
onSelect: {
action: 'onSelect',
control: { type: null },
table: {
type: { summary: 'function' },
},
description:
"Function called when a tab is selected. Receives the selected tab's ID as an argument.",
},
selectedTab: {
control: { type: null },
table: {
type: { summary: 'string' },
},
description: 'The ID of the currently selected tab.',
},
tabs: {
control: { type: null },
table: {
type: { summary: 'array' },
},
description:
'Array of tab objects. Each tab should have: name (string), title (string), panel (React.Node), and optionally panelRef (React.Ref).',
},
closeButtonLabel: {
control: { type: null },
table: {
type: { summary: 'string' },
},
description: 'Accessibility label for the close button.',
},
},
};

export default meta;

const DEMO_TABS = [
{ name: 'tab1', title: 'Settings' },
{ name: 'tab2', title: 'Styles' },
{ name: 'tab3', title: 'Advanced' },
];

export const Default = {
render: function Template( { onSelect, onClose, ...args } ) {
const [ selectedTab, setSelectedTab ] = useState();

return (
<TabbedSidebar
{ ...args }
selectedTab={ selectedTab }
onSelect={ ( ...changeArgs ) => {
onSelect( ...changeArgs );
setSelectedTab( ...changeArgs );
} }
onClose={ onClose }
/>
);
},
args: {
tabs: DEMO_TABS,
defaultTabId: 'tab1',
closeButtonLabel: 'Close Sidebar',
},
};
Loading