Repository navigation
Block Supports: Add background-clip block support UI - #77142
Conversation
|
Size Change: +2.69 kB (+0.03%) Total Size: 7.74 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in 4b983eb. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24131694168
|
808bdf6 to
d2984bc
Compare
d2984bc to
0c5ea30
Compare
4b983eb to
6bad087
Compare
🤖 PR meta 🤖🎉 PropsIf you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Updated as activity occurs, without notifying anyone named here. Add the 📦 Bundle sizeSize Change: +3.94 kB (+0.05%) Total Size: 8.52 MB 📦 View Changed
⚡ PerformanceShow the resultsClient side metrics exclude the server response time. front-end-block-theme
front-end-classic-theme
media-processing
media-upload
post-editor
site-editor
🏁 Flaky testsSome 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. shifts a cursor placed with arrow keys after a remote insert before it in
|
6bad087 to
4c44c80
Compare
0c5ea30 to
ac0c708
Compare
370440d to
f6cf50b
Compare
ac0c708 to
3896f1b
Compare
f6cf50b to
f2c9373
Compare
3896f1b to
5116af7
Compare
f2c9373 to
a22c727
Compare
a22c727 to
24d310d
Compare
5116af7 to
bb67612
Compare
24d310d to
8254683
Compare
Design asked for fewer words. "The gradient" rather than "The text gradient" also keeps the first notice off a typographic widow. The second suggestion ended "replacing any color or image", which is not what happens: a gradient and an image are layers of `background-image`, and a background color sits under both, so the clip takes in all three rather than replacing any of them. One word changes, and the length is the same. `Notice` from `@wordpress/components` is now flagged in favour of the `@wordpress/ui` one, so all three notices in these panels use it and the suppression the Typography panel carried for its own notice is pruned.
The two panels explained the same two rules in their own words. Each rule now lives in the panel that acts on it, with a cross reference from the other, and the same for the paired-selector note in the SCSS. The `settingAllowsTextClip` block drops the part the settings table in the block supports doc now carries. `BackgroundClipControl` had tests in two files. The three that render it directly move to its own suite, which leaves the Background panel suite testing the panel. Two fixes alongside: the style engine's new constant sat between `BLOCK_STYLE_DEFINITIONS_METADATA` and its docblock, so that docblock read as documentation for the wrong constant; and the Global Styles block screen rebuilt `styleState` on every render.
A rebase appended a second `background` key beside the one trunk added, so the later one won and quietly replaced trunk's default controls. `backgroundClip` now joins trunk's key, which keeps its defaults.
`hooks/typography.jsx` put the gradient back whenever the style arriving from the panel carried no text clip, which is true both when the panel never owned the gradient and when it has just cleared its own. Clearing a text gradient therefore turned it into a background gradient. It now compares against the clip the block had, so only a gradient this panel never owned is restored.
The control selected the first allowed value when the block had none, and called it the CSS initial value. It is only `border-box` when the theme allows `border-box`, so a theme offering `[ "padding-box", "text" ]` had the control reporting a clip the block was not using. Nothing set is now its own option, as it is for font appearance and font family, and choosing it clears the value.
Both controls were hidden at a viewport state, on the grounds that the clip is not emitted in a media query. It is: state styles compile through the style engine and are wrapped in the breakpoint's query, so a clip set there applies at that width and nowhere else. Hiding them left no way to escape a text gradient at one breakpoint. Both controls now appear, reading the Default state's value until the state sets its own, and clearing a text gradient writes `border-box`, which is the CSS initial value, because the Default state's declarations are not in a media query and would otherwise keep applying. That leaves nothing for the `styleState` prop to do, so it goes, along with the plumbing that reached the panels from the two hooks and the Global Styles block screen.
A state's declarations sit in a media query or a selector of their own, but the styles underneath do not, so they keep applying until the state says otherwise. Two cases were left looking broken. Escaping the clip with a box value restored the text, but the gradient underneath carried on painting as a block background. Setting only a text color did nothing at all, because the clip above fills the glyphs with `transparent`, which is what a reviewer filmed. Both generators now take the styles a state layers over: the Default state for a viewport or a pseudo state, and both merged for a pseudo state inside a viewport. A state that escapes the clip without painting its own background clears the inherited image, and a text color set without a clip of its own gets the fill back. Verified in a browser on the front end, where the gradient now stops at the breakpoint and a color set there is painted.
The canvas preview of a pseudo state was the one path into the state CSS that received no base style, so a state previewed on canvas under a text clip did not get the escape the front end gives it. The fill reset fired for a state that sets a text color alongside its own gradient. The inherited clip fills the text with that gradient, so `currentColor` painted over it. Both rules now share one check for a state painting its own background. The `Default` clip option had no swatch rule, so it drew the one above it and read as `Border box`.
`ALL_BACKGROUND_CLIP_VALUES` re-exported `VALID_BACKGROUND_CLIP_VALUES` under a second name, with a comment explaining the rename. The panel takes the style engine's constant directly. A comment above `settings` still described the `styleState` prop, which is gone. Two others restated the line below them, and one explained how this pull request arrived at the code rather than what the code does.
A state's declarations sit in a media query or a selector of their own, but the styles it layers over do not, so a state that escapes a text clip has to clear the gradient underneath, and a text colour set under a clip has to get its fill back. Both already happened for a block's own state styles and neither happened in Global Styles, so clearing a text gradient at a breakpoint there left the Default state's gradient painting every block's whole box, and a text colour set at a breakpoint was never painted. All either rule needs from the layers below is the clip still applying. In PHP a node's path carries one key per state, so dropping those keys from the innermost outward walks those layers. In the JS renderer each state node is built from its parent, which hands the clip down directly. Style variations are the exception on both sides: a variation layers over its block, which is a different relationship, so its states read the variation's clip and then the block's.
The notice says the Default state's gradient replaces the text colour, which was true while a colour set at a breakpoint was never painted. It is painted now: the state gets its fill back on both surfaces, so the colour wins and the notice has nothing left to warn about.
… review findings The picker marked a text gradient's swatch as selected in Global Styles, so clicking it dropped the gradient and kept the clip, hiding the text. The Typography notice now covers a background image, both panels share one clip helper, and the state base styles lookup is a plain loop.
getSerializedBackgroundClasses rebuilt the background style without backgroundClip, so the text clip check in getBackgroundImageClasses never saw it and the editor added has-background to a text gradient.
The rebase kept both trunk's background object and the branch's copy in block.json. Parsers keep the last key, so the duplicate went unnoticed.
A background colour on a block that clips its background to the text is clipped to the letters too, so there is no box to pad. The colour support still added has-background, which brought the theme's background padding. Skip it in the editor and on the front end, matching the background support.
A text gradient makes the letters transparent, so a text colour set on the block instance, on selected text or on the block's links was hidden when the gradient came from Global Styles. A shared rule makes the letters solid again wherever a text colour class is set. The :root prefix beats Global Styles, while a block instance's own gradient is inline and still wins. No saved markup changes, so existing content is covered.
…ext gradient A text colour set on a block instance at a breakpoint or hover state only filled the letters again when the block's own default styles held the text gradient. A gradient from Global Styles kept the colour hidden, while the same colour set for all widths showed. The fill reset now applies whenever such a state sets a text colour without its own clip or background. It does nothing when no text clip applies, and is limited to blocks that support the background clip so other blocks' state output is unchanged.
Mirror of the PHP colors support, which only treats a color as clipped to the text when the block supports backgroundClip.
f6fe1f7 to
53a9775
Compare
|
Follow-up issue created as promised: |
Backport: WordPress/wordpress-develop#13491
What?
Adds the editor UI for the
background.backgroundClipsupport: a text gradient for Heading and Paragraph, and a Clip control for themes that want the box values.Part of #30982 and #76525. Builds on #77141, now merged. Supersedes #76171.
Why?
A text gradient is a gradient clipped to the text, so it is stored as
background.gradientplusbackground.backgroundCliprather than as a support of its own. The Typography panel offers the friendly version, the Background panel owns the raw clip.background-clipclips every background layer at once, the colour and the image included. Nothing is disabled because of it. Every control stays usable and the panels explain what is happening, which also keeps the colour control reachable in forced-colour modes that drop backgrounds.How?
backgroundClip: text.Defaultis one of its options, for a block with no clip of its own.textvalue too. The Background Gradient control never shows a text gradient as its own value, so it can't clear one by accident.lib/block-supports/states.php, so the editor and the front end agree.gradientattribute or incolor.gradientis a background too. Setting a text gradient replaces it, including clearing the preset attribute, which would otherwise paint the whole block through thebackgroundshorthand and reset the clip.-webkit-text-fill-color: transparentmeans the colour it would report on is not the one painted.backgroundClip. Paragraph also gainsbackgroundImage,backgroundSizeandgradient, with its image and gradient controls behind the panel menu. Heading keeps its existing defaults.background.gradientswitches on an existing migration. A paragraph holding a custom gradient instyle.color.gradienthas it rewritten tostyle.background.gradientonce someone edits the Background panel, withhas-backgroundkept. Saved markup is untouched until then and stays valid.@wordpress/uiNotice, like the new notices beside it. That keeps one Notice component in the file and removes its lint suppression.What the theme setting allows
settings.background.backgroundCliptrue[ "text" ][ "border-box", "padding-box" ]falseBlock support only stands in on the first row, because
backgroundCliphas no default in core'stheme.json. Everywhere else the theme decides, which is how a theme turns a text gradient off on a block that opts in.Known limitation
A gradient stored the legacy way, in
color.gradient, renders as thebackgroundshorthand inline on the block. That shorthand resetsbackground-clip, so a text gradient set in Global Styles leaves those blocks with transparent text over their old gradient. Fixing it means either changing whatcolor.gradientemits, which is the breaking change thatbackground.gradientexists to avoid, or migrating the stored value, which needs each post opened and saved. Editing the block's background migrates it today. Retiringcolor.gradientis worth its own issue.Testing Instructions
Text gradient
has-backgroundclass.<!-- wp:paragraph {"gradient":"vivid-cyan-blue-to-vivid-purple"} -->.Resetting
Responsive states
Global Styles
Clip control
"settings": { "background": { "backgroundClip": true } }to a block theme, then give a Heading a background gradient, generous padding and a thick dashed border.Browsers
background-clip,-webkit-background-clipand-webkit-text-fill-color.Screenshots or screencast
Text gradient
1-text-gradient.mp4
Overriding a background
2-overriding-a-background.mp4
Resetting
6-reset-flows.mp4
Responsive states
3-responsive-states.mp4
Global Styles
4-global-styles.mp4
Clip control
5-clip-control.mp4
The gradient presets in these recordings come from a demo-only mu-plugin, since Twenty Twenty-Five ships none. They are not part of this PR.
Use of AI Tools
Claude Code was used to port this work from the earlier PR, rewrite the UI onto the current panels, record the demos and draft this description.