Skip to content

Block Editor: Reflect inherited Global Styles values in block inspector controls#77894

Open
aaronrobertshaw wants to merge 39 commits into
trunkfrom
update/global-styles-in-inspector-controls
Open

Block Editor: Reflect inherited Global Styles values in block inspector controls#77894
aaronrobertshaw wants to merge 39 commits into
trunkfrom
update/global-styles-in-inspector-controls

Conversation

@aaronrobertshaw

@aaronrobertshaw aaronrobertshaw commented May 3, 2026

Copy link
Copy Markdown
Contributor

Closes: #77595

What?

Inspector controls now reflect the Global Styles values a block inherits, so the panels line up closer to what you actually see on the block in the canvas.

  • No local value with inherited value:
    • the control shows the inherited value at rest via a placeholder, preselected option, or resolved value, depending on the control
    • it will have a dotted underline on the label to mark it as inherited
  • Local value over an inherited one:
    • an override indicator appears on the label as a small blue dot
    • the blue dot turns into a Reset to inherited value button on hover/focus
    • clicking the blue dot reset button clears the local override (a single undo) to fall back to the inherited value
  • No inherited value:
    • no override indicator will show, it only appears when there's an inherited value to override
    • normal control and panel reset behaviour has been kept

Inherited global styles values only come from the merged Global Styles data:

  • theme.json
  • user global styles edits
  • the block type global styles
  • a block style variation applied directly to the block

There are no computed styles involved, so custom CSS, enqueued stylesheets, and ancestor variations still can't be reflected even though they paint the canvas.

Scoped to an MVP

To land the core of this in 7.1 without first having to extend heavily-used @wordpress/components (like BaseControl) to accept injected label nodes and settle the related design and portal questions that come with it. Two things are deliberately out of scope here and moved to follow-ups:

  • The portalled label adornment and the "inherited from…" path tooltip. Marking where a value is inherited from needs an adornment in side the control label, but neither BaseControl nor InputControl exposes one today. Rather than push that public-API change through now, this PR keeps only the dotted underline at rest and moves the portaled adornment + path tooltip to a follow-up, where the approach and design can be settled properly.
  • Pushing an individual block style up to Global Styles. The design direction from the issue (#77595 / #49278) is now its own feature in #79839. This is still hopeful for 7.1, just tracked separately.

Why?

Right now a control only reflects what's set on the block, never what it inherits.

A Paragraph block renders with the theme's colour, size, and padding on the canvas while the controls sit empty, reading as "unset" when they're anything but. You can't tell a local override apart from an inherited value.

It's a long-standing rough edge (#37752, #43082, #49278), tracked under #77595.

How?

  • A single function, buildInheritedValue, merges the value a block inherits in precedence order; theme.json/user defaults ‹ block type ‹ applied block style variation. It's pure: all value resolution ({ ref } envelopes and theme-file image links) happens here.
  • The block support hooks (background, border, dimensions, duotone, typography, elements) read the Global Styles data via useInheritedValue, resolve the cascade for the selected block, and pass the result to the shared inspector panels as a prop.
  • The panels stay presentational. They render the value at rest, mark the control as inherited or overridden, and wire up the reset. They have no store access, so they remain liftable out of block-editor.
  • 0 is preserved, inherited values aren't saved until a user picks them, and reset stays a single undo.
  • The inherited underline and the override dot/reset render inline as label siblings, no portal.
  • The canvas is untouched. Rendering still relies on the normal CSS cascade, so this is display-only.

Architecture

The flow is a straight line from the store to the control:

  1. Block support hooks (background, border, dimensions, duotone, typography, elements) own the wiring for each control group. Through useInheritedValue, they read the merged Global Styles data (and theme-file links) from the store in a single useSelect, then call build InheritedValue to resolve the Root ‹ Block ‹ Variation cascade for the selected block, dropping root-level values that don't actually cascade to it (e.g. a root background).
  2. That resolved set of inherited styles is passed into the shared inspector panels as a prop.
  3. The panels' controls use it to reflect the values currently applied to the block, inherited or local, and to indicate when a value is inherited (and, in the follow-up, show a tooltip with the inheritance breadcrumb).

So store access lives only in the hooks, cascade resolution lives only in the pure function, and the panels stay presentational. No data dependency and liftable out of block-editor.

APIs

  • No new public APIs on this PR or the follow-up. A public API change would only be needed if we had to extend @wordpress/components (e.g. BaseControl) to wrap control labels in tooltips. This PR doesn't need that, and the follow-up avoids it too by portaling the adornment instead. Neither branch touches @wordpress/components.
  • useInheritedValue and buildInheritedValue are internal to block-editor, not re-exported from the package entry or privateApis.
  • The only change to the existing (already private) panels is one optional, backwards-compatible prop, showInheritanceLabelIndicators, which flags whether the inheritance labels and indicators should be shown. The inheritedValue prop is pre-existing.

Notes

Testing Instructions

Inherited values

  1. Select a block styled through Global Styles and open the inspector.
  2. Confirm controls across Typography, Background, Elements, Dimensions, Border, and Filters show the inherited values at rest, each with the dotted-underline label, and that they match the canvas.
  3. Check it holds for both preset values (colour slugs, font-size presets) and raw values.

Local overrides

  1. Set a local value on an inherited control and confirm the blue override dot appears on the label.
  2. Hover or focus the dot: it becomes a Reset to inherited value button. Activate it, the local value clears, the control falls back to the inherited value, and a single undo brings it back.

Edge cases

  1. Confirm a 0 value is treated as a real value, not an empty one.
  2. Confirm a plain local value with no inherited value behind it uses the normal panel reset, with no override dot.

Example theme.json

To help with defining global style values to check different controls the following theme.json might be of use. It is a modified version of the emptytheme theme.json, so applying this there and switching to emptytheme is a quick way to get up and running.

Example theme.json
{
	"$schema": "../../schemas/json/theme.json",
	"version": 3,
	"settings": {
		"appearanceTools": true,
		"typography": {
			"writingMode": true,
			"fontFamilies": [
				{
					"slug": "georgia",
					"name": "Georgia",
					"fontFamily": "Georgia, 'Times New Roman', serif"
				},
				{
					"slug": "system",
					"name": "System",
					"fontFamily": "system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif"
				}
			]
		},
		"layout": {
			"contentSize": "840px",
			"wideSize": "1100px"
		}
	},
	"styles": {
		"blocks": {
			"core/paragraph": {
				"color": {
					"text": "#1e1e1e",
					"background": "#f6f7f7",
					"gradient": "linear-gradient(135deg, #fdfbfb 0%, #ebedee 100%)"
				},
				"typography": {
					"fontFamily": "var:preset|font-family|georgia",
					"fontSize": "1.125rem",
					"fontStyle": "italic",
					"fontWeight": "600",
					"lineHeight": "1.7",
					"letterSpacing": "0.01em",
					"textAlign": "justify",
					"textColumns": "2",
					"textDecoration": "underline",
					"textIndent": "1.5em",
					"textTransform": "capitalize"
				},
				"spacing": {
					"margin": {
						"top": "0",
						"right": "0",
						"bottom": "1.5rem",
						"left": "0"
					},
					"padding": {
						"top": "0.5rem",
						"right": "1rem",
						"bottom": "0.5rem",
						"left": "1rem"
					}
				},
				"border": {
					"color": "#e0e0e0",
					"style": "solid",
					"width": "1px",
					"radius": "4px"
				},
				"elements": {
					"link": {
						"color": {
							"text": "#0073aa"
						},
						":hover": {
							"color": {
								"text": "#005177"
							}
						}
					}
				}
			},
			"core/group": {
				"background": {
					"backgroundImage": {
						"url": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScyMDAnIGhlaWdodD0nMjAwJz48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9J2cnIHgxPScwJyB5MT0nMCcgeDI9JzEnIHkyPScxJz48c3RvcCBvZmZzZXQ9JzAnIHN0b3AtY29sb3I9JyNjOWU3ZmYnLz48c3RvcCBvZmZzZXQ9JzAuNScgc3RvcC1jb2xvcj0nI2VhZTRmZicvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nI2ZmZDZlOCcvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHdpZHRoPScyMDAnIGhlaWdodD0nMjAwJyBmaWxsPSd1cmwoI2cpJy8+PGNpcmNsZSBjeD0nNjAnIGN5PSc3MCcgcj0nMjgnIGZpbGw9JyNmZmZmZmYnIG9wYWNpdHk9JzAuMzUnLz48Y2lyY2xlIGN4PScxNTAnIGN5PScxNDAnIHI9JzQwJyBmaWxsPScjZmZmZmZmJyBvcGFjaXR5PScwLjI1Jy8+PC9zdmc+"
					},
					"backgroundSize": "cover",
					"backgroundPosition": "center center",
					"backgroundRepeat": "no-repeat",
					"backgroundAttachment": "fixed"
				},
				"color": {
					"text": "#1e1e1e",
					"background": "#ffffff",
					"gradient": "linear-gradient(135deg, #f6f7f7 0%, #e5f0f5 100%)"
				},
				"typography": {
					"fontFamily": "var:preset|font-family|system",
					"fontSize": "1rem",
					"fontStyle": "italic",
					"fontWeight": "500",
					"lineHeight": "1.6",
					"letterSpacing": "0.02em",
					"textDecoration": "underline",
					"textTransform": "uppercase"
				},
				"spacing": {
					"blockGap": "1.5rem",
					"margin": {
						"top": "2rem",
						"bottom": "2rem"
					},
					"padding": {
						"top": "2rem",
						"right": "2rem",
						"bottom": "2rem",
						"left": "2rem"
					}
				},
				"dimensions": {
					"minHeight": "120px",
					"minWidth": "200px"
				},
				"border": {
					"color": "#d5d5d5",
					"style": "solid",
					"width": "1px",
					"radius": "8px"
				},
				"elements": {
					"heading": {
						"color": {
							"text": "#0a1e2e"
						},
						"typography": {
							"fontWeight": "700",
							"lineHeight": "1.2"
						}
					},
					"button": {
						"color": {
							"text": "#ffffff",
							"background": "#0073aa"
						},
						"border": {
							"radius": "4px"
						},
						":hover": {
							"color": {
								"background": "#005177"
							}
						}
					},
					"link": {
						"color": {
							"text": "#0073aa"
						},
						":hover": {
							"color": {
								"text": "#005177"
							}
						}
					}
				}
			}
		}
	},
	"customTemplates": [
		{
			"name": "custom-template",
			"title": "Custom",
			"postTypes": [ "post" ]
		}
	],
	"patterns": [ "short-text-surrounded-by-round-images", "partner-logos" ]
}

@aaronrobertshaw aaronrobertshaw self-assigned this May 3, 2026
@github-actions github-actions Bot added [Package] Components /packages/components [Package] Block editor /packages/block-editor labels May 3, 2026
@aaronrobertshaw aaronrobertshaw added [Type] Enhancement A suggestion for improvement. Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi and removed [Package] Components /packages/components labels May 3, 2026
@github-actions github-actions Bot added the [Package] Components /packages/components label May 3, 2026
@ramonjd

ramonjd commented May 4, 2026

Copy link
Copy Markdown
Member

I've given this a very quick test run and I really like that it's focussed on fixing the most immediate trust problem: the canvas shows a styled block, but the inspector controls say "empty".

The tooltips and reset button make it clear about where the styles come from too

Screenshot 2026-05-04 at 12 18 23 pm Screenshot 2026-05-04 at 12 26 11 pm

Styles can come from anywhere, e.g., computed CSS, cascades, custom CSS, plugin styles etc etc, and it can get messy pretty quickly so in my mind, communicating this block-theme specific relationship (which is the only one we can really control) is important.

One question I had was whether "Inherited from Global Styles" feels helpful enough without saying "element", "block", or "variation". But now I think that's getting into the weeds.

Fundamentally, I want to know if this block is using the global value, what happens when I change it locally (now it is overriding), and how I can reset it back to the default inheritance. So I think you've covered the basic here in my opinion.

Nice work and thanks for getting a POC up for folks to play around with.

@aaronrobertshaw

Copy link
Copy Markdown
Contributor Author

Thanks for the early feedback @ramonjd, appreciate it 🙇

One question I had was whether "Inherited from Global Styles" feels helpful enough without saying "element", "block", or "variation". But now I think that's getting into the weeds.

This is on the cards to investigate but ensuring we can accurately trace where the inheritance comes from and then also pass that data along to the tooltip being injected into the DOM was another. So I left that to follow-up iterations that I'm in the process of exploring.

@p-jackson p-jackson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I was playing around with this and noticed how, the underlined/purple text now appears everywhere. It's the default state to have your style inherited from somewhere.

Image

What's good about the bullet icon for overridden styles

Image

is that the default shows nothing special, and it's the override that changes up the UI. This inverts that. Now the default behaviour looks special and the override looks less special. You could just have a tooltip and no visual style change, but then it becomes very hard to discover.

What I'm imagining is that if the hit box for the tooltip was much bigger, like the entire panel was a hitbox, then any hover over the panel would show the detailed info.

Image

This works with a mouse which isn't ideal. The panels which have a click which expands another side panel are better for showing extra info.

Image

I'm sure you have plenty of UI proposals to choose from :)

Comment thread docs/reference-guides/block-api/block-supports.md Outdated
helper returns `{ className, title }` to spread onto the wrapping
`ToolsPanelItem` (or another wrapping element). The class hook drives the
label-level visual treatment described above; the `title` attribute carries
the i18n string `__( 'Inherited from Global Styles' )` for native browser

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The tooltip says things other than "Inherited from Global Styles" too, so I think just needs updated to "e.g. Inherited from ..."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I missed going back over all this when I iterated on the PoC adding the style breadcrumbs to the tooltip.

@aaronrobertshaw

aaronrobertshaw commented May 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks so much for the thoughtful review and feedbacjk @p-jackson 🙇

I was playing around with this and noticed how, the underlined/purple text now appears everywhere. It's the default state to have your style inherited from somewhere.

For the controls highlighted, you're right there are values inherited, in this case the theme's theme.json file acting as the base for Global Styles. So the purple and underlined labels are "correct" in that regard.

Whether it is "too much", that is a question I might direct to @jameskoster and his expertise. For now it is inline with the original design issue and recent feedback.

What I'm imagining is that if the hit box for the tooltip was much bigger, like the entire panel was a hitbox, then any hover over the panel would show the detailed info.

Initially, I looked at something like this too but wrapping more than the label meant that the tooltip there swallowed all tooltips on subcomponents which are as or more important to end users. So I deliberately kept the scope for this narrow.

@jameskoster

Copy link
Copy Markdown
Contributor

Perhaps the underline could be more subtle (text-decoration-thickness, text-decoration-color)? With the underline applied we might also try without the purple accent—it's doing the same job as the underline but not as accessibly.

@aaronrobertshaw

Copy link
Copy Markdown
Contributor Author

I've iterated further here and fix a few bugs too.

Here's a quick glimpse:

Screen.Recording.2026-05-08.at.10.57.24.pm.mp4

And here is how controls look without the purple color for reflecting inherited global styles (current PR state):

Screenshot 2026-05-08 at 11 28 40 pm

@aaronrobertshaw aaronrobertshaw force-pushed the update/global-styles-in-inspector-controls branch from 9bfb3d7 to 9313738 Compare May 8, 2026 15:30
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown

Size Change: +11.4 kB (+0.15%)

Total Size: 7.73 MB

📦 View Changed
Filename Size Change
build/scripts/block-editor/index.min.js 426 kB +4.52 kB (+1.07%)
build/scripts/block-library/index.min.js 353 kB +2.18 kB (+0.62%)
build/scripts/edit-site/index.min.js 304 kB +1.25 kB (+0.41%)
build/scripts/editor/index.min.js 498 kB +1.11 kB (+0.22%)
build/styles/block-editor/style-rtl.css 20 kB +653 B (+3.38%)
build/styles/block-editor/style-rtl.min.css 17 kB +534 B (+3.24%)
build/styles/block-editor/style.css 20 kB +643 B (+3.32%)
build/styles/block-editor/style.min.css 17 kB +536 B (+3.25%)

compressed-size-action

@aaronrobertshaw

Copy link
Copy Markdown
Contributor Author

Quick update:

I'll be away for a little while but I'll address any feedback collected over the next two weeks as well as the failing tests when i'm back.

It is worth keeping in mind this is a proof of concept at this stage and the code and approach hasn't yet been polished to a production ready state. That said, please don't be shy in leaving feedback, especially on the design and UX side of things.

@jameskoster

Copy link
Copy Markdown
Contributor

I think I'd lean toward omitting the purple colorisation (we can easily add it back later if the underline proves inadequate). Not a strong feeling though.

@aaronrobertshaw

Copy link
Copy Markdown
Contributor Author

Thanks for the continued design direction here. I'll address the current feedback in the next couple of days once I wrangle the new wave of conflicts after other recent global styles projects landed.

@aaronrobertshaw

Copy link
Copy Markdown
Contributor Author

It's been a while coming but I think I have this successfully rebased onto trunk. The state-based / responsive styling work that landed on trunk reshaped basically every panel and hook this PR touches, so just about all of the old code was in conflict.

As this PR stands now, the inherited global styles display has been relayed and updated on top of trunk and the state/responsive styles feature. A few notes:

  • Inherited value lookup is now state-aware
  • Didn't touch the per-state CSS rendering
  • Found and fixed a regression on gradient clearing

Unit and e2es are green locally but treat this as an updated PoC. With as much conflict as the previous working version had, this needs proper manual testing to confirm the inherited value UX actually makes sense across every panel and every state.

I'll continue to give this some testing and polish before flagging for review in the near future.

@aaronrobertshaw aaronrobertshaw force-pushed the update/global-styles-in-inspector-controls branch from 68fda90 to 1f96f54 Compare June 9, 2026 01:38
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

Flaky tests detected in 4e4ff76.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/29065169599
📝 Reported issues:

…ilder

Make the inherited-value builder the single source of truth for the
inspector's display of inherited Global Styles — it now holds the full
Root › Block › Variation cascade plus all resolution, so the panels stay
pure UI and the canvas stays on trunk.

- Builder: drop non-cascading root leaves (background, spacing, dimensions,
  border, shadow, filter, colour background/gradient) from value and sources
  together, and resolve theme-file `_links` image pointers inline. Typography,
  `color.text` and the `elements` passthrough still cascade.
- Close the dimensions gap — root minHeight/minWidth/aspectRatio are
  non-cascading and are now dropped like the other groups.
- Revert the background/style canvas `useBlockProps` to trunk: the merged
  value is display-only, and the CSS cascade already renders inherited styles.
- Panels: remove the in-panel `useSelect`/`getResolvedValue` and the
  `dropRootSourced`/`isRootSourced` filtering; `inheritedValue` now arrives
  fully resolved and cascade-correct.
- Remove the now-dead `root-source` module and canvas glue
  (`useInheritedStyleValue`, `getEffectiveBackgroundStyle`,
  `mergeInheritedBackgroundStyle`).
Replace the per-panel InheritedValueProvider / context / bridge chain
with one arg-taking `useInheritedValue( blockName, className, selectedState )`
hook. Each inspector wrapper now calls it directly and passes the resolved
value to the shared panel as props, so the panels stay presentational and
the store access stays in the wrapper where it already lived.

The context indirection deduped nothing (one consumer per Provider), so
removing it shrinks the wiring and drops InheritedValueProvider,
InheritedValueContext and useOwnVariation from the private API surface —
they are consumed only within block-editor. The only remaining private-API
addition is the backwards-compatible showInheritanceLabelIndicators prop.

Tests retargeted from Provider-mounting to the hook contract; the
subscription-dedup test (only reachable by nesting probes under one
Provider, which production never does) is removed.
Assert the inherited-styles feature through stable, user-facing signals
instead of brittle CSS class hooks.

- Query the reset affordance by its accessible role and name rather than
  the `.has-local-override-from-global-styles` class.
- Drop the `.is-inherited-from-global-styles` node-access assertions and the
  helpers that wrapped them, along with the now-unused eslint-disable
  directives for testing-library node access.
- Keep every behavioural assertion: value shown at rest, local override
  wins, display without commit, zero preserved, single-undo reset.
- Add coverage of the background image reset button via its accessible name.

The inherited-at-rest state has no accessible representation yet, so that
coverage is deferred to the accessibility pass that follows the label
adornment decision.
…olvedStyles

Behaviour-preserving readability refactor of the block-editor global styles
cascade builder:

- Rename buildInheritedValue -> resolveStyles, computeInheritedValue ->
  computeResolvedStyles, and useInheritedValue -> useResolvedStyles, updating
  the six inspector hook consumers and tests.
- De-abbreviate internal variable names (sVal, v, gs, acc, obj).
- Cull/condense comments: drop trivial JSDoc on self-evident helpers, keep and
  condense the domain 'why' notes and the public-entry JSDoc.

The { value, sources } output shape and the inheritedValue/inheritedSources
prop wiring are unchanged.
…nt-backed blocks

Element-backed blocks (core/button, core/heading) are painted on the canvas
by Global Styles element rules (e.g. .wp-element-button), but the inherited-
value builder only folded the block-scoped layers, so their inspector controls
read as empty while the canvas was styled.

Resolve the matching root-level styles.elements[ element ] layer as a block
contribution at root < element < block-type < variation precedence, mirroring
the same folding in the pseudo/viewport state pass. Block-type styles override
root element styles per the agreed inspector model.

Scoped to core/button and core/heading for now; other element-backed blocks
can follow up.
The builder's public entry point was renamed to resolveStyles/useResolvedStyles,
so align the filenames. Uses git mv to preserve history and keep rebases clean.

- build-inherited-value.js -> resolve-styles.js
- test/build-inherited-value.js -> test/resolve-styles.js

Updates the import in inherited-value-context.js and a doc comment in the
typography-panel test.
…trol is present

The visible Border label was gated on showInheritanceLabelIndicators, so it disappeared in Global Styles (which passes showInheritanceLabelIndicators={ false }). Widen the gate to also render when a Shadow control is present, matching trunk's hideLabelFromVision={ ! hasShadowControl } and the symmetric Shadow label guard.
…g is set

The panel passed placeholder={ undefined } to LineHeightControl when there was no local or inherited value, which clobbered the control's own BASE_DEFAULT_VALUE (1.5) placeholder (spread via ...otherProps). Conditionally spread the placeholder prop so it is only supplied when an inherited value is being surfaced, letting the built-in default apply otherwise.
The Content width and Wide width UnitControls passed the full inherited value (with unit) as the placeholder, duplicating the control's unit selector, and used value={ local ?? '' } so the inherited value only ever showed greyed-out. Align them with the Minimum height/width pattern: render the inherited value with unit as the control value at rest and use getNumericPlaceholder for a numeric-only placeholder. Values are still only written to local on user change.
… set

ColorGradientTab passed the inherited preset's slug to ColorPalette unconditionally. Since ColorPalette selects strictly by selectedSlug when set, the inherited preset swatch stayed highlighted even after the user chose a local custom colour. Only pass inheritedSlug while displaying the inherited value (placeholder mode); otherwise pass undefined so selection falls back to matching the displayed colour value.
deepMergeDroppingEmpties recursed into every plain object, so a higher-precedence layer's background.backgroundImage was merged key-by-key onto a lower layer's, mixing fields (e.g. one layer's url with another's id) into an invalid value. Add an ATOMIC_OBJECT_KEYS exception so backgroundImage is replaced wholesale (shallow-cloned to keep the merged tree fresh), mirroring the backgroundImage exception in the Global Styles engine's mergeGlobalStyles. Add focused tests.
… merge

getValueFromObjectPath does not resolve nested refs, so a resolved envelope could itself be a { ref } object (an invalid, unresolved pointer) and slip through into the merged value. Add an isRefObject( resolved ) guard to the skip block, matching getResolvedRefValue in the Global Styles engine.
Each of the six block-support panels wraps the shared raw Global Styles payload in its own { styles } object, and resolveStyles memoized on that wrapper's identity, so the full cascade merge recomputed once per consumer on every block selection. Key the resolveStyles memo on the raw styles payload (a single stable reference already shared by every consumer) instead of the throwaway wrapper, so all consumers collapse to one merge per selection.
Align the dimensions and typography panel tests with the review fixes: the inherited layout content/wide widths now render as the control value with a numeric-only placeholder (matching the Minimum height/width pattern), and the line-height control restores its BASE_DEFAULT_VALUE (1.5) placeholder when no inherited value is surfaced. Update the assertions that still encoded the pre-fix placeholder-only behaviour.
…rols

The block inspector now renders the global-styles Typography/Dimensions
panels with resolved inherited values, which changed the Button block's
inspector behaviour and broke three e2e tests:

- 'can apply named colors': the link-color sync only fired when the
  inherited text and link colors matched. A fresh button inherits a text
  color but no link color, so the sync was skipped. Sync when the
  inherited link color is unset, only skipping when a distinct link color
  was explicitly set.
- 'can apply custom colors': the color control now carries an inherited
  value, so the 'Custom color picker' swatch's accessible name gains a
  '. The currently selected color is…' suffix. Match by substring.
- 'can resize width': the Font Size control now opens in custom mode and
  renders a 'Select unit' combobox above the Width control, so the
  panel-wide '.first()' matched the wrong control. Scope the lookup to
  the Width group.
Rename `resolveStyles` to the singular `resolveStyle` and move the pure
cascade resolver from `block-editor` into `@wordpress/global-styles-engine`,
exposed via the engine's private API. The `useResolvedStyle` hook stays in
`block-editor` and owns all store access.

Also relocate `getVariationStylesWithRefValues` into the engine so
`resolveStyle` resolves the applied block style variation internally from its
slug. This collapses the earlier interim signature (a separate pre-resolved
`variationStyles` argument plus a slug used only for memoization) into a single
`ownVariation` argument, keeping the engine self-contained. `block-editor`
consumers (`block-style-variation`, `switch-section-style`) now unlock the
helper from the engine.

Relocated modules are authored in TypeScript to match engine conventions, and
their unit tests move alongside them.
@aaronrobertshaw aaronrobertshaw force-pushed the update/global-styles-in-inspector-controls branch from 40dd5f6 to 6997026 Compare July 16, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Design Tools Tools that impact the appearance of blocks both to expand the number of tools and improve the experi Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json [Package] Block editor /packages/block-editor [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Block Styles: Display inherited Global Styles and own Block Style Variation styles in Block Inspector

9 participants