@wordpress/block-editor 14.8.0 → 14.8.1-next.a9f418477.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 (290) hide show
  1. package/build/autocompleters/block.js +2 -4
  2. package/build/autocompleters/block.js.map +1 -1
  3. package/build/autocompleters/link.js +2 -4
  4. package/build/autocompleters/link.js.map +1 -1
  5. package/build/components/block-canvas/index.js +3 -6
  6. package/build/components/block-canvas/index.js.map +1 -1
  7. package/build/components/block-list/block.js +6 -5
  8. package/build/components/block-list/block.js.map +1 -1
  9. package/build/components/block-list/index.js +0 -1
  10. package/build/components/block-list/index.js.map +1 -1
  11. package/build/components/block-list/use-block-props/index.js +6 -2
  12. package/build/components/block-list/use-block-props/index.js.map +1 -1
  13. package/build/components/block-list/use-block-props/use-firefox-draggable-compatibility.js +87 -0
  14. package/build/components/block-list/use-block-props/use-firefox-draggable-compatibility.js.map +1 -0
  15. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js +98 -5
  16. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +1 -1
  17. package/build/components/block-lock/modal.js +4 -4
  18. package/build/components/block-lock/modal.js.map +1 -1
  19. package/build/components/block-parent-selector/index.js +2 -15
  20. package/build/components/block-parent-selector/index.js.map +1 -1
  21. package/build/components/block-patterns-list/index.js +13 -4
  22. package/build/components/block-patterns-list/index.js.map +1 -1
  23. package/build/components/block-popover/inbetween.js +4 -0
  24. package/build/components/block-popover/inbetween.js.map +1 -1
  25. package/build/components/block-settings-menu/block-settings-dropdown.js +7 -4
  26. package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  27. package/build/components/block-settings-menu-controls/index.js +1 -1
  28. package/build/components/block-settings-menu-controls/index.js.map +1 -1
  29. package/build/components/block-switcher/index.js +12 -22
  30. package/build/components/block-switcher/index.js.map +1 -1
  31. package/build/components/block-switcher/use-transformed-patterns.js +0 -1
  32. package/build/components/block-switcher/use-transformed-patterns.js.map +1 -1
  33. package/build/components/block-switcher/utils.js +0 -1
  34. package/build/components/block-switcher/utils.js.map +1 -1
  35. package/build/components/block-toolbar/index.js +7 -6
  36. package/build/components/block-toolbar/index.js.map +1 -1
  37. package/build/components/block-variation-transforms/index.js +0 -1
  38. package/build/components/block-variation-transforms/index.js.map +1 -1
  39. package/build/components/date-format-picker/index.js +0 -1
  40. package/build/components/date-format-picker/index.js.map +1 -1
  41. package/build/components/font-appearance-control/index.js +1 -0
  42. package/build/components/font-appearance-control/index.js.map +1 -1
  43. package/build/components/font-family/index.js +10 -0
  44. package/build/components/font-family/index.js.map +1 -1
  45. package/build/components/global-styles/dimensions-panel.js +17 -16
  46. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  47. package/build/components/global-styles/get-global-styles-changes.js +0 -1
  48. package/build/components/global-styles/get-global-styles-changes.js.map +1 -1
  49. package/build/components/iframe/use-scale-canvas.js +68 -47
  50. package/build/components/iframe/use-scale-canvas.js.map +1 -1
  51. package/build/components/inserter/block-patterns-tab/index.js +0 -10
  52. package/build/components/inserter/block-patterns-tab/index.js.map +1 -1
  53. package/build/components/inserter/menu.js +2 -1
  54. package/build/components/inserter/menu.js.map +1 -1
  55. package/build/components/inserter-draggable-blocks/index.js +19 -10
  56. package/build/components/inserter-draggable-blocks/index.js.map +1 -1
  57. package/build/components/inspector-controls/slot.js +2 -13
  58. package/build/components/inspector-controls/slot.js.map +1 -1
  59. package/build/components/letter-spacing-control/index.js +10 -0
  60. package/build/components/letter-spacing-control/index.js.map +1 -1
  61. package/build/components/line-height-control/index.js +1 -0
  62. package/build/components/line-height-control/index.js.map +1 -1
  63. package/build/components/media-placeholder/index.js +18 -18
  64. package/build/components/media-placeholder/index.js.map +1 -1
  65. package/build/components/multi-selection-inspector/index.js +9 -25
  66. package/build/components/multi-selection-inspector/index.js.map +1 -1
  67. package/build/components/observe-typing/index.js +0 -1
  68. package/build/components/observe-typing/index.js.map +1 -1
  69. package/build/components/recursion-provider/index.js +0 -1
  70. package/build/components/recursion-provider/index.js.map +1 -1
  71. package/build/components/rich-text/index.js +5 -1
  72. package/build/components/rich-text/index.js.map +1 -1
  73. package/build/components/rich-text/native/use-format-types.js +0 -1
  74. package/build/components/rich-text/native/use-format-types.js.map +1 -1
  75. package/build/components/rich-text/use-format-types.js +0 -1
  76. package/build/components/rich-text/use-format-types.js.map +1 -1
  77. package/build/components/spacing-sizes-control/utils.js +0 -1
  78. package/build/components/spacing-sizes-control/utils.js.map +1 -1
  79. package/build/components/typewriter/index.js +0 -1
  80. package/build/components/typewriter/index.js.map +1 -1
  81. package/build/components/use-block-drop-zone/index.js +11 -2
  82. package/build/components/use-block-drop-zone/index.js.map +1 -1
  83. package/build/components/use-moving-animation/index.js +15 -2
  84. package/build/components/use-moving-animation/index.js.map +1 -1
  85. package/build/components/use-resize-canvas/index.js +1 -1
  86. package/build/components/use-resize-canvas/index.js.map +1 -1
  87. package/build/components/warning/index.js +2 -3
  88. package/build/components/warning/index.js.map +1 -1
  89. package/build/components/writing-flow/use-drag-selection.js +11 -0
  90. package/build/components/writing-flow/use-drag-selection.js.map +1 -1
  91. package/build/components/writing-flow/use-tab-nav.js +6 -2
  92. package/build/components/writing-flow/use-tab-nav.js.map +1 -1
  93. package/build/hooks/block-bindings.js +4 -3
  94. package/build/hooks/block-bindings.js.map +1 -1
  95. package/build/hooks/gap.js +1 -1
  96. package/build/hooks/gap.js.map +1 -1
  97. package/build/hooks/generated-class-name.js +0 -1
  98. package/build/hooks/generated-class-name.js.map +1 -1
  99. package/build/hooks/use-zoom-out.js +47 -14
  100. package/build/hooks/use-zoom-out.js.map +1 -1
  101. package/build/store/private-selectors.js +1 -7
  102. package/build/store/private-selectors.js.map +1 -1
  103. package/build/store/reducer.js +478 -2
  104. package/build/store/reducer.js.map +1 -1
  105. package/build/store/selectors.js +12 -55
  106. package/build/store/selectors.js.map +1 -1
  107. package/build/utils/object.js +0 -1
  108. package/build/utils/object.js.map +1 -1
  109. package/build-module/autocompleters/block.js +2 -4
  110. package/build-module/autocompleters/block.js.map +1 -1
  111. package/build-module/autocompleters/link.js +2 -4
  112. package/build-module/autocompleters/link.js.map +1 -1
  113. package/build-module/components/block-canvas/index.js +3 -6
  114. package/build-module/components/block-canvas/index.js.map +1 -1
  115. package/build-module/components/block-list/block.js +8 -7
  116. package/build-module/components/block-list/block.js.map +1 -1
  117. package/build-module/components/block-list/index.js +0 -1
  118. package/build-module/components/block-list/index.js.map +1 -1
  119. package/build-module/components/block-list/use-block-props/index.js +6 -2
  120. package/build-module/components/block-list/use-block-props/index.js.map +1 -1
  121. package/build-module/components/block-list/use-block-props/use-firefox-draggable-compatibility.js +80 -0
  122. package/build-module/components/block-list/use-block-props/use-firefox-draggable-compatibility.js.map +1 -0
  123. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js +97 -5
  124. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +1 -1
  125. package/build-module/components/block-lock/modal.js +4 -4
  126. package/build-module/components/block-lock/modal.js.map +1 -1
  127. package/build-module/components/block-parent-selector/index.js +2 -15
  128. package/build-module/components/block-parent-selector/index.js.map +1 -1
  129. package/build-module/components/block-patterns-list/index.js +13 -4
  130. package/build-module/components/block-patterns-list/index.js.map +1 -1
  131. package/build-module/components/block-popover/inbetween.js +4 -0
  132. package/build-module/components/block-popover/inbetween.js.map +1 -1
  133. package/build-module/components/block-settings-menu/block-settings-dropdown.js +7 -4
  134. package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  135. package/build-module/components/block-settings-menu-controls/index.js +1 -1
  136. package/build-module/components/block-settings-menu-controls/index.js.map +1 -1
  137. package/build-module/components/block-switcher/index.js +13 -23
  138. package/build-module/components/block-switcher/index.js.map +1 -1
  139. package/build-module/components/block-switcher/use-transformed-patterns.js +0 -1
  140. package/build-module/components/block-switcher/use-transformed-patterns.js.map +1 -1
  141. package/build-module/components/block-switcher/utils.js +0 -1
  142. package/build-module/components/block-switcher/utils.js.map +1 -1
  143. package/build-module/components/block-toolbar/index.js +7 -6
  144. package/build-module/components/block-toolbar/index.js.map +1 -1
  145. package/build-module/components/block-variation-transforms/index.js +0 -1
  146. package/build-module/components/block-variation-transforms/index.js.map +1 -1
  147. package/build-module/components/date-format-picker/index.js +0 -1
  148. package/build-module/components/date-format-picker/index.js.map +1 -1
  149. package/build-module/components/font-appearance-control/index.js +1 -0
  150. package/build-module/components/font-appearance-control/index.js.map +1 -1
  151. package/build-module/components/font-family/index.js +10 -0
  152. package/build-module/components/font-family/index.js.map +1 -1
  153. package/build-module/components/global-styles/dimensions-panel.js +17 -16
  154. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  155. package/build-module/components/global-styles/get-global-styles-changes.js +0 -1
  156. package/build-module/components/global-styles/get-global-styles-changes.js.map +1 -1
  157. package/build-module/components/iframe/use-scale-canvas.js +68 -47
  158. package/build-module/components/iframe/use-scale-canvas.js.map +1 -1
  159. package/build-module/components/inserter/block-patterns-tab/index.js +1 -11
  160. package/build-module/components/inserter/block-patterns-tab/index.js.map +1 -1
  161. package/build-module/components/inserter/menu.js +2 -1
  162. package/build-module/components/inserter/menu.js.map +1 -1
  163. package/build-module/components/inserter-draggable-blocks/index.js +20 -11
  164. package/build-module/components/inserter-draggable-blocks/index.js.map +1 -1
  165. package/build-module/components/inspector-controls/slot.js +3 -14
  166. package/build-module/components/inspector-controls/slot.js.map +1 -1
  167. package/build-module/components/letter-spacing-control/index.js +9 -0
  168. package/build-module/components/letter-spacing-control/index.js.map +1 -1
  169. package/build-module/components/line-height-control/index.js +1 -0
  170. package/build-module/components/line-height-control/index.js.map +1 -1
  171. package/build-module/components/media-placeholder/index.js +18 -18
  172. package/build-module/components/media-placeholder/index.js.map +1 -1
  173. package/build-module/components/multi-selection-inspector/index.js +9 -25
  174. package/build-module/components/multi-selection-inspector/index.js.map +1 -1
  175. package/build-module/components/observe-typing/index.js +0 -1
  176. package/build-module/components/observe-typing/index.js.map +1 -1
  177. package/build-module/components/recursion-provider/index.js +0 -1
  178. package/build-module/components/recursion-provider/index.js.map +1 -1
  179. package/build-module/components/rich-text/index.js +5 -1
  180. package/build-module/components/rich-text/index.js.map +1 -1
  181. package/build-module/components/rich-text/native/use-format-types.js +0 -1
  182. package/build-module/components/rich-text/native/use-format-types.js.map +1 -1
  183. package/build-module/components/rich-text/use-format-types.js +0 -1
  184. package/build-module/components/rich-text/use-format-types.js.map +1 -1
  185. package/build-module/components/spacing-sizes-control/utils.js +0 -1
  186. package/build-module/components/spacing-sizes-control/utils.js.map +1 -1
  187. package/build-module/components/typewriter/index.js +0 -1
  188. package/build-module/components/typewriter/index.js.map +1 -1
  189. package/build-module/components/use-block-drop-zone/index.js +11 -2
  190. package/build-module/components/use-block-drop-zone/index.js.map +1 -1
  191. package/build-module/components/use-moving-animation/index.js +15 -2
  192. package/build-module/components/use-moving-animation/index.js.map +1 -1
  193. package/build-module/components/use-resize-canvas/index.js +1 -1
  194. package/build-module/components/use-resize-canvas/index.js.map +1 -1
  195. package/build-module/components/warning/index.js +2 -3
  196. package/build-module/components/warning/index.js.map +1 -1
  197. package/build-module/components/writing-flow/use-drag-selection.js +11 -0
  198. package/build-module/components/writing-flow/use-drag-selection.js.map +1 -1
  199. package/build-module/components/writing-flow/use-tab-nav.js +6 -2
  200. package/build-module/components/writing-flow/use-tab-nav.js.map +1 -1
  201. package/build-module/hooks/block-bindings.js +4 -3
  202. package/build-module/hooks/block-bindings.js.map +1 -1
  203. package/build-module/hooks/gap.js +1 -1
  204. package/build-module/hooks/gap.js.map +1 -1
  205. package/build-module/hooks/generated-class-name.js +0 -1
  206. package/build-module/hooks/generated-class-name.js.map +1 -1
  207. package/build-module/hooks/use-zoom-out.js +48 -15
  208. package/build-module/hooks/use-zoom-out.js.map +1 -1
  209. package/build-module/store/private-selectors.js +1 -6
  210. package/build-module/store/private-selectors.js.map +1 -1
  211. package/build-module/store/reducer.js +479 -3
  212. package/build-module/store/reducer.js.map +1 -1
  213. package/build-module/store/selectors.js +12 -55
  214. package/build-module/store/selectors.js.map +1 -1
  215. package/build-module/utils/object.js +0 -1
  216. package/build-module/utils/object.js.map +1 -1
  217. package/build-style/content-rtl.css +18 -5
  218. package/build-style/content.css +18 -5
  219. package/build-style/style-rtl.css +25 -64
  220. package/build-style/style.css +25 -64
  221. package/package.json +32 -32
  222. package/src/autocompleters/block.js +2 -4
  223. package/src/autocompleters/link.js +2 -4
  224. package/src/components/alignment-control/stories/aliginment-toolbar.story.js +47 -0
  225. package/src/components/alignment-control/stories/index.story.js +51 -0
  226. package/src/components/alignment-control/test/__snapshots__/index.js.snap +5 -5
  227. package/src/components/block-alignment-control/test/__snapshots__/index.js.snap +4 -4
  228. package/src/components/block-canvas/index.js +3 -5
  229. package/src/components/block-draggable/content.scss +11 -5
  230. package/src/components/block-list/block.js +7 -13
  231. package/src/components/block-list/content.scss +6 -0
  232. package/src/components/block-list/use-block-props/index.js +5 -0
  233. package/src/components/block-list/use-block-props/use-firefox-draggable-compatibility.js +83 -0
  234. package/src/components/block-list/use-block-props/use-selected-block-event-handlers.js +112 -8
  235. package/src/components/block-lock/modal.js +4 -6
  236. package/src/components/block-parent-selector/index.js +1 -19
  237. package/src/components/block-patterns-list/index.js +12 -1
  238. package/src/components/block-patterns-list/stories/fixtures.js +1 -0
  239. package/src/components/block-patterns-list/style.scss +16 -5
  240. package/src/components/block-popover/inbetween.js +4 -0
  241. package/src/components/block-settings-menu/block-settings-dropdown.js +6 -1
  242. package/src/components/block-settings-menu-controls/index.js +2 -1
  243. package/src/components/block-switcher/index.js +19 -21
  244. package/src/components/block-switcher/style.scss +0 -9
  245. package/src/components/block-title/test/index.js +2 -0
  246. package/src/components/block-toolbar/index.js +9 -6
  247. package/src/components/block-tools/style.scss +5 -0
  248. package/src/components/block-vertical-alignment-control/test/__snapshots__/index.js.snap +3 -3
  249. package/src/components/dimensions-tool/stories/aspect-ratio-tool.story.js +1 -1
  250. package/src/components/dimensions-tool/stories/index.story.js +1 -1
  251. package/src/components/dimensions-tool/stories/scale-tool.story.js +1 -1
  252. package/src/components/dimensions-tool/stories/width-height-tool.story.js +1 -1
  253. package/src/components/font-appearance-control/index.js +1 -0
  254. package/src/components/font-family/index.js +10 -0
  255. package/src/components/font-family/style.scss +5 -0
  256. package/src/components/global-styles/dimensions-panel.js +16 -16
  257. package/src/components/iframe/content.scss +6 -1
  258. package/src/components/iframe/use-scale-canvas.js +103 -81
  259. package/src/components/inserter/block-patterns-tab/index.js +1 -17
  260. package/src/components/inserter/menu.js +8 -1
  261. package/src/components/inserter-draggable-blocks/index.js +19 -29
  262. package/src/components/inspector-controls/slot.js +3 -22
  263. package/src/components/letter-spacing-control/README.md +2 -1
  264. package/src/components/letter-spacing-control/index.js +17 -0
  265. package/src/components/line-height-control/index.js +1 -0
  266. package/src/components/media-placeholder/index.js +25 -28
  267. package/src/components/multi-selection-inspector/index.js +17 -27
  268. package/src/components/multi-selection-inspector/style.scss +0 -12
  269. package/src/components/resolution-tool/stories/index.story.js +1 -1
  270. package/src/components/rich-text/index.js +5 -0
  271. package/src/components/spacing-sizes-control/style.scss +0 -29
  272. package/src/components/text-alignment-control/stories/index.story.js +1 -1
  273. package/src/components/use-block-drop-zone/index.js +18 -1
  274. package/src/components/use-moving-animation/index.js +15 -0
  275. package/src/components/use-resize-canvas/index.js +1 -1
  276. package/src/components/warning/index.js +3 -4
  277. package/src/components/warning/test/index.js +3 -1
  278. package/src/components/writing-flow/use-drag-selection.js +11 -0
  279. package/src/components/writing-flow/use-tab-nav.js +9 -6
  280. package/src/hooks/block-bindings.js +8 -4
  281. package/src/hooks/gap.js +1 -1
  282. package/src/hooks/use-zoom-out.js +48 -16
  283. package/src/store/private-selectors.js +2 -17
  284. package/src/store/reducer.js +639 -2
  285. package/src/store/selectors.js +19 -69
  286. package/src/store/test/private-selectors.js +1 -0
  287. package/src/store/test/reducer.js +849 -0
  288. package/src/store/test/selectors.js +4 -110
  289. package/src/style.scss +1 -0
  290. package/tsconfig.tsbuildinfo +1 -1
@@ -9,12 +9,20 @@ import fastDeepEqual from 'fast-deep-equal/es6';
9
9
  import { pipe } from '@wordpress/compose';
10
10
  import { combineReducers, select } from '@wordpress/data';
11
11
  import deprecated from '@wordpress/deprecated';
12
- import { store as blocksStore } from '@wordpress/blocks';
12
+ import {
13
+ store as blocksStore,
14
+ privateApis as blocksPrivateApis,
15
+ } from '@wordpress/blocks';
16
+
13
17
  /**
14
18
  * Internal dependencies
15
19
  */
16
20
  import { PREFERENCES_DEFAULTS, SETTINGS_DEFAULTS } from './defaults';
17
21
  import { insertAt, moveTo } from './array';
22
+ import { sectionRootClientIdKey } from './private-keys';
23
+ import { unlock } from '../lock-unlock';
24
+
25
+ const { isContentBlock } = unlock( blocksPrivateApis );
18
26
 
19
27
  const identity = ( x ) => x;
20
28
 
@@ -2131,6 +2139,632 @@ const combinedReducers = combineReducers( {
2131
2139
  zoomLevel,
2132
2140
  } );
2133
2141
 
2142
+ /**
2143
+ * Retrieves a block's tree structure, handling both controlled and uncontrolled inner blocks.
2144
+ *
2145
+ * @param {Object} state The current state object.
2146
+ * @param {string} clientId The client ID of the block to retrieve.
2147
+ *
2148
+ * @return {Object|undefined} The block tree object, or undefined if not found. For controlled blocks,
2149
+ * returns a merged tree with controlled inner blocks.
2150
+ */
2151
+ function getBlockTreeBlock( state, clientId ) {
2152
+ if ( clientId === '' ) {
2153
+ const rootBlock = state.blocks.tree.get( clientId );
2154
+
2155
+ if ( ! rootBlock ) {
2156
+ return;
2157
+ }
2158
+
2159
+ // Patch the root block to have a clientId property.
2160
+ // TODO - consider updating the blocks reducer so that the root block has this property.
2161
+ return {
2162
+ clientId: '',
2163
+ ...rootBlock,
2164
+ };
2165
+ }
2166
+
2167
+ if ( ! state.blocks.controlledInnerBlocks[ clientId ] ) {
2168
+ return state.blocks.tree.get( clientId );
2169
+ }
2170
+
2171
+ const controlledTree = state.blocks.tree.get( `controlled||${ clientId }` );
2172
+ const regularTree = state.blocks.tree.get( clientId );
2173
+
2174
+ return {
2175
+ ...regularTree,
2176
+ innerBlocks: controlledTree?.innerBlocks,
2177
+ };
2178
+ }
2179
+
2180
+ /**
2181
+ * Recursively traverses through a block tree of a given block and executes a callback for each block.
2182
+ *
2183
+ * @param {Object} state The store state.
2184
+ * @param {string} clientId The clientId of the block to start traversing from.
2185
+ * @param {Function} callback Function to execute for each block encountered during traversal.
2186
+ * The callback receives the current block as its argument.
2187
+ */
2188
+ function traverseBlockTree( state, clientId, callback ) {
2189
+ const parentTree = getBlockTreeBlock( state, clientId );
2190
+ if ( ! parentTree ) {
2191
+ return;
2192
+ }
2193
+
2194
+ callback( parentTree );
2195
+
2196
+ if ( ! parentTree?.innerBlocks?.length ) {
2197
+ return;
2198
+ }
2199
+
2200
+ for ( const block of parentTree?.innerBlocks ) {
2201
+ traverseBlockTree( state, block.clientId, callback );
2202
+ }
2203
+ }
2204
+
2205
+ /**
2206
+ * Checks if a block has a parent in a list of client IDs, and if so returns the client ID of the parent.
2207
+ *
2208
+ * @param {Object} state The current state object.
2209
+ * @param {string} clientId The client ID of the block to search the parents of.
2210
+ * @param {Array} clientIds The client IDs of the blocks to check.
2211
+ *
2212
+ * @return {string|undefined} The client ID of the parent block if found, undefined otherwise.
2213
+ */
2214
+ function findParentInClientIdsList( state, clientId, clientIds ) {
2215
+ let parent = state.blocks.parents.get( clientId );
2216
+ while ( parent ) {
2217
+ if ( clientIds.includes( parent ) ) {
2218
+ return parent;
2219
+ }
2220
+ parent = state.blocks.parents.get( parent );
2221
+ }
2222
+ }
2223
+
2224
+ /**
2225
+ * Checks if a block has any bindings in its metadata attributes.
2226
+ *
2227
+ * @param {Object} block The block object to check for bindings.
2228
+ * @return {boolean} True if the block has bindings, false otherwise.
2229
+ */
2230
+ function hasBindings( block ) {
2231
+ return (
2232
+ block?.attributes?.metadata?.bindings &&
2233
+ Object.keys( block?.attributes?.metadata?.bindings ).length
2234
+ );
2235
+ }
2236
+
2237
+ /**
2238
+ * Computes and returns derived block editing modes for a given block tree.
2239
+ *
2240
+ * This function calculates the editing modes for each block in the tree, taking into account
2241
+ * various factors such as zoom level, navigation mode, sections, and synced patterns.
2242
+ *
2243
+ * @param {Object} state The current state object.
2244
+ * @param {boolean} isNavMode Whether the navigation mode is active.
2245
+ * @param {string} treeClientId The client ID of the root block for the tree. Defaults to an empty string.
2246
+ * @return {Map} A Map containing the derived block editing modes, keyed by block client ID.
2247
+ */
2248
+ function getDerivedBlockEditingModesForTree(
2249
+ state,
2250
+ isNavMode = false,
2251
+ treeClientId = ''
2252
+ ) {
2253
+ const isZoomedOut =
2254
+ state?.zoomLevel < 100 || state?.zoomLevel === 'auto-scaled';
2255
+ const derivedBlockEditingModes = new Map();
2256
+
2257
+ // When there are sections, the majority of blocks are disabled,
2258
+ // so the default block editing mode is set to disabled.
2259
+ const sectionRootClientId = state.settings?.[ sectionRootClientIdKey ];
2260
+ const sectionClientIds = state.blocks.order.get( sectionRootClientId );
2261
+ const syncedPatternClientIds = Object.keys(
2262
+ state.blocks.controlledInnerBlocks
2263
+ ).filter(
2264
+ ( clientId ) =>
2265
+ state.blocks.byClientId?.get( clientId )?.name === 'core/block'
2266
+ );
2267
+
2268
+ traverseBlockTree( state, treeClientId, ( block ) => {
2269
+ const { clientId, name: blockName } = block;
2270
+ if ( isZoomedOut || isNavMode ) {
2271
+ // If the root block is the section root set its editing mode to contentOnly.
2272
+ if ( clientId === sectionRootClientId ) {
2273
+ derivedBlockEditingModes.set( clientId, 'contentOnly' );
2274
+ return;
2275
+ }
2276
+
2277
+ // There are no sections, so everything else is disabled.
2278
+ if ( ! sectionClientIds?.length ) {
2279
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2280
+ return;
2281
+ }
2282
+
2283
+ if ( sectionClientIds.includes( clientId ) ) {
2284
+ derivedBlockEditingModes.set( clientId, 'contentOnly' );
2285
+ return;
2286
+ }
2287
+
2288
+ // If zoomed out, all blocks that aren't sections or the section root are
2289
+ // disabled.
2290
+ // If the tree root is not in a section, set its editing mode to disabled.
2291
+ if (
2292
+ isZoomedOut ||
2293
+ ! findParentInClientIdsList( state, clientId, sectionClientIds )
2294
+ ) {
2295
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2296
+ return;
2297
+ }
2298
+
2299
+ // Handle synced pattern content so the inner blocks of a synced pattern are
2300
+ // properly disabled.
2301
+ if ( syncedPatternClientIds.length ) {
2302
+ const parentPatternClientId = findParentInClientIdsList(
2303
+ state,
2304
+ clientId,
2305
+ syncedPatternClientIds
2306
+ );
2307
+
2308
+ if ( parentPatternClientId ) {
2309
+ // This is a pattern nested in another pattern, it should be disabled.
2310
+ if (
2311
+ findParentInClientIdsList(
2312
+ state,
2313
+ parentPatternClientId,
2314
+ syncedPatternClientIds
2315
+ )
2316
+ ) {
2317
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2318
+ return;
2319
+ }
2320
+
2321
+ if ( hasBindings( block ) ) {
2322
+ derivedBlockEditingModes.set( clientId, 'contentOnly' );
2323
+ return;
2324
+ }
2325
+
2326
+ // Synced pattern content without a binding isn't editable
2327
+ // from the instance, the user has to edit the pattern source,
2328
+ // so return 'disabled'.
2329
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2330
+ return;
2331
+ }
2332
+ }
2333
+
2334
+ if ( blockName && isContentBlock( blockName ) ) {
2335
+ derivedBlockEditingModes.set( clientId, 'contentOnly' );
2336
+ return;
2337
+ }
2338
+
2339
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2340
+ return;
2341
+ }
2342
+
2343
+ if ( syncedPatternClientIds.length ) {
2344
+ // Synced pattern blocks (core/block).
2345
+ if ( syncedPatternClientIds.includes( clientId ) ) {
2346
+ // This is a pattern nested in another pattern, it should be disabled.
2347
+ if (
2348
+ findParentInClientIdsList(
2349
+ state,
2350
+ clientId,
2351
+ syncedPatternClientIds
2352
+ )
2353
+ ) {
2354
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2355
+ return;
2356
+ }
2357
+
2358
+ // Else do nothing, use the default block editing mode.
2359
+ return;
2360
+ }
2361
+
2362
+ // Inner blocks of synced patterns.
2363
+ const parentPatternClientId = findParentInClientIdsList(
2364
+ state,
2365
+ clientId,
2366
+ syncedPatternClientIds
2367
+ );
2368
+ if ( parentPatternClientId ) {
2369
+ // This is a pattern nested in another pattern, it should be disabled.
2370
+ if (
2371
+ findParentInClientIdsList(
2372
+ state,
2373
+ parentPatternClientId,
2374
+ syncedPatternClientIds
2375
+ )
2376
+ ) {
2377
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2378
+ return;
2379
+ }
2380
+
2381
+ if ( hasBindings( block ) ) {
2382
+ derivedBlockEditingModes.set( clientId, 'contentOnly' );
2383
+ return;
2384
+ }
2385
+
2386
+ // Synced pattern content without a binding isn't editable
2387
+ // from the instance, the user has to edit the pattern source,
2388
+ // so return 'disabled'.
2389
+ derivedBlockEditingModes.set( clientId, 'disabled' );
2390
+ }
2391
+ }
2392
+ } );
2393
+
2394
+ return derivedBlockEditingModes;
2395
+ }
2396
+
2397
+ /**
2398
+ * Updates the derived block editing modes based on added and removed blocks.
2399
+ *
2400
+ * This function handles the updating of block editing modes when blocks are added,
2401
+ * removed, or moved within the editor.
2402
+ *
2403
+ * It only returns a value when modifications are made to the block editing modes.
2404
+ *
2405
+ * @param {Object} options The options for updating derived block editing modes.
2406
+ * @param {Object} options.prevState The previous state object.
2407
+ * @param {Object} options.nextState The next state object.
2408
+ * @param {Array} [options.addedBlocks] An array of blocks that were added.
2409
+ * @param {Array} [options.removedClientIds] An array of client IDs of blocks that were removed.
2410
+ * @param {boolean} [options.isNavMode] Whether the navigation mode is active.
2411
+ * @return {Map|undefined} The updated derived block editing modes, or undefined if no changes were made.
2412
+ */
2413
+ function getDerivedBlockEditingModesUpdates( {
2414
+ prevState,
2415
+ nextState,
2416
+ addedBlocks,
2417
+ removedClientIds,
2418
+ isNavMode = false,
2419
+ } ) {
2420
+ const prevDerivedBlockEditingModes = isNavMode
2421
+ ? prevState.derivedNavModeBlockEditingModes
2422
+ : prevState.derivedBlockEditingModes;
2423
+ let nextDerivedBlockEditingModes;
2424
+
2425
+ // Perform removals before additions to handle cases like the `MOVE_BLOCKS_TO_POSITION` action.
2426
+ // That action removes a set of clientIds, but adds the same blocks back in a different location.
2427
+ // If removals were performed after additions, those moved clientIds would be removed incorrectly.
2428
+ removedClientIds?.forEach( ( clientId ) => {
2429
+ // The actions only receive parent block IDs for removal.
2430
+ // Recurse through the block tree to ensure all blocks are removed.
2431
+ // Specifically use the previous state, before the blocks were removed.
2432
+ traverseBlockTree( prevState, clientId, ( block ) => {
2433
+ if ( prevDerivedBlockEditingModes.has( block.clientId ) ) {
2434
+ if ( ! nextDerivedBlockEditingModes ) {
2435
+ nextDerivedBlockEditingModes = new Map(
2436
+ prevDerivedBlockEditingModes
2437
+ );
2438
+ }
2439
+ nextDerivedBlockEditingModes.delete( block.clientId );
2440
+ }
2441
+ } );
2442
+ } );
2443
+
2444
+ addedBlocks?.forEach( ( addedBlock ) => {
2445
+ traverseBlockTree( nextState, addedBlock.clientId, ( block ) => {
2446
+ const updates = getDerivedBlockEditingModesForTree(
2447
+ nextState,
2448
+ isNavMode,
2449
+ block.clientId
2450
+ );
2451
+
2452
+ if ( updates.size ) {
2453
+ if ( ! nextDerivedBlockEditingModes ) {
2454
+ nextDerivedBlockEditingModes = new Map( [
2455
+ ...( prevDerivedBlockEditingModes?.size
2456
+ ? prevDerivedBlockEditingModes
2457
+ : [] ),
2458
+ ...updates,
2459
+ ] );
2460
+ } else {
2461
+ nextDerivedBlockEditingModes = new Map( [
2462
+ ...( nextDerivedBlockEditingModes?.size
2463
+ ? nextDerivedBlockEditingModes
2464
+ : [] ),
2465
+ ...updates,
2466
+ ] );
2467
+ }
2468
+ }
2469
+ } );
2470
+ } );
2471
+
2472
+ return nextDerivedBlockEditingModes;
2473
+ }
2474
+
2475
+ /**
2476
+ * Higher-order reducer that adds derived block editing modes to the state.
2477
+ *
2478
+ * This function wraps a reducer and enhances it to handle actions that affect
2479
+ * block editing modes. It updates the derivedBlockEditingModes in the state
2480
+ * based on various actions such as adding, removing, or moving blocks, or changing
2481
+ * the editor mode.
2482
+ *
2483
+ * @param {Function} reducer The original reducer function to be wrapped.
2484
+ * @return {Function} A new reducer function that includes derived block editing modes handling.
2485
+ */
2486
+ export function withDerivedBlockEditingModes( reducer ) {
2487
+ return ( state, action ) => {
2488
+ const nextState = reducer( state, action );
2489
+
2490
+ // An exception is needed here to still recompute the block editing modes when
2491
+ // the editor mode changes since the editor mode isn't stored within the
2492
+ // block editor state and changing it won't trigger an altered new state.
2493
+ if ( action.type !== 'SET_EDITOR_MODE' && nextState === state ) {
2494
+ return state;
2495
+ }
2496
+
2497
+ switch ( action.type ) {
2498
+ case 'REMOVE_BLOCKS': {
2499
+ const nextDerivedBlockEditingModes =
2500
+ getDerivedBlockEditingModesUpdates( {
2501
+ prevState: state,
2502
+ nextState,
2503
+ removedClientIds: action.clientIds,
2504
+ isNavMode: false,
2505
+ } );
2506
+ const nextDerivedNavModeBlockEditingModes =
2507
+ getDerivedBlockEditingModesUpdates( {
2508
+ prevState: state,
2509
+ nextState,
2510
+ removedClientIds: action.clientIds,
2511
+ isNavMode: true,
2512
+ } );
2513
+
2514
+ if (
2515
+ nextDerivedBlockEditingModes ||
2516
+ nextDerivedNavModeBlockEditingModes
2517
+ ) {
2518
+ return {
2519
+ ...nextState,
2520
+ derivedBlockEditingModes:
2521
+ nextDerivedBlockEditingModes ??
2522
+ state.derivedBlockEditingModes,
2523
+ derivedNavModeBlockEditingModes:
2524
+ nextDerivedNavModeBlockEditingModes ??
2525
+ state.derivedNavModeBlockEditingModes,
2526
+ };
2527
+ }
2528
+ break;
2529
+ }
2530
+ case 'RECEIVE_BLOCKS':
2531
+ case 'INSERT_BLOCKS': {
2532
+ const nextDerivedBlockEditingModes =
2533
+ getDerivedBlockEditingModesUpdates( {
2534
+ prevState: state,
2535
+ nextState,
2536
+ addedBlocks: action.blocks,
2537
+ isNavMode: false,
2538
+ } );
2539
+ const nextDerivedNavModeBlockEditingModes =
2540
+ getDerivedBlockEditingModesUpdates( {
2541
+ prevState: state,
2542
+ nextState,
2543
+ addedBlocks: action.blocks,
2544
+ isNavMode: true,
2545
+ } );
2546
+
2547
+ if (
2548
+ nextDerivedBlockEditingModes ||
2549
+ nextDerivedNavModeBlockEditingModes
2550
+ ) {
2551
+ return {
2552
+ ...nextState,
2553
+ derivedBlockEditingModes:
2554
+ nextDerivedBlockEditingModes ??
2555
+ state.derivedBlockEditingModes,
2556
+ derivedNavModeBlockEditingModes:
2557
+ nextDerivedNavModeBlockEditingModes ??
2558
+ state.derivedNavModeBlockEditingModes,
2559
+ };
2560
+ }
2561
+ break;
2562
+ }
2563
+ case 'SET_HAS_CONTROLLED_INNER_BLOCKS': {
2564
+ const updatedBlock = nextState.blocks.tree.get(
2565
+ action.clientId
2566
+ );
2567
+ // The block might have been removed.
2568
+ if ( ! updatedBlock ) {
2569
+ break;
2570
+ }
2571
+
2572
+ const nextDerivedBlockEditingModes =
2573
+ getDerivedBlockEditingModesUpdates( {
2574
+ prevState: state,
2575
+ nextState,
2576
+ addedBlocks: [ updatedBlock ],
2577
+ isNavMode: false,
2578
+ } );
2579
+ const nextDerivedNavModeBlockEditingModes =
2580
+ getDerivedBlockEditingModesUpdates( {
2581
+ prevState: state,
2582
+ nextState,
2583
+ addedBlocks: [ updatedBlock ],
2584
+ isNavMode: true,
2585
+ } );
2586
+
2587
+ if (
2588
+ nextDerivedBlockEditingModes ||
2589
+ nextDerivedNavModeBlockEditingModes
2590
+ ) {
2591
+ return {
2592
+ ...nextState,
2593
+ derivedBlockEditingModes:
2594
+ nextDerivedBlockEditingModes ??
2595
+ state.derivedBlockEditingModes,
2596
+ derivedNavModeBlockEditingModes:
2597
+ nextDerivedNavModeBlockEditingModes ??
2598
+ state.derivedNavModeBlockEditingModes,
2599
+ };
2600
+ }
2601
+ break;
2602
+ }
2603
+ case 'REPLACE_BLOCKS': {
2604
+ const nextDerivedBlockEditingModes =
2605
+ getDerivedBlockEditingModesUpdates( {
2606
+ prevState: state,
2607
+ nextState,
2608
+ addedBlocks: action.blocks,
2609
+ removedClientIds: action.clientIds,
2610
+ isNavMode: false,
2611
+ } );
2612
+ const nextDerivedNavModeBlockEditingModes =
2613
+ getDerivedBlockEditingModesUpdates( {
2614
+ prevState: state,
2615
+ nextState,
2616
+ addedBlocks: action.blocks,
2617
+ removedClientIds: action.clientIds,
2618
+ isNavMode: true,
2619
+ } );
2620
+
2621
+ if (
2622
+ nextDerivedBlockEditingModes ||
2623
+ nextDerivedNavModeBlockEditingModes
2624
+ ) {
2625
+ return {
2626
+ ...nextState,
2627
+ derivedBlockEditingModes:
2628
+ nextDerivedBlockEditingModes ??
2629
+ state.derivedBlockEditingModes,
2630
+ derivedNavModeBlockEditingModes:
2631
+ nextDerivedNavModeBlockEditingModes ??
2632
+ state.derivedNavModeBlockEditingModes,
2633
+ };
2634
+ }
2635
+ break;
2636
+ }
2637
+ case 'REPLACE_INNER_BLOCKS': {
2638
+ // Get the clientIds of the blocks that are being replaced
2639
+ // from the old state, before they were removed.
2640
+ const removedClientIds = state.blocks.order.get(
2641
+ action.rootClientId
2642
+ );
2643
+ const nextDerivedBlockEditingModes =
2644
+ getDerivedBlockEditingModesUpdates( {
2645
+ prevState: state,
2646
+ nextState,
2647
+ addedBlocks: action.blocks,
2648
+ removedClientIds,
2649
+ isNavMode: false,
2650
+ } );
2651
+ const nextDerivedNavModeBlockEditingModes =
2652
+ getDerivedBlockEditingModesUpdates( {
2653
+ prevState: state,
2654
+ nextState,
2655
+ addedBlocks: action.blocks,
2656
+ removedClientIds,
2657
+ isNavMode: true,
2658
+ } );
2659
+
2660
+ if (
2661
+ nextDerivedBlockEditingModes ||
2662
+ nextDerivedNavModeBlockEditingModes
2663
+ ) {
2664
+ return {
2665
+ ...nextState,
2666
+ derivedBlockEditingModes:
2667
+ nextDerivedBlockEditingModes ??
2668
+ state.derivedBlockEditingModes,
2669
+ derivedNavModeBlockEditingModes:
2670
+ nextDerivedNavModeBlockEditingModes ??
2671
+ state.derivedNavModeBlockEditingModes,
2672
+ };
2673
+ }
2674
+ break;
2675
+ }
2676
+ case 'MOVE_BLOCKS_TO_POSITION': {
2677
+ const addedBlocks = action.clientIds.map( ( clientId ) => {
2678
+ return nextState.blocks.byClientId.get( clientId );
2679
+ } );
2680
+ const nextDerivedBlockEditingModes =
2681
+ getDerivedBlockEditingModesUpdates( {
2682
+ prevState: state,
2683
+ nextState,
2684
+ addedBlocks,
2685
+ removedClientIds: action.clientIds,
2686
+ isNavMode: false,
2687
+ } );
2688
+ const nextDerivedNavModeBlockEditingModes =
2689
+ getDerivedBlockEditingModesUpdates( {
2690
+ prevState: state,
2691
+ nextState,
2692
+ addedBlocks,
2693
+ removedClientIds: action.clientIds,
2694
+ isNavMode: true,
2695
+ } );
2696
+
2697
+ if (
2698
+ nextDerivedBlockEditingModes ||
2699
+ nextDerivedNavModeBlockEditingModes
2700
+ ) {
2701
+ return {
2702
+ ...nextState,
2703
+ derivedBlockEditingModes:
2704
+ nextDerivedBlockEditingModes ??
2705
+ state.derivedBlockEditingModes,
2706
+ derivedNavModeBlockEditingModes:
2707
+ nextDerivedNavModeBlockEditingModes ??
2708
+ state.derivedNavModeBlockEditingModes,
2709
+ };
2710
+ }
2711
+ break;
2712
+ }
2713
+ case 'UPDATE_SETTINGS': {
2714
+ // Recompute the entire tree if the section root changes.
2715
+ if (
2716
+ state?.settings?.[ sectionRootClientIdKey ] !==
2717
+ nextState?.settings?.[ sectionRootClientIdKey ]
2718
+ ) {
2719
+ return {
2720
+ ...nextState,
2721
+ derivedBlockEditingModes:
2722
+ getDerivedBlockEditingModesForTree(
2723
+ nextState,
2724
+ false /* Nav mode off */
2725
+ ),
2726
+ derivedNavModeBlockEditingModes:
2727
+ getDerivedBlockEditingModesForTree(
2728
+ nextState,
2729
+ true /* Nav mode on */
2730
+ ),
2731
+ };
2732
+ }
2733
+ break;
2734
+ }
2735
+ case 'RESET_BLOCKS':
2736
+ case 'SET_EDITOR_MODE':
2737
+ case 'RESET_ZOOM_LEVEL':
2738
+ case 'SET_ZOOM_LEVEL': {
2739
+ // Recompute the entire tree if the editor mode or zoom level changes,
2740
+ // or if all the blocks are reset.
2741
+ return {
2742
+ ...nextState,
2743
+ derivedBlockEditingModes:
2744
+ getDerivedBlockEditingModesForTree(
2745
+ nextState,
2746
+ false /* Nav mode off */
2747
+ ),
2748
+ derivedNavModeBlockEditingModes:
2749
+ getDerivedBlockEditingModesForTree(
2750
+ nextState,
2751
+ true /* Nav mode on */
2752
+ ),
2753
+ };
2754
+ }
2755
+ }
2756
+
2757
+ // If there's no change, the derivedBlockEditingModes from the previous
2758
+ // state need to be preserved.
2759
+ nextState.derivedBlockEditingModes =
2760
+ state?.derivedBlockEditingModes ?? new Map();
2761
+ nextState.derivedNavModeBlockEditingModes =
2762
+ state?.derivedNavModeBlockEditingModes ?? new Map();
2763
+
2764
+ return nextState;
2765
+ };
2766
+ }
2767
+
2134
2768
  function withAutomaticChangeReset( reducer ) {
2135
2769
  return ( state, action ) => {
2136
2770
  const nextState = reducer( state, action );
@@ -2184,4 +2818,7 @@ function withAutomaticChangeReset( reducer ) {
2184
2818
  };
2185
2819
  }
2186
2820
 
2187
- export default withAutomaticChangeReset( combinedReducers );
2821
+ export default pipe(
2822
+ withDerivedBlockEditingModes,
2823
+ withAutomaticChangeReset
2824
+ )( combinedReducers );