Skip to content

Commit 7d44519

Browse files
Block editor: Honour background skip serialization in the editor
1 parent 0771c7a commit 7d44519

8 files changed

Lines changed: 222 additions & 0 deletions

File tree

‎packages/block-editor/CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### New Features
6+
7+
- Add `useBackgroundProps` and `getBackgroundClassesAndStyles`, which return the background support's classes and inline styles so a block that skips background serialization can apply them to an inner element. The editor now also honours `background.__experimentalSkipSerialization` ([#83943](https://github.com/WordPress/gutenberg/pull/83943)).
8+
59
### Enhancements
610

711
- Inserter: Open faster when many block types are registered ([#83446](https://github.com/WordPress/gutenberg/pull/83446)).

‎packages/block-editor/README.md‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,18 @@ _Related_
431431

432432
- <https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/font-sizes/README.md>
433433

434+
### getBackgroundClassesAndStyles
435+
436+
Provides the CSS class names and inline styles for a block's background support attributes.
437+
438+
_Parameters_
439+
440+
- _attributes_ `Object`: Block attributes.
441+
442+
_Returns_
443+
444+
- `Object`: Background block support derived CSS classes & styles.
445+
434446
### getColorClassName
435447

436448
Returns a class based on the context a color is being used and its slug.
@@ -1033,6 +1045,20 @@ _Related_
10331045

10341046
- <https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/url-popover/README.md>
10351047

1048+
### useBackgroundProps
1049+
1050+
Derives the background related props for a block from its background block support attributes.
1051+
1052+
Blocks should use this hook in edit components rather than `getBackgroundClassesAndStyles`, so it can resolve editor settings later, as `useBorderProps` and `useColorProps` do, without a new API.
1053+
1054+
_Parameters_
1055+
1056+
- _attributes_ `Object`: Block attributes.
1057+
1058+
_Returns_
1059+
1060+
- `Object`: ClassName & style props from background block support.
1061+
10361062
### useBlockBindingsUtils
10371063

10381064
Retrieves the existing utils needed to update the block `bindings` metadata. They can be used to create, modify, or remove connections from the existing block attributes.

‎packages/block-editor/src/hooks/background.jsx‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@ function useBlockProps( { name, style } ) {
9191
return;
9292
}
9393

94+
// An opted-in block applies the background, defaults included, itself.
95+
const skipSerialization = getBlockSupport( name, [
96+
BACKGROUND_SUPPORT_KEY,
97+
'__experimentalSkipSerialization',
98+
] );
99+
if (
100+
skipSerialization === true ||
101+
( Array.isArray( skipSerialization ) &&
102+
skipSerialization.includes( 'backgroundImage' ) )
103+
) {
104+
return;
105+
}
106+
94107
const backgroundStyles = setBackgroundStyleDefaults( style?.background );
95108

96109
if ( ! backgroundStyles ) {

‎packages/block-editor/src/hooks/index.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ createBlockSaveFilter( [
9191
] );
9292

9393
export { useCustomSides } from './dimensions';
94+
export {
95+
getBackgroundClassesAndStyles,
96+
useBackgroundProps,
97+
} from './use-background-props';
9498
export { getDimensionsClassesAndStyles } from './use-dimensions-props';
9599
export { useLayoutClasses, useLayoutStyles } from './layout';
96100
export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';

‎packages/block-editor/src/hooks/style.jsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@ const skipSerializationPathsEdit = {
604604
[ `${ SHADOW_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [
605605
SHADOW_SUPPORT_KEY,
606606
],
607+
[ `${ BACKGROUND_SUPPORT_KEY }.__experimentalSkipSerialization` ]: [
608+
BACKGROUND_SUPPORT_KEY,
609+
],
607610
};
608611

609612
/**
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { renderHook } from '@testing-library/react';
2+
import { describe, expect, it } from 'vitest';
3+
import {
4+
getBackgroundClassesAndStyles,
5+
useBackgroundProps,
6+
} from '../use-background-props';
7+
8+
const backgroundImage = {
9+
url: 'https://example.com/image.jpg',
10+
id: 123,
11+
source: 'file',
12+
};
13+
14+
describe( 'getBackgroundClassesAndStyles', () => {
15+
it( 'should return the class and styles for a background image', () => {
16+
expect(
17+
getBackgroundClassesAndStyles( {
18+
style: { background: { backgroundImage } },
19+
} )
20+
).toEqual( {
21+
className: 'has-background',
22+
style: {
23+
backgroundImage: "url( 'https://example.com/image.jpg' )",
24+
backgroundSize: 'cover',
25+
},
26+
} );
27+
} );
28+
29+
it( 'should return the class and styles for a gradient', () => {
30+
expect(
31+
getBackgroundClassesAndStyles( {
32+
style: {
33+
background: {
34+
gradient: 'linear-gradient(135deg, #000 0%, #fff 100%)',
35+
},
36+
},
37+
} )
38+
).toEqual( {
39+
className: 'has-background',
40+
style: {
41+
backgroundImage: 'linear-gradient(135deg, #000 0%, #fff 100%)',
42+
},
43+
} );
44+
} );
45+
46+
it( 'should layer the gradient over the background image', () => {
47+
expect(
48+
getBackgroundClassesAndStyles( {
49+
style: {
50+
background: {
51+
backgroundImage,
52+
backgroundSize: 'contain',
53+
gradient: 'linear-gradient(135deg, #000 0%, #fff 100%)',
54+
},
55+
},
56+
} )
57+
).toEqual( {
58+
className: 'has-background',
59+
style: {
60+
backgroundImage:
61+
"linear-gradient(135deg, #000 0%, #fff 100%), url( 'https://example.com/image.jpg' )",
62+
backgroundSize: 'contain',
63+
backgroundPosition: '50% 50%',
64+
},
65+
} );
66+
} );
67+
68+
it( 'should convert a preset gradient to a CSS custom property', () => {
69+
expect(
70+
getBackgroundClassesAndStyles( {
71+
style: {
72+
background: { gradient: 'var:preset|gradient|aurora' },
73+
},
74+
} ).style
75+
).toEqual( {
76+
backgroundImage: 'var(--wp--preset--gradient--aurora)',
77+
} );
78+
} );
79+
80+
it( 'should not add a class when the background is clipped to the text', () => {
81+
const { className, style } = getBackgroundClassesAndStyles( {
82+
style: {
83+
background: {
84+
gradient: 'var:preset|gradient|aurora',
85+
backgroundClip: 'text',
86+
},
87+
},
88+
} );
89+
expect( className ).toBeUndefined();
90+
expect( style.backgroundClip ).toBe( 'text' );
91+
} );
92+
93+
it( 'should return nothing for empty attributes', () => {
94+
expect( getBackgroundClassesAndStyles( {} ) ).toEqual( {
95+
className: undefined,
96+
style: {},
97+
} );
98+
} );
99+
} );
100+
101+
describe( 'useBackgroundProps', () => {
102+
it( 'should return the same props as getBackgroundClassesAndStyles', () => {
103+
const attributes = {
104+
style: {
105+
background: {
106+
backgroundImage,
107+
gradient: 'var:preset|gradient|aurora',
108+
},
109+
},
110+
};
111+
const { result } = renderHook( () => useBackgroundProps( attributes ) );
112+
expect( result.current ).toEqual(
113+
getBackgroundClassesAndStyles( attributes )
114+
);
115+
} );
116+
} );
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { getInlineStyles } from './style';
2+
import {
3+
getBackgroundImageClasses,
4+
setBackgroundStyleDefaults,
5+
} from './background';
6+
7+
// This utility is intended to assist where the serialization of the background
8+
// block support is being skipped for a block but the background related CSS
9+
// classes & styles still need to be generated so they can be applied to inner
10+
// elements.
11+
12+
/**
13+
* Provides the CSS class names and inline styles for a block's background
14+
* support attributes.
15+
*
16+
* @param {Object} attributes Block attributes.
17+
* @return {Object} Background block support derived CSS classes & styles.
18+
*/
19+
export function getBackgroundClassesAndStyles( attributes ) {
20+
const { style } = attributes;
21+
const backgroundStyles = style?.background || {};
22+
23+
// Mirrors gutenberg_render_background_support() in lib/block-supports/background.php.
24+
const className =
25+
'text' !== backgroundStyles.backgroundClip
26+
? getBackgroundImageClasses( style )
27+
: '';
28+
29+
return {
30+
className: className || undefined,
31+
style: getInlineStyles( {
32+
background: {
33+
...backgroundStyles,
34+
...setBackgroundStyleDefaults( backgroundStyles ),
35+
},
36+
} ),
37+
};
38+
}
39+
40+
/**
41+
* Derives the background related props for a block from its background block
42+
* support attributes.
43+
*
44+
* Blocks should use this hook in edit components rather than
45+
* `getBackgroundClassesAndStyles`, so it can resolve editor settings later,
46+
* as `useBorderProps` and `useColorProps` do, without a new API.
47+
*
48+
* @param {Object} attributes Block attributes.
49+
*
50+
* @return {Object} ClassName & style props from background block support.
51+
*/
52+
export function useBackgroundProps( attributes ) {
53+
return getBackgroundClassesAndStyles( attributes );
54+
}

‎packages/block-editor/src/index.js‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import './hooks';
22
export {
3+
getBackgroundClassesAndStyles,
4+
useBackgroundProps,
35
getBorderClassesAndStyles as __experimentalGetBorderClassesAndStyles,
46
useBorderProps as __experimentalUseBorderProps,
57
getColorClassesAndStyles as __experimentalGetColorClassesAndStyles,

0 commit comments

Comments
 (0)