@wordpress/block-editor 11.6.0 → 11.7.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 (193) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +4 -0
  3. package/build/components/block-list/block-html.js +1 -3
  4. package/build/components/block-list/block-html.js.map +1 -1
  5. package/build/components/block-preview/auto.js +6 -23
  6. package/build/components/block-preview/auto.js.map +1 -1
  7. package/build/components/editor-styles/index.js +20 -2
  8. package/build/components/editor-styles/index.js.map +1 -1
  9. package/build/components/global-styles/color-panel.js +583 -0
  10. package/build/components/global-styles/color-panel.js.map +1 -0
  11. package/build/components/global-styles/dimensions-panel.js +8 -30
  12. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  13. package/build/components/global-styles/get-block-css-selector.js +129 -0
  14. package/build/components/global-styles/get-block-css-selector.js.map +1 -0
  15. package/build/components/global-styles/hooks.js +53 -1
  16. package/build/components/global-styles/hooks.js.map +1 -1
  17. package/build/components/global-styles/index.js +18 -2
  18. package/build/components/global-styles/index.js.map +1 -1
  19. package/build/components/global-styles/typography-panel.js +9 -35
  20. package/build/components/global-styles/typography-panel.js.map +1 -1
  21. package/build/components/global-styles/use-global-styles-output.js +160 -86
  22. package/build/components/global-styles/use-global-styles-output.js.map +1 -1
  23. package/build/components/global-styles/utils.js +2 -1
  24. package/build/components/global-styles/utils.js.map +1 -1
  25. package/build/components/image-size-control/index.js +8 -5
  26. package/build/components/image-size-control/index.js.map +1 -1
  27. package/build/components/inspector-controls-tabs/position-controls-panel.js +43 -7
  28. package/build/components/inspector-controls-tabs/position-controls-panel.js.map +1 -1
  29. package/build/components/line-height-control/index.js +15 -1
  30. package/build/components/line-height-control/index.js.map +1 -1
  31. package/build/components/list-view/appender.js +105 -0
  32. package/build/components/list-view/appender.js.map +1 -0
  33. package/build/components/list-view/block.js +5 -5
  34. package/build/components/list-view/block.js.map +1 -1
  35. package/build/components/list-view/branch.js +25 -5
  36. package/build/components/list-view/branch.js.map +1 -1
  37. package/build/components/list-view/index.js +37 -13
  38. package/build/components/list-view/index.js.map +1 -1
  39. package/build/components/media-replace-flow/index.js +13 -4
  40. package/build/components/media-replace-flow/index.js.map +1 -1
  41. package/build/components/rich-text/format-edit.js +2 -30
  42. package/build/components/rich-text/format-edit.js.map +1 -1
  43. package/build/components/writing-flow/use-input.js +4 -8
  44. package/build/components/writing-flow/use-input.js.map +1 -1
  45. package/build/hooks/border.js +0 -1
  46. package/build/hooks/border.js.map +1 -1
  47. package/build/hooks/color.js +92 -229
  48. package/build/hooks/color.js.map +1 -1
  49. package/build/hooks/content-lock-ui.js +4 -2
  50. package/build/hooks/content-lock-ui.js.map +1 -1
  51. package/build/hooks/{color-panel.js → contrast-checker.js} +11 -49
  52. package/build/hooks/contrast-checker.js.map +1 -0
  53. package/build/hooks/dimensions.js +0 -1
  54. package/build/hooks/dimensions.js.map +1 -1
  55. package/build/hooks/duotone.js +3 -1
  56. package/build/hooks/duotone.js.map +1 -1
  57. package/build/hooks/position.js +2 -2
  58. package/build/hooks/position.js.map +1 -1
  59. package/build/hooks/style.js +23 -26
  60. package/build/hooks/style.js.map +1 -1
  61. package/build/hooks/typography.js +0 -1
  62. package/build/hooks/typography.js.map +1 -1
  63. package/build/hooks/utils.js +25 -76
  64. package/build/hooks/utils.js.map +1 -1
  65. package/build/layouts/grid.js +165 -0
  66. package/build/layouts/grid.js.map +1 -0
  67. package/build/layouts/index.js +3 -1
  68. package/build/layouts/index.js.map +1 -1
  69. package/build/private-apis.js +4 -1
  70. package/build/private-apis.js.map +1 -1
  71. package/build/utils/object.js +76 -0
  72. package/build/utils/object.js.map +1 -0
  73. package/build-module/components/block-list/block-html.js +1 -3
  74. package/build-module/components/block-list/block-html.js.map +1 -1
  75. package/build-module/components/block-preview/auto.js +6 -22
  76. package/build-module/components/block-preview/auto.js.map +1 -1
  77. package/build-module/components/editor-styles/index.js +19 -2
  78. package/build-module/components/editor-styles/index.js.map +1 -1
  79. package/build-module/components/global-styles/color-panel.js +554 -0
  80. package/build-module/components/global-styles/color-panel.js.map +1 -0
  81. package/build-module/components/global-styles/dimensions-panel.js +7 -30
  82. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  83. package/build-module/components/global-styles/get-block-css-selector.js +120 -0
  84. package/build-module/components/global-styles/get-block-css-selector.js.map +1 -0
  85. package/build-module/components/global-styles/hooks.js +51 -1
  86. package/build-module/components/global-styles/hooks.js.map +1 -1
  87. package/build-module/components/global-styles/index.js +3 -1
  88. package/build-module/components/global-styles/index.js.map +1 -1
  89. package/build-module/components/global-styles/typography-panel.js +8 -35
  90. package/build-module/components/global-styles/typography-panel.js.map +1 -1
  91. package/build-module/components/global-styles/use-global-styles-output.js +161 -87
  92. package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
  93. package/build-module/components/global-styles/utils.js +2 -1
  94. package/build-module/components/global-styles/utils.js.map +1 -1
  95. package/build-module/components/image-size-control/index.js +8 -5
  96. package/build-module/components/image-size-control/index.js.map +1 -1
  97. package/build-module/components/inspector-controls-tabs/position-controls-panel.js +42 -7
  98. package/build-module/components/inspector-controls-tabs/position-controls-panel.js.map +1 -1
  99. package/build-module/components/line-height-control/index.js +15 -1
  100. package/build-module/components/line-height-control/index.js.map +1 -1
  101. package/build-module/components/list-view/appender.js +88 -0
  102. package/build-module/components/list-view/appender.js.map +1 -0
  103. package/build-module/components/list-view/block.js +5 -4
  104. package/build-module/components/list-view/block.js.map +1 -1
  105. package/build-module/components/list-view/branch.js +22 -5
  106. package/build-module/components/list-view/branch.js.map +1 -1
  107. package/build-module/components/list-view/index.js +32 -12
  108. package/build-module/components/list-view/index.js.map +1 -1
  109. package/build-module/components/media-replace-flow/index.js +12 -4
  110. package/build-module/components/media-replace-flow/index.js.map +1 -1
  111. package/build-module/components/rich-text/format-edit.js +3 -31
  112. package/build-module/components/rich-text/format-edit.js.map +1 -1
  113. package/build-module/components/writing-flow/use-input.js +4 -8
  114. package/build-module/components/writing-flow/use-input.js.map +1 -1
  115. package/build-module/hooks/border.js +0 -1
  116. package/build-module/hooks/border.js.map +1 -1
  117. package/build-module/hooks/color.js +90 -232
  118. package/build-module/hooks/color.js.map +1 -1
  119. package/build-module/hooks/content-lock-ui.js +4 -2
  120. package/build-module/hooks/content-lock-ui.js.map +1 -1
  121. package/build-module/hooks/{color-panel.js → contrast-checker.js} +10 -44
  122. package/build-module/hooks/contrast-checker.js.map +1 -0
  123. package/build-module/hooks/dimensions.js +0 -1
  124. package/build-module/hooks/dimensions.js.map +1 -1
  125. package/build-module/hooks/duotone.js +4 -2
  126. package/build-module/hooks/duotone.js.map +1 -1
  127. package/build-module/hooks/position.js +3 -3
  128. package/build-module/hooks/position.js.map +1 -1
  129. package/build-module/hooks/style.js +23 -26
  130. package/build-module/hooks/style.js.map +1 -1
  131. package/build-module/hooks/typography.js +0 -1
  132. package/build-module/hooks/typography.js.map +1 -1
  133. package/build-module/hooks/utils.js +23 -73
  134. package/build-module/hooks/utils.js.map +1 -1
  135. package/build-module/layouts/grid.js +151 -0
  136. package/build-module/layouts/grid.js.map +1 -0
  137. package/build-module/layouts/index.js +2 -1
  138. package/build-module/layouts/index.js.map +1 -1
  139. package/build-module/private-apis.js +3 -1
  140. package/build-module/private-apis.js.map +1 -1
  141. package/build-module/utils/object.js +69 -0
  142. package/build-module/utils/object.js.map +1 -0
  143. package/build-style/style-rtl.css +26 -6
  144. package/build-style/style.css +26 -6
  145. package/package.json +31 -31
  146. package/src/components/block-draggable/content.scss +1 -1
  147. package/src/components/block-list/block-html.js +1 -1
  148. package/src/components/block-preview/auto.js +2 -17
  149. package/src/components/colors-gradients/style.scss +8 -8
  150. package/src/components/editor-styles/index.js +29 -1
  151. package/src/components/global-styles/color-panel.js +706 -0
  152. package/src/components/global-styles/dimensions-panel.js +13 -42
  153. package/src/components/global-styles/get-block-css-selector.js +129 -0
  154. package/src/components/global-styles/hooks.js +80 -0
  155. package/src/components/global-styles/index.js +2 -1
  156. package/src/components/global-styles/test/use-global-styles-output.js +30 -1
  157. package/src/components/global-styles/typography-panel.js +26 -51
  158. package/src/components/global-styles/use-global-styles-output.js +163 -80
  159. package/src/components/global-styles/utils.js +3 -0
  160. package/src/components/image-size-control/index.js +4 -3
  161. package/src/components/image-size-control/test/index.js +2 -2
  162. package/src/components/inner-blocks/README.md +1 -1
  163. package/src/components/inspector-controls-tabs/position-controls-panel.js +40 -9
  164. package/src/components/line-height-control/index.js +10 -1
  165. package/src/components/list-view/appender.js +101 -0
  166. package/src/components/list-view/block.js +5 -4
  167. package/src/components/list-view/branch.js +30 -1
  168. package/src/components/list-view/index.js +43 -10
  169. package/src/components/list-view/style.scss +19 -0
  170. package/src/components/media-replace-flow/index.js +36 -24
  171. package/src/components/media-replace-flow/style.scss +5 -2
  172. package/src/components/rich-text/format-edit.js +2 -32
  173. package/src/components/writing-flow/use-input.js +4 -5
  174. package/src/hooks/border.js +0 -1
  175. package/src/hooks/color.js +120 -296
  176. package/src/hooks/content-lock-ui.js +6 -2
  177. package/src/hooks/{color-panel.js → contrast-checker.js} +10 -46
  178. package/src/hooks/dimensions.js +0 -1
  179. package/src/hooks/duotone.js +8 -5
  180. package/src/hooks/position.js +3 -3
  181. package/src/hooks/style.js +29 -28
  182. package/src/hooks/test/utils.js +0 -104
  183. package/src/hooks/typography.js +0 -1
  184. package/src/hooks/utils.js +27 -70
  185. package/src/layouts/grid.js +172 -0
  186. package/src/layouts/index.js +2 -1
  187. package/src/layouts/test/grid.js +21 -0
  188. package/src/private-apis.js +2 -0
  189. package/src/utils/object.js +69 -0
  190. package/src/utils/test/object.js +107 -0
  191. package/tsconfig.tsbuildinfo +1 -1
  192. package/build/hooks/color-panel.js.map +0 -1
  193. package/build-module/hooks/color-panel.js.map +0 -1
@@ -13,13 +13,14 @@ import {
13
13
  store as blocksStore,
14
14
  } from '@wordpress/blocks';
15
15
  import { useSelect } from '@wordpress/data';
16
- import { useContext, useMemo } from '@wordpress/element';
16
+ import { renderToString, useContext, useMemo } from '@wordpress/element';
17
17
  import { getCSSRules } from '@wordpress/style-engine';
18
18
 
19
19
  /**
20
20
  * Internal dependencies
21
21
  */
22
22
  import { PRESET_METADATA, ROOT_BLOCK_SELECTOR, scopeSelector } from './utils';
23
+ import { getBlockCSSSelector } from './get-block-css-selector';
23
24
  import { getTypographyFontSizeValue } from './typography-utils';
24
25
  import { GlobalStylesContext } from './context';
25
26
  import { useGlobalSetting } from './hooks';
@@ -144,13 +145,16 @@ function getPresetsSvgFilters( blockPresets = {} ) {
144
145
  return [ 'default', 'theme' ]
145
146
  .filter( ( origin ) => presetByOrigin[ origin ] )
146
147
  .flatMap( ( origin ) =>
147
- presetByOrigin[ origin ].map( ( preset ) => (
148
- <PresetDuotoneFilter
149
- preset={ preset }
150
- key={ preset.slug }
151
- />
152
- ) )
153
- );
148
+ presetByOrigin[ origin ].map( ( preset ) =>
149
+ renderToString(
150
+ <PresetDuotoneFilter
151
+ preset={ preset }
152
+ key={ preset.slug }
153
+ />
154
+ )
155
+ )
156
+ )
157
+ .join( '' );
154
158
  } );
155
159
  }
156
160
 
@@ -193,6 +197,89 @@ function concatFeatureVariationSelectorString(
193
197
  return combinedSelectors.join( ', ' );
194
198
  }
195
199
 
200
+ /**
201
+ * Generate style declarations for a block's custom feature and subfeature
202
+ * selectors.
203
+ *
204
+ * NOTE: The passed `styles` object will be mutated by this function.
205
+ *
206
+ * @param {Object} selectors Custom selectors object for a block.
207
+ * @param {Object} styles A block's styles object.
208
+ *
209
+ * @return {Object} Style declarations.
210
+ */
211
+ const getFeatureDeclarations = ( selectors, styles ) => {
212
+ const declarations = {};
213
+
214
+ Object.entries( selectors ).forEach( ( [ feature, selector ] ) => {
215
+ // We're only processing features/subfeatures that have styles.
216
+ if ( feature === 'root' || ! styles?.[ feature ] ) {
217
+ return;
218
+ }
219
+
220
+ const isShorthand = typeof selector === 'string';
221
+
222
+ // If we have a selector object instead of shorthand process it.
223
+ if ( ! isShorthand ) {
224
+ Object.entries( selector ).forEach(
225
+ ( [ subfeature, subfeatureSelector ] ) => {
226
+ // Don't process root feature selector yet or any
227
+ // subfeature that doesn't have a style.
228
+ if (
229
+ subfeature === 'root' ||
230
+ ! styles?.[ feature ][ subfeature ]
231
+ ) {
232
+ return;
233
+ }
234
+
235
+ // Create a temporary styles object and build
236
+ // declarations for subfeature.
237
+ const subfeatureStyles = {
238
+ [ feature ]: {
239
+ [ subfeature ]: styles[ feature ][ subfeature ],
240
+ },
241
+ };
242
+ const newDeclarations =
243
+ getStylesDeclarations( subfeatureStyles );
244
+
245
+ // Merge new declarations in with any others that
246
+ // share the same selector.
247
+ declarations[ subfeatureSelector ] = [
248
+ ...( declarations[ subfeatureSelector ] || [] ),
249
+ ...newDeclarations,
250
+ ];
251
+
252
+ // Remove the subfeature's style now it will be
253
+ // included under its own selector not the block's.
254
+ delete styles[ feature ][ subfeature ];
255
+ }
256
+ );
257
+ }
258
+
259
+ // Now subfeatures have been processed and removed, we can
260
+ // process root, or shorthand, feature selectors.
261
+ if ( isShorthand || selector.root ) {
262
+ const featureSelector = isShorthand ? selector : selector.root;
263
+
264
+ // Create temporary style object and build declarations for feature.
265
+ const featureStyles = { [ feature ]: styles[ feature ] };
266
+ const newDeclarations = getStylesDeclarations( featureStyles );
267
+
268
+ // Merge new declarations with any others that share the selector.
269
+ declarations[ featureSelector ] = [
270
+ ...( declarations[ featureSelector ] || [] ),
271
+ ...newDeclarations,
272
+ ];
273
+
274
+ // Remove the feature from the block's styles now as it will be
275
+ // included under its own selector not the block's.
276
+ delete styles[ feature ];
277
+ }
278
+ } );
279
+
280
+ return declarations;
281
+ };
282
+
196
283
  /**
197
284
  * Transform given style tree into a set of style declarations.
198
285
  *
@@ -692,23 +779,16 @@ export const toStyles = (
692
779
  // Process styles for block support features with custom feature level
693
780
  // CSS selectors set.
694
781
  if ( featureSelectors ) {
695
- Object.entries( featureSelectors ).forEach(
696
- ( [ featureName, featureSelector ] ) => {
697
- if ( styles?.[ featureName ] ) {
698
- const featureStyles = {
699
- [ featureName ]: styles[ featureName ],
700
- };
701
- const featureDeclarations =
702
- getStylesDeclarations( featureStyles );
703
- delete styles[ featureName ];
704
-
705
- if ( !! featureDeclarations.length ) {
706
- ruleset =
707
- ruleset +
708
- `${ featureSelector }{${ featureDeclarations.join(
709
- ';'
710
- ) } }`;
711
- }
782
+ const featureDeclarations = getFeatureDeclarations(
783
+ featureSelectors,
784
+ styles
785
+ );
786
+
787
+ Object.entries( featureDeclarations ).forEach(
788
+ ( [ cssSelector, declarations ] ) => {
789
+ if ( !! declarations.length ) {
790
+ const rules = declarations.join( ';' );
791
+ ruleset = ruleset + `${ cssSelector }{${ rules }}`;
712
792
  }
713
793
  }
714
794
  );
@@ -720,43 +800,32 @@ export const toStyles = (
720
800
  if ( styles?.variations?.[ styleVariationName ] ) {
721
801
  // If the block uses any custom selectors for block support, add those first.
722
802
  if ( featureSelectors ) {
723
- Object.entries( featureSelectors ).forEach(
724
- ( [ featureName, featureSelector ] ) => {
725
- if (
726
- styles?.variations?.[
727
- styleVariationName
728
- ]?.[ featureName ]
729
- ) {
730
- const featureStyles = {
731
- [ featureName ]:
732
- styles.variations[
733
- styleVariationName
734
- ][ featureName ],
735
- };
736
- const featureDeclarations =
737
- getStylesDeclarations(
738
- featureStyles
803
+ const featureDeclarations =
804
+ getFeatureDeclarations(
805
+ featureSelectors,
806
+ styles?.variations?.[
807
+ styleVariationName
808
+ ]
809
+ );
810
+
811
+ Object.entries( featureDeclarations ).forEach(
812
+ ( [ baseSelector, declarations ] ) => {
813
+ if ( !! declarations.length ) {
814
+ const cssSelector =
815
+ concatFeatureVariationSelectorString(
816
+ baseSelector,
817
+ styleVariationSelector
739
818
  );
740
- delete styles.variations[
741
- styleVariationName
742
- ][ featureName ];
743
-
744
- if (
745
- !! featureDeclarations.length
746
- ) {
747
- ruleset =
748
- ruleset +
749
- `${ concatFeatureVariationSelectorString(
750
- featureSelector,
751
- styleVariationSelector
752
- ) }{${ featureDeclarations.join(
753
- ';'
754
- ) } }`;
755
- }
819
+ const rules =
820
+ declarations.join( ';' );
821
+ ruleset =
822
+ ruleset +
823
+ `${ cssSelector }{${ rules }}`;
756
824
  }
757
825
  }
758
826
  );
759
827
  }
828
+
760
829
  // Otherwise add regular selectors.
761
830
  const styleVariationDeclarations =
762
831
  getStylesDeclarations(
@@ -907,15 +976,37 @@ export function toSvgFilters( tree, blockSelectors ) {
907
976
  } );
908
977
  }
909
978
 
979
+ const getSelectorsConfig = ( blockType, rootSelector ) => {
980
+ if ( ! isEmpty( blockType?.selectors ) ) {
981
+ return blockType.selectors;
982
+ }
983
+
984
+ const config = { root: rootSelector };
985
+ Object.entries( BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS ).forEach(
986
+ ( [ featureKey, featureName ] ) => {
987
+ const featureSelector = getBlockCSSSelector(
988
+ blockType,
989
+ featureKey
990
+ );
991
+
992
+ if ( featureSelector ) {
993
+ config[ featureName ] = featureSelector;
994
+ }
995
+ }
996
+ );
997
+
998
+ return config;
999
+ };
1000
+
910
1001
  export const getBlockSelectors = ( blockTypes, getBlockStyles ) => {
911
1002
  const result = {};
912
1003
  blockTypes.forEach( ( blockType ) => {
913
1004
  const name = blockType.name;
914
- const selector =
915
- blockType?.supports?.__experimentalSelector ??
916
- '.wp-block-' + name.replace( 'core/', '' ).replace( '/', '-' );
917
- const duotoneSelector =
918
- blockType?.supports?.color?.__experimentalDuotone ?? null;
1005
+ const selector = getBlockCSSSelector( blockType, 'root' );
1006
+ const duotoneSelector = getBlockCSSSelector(
1007
+ blockType,
1008
+ 'filter.duotone'
1009
+ );
919
1010
  const hasLayoutSupport = !! blockType?.supports?.__experimentalLayout;
920
1011
  const fallbackGapValue =
921
1012
  blockType?.supports?.spacing?.blockGap?.__experimentalDefault;
@@ -930,20 +1021,7 @@ export const getBlockSelectors = ( blockTypes, getBlockStyles ) => {
930
1021
  } );
931
1022
  }
932
1023
  // For each block support feature add any custom selectors.
933
- const featureSelectors = {};
934
- Object.entries( BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS ).forEach(
935
- ( [ featureKey, featureName ] ) => {
936
- const featureSelector =
937
- blockType?.supports?.[ featureKey ]?.__experimentalSelector;
938
-
939
- if ( featureSelector ) {
940
- featureSelectors[ featureName ] = scopeSelector(
941
- selector,
942
- featureSelector
943
- );
944
- }
945
- }
946
- );
1024
+ const featureSelectors = getSelectorsConfig( blockType, selector );
947
1025
 
948
1026
  result[ name ] = {
949
1027
  duotoneSelector,
@@ -1049,9 +1127,9 @@ export function useGlobalStylesOutput() {
1049
1127
  hasFallbackGapSupport,
1050
1128
  disableLayoutStyles
1051
1129
  );
1130
+ const svgs = toSvgFilters( mergedConfig, blockSelectors );
1052
1131
 
1053
- const filters = toSvgFilters( mergedConfig, blockSelectors );
1054
- const stylesheets = [
1132
+ const styles = [
1055
1133
  {
1056
1134
  css: customProperties,
1057
1135
  isGlobalStyles: true,
@@ -1065,6 +1143,11 @@ export function useGlobalStylesOutput() {
1065
1143
  css: mergedConfig.styles.css ?? '',
1066
1144
  isGlobalStyles: true,
1067
1145
  },
1146
+ {
1147
+ assets: svgs,
1148
+ __unstableType: 'svg',
1149
+ isGlobalStyles: true,
1150
+ },
1068
1151
  ];
1069
1152
 
1070
1153
  // Loop through the blocks to check if there are custom CSS values.
@@ -1073,7 +1156,7 @@ export function useGlobalStylesOutput() {
1073
1156
  getBlockTypes().forEach( ( blockType ) => {
1074
1157
  if ( mergedConfig.styles.blocks[ blockType.name ]?.css ) {
1075
1158
  const selector = blockSelectors[ blockType.name ].selector;
1076
- stylesheets.push( {
1159
+ styles.push( {
1077
1160
  css: processCSSNesting(
1078
1161
  mergedConfig.styles.blocks[ blockType.name ]?.css,
1079
1162
  selector
@@ -1083,7 +1166,7 @@ export function useGlobalStylesOutput() {
1083
1166
  }
1084
1167
  } );
1085
1168
 
1086
- return [ stylesheets, mergedConfig.settings, filters ];
1169
+ return [ styles, mergedConfig.settings ];
1087
1170
  }, [
1088
1171
  hasBlockGapSupport,
1089
1172
  hasFallbackGapSupport,
@@ -16,7 +16,9 @@ export const ROOT_BLOCK_SUPPORTS = [
16
16
  'backgroundColor',
17
17
  'color',
18
18
  'linkColor',
19
+ 'captionColor',
19
20
  'buttonColor',
21
+ 'headingColor',
20
22
  'fontFamily',
21
23
  'fontSize',
22
24
  'fontStyle',
@@ -103,6 +105,7 @@ export const STYLE_PATH_TO_CSS_VAR_INFIX = {
103
105
  'elements.link.typography.fontSize': 'font-size',
104
106
  'elements.button.color.text': 'color',
105
107
  'elements.button.color.background': 'color',
108
+ 'elements.caption.color.text': 'color',
106
109
  'elements.button.typography.fontFamily': 'font-family',
107
110
  'elements.button.typography.fontSize': 'font-size',
108
111
  'elements.heading.color': 'color',
@@ -38,17 +38,16 @@ export default function ImageSizeControl( {
38
38
  { imageSizeOptions && imageSizeOptions.length > 0 && (
39
39
  <SelectControl
40
40
  __nextHasNoMarginBottom
41
- label={ __( 'Image size' ) }
41
+ label={ __( 'Resolution' ) }
42
42
  value={ slug }
43
43
  options={ imageSizeOptions }
44
44
  onChange={ onChangeImage }
45
45
  help={ imageSizeHelp }
46
+ size="__unstable-large"
46
47
  />
47
48
  ) }
48
49
  { isResizable && (
49
50
  <div className="block-editor-image-size-control">
50
- <p>{ __( 'Image dimensions' ) }</p>
51
-
52
51
  <HStack align="baseline" spacing="3">
53
52
  <NumberControl
54
53
  className="block-editor-image-size-control__width"
@@ -58,6 +57,7 @@ export default function ImageSizeControl( {
58
57
  onChange={ ( value ) =>
59
58
  updateDimension( 'width', value )
60
59
  }
60
+ size="__unstable-large"
61
61
  />
62
62
  <NumberControl
63
63
  className="block-editor-image-size-control__height"
@@ -67,6 +67,7 @@ export default function ImageSizeControl( {
67
67
  onChange={ ( value ) =>
68
68
  updateDimension( 'height', value )
69
69
  }
70
+ size="__unstable-large"
70
71
  />
71
72
  </HStack>
72
73
  <HStack>
@@ -334,7 +334,7 @@ describe( 'ImageSizeControl', () => {
334
334
  );
335
335
 
336
336
  expect(
337
- screen.getByRole( 'combobox', { name: 'Image size' } )
337
+ screen.getByRole( 'combobox', { name: 'Resolution' } )
338
338
  ).toHaveValue( 'medium' );
339
339
  } );
340
340
 
@@ -351,7 +351,7 @@ describe( 'ImageSizeControl', () => {
351
351
  );
352
352
 
353
353
  await user.selectOptions(
354
- screen.getByRole( 'combobox', { name: 'Image size' } ),
354
+ screen.getByRole( 'combobox', { name: 'Resolution' } ),
355
355
  'thumbnail'
356
356
  );
357
357
 
@@ -130,7 +130,7 @@ _Options:_
130
130
  - `'insert'` — prevents inserting or removing blocks, but allows moving existing ones.
131
131
  - `false` — prevents locking from being applied to an `InnerBlocks` area even if a parent block contains locking. ( Boolean )
132
132
 
133
- If locking is not set in an `InnerBlocks` area: the locking of the parent `InnerBlocks` area is used. Note that `contentOnly` can't be overriden: it's present, the `templateLock` value of any children is ignored.
133
+ If locking is not set in an `InnerBlocks` area: the locking of the parent `InnerBlocks` area is used. Note that `contentOnly` can't be overridden: it's present, the `templateLock` value of any children is ignored.
134
134
 
135
135
  If the block is a top level block: the locking of the Custom Post Type is used.
136
136
 
@@ -5,6 +5,8 @@ import {
5
5
  PanelBody,
6
6
  __experimentalUseSlotFills as useSlotFills,
7
7
  } from '@wordpress/components';
8
+ import { useSelect } from '@wordpress/data';
9
+ import { useLayoutEffect, useState } from '@wordpress/element';
8
10
  import { __ } from '@wordpress/i18n';
9
11
 
10
12
  /**
@@ -12,26 +14,55 @@ import { __ } from '@wordpress/i18n';
12
14
  */
13
15
  import InspectorControlsGroups from '../inspector-controls/groups';
14
16
  import { default as InspectorControls } from '../inspector-controls';
17
+ import { store as blockEditorStore } from '../../store';
15
18
 
16
- const PositionControls = () => {
17
- const fills = useSlotFills(
18
- InspectorControlsGroups.position.Slot.__unstableName
19
- );
20
- const hasFills = Boolean( fills && fills.length );
19
+ const PositionControlsPanel = () => {
20
+ const [ initialOpen, setInitialOpen ] = useState();
21
21
 
22
- if ( ! hasFills ) {
23
- return null;
24
- }
22
+ // Determine whether the panel should be expanded.
23
+ const { multiSelectedBlocks } = useSelect( ( select ) => {
24
+ const { getBlocksByClientId, getSelectedBlockClientIds } =
25
+ select( blockEditorStore );
26
+ const clientIds = getSelectedBlockClientIds();
27
+ return {
28
+ multiSelectedBlocks: getBlocksByClientId( clientIds ),
29
+ };
30
+ }, [] );
31
+
32
+ useLayoutEffect( () => {
33
+ // If any selected block has a position set, open the panel by default.
34
+ // The first block's value will still be used within the control though.
35
+ if ( initialOpen === undefined ) {
36
+ setInitialOpen(
37
+ multiSelectedBlocks.some(
38
+ ( { attributes } ) => !! attributes?.style?.position?.type
39
+ )
40
+ );
41
+ }
42
+ }, [ initialOpen, multiSelectedBlocks, setInitialOpen ] );
25
43
 
26
44
  return (
27
45
  <PanelBody
28
46
  className="block-editor-block-inspector__position"
29
47
  title={ __( 'Position' ) }
30
- initialOpen={ false }
48
+ initialOpen={ initialOpen ?? false }
31
49
  >
32
50
  <InspectorControls.Slot group="position" />
33
51
  </PanelBody>
34
52
  );
35
53
  };
36
54
 
55
+ const PositionControls = () => {
56
+ const fills = useSlotFills(
57
+ InspectorControlsGroups.position.Slot.__unstableName
58
+ );
59
+ const hasFills = Boolean( fills && fills.length );
60
+
61
+ if ( ! hasFills ) {
62
+ return null;
63
+ }
64
+
65
+ return <PositionControlsPanel />;
66
+ };
67
+
37
68
  export default PositionControls;
@@ -84,6 +84,15 @@ const LineHeightControl = ( {
84
84
  ? undefined
85
85
  : { marginBottom: 24 };
86
86
 
87
+ const handleOnChange = ( nextValue, { event } ) => {
88
+ if ( event.type === 'click' ) {
89
+ onChange( adjustNextValue( nextValue, false ) );
90
+ return;
91
+ }
92
+
93
+ onChange( nextValue );
94
+ };
95
+
87
96
  return (
88
97
  <div
89
98
  className="block-editor-line-height-control"
@@ -93,7 +102,7 @@ const LineHeightControl = ( {
93
102
  { ...otherProps }
94
103
  __unstableInputWidth={ __unstableInputWidth }
95
104
  __unstableStateReducer={ stateReducer }
96
- onChange={ onChange }
105
+ onChange={ handleOnChange }
97
106
  label={ __( 'Line height' ) }
98
107
  placeholder={ BASE_DEFAULT_VALUE }
99
108
  step={ STEP }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useInstanceId } from '@wordpress/compose';
5
+ import { speak } from '@wordpress/a11y';
6
+ import { useSelect } from '@wordpress/data';
7
+ import { forwardRef, useState, useEffect } from '@wordpress/element';
8
+ import { __, sprintf } from '@wordpress/i18n';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { store as blockEditorStore } from '../../store';
14
+ import useBlockDisplayTitle from '../block-title/use-block-display-title';
15
+ import Inserter from '../inserter';
16
+
17
+ export const Appender = forwardRef(
18
+ ( { nestingLevel, blockCount, clientId, ...props }, ref ) => {
19
+ const [ insertedBlock, setInsertedBlock ] = useState( null );
20
+
21
+ const instanceId = useInstanceId( Appender );
22
+ const { hideInserter } = useSelect(
23
+ ( select ) => {
24
+ const { getTemplateLock, __unstableGetEditorMode } =
25
+ select( blockEditorStore );
26
+
27
+ return {
28
+ hideInserter:
29
+ !! getTemplateLock( clientId ) ||
30
+ __unstableGetEditorMode() === 'zoom-out',
31
+ };
32
+ },
33
+ [ clientId ]
34
+ );
35
+
36
+ const blockTitle = useBlockDisplayTitle( {
37
+ clientId,
38
+ context: 'list-view',
39
+ } );
40
+
41
+ const insertedBlockTitle = useBlockDisplayTitle( {
42
+ clientId: insertedBlock?.clientId,
43
+ context: 'list-view',
44
+ } );
45
+
46
+ useEffect( () => {
47
+ if ( ! insertedBlockTitle?.length ) {
48
+ return;
49
+ }
50
+
51
+ speak(
52
+ sprintf(
53
+ // translators: %s: name of block being inserted (i.e. Paragraph, Image, Group etc)
54
+ __( '%s block inserted' ),
55
+ insertedBlockTitle
56
+ ),
57
+ 'assertive'
58
+ );
59
+ }, [ insertedBlockTitle ] );
60
+
61
+ if ( hideInserter ) {
62
+ return null;
63
+ }
64
+
65
+ const descriptionId = `list-view-appender__${ instanceId }`;
66
+ const description = sprintf(
67
+ /* translators: 1: The name of the block. 2: The numerical position of the block. 3: The level of nesting for the block. */
68
+ __( 'Append to %1$s block at position %2$d, Level %3$d' ),
69
+ blockTitle,
70
+ blockCount + 1,
71
+ nestingLevel
72
+ );
73
+
74
+ return (
75
+ <div className="list-view-appender">
76
+ <Inserter
77
+ ref={ ref }
78
+ rootClientId={ clientId }
79
+ position="bottom right"
80
+ isAppender
81
+ selectBlockOnInsert={ false }
82
+ shouldDirectInsert={ false }
83
+ __experimentalIsQuick
84
+ { ...props }
85
+ toggleProps={ { 'aria-describedby': descriptionId } }
86
+ onSelectOrClose={ ( maybeInsertedBlock ) => {
87
+ if ( maybeInsertedBlock?.clientId ) {
88
+ setInsertedBlock( maybeInsertedBlock );
89
+ }
90
+ } }
91
+ />
92
+ <div
93
+ className="list-view-appender__description"
94
+ id={ descriptionId }
95
+ >
96
+ { description }
97
+ </div>
98
+ </div>
99
+ );
100
+ }
101
+ );
@@ -33,7 +33,6 @@ import {
33
33
  BlockMoverDownButton,
34
34
  } from '../block-mover/button';
35
35
  import ListViewBlockContents from './block-contents';
36
- import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown';
37
36
  import { useListViewContext } from './context';
38
37
  import { getBlockPositionDescription } from './utils';
39
38
  import { store as blockEditorStore } from '../../store';
@@ -135,7 +134,8 @@ function ListViewBlock( {
135
134
  )
136
135
  : __( 'Options' );
137
136
 
138
- const { isTreeGridMounted, expand, collapse } = useListViewContext();
137
+ const { isTreeGridMounted, expand, collapse, BlockSettingsMenu } =
138
+ useListViewContext();
139
139
 
140
140
  const hasSiblings = siblingBlockCount > 0;
141
141
  const hasRenderedMovers = showBlockMovers && hasSiblings;
@@ -321,14 +321,15 @@ function ListViewBlock( {
321
321
  </>
322
322
  ) }
323
323
 
324
- { showBlockActions && (
324
+ { showBlockActions && BlockSettingsMenu && (
325
325
  <TreeGridCell
326
326
  className={ listViewBlockSettingsClassName }
327
327
  aria-selected={ !! isSelected || forceSelectionContentLock }
328
328
  >
329
329
  { ( { ref, tabIndex, onFocus } ) => (
330
- <BlockSettingsDropdown
330
+ <BlockSettingsMenu
331
331
  clientIds={ dropdownClientIds }
332
+ block={ block }
332
333
  icon={ moreVertical }
333
334
  label={ settingsAriaLabel }
334
335
  toggleProps={ {