@wordpress/block-editor 12.22.0 → 12.23.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 (273) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +4 -0
  3. package/build/components/block-list/block.js +11 -3
  4. package/build/components/block-list/block.js.map +1 -1
  5. package/build/components/block-mover/button.js +4 -1
  6. package/build/components/block-mover/button.js.map +1 -1
  7. package/build/components/block-mover/index.js +5 -1
  8. package/build/components/block-mover/index.js.map +1 -1
  9. package/build/components/block-patterns-list/index.js +4 -1
  10. package/build/components/block-patterns-list/index.js.map +1 -1
  11. package/build/components/block-settings-menu/block-settings-dropdown.js +7 -3
  12. package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  13. package/build/components/block-switcher/index.js +4 -3
  14. package/build/components/block-switcher/index.js.map +1 -1
  15. package/build/components/block-toolbar/index.js +5 -4
  16. package/build/components/block-toolbar/index.js.map +1 -1
  17. package/build/components/block-toolbar/shuffle.js +18 -9
  18. package/build/components/block-toolbar/shuffle.js.map +1 -1
  19. package/build/components/block-tools/block-selection-button.js +48 -8
  20. package/build/components/block-tools/block-selection-button.js.map +1 -1
  21. package/build/components/block-tools/index.js +14 -2
  22. package/build/components/block-tools/index.js.map +1 -1
  23. package/build/components/global-styles/advanced-panel.js +9 -2
  24. package/build/components/global-styles/advanced-panel.js.map +1 -1
  25. package/build/components/global-styles/background-panel.js +444 -0
  26. package/build/components/global-styles/background-panel.js.map +1 -0
  27. package/build/components/global-styles/color-panel.js +2 -1
  28. package/build/components/global-styles/color-panel.js.map +1 -1
  29. package/build/components/global-styles/get-global-styles-changes.js +3 -0
  30. package/build/components/global-styles/get-global-styles-changes.js.map +1 -1
  31. package/build/components/global-styles/hooks.js +1 -1
  32. package/build/components/global-styles/hooks.js.map +1 -1
  33. package/build/components/global-styles/index.js +13 -0
  34. package/build/components/global-styles/index.js.map +1 -1
  35. package/build/components/global-styles/use-global-styles-output.js +15 -14
  36. package/build/components/global-styles/use-global-styles-output.js.map +1 -1
  37. package/build/components/global-styles/utils.js +2 -1
  38. package/build/components/global-styles/utils.js.map +1 -1
  39. package/build/components/iframe/index.js +9 -4
  40. package/build/components/iframe/index.js.map +1 -1
  41. package/build/components/inserter/block-patterns-tab/index.js.map +1 -1
  42. package/build/components/inserter/block-patterns-tab/pattern-category-preview-panel.js +5 -0
  43. package/build/components/inserter/block-patterns-tab/pattern-category-preview-panel.js.map +1 -1
  44. package/build/components/inserter/library.js +2 -0
  45. package/build/components/inserter/library.js.map +1 -1
  46. package/build/components/inserter/menu.js +8 -2
  47. package/build/components/inserter/menu.js.map +1 -1
  48. package/build/components/inserter/search-items.js +36 -15
  49. package/build/components/inserter/search-items.js.map +1 -1
  50. package/build/components/keyboard-shortcuts/index.js +11 -0
  51. package/build/components/keyboard-shortcuts/index.js.map +1 -1
  52. package/build/components/list-view/block-select-button.js +16 -0
  53. package/build/components/list-view/block-select-button.js.map +1 -1
  54. package/build/components/list-view/block.js +1 -1
  55. package/build/components/list-view/block.js.map +1 -1
  56. package/build/components/list-view/index.js +17 -2
  57. package/build/components/list-view/index.js.map +1 -1
  58. package/build/components/list-view/use-list-view-collapse-items.js +47 -0
  59. package/build/components/list-view/use-list-view-collapse-items.js.map +1 -0
  60. package/build/components/rich-text/index.js +14 -11
  61. package/build/components/rich-text/index.js.map +1 -1
  62. package/build/components/rich-text/index.native.js +17 -11
  63. package/build/components/rich-text/index.native.js.map +1 -1
  64. package/build/components/rich-text/native/get-format-colors.native.js +1 -1
  65. package/build/components/rich-text/native/get-format-colors.native.js.map +1 -1
  66. package/build/components/rich-text/native/index.native.js +2 -2
  67. package/build/components/rich-text/native/index.native.js.map +1 -1
  68. package/build/components/rich-text/with-deprecations.js +0 -3
  69. package/build/components/rich-text/with-deprecations.js.map +1 -1
  70. package/build/components/url-popover/image-url-input-ui.js +50 -36
  71. package/build/components/url-popover/image-url-input-ui.js.map +1 -1
  72. package/build/components/use-block-display-information/index.js +4 -6
  73. package/build/components/use-block-display-information/index.js.map +1 -1
  74. package/build/hooks/anchor.js +2 -2
  75. package/build/hooks/anchor.js.map +1 -1
  76. package/build/hooks/background.js +70 -424
  77. package/build/hooks/background.js.map +1 -1
  78. package/build/hooks/index.js +7 -0
  79. package/build/hooks/index.js.map +1 -1
  80. package/build/hooks/use-zoom-out.js +47 -0
  81. package/build/hooks/use-zoom-out.js.map +1 -0
  82. package/build/index.js +7 -0
  83. package/build/index.js.map +1 -1
  84. package/build/private-apis.js +6 -1
  85. package/build/private-apis.js.map +1 -1
  86. package/build/private-apis.native.js +3 -1
  87. package/build/private-apis.native.js.map +1 -1
  88. package/build/store/private-actions.js +13 -0
  89. package/build/store/private-actions.js.map +1 -1
  90. package/build/store/private-keys.js +2 -1
  91. package/build/store/private-keys.js.map +1 -1
  92. package/build/store/private-selectors.js +24 -3
  93. package/build/store/private-selectors.js.map +1 -1
  94. package/build/store/reducer.js +22 -0
  95. package/build/store/reducer.js.map +1 -1
  96. package/build/store/selectors.js +34 -32
  97. package/build/store/selectors.js.map +1 -1
  98. package/build/store/utils.js +7 -1
  99. package/build/store/utils.js.map +1 -1
  100. package/build/utils/transform-styles/index.js +2 -1
  101. package/build/utils/transform-styles/index.js.map +1 -1
  102. package/build-module/components/block-list/block.js +11 -3
  103. package/build-module/components/block-list/block.js.map +1 -1
  104. package/build-module/components/block-mover/button.js +4 -1
  105. package/build-module/components/block-mover/button.js.map +1 -1
  106. package/build-module/components/block-mover/index.js +5 -1
  107. package/build-module/components/block-mover/index.js.map +1 -1
  108. package/build-module/components/block-patterns-list/index.js +4 -1
  109. package/build-module/components/block-patterns-list/index.js.map +1 -1
  110. package/build-module/components/block-settings-menu/block-settings-dropdown.js +7 -3
  111. package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  112. package/build-module/components/block-switcher/index.js +4 -3
  113. package/build-module/components/block-switcher/index.js.map +1 -1
  114. package/build-module/components/block-toolbar/index.js +5 -4
  115. package/build-module/components/block-toolbar/index.js.map +1 -1
  116. package/build-module/components/block-toolbar/shuffle.js +18 -9
  117. package/build-module/components/block-toolbar/shuffle.js.map +1 -1
  118. package/build-module/components/block-tools/block-selection-button.js +50 -10
  119. package/build-module/components/block-tools/block-selection-button.js.map +1 -1
  120. package/build-module/components/block-tools/index.js +14 -2
  121. package/build-module/components/block-tools/index.js.map +1 -1
  122. package/build-module/components/global-styles/advanced-panel.js +9 -2
  123. package/build-module/components/global-styles/advanced-panel.js.map +1 -1
  124. package/build-module/components/global-styles/background-panel.js +430 -0
  125. package/build-module/components/global-styles/background-panel.js.map +1 -0
  126. package/build-module/components/global-styles/color-panel.js +2 -1
  127. package/build-module/components/global-styles/color-panel.js.map +1 -1
  128. package/build-module/components/global-styles/get-global-styles-changes.js +3 -0
  129. package/build-module/components/global-styles/get-global-styles-changes.js.map +1 -1
  130. package/build-module/components/global-styles/hooks.js +1 -1
  131. package/build-module/components/global-styles/hooks.js.map +1 -1
  132. package/build-module/components/global-styles/index.js +1 -0
  133. package/build-module/components/global-styles/index.js.map +1 -1
  134. package/build-module/components/global-styles/use-global-styles-output.js +16 -15
  135. package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
  136. package/build-module/components/global-styles/utils.js +1 -0
  137. package/build-module/components/global-styles/utils.js.map +1 -1
  138. package/build-module/components/iframe/index.js +9 -4
  139. package/build-module/components/iframe/index.js.map +1 -1
  140. package/build-module/components/inserter/block-patterns-tab/index.js.map +1 -1
  141. package/build-module/components/inserter/block-patterns-tab/pattern-category-preview-panel.js +5 -0
  142. package/build-module/components/inserter/block-patterns-tab/pattern-category-preview-panel.js.map +1 -1
  143. package/build-module/components/inserter/library.js +2 -0
  144. package/build-module/components/inserter/library.js.map +1 -1
  145. package/build-module/components/inserter/menu.js +8 -2
  146. package/build-module/components/inserter/menu.js.map +1 -1
  147. package/build-module/components/inserter/search-items.js +33 -15
  148. package/build-module/components/inserter/search-items.js.map +1 -1
  149. package/build-module/components/keyboard-shortcuts/index.js +11 -0
  150. package/build-module/components/keyboard-shortcuts/index.js.map +1 -1
  151. package/build-module/components/list-view/block-select-button.js +16 -0
  152. package/build-module/components/list-view/block-select-button.js.map +1 -1
  153. package/build-module/components/list-view/block.js +1 -1
  154. package/build-module/components/list-view/block.js.map +1 -1
  155. package/build-module/components/list-view/index.js +17 -2
  156. package/build-module/components/list-view/index.js.map +1 -1
  157. package/build-module/components/list-view/use-list-view-collapse-items.js +40 -0
  158. package/build-module/components/list-view/use-list-view-collapse-items.js.map +1 -0
  159. package/build-module/components/rich-text/index.js +15 -12
  160. package/build-module/components/rich-text/index.js.map +1 -1
  161. package/build-module/components/rich-text/index.native.js +16 -11
  162. package/build-module/components/rich-text/index.native.js.map +1 -1
  163. package/build-module/components/rich-text/native/get-format-colors.native.js +1 -1
  164. package/build-module/components/rich-text/native/get-format-colors.native.js.map +1 -1
  165. package/build-module/components/rich-text/native/index.native.js +2 -2
  166. package/build-module/components/rich-text/native/index.native.js.map +1 -1
  167. package/build-module/components/rich-text/with-deprecations.js +0 -3
  168. package/build-module/components/rich-text/with-deprecations.js.map +1 -1
  169. package/build-module/components/url-popover/image-url-input-ui.js +50 -36
  170. package/build-module/components/url-popover/image-url-input-ui.js.map +1 -1
  171. package/build-module/components/use-block-display-information/index.js +5 -7
  172. package/build-module/components/use-block-display-information/index.js.map +1 -1
  173. package/build-module/hooks/anchor.js +2 -2
  174. package/build-module/hooks/anchor.js.map +1 -1
  175. package/build-module/hooks/background.js +67 -419
  176. package/build-module/hooks/background.js.map +1 -1
  177. package/build-module/hooks/index.js +1 -0
  178. package/build-module/hooks/index.js.map +1 -1
  179. package/build-module/hooks/use-zoom-out.js +41 -0
  180. package/build-module/hooks/use-zoom-out.js.map +1 -0
  181. package/build-module/index.js +1 -1
  182. package/build-module/index.js.map +1 -1
  183. package/build-module/private-apis.js +7 -2
  184. package/build-module/private-apis.js.map +1 -1
  185. package/build-module/private-apis.native.js +3 -1
  186. package/build-module/private-apis.native.js.map +1 -1
  187. package/build-module/store/private-actions.js +12 -0
  188. package/build-module/store/private-actions.js.map +1 -1
  189. package/build-module/store/private-keys.js +1 -0
  190. package/build-module/store/private-keys.js.map +1 -1
  191. package/build-module/store/private-selectors.js +22 -4
  192. package/build-module/store/private-selectors.js.map +1 -1
  193. package/build-module/store/reducer.js +21 -0
  194. package/build-module/store/reducer.js.map +1 -1
  195. package/build-module/store/selectors.js +35 -33
  196. package/build-module/store/selectors.js.map +1 -1
  197. package/build-module/store/utils.js +6 -1
  198. package/build-module/store/utils.js.map +1 -1
  199. package/build-module/utils/transform-styles/index.js +2 -1
  200. package/build-module/utils/transform-styles/index.js.map +1 -1
  201. package/build-style/content-rtl.css +4 -1
  202. package/build-style/content.css +4 -1
  203. package/build-style/style-rtl.css +84 -79
  204. package/build-style/style.css +84 -79
  205. package/package.json +31 -31
  206. package/src/components/block-list/block.js +19 -3
  207. package/src/components/block-mover/button.js +4 -1
  208. package/src/components/block-mover/index.js +8 -1
  209. package/src/components/block-patterns-list/index.js +22 -17
  210. package/src/components/block-preview/style.scss +28 -0
  211. package/src/components/block-settings-menu/block-settings-dropdown.js +8 -2
  212. package/src/components/block-switcher/index.js +5 -3
  213. package/src/components/block-switcher/style.scss +1 -1
  214. package/src/components/block-toolbar/index.js +22 -19
  215. package/src/components/block-toolbar/shuffle.js +19 -13
  216. package/src/components/block-toolbar/style.scss +1 -1
  217. package/src/components/block-tools/block-selection-button.js +66 -9
  218. package/src/components/block-tools/index.js +18 -1
  219. package/src/components/button-block-appender/content.scss +5 -1
  220. package/src/components/default-block-appender/content.scss +2 -2
  221. package/src/components/global-styles/advanced-panel.js +8 -2
  222. package/src/components/global-styles/background-panel.js +591 -0
  223. package/src/components/global-styles/color-panel.js +2 -1
  224. package/src/components/global-styles/get-global-styles-changes.js +3 -0
  225. package/src/components/global-styles/hooks.js +1 -0
  226. package/src/components/global-styles/index.js +4 -0
  227. package/src/components/global-styles/style.scss +78 -1
  228. package/src/{hooks/test/background.js → components/global-styles/test/background-panel.js} +36 -1
  229. package/src/components/global-styles/test/get-global-styles-changes.js +22 -3
  230. package/src/components/global-styles/test/use-global-styles-output.js +9 -9
  231. package/src/components/global-styles/use-global-styles-output.js +27 -16
  232. package/src/components/global-styles/utils.js +1 -0
  233. package/src/components/iframe/index.js +19 -9
  234. package/src/components/inserter/block-patterns-tab/index.js +1 -0
  235. package/src/components/inserter/block-patterns-tab/pattern-category-preview-panel.js +5 -0
  236. package/src/components/inserter/library.js +4 -0
  237. package/src/components/inserter/menu.js +8 -1
  238. package/src/components/inserter/search-items.js +37 -15
  239. package/src/components/inserter/style.scss +6 -12
  240. package/src/components/keyboard-shortcuts/index.js +11 -0
  241. package/src/components/list-view/block-select-button.js +13 -1
  242. package/src/components/list-view/block.js +1 -1
  243. package/src/components/list-view/index.js +18 -1
  244. package/src/components/list-view/style.scss +4 -4
  245. package/src/components/list-view/use-list-view-collapse-items.js +33 -0
  246. package/src/components/rich-text/index.js +30 -13
  247. package/src/components/rich-text/index.native.js +14 -11
  248. package/src/components/rich-text/native/get-format-colors.native.js +1 -1
  249. package/src/components/rich-text/native/index.native.js +2 -2
  250. package/src/components/rich-text/with-deprecations.js +0 -3
  251. package/src/components/url-popover/image-url-input-ui.js +68 -51
  252. package/src/components/use-block-display-information/index.js +8 -10
  253. package/src/hooks/anchor.js +11 -9
  254. package/src/hooks/background.js +77 -538
  255. package/src/hooks/index.js +1 -0
  256. package/src/hooks/use-zoom-out.js +36 -0
  257. package/src/index.js +1 -0
  258. package/src/private-apis.js +13 -1
  259. package/src/private-apis.native.js +2 -0
  260. package/src/store/private-actions.js +12 -0
  261. package/src/store/private-keys.js +1 -0
  262. package/src/store/private-selectors.js +54 -27
  263. package/src/store/reducer.js +22 -0
  264. package/src/store/selectors.js +195 -180
  265. package/src/store/test/private-actions.js +10 -0
  266. package/src/store/test/private-selectors.js +13 -0
  267. package/src/store/test/reducer.js +26 -0
  268. package/src/store/test/selectors.js +90 -199
  269. package/src/store/utils.js +13 -0
  270. package/src/style.scss +0 -2
  271. package/src/utils/transform-styles/index.js +2 -1
  272. package/src/hooks/anchor.scss +0 -4
  273. package/src/hooks/background.scss +0 -75
@@ -2,7 +2,7 @@
2
2
  fill: currentColor;
3
3
  }
4
4
 
5
- // @todo: Ideally, popover, swatch size, and gap values should be CSS variables
5
+ // @todo Ideally, popover, swatch size, and gap values should be CSS variables
6
6
  // to apply precise grid layouts.
7
7
  // https://github.com/WordPress/gutenberg/blob/954ecae571abbddc113d3a4bd8e1a72230180554/packages/block-editor/src/components/duotone-control/style.scss#L3-L9
8
8
  .block-editor-global-styles__shadow-popover-container {
@@ -70,3 +70,80 @@
70
70
  /*rtl:ignore*/
71
71
  direction: ltr;
72
72
  }
73
+
74
+ .block-editor-global-styles-background-panel__inspector-media-replace-container {
75
+ position: relative;
76
+ // Since there is no option to skip rendering the drag'n'drop icon in drop
77
+ // zone, we hide it for now.
78
+ .components-drop-zone__content-icon {
79
+ display: none;
80
+ }
81
+
82
+ button.components-button {
83
+ color: $gray-900;
84
+ box-shadow: inset 0 0 0 $border-width $gray-300;
85
+ width: 100%;
86
+ display: block;
87
+ height: $grid-unit-50;
88
+
89
+ &:hover {
90
+ color: var(--wp-admin-theme-color);
91
+ }
92
+
93
+ &:focus {
94
+ box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
95
+ }
96
+ }
97
+
98
+ .block-editor-global-styles-background-panel__inspector-media-replace-title {
99
+ word-break: break-all;
100
+ // The Button component is white-space: nowrap, and that won't work with line-clamp.
101
+ white-space: normal;
102
+
103
+ // Without this, the ellipsis can sometimes be partially hidden by the Button padding.
104
+ text-align: start;
105
+ text-align-last: center;
106
+ }
107
+
108
+ .components-dropdown {
109
+ display: block;
110
+ }
111
+ }
112
+
113
+ .block-editor-global-styles-background-panel__inspector-image-indicator-wrapper {
114
+ background: #fff linear-gradient(-45deg, transparent 48%, $gray-300 48%, $gray-300 52%, transparent 52%); // Show a diagonal line (crossed out) for empty background image.
115
+ border-radius: $radius-round !important; // Override the default border-radius inherited from FlexItem.
116
+ box-shadow: inset 0 0 0 $border-width rgba(0, 0, 0, 0.2);
117
+ display: block;
118
+ width: 20px;
119
+ height: 20px;
120
+ flex: none;
121
+
122
+ &.has-image {
123
+ background: #fff; // No diagonal line for non-empty background image. A background color is in use to account for partially transparent images.
124
+ }
125
+ }
126
+
127
+ .block-editor-global-styles-background-panel__inspector-image-indicator {
128
+ background-size: cover;
129
+ border-radius: $radius-round;
130
+ width: 20px;
131
+ height: 20px;
132
+ display: block;
133
+ position: relative;
134
+ }
135
+
136
+ .block-editor-global-styles-background-panel__inspector-image-indicator::after {
137
+ content: "";
138
+ position: absolute;
139
+ top: -1px;
140
+ left: -1px;
141
+ bottom: -1px;
142
+ right: -1px;
143
+ border-radius: $radius-round;
144
+ box-shadow: inset 0 0 0 $border-width rgba(0, 0, 0, 0.2);
145
+ // Show a thin outline in Windows high contrast mode, otherwise the button is invisible.
146
+ border: 1px solid transparent;
147
+ box-sizing: inherit;
148
+ }
149
+
@@ -5,7 +5,8 @@
5
5
  import {
6
6
  backgroundPositionToCoords,
7
7
  coordsToBackgroundPosition,
8
- } from '../background';
8
+ hasBackgroundImageValue,
9
+ } from '../background-panel';
9
10
 
10
11
  describe( 'backgroundPositionToCoords', () => {
11
12
  it( 'should return the correct coordinates for a percentage value using 2-value syntax', () => {
@@ -48,3 +49,37 @@ describe( 'coordsToBackgroundPosition', () => {
48
49
  expect( coordsToBackgroundPosition( {} ) ).toBeUndefined();
49
50
  } );
50
51
  } );
52
+
53
+ describe( 'hasBackgroundImageValue', () => {
54
+ it( 'should return `true` when id and url exist', () => {
55
+ expect(
56
+ hasBackgroundImageValue( {
57
+ background: { backgroundImage: { id: 1, url: 'url' } },
58
+ } )
59
+ ).toBe( true );
60
+ } );
61
+
62
+ it( 'should return `true` when only url exists', () => {
63
+ expect(
64
+ hasBackgroundImageValue( {
65
+ background: { backgroundImage: { url: 'url' } },
66
+ } )
67
+ ).toBe( true );
68
+ } );
69
+
70
+ it( 'should return `true` when only id exists', () => {
71
+ expect(
72
+ hasBackgroundImageValue( {
73
+ background: { backgroundImage: { id: 1 } },
74
+ } )
75
+ ).toBe( true );
76
+ } );
77
+
78
+ it( 'should return `false` when id and url do not exist', () => {
79
+ expect(
80
+ hasBackgroundImageValue( {
81
+ background: { backgroundImage: {} },
82
+ } )
83
+ ).toBe( false );
84
+ } );
85
+ } );
@@ -17,6 +17,15 @@ import {
17
17
  describe( 'getGlobalStylesChanges and utils', () => {
18
18
  const next = {
19
19
  styles: {
20
+ background: {
21
+ backgroundImage: {
22
+ url: 'https://example.com/image.jpg',
23
+ source: 'file',
24
+ },
25
+ backgroundSize: 'contain',
26
+ backgroundPosition: '30% 30%',
27
+ backgroundRepeat: 'no-repeat',
28
+ },
20
29
  typography: {
21
30
  fontSize: 'var(--wp--preset--font-size--potato)',
22
31
  fontStyle: 'normal',
@@ -84,6 +93,15 @@ describe( 'getGlobalStylesChanges and utils', () => {
84
93
  };
85
94
  const previous = {
86
95
  styles: {
96
+ background: {
97
+ backgroundImage: {
98
+ url: 'https://example.com/image_new.jpg',
99
+ source: 'file',
100
+ },
101
+ backgroundSize: 'contain',
102
+ backgroundPosition: '40% 77%',
103
+ backgroundRepeat: 'repeat',
104
+ },
87
105
  typography: {
88
106
  fontSize: 'var(--wp--preset--font-size--fungus)',
89
107
  fontStyle: 'normal',
@@ -195,7 +213,7 @@ describe( 'getGlobalStylesChanges and utils', () => {
195
213
  it( 'returns a list of changes', () => {
196
214
  const result = getGlobalStylesChanges( next, previous );
197
215
  expect( result ).toEqual( [
198
- 'Colors, Typography styles.',
216
+ 'Background, Colors, Typography styles.',
199
217
  'Test pumpkin flowers block.',
200
218
  'H3, Caption, H6, Link elements.',
201
219
  'Color, Typography settings.',
@@ -204,10 +222,10 @@ describe( 'getGlobalStylesChanges and utils', () => {
204
222
 
205
223
  it( 'returns a list of truncated changes', () => {
206
224
  const resultA = getGlobalStylesChanges( next, previous, {
207
- maxResults: 3,
225
+ maxResults: 4,
208
226
  } );
209
227
  expect( resultA ).toEqual( [
210
- 'Colors, Typography styles.',
228
+ 'Background, Colors, Typography styles.',
211
229
  'Test pumpkin flowers block.',
212
230
  ] );
213
231
  } );
@@ -254,6 +272,7 @@ describe( 'getGlobalStylesChanges and utils', () => {
254
272
  const resultA = getGlobalStylesChangelist( next, previous );
255
273
 
256
274
  expect( resultA ).toEqual( [
275
+ [ 'styles', 'Background' ],
257
276
  [ 'styles', 'Colors' ],
258
277
  [ 'styles', 'Typography' ],
259
278
  [ 'blocks', 'Test pumpkin flowers' ],
@@ -16,7 +16,7 @@ import {
16
16
  getStylesDeclarations,
17
17
  processCSSNesting,
18
18
  } from '../use-global-styles-output';
19
- import { ROOT_BLOCK_SELECTOR } from '../utils';
19
+ import { ROOT_BLOCK_SELECTOR, ROOT_CSS_PROPERTIES_SELECTOR } from '../utils';
20
20
 
21
21
  describe( 'global styles renderer', () => {
22
22
  describe( 'getNodesWithStyles', () => {
@@ -254,7 +254,7 @@ describe( 'global styles renderer', () => {
254
254
  ],
255
255
  },
256
256
  },
257
- selector: ROOT_BLOCK_SELECTOR,
257
+ selector: ROOT_CSS_PROPERTIES_SELECTOR,
258
258
  },
259
259
  {
260
260
  presets: {
@@ -342,7 +342,7 @@ describe( 'global styles renderer', () => {
342
342
  };
343
343
 
344
344
  expect( toCustomProperties( tree, blockSelectors ) ).toEqual(
345
- 'body{--wp--preset--color--white: white;--wp--preset--color--black: black;--wp--preset--color--white-2-black: value;--wp--custom--white-2-black: value;--wp--custom--font-primary: value;--wp--custom--line-height--body: 1.7;--wp--custom--line-height--heading: 1.3;}h1,h2,h3,h4,h5,h6{--wp--preset--font-size--small: 12px;--wp--preset--font-size--medium: 23px;}'
345
+ ':root{--wp--preset--color--white: white;--wp--preset--color--black: black;--wp--preset--color--white-2-black: value;--wp--custom--white-2-black: value;--wp--custom--font-primary: value;--wp--custom--line-height--body: 1.7;--wp--custom--line-height--heading: 1.3;}h1,h2,h3,h4,h5,h6{--wp--preset--font-size--small: 12px;--wp--preset--font-size--medium: 23px;}'
346
346
  );
347
347
  } );
348
348
  } );
@@ -481,8 +481,8 @@ describe( 'global styles renderer', () => {
481
481
 
482
482
  expect( toStyles( tree, blockSelectors ) ).toEqual(
483
483
  'body {margin: 0;}body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }body .is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }body .is-layout-grid { display:grid; }body .is-layout-grid > * { margin: 0; }' +
484
- 'body{background-color: red;margin: 10px;padding: 10px;}a:where(:not(.wp-element-button)){color: blue;}a:where(:not(.wp-element-button)):hover{color: orange;}a:where(:not(.wp-element-button)):focus{color: orange;}h1{font-size: 42px;}.wp-block-group{margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}h1,h2,h3,h4,h5,h6{color: orange;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){color: hotpink;}h1 a:where(:not(.wp-element-button)):hover,h2 a:where(:not(.wp-element-button)):hover,h3 a:where(:not(.wp-element-button)):hover,h4 a:where(:not(.wp-element-button)):hover,h5 a:where(:not(.wp-element-button)):hover,h6 a:where(:not(.wp-element-button)):hover{color: red;}h1 a:where(:not(.wp-element-button)):focus,h2 a:where(:not(.wp-element-button)):focus,h3 a:where(:not(.wp-element-button)):focus,h4 a:where(:not(.wp-element-button)):focus,h5 a:where(:not(.wp-element-button)):focus,h6 a:where(:not(.wp-element-button)):focus{color: red;}' +
485
- '.wp-block-image img, .wp-block-image .wp-crop-area{border-radius: 9999px;}.wp-block-image{color: red;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }' +
484
+ ':where(body){background-color: red;margin: 10px;padding: 10px;}:where(a:where(:not(.wp-element-button))){color: blue;}a:where(:not(.wp-element-button)):hover{color: orange;}a:where(:not(.wp-element-button)):focus{color: orange;}:where(h1){font-size: 42px;}:where(.wp-block-group){margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}:where(h1,h2,h3,h4,h5,h6){color: orange;}:where(h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button))){color: hotpink;}h1 a:where(:not(.wp-element-button)):hover,h2 a:where(:not(.wp-element-button)):hover,h3 a:where(:not(.wp-element-button)):hover,h4 a:where(:not(.wp-element-button)):hover,h5 a:where(:not(.wp-element-button)):hover,h6 a:where(:not(.wp-element-button)):hover{color: red;}h1 a:where(:not(.wp-element-button)):focus,h2 a:where(:not(.wp-element-button)):focus,h3 a:where(:not(.wp-element-button)):focus,h4 a:where(:not(.wp-element-button)):focus,h5 a:where(:not(.wp-element-button)):focus,h6 a:where(:not(.wp-element-button)):focus{color: red;}' +
485
+ ':where(.wp-block-image img, .wp-block-image .wp-crop-area){border-radius: 9999px;}:where(.wp-block-image){color: red;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }' +
486
486
  '.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}'
487
487
  );
488
488
  } );
@@ -524,7 +524,7 @@ describe( 'global styles renderer', () => {
524
524
 
525
525
  expect( toStyles( Object.freeze( tree ), blockSelectors ) ).toEqual(
526
526
  'body {margin: 0;}body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }body .is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }body .is-layout-grid { display:grid; }body .is-layout-grid > * { margin: 0; }' +
527
- '.wp-image-spacing{padding-top: 1px;}.wp-image-border-color{border-color: red;}.wp-image-border{border-radius: 9999px;}.wp-image{color: red;}' +
527
+ ':where(.wp-image-spacing){padding-top: 1px;}:where(.wp-image-border-color){border-color: red;}:where(.wp-image-border){border-radius: 9999px;}:where(.wp-image){color: red;}' +
528
528
  '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'
529
529
  );
530
530
  } );
@@ -614,7 +614,7 @@ describe( 'global styles renderer', () => {
614
614
  },
615
615
  };
616
616
  expect( toStyles( Object.freeze( tree ), 'body' ) ).toEqual(
617
- 'body {margin: 0; --wp--style--global--content-size: 840px; --wp--style--global--wide-size: 1100px;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'
617
+ ':root { --wp--style--global--content-size: 840px; --wp--style--global--wide-size: 1100px;}body {margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'
618
618
  );
619
619
  } );
620
620
  } );
@@ -734,7 +734,7 @@ describe( 'global styles renderer', () => {
734
734
  } );
735
735
 
736
736
  expect( layoutStyles ).toEqual(
737
- ':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 0.5em; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 0.5em; }body { --wp--style--block-gap: 0.5em; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
737
+ ':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 0.5em; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 0.5em; }:root { --wp--style--block-gap: 0.5em; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
738
738
  );
739
739
  } );
740
740
 
@@ -751,7 +751,7 @@ describe( 'global styles renderer', () => {
751
751
  } );
752
752
 
753
753
  expect( layoutStyles ).toEqual(
754
- ':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 12px; }body { --wp--style--block-gap: 12px; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
754
+ ':where(body .is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:where(body .is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:where(body .is-layout-flex) { gap: 12px; }:root { --wp--style--block-gap: 12px; }body .is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }body .is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }body .is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }body .is-layout-flex { flex-wrap: wrap; align-items: center; }body .is-layout-flex > * { margin: 0; }'
755
755
  );
756
756
  } );
757
757
 
@@ -19,6 +19,7 @@ import { privateApis as componentsPrivateApis } from '@wordpress/components';
19
19
  import {
20
20
  PRESET_METADATA,
21
21
  ROOT_BLOCK_SELECTOR,
22
+ ROOT_CSS_PROPERTIES_SELECTOR,
22
23
  scopeSelector,
23
24
  appendToSelector,
24
25
  getBlockStyleVariationSelector,
@@ -543,7 +544,7 @@ export function getLayoutStyles( {
543
544
  );
544
545
  // For backwards compatibility, ensure the legacy block gap CSS variable is still available.
545
546
  if ( selector === ROOT_BLOCK_SELECTOR && hasBlockGapSupport ) {
546
- ruleset += `${ selector } { --wp--style--block-gap: ${ gapValue }; }`;
547
+ ruleset += `${ ROOT_CSS_PROPERTIES_SELECTOR } { --wp--style--block-gap: ${ gapValue }; }`;
547
548
  }
548
549
  }
549
550
 
@@ -729,7 +730,7 @@ export const getNodesWithSettings = ( tree, blockSelectors ) => {
729
730
  nodes.push( {
730
731
  presets,
731
732
  custom,
732
- selector: ROOT_BLOCK_SELECTOR,
733
+ selector: ROOT_CSS_PROPERTIES_SELECTOR,
733
734
  } );
734
735
  }
735
736
 
@@ -781,24 +782,28 @@ export const toStyles = (
781
782
  const nodesWithSettings = getNodesWithSettings( tree, blockSelectors );
782
783
  const useRootPaddingAlign = tree?.settings?.useRootPaddingAwareAlignments;
783
784
  const { contentSize, wideSize } = tree?.settings?.layout || {};
785
+ let ruleset = '';
786
+
787
+ if ( contentSize || wideSize ) {
788
+ ruleset += `${ ROOT_CSS_PROPERTIES_SELECTOR } {`;
789
+ ruleset = contentSize
790
+ ? ruleset + ` --wp--style--global--content-size: ${ contentSize };`
791
+ : ruleset;
792
+ ruleset = wideSize
793
+ ? ruleset + ` --wp--style--global--wide-size: ${ wideSize };`
794
+ : ruleset;
795
+ ruleset += '}';
796
+ }
784
797
 
785
798
  /*
786
- * Reset default browser margin on the root body element.
787
- * This is set on the root selector **before** generating the ruleset
799
+ * Reset default browser margin on the body element.
800
+ * This is set on the body selector **before** generating the ruleset
788
801
  * from the `theme.json`. This is to ensure that if the `theme.json` declares
789
802
  * `margin` in its `spacing` declaration for the `body` element then these
790
803
  * user-generated values take precedence in the CSS cascade.
791
804
  * @link https://github.com/WordPress/gutenberg/issues/36147.
792
805
  */
793
- let ruleset = 'body {margin: 0;';
794
-
795
- if ( contentSize ) {
796
- ruleset += ` --wp--style--global--content-size: ${ contentSize };`;
797
- }
798
-
799
- if ( wideSize ) {
800
- ruleset += ` --wp--style--global--wide-size: ${ wideSize };`;
801
- }
806
+ ruleset += 'body {margin: 0;';
802
807
 
803
808
  // Root padding styles should only be output for full templates, not patterns or template parts.
804
809
  if ( useRootPaddingAlign && isTemplate ) {
@@ -839,7 +844,7 @@ export const toStyles = (
839
844
  ( [ cssSelector, declarations ] ) => {
840
845
  if ( declarations.length ) {
841
846
  const rules = declarations.join( ';' );
842
- ruleset += `${ cssSelector }{${ rules };}`;
847
+ ruleset += `:where(${ cssSelector }){${ rules };}`;
843
848
  }
844
849
  }
845
850
  );
@@ -932,7 +937,9 @@ export const toStyles = (
932
937
  isTemplate
933
938
  );
934
939
  if ( declarations?.length ) {
935
- ruleset += `${ selector }{${ declarations.join( ';' ) };}`;
940
+ ruleset += `:where(${ selector }){${ declarations.join(
941
+ ';'
942
+ ) };}`;
936
943
  }
937
944
 
938
945
  // Check for pseudo selector in `styles` and handle separately.
@@ -1000,7 +1007,10 @@ export const toStyles = (
1000
1007
  }
1001
1008
 
1002
1009
  nodesWithSettings.forEach( ( { selector, presets } ) => {
1003
- if ( ROOT_BLOCK_SELECTOR === selector ) {
1010
+ if (
1011
+ ROOT_BLOCK_SELECTOR === selector ||
1012
+ ROOT_CSS_PROPERTIES_SELECTOR === selector
1013
+ ) {
1004
1014
  // Do not add extra specificity for top-level classes.
1005
1015
  selector = '';
1006
1016
  }
@@ -1211,6 +1221,7 @@ export function useGlobalStylesOutputWithConfig( mergedConfig = {} ) {
1211
1221
  updatedConfig,
1212
1222
  blockSelectors
1213
1223
  );
1224
+
1214
1225
  const globalStyles = toStyles(
1215
1226
  updatedConfig,
1216
1227
  blockSelectors,
@@ -11,6 +11,7 @@ import { getValueFromObjectPath } from '../../utils/object';
11
11
 
12
12
  /* Supporting data. */
13
13
  export const ROOT_BLOCK_SELECTOR = 'body';
14
+ export const ROOT_CSS_PROPERTIES_SELECTOR = ':root';
14
15
 
15
16
  export const PRESET_METADATA = [
16
17
  {
@@ -141,6 +141,13 @@ function Iframe( {
141
141
  function onLoad() {
142
142
  const { contentDocument, ownerDocument } = node;
143
143
  const { documentElement } = contentDocument;
144
+ // Get any CSS classes the iframe document body may initially have
145
+ // to re-apply them later together with the ones of the main document
146
+ // body. This is necessary for some CSS classes for example the
147
+ // `is-dark-theme` class added by useDarkThemeBodyClassName.
148
+ const initialIframeBodyClasses = Array.from(
149
+ contentDocument.body.classList
150
+ );
144
151
  iFrameDocument = contentDocument;
145
152
 
146
153
  documentElement.classList.add( 'block-editor-iframe__html' );
@@ -151,12 +158,15 @@ function Iframe( {
151
158
  // be added in the editor too, which we'll somehow have to get from
152
159
  // the server in the future (which will run the PHP filters).
153
160
  setBodyClasses(
154
- Array.from( ownerDocument.body.classList ).filter(
155
- ( name ) =>
156
- name.startsWith( 'admin-color-' ) ||
157
- name.startsWith( 'post-type-' ) ||
158
- name === 'wp-embed-responsive'
159
- )
161
+ Array.from( ownerDocument.body.classList )
162
+ .concat( initialIframeBodyClasses )
163
+ .filter(
164
+ ( name ) =>
165
+ name.startsWith( 'admin-color-' ) ||
166
+ name.startsWith( 'post-type-' ) ||
167
+ name === 'wp-embed-responsive' ||
168
+ name === 'is-dark-theme'
169
+ )
160
170
  );
161
171
 
162
172
  contentDocument.dir = ownerDocument.dir;
@@ -244,12 +254,12 @@ function Iframe( {
244
254
  height: auto !important;
245
255
  min-height: 100%;
246
256
  }
247
-
248
- body {
257
+ /* Lowest specificity to not override global styles */
258
+ :where(body) {
249
259
  margin: 0;
250
260
  /* Default background color in case zoom out mode background
251
261
  colors the html element */
252
- background: white;
262
+ background-color: white;
253
263
  }
254
264
  </style>
255
265
  ${ styles }
@@ -33,6 +33,7 @@ function BlockPatternsTab( {
33
33
 
34
34
  const initialCategory = selectedCategory || categories[ 0 ];
35
35
  const isMobile = useViewportMatch( 'medium', '<' );
36
+
36
37
  return (
37
38
  <>
38
39
  { ! isMobile && (
@@ -10,6 +10,7 @@ import { focus } from '@wordpress/dom';
10
10
  */
11
11
 
12
12
  import { PatternCategoryPreviews } from './pattern-category-previews';
13
+ import { useZoomOut } from '../../../hooks/use-zoom-out';
13
14
 
14
15
  export function PatternCategoryPreviewPanel( {
15
16
  rootClientId,
@@ -29,6 +30,10 @@ export function PatternCategoryPreviewPanel( {
29
30
  return () => clearTimeout( timeout );
30
31
  }, [ category ] );
31
32
 
33
+ // Move to zoom out mode when this component is mounted
34
+ // and back to the previous mode when unmounted.
35
+ useZoomOut();
36
+
32
37
  return (
33
38
  <div
34
39
  ref={ container }
@@ -21,6 +21,7 @@ function InserterLibrary(
21
21
  showMostUsedBlocks = false,
22
22
  __experimentalInsertionIndex,
23
23
  __experimentalFilterValue,
24
+ __experimentalOnPatternCategorySelection,
24
25
  onSelect = noop,
25
26
  shouldFocusBlock = false,
26
27
  },
@@ -48,6 +49,9 @@ function InserterLibrary(
48
49
  showMostUsedBlocks={ showMostUsedBlocks }
49
50
  __experimentalInsertionIndex={ __experimentalInsertionIndex }
50
51
  __experimentalFilterValue={ __experimentalFilterValue }
52
+ __experimentalOnPatternCategorySelection={
53
+ __experimentalOnPatternCategorySelection
54
+ }
51
55
  shouldFocusBlock={ shouldFocusBlock }
52
56
  ref={ ref }
53
57
  />
@@ -34,6 +34,7 @@ import useInsertionPoint from './hooks/use-insertion-point';
34
34
  import InserterTabs from './tabs';
35
35
  import { store as blockEditorStore } from '../../store';
36
36
 
37
+ const NOOP = () => {};
37
38
  function InserterMenu(
38
39
  {
39
40
  rootClientId,
@@ -45,6 +46,7 @@ function InserterMenu(
45
46
  showMostUsedBlocks,
46
47
  __experimentalFilterValue = '',
47
48
  shouldFocusBlock = true,
49
+ __experimentalOnPatternCategorySelection = NOOP,
48
50
  },
49
51
  ref
50
52
  ) {
@@ -110,12 +112,17 @@ function InserterMenu(
110
112
  [ onToggleInsertionPoint ]
111
113
  );
112
114
 
115
+ const isZoomedOutViewExperimentEnabled =
116
+ window?.__experimentalEnableZoomedOutView;
113
117
  const onClickPatternCategory = useCallback(
114
118
  ( patternCategory, filter ) => {
115
119
  setSelectedPatternCategory( patternCategory );
116
120
  setPatternFilter( filter );
121
+ if ( isZoomedOutViewExperimentEnabled ) {
122
+ __experimentalOnPatternCategorySelection();
123
+ }
117
124
  },
118
- [ setSelectedPatternCategory ]
125
+ [ setSelectedPatternCategory, __experimentalOnPatternCategorySelection ]
119
126
  );
120
127
 
121
128
  const blocksTab = useMemo(
@@ -12,6 +12,17 @@ const defaultGetKeywords = ( item ) => item.keywords || [];
12
12
  const defaultGetCategory = ( item ) => item.category;
13
13
  const defaultGetCollection = () => null;
14
14
 
15
+ // Normalization regexes
16
+ const splitRegexp = [
17
+ /([\p{Ll}\p{Lo}\p{N}])([\p{Lu}\p{Lt}])/gu, // One lowercase or digit, followed by one uppercase.
18
+ /([\p{Lu}\p{Lt}])([\p{Lu}\p{Lt}][\p{Ll}\p{Lo}])/gu, // One uppercase followed by one uppercase and one lowercase.
19
+ ];
20
+ const stripRegexp = /(\p{C}|\p{P}|\p{S})+/giu; // Anything that's not a punctuation, symbol or control/format character.
21
+
22
+ // Normalization cache
23
+ const extractedWords = new Map();
24
+ const normalizedStrings = new Map();
25
+
15
26
  /**
16
27
  * Extracts words from an input string.
17
28
  *
@@ -19,16 +30,21 @@ const defaultGetCollection = () => null;
19
30
  *
20
31
  * @return {Array} Words, extracted from the input string.
21
32
  */
22
- function extractWords( input = '' ) {
23
- return noCase( input, {
24
- splitRegexp: [
25
- /([\p{Ll}\p{Lo}\p{N}])([\p{Lu}\p{Lt}])/gu, // One lowercase or digit, followed by one uppercase.
26
- /([\p{Lu}\p{Lt}])([\p{Lu}\p{Lt}][\p{Ll}\p{Lo}])/gu, // One uppercase followed by one uppercase and one lowercase.
27
- ],
28
- stripRegexp: /(\p{C}|\p{P}|\p{S})+/giu, // Anything that's not a punctuation, symbol or control/format character.
33
+ export function extractWords( input = '' ) {
34
+ if ( extractedWords.has( input ) ) {
35
+ return extractedWords.get( input );
36
+ }
37
+
38
+ const result = noCase( input, {
39
+ splitRegexp,
40
+ stripRegexp,
29
41
  } )
30
42
  .split( ' ' )
31
43
  .filter( Boolean );
44
+
45
+ extractedWords.set( input, result );
46
+
47
+ return result;
32
48
  }
33
49
 
34
50
  /**
@@ -38,20 +54,26 @@ function extractWords( input = '' ) {
38
54
  *
39
55
  * @return {string} The normalized search input.
40
56
  */
41
- function normalizeSearchInput( input = '' ) {
57
+ export function normalizeString( input = '' ) {
58
+ if ( normalizedStrings.has( input ) ) {
59
+ return normalizedStrings.get( input );
60
+ }
61
+
42
62
  // Disregard diacritics.
43
63
  // Input: "média"
44
- input = removeAccents( input );
64
+ let result = removeAccents( input );
45
65
 
46
66
  // Accommodate leading slash, matching autocomplete expectations.
47
67
  // Input: "/media"
48
- input = input.replace( /^\//, '' );
68
+ result = result.replace( /^\//, '' );
49
69
 
50
70
  // Lowercase.
51
71
  // Input: "MEDIA"
52
- input = input.toLowerCase();
72
+ result = result.toLowerCase();
73
+
74
+ normalizedStrings.set( input, result );
53
75
 
54
- return input;
76
+ return result;
55
77
  }
56
78
 
57
79
  /**
@@ -62,7 +84,7 @@ function normalizeSearchInput( input = '' ) {
62
84
  * @return {string[]} The normalized list of search terms.
63
85
  */
64
86
  export const getNormalizedSearchTerms = ( input = '' ) => {
65
- return extractWords( normalizeSearchInput( input ) );
87
+ return extractWords( normalizeString( input ) );
66
88
  };
67
89
 
68
90
  const removeMatchingTerms = ( unmatchedTerms, unprocessedTerms ) => {
@@ -148,8 +170,8 @@ export function getItemSearchRank( item, searchTerm, config = {} ) {
148
170
  const category = getCategory( item );
149
171
  const collection = getCollection( item );
150
172
 
151
- const normalizedSearchInput = normalizeSearchInput( searchTerm );
152
- const normalizedTitle = normalizeSearchInput( title );
173
+ const normalizedSearchInput = normalizeString( searchTerm );
174
+ const normalizedTitle = normalizeString( title );
153
175
 
154
176
  let rank = 0;
155
177
 
@@ -22,7 +22,6 @@ $block-inserter-tabs-height: 44px;
22
22
  flex-direction: column;
23
23
  height: 100%;
24
24
  gap: $grid-unit-20;
25
- overflow-y: hidden;
26
25
 
27
26
  &.show-as-tabs {
28
27
  gap: 0;
@@ -142,6 +141,8 @@ $block-inserter-tabs-height: 44px;
142
141
  .block-editor-inserter__no-tab-container {
143
142
  overflow-y: auto;
144
143
  flex-grow: 1;
144
+ // Fixes the editor canvas scrolling on search results https://github.com/WordPress/gutenberg/issues/56811
145
+ position: relative;
145
146
  }
146
147
 
147
148
  .block-editor-inserter__panel-header {
@@ -318,17 +319,6 @@ $block-inserter-tabs-height: 44px;
318
319
  }
319
320
  }
320
321
 
321
- .block-editor-block-patterns-list__list-item {
322
- .block-editor-block-preview__container {
323
- box-shadow: 0 15px 25px rgb(0 0 0 / 7%);
324
- }
325
- &:hover {
326
- .block-editor-block-preview__container {
327
- box-shadow: 0 0 0 2px $gray-900, 0 15px 25px rgb(0 0 0 / 7%);
328
- }
329
- }
330
- }
331
-
332
322
  .block-editor-inserter__patterns-category-panel {
333
323
  padding: 0 $grid-unit-20;
334
324
  display: flex;
@@ -776,4 +766,8 @@ $block-inserter-tabs-height: 44px;
776
766
  .block-editor-inserter__patterns-category-dialog {
777
767
  position: static;
778
768
  }
769
+
770
+ .block-editor-inserter__media-dialog {
771
+ position: static;
772
+ }
779
773
  }