@wordpress/edit-site 4.9.0 → 4.12.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 (199) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/build/components/add-new-template/add-custom-generic-template-modal.js +84 -0
  3. package/build/components/add-new-template/add-custom-generic-template-modal.js.map +1 -0
  4. package/build/components/add-new-template/add-custom-template-modal.js +82 -61
  5. package/build/components/add-new-template/add-custom-template-modal.js.map +1 -1
  6. package/build/components/add-new-template/new-template.js +94 -81
  7. package/build/components/add-new-template/new-template.js.map +1 -1
  8. package/build/components/add-new-template/utils.js +574 -57
  9. package/build/components/add-new-template/utils.js.map +1 -1
  10. package/build/components/block-editor/index.js +1 -3
  11. package/build/components/block-editor/index.js.map +1 -1
  12. package/build/components/code-editor/index.js +17 -4
  13. package/build/components/code-editor/index.js.map +1 -1
  14. package/build/components/editor/index.js +16 -0
  15. package/build/components/editor/index.js.map +1 -1
  16. package/build/components/error-boundary/index.js +6 -0
  17. package/build/components/error-boundary/index.js.map +1 -1
  18. package/build/components/global-styles/dimensions-panel.js +191 -21
  19. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  20. package/build/components/global-styles/global-styles-provider.js +4 -2
  21. package/build/components/global-styles/global-styles-provider.js.map +1 -1
  22. package/build/components/global-styles/hooks.js +11 -2
  23. package/build/components/global-styles/hooks.js.map +1 -1
  24. package/build/components/global-styles/screen-color-palette.js +13 -17
  25. package/build/components/global-styles/screen-color-palette.js.map +1 -1
  26. package/build/components/global-styles/screen-colors.js +59 -7
  27. package/build/components/global-styles/screen-colors.js.map +1 -1
  28. package/build/components/global-styles/screen-heading-color.js +157 -0
  29. package/build/components/global-styles/screen-heading-color.js.map +1 -0
  30. package/build/components/global-styles/screen-link-color.js +48 -14
  31. package/build/components/global-styles/screen-link-color.js.map +1 -1
  32. package/build/components/global-styles/screen-typography-element.js +4 -0
  33. package/build/components/global-styles/screen-typography-element.js.map +1 -1
  34. package/build/components/global-styles/screen-typography.js +5 -0
  35. package/build/components/global-styles/screen-typography.js.map +1 -1
  36. package/build/components/global-styles/typography-panel.js +73 -12
  37. package/build/components/global-styles/typography-panel.js.map +1 -1
  38. package/build/components/global-styles/typography-utils.js +217 -0
  39. package/build/components/global-styles/typography-utils.js.map +1 -0
  40. package/build/components/global-styles/ui.js +11 -0
  41. package/build/components/global-styles/ui.js.map +1 -1
  42. package/build/components/global-styles/use-global-styles-output.js +298 -61
  43. package/build/components/global-styles/use-global-styles-output.js.map +1 -1
  44. package/build/components/global-styles/utils.js +49 -3
  45. package/build/components/global-styles/utils.js.map +1 -1
  46. package/build/components/header/index.js +22 -10
  47. package/build/components/header/index.js.map +1 -1
  48. package/build/components/header/undo-redo/redo.js +2 -1
  49. package/build/components/header/undo-redo/redo.js.map +1 -1
  50. package/build/components/keyboard-shortcut-help-modal/index.js +1 -3
  51. package/build/components/keyboard-shortcut-help-modal/index.js.map +1 -1
  52. package/build/components/list/actions/index.js +1 -1
  53. package/build/components/list/actions/index.js.map +1 -1
  54. package/build/components/save-button/index.js +2 -3
  55. package/build/components/save-button/index.js.map +1 -1
  56. package/build/components/sidebar/navigation-menu-sidebar/navigation-menu.js +2 -2
  57. package/build/components/sidebar/navigation-menu-sidebar/navigation-menu.js.map +1 -1
  58. package/build/components/sidebar/template-card/template-actions.js +1 -1
  59. package/build/components/sidebar/template-card/template-actions.js.map +1 -1
  60. package/build/components/template-details/edit-template-title.js +11 -3
  61. package/build/components/template-details/edit-template-title.js.map +1 -1
  62. package/build/components/template-details/index.js +2 -21
  63. package/build/components/template-details/index.js.map +1 -1
  64. package/build/components/template-details/template-areas.js +1 -1
  65. package/build/components/template-details/template-areas.js.map +1 -1
  66. package/build/components/template-part-converter/convert-to-template-part.js +4 -1
  67. package/build/components/template-part-converter/convert-to-template-part.js.map +1 -1
  68. package/build/hooks/index.js +2 -0
  69. package/build/hooks/index.js.map +1 -1
  70. package/build/hooks/template-part-edit.js +86 -0
  71. package/build/hooks/template-part-edit.js.map +1 -0
  72. package/build/store/selectors.js +4 -1
  73. package/build/store/selectors.js.map +1 -1
  74. package/build-module/components/add-new-template/add-custom-generic-template-modal.js +77 -0
  75. package/build-module/components/add-new-template/add-custom-generic-template-modal.js.map +1 -0
  76. package/build-module/components/add-new-template/add-custom-template-modal.js +82 -61
  77. package/build-module/components/add-new-template/add-custom-template-modal.js.map +1 -1
  78. package/build-module/components/add-new-template/new-template.js +96 -84
  79. package/build-module/components/add-new-template/new-template.js.map +1 -1
  80. package/build-module/components/add-new-template/utils.js +555 -50
  81. package/build-module/components/add-new-template/utils.js.map +1 -1
  82. package/build-module/components/block-editor/index.js +1 -2
  83. package/build-module/components/block-editor/index.js.map +1 -1
  84. package/build-module/components/code-editor/index.js +18 -5
  85. package/build-module/components/code-editor/index.js.map +1 -1
  86. package/build-module/components/editor/index.js +16 -0
  87. package/build-module/components/editor/index.js.map +1 -1
  88. package/build-module/components/error-boundary/index.js +5 -0
  89. package/build-module/components/error-boundary/index.js.map +1 -1
  90. package/build-module/components/global-styles/dimensions-panel.js +191 -22
  91. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  92. package/build-module/components/global-styles/global-styles-provider.js +4 -2
  93. package/build-module/components/global-styles/global-styles-provider.js.map +1 -1
  94. package/build-module/components/global-styles/hooks.js +11 -2
  95. package/build-module/components/global-styles/hooks.js.map +1 -1
  96. package/build-module/components/global-styles/screen-color-palette.js +14 -19
  97. package/build-module/components/global-styles/screen-color-palette.js.map +1 -1
  98. package/build-module/components/global-styles/screen-colors.js +59 -7
  99. package/build-module/components/global-styles/screen-colors.js.map +1 -1
  100. package/build-module/components/global-styles/screen-heading-color.js +143 -0
  101. package/build-module/components/global-styles/screen-heading-color.js.map +1 -0
  102. package/build-module/components/global-styles/screen-link-color.js +47 -14
  103. package/build-module/components/global-styles/screen-link-color.js.map +1 -1
  104. package/build-module/components/global-styles/screen-typography-element.js +4 -0
  105. package/build-module/components/global-styles/screen-typography-element.js.map +1 -1
  106. package/build-module/components/global-styles/screen-typography.js +5 -0
  107. package/build-module/components/global-styles/screen-typography.js.map +1 -1
  108. package/build-module/components/global-styles/typography-panel.js +74 -13
  109. package/build-module/components/global-styles/typography-panel.js.map +1 -1
  110. package/build-module/components/global-styles/typography-utils.js +204 -0
  111. package/build-module/components/global-styles/typography-utils.js.map +1 -0
  112. package/build-module/components/global-styles/ui.js +10 -0
  113. package/build-module/components/global-styles/ui.js.map +1 -1
  114. package/build-module/components/global-styles/use-global-styles-output.js +294 -69
  115. package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
  116. package/build-module/components/global-styles/utils.js +47 -4
  117. package/build-module/components/global-styles/utils.js.map +1 -1
  118. package/build-module/components/header/index.js +25 -12
  119. package/build-module/components/header/index.js.map +1 -1
  120. package/build-module/components/header/undo-redo/redo.js +3 -2
  121. package/build-module/components/header/undo-redo/redo.js.map +1 -1
  122. package/build-module/components/keyboard-shortcut-help-modal/index.js +1 -2
  123. package/build-module/components/keyboard-shortcut-help-modal/index.js.map +1 -1
  124. package/build-module/components/list/actions/index.js +1 -1
  125. package/build-module/components/list/actions/index.js.map +1 -1
  126. package/build-module/components/save-button/index.js +3 -4
  127. package/build-module/components/save-button/index.js.map +1 -1
  128. package/build-module/components/sidebar/navigation-menu-sidebar/navigation-menu.js +3 -3
  129. package/build-module/components/sidebar/navigation-menu-sidebar/navigation-menu.js.map +1 -1
  130. package/build-module/components/sidebar/template-card/template-actions.js +1 -1
  131. package/build-module/components/sidebar/template-card/template-actions.js.map +1 -1
  132. package/build-module/components/template-details/edit-template-title.js +12 -3
  133. package/build-module/components/template-details/edit-template-title.js.map +1 -1
  134. package/build-module/components/template-details/index.js +3 -22
  135. package/build-module/components/template-details/index.js.map +1 -1
  136. package/build-module/components/template-details/template-areas.js +1 -1
  137. package/build-module/components/template-details/template-areas.js.map +1 -1
  138. package/build-module/components/template-part-converter/convert-to-template-part.js +3 -1
  139. package/build-module/components/template-part-converter/convert-to-template-part.js.map +1 -1
  140. package/build-module/hooks/index.js +1 -0
  141. package/build-module/hooks/index.js.map +1 -1
  142. package/build-module/hooks/template-part-edit.js +67 -0
  143. package/build-module/hooks/template-part-edit.js.map +1 -0
  144. package/build-module/store/selectors.js +5 -2
  145. package/build-module/store/selectors.js.map +1 -1
  146. package/build-style/style-rtl.css +55 -48
  147. package/build-style/style.css +55 -48
  148. package/package.json +29 -29
  149. package/src/components/add-new-template/add-custom-generic-template-modal.js +97 -0
  150. package/src/components/add-new-template/add-custom-template-modal.js +93 -68
  151. package/src/components/add-new-template/new-template.js +126 -95
  152. package/src/components/add-new-template/style.scss +41 -8
  153. package/src/components/add-new-template/utils.js +622 -80
  154. package/src/components/block-editor/index.js +0 -2
  155. package/src/components/code-editor/index.js +15 -5
  156. package/src/components/editor/index.js +11 -0
  157. package/src/components/error-boundary/index.js +5 -0
  158. package/src/components/global-styles/dimensions-panel.js +214 -24
  159. package/src/components/global-styles/global-styles-provider.js +8 -9
  160. package/src/components/global-styles/hooks.js +18 -0
  161. package/src/components/global-styles/screen-color-palette.js +25 -27
  162. package/src/components/global-styles/screen-colors.js +55 -7
  163. package/src/components/global-styles/screen-heading-color.js +201 -0
  164. package/src/components/global-styles/screen-link-color.js +65 -23
  165. package/src/components/global-styles/screen-typography-element.js +4 -0
  166. package/src/components/global-styles/screen-typography.js +6 -0
  167. package/src/components/global-styles/style.scss +14 -11
  168. package/src/components/global-styles/test/typography-utils.js +130 -0
  169. package/src/components/global-styles/test/use-global-styles-output.js +296 -2
  170. package/src/components/global-styles/typography-panel.js +85 -16
  171. package/src/components/global-styles/typography-utils.js +228 -0
  172. package/src/components/global-styles/ui.js +13 -0
  173. package/src/components/global-styles/use-global-styles-output.js +387 -89
  174. package/src/components/global-styles/utils.js +43 -2
  175. package/src/components/header/index.js +37 -13
  176. package/src/components/header/style.scss +5 -3
  177. package/src/components/header/undo-redo/redo.js +6 -2
  178. package/src/components/keyboard-shortcut-help-modal/index.js +1 -2
  179. package/src/components/keyboard-shortcut-help-modal/style.scss +0 -5
  180. package/src/components/list/actions/index.js +3 -1
  181. package/src/components/list/style.scss +0 -8
  182. package/src/components/save-button/index.js +10 -13
  183. package/src/components/sidebar/navigation-menu-sidebar/navigation-menu.js +1 -5
  184. package/src/components/sidebar/style.scss +4 -0
  185. package/src/components/sidebar/template-card/template-actions.js +3 -1
  186. package/src/components/template-details/edit-template-title.js +10 -2
  187. package/src/components/template-details/index.js +7 -22
  188. package/src/components/template-details/template-areas.js +3 -1
  189. package/src/components/template-part-converter/convert-to-template-part.js +3 -1
  190. package/src/components/test/error-boundary.js +38 -0
  191. package/src/hooks/index.js +1 -0
  192. package/src/hooks/template-part-edit.js +82 -0
  193. package/src/store/selectors.js +11 -5
  194. package/src/style.scss +0 -1
  195. package/build/components/edit-template-part-menu-button/index.js +0 -90
  196. package/build/components/edit-template-part-menu-button/index.js.map +0 -1
  197. package/build-module/components/edit-template-part-menu-button/index.js +0 -72
  198. package/build-module/components/edit-template-part-menu-button/index.js.map +0 -1
  199. package/src/components/edit-template-part-menu-button/index.js +0 -82
@@ -6,12 +6,10 @@ import {
6
6
  forEach,
7
7
  get,
8
8
  isEmpty,
9
- isString,
10
9
  kebabCase,
11
10
  pickBy,
12
11
  reduce,
13
12
  set,
14
- startsWith,
15
13
  } from 'lodash';
16
14
 
17
15
  /**
@@ -22,22 +20,36 @@ import {
22
20
  __EXPERIMENTAL_ELEMENTS as ELEMENTS,
23
21
  getBlockTypes,
24
22
  } from '@wordpress/blocks';
25
- import { useEffect, useState, useContext } from '@wordpress/element';
23
+ import { useSelect } from '@wordpress/data';
24
+ import { useContext, useMemo } from '@wordpress/element';
26
25
  import { getCSSRules } from '@wordpress/style-engine';
27
- import { __unstablePresetDuotoneFilter as PresetDuotoneFilter } from '@wordpress/block-editor';
26
+ import {
27
+ __unstablePresetDuotoneFilter as PresetDuotoneFilter,
28
+ __experimentalGetGapCSSValue as getGapCSSValue,
29
+ store as blockEditorStore,
30
+ } from '@wordpress/block-editor';
28
31
 
29
32
  /**
30
33
  * Internal dependencies
31
34
  */
32
- import { PRESET_METADATA, ROOT_BLOCK_SELECTOR } from './utils';
35
+ import { PRESET_METADATA, ROOT_BLOCK_SELECTOR, scopeSelector } from './utils';
33
36
  import { GlobalStylesContext } from './context';
34
37
  import { useSetting } from './hooks';
35
38
 
39
+ // List of block support features that can have their related styles
40
+ // generated under their own feature level selector rather than the block's.
41
+ const BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS = {
42
+ __experimentalBorder: 'border',
43
+ color: 'color',
44
+ spacing: 'spacing',
45
+ typography: 'typography',
46
+ };
47
+
36
48
  function compileStyleValue( uncompiledValue ) {
37
49
  const VARIABLE_REFERENCE_PREFIX = 'var:';
38
50
  const VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE = '|';
39
51
  const VARIABLE_PATH_SEPARATOR_TOKEN_STYLE = '--';
40
- if ( startsWith( uncompiledValue, VARIABLE_REFERENCE_PREFIX ) ) {
52
+ if ( uncompiledValue?.startsWith( VARIABLE_REFERENCE_PREFIX ) ) {
41
53
  const variable = uncompiledValue
42
54
  .slice( VARIABLE_REFERENCE_PREFIX.length )
43
55
  .split( VARIABLE_PATH_SEPARATOR_TOKEN_ATTRIBUTE )
@@ -51,10 +63,11 @@ function compileStyleValue( uncompiledValue ) {
51
63
  * Transform given preset tree into a set of style declarations.
52
64
  *
53
65
  * @param {Object} blockPresets
66
+ * @param {Object} mergedSettings Merged theme.json settings.
54
67
  *
55
- * @return {Array} An array of style declarations.
68
+ * @return {Array<Object>} An array of style declarations.
56
69
  */
57
- function getPresetsDeclarations( blockPresets = {} ) {
70
+ function getPresetsDeclarations( blockPresets = {}, mergedSettings ) {
58
71
  return reduce(
59
72
  PRESET_METADATA,
60
73
  ( declarations, { path, valueKey, valueFunc, cssVarInfix } ) => {
@@ -62,7 +75,7 @@ function getPresetsDeclarations( blockPresets = {} ) {
62
75
  [ 'default', 'theme', 'custom' ].forEach( ( origin ) => {
63
76
  if ( presetByOrigin[ origin ] ) {
64
77
  presetByOrigin[ origin ].forEach( ( value ) => {
65
- if ( valueKey ) {
78
+ if ( valueKey && ! valueFunc ) {
66
79
  declarations.push(
67
80
  `--wp--preset--${ cssVarInfix }--${ kebabCase(
68
81
  value.slug
@@ -75,7 +88,7 @@ function getPresetsDeclarations( blockPresets = {} ) {
75
88
  declarations.push(
76
89
  `--wp--preset--${ cssVarInfix }--${ kebabCase(
77
90
  value.slug
78
- ) }: ${ valueFunc( value ) }`
91
+ ) }: ${ valueFunc( value, mergedSettings ) }`
79
92
  );
80
93
  }
81
94
  } );
@@ -170,14 +183,26 @@ function flattenTree( input = {}, prefix, token ) {
170
183
  /**
171
184
  * Transform given style tree into a set of style declarations.
172
185
  *
173
- * @param {Object} blockStyles Block styles.
186
+ * @param {Object} blockStyles Block styles.
187
+ *
188
+ * @param {string} selector The selector these declarations should attach to.
189
+ *
190
+ * @param {boolean} useRootPaddingAlign Whether to use CSS custom properties in root selector.
174
191
  *
175
192
  * @return {Array} An array of style declarations.
176
193
  */
177
- function getStylesDeclarations( blockStyles = {} ) {
194
+ export function getStylesDeclarations(
195
+ blockStyles = {},
196
+ selector = '',
197
+ useRootPaddingAlign
198
+ ) {
199
+ const isRoot = ROOT_BLOCK_SELECTOR === selector;
178
200
  const output = reduce(
179
201
  STYLE_PROPERTY,
180
- ( declarations, { value, properties, useEngine }, key ) => {
202
+ ( declarations, { value, properties, useEngine, rootOnly }, key ) => {
203
+ if ( rootOnly && ! isRoot ) {
204
+ return declarations;
205
+ }
181
206
  const pathToValue = value;
182
207
  if ( first( pathToValue ) === 'elements' || useEngine ) {
183
208
  return declarations;
@@ -185,7 +210,16 @@ function getStylesDeclarations( blockStyles = {} ) {
185
210
 
186
211
  const styleValue = get( blockStyles, pathToValue );
187
212
 
188
- if ( !! properties && ! isString( styleValue ) ) {
213
+ // Root-level padding styles don't currently support strings with CSS shorthand values.
214
+ // This may change: https://github.com/WordPress/gutenberg/issues/40132.
215
+ if (
216
+ key === '--wp--style--root--padding' &&
217
+ ( typeof styleValue === 'string' || ! useRootPaddingAlign )
218
+ ) {
219
+ return declarations;
220
+ }
221
+
222
+ if ( !! properties && typeof styleValue !== 'string' ) {
189
223
  Object.entries( properties ).forEach( ( entry ) => {
190
224
  const [ name, prop ] = entry;
191
225
 
@@ -195,7 +229,9 @@ function getStylesDeclarations( blockStyles = {} ) {
195
229
  return;
196
230
  }
197
231
 
198
- const cssProperty = kebabCase( name );
232
+ const cssProperty = name.startsWith( '--' )
233
+ ? name
234
+ : kebabCase( name );
199
235
  declarations.push(
200
236
  `${ cssProperty }: ${ compileStyleValue(
201
237
  get( styleValue, [ prop ] )
@@ -222,6 +258,14 @@ function getStylesDeclarations( blockStyles = {} ) {
222
258
  // This is temporary as we absorb more and more styles into the engine.
223
259
  const extraRules = getCSSRules( blockStyles );
224
260
  extraRules.forEach( ( rule ) => {
261
+ // Don't output padding properties if padding variables are set.
262
+ if (
263
+ isRoot &&
264
+ useRootPaddingAlign &&
265
+ rule.key.startsWith( 'padding' )
266
+ ) {
267
+ return;
268
+ }
225
269
  const cssProperty = rule.key.startsWith( '--' )
226
270
  ? rule.key
227
271
  : kebabCase( rule.key );
@@ -231,6 +275,149 @@ function getStylesDeclarations( blockStyles = {} ) {
231
275
  return output;
232
276
  }
233
277
 
278
+ /**
279
+ * Get generated CSS for layout styles by looking up layout definitions provided
280
+ * in theme.json, and outputting common layout styles, and specific blockGap values.
281
+ *
282
+ * @param {Object} props
283
+ * @param {Object} props.tree A theme.json tree containing layout definitions.
284
+ * @param {Object} props.style A style object containing spacing values.
285
+ * @param {string} props.selector Selector used to group together layout styling rules.
286
+ * @param {boolean} props.hasBlockGapSupport Whether or not the theme opts-in to blockGap support.
287
+ * @param {boolean} props.hasFallbackGapSupport Whether or not the theme allows fallback gap styles.
288
+ * @param {?string} props.fallbackGapValue An optional fallback gap value if no real gap value is available.
289
+ * @return {string} Generated CSS rules for the layout styles.
290
+ */
291
+ export function getLayoutStyles( {
292
+ tree,
293
+ style,
294
+ selector,
295
+ hasBlockGapSupport,
296
+ hasFallbackGapSupport,
297
+ fallbackGapValue,
298
+ } ) {
299
+ let ruleset = '';
300
+ let gapValue = hasBlockGapSupport
301
+ ? getGapCSSValue( style?.spacing?.blockGap )
302
+ : '';
303
+
304
+ // Ensure a fallback gap value for the root layout definitions,
305
+ // and use a fallback value if one is provided for the current block.
306
+ if ( hasFallbackGapSupport ) {
307
+ if ( selector === ROOT_BLOCK_SELECTOR ) {
308
+ gapValue = ! gapValue ? '0.5em' : gapValue;
309
+ } else if ( ! hasBlockGapSupport && fallbackGapValue ) {
310
+ gapValue = fallbackGapValue;
311
+ }
312
+ }
313
+
314
+ if ( gapValue && tree?.settings?.layout?.definitions ) {
315
+ Object.values( tree.settings.layout.definitions ).forEach(
316
+ ( { className, name, spacingStyles } ) => {
317
+ // Allow skipping default layout for themes that opt-in to block styles, but opt-out of blockGap.
318
+ if ( ! hasBlockGapSupport && 'default' === name ) {
319
+ return;
320
+ }
321
+
322
+ if ( spacingStyles?.length ) {
323
+ spacingStyles.forEach( ( spacingStyle ) => {
324
+ const declarations = [];
325
+
326
+ if ( spacingStyle.rules ) {
327
+ Object.entries( spacingStyle.rules ).forEach(
328
+ ( [ cssProperty, cssValue ] ) => {
329
+ declarations.push(
330
+ `${ cssProperty }: ${
331
+ cssValue ? cssValue : gapValue
332
+ }`
333
+ );
334
+ }
335
+ );
336
+ }
337
+
338
+ if ( declarations.length ) {
339
+ let combinedSelector = '';
340
+
341
+ if ( ! hasBlockGapSupport ) {
342
+ // For fallback gap styles, use lower specificity, to ensure styles do not unintentionally override theme styles.
343
+ combinedSelector =
344
+ selector === ROOT_BLOCK_SELECTOR
345
+ ? `:where(.${ className }${
346
+ spacingStyle?.selector || ''
347
+ })`
348
+ : `:where(${ selector }.${ className }${
349
+ spacingStyle?.selector || ''
350
+ })`;
351
+ } else {
352
+ combinedSelector =
353
+ selector === ROOT_BLOCK_SELECTOR
354
+ ? `${ selector } .${ className }${
355
+ spacingStyle?.selector || ''
356
+ }`
357
+ : `${ selector }.${ className }${
358
+ spacingStyle?.selector || ''
359
+ }`;
360
+ }
361
+ ruleset += `${ combinedSelector } { ${ declarations.join(
362
+ '; '
363
+ ) }; }`;
364
+ }
365
+ } );
366
+ }
367
+ }
368
+ );
369
+ // For backwards compatibility, ensure the legacy block gap CSS variable is still available.
370
+ if ( selector === ROOT_BLOCK_SELECTOR && hasBlockGapSupport ) {
371
+ ruleset += `${ selector } { --wp--style--block-gap: ${ gapValue }; }`;
372
+ }
373
+ }
374
+
375
+ // Output base styles
376
+ if (
377
+ selector === ROOT_BLOCK_SELECTOR &&
378
+ tree?.settings?.layout?.definitions
379
+ ) {
380
+ const validDisplayModes = [ 'block', 'flex', 'grid' ];
381
+ Object.values( tree.settings.layout.definitions ).forEach(
382
+ ( { className, displayMode, baseStyles } ) => {
383
+ if (
384
+ displayMode &&
385
+ validDisplayModes.includes( displayMode )
386
+ ) {
387
+ ruleset += `${ selector } .${ className } { display:${ displayMode }; }`;
388
+ }
389
+
390
+ if ( baseStyles?.length ) {
391
+ baseStyles.forEach( ( baseStyle ) => {
392
+ const declarations = [];
393
+
394
+ if ( baseStyle.rules ) {
395
+ Object.entries( baseStyle.rules ).forEach(
396
+ ( [ cssProperty, cssValue ] ) => {
397
+ declarations.push(
398
+ `${ cssProperty }: ${ cssValue }`
399
+ );
400
+ }
401
+ );
402
+ }
403
+
404
+ if ( declarations.length ) {
405
+ const combinedSelector = `${ selector } .${ className }${
406
+ baseStyle?.selector || ''
407
+ }`;
408
+ ruleset += `${ combinedSelector } { ${ declarations.join(
409
+ '; '
410
+ ) }; }`;
411
+ }
412
+ } );
413
+ }
414
+ }
415
+ );
416
+ }
417
+
418
+ return ruleset;
419
+ }
420
+
234
421
  export const getNodesWithStyles = ( tree, blockSelectors ) => {
235
422
  const nodes = [];
236
423
 
@@ -253,11 +440,12 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => {
253
440
  selector: ROOT_BLOCK_SELECTOR,
254
441
  } );
255
442
  }
256
- forEach( tree.styles?.elements, ( value, key ) => {
257
- if ( !! value && !! ELEMENTS[ key ] ) {
443
+
444
+ forEach( ELEMENTS, ( selector, name ) => {
445
+ if ( !! tree.styles?.elements[ name ] ) {
258
446
  nodes.push( {
259
- styles: value,
260
- selector: ELEMENTS[ key ],
447
+ styles: tree.styles?.elements[ name ],
448
+ selector,
261
449
  } );
262
450
  }
263
451
  } );
@@ -267,9 +455,12 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => {
267
455
  const blockStyles = pickStyleKeys( node );
268
456
  if ( !! blockStyles && !! blockSelectors?.[ blockName ]?.selector ) {
269
457
  nodes.push( {
270
- styles: blockStyles,
271
- selector: blockSelectors[ blockName ].selector,
272
458
  duotoneSelector: blockSelectors[ blockName ].duotoneSelector,
459
+ fallbackGapValue: blockSelectors[ blockName ].fallbackGapValue,
460
+ hasLayoutSupport: blockSelectors[ blockName ].hasLayoutSupport,
461
+ selector: blockSelectors[ blockName ].selector,
462
+ styles: blockStyles,
463
+ featureSelectors: blockSelectors[ blockName ].featureSelectors,
273
464
  } );
274
465
  }
275
466
 
@@ -347,10 +538,9 @@ export const getNodesWithSettings = ( tree, blockSelectors ) => {
347
538
 
348
539
  export const toCustomProperties = ( tree, blockSelectors ) => {
349
540
  const settings = getNodesWithSettings( tree, blockSelectors );
350
-
351
541
  let ruleset = '';
352
542
  settings.forEach( ( { presets, custom, selector } ) => {
353
- const declarations = getPresetsDeclarations( presets );
543
+ const declarations = getPresetsDeclarations( presets, tree?.settings );
354
544
  const customProps = flattenTree( custom, '--wp--custom--', '--' );
355
545
  if ( customProps.length > 0 ) {
356
546
  declarations.push( ...customProps );
@@ -364,9 +554,16 @@ export const toCustomProperties = ( tree, blockSelectors ) => {
364
554
  return ruleset;
365
555
  };
366
556
 
367
- export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => {
557
+ export const toStyles = (
558
+ tree,
559
+ blockSelectors,
560
+ hasBlockGapSupport,
561
+ hasFallbackGapSupport,
562
+ disableLayoutStyles = false
563
+ ) => {
368
564
  const nodesWithStyles = getNodesWithStyles( tree, blockSelectors );
369
565
  const nodesWithSettings = getNodesWithSettings( tree, blockSelectors );
566
+ const useRootPaddingAlign = tree?.settings?.useRootPaddingAwareAlignments;
370
567
 
371
568
  /*
372
569
  * Reset default browser margin on the root body element.
@@ -377,63 +574,129 @@ export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => {
377
574
  * @link https://github.com/WordPress/gutenberg/issues/36147.
378
575
  */
379
576
  let ruleset = 'body {margin: 0;}';
380
- nodesWithStyles.forEach( ( { selector, duotoneSelector, styles } ) => {
381
- const duotoneStyles = {};
382
- if ( styles?.filter ) {
383
- duotoneStyles.filter = styles.filter;
384
- delete styles.filter;
385
- }
386
577
 
387
- // Process duotone styles (they use color.__experimentalDuotone selector).
388
- if ( duotoneSelector ) {
389
- const duotoneDeclarations = getStylesDeclarations( duotoneStyles );
390
- if ( duotoneDeclarations.length === 0 ) {
391
- return;
392
- }
393
- ruleset =
394
- ruleset +
395
- `${ duotoneSelector }{${ duotoneDeclarations.join( ';' ) };}`;
396
- }
397
-
398
- // Process the remaning block styles (they use either normal block class or __experimentalSelector).
399
- const declarations = getStylesDeclarations( styles );
400
- if ( declarations?.length ) {
401
- ruleset = ruleset + `${ selector }{${ declarations.join( ';' ) };}`;
402
- }
578
+ if ( useRootPaddingAlign ) {
579
+ ruleset =
580
+ 'body { margin: 0; padding-right: 0; padding-left: 0; padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom) } .has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); } .has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); } .has-global-padding > .alignfull > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }';
581
+ }
403
582
 
404
- // Check for pseudo selector in `styles` and handle separately.
405
- const psuedoSelectorStyles = Object.entries( styles ).filter(
406
- ( [ key ] ) => key.startsWith( ':' )
407
- );
583
+ nodesWithStyles.forEach(
584
+ ( {
585
+ selector,
586
+ duotoneSelector,
587
+ styles,
588
+ fallbackGapValue,
589
+ hasLayoutSupport,
590
+ featureSelectors,
591
+ } ) => {
592
+ // Process styles for block support features with custom feature level
593
+ // CSS selectors set.
594
+ if ( featureSelectors ) {
595
+ Object.entries( featureSelectors ).forEach(
596
+ ( [ featureName, featureSelector ] ) => {
597
+ if ( styles?.[ featureName ] ) {
598
+ const featureStyles = {
599
+ [ featureName ]: styles[ featureName ],
600
+ };
601
+ const featureDeclarations =
602
+ getStylesDeclarations( featureStyles );
603
+ delete styles[ featureName ];
604
+
605
+ if ( !! featureDeclarations.length ) {
606
+ ruleset =
607
+ ruleset +
608
+ `${ featureSelector }{${ featureDeclarations.join(
609
+ ';'
610
+ ) } }`;
611
+ }
612
+ }
613
+ }
614
+ );
615
+ }
408
616
 
409
- if ( psuedoSelectorStyles?.length ) {
410
- psuedoSelectorStyles.forEach( ( [ pseudoKey, pseudoRule ] ) => {
411
- const pseudoDeclarations = getStylesDeclarations( pseudoRule );
617
+ const duotoneStyles = {};
618
+ if ( styles?.filter ) {
619
+ duotoneStyles.filter = styles.filter;
620
+ delete styles.filter;
621
+ }
412
622
 
413
- if ( ! pseudoDeclarations?.length ) {
623
+ // Process duotone styles (they use color.__experimentalDuotone selector).
624
+ if ( duotoneSelector ) {
625
+ const duotoneDeclarations =
626
+ getStylesDeclarations( duotoneStyles );
627
+ if ( duotoneDeclarations.length === 0 ) {
414
628
  return;
415
629
  }
630
+ ruleset =
631
+ ruleset +
632
+ `${ duotoneSelector }{${ duotoneDeclarations.join(
633
+ ';'
634
+ ) };}`;
635
+ }
416
636
 
417
- // `selector` maybe provided in a form
418
- // where block level selectors have sub element
419
- // selectors appended to them as a comma seperated
420
- // string.
421
- // e.g. `h1 a,h2 a,h3 a,h4 a,h5 a,h6 a`;
422
- // Split and append pseudo selector to create
423
- // the proper rules to target the elements.
424
- const _selector = selector
425
- .split( ',' )
426
- .map( ( sel ) => sel + pseudoKey )
427
- .join( ',' );
428
-
429
- const psuedoRule = `${ _selector }{${ pseudoDeclarations.join(
430
- ';'
431
- ) };}`;
432
-
433
- ruleset = ruleset + psuedoRule;
434
- } );
637
+ // Process blockGap and layout styles.
638
+ if (
639
+ ! disableLayoutStyles &&
640
+ ( ROOT_BLOCK_SELECTOR === selector || hasLayoutSupport )
641
+ ) {
642
+ ruleset += getLayoutStyles( {
643
+ tree,
644
+ style: styles,
645
+ selector,
646
+ hasBlockGapSupport,
647
+ hasFallbackGapSupport,
648
+ fallbackGapValue,
649
+ } );
650
+ }
651
+
652
+ // Process the remaining block styles (they use either normal block class or __experimentalSelector).
653
+ const declarations = getStylesDeclarations(
654
+ styles,
655
+ selector,
656
+ useRootPaddingAlign
657
+ );
658
+ if ( declarations?.length ) {
659
+ ruleset =
660
+ ruleset + `${ selector }{${ declarations.join( ';' ) };}`;
661
+ }
662
+
663
+ // Check for pseudo selector in `styles` and handle separately.
664
+ const pseudoSelectorStyles = Object.entries( styles ).filter(
665
+ ( [ key ] ) => key.startsWith( ':' )
666
+ );
667
+
668
+ if ( pseudoSelectorStyles?.length ) {
669
+ pseudoSelectorStyles.forEach(
670
+ ( [ pseudoKey, pseudoStyle ] ) => {
671
+ const pseudoDeclarations =
672
+ getStylesDeclarations( pseudoStyle );
673
+
674
+ if ( ! pseudoDeclarations?.length ) {
675
+ return;
676
+ }
677
+
678
+ // `selector` maybe provided in a form
679
+ // where block level selectors have sub element
680
+ // selectors appended to them as a comma separated
681
+ // string.
682
+ // e.g. `h1 a,h2 a,h3 a,h4 a,h5 a,h6 a`;
683
+ // Split and append pseudo selector to create
684
+ // the proper rules to target the elements.
685
+ const _selector = selector
686
+ .split( ',' )
687
+ .map( ( sel ) => sel + pseudoKey )
688
+ .join( ',' );
689
+
690
+ const pseudoRule = `${ _selector }{${ pseudoDeclarations.join(
691
+ ';'
692
+ ) };}`;
693
+
694
+ ruleset = ruleset + pseudoRule;
695
+ }
696
+ );
697
+ }
435
698
  }
436
- } );
699
+ );
437
700
 
438
701
  /* Add alignment / layout styles */
439
702
  ruleset =
@@ -447,12 +710,15 @@ export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => {
447
710
  '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
448
711
 
449
712
  if ( hasBlockGapSupport ) {
713
+ // Use fallback of `0.5em` just in case, however if there is blockGap support, there should nearly always be a real value.
714
+ const gapValue =
715
+ getGapCSSValue( tree?.styles?.spacing?.blockGap ) || '0.5em';
450
716
  ruleset =
451
717
  ruleset +
452
718
  '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
453
719
  ruleset =
454
720
  ruleset +
455
- '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
721
+ `.wp-site-blocks > * + * { margin-block-start: ${ gapValue }; }`;
456
722
  }
457
723
 
458
724
  nodesWithSettings.forEach( ( { selector, presets } ) => {
@@ -477,7 +743,7 @@ export function toSvgFilters( tree, blockSelectors ) {
477
743
  } );
478
744
  }
479
745
 
480
- const getBlockSelectors = ( blockTypes ) => {
746
+ export const getBlockSelectors = ( blockTypes ) => {
481
747
  const result = {};
482
748
  blockTypes.forEach( ( blockType ) => {
483
749
  const name = blockType.name;
@@ -486,10 +752,35 @@ const getBlockSelectors = ( blockTypes ) => {
486
752
  '.wp-block-' + name.replace( 'core/', '' ).replace( '/', '-' );
487
753
  const duotoneSelector =
488
754
  blockType?.supports?.color?.__experimentalDuotone ?? null;
755
+ const hasLayoutSupport = !! blockType?.supports?.__experimentalLayout;
756
+ const fallbackGapValue =
757
+ blockType?.supports?.spacing?.blockGap?.__experimentalDefault;
758
+
759
+ // For each block support feature add any custom selectors.
760
+ const featureSelectors = {};
761
+ Object.entries( BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS ).forEach(
762
+ ( [ featureKey, featureName ] ) => {
763
+ const featureSelector =
764
+ blockType?.supports?.[ featureKey ]?.__experimentalSelector;
765
+
766
+ if ( featureSelector ) {
767
+ featureSelectors[ featureName ] = scopeSelector(
768
+ selector,
769
+ featureSelector
770
+ );
771
+ }
772
+ }
773
+ );
774
+
489
775
  result[ name ] = {
776
+ duotoneSelector,
777
+ fallbackGapValue,
778
+ featureSelectors: Object.keys( featureSelectors ).length
779
+ ? featureSelectors
780
+ : undefined,
781
+ hasLayoutSupport,
490
782
  name,
491
783
  selector,
492
- duotoneSelector,
493
784
  };
494
785
  } );
495
786
 
@@ -497,16 +788,18 @@ const getBlockSelectors = ( blockTypes ) => {
497
788
  };
498
789
 
499
790
  export function useGlobalStylesOutput() {
500
- const [ stylesheets, setStylesheets ] = useState( [] );
501
- const [ settings, setSettings ] = useState( {} );
502
- const [ svgFilters, setSvgFilters ] = useState( {} );
503
791
  const { merged: mergedConfig } = useContext( GlobalStylesContext );
504
792
  const [ blockGap ] = useSetting( 'spacing.blockGap' );
505
793
  const hasBlockGapSupport = blockGap !== null;
794
+ const hasFallbackGapSupport = ! hasBlockGapSupport; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback styles support.
795
+ const disableLayoutStyles = useSelect( ( select ) => {
796
+ const { getSettings } = select( blockEditorStore );
797
+ return !! getSettings().disableLayoutStyles;
798
+ } );
506
799
 
507
- useEffect( () => {
800
+ return useMemo( () => {
508
801
  if ( ! mergedConfig?.styles || ! mergedConfig?.settings ) {
509
- return;
802
+ return [];
510
803
  }
511
804
 
512
805
  const blockSelectors = getBlockSelectors( getBlockTypes() );
@@ -517,10 +810,12 @@ export function useGlobalStylesOutput() {
517
810
  const globalStyles = toStyles(
518
811
  mergedConfig,
519
812
  blockSelectors,
520
- hasBlockGapSupport
813
+ hasBlockGapSupport,
814
+ hasFallbackGapSupport,
815
+ disableLayoutStyles
521
816
  );
522
817
  const filters = toSvgFilters( mergedConfig, blockSelectors );
523
- setStylesheets( [
818
+ const stylesheets = [
524
819
  {
525
820
  css: customProperties,
526
821
  isGlobalStyles: true,
@@ -529,10 +824,13 @@ export function useGlobalStylesOutput() {
529
824
  css: globalStyles,
530
825
  isGlobalStyles: true,
531
826
  },
532
- ] );
533
- setSettings( mergedConfig.settings );
534
- setSvgFilters( filters );
535
- }, [ mergedConfig ] );
536
-
537
- return [ stylesheets, settings, svgFilters, hasBlockGapSupport ];
827
+ ];
828
+
829
+ return [ stylesheets, mergedConfig.settings, filters ];
830
+ }, [
831
+ hasBlockGapSupport,
832
+ hasFallbackGapSupport,
833
+ mergedConfig,
834
+ disableLayoutStyles,
835
+ ] );
538
836
  }