@wordpress/block-editor 16.0.0 → 16.1.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 (368) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +8 -0
  3. package/build/components/alignment-control/ui.cjs +2 -4
  4. package/build/components/alignment-control/ui.cjs.map +2 -2
  5. package/build/components/background-image-control/index.cjs +40 -10
  6. package/build/components/background-image-control/index.cjs.map +2 -2
  7. package/build/components/block-alignment-control/ui.cjs +5 -3
  8. package/build/components/block-alignment-control/ui.cjs.map +2 -2
  9. package/build/components/block-inspector/index.cjs +73 -46
  10. package/build/components/block-inspector/index.cjs.map +2 -2
  11. package/build/components/block-list/block-html.cjs +4 -1
  12. package/build/components/block-list/block-html.cjs.map +2 -2
  13. package/build/components/block-list/use-block-props/index.cjs +5 -2
  14. package/build/components/block-list/use-block-props/index.cjs.map +2 -2
  15. package/build/components/block-list/use-block-props/use-focus-handler.cjs +2 -3
  16. package/build/components/block-list/use-block-props/use-focus-handler.cjs.map +2 -2
  17. package/build/components/block-list/use-block-props/use-register-block-event-handlers.cjs +48 -0
  18. package/build/components/block-list/use-block-props/use-register-block-event-handlers.cjs.map +7 -0
  19. package/build/components/block-parent-selector/index.cjs +2 -2
  20. package/build/components/block-parent-selector/index.cjs.map +2 -2
  21. package/build/components/block-toolbar/switch-section-style.cjs +4 -2
  22. package/build/components/block-toolbar/switch-section-style.cjs.map +3 -3
  23. package/build/components/block-tools/empty-block-inserter.cjs +2 -7
  24. package/build/components/block-tools/empty-block-inserter.cjs.map +2 -2
  25. package/build/components/block-vertical-alignment-control/ui.cjs +3 -5
  26. package/build/components/block-vertical-alignment-control/ui.cjs.map +2 -2
  27. package/build/components/border-radius-control/utils.cjs +8 -58
  28. package/build/components/border-radius-control/utils.cjs.map +2 -2
  29. package/build/components/colors-gradients/control.cjs +5 -3
  30. package/build/components/colors-gradients/control.cjs.map +2 -2
  31. package/build/components/dimension-control/index.cjs +30 -20
  32. package/build/components/dimension-control/index.cjs.map +3 -3
  33. package/build/components/dimensions-tool/aspect-ratio-tool.cjs +9 -2
  34. package/build/components/dimensions-tool/aspect-ratio-tool.cjs.map +3 -3
  35. package/build/components/editor-styles/index.cjs +9 -1
  36. package/build/components/editor-styles/index.cjs.map +2 -2
  37. package/build/components/global-styles/background-panel.cjs +66 -25
  38. package/build/components/global-styles/background-panel.cjs.map +3 -3
  39. package/build/components/global-styles/border-panel.cjs +153 -55
  40. package/build/components/global-styles/border-panel.cjs.map +3 -3
  41. package/build/components/global-styles/color-gradient-dropdown-item.cjs +46 -14
  42. package/build/components/global-styles/color-gradient-dropdown-item.cjs.map +3 -3
  43. package/build/components/global-styles/color-panel.cjs +63 -17
  44. package/build/components/global-styles/color-panel.cjs.map +2 -2
  45. package/build/components/global-styles/dimensions-panel.cjs +242 -64
  46. package/build/components/global-styles/dimensions-panel.cjs.map +3 -3
  47. package/build/components/global-styles/filters-panel.cjs +59 -20
  48. package/build/components/global-styles/filters-panel.cjs.map +3 -3
  49. package/build/components/global-styles/hooks.cjs +4 -1
  50. package/build/components/global-styles/hooks.cjs.map +2 -2
  51. package/build/components/global-styles/inheritance/index.cjs +142 -0
  52. package/build/components/global-styles/inheritance/index.cjs.map +7 -0
  53. package/build/components/global-styles/inherited-value-context.cjs +173 -0
  54. package/build/components/global-styles/inherited-value-context.cjs.map +7 -0
  55. package/build/components/global-styles/shadow-panel-components.cjs +38 -20
  56. package/build/components/global-styles/shadow-panel-components.cjs.map +2 -2
  57. package/build/components/global-styles/state-control.cjs +1 -1
  58. package/build/components/global-styles/state-control.cjs.map +2 -2
  59. package/build/components/global-styles/typography-panel.cjs +271 -78
  60. package/build/components/global-styles/typography-panel.cjs.map +3 -3
  61. package/build/components/inspector-controls-tabs/styles-tab.cjs +10 -1
  62. package/build/components/inspector-controls-tabs/styles-tab.cjs.map +2 -2
  63. package/build/components/line-height-control/index.cjs +1 -1
  64. package/build/components/line-height-control/index.cjs.map +2 -2
  65. package/build/components/link-control/index.cjs +3 -1
  66. package/build/components/link-control/index.cjs.map +2 -2
  67. package/build/components/preset-input-control/index.cjs +2 -1
  68. package/build/components/preset-input-control/index.cjs.map +2 -2
  69. package/build/components/provider/block-refs-provider.cjs +8 -2
  70. package/build/components/provider/block-refs-provider.cjs.map +2 -2
  71. package/build/components/provider/index.cjs +1 -1
  72. package/build/components/provider/index.cjs.map +2 -2
  73. package/build/components/provider/use-block-sync.cjs +18 -6
  74. package/build/components/provider/use-block-sync.cjs.map +2 -2
  75. package/build/components/provider/use-media-upload-settings.cjs +3 -1
  76. package/build/components/provider/use-media-upload-settings.cjs.map +2 -2
  77. package/build/components/rich-text/index.cjs +23 -13
  78. package/build/components/rich-text/index.cjs.map +2 -2
  79. package/build/components/spacing-sizes-control/utils.cjs +6 -19
  80. package/build/components/spacing-sizes-control/utils.cjs.map +2 -2
  81. package/build/components/text-indent-control/index.cjs +8 -2
  82. package/build/components/text-indent-control/index.cjs.map +2 -2
  83. package/build/components/url-input/index.cjs +303 -344
  84. package/build/components/url-input/index.cjs.map +3 -3
  85. package/build/components/writing-flow/index.cjs +2 -0
  86. package/build/components/writing-flow/index.cjs.map +3 -3
  87. package/build/components/writing-flow/use-arrow-nav.cjs +24 -1
  88. package/build/components/writing-flow/use-arrow-nav.cjs.map +2 -2
  89. package/build/components/writing-flow/use-click-selection.cjs +28 -2
  90. package/build/components/writing-flow/use-click-selection.cjs.map +2 -2
  91. package/build/components/writing-flow/use-editable-root-event-handlers.cjs +179 -0
  92. package/build/components/writing-flow/use-editable-root-event-handlers.cjs.map +7 -0
  93. package/build/components/writing-flow/use-editable-root.cjs +5 -42
  94. package/build/components/writing-flow/use-editable-root.cjs.map +2 -2
  95. package/build/components/writing-flow/use-home-end.cjs +1 -1
  96. package/build/components/writing-flow/use-home-end.cjs.map +2 -2
  97. package/build/components/writing-flow/use-selection-observer.cjs +17 -13
  98. package/build/components/writing-flow/use-selection-observer.cjs.map +2 -2
  99. package/build/components/writing-flow/utils.cjs +3 -14
  100. package/build/components/writing-flow/utils.cjs.map +2 -2
  101. package/build/hooks/background.cjs +13 -10
  102. package/build/hooks/background.cjs.map +2 -2
  103. package/build/hooks/block-style-variation.cjs +4 -45
  104. package/build/hooks/block-style-variation.cjs.map +3 -3
  105. package/build/hooks/border.cjs +19 -4
  106. package/build/hooks/border.cjs.map +2 -2
  107. package/build/hooks/custom-css.cjs +6 -2
  108. package/build/hooks/custom-css.cjs.map +2 -2
  109. package/build/hooks/dimensions.cjs +15 -4
  110. package/build/hooks/dimensions.cjs.map +2 -2
  111. package/build/hooks/duotone.cjs +26 -14
  112. package/build/hooks/duotone.cjs.map +3 -3
  113. package/build/hooks/elements.cjs +14 -4
  114. package/build/hooks/elements.cjs.map +2 -2
  115. package/build/hooks/line-height.cjs +1 -2
  116. package/build/hooks/line-height.cjs.map +2 -2
  117. package/build/hooks/typography.cjs +13 -4
  118. package/build/hooks/typography.cjs.map +2 -2
  119. package/build/private-apis.cjs +9 -5
  120. package/build/private-apis.cjs.map +3 -3
  121. package/build/store/actions.cjs +9 -4
  122. package/build/store/actions.cjs.map +2 -2
  123. package/build/store/private-selectors.cjs +28 -1
  124. package/build/store/private-selectors.cjs.map +2 -2
  125. package/build/store/reducer.cjs +6 -6
  126. package/build/store/reducer.cjs.map +2 -2
  127. package/build/store/selectors.cjs +23 -0
  128. package/build/store/selectors.cjs.map +2 -2
  129. package/build/utils/native-undo.cjs +55 -0
  130. package/build/utils/native-undo.cjs.map +7 -0
  131. package/build-module/components/alignment-control/ui.mjs +2 -4
  132. package/build-module/components/alignment-control/ui.mjs.map +2 -2
  133. package/build-module/components/background-image-control/index.mjs +43 -10
  134. package/build-module/components/background-image-control/index.mjs.map +2 -2
  135. package/build-module/components/block-alignment-control/ui.mjs +5 -3
  136. package/build-module/components/block-alignment-control/ui.mjs.map +2 -2
  137. package/build-module/components/block-inspector/index.mjs +74 -46
  138. package/build-module/components/block-inspector/index.mjs.map +2 -2
  139. package/build-module/components/block-list/block-html.mjs +4 -1
  140. package/build-module/components/block-list/block-html.mjs.map +2 -2
  141. package/build-module/components/block-list/use-block-props/index.mjs +5 -2
  142. package/build-module/components/block-list/use-block-props/index.mjs.map +2 -2
  143. package/build-module/components/block-list/use-block-props/use-focus-handler.mjs +2 -3
  144. package/build-module/components/block-list/use-block-props/use-focus-handler.mjs.map +2 -2
  145. package/build-module/components/block-list/use-block-props/use-register-block-event-handlers.mjs +28 -0
  146. package/build-module/components/block-list/use-block-props/use-register-block-event-handlers.mjs.map +7 -0
  147. package/build-module/components/block-parent-selector/index.mjs +2 -2
  148. package/build-module/components/block-parent-selector/index.mjs.map +2 -2
  149. package/build-module/components/block-toolbar/switch-section-style.mjs +4 -2
  150. package/build-module/components/block-toolbar/switch-section-style.mjs.map +2 -2
  151. package/build-module/components/block-tools/empty-block-inserter.mjs +2 -7
  152. package/build-module/components/block-tools/empty-block-inserter.mjs.map +2 -2
  153. package/build-module/components/block-vertical-alignment-control/ui.mjs +4 -6
  154. package/build-module/components/block-vertical-alignment-control/ui.mjs.map +2 -2
  155. package/build-module/components/border-radius-control/utils.mjs +11 -53
  156. package/build-module/components/border-radius-control/utils.mjs.map +2 -2
  157. package/build-module/components/colors-gradients/control.mjs +5 -3
  158. package/build-module/components/colors-gradients/control.mjs.map +2 -2
  159. package/build-module/components/dimension-control/index.mjs +30 -20
  160. package/build-module/components/dimension-control/index.mjs.map +2 -2
  161. package/build-module/components/dimensions-tool/aspect-ratio-tool.mjs +10 -6
  162. package/build-module/components/dimensions-tool/aspect-ratio-tool.mjs.map +2 -2
  163. package/build-module/components/editor-styles/index.mjs +9 -1
  164. package/build-module/components/editor-styles/index.mjs.map +2 -2
  165. package/build-module/components/global-styles/background-panel.mjs +71 -29
  166. package/build-module/components/global-styles/background-panel.mjs.map +2 -2
  167. package/build-module/components/global-styles/border-panel.mjs +157 -56
  168. package/build-module/components/global-styles/border-panel.mjs.map +2 -2
  169. package/build-module/components/global-styles/color-gradient-dropdown-item.mjs +51 -15
  170. package/build-module/components/global-styles/color-gradient-dropdown-item.mjs.map +2 -2
  171. package/build-module/components/global-styles/color-panel.mjs +63 -17
  172. package/build-module/components/global-styles/color-panel.mjs.map +2 -2
  173. package/build-module/components/global-styles/dimensions-panel.mjs +248 -66
  174. package/build-module/components/global-styles/dimensions-panel.mjs.map +2 -2
  175. package/build-module/components/global-styles/filters-panel.mjs +64 -21
  176. package/build-module/components/global-styles/filters-panel.mjs.map +2 -2
  177. package/build-module/components/global-styles/hooks.mjs +4 -1
  178. package/build-module/components/global-styles/hooks.mjs.map +2 -2
  179. package/build-module/components/global-styles/inheritance/index.mjs +108 -0
  180. package/build-module/components/global-styles/inheritance/index.mjs.map +7 -0
  181. package/build-module/components/global-styles/inherited-value-context.mjs +141 -0
  182. package/build-module/components/global-styles/inherited-value-context.mjs.map +7 -0
  183. package/build-module/components/global-styles/shadow-panel-components.mjs +38 -20
  184. package/build-module/components/global-styles/shadow-panel-components.mjs.map +2 -2
  185. package/build-module/components/global-styles/state-control.mjs +1 -1
  186. package/build-module/components/global-styles/state-control.mjs.map +2 -2
  187. package/build-module/components/global-styles/typography-panel.mjs +276 -79
  188. package/build-module/components/global-styles/typography-panel.mjs.map +2 -2
  189. package/build-module/components/inspector-controls-tabs/styles-tab.mjs +6 -1
  190. package/build-module/components/inspector-controls-tabs/styles-tab.mjs.map +2 -2
  191. package/build-module/components/line-height-control/index.mjs +1 -1
  192. package/build-module/components/line-height-control/index.mjs.map +2 -2
  193. package/build-module/components/link-control/index.mjs +4 -2
  194. package/build-module/components/link-control/index.mjs.map +2 -2
  195. package/build-module/components/preset-input-control/index.mjs +2 -1
  196. package/build-module/components/preset-input-control/index.mjs.map +2 -2
  197. package/build-module/components/provider/block-refs-provider.mjs +8 -2
  198. package/build-module/components/provider/block-refs-provider.mjs.map +2 -2
  199. package/build-module/components/provider/index.mjs +1 -1
  200. package/build-module/components/provider/index.mjs.map +2 -2
  201. package/build-module/components/provider/use-block-sync.mjs +18 -6
  202. package/build-module/components/provider/use-block-sync.mjs.map +2 -2
  203. package/build-module/components/provider/use-media-upload-settings.mjs +3 -1
  204. package/build-module/components/provider/use-media-upload-settings.mjs.map +2 -2
  205. package/build-module/components/rich-text/index.mjs +28 -14
  206. package/build-module/components/rich-text/index.mjs.map +2 -2
  207. package/build-module/components/spacing-sizes-control/utils.mjs +6 -18
  208. package/build-module/components/spacing-sizes-control/utils.mjs.map +2 -2
  209. package/build-module/components/text-indent-control/index.mjs +8 -2
  210. package/build-module/components/text-indent-control/index.mjs.map +2 -2
  211. package/build-module/components/url-input/index.mjs +306 -353
  212. package/build-module/components/url-input/index.mjs.map +2 -2
  213. package/build-module/components/writing-flow/index.mjs +2 -0
  214. package/build-module/components/writing-flow/index.mjs.map +2 -2
  215. package/build-module/components/writing-flow/use-arrow-nav.mjs +24 -1
  216. package/build-module/components/writing-flow/use-arrow-nav.mjs.map +2 -2
  217. package/build-module/components/writing-flow/use-click-selection.mjs +28 -2
  218. package/build-module/components/writing-flow/use-click-selection.mjs.map +2 -2
  219. package/build-module/components/writing-flow/use-editable-root-event-handlers.mjs +154 -0
  220. package/build-module/components/writing-flow/use-editable-root-event-handlers.mjs.map +7 -0
  221. package/build-module/components/writing-flow/use-editable-root.mjs +5 -37
  222. package/build-module/components/writing-flow/use-editable-root.mjs.map +2 -2
  223. package/build-module/components/writing-flow/use-home-end.mjs +1 -1
  224. package/build-module/components/writing-flow/use-home-end.mjs.map +2 -2
  225. package/build-module/components/writing-flow/use-selection-observer.mjs +18 -14
  226. package/build-module/components/writing-flow/use-selection-observer.mjs.map +2 -2
  227. package/build-module/components/writing-flow/utils.mjs +2 -11
  228. package/build-module/components/writing-flow/utils.mjs.map +2 -2
  229. package/build-module/hooks/background.mjs +13 -10
  230. package/build-module/hooks/background.mjs.map +2 -2
  231. package/build-module/hooks/block-style-variation.mjs +8 -44
  232. package/build-module/hooks/block-style-variation.mjs.map +2 -2
  233. package/build-module/hooks/border.mjs +19 -4
  234. package/build-module/hooks/border.mjs.map +2 -2
  235. package/build-module/hooks/custom-css.mjs +7 -3
  236. package/build-module/hooks/custom-css.mjs.map +2 -2
  237. package/build-module/hooks/dimensions.mjs +15 -4
  238. package/build-module/hooks/dimensions.mjs.map +2 -2
  239. package/build-module/hooks/duotone.mjs +20 -9
  240. package/build-module/hooks/duotone.mjs.map +2 -2
  241. package/build-module/hooks/elements.mjs +14 -4
  242. package/build-module/hooks/elements.mjs.map +2 -2
  243. package/build-module/hooks/line-height.mjs +1 -2
  244. package/build-module/hooks/line-height.mjs.map +2 -2
  245. package/build-module/hooks/typography.mjs +13 -4
  246. package/build-module/hooks/typography.mjs.map +2 -2
  247. package/build-module/private-apis.mjs +7 -3
  248. package/build-module/private-apis.mjs.map +2 -2
  249. package/build-module/store/actions.mjs +9 -4
  250. package/build-module/store/actions.mjs.map +2 -2
  251. package/build-module/store/private-selectors.mjs +29 -1
  252. package/build-module/store/private-selectors.mjs.map +2 -2
  253. package/build-module/store/reducer.mjs +6 -6
  254. package/build-module/store/reducer.mjs.map +2 -2
  255. package/build-module/store/selectors.mjs +23 -0
  256. package/build-module/store/selectors.mjs.map +2 -2
  257. package/build-module/utils/native-undo.mjs +29 -0
  258. package/build-module/utils/native-undo.mjs.map +7 -0
  259. package/build-style/content-rtl.css +10 -18
  260. package/build-style/content.css +10 -18
  261. package/build-style/style-rtl.css +150 -7
  262. package/build-style/style.css +150 -7
  263. package/package.json +40 -41
  264. package/src/components/alignment-control/test/__snapshots__/index.js.snap +1 -1
  265. package/src/components/alignment-control/ui.js +2 -4
  266. package/src/components/background-image-control/index.js +74 -37
  267. package/src/components/background-image-control/style.scss +13 -4
  268. package/src/components/block-alignment-control/test/__snapshots__/index.js.snap +3 -3
  269. package/src/components/block-alignment-control/test/index.js +1 -1
  270. package/src/components/block-alignment-control/ui.js +4 -2
  271. package/src/components/block-breadcrumb/test/__snapshots__/index.js.snap +1 -1
  272. package/src/components/block-compare/test/__snapshots__/block-view.js.snap +1 -1
  273. package/src/components/block-icon/test/__snapshots__/index.js.snap +1 -1
  274. package/src/components/block-inspector/index.js +60 -31
  275. package/src/components/block-list/block-html.js +5 -0
  276. package/src/components/block-list/content.scss +1 -11
  277. package/src/components/block-list/use-block-props/index.js +5 -1
  278. package/src/components/block-list/use-block-props/use-focus-handler.js +9 -8
  279. package/src/components/block-list/use-block-props/use-register-block-event-handlers.js +45 -0
  280. package/src/components/block-parent-selector/index.js +5 -2
  281. package/src/components/block-toolbar/switch-section-style.js +5 -2
  282. package/src/components/block-tools/empty-block-inserter.js +3 -7
  283. package/src/components/block-vertical-alignment-control/test/__snapshots__/index.js.snap +3 -3
  284. package/src/components/block-vertical-alignment-control/test/index.js +18 -2
  285. package/src/components/block-vertical-alignment-control/ui.js +3 -5
  286. package/src/components/border-radius-control/test/utils.js +0 -41
  287. package/src/components/border-radius-control/utils.js +16 -107
  288. package/src/components/button-block-appender/content.scss +6 -2
  289. package/src/components/color-palette/test/__snapshots__/control.js.snap +1 -1
  290. package/src/components/colors-gradients/control.js +6 -3
  291. package/src/components/default-block-appender/test/__snapshots__/index.js.snap +1 -1
  292. package/src/components/dimension-control/index.js +13 -1
  293. package/src/components/dimensions-tool/aspect-ratio-tool.js +13 -6
  294. package/src/components/editor-styles/index.js +16 -1
  295. package/src/components/global-styles/background-panel.js +107 -34
  296. package/src/components/global-styles/border-panel.js +219 -48
  297. package/src/components/global-styles/color-gradient-dropdown-item.js +93 -28
  298. package/src/components/global-styles/color-panel.js +92 -11
  299. package/src/components/global-styles/dimensions-panel.js +422 -71
  300. package/src/components/global-styles/filters-panel.js +88 -28
  301. package/src/components/global-styles/hooks.js +8 -1
  302. package/src/components/global-styles/inheritance/index.js +204 -0
  303. package/src/components/global-styles/inheritance/style.scss +184 -0
  304. package/src/components/global-styles/inheritance/test/index.js +281 -0
  305. package/src/components/global-styles/inherited-value-context.js +271 -0
  306. package/src/components/global-styles/shadow-panel-components.js +48 -26
  307. package/src/components/global-styles/state-control.js +2 -2
  308. package/src/components/global-styles/test/background-panel.js +338 -1
  309. package/src/components/global-styles/test/border-panel.js +441 -0
  310. package/src/components/global-styles/test/color-panel.js +182 -2
  311. package/src/components/global-styles/test/dimensions-panel.js +753 -0
  312. package/src/components/global-styles/test/filters-panel.js +194 -0
  313. package/src/components/global-styles/test/inherited-value-context-core.js +98 -0
  314. package/src/components/global-styles/test/inherited-value-context.js +454 -0
  315. package/src/components/global-styles/test/typography-panel-core.js +185 -0
  316. package/src/components/global-styles/test/typography-panel.js +849 -12
  317. package/src/components/global-styles/typography-panel.js +449 -100
  318. package/src/components/image-editor/style.scss +33 -0
  319. package/src/components/inner-blocks/test/__snapshots__/index.js.snap +1 -1
  320. package/src/components/inspector-controls-tabs/styles-tab.js +5 -1
  321. package/src/components/line-height-control/index.js +1 -1
  322. package/src/components/link-control/index.js +7 -2
  323. package/src/components/preset-input-control/index.js +4 -1
  324. package/src/components/provider/block-refs-provider.js +12 -2
  325. package/src/components/provider/index.js +2 -2
  326. package/src/components/provider/use-block-sync.js +18 -6
  327. package/src/components/provider/use-media-upload-settings.js +2 -0
  328. package/src/components/rich-text/index.js +37 -16
  329. package/src/components/spacing-sizes-control/test/utils.js +16 -5
  330. package/src/components/spacing-sizes-control/utils.js +11 -28
  331. package/src/components/text-indent-control/index.js +8 -0
  332. package/src/components/url-input/index.js +363 -431
  333. package/src/components/url-input/test/index.js +592 -0
  334. package/src/components/warning/test/__snapshots__/index.js.snap +1 -1
  335. package/src/components/writing-flow/index.js +2 -0
  336. package/src/components/writing-flow/use-arrow-nav.js +51 -1
  337. package/src/components/writing-flow/use-click-selection.js +54 -3
  338. package/src/components/writing-flow/use-editable-root-event-handlers.js +266 -0
  339. package/src/components/writing-flow/use-editable-root.js +7 -77
  340. package/src/components/writing-flow/use-home-end.js +17 -9
  341. package/src/components/writing-flow/use-selection-observer.js +32 -15
  342. package/src/components/writing-flow/utils.js +3 -24
  343. package/src/hooks/background.js +26 -21
  344. package/src/hooks/block-fields/rich-text/styles.scss +1 -1
  345. package/src/hooks/block-style-variation.js +8 -74
  346. package/src/hooks/border.js +19 -4
  347. package/src/hooks/custom-css.js +15 -6
  348. package/src/hooks/dimensions.js +17 -4
  349. package/src/hooks/duotone.js +26 -8
  350. package/src/hooks/elements.js +14 -3
  351. package/src/hooks/line-height.js +0 -1
  352. package/src/hooks/test/inherited-value-wiring.js +411 -0
  353. package/src/hooks/test/preset-round-trip.js +456 -0
  354. package/src/hooks/typography.js +35 -23
  355. package/src/private-apis.js +11 -2
  356. package/src/store/actions.js +10 -4
  357. package/src/store/private-selectors.js +57 -1
  358. package/src/store/reducer.js +9 -9
  359. package/src/store/selectors.js +56 -8
  360. package/src/store/test/private-selectors.js +160 -1
  361. package/src/style.scss +2 -0
  362. package/src/utils/native-undo.js +56 -0
  363. package/build/components/duotone/utils.cjs +0 -87
  364. package/build/components/duotone/utils.cjs.map +0 -7
  365. package/build-module/components/duotone/utils.mjs +0 -59
  366. package/build-module/components/duotone/utils.mjs.map +0 -7
  367. package/src/components/duotone/utils.js +0 -90
  368. package/src/hooks/test/get-variation-styles-with-ref-values.js +0 -91
@@ -13,8 +13,12 @@ import { getBlockClientId } from '../../utils/dom';
13
13
 
14
14
  export default function useClickSelection() {
15
15
  const { selectBlock } = useDispatch( blockEditorStore );
16
- const { isSelectionEnabled, getBlockSelectionStart, hasMultiSelection } =
17
- useSelect( blockEditorStore );
16
+ const {
17
+ isSelectionEnabled,
18
+ getBlockSelectionStart,
19
+ getSelectionStart,
20
+ hasMultiSelection,
21
+ } = useSelect( blockEditorStore );
18
22
  return useRefEffect(
19
23
  ( node ) => {
20
24
  function onMouseDown( event ) {
@@ -31,7 +35,53 @@ export default function useClickSelection() {
31
35
  // When selecting a single block in a document by holding the shift key,
32
36
  // don't mark this action as multiselection.
33
37
  if ( startClientId && startClientId !== clickedClientId ) {
34
- setContentEditableWrapper( node, true );
38
+ // When the selected block has no text selection
39
+ // within it (e.g. an image or spacer), there is no
40
+ // native selection for the wrapper to adopt when it
41
+ // is focused, so Safari inserts a caret at the start
42
+ // of the wrapper and asynchronously reveals it,
43
+ // scrolling a scrolled-down viewport back up, which
44
+ // `preventScroll` does not cover. Leave focus alone
45
+ // in that case: the click moves it.
46
+ const { clientId, attributeKey } = getSelectionStart();
47
+ setContentEditableWrapper( node, true, {
48
+ focus: !! attributeKey,
49
+ } );
50
+
51
+ // The browser extends the selection from the native
52
+ // anchor. When a block is selected without a text
53
+ // selection within it, there is no native anchor,
54
+ // and browsers synthesize one at the nearest text
55
+ // instead, excluding the block itself. Give the
56
+ // browser the right anchor before it acts on the
57
+ // click: the near edge of the selected block, so the
58
+ // whole block ends up within the extended selection.
59
+ const { ownerDocument } = node;
60
+ const selection =
61
+ ownerDocument.defaultView.getSelection();
62
+ const blockElement =
63
+ ! attributeKey &&
64
+ ownerDocument.getElementById(
65
+ `block-${ clientId }`
66
+ );
67
+
68
+ if (
69
+ blockElement &&
70
+ ! (
71
+ selection.anchorNode &&
72
+ blockElement.contains( selection.anchorNode )
73
+ )
74
+ ) {
75
+ const isForward =
76
+ // eslint-disable-next-line no-bitwise
77
+ blockElement.compareDocumentPosition(
78
+ event.target
79
+ ) & node.DOCUMENT_POSITION_FOLLOWING;
80
+ selection.setPosition(
81
+ blockElement,
82
+ isForward ? 0 : blockElement.childNodes.length
83
+ );
84
+ }
35
85
  }
36
86
  } else if ( hasMultiSelection() ) {
37
87
  // Allow user to escape out of a multi-selection to a
@@ -54,6 +104,7 @@ export default function useClickSelection() {
54
104
  selectBlock,
55
105
  isSelectionEnabled,
56
106
  getBlockSelectionStart,
107
+ getSelectionStart,
57
108
  hasMultiSelection,
58
109
  ]
59
110
  );
@@ -0,0 +1,266 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+ import { useRefEffect } from '@wordpress/compose';
6
+ import { useContext } from '@wordpress/element';
7
+
8
+ /**
9
+ * Internal dependencies
10
+ */
11
+ import { store as blockEditorStore } from '../../store';
12
+ import { getBlockClientId, getSelectionEditableElement } from '../../utils/dom';
13
+ import { BlockRefs } from '../provider/block-refs-provider';
14
+
15
+ // The React `on*` props the host bridges, mapped to their DOM event type. Only
16
+ // editing events are redirected under `editableRoot` (the wrapper becomes the
17
+ // editing host, so keyboard, input and composition events target it instead of
18
+ // the block); pointer and other events still reach the block and need no
19
+ // bridging. React prop names don't map to DOM types by lowercasing in general
20
+ // (onChange is `input`, onDoubleClick is `dblclick`), so the mapping is
21
+ // explicit, which also locks the bridged surface to events React actually fires.
22
+ const SUPPORTED_EVENTS = {
23
+ onKeyDown: 'keydown',
24
+ onKeyUp: 'keyup',
25
+ onBeforeInput: 'beforeinput',
26
+ onInput: 'input',
27
+ onCompositionStart: 'compositionstart',
28
+ onCompositionUpdate: 'compositionupdate',
29
+ onCompositionEnd: 'compositionend',
30
+ };
31
+
32
+ // The DOM event types the host listens for. Fixed, so the host attaches these
33
+ // listeners once rather than tracking which types are in use.
34
+ const EVENT_TYPES = Object.values( SUPPORTED_EVENTS );
35
+
36
+ /**
37
+ * Collects the supported `on*` event handlers from a set of props, e.g. a
38
+ * block's merged `wrapperProps`, keyed by DOM event type. Used by the block to
39
+ * register them (see `useRegisterBlockEventHandlers`).
40
+ *
41
+ * @param {Object} props Props to read handlers from.
42
+ *
43
+ * @return {Object|undefined} The handlers by event type, or undefined when
44
+ * there are none.
45
+ */
46
+ export function getEventHandlers( props ) {
47
+ let handlers;
48
+
49
+ for ( const name in SUPPORTED_EVENTS ) {
50
+ if ( typeof props[ name ] === 'function' ) {
51
+ handlers = handlers || {};
52
+ handlers[ SUPPORTED_EVENTS[ name ] ] = props[ name ];
53
+ }
54
+ }
55
+
56
+ return handlers;
57
+ }
58
+
59
+ // The native properties React copies onto its SyntheticEvent for each event
60
+ // type (the *EventInterface tables in react-dom), so the wrapper exposes exactly
61
+ // what a React handler would see and nothing more. Values are copied straight
62
+ // from the native event; React's normalizers only paper over browsers we don't
63
+ // support, and anything omitted stays reachable through `nativeEvent`, as in
64
+ // React (e.g. `getTargetRanges` on a `beforeinput`).
65
+ const EVENT_INTERFACE = [
66
+ 'eventPhase',
67
+ 'bubbles',
68
+ 'cancelable',
69
+ 'timeStamp',
70
+ 'defaultPrevented',
71
+ 'isTrusted',
72
+ ];
73
+ const KEYBOARD_EVENT_INTERFACE = [
74
+ ...EVENT_INTERFACE,
75
+ 'view',
76
+ 'detail',
77
+ 'key',
78
+ 'code',
79
+ 'location',
80
+ 'ctrlKey',
81
+ 'shiftKey',
82
+ 'altKey',
83
+ 'metaKey',
84
+ 'repeat',
85
+ 'locale',
86
+ 'getModifierState',
87
+ 'charCode',
88
+ 'keyCode',
89
+ 'which',
90
+ ];
91
+ const INPUT_EVENT_INTERFACE = [ ...EVENT_INTERFACE, 'data' ];
92
+ const EVENT_INTERFACES = {
93
+ keydown: KEYBOARD_EVENT_INTERFACE,
94
+ keyup: KEYBOARD_EVENT_INTERFACE,
95
+ beforeinput: INPUT_EVENT_INTERFACE,
96
+ input: INPUT_EVENT_INTERFACE,
97
+ compositionstart: INPUT_EVENT_INTERFACE,
98
+ compositionupdate: INPUT_EVENT_INTERFACE,
99
+ compositionend: INPUT_EVENT_INTERFACE,
100
+ };
101
+
102
+ /**
103
+ * Builds a React `SyntheticEvent`-like object for an extension handler, which
104
+ * expects one. It mirrors what react-dom does: a plain object wrapping the real
105
+ * native event, eagerly copying the same interface properties React exposes for
106
+ * the event type, so a handler sees exactly React's surface and nothing more.
107
+ *
108
+ * `preventDefault` and `stopPropagation` forward to the native event, so they
109
+ * behave as through React; `stopPropagation` also flags the walk through block
110
+ * ancestors to stop. `target` is the editable inside the block rather than the
111
+ * real target (the editing host above it), and `currentTarget` is reassigned as
112
+ * the event bubbles from block to block.
113
+ *
114
+ * @param {Event} nativeEvent The event to wrap.
115
+ * @param {HTMLElement} target The element to report as the target.
116
+ *
117
+ * @return {Object} The synthetic event.
118
+ */
119
+ function createBlockSyntheticEvent( nativeEvent, target ) {
120
+ let propagationStopped = false;
121
+
122
+ const syntheticEvent = {
123
+ nativeEvent,
124
+ type: nativeEvent.type,
125
+ target,
126
+ currentTarget: null,
127
+ preventDefault() {
128
+ nativeEvent.preventDefault();
129
+ syntheticEvent.defaultPrevented = true;
130
+ },
131
+ isDefaultPrevented() {
132
+ return syntheticEvent.defaultPrevented;
133
+ },
134
+ stopPropagation() {
135
+ nativeEvent.stopPropagation();
136
+ propagationStopped = true;
137
+ },
138
+ isPropagationStopped() {
139
+ return propagationStopped;
140
+ },
141
+ // The modern event system doesn't pool, so persistence is a no-op.
142
+ persist() {},
143
+ isPersistent() {
144
+ return true;
145
+ },
146
+ };
147
+
148
+ for ( const property of EVENT_INTERFACES[ nativeEvent.type ] ) {
149
+ const value = nativeEvent[ property ];
150
+ syntheticEvent[ property ] =
151
+ typeof value === 'function' ? value.bind( nativeEvent ) : value;
152
+ }
153
+
154
+ return syntheticEvent;
155
+ }
156
+
157
+ /**
158
+ * Backwards compatibility for block event handlers under `editableRoot`.
159
+ *
160
+ * When a block supports `editableRoot`, the writing flow wrapper is the
161
+ * contentEditable editing host, so keyboard, input and composition events
162
+ * target the wrapper instead of the block. React `on*` handlers a third party
163
+ * added to a block through `wrapperProps` (e.g. via an `editor.BlockListBlock`
164
+ * filter) are on the block element, below the target, so they stop firing.
165
+ *
166
+ * The block registers those handlers (see `useBlockProps`), and this hook
167
+ * calls them from the host: it resolves the block that owns the selection and
168
+ * every block ancestor, and invokes each registered handler with a synthetic
169
+ * event, innermost first, like a bubbling event. The listeners are attached
170
+ * where React attaches its own (the portal container, the iframe's document
171
+ * element), so a block's handler runs and its `preventDefault` /
172
+ * `stopPropagation` behave as they would through React, without editableRoot.
173
+ *
174
+ * This does not cover handlers a filter puts on its own wrapping element rather
175
+ * than the block's `wrapperProps`; the block element is the supported event
176
+ * surface. It can be removed once input handling is lifted to the host.
177
+ */
178
+ export default function useEditableRootEventHandlers() {
179
+ const { hasMultiSelection, getBlockParents } =
180
+ useSelect( blockEditorStore );
181
+ const { refsMap, eventHandlers } = useContext( BlockRefs );
182
+ return useRefEffect(
183
+ ( node ) => {
184
+ function onEvent( event ) {
185
+ // Only act on real events targeting the host itself, while it
186
+ // is the editing host for a single block and some block has a
187
+ // handler to call.
188
+ if (
189
+ ! eventHandlers.size ||
190
+ event.target !== node ||
191
+ ! event.isTrusted ||
192
+ node.contentEditable !== 'true' ||
193
+ hasMultiSelection()
194
+ ) {
195
+ return;
196
+ }
197
+
198
+ const selection = node.ownerDocument.defaultView.getSelection();
199
+
200
+ if ( ! selection.rangeCount ) {
201
+ return;
202
+ }
203
+
204
+ const editable = getSelectionEditableElement( selection, node );
205
+ const clientId = getBlockClientId( editable );
206
+
207
+ if ( ! clientId ) {
208
+ return;
209
+ }
210
+
211
+ // Call the handler on the block that owns the selection and each
212
+ // of its block ancestors, innermost first, like a bubbling
213
+ // event. The hierarchy comes from the store rather than the DOM,
214
+ // and one synthetic event, wrapping the real event, is reused
215
+ // for the whole chain, its currentTarget moved from block to
216
+ // block. The element is only resolved for blocks with a handler.
217
+ const clientIds = [
218
+ clientId,
219
+ ...getBlockParents( clientId, true ),
220
+ ];
221
+
222
+ let syntheticEvent;
223
+ for ( const ancestorClientId of clientIds ) {
224
+ const handler =
225
+ eventHandlers.get( ancestorClientId )?.current?.[
226
+ event.type
227
+ ];
228
+ const element = handler && refsMap.get( ancestorClientId );
229
+
230
+ if ( ! element ) {
231
+ continue;
232
+ }
233
+
234
+ if ( ! syntheticEvent ) {
235
+ syntheticEvent = createBlockSyntheticEvent(
236
+ event,
237
+ editable
238
+ );
239
+ }
240
+
241
+ syntheticEvent.currentTarget = element;
242
+ handler( syntheticEvent );
243
+
244
+ if ( syntheticEvent.isPropagationStopped() ) {
245
+ break;
246
+ }
247
+ }
248
+ }
249
+
250
+ // Attach where React attaches its own event system: the portal
251
+ // container, which for the iframed canvas is the document element
252
+ // (see `preparePortalMount` in react-dom). Listening at the same
253
+ // node, non-capture, means a block's handler runs in the bubbling
254
+ // phase after core, and its stopPropagation stops at the same point
255
+ // React's would, as its `on*` handler would without editableRoot.
256
+ const root = node.ownerDocument.documentElement;
257
+ const unsubscribers = EVENT_TYPES.map( ( type ) => {
258
+ root.addEventListener( type, onEvent );
259
+ return () => root.removeEventListener( type, onEvent );
260
+ } );
261
+ return () =>
262
+ unsubscribers.forEach( ( unsubscribe ) => unsubscribe() );
263
+ },
264
+ [ hasMultiSelection, getBlockParents, refsMap, eventHandlers ]
265
+ );
266
+ }
@@ -3,7 +3,6 @@
3
3
  */
4
4
  import { useRegistry, useSelect } from '@wordpress/data';
5
5
  import { useRefEffect } from '@wordpress/compose';
6
- import { hasBlockSupport } from '@wordpress/blocks';
7
6
 
8
7
  /**
9
8
  * Internal dependencies
@@ -13,77 +12,6 @@ import { setContentEditableWrapper } from './utils';
13
12
  import { getBlockClientId, getSelectionEditableElement } from '../../utils/dom';
14
13
  import { unlock } from '../../lock-unlock';
15
14
 
16
- /**
17
- * Returns true when the writing flow wrapper can host editing for the given
18
- * block: it supports `editableRoot`, is edited visually in the default
19
- * editing mode, and has sibling blocks for a native selection to extend
20
- * into, all of them editable.
21
- *
22
- * @param {Object} select Bound block editor store selectors.
23
- * @param {string} clientId Block client ID.
24
- *
25
- * @return {boolean} Whether an editing host can host the block.
26
- */
27
- export function canHostEditableRoot( select, clientId ) {
28
- const {
29
- getBlockName,
30
- getBlockEditingMode,
31
- getBlockMode,
32
- getBlockRootClientId,
33
- getBlockOrder,
34
- } = select;
35
-
36
- if (
37
- ! clientId ||
38
- getBlockEditingMode( clientId ) !== 'default' ||
39
- // Not when the block is edited as HTML: there is no rich text to
40
- // host then, only a textarea, which the editing host would
41
- // interfere with.
42
- getBlockMode( clientId ) !== 'visual' ||
43
- ! hasBlockSupport( getBlockName( clientId ), 'editableRoot', false )
44
- ) {
45
- return false;
46
- }
47
-
48
- // Only host when the block has sibling blocks for a native selection to
49
- // extend into, all of them editable. A lone block (e.g. a single
50
- // paragraph nested in an HTML block) is edited on its own element, and
51
- // read-only siblings (e.g. pattern content without overrides enabled)
52
- // must not become editable by inheriting from the host.
53
- const siblings = getBlockOrder( getBlockRootClientId( clientId ) );
54
- return (
55
- siblings.length > 1 &&
56
- siblings.every(
57
- ( siblingClientId ) =>
58
- getBlockEditingMode( siblingClientId ) === 'default'
59
- )
60
- );
61
- }
62
-
63
- /**
64
- * Returns true when the writing flow wrapper should be contentEditable: the
65
- * selected block supports `editableRoot`.
66
- *
67
- * @return {boolean} Whether the wrapper should be editable.
68
- */
69
- export function useHasEditableRoot() {
70
- return useSelect( ( select ) => {
71
- const selectors = select( blockEditorStore );
72
- return canHostEditableRoot(
73
- selectors,
74
- selectors.getSelectedBlockClientId()
75
- );
76
- }, [] );
77
- }
78
-
79
- /**
80
- * Keeps the writing flow wrapper contentEditable while the selected block
81
- * supports `editableRoot`, so the native selection can extend across blocks.
82
- * While the wrapper is editable it must also hold focus: a nested editable
83
- * element cannot retain focus once an ancestor becomes an editing host (the
84
- * first DOM mutation moves focus to the host, inconsistently across
85
- * browsers).
86
- */
87
15
  /**
88
16
  * Keeps the writing flow wrapper contentEditable while the selected block
89
17
  * supports `editableRoot`, so the native selection can extend across blocks.
@@ -94,11 +22,13 @@ export function useHasEditableRoot() {
94
22
  */
95
23
  export default function useEditableRoot() {
96
24
  const registry = useRegistry();
97
- const isZoomOut = useSelect(
98
- ( select ) => unlock( select( blockEditorStore ) ).isZoomOut(),
99
- []
100
- );
101
- const enabled = useHasEditableRoot() && ! isZoomOut;
25
+ const enabled = useSelect( ( select ) => {
26
+ const { getSelectedBlockClientId, canHostEditableRoot, isZoomOut } =
27
+ unlock( select( blockEditorStore ) );
28
+ return (
29
+ ! isZoomOut() && canHostEditableRoot( getSelectedBlockClientId() )
30
+ );
31
+ }, [] );
102
32
 
103
33
  return useRefEffect(
104
34
  ( node ) => {
@@ -12,10 +12,16 @@ import { getSelectionEditableElement } from '../../utils/dom';
12
12
  import { store as blockEditorStore } from '../../store';
13
13
 
14
14
  /**
15
- * While the wrapper is the contentEditable editing host (a selected block
16
- * supports `editableRoot`), browsers don't perform the default caret
17
- * movement for Home and End. Perform the equivalent movement with
18
- * `Selection.modify()`.
15
+ * Moves the caret to the start or end of the visual line for Home and End
16
+ * with `Selection.modify()`, because the browser's default caret movement
17
+ * cannot be relied on in two cases:
18
+ *
19
+ * - While the wrapper is the contentEditable editing host (a selected block
20
+ * supports `editableRoot`), browsers don't perform the default caret
21
+ * movement for Home and End.
22
+ * - Chromium on macOS maps Home and End to scroll commands, so it never
23
+ * moves the caret in editable content on that platform, including nested
24
+ * editable elements like the tab labels in the tab-list block.
19
25
  */
20
26
  export default function useHomeEnd() {
21
27
  const { hasMultiSelection } = useSelect( blockEditorStore );
@@ -33,11 +39,13 @@ export default function useHomeEnd() {
33
39
  return;
34
40
  }
35
41
 
36
- if (
37
- node.contentEditable !== 'true' ||
38
- node.ownerDocument.activeElement !== node ||
39
- hasMultiSelection()
40
- ) {
42
+ // Only handle keys pressed in editable content, in both of the
43
+ // cases mentioned above: `event.target` is the focused element,
44
+ // and `isContentEditable` is true both for the wrapper as the
45
+ // editing host and for a nested editable element like a tab label.
46
+ // Anything else that takes focus like inputs and textareas keep
47
+ // default behavior.
48
+ if ( ! event.target.isContentEditable || hasMultiSelection() ) {
41
49
  return;
42
50
  }
43
51
 
@@ -14,8 +14,7 @@ import { isSelectionForward } from '@wordpress/dom';
14
14
  */
15
15
  import { store as blockEditorStore } from '../../store';
16
16
  import { getBlockClientId } from '../../utils/dom';
17
- import { canHostEditableRoot } from './use-editable-root';
18
- import { setContentEditableWrapper, setShiftClickInProgress } from './utils';
17
+ import { setContentEditableWrapper } from './utils';
19
18
  import { unlock } from '../../lock-unlock';
20
19
 
21
20
  const { ownsSelection } = unlock( richTextPrivateApis );
@@ -102,9 +101,13 @@ function getRichTextElement( node ) {
102
101
  * Sets a multi-selection based on the native selection across blocks.
103
102
  */
104
103
  export default function useSelectionObserver() {
105
- const { multiSelect, selectBlock, selectionChange } =
106
- useDispatch( blockEditorStore );
107
- const blockEditorSelectors = useSelect( blockEditorStore );
104
+ const {
105
+ multiSelect,
106
+ selectBlock,
107
+ selectionChange,
108
+ startMultiSelect,
109
+ stopMultiSelect,
110
+ } = useDispatch( blockEditorStore );
108
111
  const {
109
112
  getBlockParents,
110
113
  getBlockSelectionStart,
@@ -112,7 +115,8 @@ export default function useSelectionObserver() {
112
115
  getSelectionStart,
113
116
  getSelectionEnd,
114
117
  getSelectedBlockClientId,
115
- } = blockEditorSelectors;
118
+ canHostEditableRoot,
119
+ } = unlock( useSelect( blockEditorStore ) );
116
120
  return useRefEffect(
117
121
  ( node ) => {
118
122
  const { ownerDocument } = node;
@@ -122,12 +126,18 @@ export default function useSelectionObserver() {
122
126
 
123
127
  function onMouseDown( event ) {
124
128
  isTripleClick = event.detail === 3;
125
- setShiftClickInProgress( event.shiftKey );
129
+ // A shift+click makes a multi-selection: mark the gesture as
130
+ // in progress so the clicked block's focus handler does not
131
+ // select it (collapsing the native range being made), and so
132
+ // use-multi-selection does not clear the native selection.
133
+ // The selection is built on mouseup.
134
+ if ( event.shiftKey ) {
135
+ startMultiSelect();
136
+ }
126
137
  }
127
138
 
128
139
  function onKeyDown() {
129
140
  isTripleClick = false;
130
- setShiftClickInProgress( false );
131
141
  }
132
142
 
133
143
  function onSelectionChange( event ) {
@@ -174,10 +184,7 @@ export default function useSelectionObserver() {
174
184
  // always move it), which must not re-enable the wrapper
175
185
  // after another block has been selected.
176
186
  collapsedClientId === getSelectedBlockClientId() &&
177
- canHostEditableRoot(
178
- blockEditorSelectors,
179
- collapsedClientId
180
- )
187
+ canHostEditableRoot( collapsedClientId )
181
188
  ) {
182
189
  setContentEditableWrapper( node, true );
183
190
 
@@ -362,9 +369,19 @@ export default function useSelectionObserver() {
362
369
  ];
363
370
  const depth = findDepth( startPath, endPath );
364
371
 
372
+ // If one path ends before they diverge, one block
373
+ // contains the other, so there are no sibling blocks
374
+ // to promote the selection to. Record the selection as
375
+ // is: it resolves to the outer block, which is treated
376
+ // as fully selected. See `getSelectionNestingAncestor`
377
+ // in the store.
378
+ const isAncestorDescendant =
379
+ depth >= startPath.length || depth >= endPath.length;
380
+
365
381
  if (
366
- startPath[ depth ] !== startClientId ||
367
- endPath[ depth ] !== endClientId
382
+ ! isAncestorDescendant &&
383
+ ( startPath[ depth ] !== startClientId ||
384
+ endPath[ depth ] !== endClientId )
368
385
  ) {
369
386
  multiSelect( startPath[ depth ], endPath[ depth ] );
370
387
  return;
@@ -444,7 +461,7 @@ export default function useSelectionObserver() {
444
461
  );
445
462
  function onMouseUp( event ) {
446
463
  onSelectionChange( event );
447
- setShiftClickInProgress( false );
464
+ stopMultiSelect();
448
465
  }
449
466
 
450
467
  defaultView.addEventListener( 'mouseup', onMouseUp );
@@ -118,29 +118,6 @@ function toPlainText( html ) {
118
118
  return plainText.replace( /\n\n+/g, '\n\n' );
119
119
  }
120
120
 
121
- let shiftClickInProgress = false;
122
-
123
- /**
124
- * Tracks whether a shift+click gesture is in progress, from the shift held
125
- * mousedown until its mouseup. Maintained by the selection observer; read by
126
- * the block focus handler, since the focus event fired between the two
127
- * carries no modifier keys.
128
- *
129
- * @param {boolean} value Whether a shift+click gesture is in progress.
130
- */
131
- export function setShiftClickInProgress( value ) {
132
- shiftClickInProgress = value;
133
- }
134
-
135
- /**
136
- * Returns whether a shift+click gesture is in progress.
137
- *
138
- * @return {boolean} Whether a shift+click gesture is in progress.
139
- */
140
- export function isShiftClickInProgress() {
141
- return shiftClickInProgress;
142
- }
143
-
144
121
  /**
145
122
  * Makes the wrapper element an editing host, or stops it from being one. The
146
123
  * ARIA attributes travel with the editability: while the wrapper is the
@@ -194,7 +171,9 @@ export function setContentEditableWrapper(
194
171
  node.setAttribute( 'aria-label', __( 'Editor canvas' ) );
195
172
 
196
173
  if ( focus ) {
197
- node.focus();
174
+ // Without preventScroll, focusing the wrapper scrolls the
175
+ // viewport to the top of the wrapper.
176
+ node.focus( { preventScroll: true } );
198
177
  }
199
178
 
200
179
  return true;