Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Global Styles: mark customized blocks with a dot rather than a summary
Reviewers preferred the dot: from the block list the question is which
blocks have been customized, not what changed inside each one, and the
summary added noise without answering that faster.

Drop the summary and the getGlobalStylesChangelist export it needed. The
filter, the empty states and the rest of the screen are unchanged.
  • Loading branch information
ramonjd committed Aug 18, 2026
commit b582168c44da789963688489da156387e424cecc
4 changes: 0 additions & 4 deletions packages/global-styles-engine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

## Unreleased

### Enhancements

- Export `getGlobalStylesChangelist`, which returns the changed styles as translated labels grouped by type ([#81373](https://github.com/WordPress/gutenberg/pull/81373)).

## 1.20.0 (2026-08-12)

### Bug Fixes
Expand Down
5 changes: 1 addition & 4 deletions packages/global-styles-engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ export { default as getPalettes } from './settings/get-palette';
// Utilities
export { areGlobalStylesEqual } from './core/equal';
export { mergeGlobalStyles } from './core/merge';
export {
default as getGlobalStylesChanges,
getGlobalStylesChangelist,
} from './utils/get-global-styles-changes';
export { default as getGlobalStylesChanges } from './utils/get-global-styles-changes';

// Core rendering
export { generateGlobalStyles } from './core/render';
Expand Down
2 changes: 1 addition & 1 deletion packages/global-styles-ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### Enhancements

- Expose typography and color controls for citations, inputs, and selects in Global Styles ([#80852](https://github.com/WordPress/gutenberg/pull/80852)).
- Summarize the styles a user changed on each block in the block list, and add a filter to show only the blocks they have changed ([#81373](https://github.com/WordPress/gutenberg/pull/81373)).
- Mark blocks that have user styles in the block list, and add a filter to show only those blocks ([#81373](https://github.com/WordPress/gutenberg/pull/81373)).

## 1.20.0 (2026-08-12)

Expand Down
136 changes: 29 additions & 107 deletions packages/global-styles-ui/src/screen-block-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
__experimentalHStack as HStack,
__experimentalText as WCText,
} from '@wordpress/components';
import { VisuallyHidden } from '@wordpress/ui';
import { useSelect } from '@wordpress/data';
import {
useState,
Expand All @@ -18,10 +19,7 @@ import {
useDeferredValue,
memo,
} from '@wordpress/element';
import {
getGlobalStylesChangelist,
type GlobalStylesConfig,
} from '@wordpress/global-styles-engine';
import type { GlobalStylesConfig } from '@wordpress/global-styles-engine';
import {
BlockIcon,
privateApis as blockEditorPrivateApis,
Expand Down Expand Up @@ -97,74 +95,6 @@ export function hasUserStylesForBlock(
);
}

interface BlockStyle {
name: string;
label?: string;
}

/**
* A short summary of what the user changed on a block, e.g.
* "Typography, Colors, Plain variation".
*
* A changed style variation is named rather than described: whatever was
* changed inside it, it contributes one "{Label} variation" entry.
*
* Returns an empty string when nothing can be named: a block changed only
* through its custom CSS counts as customized but has nothing to show.
*
* @param user The user's global styles config.
* @param blockName The block to summarize, e.g. `core/quote`.
* @param registeredStyles The block's registered style variations, used to turn
* a variation's slug into its label.
* @return The summary, or an empty string.
*/
export function getUserStylesSummary(
user: GlobalStylesConfig | undefined,
blockName: string,
registeredStyles: BlockStyle[] = []
): string {
const blockStyles = user?.styles?.blocks?.[ blockName ];
// Compare this block's own entry against nothing, so the changelist reports
// the block's categories rather than the whole config's. `variations` is not
// one of the keys it inspects, so it never reports them here.
const changes = getGlobalStylesChangelist(
{
styles: blockStyles,
settings: user?.settings?.blocks?.[ blockName ],
},
{}
);
const entries = [ ...new Set( changes.map( ( [ , label ] ) => label ) ) ];

// Name each changed variation instead of describing what changed in it.
Object.entries( blockStyles?.variations ?? {} ).forEach(
( [ slug, variationStyles ] ) => {
if ( ! hasAnyValue( variationStyles ) ) {
return;
}
const label =
registeredStyles.find( ( style ) => style.name === slug )
?.label || slug;
entries.push(
sprintf(
/* translators: %s: the name of a block style variation, e.g. "Plain". */
__( '%s variation' ),
label
)
);
}
);

if ( ! entries.length ) {
return '';
}

return entries.join(
/* translators: Used between list items, there is a space after the comma. */
__( ', ' ) // eslint-disable-line @wordpress/i18n-no-flanking-whitespace
);
}

type StyleFilter = 'all' | 'customized';

function useSortedBlockTypes() {
Expand Down Expand Up @@ -211,10 +141,10 @@ export function useBlockHasGlobalStyles( blockName: string ) {

interface BlockMenuItemProps {
block: any;
summary: string;
isCustomized: boolean;
}

function BlockMenuItem( { block, summary }: BlockMenuItemProps ) {
function BlockMenuItem( { block, isCustomized }: BlockMenuItemProps ) {
const hasBlockMenuItem = useBlockHasGlobalStyles( block.name );

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.

Not for now, but potentially a refactor idea: this currently places the check of whether or not to render within BlockMenuItem rather than further up the hierarchy where we show an empty state. So, it's theoretically possible (but unlikely) to have a situation where the list renders completely empty (because every item in the list returns false for this check) rather than show the empty state text.

So, at some point, we might want the check to occur at the same place where we do the filtering. Just a thought for later, nothing blocking for now!

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.

Good point. Hoisting might change a few files, so I'll do it a follow up. 👍🏻

if ( ! hasBlockMenuItem ) {
return null;
Expand All @@ -224,23 +154,23 @@ function BlockMenuItem( { block, summary }: BlockMenuItemProps ) {
<NavigationButtonAsItem
path={ '/blocks/' + encodeURIComponent( block.name ) }
>
<HStack
justify="flex-start"
alignment={ !! summary ? 'flex-start' : 'center' }
spacing={ 2 }
>
<HStack justify="flex-start" spacing={ 2 }>
<BlockIcon
className="global-styles-ui-block-types-item__icon"
icon={ block.icon }
/>
<FlexItem>
{ block.title }
{ !! summary && (
<span className="global-styles-ui-block-types-item__summary">
{ summary }
</span>
) }
</FlexItem>
<FlexItem>{ block.title }</FlexItem>
{ isCustomized && (
<>
<VisuallyHidden>
{ __( 'Has custom styles' ) }
</VisuallyHidden>
<span
aria-hidden="true"
className="global-styles-ui-block-types-item__indicator"
/>
</>
) }
</HStack>
</NavigationButtonAsItem>
);
Expand Down Expand Up @@ -278,32 +208,24 @@ interface BlockListProps {
function BlockList( { filterValue, styleFilter }: BlockListProps ) {
const sortedBlockTypes = useSortedBlockTypes();
const debouncedSpeak = useDebounce( speak, 500 );
const { isMatchingSearchTerm, getBlockStyles } = useSelect( blocksStore );
const { isMatchingSearchTerm } = useSelect( blocksStore );
const { user } = useContext( GlobalStylesContext );

// Computed once for the whole list rather than per row, so the list does not
// open a context subscription for every registered block. Maps a customized
// block's name to its summary, which can be an empty string.
const customizedBlocks = useMemo( () => {
const summaries = new Map< string, string >();
const blockNames = new Set( [
// Computed once for the whole list rather than per row, so the list does
// not open a context subscription for every registered block.
const customizedBlockNames = useMemo( () => {
const names = new Set< string >();
const blockNames = [
...Object.keys( user?.styles?.blocks ?? {} ),
...Object.keys( user?.settings?.blocks ?? {} ),
] );
];
blockNames.forEach( ( blockName ) => {
if ( hasUserStylesForBlock( user, blockName ) ) {
summaries.set(
blockName,
getUserStylesSummary(
user,
blockName,
getBlockStyles( blockName )
)
);
names.add( blockName );
}
} );
return summaries;
}, [ user, getBlockStyles ] );
return names;
}, [ user ] );

const searchedBlockTypes = ! filterValue
? sortedBlockTypes
Expand All @@ -314,7 +236,7 @@ function BlockList( { filterValue, styleFilter }: BlockListProps ) {
const filteredBlockTypes =
styleFilter === 'customized'
? searchedBlockTypes.filter( ( blockType ) =>
customizedBlocks.has( blockType.name )
customizedBlockNames.has( blockType.name )
)
: searchedBlockTypes;

Expand Down Expand Up @@ -358,7 +280,7 @@ function BlockList( { filterValue, styleFilter }: BlockListProps ) {
filteredBlockTypes.map( ( block ) => (
<BlockMenuItem
block={ block }
summary={ customizedBlocks.get( block.name ) ?? '' }
isCustomized={ customizedBlockNames.has( block.name ) }
key={ 'menu-itemblock-' + block.name }
/>
) )
Expand Down
15 changes: 7 additions & 8 deletions packages/global-styles-ui/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,13 @@
padding-top: variables.$grid-unit-20;
}

&__summary {
color: colors.$gray-700;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
margin: variables.$grid-unit-05 0;
&__indicator {
background: var(--wp-admin-theme-color);
border-radius: 50%;
flex: none;
height: 6px;
margin-left: auto;
width: 6px;
}
}

Expand Down
Loading