Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions packages/block-editor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- State control badges: migrate from the private `@wordpress/components` `Badge` to `@wordpress/ui` `Badge` ([#82608](https://github.com/WordPress/gutenberg/pull/82608)).
- Use the `inertValue` helper to set `inert` attributes, for better React 18/19 compatibility ([#83871](https://github.com/WordPress/gutenberg/pull/83871)).
- `LinkControl`: Add a `transformSuggestions` prop, so a consumer can filter, order or add to the search suggestions before they are shown ([#83652](https://github.com/WordPress/gutenberg/pull/83652)).
- Block inspector: Move the Additional CSS and Additional CSS class(es) controls from the Advanced panel in the Settings tab to a new "Additional styles" panel in the Styles tab, through a new `additional-styles` group for `InspectorControls`. Additional styles controls count toward Styles tab availability. When tabs are disabled or only one tab is available, the Additional styles and Advanced panels appear in the combined inspector ([#83753](https://github.com/WordPress/gutenberg/pull/83753)).

### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { SectionStyleControls } from '../inspector-controls-tabs/styles-tab';
import useInspectorControlsTabs from '../inspector-controls-tabs/use-inspector-controls-tabs';
import InspectorControlsLastItem from '../inspector-controls/last-item';
import AdvancedControls from '../inspector-controls-tabs/advanced-controls-panel';
import AdditionalStyles from '../inspector-controls-tabs/additional-styles-panel';
import PositionControls from '../inspector-controls-tabs/position-controls-panel';
import useBlockInspectorAnimationSettings from './useBlockInspectorAnimationSettings';
import { BlockStateBadges, BlockStatesControl } from '../../hooks/states';
Expand Down Expand Up @@ -82,6 +83,9 @@ function StyleInspectorSlots( {
) }
{ showAdvancedControls && (
<div>
{ /* There are no tabs to divide the advanced tools
between, so each appears as its own panel. */ }
<AdditionalStyles />
<AdvancedControls />
</div>
) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
// Ensures this PanelBody is treated like the ToolsPanel, removing double borders.
margin-top: -$border-width;
}

// The Advanced panel can hold two slot groups at once, the settings tools
// and the styling tools. Each slot renders its own container, so the
// margin between controls above stops at the last control of a container.
// Restore the gap where two containers meet.
.block-editor-block-inspector__advanced > div + div {
margin-top: $grid-unit-20;
}
}

.block-editor-block-inspector__no-blocks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default function AdvancedPanel( {
</Notice>
) }
<WCTextareaControl
label={ __( 'Additional CSS' ) }
label={ __( 'CSS' ) }
value={ customCSS }
onChange={ ( newValue ) => handleOnChange( newValue ) }
onBlur={ handleOnBlur }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
PanelBody,
__experimentalUseSlotFills as useSlotFills,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { default as InspectorControls } from '../inspector-controls';
import groups from '../inspector-controls/groups';

/**
* Renders the "Additional styles" panel for the block inspector.
*
* The panel holds advanced styling controls such as Additional CSS, which live
* in the `additional-styles` group. It renders nothing when the group has no
* fills.
*
* @param {Object} props Component props.
* @param {boolean} [props.initialOpen] Whether the panel starts expanded.
*/
const AdditionalStyles = ( { initialOpen = false } ) => {
const fills = useSlotFills( groups[ 'additional-styles' ].name );

if ( ! fills?.length ) {
return null;
}

return (
<PanelBody
className="block-editor-block-inspector__additional-styles"
title={ __( 'Additional styles' ) }
initialOpen={ initialOpen }
>
<InspectorControls.Slot group="additional-styles" />
</PanelBody>
);
};

export default AdditionalStyles;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import {
} from '../inspector-controls';
import { PrivateInspectorControlsAllowedBlocks } from '../inspector-controls/groups';

/**
* Renders the "Advanced" panel for the block inspector.
*
* The panel holds advanced settings tools such as the HTML anchor, from the
* `advanced` group, alongside the private allowed-blocks control. It renders
* nothing when neither has fills.
*
* @param {Object} props Component props.
* @param {boolean} [props.initialOpen] Whether the panel starts expanded.
*/
const AdvancedControls = ( { initialOpen = false } ) => {
const fills = useSlotFills( InspectorAdvancedControls.slotName );
const privateFills = useSlotFills(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export default function InspectorControlsTabs( {
hasBlockStyles={ hasBlockStyles }
isSectionBlock={ isSectionBlock }
contentClientIds={ contentClientIds }
showAdditionalStyles={ !! blockName }
/>
</Tabs.TabPanel>
</Tabs>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import AdditionalStyles from './additional-styles-panel';
import BlockStyles from '../block-styles';
import InspectorControls from '../inspector-controls';
import PositionControls from './position-controls-panel';
Expand Down Expand Up @@ -101,6 +102,7 @@ const StylesTab = ( {
hasBlockStyles,
isSectionBlock,
contentClientIds,
showAdditionalStyles = false,
} ) => {
return (
<>
Expand Down Expand Up @@ -156,6 +158,13 @@ const StylesTab = ( {
<InspectorControls.Slot group="styles" />
</>
) }
{ /* Section blocks are excluded from the panels above but still
expose additional styling tools such as Additional CSS. */ }
{ showAdditionalStyles && (
<div>
<AdditionalStyles />
</div>
) }
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { describe, expect, it } from 'vitest';
import { render, screen } from '@testing-library/react';
import { SlotFillProvider } from '@wordpress/components';
import AdvancedControls from '../advanced-controls-panel';
import AdditionalStyles from '../additional-styles-panel';
import groups from '../../inspector-controls/groups';

// The `InspectorControls` fill component is bypassed in favour of the
// underlying group fills, so that the panels can be exercised without a
// selected block and its editing mode.
const AdvancedFill = groups.advanced.Fill;
const AdditionalStylesFill = groups[ 'additional-styles' ].Fill;

describe( 'AdvancedControls', () => {
it( 'renders nothing when the advanced group has no fills', () => {
render(
<SlotFillProvider>
<AdvancedControls initialOpen />
</SlotFillProvider>
);

expect(
screen.queryByRole( 'button', { name: 'Advanced' } )
).not.toBeInTheDocument();
} );

it( 'renders the advanced group fills', () => {
render(
<SlotFillProvider>
<AdvancedFill>
<span>HTML anchor</span>
</AdvancedFill>
<AdvancedControls initialOpen />
</SlotFillProvider>
);

expect(
screen.getByRole( 'button', { name: 'Advanced' } )
).toBeVisible();
expect( screen.getByText( 'HTML anchor' ) ).toBeVisible();
} );

it( 'renders nothing when only the additional-styles group has fills', () => {
render(
<SlotFillProvider>
<AdditionalStylesFill>
<span>Additional CSS</span>
</AdditionalStylesFill>
<AdvancedControls initialOpen />
</SlotFillProvider>
);

expect(
screen.queryByRole( 'button', { name: 'Advanced' } )
).not.toBeInTheDocument();
} );
} );

describe( 'AdditionalStyles', () => {
it( 'renders nothing when the additional-styles group has no fills', () => {
render(
<SlotFillProvider>
<AdditionalStyles initialOpen />
</SlotFillProvider>
);

expect(
screen.queryByRole( 'button', { name: 'Additional styles' } )
).not.toBeInTheDocument();
} );

it( 'renders the additional-styles group fills', () => {
render(
<SlotFillProvider>
<AdditionalStylesFill>
<span>Additional CSS</span>
</AdditionalStylesFill>
<AdditionalStyles initialOpen />
</SlotFillProvider>
);

expect(
screen.getByRole( 'button', { name: 'Additional styles' } )
).toBeVisible();
expect( screen.getByText( 'Additional CSS' ) ).toBeVisible();
} );
} );

describe( 'Advanced and Additional styles together', () => {
it( 'renders as two separate panels', () => {
render(
<SlotFillProvider>
<AdvancedFill>
<span>HTML anchor</span>
</AdvancedFill>
<AdditionalStylesFill>
<span>Additional CSS</span>
</AdditionalStylesFill>
<AdditionalStyles initialOpen />
<AdvancedControls initialOpen />
</SlotFillProvider>
);

expect(
screen.getByRole( 'button', { name: 'Additional styles' } )
).toBeVisible();
expect(
screen.getByRole( 'button', { name: 'Advanced' } )
).toBeVisible();
expect( screen.getByText( 'Additional CSS' ) ).toBeVisible();
expect( screen.getByText( 'HTML anchor' ) ).toBeVisible();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,41 @@ vi.mock( import( '@wordpress/data' ), async ( importOriginal ) => {
} );

describe( 'useInspectorControlsTabs', () => {
it( 'includes Styles when Additional styles is the only group with controls', () => {
const AdditionalStylesFill = groups[ 'additional-styles' ].Fill;
const { result } = renderHook(
() => useInspectorControlsTabs( 'test/block', [], false, false ),
{
wrapper: ( { children }: { children: ReactNode } ) => (
<SlotFillProvider>
<AdditionalStylesFill>CSS</AdditionalStylesFill>
{ children }
</SlotFillProvider>
),
}
);

expect( result.current ).toEqual( [ TAB_STYLES ] );
} );

it( 'keeps Additional styles in Styles without adding Settings alongside List View', () => {
const AdditionalStylesFill = groups[ 'additional-styles' ].Fill;
const { result } = renderHook(
() => useInspectorControlsTabs( 'test/block', [], false, false ),
{
wrapper: ( { children }: { children: ReactNode } ) => (
<SlotFillProvider>
<groups.list.Fill>List View</groups.list.Fill>
<AdditionalStylesFill>CSS</AdditionalStylesFill>
{ children }
</SlotFillProvider>
),
}
);

expect( result.current ).toEqual( [ TAB_LIST_VIEW, TAB_STYLES ] );
} );

it( 'includes Settings when Allowed blocks is the only settings control', () => {
const { result } = renderHook(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function useInspectorControlsTabs(
) {
const tabs = [];
const {
'additional-styles': additionalStylesGroup,
bindings: bindingsGroup,
border: borderGroup,
color: colorGroup,
Expand All @@ -56,6 +57,7 @@ export default function useInspectorControlsTabs(
// Styles Tab: Add this tab if there are any fills for block supports
// e.g. border, color, spacing, typography, etc.
const styleFills = [
...( useSlotFills( additionalStylesGroup.name ) || [] ),
...( useSlotFills( borderGroup.name ) || [] ),
...( useSlotFills( colorGroup.name ) || [] ),
...( useSlotFills( layoutGroup.name ) || [] ),
Expand All @@ -67,6 +69,16 @@ export default function useInspectorControlsTabs(
];
const hasStyleFills = styleFills.length;

const { tabSettings, isPreviewMode } = useSelect( ( select ) => {
const settings = select( blockEditorStore ).getSettings();
return {
tabSettings: settings.blockInspectorTabs,
isPreviewMode: settings.isPreviewMode,
};
}, [] );

const hasStylesTab = ! isPreviewMode && ( hasBlockStyles || hasStyleFills );

// Settings Tab: If we don't have multiple tabs to display
// (i.e. both list view and styles), check only the default
// InspectorControls slots. If we have multiple tabs, we'll need to check
Expand Down Expand Up @@ -106,15 +118,7 @@ export default function useInspectorControlsTabs(
tabs.push( TAB_SETTINGS );
}

const { tabSettings, isPreviewMode } = useSelect( ( select ) => {
const settings = select( blockEditorStore ).getSettings();
return {
tabSettings: settings.blockInspectorTabs,
isPreviewMode: settings.isPreviewMode,
};
}, [] );

if ( ! isPreviewMode && ( hasBlockStyles || hasStyleFills ) ) {
if ( hasStylesTab ) {
Comment thread
talldan marked this conversation as resolved.
tabs.push( TAB_STYLES );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { createSlotFill } from '@wordpress/components';

const InspectorControlsDefault = createSlotFill( 'InspectorControls' );
const InspectorControlsAdvanced = createSlotFill( 'InspectorAdvancedControls' );
const InspectorControlsAdditionalStyles = createSlotFill(
'InspectorControlsAdditionalStyles'
);
const InspectorControlsBindings = createSlotFill( 'InspectorControlsBindings' );
const InspectorControlsBackground = createSlotFill(
'InspectorControlsBackground'
Expand All @@ -27,6 +30,7 @@ const InspectorControlsContent = createSlotFill( 'InspectorControlsContent' );
const groups = {
default: InspectorControlsDefault,
advanced: InspectorControlsAdvanced,
'additional-styles': InspectorControlsAdditionalStyles,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we document group="additional-styles" and update the inspector tab mapping?

Looks like the current docs still place custom CSS classes under Advanced and don't mention the new group.

background: InspectorControlsBackground,
bindings: InspectorControlsBindings,
border: InspectorControlsBorder,
Expand Down
4 changes: 2 additions & 2 deletions packages/block-editor/src/hooks/custom-class-name.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ function CustomClassNameControlsPure( { className, setAttributes } ) {
}

return (
<InspectorControls group="advanced">
<InspectorControls group="additional-styles">
<TextControl
autoComplete="off"
label={ __( 'Additional CSS class(es)' ) }
label={ __( 'CSS class(es)' ) }
value={ className || '' }
onChange={ ( nextValue ) => {
setAttributes( {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-editor/src/hooks/custom-css.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function CustomCSSControl( { blockName, setAttributes, style } ) {
);

return (
<InspectorControls group="advanced">
<InspectorControls group="additional-styles">
<AdvancedPanel
value={ style }
onChange={ onChange }
Expand Down
Loading
Loading