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 1/2] 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 b0c05544d6b19..862a1bfe2b28c 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 309612664cb9c..1296cdd03b89f 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 379d8806f2a68..f48819ec4a02b 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 b7cfdcf46333a..08ca013629927 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 0000000000000..83027861e9d19 --- /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 0000000000000..deb3bccffaa16 --- /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 0000000000000..62b87dd58e11c --- /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 0000000000000..a000173807c19 --- /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 0000000000000..0bec1088174d3 --- /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 62169314631bd..77cd8697cd866 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 a4a1c0c525370..c3e889a2bbf33 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 206c2b8aab0a7..dfd3ebd945519 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 2a89da6a215b7..1436b8034a66a 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 c044d0b49714c..677161c6b5a38 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 080be432eb09d..12073a77b56e0 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 c7f891a5292db..5870ccba9ab04 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 0000000000000..2e1626fb1fe17 --- /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 0000000000000..95a8e72f775fb --- /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; From 84bf480d930c5b04c6b8c9e44d4114c69f76227d Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Thu, 17 Nov 2022 15:00:35 +0800 Subject: [PATCH 2/2] Fix changelog --- packages/components/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 77cd8697cd866..7f740706518c2 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,12 +2,15 @@ ## Unreleased +### Enhancements + +- `TabPanel`: Add ability to set icon only tab buttons ([#45005](https://github.com/WordPress/gutenberg/pull/45005)). + ## 22.1.0 (2022-11-16) ### 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