From 2990b6174d5436a177fc009410392298e0c2ef7f Mon Sep 17 00:00:00 2001
From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
Date: Mon, 17 Oct 2022 17:02:18 +1000
Subject: [PATCH] Add drawer icons to icons package
Switch editor sidebar icons to new drawer icons
Icon should reflect RTL as well.
Update TabPanel to allow icons on TabButtons
Add menu group to InspectorControl slot fills
Move nav menu controls into InspectorControls menu group
Introduce menu, settings & appearance tabs to sidebar
Refactor InspectorControlTabs
Re-orders the appearance and settings tabs. Also now omits the TabPanel altogether if only a single tab has contents.
Make block inspector tabs a Gutenberg experiment
A little tidy up
Clean up conditional tabs display
Remove nav specific menu tab for now
Remove Menu inspector controls group
Refactor inspector controls tabs to components
Remove conditional display of tabs
Render no settings or tools messages when no fills
Reduce new styles for equal width tabs
Add general slot for items applying to block as a whole
Move query block new post link to new slot
Revert "Move query block new post link to new slot"
This reverts commit 12799852648a67cb566112639d4d71e33a2d9834.
Revert "Add general slot for items applying to block as a whole"
This reverts commit 186276fb42af1a7dd571892b349eaacd34f0a3b0.
Tweak no style options message
Add changelog for TabPanel updates
Remove empty readme until experiment settles
Fix copy and paste error
---
lib/experimental/editor-settings.php | 3 +
lib/experiments-page.php | 14 ++
.../src/components/block-inspector/index.js | 163 +++++++++---------
.../src/components/block-inspector/style.scss | 10 +-
.../advanced-controls-panel.js | 37 ++++
.../inspector-controls-tabs/appearance-tab.js | 75 ++++++++
.../inspector-controls-tabs/index.js | 42 +++++
.../inspector-controls-tabs/settings-tab.js | 43 +++++
.../inspector-controls-tabs/utils.js | 20 +++
packages/components/CHANGELOG.md | 1 +
packages/components/src/tab-panel/README.md | 1 +
packages/components/src/tab-panel/index.tsx | 5 +-
packages/components/src/tab-panel/types.ts | 10 +-
.../sidebar/settings-sidebar/index.js | 10 +-
.../src/components/sidebar-edit-mode/index.js | 6 +-
packages/icons/src/index.js | 2 +
packages/icons/src/library/drawer-left.js | 21 +++
packages/icons/src/library/drawer-right.js | 21 +++
18 files changed, 394 insertions(+), 90 deletions(-)
create mode 100644 packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.js
create mode 100644 packages/block-editor/src/components/inspector-controls-tabs/appearance-tab.js
create mode 100644 packages/block-editor/src/components/inspector-controls-tabs/index.js
create mode 100644 packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js
create mode 100644 packages/block-editor/src/components/inspector-controls-tabs/utils.js
create mode 100644 packages/icons/src/library/drawer-left.js
create mode 100644 packages/icons/src/library/drawer-right.js
diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php
index b0c05544d6b199..862a1bfe2b28c6 100644
--- a/lib/experimental/editor-settings.php
+++ b/lib/experimental/editor-settings.php
@@ -86,6 +86,9 @@ function gutenberg_enable_experiments() {
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-off-canvas-navigation-editor', $gutenberg_experiments ) ) {
wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableOffCanvasNavigationEditor = true', 'before' );
}
+ if ( $gutenberg_experiments && array_key_exists( 'gutenberg-block-inspector-tabs', $gutenberg_experiments ) ) {
+ wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableBlockInspectorTabs = true', 'before' );
+ }
}
add_action( 'admin_init', 'gutenberg_enable_experiments' );
diff --git a/lib/experiments-page.php b/lib/experiments-page.php
index 309612664cb9c9..1296cdd03b89fa 100644
--- a/lib/experiments-page.php
+++ b/lib/experiments-page.php
@@ -52,6 +52,7 @@ function gutenberg_initialize_experiments_settings() {
'id' => 'gutenberg-zoomed-out-view',
)
);
+
add_settings_field(
'gutenberg-off-canvas-navigation-editor',
__( 'Off canvas navigation editor ', 'gutenberg' ),
@@ -63,6 +64,7 @@ function gutenberg_initialize_experiments_settings() {
'id' => 'gutenberg-off-canvas-navigation-editor',
)
);
+
add_settings_field(
'gutenberg-color-randomizer',
__( 'Color randomizer ', 'gutenberg' ),
@@ -75,6 +77,18 @@ function gutenberg_initialize_experiments_settings() {
)
);
+ add_settings_field(
+ 'gutenberg-block-inspector-tabs',
+ __( 'Block inspector tabs ', 'gutenberg' ),
+ 'gutenberg_display_experiment_field',
+ 'gutenberg-experiments',
+ 'gutenberg_experiments_section',
+ array(
+ 'label' => __( 'Test a new block inspector view splitting settings and appearance controls into tabs', 'gutenberg' ),
+ 'id' => 'gutenberg-block-inspector-tabs',
+ )
+ );
+
register_setting(
'gutenberg-experiments',
'gutenberg-experiments'
diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 379d8806f2a68c..f48819ec4a02b6 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -9,9 +9,8 @@ import {
store as blocksStore,
} from '@wordpress/blocks';
import {
- PanelBody,
- __experimentalUseSlotFills as useSlotFills,
FlexItem,
+ PanelBody,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
Button,
@@ -24,20 +23,19 @@ import { useMemo, useCallback } from '@wordpress/element';
*/
import SkipToSelectedBlock from '../skip-to-selected-block';
import BlockCard from '../block-card';
-import {
- default as InspectorControls,
- InspectorAdvancedControls,
-} from '../inspector-controls';
-import BlockStyles from '../block-styles';
import MultiSelectionInspector from '../multi-selection-inspector';
-import DefaultStylePicker from '../default-style-picker';
import BlockVariationTransforms from '../block-variation-transforms';
import useBlockDisplayInformation from '../use-block-display-information';
import { store as blockEditorStore } from '../../store';
import BlockIcon from '../block-icon';
+import BlockStyles from '../block-styles';
+import DefaultStylePicker from '../default-style-picker';
+import { default as InspectorControls } from '../inspector-controls';
+import { default as InspectorControlsTabs } from '../inspector-controls-tabs';
+import AdvancedControls from '../inspector-controls-tabs/advanced-controls-panel';
function useContentBlocks( blockTypes, block ) {
- const contenBlocksObjectAux = useMemo( () => {
+ const contentBlocksObjectAux = useMemo( () => {
return blockTypes.reduce( ( result, blockType ) => {
if (
blockType.name !== 'core/list-item' &&
@@ -53,7 +51,7 @@ function useContentBlocks( blockTypes, block ) {
}, [ blockTypes ] );
const isContentBlock = useCallback(
( blockName ) => {
- return !! contenBlocksObjectAux[ blockName ];
+ return !! contentBlocksObjectAux[ blockName ];
},
[ blockTypes ]
);
@@ -166,28 +164,36 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
};
}, [] );
+ const showTabs = window?.__experimentalEnableBlockInspectorTabs;
+
if ( count > 1 ) {
return (
-
-
-
-
-
+ { showTabs ? (
+
+ ) : (
+ <>
+
+
+
+
+
+ >
+ ) }
);
}
@@ -229,6 +235,8 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
};
const BlockInspectorSingleBlock = ( { clientId, blockName } ) => {
+ const showTabs = window?.__experimentalEnableBlockInspectorTabs;
+
const hasBlockStyles = useSelect(
( select ) => {
const { getBlockStyles } = select( blocksStore );
@@ -238,67 +246,64 @@ const BlockInspectorSingleBlock = ( { clientId, blockName } ) => {
[ blockName ]
);
const blockInformation = useBlockDisplayInformation( clientId );
+
return (
- { hasBlockStyles && (
-
-
-
- { hasBlockSupport(
- blockName,
- 'defaultStylePicker',
- true
- ) && }
-
-
+ { showTabs && (
+
+ ) }
+ { ! showTabs && (
+ <>
+ { hasBlockStyles && (
+
+
+
+ { hasBlockSupport(
+ blockName,
+ 'defaultStylePicker',
+ true
+ ) && (
+
+ ) }
+
+
+ ) }
+
+
+
+
+
+
+ >
) }
-
-
-
-
-
-
);
};
-const AdvancedControls = () => {
- const fills = useSlotFills( InspectorAdvancedControls.slotName );
- const hasFills = Boolean( fills && fills.length );
-
- if ( ! hasFills ) {
- return null;
- }
-
- return (
-
-
-
- );
-};
-
/**
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/block-inspector/README.md
*/
diff --git a/packages/block-editor/src/components/block-inspector/style.scss b/packages/block-editor/src/components/block-inspector/style.scss
index b7cfdcf46333a2..08ca013629927e 100644
--- a/packages/block-editor/src/components/block-inspector/style.scss
+++ b/packages/block-editor/src/components/block-inspector/style.scss
@@ -27,7 +27,8 @@
}
}
-.block-editor-block-inspector__no-blocks {
+.block-editor-block-inspector__no-blocks,
+.block-editor-block-inspector__no-block-tools {
display: block;
font-size: $default-font-size;
background: $white;
@@ -35,6 +36,13 @@
text-align: center;
}
+.block-editor-block-inspector__no-block-tools {
+ border-top: $border-width solid $gray-300;
+}
+
+.block-editor-block-inspector__tab-item {
+ flex: 1 1 0px;
+}
.block-editor-block-inspector__block-buttons-container {
border-top: $border-width solid $gray-200;
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.js b/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.js
new file mode 100644
index 00000000000000..83027861e9d190
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.js
@@ -0,0 +1,37 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ PanelBody,
+ __experimentalUseSlotFills as useSlotFills,
+} from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import {
+ default as InspectorControls,
+ InspectorAdvancedControls,
+} from '../inspector-controls';
+
+const AdvancedControls = () => {
+ const fills = useSlotFills( InspectorAdvancedControls.slotName );
+ const hasFills = Boolean( fills && fills.length );
+
+ if ( ! hasFills ) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+};
+
+export default AdvancedControls;
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/appearance-tab.js b/packages/block-editor/src/components/inspector-controls-tabs/appearance-tab.js
new file mode 100644
index 00000000000000..deb3bccffaa168
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/appearance-tab.js
@@ -0,0 +1,75 @@
+/**
+ * WordPress dependencies
+ */
+import { hasBlockSupport } from '@wordpress/blocks';
+import {
+ PanelBody,
+ __experimentalUseSlotFills as useSlotFills,
+} from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import BlockStyles from '../block-styles';
+import DefaultStylePicker from '../default-style-picker';
+import InspectorControls from '../inspector-controls';
+import InspectorControlsGroups from '../inspector-controls/groups';
+
+const AppearanceTab = ( {
+ blockName,
+ clientId,
+ hasBlockStyles,
+ hasSingleBlockSelection = false,
+} ) => {
+ const { border, color, dimensions, typography } = InspectorControlsGroups;
+ const appearanceFills = [
+ ...( useSlotFills( border.Slot.__unstableName ) || [] ),
+ ...( useSlotFills( color.Slot.__unstableName ) || [] ),
+ ...( useSlotFills( dimensions.Slot.__unstableName ) || [] ),
+ ...( useSlotFills( typography.Slot.__unstableName ) || [] ),
+ ];
+
+ return (
+ <>
+ { ! appearanceFills.length && (
+
+ { hasSingleBlockSelection
+ ? __( 'This block has no style options.' )
+ : __( 'The selected blocks have no style options.' ) }
+
+ ) }
+ { hasBlockStyles && (
+
+
+
+ { hasBlockSupport(
+ blockName,
+ 'defaultStylePicker',
+ true
+ ) && }
+
+
+ ) }
+
+
+
+
+ >
+ );
+};
+
+export default AppearanceTab;
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/index.js b/packages/block-editor/src/components/inspector-controls-tabs/index.js
new file mode 100644
index 00000000000000..62b87dd58e11cf
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/index.js
@@ -0,0 +1,42 @@
+/**
+ * WordPress dependencies
+ */
+import { TabPanel } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import { TAB_SETTINGS, TAB_APPEARANCE } from './utils';
+import AppearanceTab from './appearance-tab';
+import SettingsTab from './settings-tab';
+
+const tabs = [ TAB_APPEARANCE, TAB_SETTINGS ];
+
+export default function InspectorControlsTabs( {
+ blockName,
+ clientId,
+ hasBlockStyles,
+} ) {
+ return (
+
+ { ( tab ) => {
+ if ( tab.name === TAB_SETTINGS.name ) {
+ return (
+
+ );
+ }
+
+ if ( tab.name === TAB_APPEARANCE.name ) {
+ return (
+
+ );
+ }
+ } }
+
+ );
+}
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js b/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js
new file mode 100644
index 00000000000000..a000173807c197
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/settings-tab.js
@@ -0,0 +1,43 @@
+/**
+ * WordPress dependencies
+ */
+import { __experimentalUseSlotFills as useSlotFills } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import AdvancedControls from './advanced-controls-panel';
+import InspectorControlsGroups from '../inspector-controls/groups';
+import {
+ default as InspectorControls,
+ InspectorAdvancedControls,
+} from '../inspector-controls';
+
+const SettingsTab = ( { hasSingleBlockSelection = false } ) => {
+ const { default: defaultGroup } = InspectorControlsGroups;
+ const settingsFills = [
+ ...( useSlotFills( defaultGroup.Slot.__unstableName ) || [] ),
+ ...( useSlotFills( InspectorAdvancedControls.slotName ) || [] ),
+ ];
+
+ return (
+ <>
+
+ { hasSingleBlockSelection && (
+
+ ) }
+ { ! settingsFills.length && (
+
+ { hasSingleBlockSelection
+ ? __( 'This block has no settings.' )
+ : __( 'The selected blocks have no settings.' ) }
+
+ ) }
+ >
+ );
+};
+
+export default SettingsTab;
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/utils.js b/packages/block-editor/src/components/inspector-controls-tabs/utils.js
new file mode 100644
index 00000000000000..0bec1088174d31
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/utils.js
@@ -0,0 +1,20 @@
+/**
+ * WordPress dependencies
+ */
+import { cog, styles } from '@wordpress/icons';
+
+export const TAB_SETTINGS = {
+ name: 'settings',
+ title: 'Settings',
+ value: 'settings',
+ icon: cog,
+ className: 'block-editor-block-inspector__tab-item',
+};
+
+export const TAB_APPEARANCE = {
+ name: 'appearance',
+ title: 'Appearance',
+ value: 'appearance',
+ icon: styles,
+ className: 'block-editor-block-inspector__tab-item',
+};
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 62169314631bda..77cd8697cd8665 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -7,6 +7,7 @@
### Enhancements
- `ColorPalette`, `BorderBox`, `BorderBoxControl`: polish and DRY prop types, add default values ([#45463](https://github.com/WordPress/gutenberg/pull/45463)).
+- `TabPanel`: Add ability to set icon only tab buttons ([#45005](https://github.com/WordPress/gutenberg/pull/45005)).
### Bug Fix
diff --git a/packages/components/src/tab-panel/README.md b/packages/components/src/tab-panel/README.md
index a4a1c0c525370e..c3e889a2bbf33d 100644
--- a/packages/components/src/tab-panel/README.md
+++ b/packages/components/src/tab-panel/README.md
@@ -120,6 +120,7 @@ An array of objects containing the following properties:
- `name`: `(string)` Defines the key for the tab.
- `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.
> > **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 206c2b8aab0a71..dfd3ebd9455190 100644
--- a/packages/components/src/tab-panel/index.tsx
+++ b/packages/components/src/tab-panel/index.tsx
@@ -127,8 +127,11 @@ export function TabPanel( {
selected={ tab.name === selected }
key={ tab.name }
onClick={ () => handleTabSelection( tab.name ) }
+ label={ tab.icon && tab.title }
+ icon={ tab.icon }
+ showTooltip={ !! tab.icon }
>
- { tab.title }
+ { ! tab.icon && tab.title }
) ) }
diff --git a/packages/components/src/tab-panel/types.ts b/packages/components/src/tab-panel/types.ts
index 2a89da6a215b7d..1436b8034a66af 100644
--- a/packages/components/src/tab-panel/types.ts
+++ b/packages/components/src/tab-panel/types.ts
@@ -3,6 +3,11 @@
*/
import type { ReactNode } from 'react';
+/**
+ * Internal dependencies
+ */
+import type { IconType } from '../icon';
+
type Tab = {
/**
* The key of the tab.
@@ -18,11 +23,14 @@ type Tab = {
className?: string;
} & Record< any, any >;
-export type TabButtonProps = {
+export type TabButtonProps< IconProps = unknown > = {
children: ReactNode;
className?: string;
+ icon?: IconType< IconProps >;
+ label?: string;
onClick: ( event: MouseEvent ) => void;
selected: boolean;
+ showTooltip?: boolean;
tabId: string;
};
diff --git a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js
index c044d0b49714cd..677161c6b5a383 100644
--- a/packages/edit-post/src/components/sidebar/settings-sidebar/index.js
+++ b/packages/edit-post/src/components/sidebar/settings-sidebar/index.js
@@ -5,10 +5,12 @@ import {
BlockInspector,
store as blockEditorStore,
} from '@wordpress/block-editor';
-import { cog } from '@wordpress/icons';
+import { useSelect } from '@wordpress/data';
import { Platform } from '@wordpress/element';
-import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
+import { isRTL, __ } from '@wordpress/i18n';
+import { drawerLeft, drawerRight } from '@wordpress/icons';
import { store as interfaceStore } from '@wordpress/interface';
+import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
/**
* Internal dependencies
@@ -25,8 +27,6 @@ import MetaBoxes from '../../meta-boxes';
import PluginDocumentSettingPanel from '../plugin-document-setting-panel';
import PluginSidebarEditPost from '../plugin-sidebar';
import TemplateSummary from '../template-summary';
-import { __ } from '@wordpress/i18n';
-import { useSelect } from '@wordpress/data';
import { store as editPostStore } from '../../../store';
const SIDEBAR_ACTIVE_BY_DEFAULT = Platform.select( {
@@ -78,7 +78,7 @@ const SettingsSidebar = () => {
/* translators: button label text should, if possible, be under 16 characters. */
title={ __( 'Settings' ) }
toggleShortcut={ keyboardShortcut }
- icon={ cog }
+ icon={ isRTL() ? drawerLeft : drawerRight }
isActiveByDefault={ SIDEBAR_ACTIVE_BY_DEFAULT }
>
{ ! isTemplateMode && sidebarName === 'edit-post/document' && (
diff --git a/packages/edit-site/src/components/sidebar-edit-mode/index.js b/packages/edit-site/src/components/sidebar-edit-mode/index.js
index 080be432eb09d8..12073a77b56e03 100644
--- a/packages/edit-site/src/components/sidebar-edit-mode/index.js
+++ b/packages/edit-site/src/components/sidebar-edit-mode/index.js
@@ -2,8 +2,8 @@
* WordPress dependencies
*/
import { createSlotFill, PanelBody } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
-import { cog } from '@wordpress/icons';
+import { isRTL, __ } from '@wordpress/i18n';
+import { drawerLeft, drawerRight } from '@wordpress/icons';
import { useEffect, Fragment } from '@wordpress/element';
import { useSelect, useDispatch } from '@wordpress/data';
import { store as interfaceStore } from '@wordpress/interface';
@@ -78,7 +78,7 @@ export function SidebarComplementaryAreaFills() {
}
headerClassName="edit-site-sidebar-edit-mode__panel-tabs"
diff --git a/packages/icons/src/index.js b/packages/icons/src/index.js
index c7f891a5292dbf..5870ccba9ab043 100644
--- a/packages/icons/src/index.js
+++ b/packages/icons/src/index.js
@@ -66,6 +66,8 @@ export { default as currencyPound } from './library/currency-pound';
export { default as customPostType } from './library/custom-post-type';
export { default as desktop } from './library/desktop';
export { default as dragHandle } from './library/drag-handle';
+export { default as drawerLeft } from './library/drawer-left';
+export { default as drawerRight } from './library/drawer-right';
export { default as download } from './library/download';
export { default as edit } from './library/edit';
export { default as external } from './library/external';
diff --git a/packages/icons/src/library/drawer-left.js b/packages/icons/src/library/drawer-left.js
new file mode 100644
index 00000000000000..2e1626fb1fe17a
--- /dev/null
+++ b/packages/icons/src/library/drawer-left.js
@@ -0,0 +1,21 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/primitives';
+
+const drawerLeft = (
+
+);
+
+export default drawerLeft;
diff --git a/packages/icons/src/library/drawer-right.js b/packages/icons/src/library/drawer-right.js
new file mode 100644
index 00000000000000..95a8e72f775fb1
--- /dev/null
+++ b/packages/icons/src/library/drawer-right.js
@@ -0,0 +1,21 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/primitives';
+
+const drawerRight = (
+
+);
+
+export default drawerRight;