Skip to content
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
12 changes: 5 additions & 7 deletions packages/editor/src/components/sidebar/header.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/**
* WordPress dependencies
*/
import { privateApis as componentsPrivateApis } from '@wordpress/components';
import { __, _x } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';
import { Tabs } from '@wordpress/ui';

/**
* Internal dependencies
Expand All @@ -13,8 +13,6 @@ import { store as editorStore } from '../../store';
import { unlock } from '../../lock-unlock';
import { sidebars } from './constants';

const { Tabs } = unlock( componentsPrivateApis );

export default function SidebarHeader() {
const { postTypeLabel, isRevisionsMode } = useSelect( ( select ) => {
const { getPostTypeLabel } = select( editorStore );
Expand All @@ -38,12 +36,12 @@ export default function SidebarHeader() {
}

return (
<Tabs.TabList>
<Tabs.Tab tabId={ sidebars.document }>{ documentLabel }</Tabs.Tab>
<Tabs.Tab tabId={ sidebars.block }>
<Tabs.List activateOnFocus={ false }>
<Tabs.Tab value={ sidebars.document }>{ documentLabel }</Tabs.Tab>
<Tabs.Tab value={ sidebars.block }>
{ /* translators: Text label for the Block Settings Sidebar tab. */ }
{ __( 'Block' ) }
</Tabs.Tab>
</Tabs.TabList>
</Tabs.List>
);
}
141 changes: 53 additions & 88 deletions packages/editor/src/components/sidebar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import {
store as blockEditorStore,
} from '@wordpress/block-editor';
import { useSelect, useDispatch } from '@wordpress/data';
import { useCallback, useContext } from '@wordpress/element';
import { isRTL, __, _x } from '@wordpress/i18n';
import { drawerLeft, drawerRight } from '@wordpress/icons';
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
import { privateApis as componentsPrivateApis } from '@wordpress/components';
import { store as interfaceStore } from '@wordpress/interface';
import { Tabs } from '@wordpress/ui';

/**
* Internal dependencies
Expand All @@ -34,23 +33,46 @@ import { sidebars } from './constants';
import { unlock } from '../../lock-unlock';
import { store as editorStore } from '../../store';

const { Tabs } = unlock( componentsPrivateApis );

const SIDEBAR_ACTIVE_BY_DEFAULT = true;

const SidebarContent = ( {
tabName,
keyboardShortcut,
onActionPerformed,
extraPanels,
} ) => {
// Because `PluginSidebar` renders a `ComplementaryArea`, we
// need to forward the `Tabs` context so it can be passed through the
// underlying slot/fill.
const tabsContextValue = useContext( Tabs.Context );
const isRevisionsMode = useSelect( ( select ) => {
return unlock( select( editorStore ) ).isRevisionsMode();
} );
function Sidebar( { extraPanels, onActionPerformed } ) {
useAutoSwitchEditorSidebars();

const { tabName, keyboardShortcut, isRevisionsMode } = useSelect(
( select ) => {
const shortcut = select(
keyboardShortcutsStore
).getShortcutRepresentation( 'core/editor/toggle-sidebar' );

const sidebar =
select( interfaceStore ).getActiveComplementaryArea( 'core' );
const _isEditorSidebarOpened = [
sidebars.block,
sidebars.document,
].includes( sidebar );
let _tabName = sidebar;
if ( ! _isEditorSidebarOpened ) {
_tabName = select( blockEditorStore ).getBlockSelectionStart()
? sidebars.block
: sidebars.document;
}

return {
tabName: _tabName,
keyboardShortcut: shortcut,
isRevisionsMode: unlock(
select( editorStore )
).isRevisionsMode(),
};
},
[]
);

const { enableComplementaryArea } = useDispatch( interfaceStore );

function onTabSelect( newSelectedTabId ) {
enableComplementaryArea( 'core', newSelectedTabId );
}
Comment on lines +73 to +75

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callback memoization isn't needed, and newSelectedTabId should always have a value.


let tabContent;
if ( isRevisionsMode ) {
Expand Down Expand Up @@ -82,15 +104,8 @@ const SidebarContent = ( {
return (
<PluginSidebar
identifier={ tabName }
header={
<Tabs.Context.Provider value={ tabsContextValue }>
<SidebarHeader />
</Tabs.Context.Provider>
}
header={ <SidebarHeader /> }
closeLabel={ __( 'Close Settings' ) }
// This classname is added so we can apply a corrective negative
// margin to the panel.
// see https://github.com/WordPress/gutenberg/pull/55360#pullrequestreview-1737671049
Comment on lines -91 to -93

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a stale comment. The panel has no negative margin.

className="editor-sidebar__panel"
headerClassName="editor-sidebar__panel-tabs"
title={
Expand All @@ -100,71 +115,21 @@ const SidebarContent = ( {
toggleShortcut={ keyboardShortcut }
icon={ isRTL() ? drawerLeft : drawerRight }
isActiveByDefault={ SIDEBAR_ACTIVE_BY_DEFAULT }
>
<Tabs.Context.Provider value={ tabsContextValue }>
<Tabs.TabPanel tabId={ sidebars.document } focusable={ false }>
{ tabContent }
</Tabs.TabPanel>
<Tabs.TabPanel tabId={ sidebars.block } focusable={ false }>
<BlockInspector />
{ isRevisionsMode && <RevisionBlockDiffPanel /> }
</Tabs.TabPanel>
</Tabs.Context.Provider>
</PluginSidebar>
);
};

const Sidebar = ( { extraPanels, onActionPerformed } ) => {
useAutoSwitchEditorSidebars();
const { tabName, keyboardShortcut } = useSelect( ( select ) => {
const shortcut = select(
keyboardShortcutsStore
).getShortcutRepresentation( 'core/editor/toggle-sidebar' );

const sidebar =
select( interfaceStore ).getActiveComplementaryArea( 'core' );
const _isEditorSidebarOpened = [
sidebars.block,
sidebars.document,
].includes( sidebar );
let _tabName = sidebar;
if ( ! _isEditorSidebarOpened ) {
_tabName = !! select( blockEditorStore ).getBlockSelectionStart()
? sidebars.block
: sidebars.document;
}

return {
tabName: _tabName,
keyboardShortcut: shortcut,
};
}, [] );

const { enableComplementaryArea } = useDispatch( interfaceStore );

const onTabSelect = useCallback(
( newSelectedTabId ) => {
if ( !! newSelectedTabId ) {
enableComplementaryArea( 'core', newSelectedTabId );
// Makes `Tabs.Root` the container, so the tab list passed as
// `header` and the panels below share a subtree across the fill.
render={
<Tabs.Root value={ tabName } onValueChange={ onTabSelect } />
}
},
[ enableComplementaryArea ]
);

return (
<Tabs
selectedTabId={ tabName }
onSelect={ onTabSelect }
selectOnMove={ false }
>
<SidebarContent
tabName={ tabName }
keyboardShortcut={ keyboardShortcut }
onActionPerformed={ onActionPerformed }
extraPanels={ extraPanels }
/>
</Tabs>
<Tabs.Panel value={ sidebars.document } tabIndex={ -1 }>
{ tabContent }
</Tabs.Panel>
<Tabs.Panel value={ sidebars.block } tabIndex={ -1 }>
<BlockInspector />
{ isRevisionsMode && <RevisionBlockDiffPanel /> }
</Tabs.Panel>
</PluginSidebar>
);
};
}

export default Sidebar;
4 changes: 4 additions & 0 deletions packages/interface/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Enhancements

- `ComplementaryArea`: Add a `render` prop to replace the default container element, following the `@wordpress/ui` convention ([#81054](https://github.com/WordPress/gutenberg/pull/81054)).

### Bug Fixes

- `ComplementaryArea`: Remove incorrect `aria-expanded` attribute from the "Pin to toolbar" toggle button, which already exposes its state via `aria-pressed` ([#79874](https://github.com/WordPress/gutenberg/pull/79874)).
Expand Down
53 changes: 44 additions & 9 deletions packages/interface/src/components/complementary-area/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ import {
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { check, starEmpty, starFilled } from '@wordpress/icons';
import { useEffect, useRef, useState } from '@wordpress/element';
import {
cloneElement,
isValidElement,
useEffect,
useRef,
useState,
} from '@wordpress/element';
import { store as viewportStore } from '@wordpress/viewport';
import { store as preferencesStore } from '@wordpress/preferences';
import {
Expand Down Expand Up @@ -49,13 +55,41 @@ const variants = {
mobileOpen: { width: '100vw' },
};

/**
* Renders the complementary area container, replacing the default `div` with
* the element (or element factory) given via the `render` prop.
*
* `className` and `style` are composed rather than overwritten, since the
* container is also the scroll container for the sidebar.
*
* @param {Function|Object} [render] Replacement element, or a function
* returning one.
* @param {Object} props Props for the container.
*/
function renderContainer( render, props ) {
if ( typeof render === 'function' ) {
return render( props );
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to support the function renderer or just the element with div fallback?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a simple element-only version should be fine for now. If this happens a lot, or if we need function renderer support, I think we should consider re-exporting Base UI useRender from @wordpress/ui.


if ( isValidElement( render ) ) {
return cloneElement( render, {
...props,
className: clsx( render.props.className, props.className ),
style: { ...render.props.style, ...props.style },
} );
}

return <div { ...props } />;
}

function ComplementaryAreaFill( {
activeArea,
isActive,
scope,
children,
className,
id,
render,
} ) {
const disableMotion = useReducedMotion();
const isMobileViewport = useViewportMatch( 'medium', '<' );
Expand Down Expand Up @@ -94,17 +128,16 @@ function ComplementaryAreaFill( {
transition={ transition }
className="interface-complementary-area__fill"
>
<div
id={ id }
className={ className }
style={ {
{ renderContainer( render, {
id,
className,
style: {
width: isMobileViewport
? '100vw'
: SIDEBAR_WIDTH,
} }
>
{ children }
</div>
},
children,
} ) }
</motion.div>
) }
</AnimatePresence>
Expand Down Expand Up @@ -177,6 +210,7 @@ function ComplementaryArea( {
icon: iconProp,
isPinnable = true,
panelClassName,
render,
scope,
name,
title,
Expand Down Expand Up @@ -302,6 +336,7 @@ function ComplementaryArea( {
className={ clsx( 'interface-complementary-area', className ) }
scope={ scope }
id={ identifier.replace( '/', ':' ) }
render={ render }
>
<ComplementaryAreaHeader
className={ headerClassName }
Expand Down
10 changes: 0 additions & 10 deletions tools/eslint/suppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -1377,16 +1377,6 @@
"count": 1
}
},
"packages/editor/src/components/sidebar/header.js": {
"@wordpress/use-recommended-components": {
"count": 1
}
},
"packages/editor/src/components/sidebar/index.js": {
"@wordpress/use-recommended-components": {
"count": 1
}
},
"packages/editor/src/components/sidebar/post-revision-summary.js": {
"@wordpress/use-recommended-components": {
"count": 2
Expand Down
Loading