@wordpress/block-editor 15.15.0 → 15.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-inspector/index.cjs +2 -1
  3. package/build/components/block-inspector/index.cjs.map +2 -2
  4. package/build/components/block-visibility/modal.cjs +2 -2
  5. package/build/components/block-visibility/modal.cjs.map +1 -1
  6. package/build/components/block-visibility/viewport-visibility-info.cjs +6 -1
  7. package/build/components/block-visibility/viewport-visibility-info.cjs.map +2 -2
  8. package/build/components/global-styles/background-panel.cjs +142 -33
  9. package/build/components/global-styles/background-panel.cjs.map +2 -2
  10. package/build/components/global-styles/color-panel.cjs +18 -7
  11. package/build/components/global-styles/color-panel.cjs.map +2 -2
  12. package/build/components/global-styles/hooks.cjs +8 -4
  13. package/build/components/global-styles/hooks.cjs.map +2 -2
  14. package/build/components/inspector-controls-tabs/styles-tab.cjs +2 -1
  15. package/build/components/inspector-controls-tabs/styles-tab.cjs.map +2 -2
  16. package/build/hooks/background.cjs +74 -21
  17. package/build/hooks/background.cjs.map +3 -3
  18. package/build/hooks/cross-origin-isolation.cjs +6 -6
  19. package/build/hooks/cross-origin-isolation.cjs.map +2 -2
  20. package/build/hooks/custom-css.cjs +5 -0
  21. package/build/hooks/custom-css.cjs.map +2 -2
  22. package/build/hooks/fit-text.cjs +46 -58
  23. package/build/hooks/fit-text.cjs.map +3 -3
  24. package/build/hooks/utils.cjs +5 -1
  25. package/build/hooks/utils.cjs.map +2 -2
  26. package/build/store/actions.cjs +8 -4
  27. package/build/store/actions.cjs.map +2 -2
  28. package/build/store/private-selectors.cjs +2 -2
  29. package/build/store/private-selectors.cjs.map +2 -2
  30. package/build/store/reducer.cjs +62 -95
  31. package/build/store/reducer.cjs.map +2 -2
  32. package/build/store/selectors.cjs +2 -2
  33. package/build/store/selectors.cjs.map +2 -2
  34. package/build-module/components/block-inspector/index.mjs +2 -1
  35. package/build-module/components/block-inspector/index.mjs.map +2 -2
  36. package/build-module/components/block-visibility/modal.mjs +2 -2
  37. package/build-module/components/block-visibility/modal.mjs.map +1 -1
  38. package/build-module/components/block-visibility/viewport-visibility-info.mjs +6 -1
  39. package/build-module/components/block-visibility/viewport-visibility-info.mjs.map +2 -2
  40. package/build-module/components/global-styles/background-panel.mjs +141 -34
  41. package/build-module/components/global-styles/background-panel.mjs.map +2 -2
  42. package/build-module/components/global-styles/color-panel.mjs +17 -7
  43. package/build-module/components/global-styles/color-panel.mjs.map +2 -2
  44. package/build-module/components/global-styles/hooks.mjs +8 -4
  45. package/build-module/components/global-styles/hooks.mjs.map +2 -2
  46. package/build-module/components/inspector-controls-tabs/styles-tab.mjs +2 -1
  47. package/build-module/components/inspector-controls-tabs/styles-tab.mjs.map +2 -2
  48. package/build-module/hooks/background.mjs +76 -22
  49. package/build-module/hooks/background.mjs.map +2 -2
  50. package/build-module/hooks/cross-origin-isolation.mjs +6 -6
  51. package/build-module/hooks/cross-origin-isolation.mjs.map +2 -2
  52. package/build-module/hooks/custom-css.mjs +5 -0
  53. package/build-module/hooks/custom-css.mjs.map +2 -2
  54. package/build-module/hooks/fit-text.mjs +46 -58
  55. package/build-module/hooks/fit-text.mjs.map +2 -2
  56. package/build-module/hooks/utils.mjs +5 -1
  57. package/build-module/hooks/utils.mjs.map +2 -2
  58. package/build-module/store/actions.mjs +8 -4
  59. package/build-module/store/actions.mjs.map +2 -2
  60. package/build-module/store/private-selectors.mjs +2 -2
  61. package/build-module/store/private-selectors.mjs.map +2 -2
  62. package/build-module/store/reducer.mjs +62 -94
  63. package/build-module/store/reducer.mjs.map +2 -2
  64. package/build-module/store/selectors.mjs +2 -2
  65. package/build-module/store/selectors.mjs.map +2 -2
  66. package/build-style/content-rtl.css +2 -2
  67. package/build-style/content.css +2 -2
  68. package/build-style/style-rtl.css +35 -7
  69. package/build-style/style.css +35 -7
  70. package/package.json +39 -39
  71. package/src/components/background-image-control/style.scss +0 -4
  72. package/src/components/block-inspector/index.js +1 -0
  73. package/src/components/block-visibility/viewport-visibility-info.js +8 -1
  74. package/src/components/fit-text-size-warning/style.scss +1 -5
  75. package/src/components/global-styles/background-panel.js +157 -11
  76. package/src/components/global-styles/color-panel.js +23 -7
  77. package/src/components/global-styles/hooks.js +12 -4
  78. package/src/components/global-styles/test/background-panel.js +44 -1
  79. package/src/components/inspector-controls-tabs/styles-tab.js +1 -0
  80. package/src/hooks/background.js +122 -21
  81. package/src/hooks/background.scss +45 -0
  82. package/src/hooks/cross-origin-isolation.js +6 -6
  83. package/src/hooks/custom-css.js +6 -0
  84. package/src/hooks/fit-text.js +73 -83
  85. package/src/hooks/test/cross-origin-isolation.js +7 -3
  86. package/src/hooks/utils.js +4 -0
  87. package/src/store/actions.js +9 -8
  88. package/src/store/private-selectors.js +2 -2
  89. package/src/store/reducer.js +84 -128
  90. package/src/store/selectors.js +2 -2
  91. package/src/store/test/private-selectors.js +67 -34
  92. package/src/store/test/reducer.js +436 -66
  93. package/src/store/test/selectors.js +81 -63
  94. package/src/style.scss +1 -0
@@ -2,7 +2,10 @@
2
2
  * Internal dependencies
3
3
  */
4
4
 
5
- import { hasBackgroundImageValue } from '../background-panel';
5
+ import {
6
+ hasBackgroundImageValue,
7
+ hasBackgroundGradientValue,
8
+ } from '../background-panel';
6
9
 
7
10
  describe( 'hasBackgroundImageValue', () => {
8
11
  it( 'should return `true` when id and url exist', () => {
@@ -37,3 +40,43 @@ describe( 'hasBackgroundImageValue', () => {
37
40
  ).toBe( false );
38
41
  } );
39
42
  } );
43
+
44
+ describe( 'hasBackgroundGradientValue', () => {
45
+ it( 'should return `true` when a gradient string is set', () => {
46
+ expect(
47
+ hasBackgroundGradientValue( {
48
+ background: {
49
+ gradient: 'linear-gradient(135deg, red 0%, blue 100%)',
50
+ },
51
+ } )
52
+ ).toBe( true );
53
+ } );
54
+
55
+ it( 'should return `true` for a preset slug reference', () => {
56
+ expect(
57
+ hasBackgroundGradientValue( {
58
+ background: { gradient: 'var:preset|gradient|vivid-cyan-blue' },
59
+ } )
60
+ ).toBe( true );
61
+ } );
62
+
63
+ it( 'should return `false` when gradient is undefined', () => {
64
+ expect( hasBackgroundGradientValue( { background: {} } ) ).toBe(
65
+ false
66
+ );
67
+ } );
68
+
69
+ it( 'should return `false` when gradient is an empty string', () => {
70
+ expect(
71
+ hasBackgroundGradientValue( { background: { gradient: '' } } )
72
+ ).toBe( false );
73
+ } );
74
+
75
+ it( 'should return `false` when background is undefined', () => {
76
+ expect( hasBackgroundGradientValue( {} ) ).toBe( false );
77
+ } );
78
+
79
+ it( 'should return `false` when style is undefined', () => {
80
+ expect( hasBackgroundGradientValue( undefined ) ).toBe( false );
81
+ } );
82
+ } );
@@ -88,6 +88,7 @@ const StylesTab = ( {
88
88
  <InspectorControls.Slot
89
89
  group="background"
90
90
  label={ __( 'Background image' ) }
91
+ className="background-block-support-panel__inner-wrapper"
91
92
  />
92
93
  <InspectorControls.Slot group="filter" />
93
94
  <InspectorControls.Slot
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -15,6 +20,7 @@ import {
15
20
  default as StylesBackgroundPanel,
16
21
  useHasBackgroundPanel,
17
22
  hasBackgroundImageValue,
23
+ hasBackgroundGradientValue,
18
24
  } from '../components/global-styles/background-panel';
19
25
  import { globalStylesDataKey } from '../store/private-keys';
20
26
 
@@ -45,7 +51,8 @@ export function hasBackgroundSupport( blockName, feature = 'any' ) {
45
51
  return (
46
52
  !! support?.backgroundImage ||
47
53
  !! support?.backgroundSize ||
48
- !! support?.backgroundRepeat
54
+ !! support?.backgroundRepeat ||
55
+ !! support?.gradient
49
56
  );
50
57
  }
51
58
 
@@ -107,19 +114,43 @@ function useBlockProps( { name, style } ) {
107
114
  * @return {string} CSS class name.
108
115
  */
109
116
  export function getBackgroundImageClasses( style ) {
110
- return hasBackgroundImageValue( style ) ? 'has-background' : '';
117
+ return hasBackgroundImageValue( style ) ||
118
+ hasBackgroundGradientValue( style )
119
+ ? 'has-background'
120
+ : '';
111
121
  }
112
122
 
113
- function BackgroundInspectorControl( { children } ) {
114
- const resetAllFilter = useCallback( ( attributes ) => {
115
- return {
116
- ...attributes,
117
- style: {
118
- ...attributes.style,
119
- background: undefined,
120
- },
121
- };
122
- }, [] );
123
+ function BackgroundInspectorControl( {
124
+ children,
125
+ backgroundGradientSupported = false,
126
+ } ) {
127
+ const resetAllFilter = useCallback(
128
+ ( attributes ) => {
129
+ const updatedClassName = attributes.className?.includes(
130
+ 'has-background'
131
+ )
132
+ ? attributes.className
133
+ .split( ' ' )
134
+ .filter( ( c ) => c !== 'has-background' )
135
+ .join( ' ' ) || undefined
136
+ : attributes.className;
137
+ return {
138
+ ...attributes,
139
+ className: updatedClassName,
140
+ style: cleanEmptyObject( {
141
+ ...attributes.style,
142
+ background: undefined,
143
+ color: backgroundGradientSupported
144
+ ? {
145
+ ...attributes.style?.color,
146
+ gradient: undefined,
147
+ }
148
+ : attributes.style?.color,
149
+ } ),
150
+ };
151
+ },
152
+ [ backgroundGradientSupported ]
153
+ );
123
154
  return (
124
155
  <InspectorControls group="background" resetAllFilter={ resetAllFilter }>
125
156
  { children }
@@ -133,13 +164,15 @@ export function BackgroundImagePanel( {
133
164
  setAttributes,
134
165
  settings,
135
166
  } ) {
136
- const { style, inheritedValue } = useSelect(
167
+ const { style, className, inheritedValue } = useSelect(
137
168
  ( select ) => {
138
169
  const { getBlockAttributes, getSettings } =
139
170
  select( blockEditorStore );
140
171
  const _settings = getSettings();
172
+ const blockAttributes = getBlockAttributes( clientId );
141
173
  return {
142
- style: getBlockAttributes( clientId )?.style,
174
+ style: blockAttributes?.style,
175
+ className: blockAttributes?.className,
143
176
  /*
144
177
  * To ensure we pass down the right inherited values:
145
178
  * @TODO 1. Pass inherited value down to all block style controls,
@@ -154,19 +187,87 @@ export function BackgroundImagePanel( {
154
187
  [ clientId, name ]
155
188
  );
156
189
 
190
+ const backgroundGradientSupported = hasBackgroundSupport(
191
+ name,
192
+ 'gradient'
193
+ );
194
+
195
+ // Must be declared before the early return to follow Rules of Hooks.
196
+ // Passes backgroundGradientSupported so that "Reset All" also clears
197
+ // the legacy color.gradient value when background.gradient is supported.
198
+ const as = useCallback(
199
+ ( { children } ) => (
200
+ <BackgroundInspectorControl
201
+ backgroundGradientSupported={ backgroundGradientSupported }
202
+ >
203
+ { children }
204
+ </BackgroundInspectorControl>
205
+ ),
206
+ [ backgroundGradientSupported ]
207
+ );
208
+
157
209
  if (
158
210
  ! useHasBackgroundPanel( settings ) ||
159
- ! hasBackgroundSupport( name, 'backgroundImage' )
211
+ ! hasBackgroundSupport( name )
160
212
  ) {
161
213
  return null;
162
214
  }
163
215
 
164
216
  const onChange = ( newStyle ) => {
165
- setAttributes( {
166
- style: cleanEmptyObject( newStyle ),
167
- } );
217
+ const isMigrating =
218
+ backgroundGradientSupported && !! style?.color?.gradient;
219
+ const newAttributes = {
220
+ style: cleanEmptyObject(
221
+ backgroundGradientSupported
222
+ ? {
223
+ ...newStyle,
224
+ color: {
225
+ ...newStyle?.color,
226
+ gradient: undefined,
227
+ },
228
+ }
229
+ : newStyle
230
+ ),
231
+ };
232
+
233
+ // When migrating from color.gradient to background.gradient, preserve
234
+ // the has-background class so existing styles relying on it (e.g.
235
+ // theme padding) are not silently broken. Only add the class when a
236
+ // gradient value is being set — not when it is being cleared/reset.
237
+ // Conversely, if the gradient is cleared and has-background was added
238
+ // during a previous migration, remove it so it does not linger.
239
+ if ( isMigrating && !! newStyle?.background?.gradient ) {
240
+ newAttributes.className = clsx( className, 'has-background' );
241
+ } else if (
242
+ ! newStyle?.background?.gradient &&
243
+ className?.includes( 'has-background' )
244
+ ) {
245
+ newAttributes.className =
246
+ className
247
+ .split( ' ' )
248
+ .filter( ( c ) => c !== 'has-background' )
249
+ .join( ' ' ) || undefined;
250
+ }
251
+
252
+ setAttributes( newAttributes );
168
253
  };
169
254
 
255
+ // When background.gradient is supported but not yet explicitly set, fall
256
+ // back to color.gradient for display. Any write from this panel migrates
257
+ // the value to background.gradient and clears color.gradient atomically.
258
+ const styleValue =
259
+ backgroundGradientSupported &&
260
+ ! style?.background?.gradient &&
261
+ style?.color?.gradient
262
+ ? {
263
+ ...style,
264
+ background: {
265
+ ...style?.background,
266
+ gradient: style?.color?.gradient,
267
+ },
268
+ }
269
+ : style;
270
+
170
271
  const updatedSettings = {
171
272
  ...settings,
172
273
  background: {
@@ -179,19 +280,19 @@ export function BackgroundImagePanel( {
179
280
 
180
281
  const defaultControls = getBlockSupport( name, [
181
282
  BACKGROUND_SUPPORT_KEY,
182
- 'defaultControls',
283
+ '__experimentalDefaultControls',
183
284
  ] );
184
285
 
185
286
  return (
186
287
  <StylesBackgroundPanel
187
288
  inheritedValue={ inheritedValue }
188
- as={ BackgroundInspectorControl }
289
+ as={ as }
189
290
  panelId={ clientId }
190
291
  defaultValues={ BACKGROUND_BLOCK_DEFAULT_VALUES }
191
292
  settings={ updatedSettings }
192
293
  onChange={ onChange }
193
294
  defaultControls={ defaultControls }
194
- value={ style }
295
+ value={ styleValue }
195
296
  />
196
297
  );
197
298
  }
@@ -0,0 +1,45 @@
1
+ @use "@wordpress/base-styles/variables" as *;
2
+ @use "@wordpress/base-styles/colors" as *;
3
+
4
+ /**
5
+ * ItemGroup-like border styles for the background panel's ToolsPanelItems.
6
+ * Replicates the separated border of the `ItemGroup` component while
7
+ * allowing for hidden placeholder items (same approach as the color panel).
8
+ */
9
+ .block-editor-background-panel__item {
10
+ padding: 0;
11
+ max-width: 100%;
12
+ position: relative;
13
+
14
+ // Border styles.
15
+ border-left: 1px solid $gray-300;
16
+ border-right: 1px solid $gray-300;
17
+ border-bottom: 1px solid $gray-300;
18
+
19
+ // Identify the first visible instance as placeholder items will not have this class.
20
+ &:nth-child(1 of &) {
21
+ border-top-left-radius: $radius-small;
22
+ border-top-right-radius: $radius-small;
23
+ border-top: 1px solid $gray-300;
24
+ }
25
+
26
+ // Identify the last visible instance as placeholder items will not have this class.
27
+ &:nth-last-child(1 of &) {
28
+ border-bottom-left-radius: $radius-small;
29
+ border-bottom-right-radius: $radius-small;
30
+ }
31
+
32
+ > div,
33
+ > div > button {
34
+ border-radius: inherit;
35
+ }
36
+ }
37
+
38
+ .background-block-support-panel {
39
+ /* Increased specificity required to remove the slot wrapper's row gap */
40
+ &#{&} {
41
+ .background-block-support-panel__inner-wrapper {
42
+ row-gap: 0;
43
+ }
44
+ }
45
+ }
@@ -27,14 +27,14 @@ if ( window.crossOriginIsolated ) {
27
27
  return;
28
28
  }
29
29
 
30
- el.querySelectorAll(
31
- 'img,source,script,video,link'
32
- ).forEach( ( v ) => {
33
- addCrossOriginAttribute( v );
34
- } );
30
+ el.querySelectorAll( 'source,script,video,link' ).forEach(
31
+ ( v ) => {
32
+ addCrossOriginAttribute( v );
33
+ }
34
+ );
35
35
 
36
36
  if (
37
- [ 'IMG', 'SOURCE', 'SCRIPT', 'VIDEO', 'LINK' ].includes(
37
+ [ 'SOURCE', 'SCRIPT', 'VIDEO', 'LINK' ].includes(
38
38
  el.nodeName
39
39
  )
40
40
  ) {
@@ -7,6 +7,7 @@ import { useInstanceId } from '@wordpress/compose';
7
7
  import { getBlockType, hasBlockSupport } from '@wordpress/blocks';
8
8
  import { __, sprintf } from '@wordpress/i18n';
9
9
  import { processCSSNesting } from '@wordpress/global-styles-engine';
10
+ import { useBlockEditingMode } from '../components/block-editing-mode';
10
11
 
11
12
  /**
12
13
  * Internal dependencies
@@ -33,6 +34,11 @@ const EMPTY_STYLE = {};
33
34
  * @param {Object} props.style Block style attribute.
34
35
  */
35
36
  function CustomCSSControl( { blockName, setAttributes, style } ) {
37
+ const blockEditingMode = useBlockEditingMode();
38
+
39
+ if ( blockEditingMode !== 'default' ) {
40
+ return null;
41
+ }
36
42
  const blockType = getBlockType( blockName );
37
43
 
38
44
  function onChange( newStyle ) {
@@ -232,14 +232,13 @@ function useFitText( { fitText, name, clientId } ) {
232
232
  /**
233
233
  * Fit text control component for the typography panel.
234
234
  *
235
- * @param {Object} props Component props.
236
- * @param {string} props.clientId Block client ID.
237
- * @param {Function} props.setAttributes Function to set block attributes.
238
- * @param {string} props.name Block name.
239
- * @param {boolean} props.fitText Whether fit text is enabled.
240
- * @param {string} props.fontSize Font size slug.
241
- * @param {Object} props.style Block style object.
242
- * @param {React.JSX.Element} props.warning Warning component to display.
235
+ * @param {Object} props Component props.
236
+ * @param {string} props.clientId Block client ID.
237
+ * @param {Function} props.setAttributes Function to set block attributes.
238
+ * @param {string} props.name Block name.
239
+ * @param {boolean} props.fitText Whether fit text is enabled.
240
+ * @param {string} props.fontSize Font size slug.
241
+ * @param {Object} props.style Block style object.
243
242
  */
244
243
  export function FitTextControl( {
245
244
  clientId,
@@ -248,56 +247,52 @@ export function FitTextControl( {
248
247
  name,
249
248
  fontSize,
250
249
  style,
251
- warning,
252
250
  } ) {
253
251
  if ( ! hasBlockSupport( name, FIT_TEXT_SUPPORT_KEY ) ) {
254
252
  return null;
255
253
  }
256
254
  return (
257
- <InspectorControls group="typography">
258
- <ToolsPanelItem
259
- hasValue={ () => fitText }
255
+ <ToolsPanelItem
256
+ hasValue={ () => fitText }
257
+ label={ __( 'Fit text' ) }
258
+ onDeselect={ () => setAttributes( { fitText: undefined } ) }
259
+ resetAllFilter={ () => ( { fitText: undefined } ) }
260
+ panelId={ clientId }
261
+ >
262
+ <ToggleControl
260
263
  label={ __( 'Fit text' ) }
261
- onDeselect={ () => setAttributes( { fitText: undefined } ) }
262
- resetAllFilter={ () => ( { fitText: undefined } ) }
263
- panelId={ clientId }
264
- >
265
- <ToggleControl
266
- label={ __( 'Fit text' ) }
267
- checked={ fitText }
268
- onChange={ () => {
269
- const newFitText = ! fitText || undefined;
270
- const updates = { fitText: newFitText };
271
-
272
- // When enabling fit text, clear font size if it has a value
273
- if ( newFitText ) {
274
- if ( fontSize ) {
275
- updates.fontSize = undefined;
276
- }
277
- if ( style?.typography?.fontSize ) {
278
- updates.style = {
279
- ...style,
280
- typography: {
281
- ...style?.typography,
282
- fontSize: undefined,
283
- },
284
- };
285
- }
264
+ checked={ fitText }
265
+ onChange={ () => {
266
+ const newFitText = ! fitText || undefined;
267
+ const updates = { fitText: newFitText };
268
+
269
+ // When enabling fit text, clear font size if it has a value
270
+ if ( newFitText ) {
271
+ if ( fontSize ) {
272
+ updates.fontSize = undefined;
273
+ }
274
+ if ( style?.typography?.fontSize ) {
275
+ updates.style = {
276
+ ...style,
277
+ typography: {
278
+ ...style?.typography,
279
+ fontSize: undefined,
280
+ },
281
+ };
286
282
  }
287
-
288
- setAttributes( updates );
289
- } }
290
- help={
291
- fitText
292
- ? __( 'Text will resize to fit its container.' )
293
- : __(
294
- 'The text will resize to fit its container, resetting other font size settings.'
295
- )
296
283
  }
297
- />
298
- { warning }
299
- </ToolsPanelItem>
300
- </InspectorControls>
284
+
285
+ setAttributes( updates );
286
+ } }
287
+ help={
288
+ fitText
289
+ ? __( 'Text will resize to fit its container.' )
290
+ : __(
291
+ 'The text will resize to fit its container, resetting other font size settings.'
292
+ )
293
+ }
294
+ />
295
+ </ToolsPanelItem>
301
296
  );
302
297
  }
303
298
 
@@ -358,14 +353,27 @@ const hasFitTextSupport = ( blockNameOrType ) => {
358
353
  return hasBlockSupport( blockNameOrType, FIT_TEXT_SUPPORT_KEY );
359
354
  };
360
355
 
361
- /*
362
- * Helper to encapsulate calls to the relatively expensive `useFitText` hook.
363
- * Used in `addFitTextControl` so that the hook is only called when a block's
364
- * `fitText` attribute is set.
356
+ /**
357
+ * Component that handles the fit text font size and displays a warning
358
+ * if the fit text font size is below a minimum threshold.
359
+ *
360
+ * @param {Object} props Component props.
361
+ * @param {boolean} props.fitText Whether fit text is enabled.
362
+ * @param {string} props.name Block name.
363
+ * @param {string} props.clientId Block client ID.
364
+ * @param {boolean} props.isSelected Whether the block is selected.
365
+ * @return {Element|null} Warning component or null.
365
366
  */
366
- function WithFitTextFontSize( { fitText, name, clientId, children } ) {
367
+ function FitTextFontSize( { fitText, name, clientId, isSelected } ) {
367
368
  const { fontSize } = useFitText( { fitText, name, clientId } );
368
- return children( fontSize );
369
+ if ( isSelected && fontSize && fontSize < MIN_FONT_SIZE_FOR_WARNING ) {
370
+ return (
371
+ <InspectorControls group="typography">
372
+ <FitTextSizeWarning />
373
+ </InspectorControls>
374
+ );
375
+ }
376
+ return null;
369
377
  }
370
378
 
371
379
  /*
@@ -385,33 +393,7 @@ const addFitTextControl = createHigherOrderComponent( ( BlockEdit ) => {
385
393
  return (
386
394
  <>
387
395
  <BlockEdit { ...props } />
388
- { fitText && (
389
- <WithFitTextFontSize
390
- fitText={ fitText }
391
- name={ name }
392
- clientId={ clientId }
393
- >
394
- { ( fontSize ) =>
395
- isSelected && (
396
- <FitTextControl
397
- clientId={ clientId }
398
- fitText={ fitText }
399
- setAttributes={ setAttributes }
400
- name={ name }
401
- fontSize={ attributes.fontSize }
402
- style={ attributes.style }
403
- warning={
404
- fontSize <
405
- MIN_FONT_SIZE_FOR_WARNING && (
406
- <FitTextSizeWarning />
407
- )
408
- }
409
- />
410
- )
411
- }
412
- </WithFitTextFontSize>
413
- ) }
414
- { ! fitText && isSelected && (
396
+ <InspectorControls group="typography">
415
397
  <FitTextControl
416
398
  clientId={ clientId }
417
399
  fitText={ fitText }
@@ -420,6 +402,14 @@ const addFitTextControl = createHigherOrderComponent( ( BlockEdit ) => {
420
402
  fontSize={ attributes.fontSize }
421
403
  style={ attributes.style }
422
404
  />
405
+ </InspectorControls>
406
+ { fitText && (
407
+ <FitTextFontSize
408
+ fitText={ fitText }
409
+ name={ name }
410
+ clientId={ clientId }
411
+ isSelected={ isSelected }
412
+ />
423
413
  ) }
424
414
  </>
425
415
  );
@@ -152,7 +152,7 @@ describe( 'cross-origin-isolation', () => {
152
152
  expect( observeSpy ).not.toHaveBeenCalled();
153
153
  } );
154
154
 
155
- it( 'should add crossorigin="anonymous" to images', async () => {
155
+ it( 'should not add crossorigin="anonymous" to images', async () => {
156
156
  Object.defineProperty( window, 'crossOriginIsolated', {
157
157
  value: true,
158
158
  writable: true,
@@ -172,8 +172,12 @@ describe( 'cross-origin-isolation', () => {
172
172
  // Wait for MutationObserver callback to fire (async microtask).
173
173
  await new Promise( ( resolve ) => setTimeout( resolve, 0 ) );
174
174
 
175
- // The image should get the crossorigin attribute
176
- expect( img ).toHaveAttribute( 'crossorigin', 'anonymous' );
175
+ // Images should NOT get the crossorigin attribute.
176
+ // Under Document-Isolation-Policy: isolate-and-credentialless,
177
+ // the credentialless mode handles image loading without CORS headers.
178
+ // Adding crossorigin="anonymous" would override this and break
179
+ // external images that don't serve CORS headers.
180
+ expect( img ).not.toHaveAttribute( 'crossorigin' );
177
181
 
178
182
  document.body.removeChild( img );
179
183
  } );
@@ -238,6 +238,7 @@ export function useBlockSettings( name, parentLayout ) {
238
238
  const [
239
239
  backgroundImage,
240
240
  backgroundSize,
241
+ gradient,
241
242
  customFontFamilies,
242
243
  defaultFontFamilies,
243
244
  themeFontFamilies,
@@ -300,6 +301,7 @@ export function useBlockSettings( name, parentLayout ) {
300
301
  ] = useSettings(
301
302
  'background.backgroundImage',
302
303
  'background.backgroundSize',
304
+ 'background.gradient',
303
305
  'typography.fontFamilies.custom',
304
306
  'typography.fontFamilies.default',
305
307
  'typography.fontFamilies.theme',
@@ -366,6 +368,7 @@ export function useBlockSettings( name, parentLayout ) {
366
368
  background: {
367
369
  backgroundImage,
368
370
  backgroundSize,
371
+ gradient,
369
372
  },
370
373
  color: {
371
374
  palette: {
@@ -453,6 +456,7 @@ export function useBlockSettings( name, parentLayout ) {
453
456
  }, [
454
457
  backgroundImage,
455
458
  backgroundSize,
459
+ gradient,
456
460
  customFontFamilies,
457
461
  defaultFontFamilies,
458
462
  themeFontFamilies,
@@ -1616,16 +1616,17 @@ export function updateSettings( settings ) {
1616
1616
  * Action that signals that a temporary reusable block has been saved
1617
1617
  * in order to switch its temporary id with the real id.
1618
1618
  *
1619
- * @param {string} id Reusable block's id.
1620
- * @param {string} updatedId Updated block's id.
1621
- *
1622
- * @return {Object} Action object.
1619
+ * @deprecated
1623
1620
  */
1624
- export function __unstableSaveReusableBlock( id, updatedId ) {
1621
+ export function __unstableSaveReusableBlock() {
1622
+ deprecated(
1623
+ 'wp.data.dispatch( "core/block-editor" ).__unstableSaveReusableBlock',
1624
+ {
1625
+ since: '7.1',
1626
+ }
1627
+ );
1625
1628
  return {
1626
- type: 'SAVE_REUSABLE_BLOCK_SUCCESS',
1627
- id,
1628
- updatedId,
1629
+ type: 'DO_NOTHING',
1629
1630
  };
1630
1631
  }
1631
1632
 
@@ -147,7 +147,7 @@ export const getEnabledClientIdsTree = createRegistrySelector( () =>
147
147
  createSelector( getEnabledClientIdsTreeUnmemoized, ( state ) => [
148
148
  state.blocks.order,
149
149
  state.derivedBlockEditingModes,
150
- state.blockEditingModes,
150
+ state.blocks.blockEditingModes,
151
151
  ] )
152
152
  );
153
153
 
@@ -170,7 +170,7 @@ export const getEnabledBlockParents = createSelector(
170
170
  },
171
171
  ( state ) => [
172
172
  state.blocks.parents,
173
- state.blockEditingModes,
173
+ state.blocks.blockEditingModes,
174
174
  state.settings.templateLock,
175
175
  state.blockListSettings,
176
176
  ]