diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md
index 7dabc36971ff68..2f36590f52fec4 100644
--- a/packages/block-editor/CHANGELOG.md
+++ b/packages/block-editor/CHANGELOG.md
@@ -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
diff --git a/packages/block-editor/src/components/block-inspector/index.jsx b/packages/block-editor/src/components/block-inspector/index.jsx
index faf41677e5bda0..19c236c1d20981 100644
--- a/packages/block-editor/src/components/block-inspector/index.jsx
+++ b/packages/block-editor/src/components/block-inspector/index.jsx
@@ -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';
@@ -82,6 +83,9 @@ function StyleInspectorSlots( {
) }
{ showAdvancedControls && (
+ { /* There are no tabs to divide the advanced tools
+ between, so each appears as its own panel. */ }
+
) }
diff --git a/packages/block-editor/src/components/block-inspector/style.scss b/packages/block-editor/src/components/block-inspector/style.scss
index 109a10cb312e8d..cd0a2bccd37d1c 100644
--- a/packages/block-editor/src/components/block-inspector/style.scss
+++ b/packages/block-editor/src/components/block-inspector/style.scss
@@ -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,
diff --git a/packages/block-editor/src/components/global-styles/advanced-panel.jsx b/packages/block-editor/src/components/global-styles/advanced-panel.jsx
index 6c55d26e715d13..e67e0050aa4e07 100644
--- a/packages/block-editor/src/components/global-styles/advanced-panel.jsx
+++ b/packages/block-editor/src/components/global-styles/advanced-panel.jsx
@@ -92,7 +92,7 @@ export default function AdvancedPanel( {
) }
handleOnChange( newValue ) }
onBlur={ handleOnBlur }
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/additional-styles-panel.jsx b/packages/block-editor/src/components/inspector-controls-tabs/additional-styles-panel.jsx
new file mode 100644
index 00000000000000..6a441f8433ea32
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/additional-styles-panel.jsx
@@ -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 (
+
+
+
+ );
+};
+
+export default AdditionalStyles;
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.jsx b/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.jsx
index 7dfd6930e8c24a..f192f4130bb748 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.jsx
+++ b/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.jsx
@@ -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(
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/index.jsx b/packages/block-editor/src/components/inspector-controls-tabs/index.jsx
index c0d15b7d3cfd0d..ac6868756290ec 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/index.jsx
+++ b/packages/block-editor/src/components/inspector-controls-tabs/index.jsx
@@ -203,6 +203,7 @@ export default function InspectorControlsTabs( {
hasBlockStyles={ hasBlockStyles }
isSectionBlock={ isSectionBlock }
contentClientIds={ contentClientIds }
+ showAdditionalStyles={ !! blockName }
/>
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.jsx b/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.jsx
index ccd99f6837de60..e9e239d911c21e 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.jsx
+++ b/packages/block-editor/src/components/inspector-controls-tabs/styles-tab.jsx
@@ -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';
@@ -101,6 +102,7 @@ const StylesTab = ( {
hasBlockStyles,
isSectionBlock,
contentClientIds,
+ showAdditionalStyles = false,
} ) => {
return (
<>
@@ -156,6 +158,13 @@ const StylesTab = ( {
>
) }
+ { /* Section blocks are excluded from the panels above but still
+ expose additional styling tools such as Additional CSS. */ }
+ { showAdditionalStyles && (
+
+ ) }
>
);
};
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/test/advanced-panels.jsdom.test.tsx b/packages/block-editor/src/components/inspector-controls-tabs/test/advanced-panels.jsdom.test.tsx
new file mode 100644
index 00000000000000..4d29c4a8eb50e5
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls-tabs/test/advanced-panels.jsdom.test.tsx
@@ -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(
+
+
+
+ );
+
+ expect(
+ screen.queryByRole( 'button', { name: 'Advanced' } )
+ ).not.toBeInTheDocument();
+ } );
+
+ it( 'renders the advanced group fills', () => {
+ render(
+
+
+ HTML anchor
+
+
+
+ );
+
+ 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(
+
+
+ Additional CSS
+
+
+
+ );
+
+ expect(
+ screen.queryByRole( 'button', { name: 'Advanced' } )
+ ).not.toBeInTheDocument();
+ } );
+} );
+
+describe( 'AdditionalStyles', () => {
+ it( 'renders nothing when the additional-styles group has no fills', () => {
+ render(
+
+
+
+ );
+
+ expect(
+ screen.queryByRole( 'button', { name: 'Additional styles' } )
+ ).not.toBeInTheDocument();
+ } );
+
+ it( 'renders the additional-styles group fills', () => {
+ render(
+
+
+ Additional CSS
+
+
+
+ );
+
+ 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(
+
+
+ HTML anchor
+
+
+ Additional CSS
+
+
+
+
+ );
+
+ 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();
+ } );
+} );
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/test/use-inspector-controls-tabs.jsdom.test.tsx b/packages/block-editor/src/components/inspector-controls-tabs/test/use-inspector-controls-tabs.jsdom.test.tsx
index 2daf9805201ff0..2f16bd85f1de9d 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/test/use-inspector-controls-tabs.jsdom.test.tsx
+++ b/packages/block-editor/src/components/inspector-controls-tabs/test/use-inspector-controls-tabs.jsdom.test.tsx
@@ -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 } ) => (
+
+ CSS
+ { children }
+
+ ),
+ }
+ );
+
+ 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 } ) => (
+
+ List View
+ CSS
+ { children }
+
+ ),
+ }
+ );
+
+ expect( result.current ).toEqual( [ TAB_LIST_VIEW, TAB_STYLES ] );
+ } );
+
it( 'includes Settings when Allowed blocks is the only settings control', () => {
const { result } = renderHook(
() =>
diff --git a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
index 8ee421f14ecf04..7607ea113cc4f6 100644
--- a/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
+++ b/packages/block-editor/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js
@@ -31,6 +31,7 @@ export default function useInspectorControlsTabs(
) {
const tabs = [];
const {
+ 'additional-styles': additionalStylesGroup,
bindings: bindingsGroup,
border: borderGroup,
color: colorGroup,
@@ -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 ) || [] ),
@@ -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
@@ -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 ) {
tabs.push( TAB_STYLES );
}
diff --git a/packages/block-editor/src/components/inspector-controls/groups.js b/packages/block-editor/src/components/inspector-controls/groups.js
index 9dbdc41607a460..4d893924993728 100644
--- a/packages/block-editor/src/components/inspector-controls/groups.js
+++ b/packages/block-editor/src/components/inspector-controls/groups.js
@@ -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'
@@ -27,6 +30,7 @@ const InspectorControlsContent = createSlotFill( 'InspectorControlsContent' );
const groups = {
default: InspectorControlsDefault,
advanced: InspectorControlsAdvanced,
+ 'additional-styles': InspectorControlsAdditionalStyles,
background: InspectorControlsBackground,
bindings: InspectorControlsBindings,
border: InspectorControlsBorder,
diff --git a/packages/block-editor/src/hooks/custom-class-name.jsx b/packages/block-editor/src/hooks/custom-class-name.jsx
index db636379ec87f8..b016bccabd9ce0 100644
--- a/packages/block-editor/src/hooks/custom-class-name.jsx
+++ b/packages/block-editor/src/hooks/custom-class-name.jsx
@@ -34,10 +34,10 @@ function CustomClassNameControlsPure( { className, setAttributes } ) {
}
return (
-
+
{
setAttributes( {
diff --git a/packages/block-editor/src/hooks/custom-css.jsx b/packages/block-editor/src/hooks/custom-css.jsx
index 0cebf5bdc5654e..6aea23f4e73531 100644
--- a/packages/block-editor/src/hooks/custom-css.jsx
+++ b/packages/block-editor/src/hooks/custom-css.jsx
@@ -52,7 +52,7 @@ function CustomCSSControl( { blockName, setAttributes, style } ) {
);
return (
-
+
{
- it( 'should remove nested keys', () => {
- expect( cleanEmptyObject( { color: { text: undefined } } ) ).toEqual(
- undefined
- );
- } );
-
- it( 'should remove partial nested keys', () => {
- expect(
- cleanEmptyObject( {
- color: { text: undefined },
- typography: { fontSize: '10px' },
- } )
- ).toEqual( {
- typography: { fontSize: '10px' },
- } );
- } );
-
- it( 'should not remove falsy nested keys', () => {
- expect( cleanEmptyObject( { color: { text: false } } ) ).not.toEqual(
- undefined
- );
- expect( cleanEmptyObject( { color: { text: '' } } ) ).not.toEqual(
- undefined
- );
- } );
-} );
diff --git a/packages/block-editor/src/hooks/test/utils.jsdom.test.tsx b/packages/block-editor/src/hooks/test/utils.jsdom.test.tsx
index 9b92ee293f3cf4..3e223f2ab06445 100644
--- a/packages/block-editor/src/hooks/test/utils.jsdom.test.tsx
+++ b/packages/block-editor/src/hooks/test/utils.jsdom.test.tsx
@@ -2,13 +2,41 @@ import { afterEach, describe, expect, it } from 'vitest';
import { render, screen } from '@testing-library/react';
import { applyFilters, removeFilter } from '@wordpress/hooks';
import type { ComponentType } from 'react';
-import { createBlockEditFilter } from '../utils';
+import { cleanEmptyObject, createBlockEditFilter } from '../utils';
import {
BlockEditContextProvider,
mayDisplayControlsKey,
mayDisplayPatternEditingControlsKey,
} from '../../components/block-edit/context';
+describe( 'cleanEmptyObject', () => {
+ it( 'removes nested keys', () => {
+ expect( cleanEmptyObject( { color: { text: undefined } } ) ).toEqual(
+ undefined
+ );
+ } );
+
+ it( 'removes partial nested keys', () => {
+ expect(
+ cleanEmptyObject( {
+ color: { text: undefined },
+ typography: { fontSize: '10px' },
+ } )
+ ).toEqual( {
+ typography: { fontSize: '10px' },
+ } );
+ } );
+
+ it( 'preserves falsy nested keys', () => {
+ expect( cleanEmptyObject( { color: { text: false } } ) ).not.toEqual(
+ undefined
+ );
+ expect( cleanEmptyObject( { color: { text: '' } } ) ).not.toEqual(
+ undefined
+ );
+ } );
+} );
+
describe( 'createBlockEditFilter', () => {
afterEach( () => {
removeFilter( 'editor.BlockEdit', 'core/editor/hooks' );
diff --git a/packages/block-editor/tsconfig.json b/packages/block-editor/tsconfig.json
index 82b202cbf76b14..d93e45e623779c 100644
--- a/packages/block-editor/tsconfig.json
+++ b/packages/block-editor/tsconfig.json
@@ -5,51 +5,128 @@
"types": []
},
"references": [
- { "path": "./tsconfig.build.json" },
- { "path": "../a11y/tsconfig.build.json" },
- { "path": "../block-serialization-default-parser" },
- { "path": "../blob/tsconfig.build.json" },
- { "path": "../blocks" },
- { "path": "../components/tsconfig.build.json" },
- { "path": "../compose/tsconfig.build.json" },
- { "path": "../data" },
- { "path": "../dataviews/tsconfig.build.json" },
- { "path": "../date" },
- { "path": "../deprecated/tsconfig.build.json" },
- { "path": "../dom" },
- { "path": "../element/tsconfig.build.json" },
- { "path": "../preferences/tsconfig.build.json" },
- { "path": "../global-styles-engine/tsconfig.build.json" },
- { "path": "../priority-queue/tsconfig.build.json" },
- { "path": "../private-apis" },
- { "path": "../hooks" },
- { "path": "../html-entities/tsconfig.build.json" },
- { "path": "../i18n/tsconfig.build.json" },
- { "path": "../icons/tsconfig.build.json" },
- { "path": "../image-cropper/tsconfig.build.json" },
- { "path": "../interactivity/tsconfig.build.json" },
- { "path": "../is-shallow-equal/tsconfig.build.json" },
- { "path": "../kebab-case" },
- { "path": "../keycodes/tsconfig.build.json" },
- { "path": "../keyboard-shortcuts" },
- { "path": "../notices/tsconfig.build.json" },
- { "path": "../rich-text" },
- { "path": "../style-engine" },
- { "path": "../token-list/tsconfig.build.json" },
- { "path": "../ui/tsconfig.build.json" },
- { "path": "../url" },
- { "path": "../upload-media/tsconfig.build.json" },
- { "path": "../warning" }
+ {
+ "path": "./tsconfig.build.json"
+ },
+ {
+ "path": "../a11y/tsconfig.build.json"
+ },
+ {
+ "path": "../block-serialization-default-parser"
+ },
+ {
+ "path": "../blob/tsconfig.build.json"
+ },
+ {
+ "path": "../blocks"
+ },
+ {
+ "path": "../components/tsconfig.build.json"
+ },
+ {
+ "path": "../compose/tsconfig.build.json"
+ },
+ {
+ "path": "../data"
+ },
+ {
+ "path": "../dataviews/tsconfig.build.json"
+ },
+ {
+ "path": "../date"
+ },
+ {
+ "path": "../deprecated/tsconfig.build.json"
+ },
+ {
+ "path": "../dom"
+ },
+ {
+ "path": "../element/tsconfig.build.json"
+ },
+ {
+ "path": "../preferences/tsconfig.build.json"
+ },
+ {
+ "path": "../global-styles-engine/tsconfig.build.json"
+ },
+ {
+ "path": "../priority-queue/tsconfig.build.json"
+ },
+ {
+ "path": "../private-apis"
+ },
+ {
+ "path": "../hooks"
+ },
+ {
+ "path": "../html-entities/tsconfig.build.json"
+ },
+ {
+ "path": "../i18n/tsconfig.build.json"
+ },
+ {
+ "path": "../icons/tsconfig.build.json"
+ },
+ {
+ "path": "../image-cropper/tsconfig.build.json"
+ },
+ {
+ "path": "../interactivity/tsconfig.build.json"
+ },
+ {
+ "path": "../is-shallow-equal/tsconfig.build.json"
+ },
+ {
+ "path": "../kebab-case"
+ },
+ {
+ "path": "../keycodes/tsconfig.build.json"
+ },
+ {
+ "path": "../keyboard-shortcuts"
+ },
+ {
+ "path": "../notices/tsconfig.build.json"
+ },
+ {
+ "path": "../rich-text"
+ },
+ {
+ "path": "../style-engine"
+ },
+ {
+ "path": "../token-list/tsconfig.build.json"
+ },
+ {
+ "path": "../ui/tsconfig.build.json"
+ },
+ {
+ "path": "../url"
+ },
+ {
+ "path": "../upload-media/tsconfig.build.json"
+ },
+ {
+ "path": "../warning"
+ }
],
/*
* These dev files import sources outside the build's TypeScript allowlist.
* TypeScript unit tests are checked separately by test:unit:conventions.
+ *
+ * Each excluded file imports a component the build allowlist does not
+ * type yet. A composite project has to resolve every relative import
+ * within its own program, so including one of these would mean adding
+ * the whole subgraph behind it. Drop an entry once the allowlist in
+ * `tsconfig.build.json` covers what it imports.
*/
"exclude": [
"**/benchmark",
"src/components/block-icon/stories/index.story.ts",
"src/components/contrast-checker/stories/index.story.ts",
"src/components/inspector-controls-tabs/test/use-inspector-controls-tabs.jsdom.test.tsx",
- "src/hooks/test/utils.jsdom.test.tsx"
+ "src/hooks/test/utils.jsdom.test.tsx",
+ "src/components/inspector-controls-tabs/test/advanced-panels.jsdom.test.tsx"
]
}
diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md
index 4c50ef714dd885..53522b189ad726 100644
--- a/packages/editor/CHANGELOG.md
+++ b/packages/editor/CHANGELOG.md
@@ -7,6 +7,7 @@
- `PostAuthor`: The field renders with the `SearchableSelect` component of `@wordpress/ui` instead of `ComboboxControl` and `SelectControl` ([#83323](https://github.com/WordPress/gutenberg/pull/83323)).
- `DocumentOutline`: Show the outline items' focus ring with the design system's outline instead of a legacy box-shadow ([#83755](https://github.com/WordPress/gutenberg/pull/83755)).
- Notes: Add a "Notes" submenu to the View group of the Options menu ([#83768](https://github.com/WordPress/gutenberg/pull/83768)).
+- Block inspector: Move the "Apply globally" control from the Advanced panel in the Settings tab to the new "Additional styles" panel in the Styles tab, by filling the `additional-styles` group ([#83753](https://github.com/WordPress/gutenberg/pull/83753)).
### Bug Fixes
diff --git a/packages/editor/src/hooks/push-changes-to-global-styles/index.jsx b/packages/editor/src/hooks/push-changes-to-global-styles/index.jsx
index 9a15c415984656..6a289d9212898c 100644
--- a/packages/editor/src/hooks/push-changes-to-global-styles/index.jsx
+++ b/packages/editor/src/hooks/push-changes-to-global-styles/index.jsx
@@ -1,7 +1,7 @@
import { addFilter } from '@wordpress/hooks';
import { createHigherOrderComponent } from '@wordpress/compose';
import {
- InspectorAdvancedControls,
+ InspectorControls,
store as blockEditorStore,
privateApis as blockEditorPrivateApis,
useBlockEditingMode,
@@ -556,9 +556,9 @@ function PushChangesToGlobalStyles( props ) {
}
return (
-
+
-
+
);
}
diff --git a/packages/format-library/src/link/inline.tsx b/packages/format-library/src/link/inline.tsx
index 17e348b691e120..4542cdf62df526 100644
--- a/packages/format-library/src/link/inline.tsx
+++ b/packages/format-library/src/link/inline.tsx
@@ -57,7 +57,7 @@ const LINK_SETTINGS = [
},
{
id: 'cssClasses',
- title: __( 'Additional CSS class(es)' ),
+ title: __( 'CSS class(es)' ),
render: (
setting: CSSClassesSettingProps[ 'setting' ],
value: CSSClassesSettingProps[ 'value' ],
diff --git a/packages/format-library/src/link/test/css-classes-setting.jsdom.test.jsx b/packages/format-library/src/link/test/css-classes-setting.jsdom.test.jsx
index b0230a2cb23705..7e78ea322b70a2 100644
--- a/packages/format-library/src/link/test/css-classes-setting.jsdom.test.jsx
+++ b/packages/format-library/src/link/test/css-classes-setting.jsdom.test.jsx
@@ -11,7 +11,7 @@ describe( 'CSSClassesSettingComponent', () => {
{} }
@@ -20,7 +20,7 @@ describe( 'CSSClassesSettingComponent', () => {
// Checkbox should be visible
const checkbox = screen.getByRole( 'checkbox', {
- name: 'Additional CSS class(es)',
+ name: 'CSS class(es)',
} );
expect( checkbox ).toBeVisible();
@@ -46,7 +46,7 @@ describe( 'CSSClassesSettingComponent', () => {
{
// Toggle on
const checkbox = screen.getByRole( 'checkbox', {
- name: 'Additional CSS class(es)',
+ name: 'CSS class(es)',
} );
// starts collapsed
expect( checkbox ).toHaveAttribute( 'aria-expanded', 'false' );
@@ -92,7 +92,7 @@ describe( 'CSSClassesSettingComponent', () => {
{
);
const checkbox = screen.getByRole( 'checkbox', {
- name: 'Additional CSS class(es)',
+ name: 'CSS class(es)',
} );
// Initially expanded and has aria-controls
diff --git a/packages/global-styles-ui/src/screen-block.tsx b/packages/global-styles-ui/src/screen-block.tsx
index a79df252b5d417..41fc407a196cf7 100644
--- a/packages/global-styles-ui/src/screen-block.tsx
+++ b/packages/global-styles-ui/src/screen-block.tsx
@@ -461,7 +461,10 @@ function ScreenBlock( {
) }
{ canEditCSS && (
-
+
{
await pageUtils.pressKeys( 'primary+k' );
await page.keyboard.type( 'custom CSS' );
await page.getByRole( 'option', { name: 'Open custom CSS' } ).click();
- await expect( page.getByLabel( 'Additional CSS' ) ).toBeVisible();
+ // Expect the CSS input to be present.
+ await expect( page.getByLabel( 'CSS' ) ).toBeVisible();
} );
test( 'Suggestions section shows contextual commands on open', async ( {
diff --git a/test/e2e/specs/site-editor/push-to-global-styles.spec.js b/test/e2e/specs/site-editor/push-to-global-styles.spec.js
index b9aa363bc00182..0950a8fad3fd7d 100644
--- a/test/e2e/specs/site-editor/push-to-global-styles.spec.js
+++ b/test/e2e/specs/site-editor/push-to-global-styles.spec.js
@@ -31,8 +31,8 @@ test.describe( 'Push to Global Styles button', () => {
}
/**
- * Adds a Heading block, opens its Advanced panel and turns on Letter case
- * so there's a change to push.
+ * Adds a Heading block, opens its Additional styles panel and turns on
+ * Letter case so there's a change to push.
*
* @param {Object} options Playwright fixtures.
* @param {Object} options.page Playwright page.
@@ -43,9 +43,9 @@ test.describe( 'Push to Global Styles button', () => {
await editor.insertBlock( { name: 'core/heading' } );
await page.keyboard.type( 'A heading' );
- // Go to block settings and open the Advanced panel.
+ // Go to block settings and open the Additional styles panel.
await editor.openDocumentSettingsSidebar();
- await page.getByRole( 'button', { name: 'Advanced' } ).click();
+ await page.getByRole( 'button', { name: 'Additional styles' } ).click();
// Push button should be disabled with no changes.
await expect(
diff --git a/tools/eslint/suppressions.json b/tools/eslint/suppressions.json
index de235b68813fbf..ef1ba312d35c4f 100644
--- a/tools/eslint/suppressions.json
+++ b/tools/eslint/suppressions.json
@@ -1514,6 +1514,11 @@
"count": 1
}
},
+ "packages/block-editor/src/components/inspector-controls-tabs/additional-styles-panel.jsx": {
+ "react/jsx-filename-extension": {
+ "count": 1
+ }
+ },
"packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.jsx": {
"react/jsx-filename-extension": {
"count": 1