@wordpress/block-editor 15.19.1-next.v.202605131006.0 → 15.20.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 (352) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/build/components/block-card/index.cjs +51 -41
  3. package/build/components/block-card/index.cjs.map +3 -3
  4. package/build/components/block-heading-level-dropdown/heading-level-icon.cjs.map +3 -3
  5. package/build/components/block-icon/index.cjs +7 -1
  6. package/build/components/block-icon/index.cjs.map +3 -3
  7. package/build/components/block-inspector/index.cjs +156 -11
  8. package/build/components/block-inspector/index.cjs.map +3 -3
  9. package/build/components/block-inspector/inspector-pre-tabs-slot-fill.cjs +38 -0
  10. package/build/components/block-inspector/inspector-pre-tabs-slot-fill.cjs.map +7 -0
  11. package/build/components/block-list/use-block-props/index.cjs +1 -1
  12. package/build/components/block-list/use-block-props/index.cjs.map +2 -2
  13. package/build/components/block-list/use-block-props/use-focus-handler.cjs +3 -4
  14. package/build/components/block-list/use-block-props/use-focus-handler.cjs.map +3 -3
  15. package/build/components/block-list/use-block-props/use-is-hovered.cjs +24 -14
  16. package/build/components/block-list/use-block-props/use-is-hovered.cjs.map +3 -3
  17. package/build/components/block-lock/modal.cjs.map +3 -3
  18. package/build/components/block-patterns-list/index.cjs +13 -2
  19. package/build/components/block-patterns-list/index.cjs.map +2 -2
  20. package/build/components/block-popover/index.cjs +13 -3
  21. package/build/components/block-popover/index.cjs.map +2 -2
  22. package/build/components/block-toolbar/switch-section-style.cjs.map +3 -3
  23. package/build/components/block-visibility/modal.cjs.map +3 -3
  24. package/build/components/block-visibility/viewport-visibility-info.cjs.map +3 -3
  25. package/build/components/colors-gradients/control.cjs +7 -4
  26. package/build/components/colors-gradients/control.cjs.map +2 -2
  27. package/build/components/global-styles/advanced-panel.cjs +24 -22
  28. package/build/components/global-styles/advanced-panel.cjs.map +3 -3
  29. package/build/components/global-styles/color-panel.cjs +95 -58
  30. package/build/components/global-styles/color-panel.cjs.map +2 -2
  31. package/build/components/global-styles/dimensions-panel.cjs +11 -5
  32. package/build/components/global-styles/dimensions-panel.cjs.map +2 -2
  33. package/build/components/global-styles/index.cjs +3 -0
  34. package/build/components/global-styles/index.cjs.map +2 -2
  35. package/build/components/global-styles/shadow-panel-components.cjs +38 -26
  36. package/build/components/global-styles/shadow-panel-components.cjs.map +2 -2
  37. package/build/components/global-styles/state-control-badges.cjs +69 -0
  38. package/build/components/global-styles/state-control-badges.cjs.map +7 -0
  39. package/build/components/global-styles/state-control.cjs +54 -63
  40. package/build/components/global-styles/state-control.cjs.map +3 -3
  41. package/build/components/iframe/index.cjs +0 -3
  42. package/build/components/iframe/index.cjs.map +2 -2
  43. package/build/components/iframe/use-scale-canvas.cjs +4 -1
  44. package/build/components/iframe/use-scale-canvas.cjs.map +2 -2
  45. package/build/components/inserter/hooks/use-patterns-state.cjs +4 -6
  46. package/build/components/inserter/hooks/use-patterns-state.cjs.map +2 -2
  47. package/build/components/inserter/index.cjs +1 -0
  48. package/build/components/inserter/index.cjs.map +2 -2
  49. package/build/components/inserter/media-tab/media-preview.cjs +27 -18
  50. package/build/components/inserter/media-tab/media-preview.cjs.map +2 -2
  51. package/build/components/inserter/media-tab/utils.cjs +1 -1
  52. package/build/components/inserter/media-tab/utils.cjs.map +2 -2
  53. package/build/components/inserter/panel.cjs.map +3 -3
  54. package/build/components/inspector-controls/block-support-tools-panel.cjs +10 -2
  55. package/build/components/inspector-controls/block-support-tools-panel.cjs.map +2 -2
  56. package/build/components/inspector-controls/fill.cjs +14 -4
  57. package/build/components/inspector-controls/fill.cjs.map +2 -2
  58. package/build/components/inspector-controls/groups.cjs +2 -0
  59. package/build/components/inspector-controls/groups.cjs.map +2 -2
  60. package/build/components/inspector-controls-tabs/index.cjs +13 -8
  61. package/build/components/inspector-controls-tabs/index.cjs.map +3 -3
  62. package/build/components/inspector-controls-tabs/settings-tab.cjs +1 -4
  63. package/build/components/inspector-controls-tabs/settings-tab.cjs.map +3 -3
  64. package/build/components/inspector-controls-tabs/styles-tab.cjs +9 -0
  65. package/build/components/inspector-controls-tabs/styles-tab.cjs.map +3 -3
  66. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.cjs +11 -5
  67. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.cjs.map +2 -2
  68. package/build/components/list-view/block-select-button.cjs +20 -8
  69. package/build/components/list-view/block-select-button.cjs.map +2 -2
  70. package/build/components/list-view/block.cjs +2 -1
  71. package/build/components/list-view/block.cjs.map +2 -2
  72. package/build/components/preset-input-control/custom-value-controls.cjs +10 -1
  73. package/build/components/preset-input-control/custom-value-controls.cjs.map +2 -2
  74. package/build/components/preset-input-control/index.cjs.map +3 -3
  75. package/build/components/provider/use-media-upload-settings.cjs +1 -0
  76. package/build/components/provider/use-media-upload-settings.cjs.map +2 -2
  77. package/build/components/rich-text/event-listeners/enter.cjs +9 -2
  78. package/build/components/rich-text/event-listeners/enter.cjs.map +3 -3
  79. package/build/components/rich-text/event-listeners/paste-handler.cjs +4 -4
  80. package/build/components/rich-text/event-listeners/paste-handler.cjs.map +3 -3
  81. package/build/hooks/background.cjs +13 -3
  82. package/build/hooks/background.cjs.map +2 -2
  83. package/build/hooks/block-fields/link/index.cjs.map +3 -3
  84. package/build/hooks/block-fields/media/index.cjs.map +3 -3
  85. package/build/hooks/block-style-state.cjs +112 -0
  86. package/build/hooks/block-style-state.cjs.map +7 -0
  87. package/build/hooks/border.cjs +13 -3
  88. package/build/hooks/border.cjs.map +2 -2
  89. package/build/hooks/color.cjs +28 -9
  90. package/build/hooks/color.cjs.map +2 -2
  91. package/build/hooks/dimensions.cjs +15 -6
  92. package/build/hooks/dimensions.cjs.map +2 -2
  93. package/build/hooks/layout-child.cjs +147 -61
  94. package/build/hooks/layout-child.cjs.map +2 -2
  95. package/build/hooks/layout.cjs +263 -56
  96. package/build/hooks/layout.cjs.map +3 -3
  97. package/build/hooks/state-utils.cjs +94 -0
  98. package/build/hooks/state-utils.cjs.map +7 -0
  99. package/build/hooks/states.cjs +124 -0
  100. package/build/hooks/states.cjs.map +7 -0
  101. package/build/hooks/style.cjs +304 -17
  102. package/build/hooks/style.cjs.map +3 -3
  103. package/build/hooks/typography.cjs +14 -5
  104. package/build/hooks/typography.cjs.map +2 -2
  105. package/build/layouts/constrained.cjs +128 -55
  106. package/build/layouts/constrained.cjs.map +3 -3
  107. package/build/layouts/flex.cjs +119 -31
  108. package/build/layouts/flex.cjs.map +3 -3
  109. package/build/layouts/grid.cjs +103 -40
  110. package/build/layouts/grid.cjs.map +3 -3
  111. package/build/private-apis.cjs +2 -0
  112. package/build/private-apis.cjs.map +2 -2
  113. package/build/store/private-actions.cjs +18 -0
  114. package/build/store/private-actions.cjs.map +2 -2
  115. package/build/store/private-keys.cjs +10 -2
  116. package/build/store/private-keys.cjs.map +2 -2
  117. package/build/store/private-selectors.cjs +26 -2
  118. package/build/store/private-selectors.cjs.map +2 -2
  119. package/build/store/reducer.cjs +70 -1
  120. package/build/store/reducer.cjs.map +2 -2
  121. package/build/store/utils.cjs +1 -1
  122. package/build/store/utils.cjs.map +2 -2
  123. package/build/utils/color-values.cjs +44 -0
  124. package/build/utils/color-values.cjs.map +7 -0
  125. package/build-module/components/block-card/index.mjs +52 -45
  126. package/build-module/components/block-card/index.mjs.map +2 -2
  127. package/build-module/components/block-heading-level-dropdown/heading-level-icon.mjs +2 -2
  128. package/build-module/components/block-heading-level-dropdown/heading-level-icon.mjs.map +2 -2
  129. package/build-module/components/block-icon/index.mjs +8 -2
  130. package/build-module/components/block-icon/index.mjs.map +2 -2
  131. package/build-module/components/block-inspector/index.mjs +166 -13
  132. package/build-module/components/block-inspector/index.mjs.map +2 -2
  133. package/build-module/components/block-inspector/inspector-pre-tabs-slot-fill.mjs +12 -0
  134. package/build-module/components/block-inspector/inspector-pre-tabs-slot-fill.mjs.map +7 -0
  135. package/build-module/components/block-list/use-block-props/index.mjs +1 -1
  136. package/build-module/components/block-list/use-block-props/index.mjs.map +2 -2
  137. package/build-module/components/block-list/use-block-props/use-focus-handler.mjs +7 -5
  138. package/build-module/components/block-list/use-block-props/use-focus-handler.mjs.map +2 -2
  139. package/build-module/components/block-list/use-block-props/use-is-hovered.mjs +28 -15
  140. package/build-module/components/block-list/use-block-props/use-is-hovered.mjs.map +2 -2
  141. package/build-module/components/block-lock/modal.mjs +4 -4
  142. package/build-module/components/block-lock/modal.mjs.map +2 -2
  143. package/build-module/components/block-patterns-list/index.mjs +14 -4
  144. package/build-module/components/block-patterns-list/index.mjs.map +2 -2
  145. package/build-module/components/block-popover/index.mjs +13 -3
  146. package/build-module/components/block-popover/index.mjs.map +2 -2
  147. package/build-module/components/block-toolbar/switch-section-style.mjs +2 -2
  148. package/build-module/components/block-toolbar/switch-section-style.mjs.map +2 -2
  149. package/build-module/components/block-visibility/modal.mjs +2 -2
  150. package/build-module/components/block-visibility/modal.mjs.map +2 -2
  151. package/build-module/components/block-visibility/viewport-visibility-info.mjs +2 -2
  152. package/build-module/components/block-visibility/viewport-visibility-info.mjs.map +2 -2
  153. package/build-module/components/colors-gradients/control.mjs +7 -4
  154. package/build-module/components/colors-gradients/control.mjs.map +2 -2
  155. package/build-module/components/global-styles/advanced-panel.mjs +25 -27
  156. package/build-module/components/global-styles/advanced-panel.mjs.map +2 -2
  157. package/build-module/components/global-styles/color-panel.mjs +96 -59
  158. package/build-module/components/global-styles/color-panel.mjs.map +2 -2
  159. package/build-module/components/global-styles/dimensions-panel.mjs +14 -5
  160. package/build-module/components/global-styles/dimensions-panel.mjs.map +2 -2
  161. package/build-module/components/global-styles/index.mjs +2 -0
  162. package/build-module/components/global-styles/index.mjs.map +2 -2
  163. package/build-module/components/global-styles/shadow-panel-components.mjs +39 -28
  164. package/build-module/components/global-styles/shadow-panel-components.mjs.map +2 -2
  165. package/build-module/components/global-styles/state-control-badges.mjs +48 -0
  166. package/build-module/components/global-styles/state-control-badges.mjs.map +7 -0
  167. package/build-module/components/global-styles/state-control.mjs +57 -71
  168. package/build-module/components/global-styles/state-control.mjs.map +2 -2
  169. package/build-module/components/iframe/index.mjs +0 -3
  170. package/build-module/components/iframe/index.mjs.map +2 -2
  171. package/build-module/components/iframe/use-scale-canvas.mjs +4 -1
  172. package/build-module/components/iframe/use-scale-canvas.mjs.map +2 -2
  173. package/build-module/components/inserter/hooks/use-patterns-state.mjs +8 -7
  174. package/build-module/components/inserter/hooks/use-patterns-state.mjs.map +2 -2
  175. package/build-module/components/inserter/index.mjs +1 -0
  176. package/build-module/components/inserter/index.mjs.map +2 -2
  177. package/build-module/components/inserter/media-tab/media-preview.mjs +27 -19
  178. package/build-module/components/inserter/media-tab/media-preview.mjs.map +2 -2
  179. package/build-module/components/inserter/media-tab/utils.mjs +1 -1
  180. package/build-module/components/inserter/media-tab/utils.mjs.map +2 -2
  181. package/build-module/components/inserter/panel.mjs +2 -2
  182. package/build-module/components/inserter/panel.mjs.map +2 -2
  183. package/build-module/components/inspector-controls/block-support-tools-panel.mjs +10 -2
  184. package/build-module/components/inspector-controls/block-support-tools-panel.mjs.map +2 -2
  185. package/build-module/components/inspector-controls/fill.mjs +18 -5
  186. package/build-module/components/inspector-controls/fill.mjs.map +2 -2
  187. package/build-module/components/inspector-controls/groups.mjs +2 -0
  188. package/build-module/components/inspector-controls/groups.mjs.map +2 -2
  189. package/build-module/components/inspector-controls-tabs/index.mjs +14 -10
  190. package/build-module/components/inspector-controls-tabs/index.mjs.map +2 -2
  191. package/build-module/components/inspector-controls-tabs/settings-tab.mjs +1 -4
  192. package/build-module/components/inspector-controls-tabs/settings-tab.mjs.map +2 -2
  193. package/build-module/components/inspector-controls-tabs/styles-tab.mjs +9 -0
  194. package/build-module/components/inspector-controls-tabs/styles-tab.mjs.map +2 -2
  195. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.mjs +11 -5
  196. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.mjs.map +2 -2
  197. package/build-module/components/list-view/block-select-button.mjs +20 -9
  198. package/build-module/components/list-view/block-select-button.mjs.map +2 -2
  199. package/build-module/components/list-view/block.mjs +2 -1
  200. package/build-module/components/list-view/block.mjs.map +2 -2
  201. package/build-module/components/preset-input-control/custom-value-controls.mjs +10 -2
  202. package/build-module/components/preset-input-control/custom-value-controls.mjs.map +2 -2
  203. package/build-module/components/preset-input-control/index.mjs +2 -2
  204. package/build-module/components/preset-input-control/index.mjs.map +2 -2
  205. package/build-module/components/provider/use-media-upload-settings.mjs +1 -0
  206. package/build-module/components/provider/use-media-upload-settings.mjs.map +2 -2
  207. package/build-module/components/rich-text/event-listeners/enter.mjs +9 -2
  208. package/build-module/components/rich-text/event-listeners/enter.mjs.map +2 -2
  209. package/build-module/components/rich-text/event-listeners/paste-handler.mjs +4 -4
  210. package/build-module/components/rich-text/event-listeners/paste-handler.mjs.map +2 -2
  211. package/build-module/hooks/background.mjs +18 -3
  212. package/build-module/hooks/background.mjs.map +2 -2
  213. package/build-module/hooks/block-fields/link/index.mjs +3 -3
  214. package/build-module/hooks/block-fields/link/index.mjs.map +2 -2
  215. package/build-module/hooks/block-fields/media/index.mjs +3 -3
  216. package/build-module/hooks/block-fields/media/index.mjs.map +2 -2
  217. package/build-module/hooks/block-style-state.mjs +79 -0
  218. package/build-module/hooks/block-style-state.mjs.map +7 -0
  219. package/build-module/hooks/border.mjs +18 -3
  220. package/build-module/hooks/border.mjs.map +2 -2
  221. package/build-module/hooks/color.mjs +33 -9
  222. package/build-module/hooks/color.mjs.map +2 -2
  223. package/build-module/hooks/dimensions.mjs +20 -6
  224. package/build-module/hooks/dimensions.mjs.map +2 -2
  225. package/build-module/hooks/layout-child.mjs +141 -61
  226. package/build-module/hooks/layout-child.mjs.map +2 -2
  227. package/build-module/hooks/layout.mjs +270 -58
  228. package/build-module/hooks/layout.mjs.map +2 -2
  229. package/build-module/hooks/state-utils.mjs +64 -0
  230. package/build-module/hooks/state-utils.mjs.map +7 -0
  231. package/build-module/hooks/states.mjs +85 -0
  232. package/build-module/hooks/states.mjs.map +7 -0
  233. package/build-module/hooks/style.mjs +309 -18
  234. package/build-module/hooks/style.mjs.map +2 -2
  235. package/build-module/hooks/typography.mjs +19 -5
  236. package/build-module/hooks/typography.mjs.map +2 -2
  237. package/build-module/layouts/constrained.mjs +130 -57
  238. package/build-module/layouts/constrained.mjs.map +2 -2
  239. package/build-module/layouts/flex.mjs +123 -35
  240. package/build-module/layouts/flex.mjs.map +2 -2
  241. package/build-module/layouts/grid.mjs +105 -42
  242. package/build-module/layouts/grid.mjs.map +2 -2
  243. package/build-module/private-apis.mjs +4 -0
  244. package/build-module/private-apis.mjs.map +2 -2
  245. package/build-module/store/private-actions.mjs +16 -0
  246. package/build-module/store/private-actions.mjs.map +2 -2
  247. package/build-module/store/private-keys.mjs +7 -1
  248. package/build-module/store/private-keys.mjs.map +2 -2
  249. package/build-module/store/private-selectors.mjs +25 -2
  250. package/build-module/store/private-selectors.mjs.map +2 -2
  251. package/build-module/store/reducer.mjs +69 -1
  252. package/build-module/store/reducer.mjs.map +2 -2
  253. package/build-module/store/utils.mjs +5 -2
  254. package/build-module/store/utils.mjs.map +2 -2
  255. package/build-module/utils/color-values.mjs +19 -0
  256. package/build-module/utils/color-values.mjs.map +7 -0
  257. package/build-style/content-rtl.css +18 -3
  258. package/build-style/content.css +18 -3
  259. package/build-style/style-rtl.css +14 -17
  260. package/build-style/style.css +14 -17
  261. package/package.json +41 -41
  262. package/src/components/audio-player/index.native.js +7 -3
  263. package/src/components/block-card/index.js +67 -60
  264. package/src/components/block-heading-level-dropdown/heading-level-icon.js +2 -2
  265. package/src/components/block-icon/index.js +5 -2
  266. package/src/components/block-icon/index.native.js +2 -2
  267. package/src/components/block-inspector/index.js +153 -7
  268. package/src/components/block-inspector/inspector-pre-tabs-slot-fill.js +11 -0
  269. package/src/components/block-list/block-selection-button.native.js +3 -3
  270. package/src/components/block-list/content.scss +0 -6
  271. package/src/components/block-list/use-block-props/index.js +1 -1
  272. package/src/components/block-list/use-block-props/use-focus-handler.js +8 -6
  273. package/src/components/block-list/use-block-props/use-is-hovered.js +32 -15
  274. package/src/components/block-lock/modal.js +4 -4
  275. package/src/components/block-patterns-list/index.js +14 -5
  276. package/src/components/block-patterns-list/stories/index.story.jsx +2 -0
  277. package/src/components/block-patterns-list/style.scss +0 -1
  278. package/src/components/block-popover/index.js +20 -10
  279. package/src/components/block-toolbar/switch-section-style.js +2 -2
  280. package/src/components/block-visibility/modal.js +2 -2
  281. package/src/components/block-visibility/viewport-visibility-info.js +2 -2
  282. package/src/components/colors/test/with-colors.js +1 -1
  283. package/src/components/colors-gradients/control.js +10 -8
  284. package/src/components/colors-gradients/test/control.js +98 -1
  285. package/src/components/global-styles/advanced-panel.js +44 -39
  286. package/src/components/global-styles/color-panel.js +133 -60
  287. package/src/components/global-styles/dimensions-panel.js +17 -4
  288. package/src/components/global-styles/index.js +1 -0
  289. package/src/components/global-styles/shadow-panel-components.js +29 -19
  290. package/src/components/global-styles/state-control-badges.js +58 -0
  291. package/src/components/global-styles/state-control.js +28 -36
  292. package/src/components/global-styles/test/color-panel.js +135 -0
  293. package/src/components/iframe/index.js +0 -3
  294. package/src/components/iframe/use-scale-canvas.js +8 -2
  295. package/src/components/inserter/hooks/use-patterns-state.js +12 -7
  296. package/src/components/inserter/index.js +1 -0
  297. package/src/components/inserter/media-tab/media-preview.js +29 -20
  298. package/src/components/inserter/media-tab/utils.js +1 -1
  299. package/src/components/inserter/panel.js +2 -2
  300. package/src/components/inserter/style.scss +1 -0
  301. package/src/components/inserter-button/index.native.js +5 -2
  302. package/src/components/inspector-controls/block-support-tools-panel.js +10 -2
  303. package/src/components/inspector-controls/fill.js +18 -5
  304. package/src/components/inspector-controls/groups.js +2 -0
  305. package/src/components/inspector-controls-tabs/index.js +9 -5
  306. package/src/components/inspector-controls-tabs/settings-tab.js +1 -7
  307. package/src/components/inspector-controls-tabs/styles-tab.js +6 -0
  308. package/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js +13 -7
  309. package/src/components/list-view/block-select-button.js +19 -9
  310. package/src/components/list-view/block.js +6 -1
  311. package/src/components/media-replace-flow/style.scss +0 -18
  312. package/src/components/preset-input-control/custom-value-controls.js +13 -6
  313. package/src/components/preset-input-control/index.js +2 -2
  314. package/src/components/provider/use-media-upload-settings.js +1 -0
  315. package/src/components/rich-text/event-listeners/enter.js +14 -2
  316. package/src/components/rich-text/event-listeners/paste-handler.js +5 -4
  317. package/src/components/unsupported-block-details/index.native.js +6 -2
  318. package/src/components/video-player/index.native.js +2 -2
  319. package/src/components/warning/index.native.js +2 -2
  320. package/src/hooks/background.js +59 -37
  321. package/src/hooks/block-fields/link/index.js +3 -3
  322. package/src/hooks/block-fields/media/index.js +3 -3
  323. package/src/hooks/block-style-state.js +127 -0
  324. package/src/hooks/border.js +25 -6
  325. package/src/hooks/color.js +40 -18
  326. package/src/hooks/dimensions.js +32 -11
  327. package/src/hooks/layout-child.js +179 -62
  328. package/src/hooks/layout.js +349 -75
  329. package/src/hooks/layout.scss +6 -0
  330. package/src/hooks/state-utils.js +158 -0
  331. package/src/hooks/states.js +109 -0
  332. package/src/hooks/style.js +456 -19
  333. package/src/hooks/test/block-style-state.js +270 -0
  334. package/src/hooks/test/layout.js +185 -0
  335. package/src/hooks/test/state-utils.js +193 -0
  336. package/src/hooks/test/style.js +301 -1
  337. package/src/hooks/typography.js +33 -14
  338. package/src/layouts/constrained.js +182 -95
  339. package/src/layouts/flex.js +141 -36
  340. package/src/layouts/grid.js +122 -32
  341. package/src/layouts/test/flex.js +57 -20
  342. package/src/private-apis.js +4 -0
  343. package/src/store/private-actions.js +32 -0
  344. package/src/store/private-keys.js +4 -0
  345. package/src/store/private-selectors.js +44 -2
  346. package/src/store/reducer.js +105 -1
  347. package/src/store/test/private-actions.js +26 -0
  348. package/src/store/test/private-selectors.js +90 -0
  349. package/src/store/test/reducer.js +363 -0
  350. package/src/store/utils.js +6 -2
  351. package/src/utils/color-values.js +28 -0
  352. package/src/utils/test/color-values.js +78 -0
@@ -8,6 +8,7 @@ import clsx from 'clsx';
8
8
  */
9
9
  import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
10
10
  import { addFilter } from '@wordpress/hooks';
11
+ import { useCallback } from '@wordpress/element';
11
12
  import {
12
13
  getBlockSupport,
13
14
  hasBlockSupport,
@@ -18,7 +19,7 @@ import {
18
19
  __experimentalToggleGroupControl as ToggleGroupControl,
19
20
  __experimentalToggleGroupControlOption as ToggleGroupControlOption,
20
21
  ToggleControl,
21
- PanelBody,
22
+ __experimentalToolsPanelItem as ToolsPanelItem,
22
23
  privateApis as componentsPrivateApis,
23
24
  } from '@wordpress/components';
24
25
  import { __ } from '@wordpress/i18n';
@@ -32,16 +33,93 @@ import { useSettings } from '../components/use-settings';
32
33
  import { getLayoutType, getLayoutTypes } from '../layouts';
33
34
  import { useBlockEditingMode } from '../components/block-editing-mode';
34
35
  import { LAYOUT_DEFINITIONS } from '../layouts/definitions';
35
- import { useBlockSettings, useStyleOverride } from './utils';
36
+ import { cleanEmptyObject, useBlockSettings, useStyleOverride } from './utils';
36
37
  import { unlock } from '../lock-unlock';
37
38
  import { globalStylesDataKey } from '../store/private-keys';
38
39
  import { getVariationNameFromClass } from './block-style-variation';
40
+ import {
41
+ DEFAULT_BLOCK_STYLE_STATE,
42
+ getStyleForState,
43
+ hasPseudoBlockStyleState,
44
+ hasViewportBlockStyleState,
45
+ isDefaultBlockStyleState,
46
+ setStyleForState,
47
+ } from './block-style-state';
39
48
 
40
49
  const VARIATION_PREFIX = 'is-style-';
41
50
 
42
51
  const layoutBlockSupportKey = 'layout';
52
+ // Keep in sync with WP_Theme_JSON_Gutenberg::RESPONSIVE_BREAKPOINTS and
53
+ // packages/global-styles-engine/src/core/render.tsx.
54
+ const RESPONSIVE_BREAKPOINTS = {
55
+ mobile: '@media (width <= 480px)',
56
+ tablet: '@media (480px < width <= 782px)',
57
+ };
58
+ const CHILD_LAYOUT_KEYS = [
59
+ 'selfStretch',
60
+ 'flexSize',
61
+ 'columnStart',
62
+ 'columnSpan',
63
+ 'rowStart',
64
+ 'rowSpan',
65
+ ];
43
66
  const { kebabCase } = unlock( componentsPrivateApis );
44
67
 
68
+ function getDefaultLayout( layoutBlockSupport = {}, blockVariation ) {
69
+ const defaultBlockLayout = layoutBlockSupport?.default;
70
+
71
+ return blockVariation?.attributes?.layout ?? defaultBlockLayout;
72
+ }
73
+
74
+ /**
75
+ * Returns the layout values to use when resetting layout controls.
76
+ *
77
+ * @param { Object } layoutBlockSupport Block layout support settings.
78
+ * @param { Object|undefined } blockVariation Block variation settings.
79
+ *
80
+ * @return { Object|undefined } Reset layout values.
81
+ */
82
+ export function getResetLayout( layoutBlockSupport = {}, blockVariation ) {
83
+ return cleanEmptyObject( {
84
+ ...getDefaultLayout( layoutBlockSupport, blockVariation ),
85
+ } );
86
+ }
87
+
88
+ function getLayoutStateOverrides(
89
+ layout = {},
90
+ baseLayout = {},
91
+ existingLayout = {}
92
+ ) {
93
+ const overrides = {};
94
+ const childLayoutValues = Object.fromEntries(
95
+ CHILD_LAYOUT_KEYS.filter( ( key ) =>
96
+ Object.hasOwn( existingLayout || {}, key )
97
+ ).map( ( key ) => [ key, existingLayout[ key ] ] )
98
+ );
99
+
100
+ Object.entries( layout || {} ).forEach( ( [ key, value ] ) => {
101
+ if (
102
+ ! CHILD_LAYOUT_KEYS.includes( key ) &&
103
+ value !== baseLayout?.[ key ]
104
+ ) {
105
+ overrides[ key ] = value;
106
+ }
107
+ } );
108
+
109
+ return cleanEmptyObject( {
110
+ ...childLayoutValues,
111
+ ...overrides,
112
+ } );
113
+ }
114
+
115
+ function getLayoutContainerValues( layout = {} ) {
116
+ return Object.fromEntries(
117
+ Object.entries( layout || {} ).filter(
118
+ ( [ key ] ) => ! CHILD_LAYOUT_KEYS.includes( key )
119
+ )
120
+ );
121
+ }
122
+
45
123
  function hasLayoutBlockSupport( blockName ) {
46
124
  return (
47
125
  hasBlockSupport( blockName, 'layout' ) ||
@@ -148,8 +226,71 @@ export function useLayoutStyles( blockAttributes = {}, blockName, selector ) {
148
226
  } );
149
227
  }
150
228
 
229
+ /**
230
+ * Generates responsive layout CSS for viewport state styles.
231
+ *
232
+ * Viewport state blockGap values need to go through the layout definitions
233
+ * because flow/constrained layouts use child margins while flex/grid use gap.
234
+ *
235
+ * @param { Object } options Options.
236
+ * @param { Object } options.attributes Block attributes.
237
+ * @param { string } options.blockName Block name.
238
+ * @param { string } options.selector CSS selector.
239
+ * @param { Object } options.layout Active block layout.
240
+ * @param { boolean } options.hasBlockGapSupport Whether block gap is supported.
241
+ * @param { * } options.globalBlockGapValue Global block gap fallback.
242
+ *
243
+ * @return { string } CSS rule.
244
+ */
245
+ export function getResponsiveLayoutStyles( {
246
+ attributes = {},
247
+ blockName,
248
+ selector,
249
+ layout = {},
250
+ hasBlockGapSupport,
251
+ globalBlockGapValue,
252
+ } ) {
253
+ return Object.entries( RESPONSIVE_BREAKPOINTS )
254
+ .map( ( [ viewport, mediaQuery ] ) => {
255
+ const viewportStyle = attributes?.style?.[ viewport ];
256
+ const viewportLayout = getLayoutContainerValues(
257
+ viewportStyle?.layout
258
+ );
259
+ const hasViewportLayout = Object.keys( viewportLayout ).length > 0;
260
+ const hasViewportBlockGap =
261
+ viewportStyle?.spacing &&
262
+ Object.hasOwn( viewportStyle.spacing, 'blockGap' );
263
+ const hasViewportPadding =
264
+ viewportStyle?.spacing &&
265
+ Object.hasOwn( viewportStyle.spacing, 'padding' );
266
+ if (
267
+ ! hasViewportLayout &&
268
+ ! hasViewportBlockGap &&
269
+ ! hasViewportPadding
270
+ ) {
271
+ return '';
272
+ }
273
+
274
+ const layoutType = getLayoutType( layout?.type || 'default' );
275
+ const viewportCSS = layoutType?.getLayoutStyle?.( {
276
+ blockName,
277
+ selector,
278
+ layout,
279
+ viewportOverrides: viewportLayout,
280
+ style: viewportStyle,
281
+ hasBlockGapSupport,
282
+ globalBlockGapValue,
283
+ } );
284
+
285
+ return viewportCSS ? `${ mediaQuery }{${ viewportCSS }}` : '';
286
+ } )
287
+ .filter( Boolean )
288
+ .join( '' );
289
+ }
290
+
151
291
  function LayoutPanelPure( {
152
292
  layout,
293
+ style,
153
294
  setAttributes,
154
295
  name: blockName,
155
296
  clientId,
@@ -157,13 +298,81 @@ function LayoutPanelPure( {
157
298
  const settings = useBlockSettings( blockName );
158
299
  // Block settings come from theme.json under settings.[blockName].
159
300
  const { layout: layoutSettings } = settings;
160
- const { themeSupportsLayout } = useSelect( ( select ) => {
161
- const { getSettings } = select( blockEditorStore );
162
- return {
163
- themeSupportsLayout: getSettings().supportsLayout,
164
- };
165
- }, [] );
301
+ const { themeSupportsLayout, activeBlockVariation, selectedState } =
302
+ useSelect(
303
+ ( select ) => {
304
+ const blockEditorSelect = select( blockEditorStore );
305
+ const { getBlockAttributes, getSettings } = blockEditorSelect;
306
+ const { getSelectedBlockStyleState } =
307
+ unlock( blockEditorSelect );
308
+ return {
309
+ activeBlockVariation: select(
310
+ blocksStore
311
+ ).getActiveBlockVariation(
312
+ blockName,
313
+ getBlockAttributes( clientId ) || {},
314
+ 'block'
315
+ ),
316
+ themeSupportsLayout: getSettings().supportsLayout,
317
+ selectedState:
318
+ getSelectedBlockStyleState?.( clientId ) ??
319
+ DEFAULT_BLOCK_STYLE_STATE,
320
+ };
321
+ },
322
+ [ blockName, clientId ]
323
+ );
324
+
166
325
  const blockEditingMode = useBlockEditingMode();
326
+ const isViewportLayoutState =
327
+ hasViewportBlockStyleState( selectedState ) &&
328
+ ! hasPseudoBlockStyleState( selectedState );
329
+ const resetLayoutFilter = useCallback(
330
+ ( ...resetArgs ) => {
331
+ const attributes = resetArgs[ 0 ] || {};
332
+ const context = resetArgs[ 1 ] || {};
333
+
334
+ if ( isViewportLayoutState ) {
335
+ const existingStateStyle =
336
+ getStyleForState(
337
+ attributes.style ?? style,
338
+ selectedState
339
+ ) || {};
340
+ const nextStateStyle = cleanEmptyObject( {
341
+ ...existingStateStyle,
342
+ layout: undefined,
343
+ } );
344
+
345
+ return {
346
+ style: setStyleForState(
347
+ attributes.style ?? style,
348
+ selectedState,
349
+ nextStateStyle
350
+ ),
351
+ };
352
+ }
353
+
354
+ const resetBlockName = context.name || blockName;
355
+ const resetLayoutBlockSupport = getBlockSupport(
356
+ resetBlockName,
357
+ layoutBlockSupportKey,
358
+ {}
359
+ );
360
+
361
+ return {
362
+ layout: getResetLayout(
363
+ resetLayoutBlockSupport,
364
+ activeBlockVariation
365
+ ),
366
+ };
367
+ },
368
+ [
369
+ blockName,
370
+ activeBlockVariation,
371
+ isViewportLayoutState,
372
+ selectedState,
373
+ style,
374
+ ]
375
+ );
167
376
 
168
377
  if ( blockEditingMode !== 'default' ) {
169
378
  return null;
@@ -194,9 +403,23 @@ function LayoutPanelPure( {
194
403
  * Try to find the layout type from either the
195
404
  * block's layout settings or any saved layout config.
196
405
  */
406
+ const baseLayout = layout || defaultBlockLayout || {};
407
+ const stateStyle = isViewportLayoutState
408
+ ? getStyleForState( style, selectedState )
409
+ : undefined;
410
+ const stateLayout = stateStyle?.layout;
411
+ const usedLayout = isViewportLayoutState
412
+ ? cleanEmptyObject( {
413
+ ...baseLayout,
414
+ ...stateLayout,
415
+ } ) || {}
416
+ : baseLayout;
417
+ const resetLayoutDefaults = isViewportLayoutState
418
+ ? baseLayout
419
+ : getResetLayout( layoutBlockSupport, activeBlockVariation );
197
420
  const blockSupportAndLayout = {
198
421
  ...layoutBlockSupport,
199
- ...layout,
422
+ ...usedLayout,
200
423
  };
201
424
  const { type, default: { type: defaultType = 'default' } = {} } =
202
425
  blockSupportAndLayout;
@@ -212,7 +435,6 @@ function LayoutPanelPure( {
212
435
  blockSupportAndLayout.inherit )
213
436
  );
214
437
 
215
- const usedLayout = layout || defaultBlockLayout || {};
216
438
  const { inherit = false, contentSize = null } = usedLayout;
217
439
  /**
218
440
  * `themeSupportsLayout` is only relevant to the `default/flow` or
@@ -231,76 +453,117 @@ function LayoutPanelPure( {
231
453
  const displayControlsForLegacyLayouts =
232
454
  ! usedLayout.type && ( contentSize || inherit );
233
455
  const hasContentSizeOrLegacySettings = !! inherit || !! contentSize;
234
-
235
- const onChangeType = ( newType ) =>
236
- setAttributes( { layout: { type: newType } } );
237
- const onChangeLayout = ( newLayout ) =>
238
- setAttributes( { layout: newLayout } );
456
+ const showLayoutTypeSwitcher =
457
+ isDefaultBlockStyleState( selectedState ) &&
458
+ ! inherit &&
459
+ allowSwitching;
460
+
461
+ const onChangeLayout = ( newLayout ) => {
462
+ if ( isViewportLayoutState ) {
463
+ const nextStateStyle = cleanEmptyObject( {
464
+ ...stateStyle,
465
+ layout: getLayoutStateOverrides(
466
+ cleanEmptyObject( newLayout ),
467
+ baseLayout,
468
+ stateStyle?.layout
469
+ ),
470
+ } );
471
+ setAttributes( {
472
+ style: setStyleForState( style, selectedState, nextStateStyle ),
473
+ } );
474
+ return;
475
+ }
476
+
477
+ setAttributes( { layout: cleanEmptyObject( newLayout ) } );
478
+ };
479
+ const onChangeType = ( newType ) => onChangeLayout( { type: newType } );
480
+ const resetLayout = () => onChangeLayout( resetLayoutDefaults );
481
+ const resetInheritToggle = () => onChangeLayout( { type: 'default' } );
482
+ const isUsingContentWidth = () =>
483
+ layoutType?.name === 'constrained' || hasContentSizeOrLegacySettings;
484
+ const hasInheritToggleValue = () =>
485
+ isViewportLayoutState
486
+ ? ( usedLayout?.type ?? 'default' ) !==
487
+ ( resetLayoutDefaults?.type ?? 'default' )
488
+ : layout?.type === 'constrained';
489
+ const hasLayoutTypeValue = () =>
490
+ ( usedLayout?.type ?? 'default' ) !==
491
+ ( resetLayoutDefaults?.type ?? 'default' );
239
492
 
240
493
  return (
241
494
  <>
242
- <InspectorControls>
243
- <PanelBody title={ __( 'Layout' ) }>
244
- { showInheritToggle && (
245
- <>
246
- <ToggleControl
247
- label={ __( 'Inner blocks use content width' ) }
248
- checked={
249
- layoutType?.name === 'constrained' ||
250
- hasContentSizeOrLegacySettings
251
- }
252
- onChange={ () =>
253
- setAttributes( {
254
- layout: {
255
- type:
256
- layoutType?.name ===
257
- 'constrained' ||
258
- hasContentSizeOrLegacySettings
259
- ? 'default'
260
- : 'constrained',
261
- },
262
- } )
263
- }
264
- help={
265
- layoutType?.name === 'constrained' ||
266
- hasContentSizeOrLegacySettings
267
- ? __(
268
- 'Nested blocks use content width with options for full and wide widths.'
269
- )
270
- : __(
271
- 'Nested blocks will fill the width of this container.'
272
- )
273
- }
274
- />
275
- </>
276
- ) }
277
-
278
- { ! inherit && allowSwitching && (
495
+ <InspectorControls
496
+ group="layout"
497
+ resetAllFilter={ resetLayoutFilter }
498
+ >
499
+ { showInheritToggle && (
500
+ <ToolsPanelItem
501
+ label={ __( 'Use content width' ) }
502
+ hasValue={ hasInheritToggleValue }
503
+ onDeselect={ resetInheritToggle }
504
+ isShownByDefault
505
+ panelId={ clientId }
506
+ >
507
+ <ToggleControl
508
+ label={ __( 'Inner blocks use content width' ) }
509
+ checked={ isUsingContentWidth() }
510
+ onChange={ () =>
511
+ onChangeLayout( {
512
+ type: isUsingContentWidth()
513
+ ? 'default'
514
+ : 'constrained',
515
+ } )
516
+ }
517
+ help={
518
+ isUsingContentWidth()
519
+ ? __(
520
+ 'Nested blocks use content width with options for full and wide widths.'
521
+ )
522
+ : __(
523
+ 'Nested blocks will fill the width of this container.'
524
+ )
525
+ }
526
+ />
527
+ </ToolsPanelItem>
528
+ ) }
529
+
530
+ { showLayoutTypeSwitcher && (
531
+ <ToolsPanelItem
532
+ label={ __( 'Layout type' ) }
533
+ hasValue={ hasLayoutTypeValue }
534
+ onDeselect={ resetLayout }
535
+ isShownByDefault
536
+ panelId={ clientId }
537
+ >
279
538
  <LayoutTypeSwitcher
280
539
  type={ blockLayoutType }
281
540
  onChange={ onChangeType }
282
541
  />
283
- ) }
284
-
285
- { layoutType && layoutType.name !== 'default' && (
286
- <layoutType.inspectorControls
287
- layout={ usedLayout }
288
- onChange={ onChangeLayout }
289
- layoutBlockSupport={ blockSupportAndThemeSettings }
290
- name={ blockName }
291
- clientId={ clientId }
292
- />
293
- ) }
294
- { constrainedType && displayControlsForLegacyLayouts && (
295
- <constrainedType.inspectorControls
296
- layout={ usedLayout }
297
- onChange={ onChangeLayout }
298
- layoutBlockSupport={ blockSupportAndThemeSettings }
299
- name={ blockName }
300
- clientId={ clientId }
301
- />
302
- ) }
303
- </PanelBody>
542
+ </ToolsPanelItem>
543
+ ) }
544
+
545
+ { layoutType && layoutType.name !== 'default' && (
546
+ <layoutType.inspectorControls
547
+ layout={ usedLayout }
548
+ value={ layout }
549
+ onChange={ onChangeLayout }
550
+ layoutBlockSupport={ blockSupportAndThemeSettings }
551
+ resetLayout={ resetLayoutDefaults }
552
+ name={ blockName }
553
+ clientId={ clientId }
554
+ />
555
+ ) }
556
+ { constrainedType && displayControlsForLegacyLayouts && (
557
+ <constrainedType.inspectorControls
558
+ layout={ usedLayout }
559
+ value={ layout }
560
+ onChange={ onChangeLayout }
561
+ layoutBlockSupport={ blockSupportAndThemeSettings }
562
+ resetLayout={ resetLayoutDefaults }
563
+ name={ blockName }
564
+ clientId={ clientId }
565
+ />
566
+ ) }
304
567
  </InspectorControls>
305
568
  { ! inherit && layoutType && (
306
569
  <layoutType.toolBarControls
@@ -318,7 +581,7 @@ function LayoutPanelPure( {
318
581
  export default {
319
582
  shareWithChildBlocks: true,
320
583
  edit: LayoutPanelPure,
321
- attributeKeys: [ 'layout' ],
584
+ attributeKeys: [ 'layout', 'style' ],
322
585
  hasSupport( name ) {
323
586
  return hasLayoutBlockSupport( name );
324
587
  },
@@ -396,7 +659,7 @@ function BlockWithLayoutStyles( {
396
659
  // Get CSS string for the current layout type.
397
660
  // The CSS and `style` element is only output if it is not empty.
398
661
  const fullLayoutType = getLayoutType( usedLayout?.type || 'default' );
399
- const css = fullLayoutType?.getLayoutStyle?.( {
662
+ const baseLayoutCSS = fullLayoutType?.getLayoutStyle?.( {
400
663
  blockName: name,
401
664
  selector,
402
665
  layout: usedLayout,
@@ -404,6 +667,17 @@ function BlockWithLayoutStyles( {
404
667
  hasBlockGapSupport,
405
668
  globalBlockGapValue,
406
669
  } );
670
+ const responsiveLayoutCSS = getResponsiveLayoutStyles( {
671
+ attributes,
672
+ blockName: name,
673
+ selector,
674
+ layout: usedLayout,
675
+ hasBlockGapSupport,
676
+ globalBlockGapValue,
677
+ } );
678
+ const css = [ baseLayoutCSS, responsiveLayoutCSS ]
679
+ .filter( Boolean )
680
+ .join( '' );
407
681
 
408
682
  // Attach a `wp-container-` id-based class name as well as a layout class name such as `is-layout-flex`.
409
683
  const layoutClassNames = clsx(
@@ -13,6 +13,12 @@
13
13
  margin-bottom: 0; // Cancel out margins added by common.css
14
14
  }
15
15
 
16
+ .layout-block-support-panel {
17
+ .block-editor-hooks__flex-layout-controls {
18
+ grid-column: 1 / -1;
19
+ }
20
+ }
21
+
16
22
  .block-editor-hooks__flex-layout-justification-controls,
17
23
  .block-editor-hooks__flex-layout-orientation-controls {
18
24
  margin-bottom: $grid-unit-15;
@@ -0,0 +1,158 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { getBlockType } from '@wordpress/blocks';
5
+ import { splitSelectorList } from '@wordpress/global-styles-engine';
6
+
7
+ /**
8
+ * Given a block's `selectors.root` value, returns the part of the selector
9
+ * that is relative to the block wrapper — i.e., everything after the first
10
+ * compound selector segment.
11
+ *
12
+ * Examples:
13
+ * ".wp-block-button .wp-block-button__link" → ".wp-block-button__link"
14
+ * ".wp-block-foo > .inner" → "> .inner"
15
+ * ".wp-block-foo" → null (no descendant)
16
+ *
17
+ * @param {string} rootSelector The block's `selectors.root` value.
18
+ * @return {string|null} Relative selector, or null if rootSelector targets the wrapper itself.
19
+ */
20
+ export function getRelativeRootSelector( rootSelector ) {
21
+ // Match everything after the first compound selector (up to the first
22
+ // whitespace or combinator character).
23
+ // Require at least one combinator character (space, >, +, ~) between the
24
+ // first compound selector and the rest. Without this anchor, a greedy
25
+ // quantifier would backtrack into the first token and produce false matches.
26
+ const match = rootSelector.trim().match( /^[^ >+~]+[ >+~](.*)$/ );
27
+ if ( ! match ) {
28
+ return null;
29
+ }
30
+ const rest = match[ 1 ].trim();
31
+ return rest || null;
32
+ }
33
+
34
+ /**
35
+ * Builds a scoped selector from a block selector and optional suffix.
36
+ *
37
+ * If the block selector targets a descendant, the descendant portion is scoped
38
+ * under the provided base selector. Otherwise the base selector itself is used.
39
+ *
40
+ * @param {string} baseSelector The block-instance scoping selector.
41
+ * @param {string} blockSelector The block or feature selector from block metadata.
42
+ * @param {string} suffix Optional selector suffix, e.g. ":hover".
43
+ * @return {string} The scoped CSS selector.
44
+ */
45
+ export function buildScopedBlockSelector(
46
+ baseSelector,
47
+ blockSelector,
48
+ suffix = ''
49
+ ) {
50
+ if ( typeof blockSelector !== 'string' || ! blockSelector ) {
51
+ return splitSelectorList( baseSelector )
52
+ .map( ( selector ) => `${ selector.trim() }${ suffix }` )
53
+ .join( ', ' );
54
+ }
55
+
56
+ const baseSelectors = splitSelectorList( baseSelector ).filter(
57
+ ( selector ) => selector.trim()
58
+ );
59
+ const selectors = splitSelectorList( blockSelector ).filter( ( selector ) =>
60
+ selector.trim()
61
+ );
62
+
63
+ if ( ! selectors.length ) {
64
+ return baseSelectors
65
+ .map( ( selector ) => `${ selector.trim() }${ suffix }` )
66
+ .join( ', ' );
67
+ }
68
+
69
+ return selectors
70
+ .map( ( selector ) => {
71
+ selector = selector.trim();
72
+
73
+ /*
74
+ * Replace only the leading block selector part (e.g. class name,
75
+ * attribute selector, ID, or tag name) with the block instance selector.
76
+ * Preserve anything after that prefix, including modifier classes on the
77
+ * same element and combinators without spaces.
78
+ */
79
+ const match = selector.match( /^([.#]?[-_a-zA-Z0-9]+|\[[^\]]+\])/ );
80
+ if ( match ) {
81
+ return baseSelectors
82
+ .map(
83
+ ( base ) =>
84
+ `${ base.trim() }${ selector.slice(
85
+ match[ 0 ].length
86
+ ) }${ suffix }`
87
+ )
88
+ .join( ', ' );
89
+ }
90
+
91
+ return baseSelectors
92
+ .map( ( base ) => `${ base.trim() }${ suffix }` )
93
+ .join( ', ' );
94
+ } )
95
+ .join( ', ' );
96
+ }
97
+
98
+ /**
99
+ * Builds the scoped selector for root block style state styles.
100
+ *
101
+ * Uses the block's `selectors.root` to determine which element should receive
102
+ * root-level state styles. If `selectors.root` describes a descendant element
103
+ * (e.g. `.wp-block-button .wp-block-button__link`), the relative portion is
104
+ * scoped under `baseSelector`. If no descendant is present, falls back to the
105
+ * base selector.
106
+ *
107
+ * @param {string} baseSelector The block-instance scoping class selector.
108
+ * @param {string} name The block name, used to look up selectors.
109
+ * @return {string} The fully-scoped CSS selector for root state styles.
110
+ */
111
+ export function buildRootStyleStateSelector( baseSelector, name ) {
112
+ const rootSelector = getBlockType( name )?.selectors?.root;
113
+ return buildScopedBlockSelector( baseSelector, rootSelector );
114
+ }
115
+
116
+ /**
117
+ * Builds the scoped CSS selector for a block state (e.g. :hover, :focus).
118
+ *
119
+ * Uses the block's `selectors.root` to determine which element the state
120
+ * pseudo-class should apply to. If `selectors.root` describes a descendant
121
+ * element (e.g. ".wp-block-button .wp-block-button__link"), the relative
122
+ * portion (".wp-block-button__link") is scoped under `baseSelector`. If no
123
+ * descendant is present, falls back to appending the state to `baseSelector`.
124
+ *
125
+ * @param {string} baseSelector The block-instance scoping class selector.
126
+ * @param {string} name The block name, used to look up selectors.
127
+ * @param {string} state The pseudo-class string, e.g. ":hover".
128
+ * @return {string} The fully-scoped CSS selector for this state.
129
+ */
130
+ export function buildPseudoStyleStateSelector( baseSelector, name, state ) {
131
+ return `${ buildRootStyleStateSelector( baseSelector, name ) }${ state }`;
132
+ }
133
+
134
+ export function buildStateSelector( baseSelector, name, state ) {
135
+ const rootSelector = getBlockType( name )?.selectors?.root;
136
+ return buildScopedBlockSelector( baseSelector, rootSelector, state );
137
+ }
138
+
139
+ /**
140
+ * Builds the CSS selector used to preview a state on the editor canvas,
141
+ * scoped to a specific block instance via its `data-block` attribute.
142
+ *
143
+ * For blocks whose `selectors.root` targets a descendant element
144
+ * (e.g. ".wp-block-button .wp-block-button__link"), the selector targets
145
+ * that descendant inside the block wrapper. Otherwise it targets the wrapper
146
+ * itself.
147
+ *
148
+ * @param {string} clientId The block's clientId.
149
+ * @param {string} name The block name, used to look up selectors.
150
+ * @return {string} CSS selector scoped to this block instance.
151
+ */
152
+ export function buildCanvasStateSelector( clientId, name ) {
153
+ const rootSelector = getBlockType( name )?.selectors?.root;
154
+ return buildScopedBlockSelector(
155
+ `[data-block="${ clientId }"]`,
156
+ rootSelector
157
+ );
158
+ }