@wordpress/block-editor 10.5.0 → 11.0.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 (488) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/build/autocompleters/block.js +2 -6
  3. package/build/autocompleters/block.js.map +1 -1
  4. package/build/autocompleters/link.js +2 -0
  5. package/build/autocompleters/link.js.map +1 -1
  6. package/build/components/block-card/index.js +51 -3
  7. package/build/components/block-card/index.js.map +1 -1
  8. package/build/components/block-draggable/index.native.js +46 -39
  9. package/build/components/block-draggable/index.native.js.map +1 -1
  10. package/build/components/block-edit/edit.js +4 -3
  11. package/build/components/block-edit/edit.js.map +1 -1
  12. package/build/components/block-edit/edit.native.js +4 -7
  13. package/build/components/block-edit/edit.native.js.map +1 -1
  14. package/build/components/block-inspector/index.js +35 -33
  15. package/build/components/block-inspector/index.js.map +1 -1
  16. package/build/components/block-list/block-list-context.native.js +5 -8
  17. package/build/components/block-list/block-list-context.native.js.map +1 -1
  18. package/build/components/block-list/block.js +55 -24
  19. package/build/components/block-list/block.js.map +1 -1
  20. package/build/components/block-list/block.native.js +61 -28
  21. package/build/components/block-list/block.native.js.map +1 -1
  22. package/build/components/block-mobile-toolbar/block-actions-menu.native.js +12 -4
  23. package/build/components/block-mobile-toolbar/block-actions-menu.native.js.map +1 -1
  24. package/build/components/block-pattern-setup/index.js +3 -2
  25. package/build/components/block-pattern-setup/index.js.map +1 -1
  26. package/build/components/block-patterns-list/index.js +33 -11
  27. package/build/components/block-patterns-list/index.js.map +1 -1
  28. package/build/components/block-preview/auto.js +9 -3
  29. package/build/components/block-preview/auto.js.map +1 -1
  30. package/build/components/block-preview/index.js +5 -9
  31. package/build/components/block-preview/index.js.map +1 -1
  32. package/build/components/block-settings-menu/block-settings-dropdown.js +5 -2
  33. package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  34. package/build/components/block-toolbar/index.js +5 -1
  35. package/build/components/block-toolbar/index.js.map +1 -1
  36. package/build/components/block-tools/insertion-point.js +8 -49
  37. package/build/components/block-tools/insertion-point.js.map +1 -1
  38. package/build/components/block-variation-picker/index.js +1 -2
  39. package/build/components/block-variation-picker/index.js.map +1 -1
  40. package/build/components/height-control/index.js +115 -0
  41. package/build/components/height-control/index.js.map +1 -0
  42. package/build/components/iframe/index.js +11 -8
  43. package/build/components/iframe/index.js.map +1 -1
  44. package/build/components/image-editor/use-save-image.js +2 -0
  45. package/build/components/image-editor/use-save-image.js.map +1 -1
  46. package/build/components/image-editor/zoom-dropdown.js +1 -0
  47. package/build/components/image-editor/zoom-dropdown.js.map +1 -1
  48. package/build/components/index.js +9 -0
  49. package/build/components/index.js.map +1 -1
  50. package/build/components/inner-blocks/index.js +20 -6
  51. package/build/components/inner-blocks/index.js.map +1 -1
  52. package/build/components/inner-blocks/use-inner-block-template-sync.js +25 -10
  53. package/build/components/inner-blocks/use-inner-block-template-sync.js.map +1 -1
  54. package/build/components/inserter/block-patterns-explorer/sidebar.js +1 -0
  55. package/build/components/inserter/block-patterns-explorer/sidebar.js.map +1 -1
  56. package/build/components/inserter/block-patterns-tab.js +25 -46
  57. package/build/components/inserter/block-patterns-tab.js.map +1 -1
  58. package/build/components/inserter/block-types-tab.js +3 -1
  59. package/build/components/inserter/block-types-tab.js.map +1 -1
  60. package/build/components/inserter/hooks/use-debounced-input.js +27 -0
  61. package/build/components/inserter/hooks/use-debounced-input.js.map +1 -0
  62. package/build/components/inserter/index.js +8 -3
  63. package/build/components/inserter/index.js.map +1 -1
  64. package/build/components/inserter/index.native.js +3 -4
  65. package/build/components/inserter/index.native.js.map +1 -1
  66. package/build/components/inserter/media-tab/hooks.js +103 -0
  67. package/build/components/inserter/media-tab/hooks.js.map +1 -0
  68. package/build/components/inserter/media-tab/index.js +32 -0
  69. package/build/components/inserter/media-tab/index.js.map +1 -0
  70. package/build/components/inserter/media-tab/media-list.js +100 -0
  71. package/build/components/inserter/media-tab/media-list.js.map +1 -0
  72. package/build/components/inserter/media-tab/media-panel.js +96 -0
  73. package/build/components/inserter/media-tab/media-panel.js.map +1 -0
  74. package/build/components/inserter/media-tab/media-tab.js +120 -0
  75. package/build/components/inserter/media-tab/media-tab.js.map +1 -0
  76. package/build/components/inserter/media-tab/utils.js +54 -0
  77. package/build/components/inserter/media-tab/utils.js.map +1 -0
  78. package/build/components/inserter/menu.js +35 -12
  79. package/build/components/inserter/menu.js.map +1 -1
  80. package/build/components/inserter/mobile-tab-navigation.js +70 -0
  81. package/build/components/inserter/mobile-tab-navigation.js.map +1 -0
  82. package/build/components/inserter/quick-inserter.js +1 -0
  83. package/build/components/inserter/quick-inserter.js.map +1 -1
  84. package/build/components/inserter/search-results.js +3 -1
  85. package/build/components/inserter/search-results.js.map +1 -1
  86. package/build/components/inserter/tabs.js +16 -2
  87. package/build/components/inserter/tabs.js.map +1 -1
  88. package/build/components/inserter-list-item/index.js +4 -1
  89. package/build/components/inserter-list-item/index.js.map +1 -1
  90. package/build/components/inspector-controls/groups.js +2 -0
  91. package/build/components/inspector-controls/groups.js.map +1 -1
  92. package/build/components/inspector-controls-tabs/advanced-controls-panel.js +46 -0
  93. package/build/components/inspector-controls-tabs/advanced-controls-panel.js.map +1 -0
  94. package/build/components/inspector-controls-tabs/index.js +71 -0
  95. package/build/components/inspector-controls-tabs/index.js.map +1 -0
  96. package/build/components/inspector-controls-tabs/settings-tab.js +28 -0
  97. package/build/components/inspector-controls-tabs/settings-tab.js.map +1 -0
  98. package/build/components/inspector-controls-tabs/styles-tab.js +61 -0
  99. package/build/components/inspector-controls-tabs/styles-tab.js.map +1 -0
  100. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js +97 -0
  101. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +1 -0
  102. package/build/components/inspector-controls-tabs/use-is-list-view-tab-disabled.js +18 -0
  103. package/build/components/inspector-controls-tabs/use-is-list-view-tab-disabled.js.map +1 -0
  104. package/build/components/inspector-controls-tabs/utils.js +37 -0
  105. package/build/components/inspector-controls-tabs/utils.js.map +1 -0
  106. package/build/components/link-control/index.js +1 -0
  107. package/build/components/link-control/index.js.map +1 -1
  108. package/build/components/link-control/search-input.js +0 -1
  109. package/build/components/link-control/search-input.js.map +1 -1
  110. package/build/components/link-control/use-internal-input-value.js +3 -3
  111. package/build/components/link-control/use-internal-input-value.js.map +1 -1
  112. package/build/components/list-view/block.js +5 -2
  113. package/build/components/list-view/block.js.map +1 -1
  114. package/build/components/list-view/branch.js +13 -12
  115. package/build/components/list-view/branch.js.map +1 -1
  116. package/build/components/media-upload/index.native.js +2 -3
  117. package/build/components/media-upload/index.native.js.map +1 -1
  118. package/build/components/off-canvas-editor/appender.js +104 -0
  119. package/build/components/off-canvas-editor/appender.js.map +1 -0
  120. package/build/components/off-canvas-editor/block-edit-button.js +50 -0
  121. package/build/components/off-canvas-editor/block-edit-button.js.map +1 -0
  122. package/build/components/off-canvas-editor/block.js +36 -4
  123. package/build/components/off-canvas-editor/block.js.map +1 -1
  124. package/build/components/off-canvas-editor/branch.js +3 -5
  125. package/build/components/off-canvas-editor/branch.js.map +1 -1
  126. package/build/components/off-canvas-editor/index.js +20 -11
  127. package/build/components/off-canvas-editor/index.js.map +1 -1
  128. package/build/components/off-canvas-editor/leaf.js +1 -1
  129. package/build/components/off-canvas-editor/leaf.js.map +1 -1
  130. package/build/components/off-canvas-editor/link-ui.js +185 -0
  131. package/build/components/off-canvas-editor/link-ui.js.map +1 -0
  132. package/build/components/off-canvas-editor/update-attributes.js +108 -0
  133. package/build/components/off-canvas-editor/update-attributes.js.map +1 -0
  134. package/build/components/rich-text/format-toolbar/index.js +8 -4
  135. package/build/components/rich-text/format-toolbar/index.js.map +1 -1
  136. package/build/components/rich-text/index.js +3 -3
  137. package/build/components/rich-text/index.js.map +1 -1
  138. package/build/components/rich-text/index.native.js +0 -2
  139. package/build/components/rich-text/index.native.js.map +1 -1
  140. package/build/components/rich-text/use-insert-replacement-text.js +43 -0
  141. package/build/components/rich-text/use-insert-replacement-text.js.map +1 -0
  142. package/build/components/rich-text/use-undo-automatic-change.js +9 -1
  143. package/build/components/rich-text/use-undo-automatic-change.js.map +1 -1
  144. package/build/components/rich-text/utils.js +1 -19
  145. package/build/components/rich-text/utils.js.map +1 -1
  146. package/build/components/spacing-sizes-control/spacing-input-control.js +12 -3
  147. package/build/components/spacing-sizes-control/spacing-input-control.js.map +1 -1
  148. package/build/components/ungroup-button/index.native.js +4 -2
  149. package/build/components/ungroup-button/index.native.js.map +1 -1
  150. package/build/components/url-input/index.js +46 -43
  151. package/build/components/url-input/index.js.map +1 -1
  152. package/build/components/use-block-display-information/index.js +8 -4
  153. package/build/components/use-block-display-information/index.js.map +1 -1
  154. package/build/components/use-setting/index.js +9 -1
  155. package/build/components/use-setting/index.js.map +1 -1
  156. package/build/hooks/child-layout.js +209 -0
  157. package/build/hooks/child-layout.js.map +1 -0
  158. package/build/hooks/content-lock-ui.js +1 -1
  159. package/build/hooks/content-lock-ui.js.map +1 -1
  160. package/build/hooks/dimensions.js +25 -7
  161. package/build/hooks/dimensions.js.map +1 -1
  162. package/build/hooks/layout.js +57 -1
  163. package/build/hooks/layout.js.map +1 -1
  164. package/build/hooks/min-height.js +4 -10
  165. package/build/hooks/min-height.js.map +1 -1
  166. package/build/store/reducer.js +393 -270
  167. package/build/store/reducer.js.map +1 -1
  168. package/build/store/selectors.js +57 -47
  169. package/build/store/selectors.js.map +1 -1
  170. package/build/utils/sorting.js +63 -0
  171. package/build/utils/sorting.js.map +1 -0
  172. package/build-module/autocompleters/block.js +2 -6
  173. package/build-module/autocompleters/block.js.map +1 -1
  174. package/build-module/autocompleters/link.js +2 -0
  175. package/build-module/autocompleters/link.js.map +1 -1
  176. package/build-module/components/block-card/index.js +45 -3
  177. package/build-module/components/block-card/index.js.map +1 -1
  178. package/build-module/components/block-draggable/index.native.js +40 -31
  179. package/build-module/components/block-draggable/index.native.js.map +1 -1
  180. package/build-module/components/block-edit/edit.js +4 -2
  181. package/build-module/components/block-edit/edit.js.map +1 -1
  182. package/build-module/components/block-edit/edit.native.js +4 -6
  183. package/build-module/components/block-edit/edit.native.js.map +1 -1
  184. package/build-module/components/block-inspector/index.js +32 -30
  185. package/build-module/components/block-inspector/index.js.map +1 -1
  186. package/build-module/components/block-list/block-list-context.native.js +5 -8
  187. package/build-module/components/block-list/block-list-context.native.js.map +1 -1
  188. package/build-module/components/block-list/block.js +55 -25
  189. package/build-module/components/block-list/block.js.map +1 -1
  190. package/build-module/components/block-list/block.native.js +61 -28
  191. package/build-module/components/block-list/block.native.js.map +1 -1
  192. package/build-module/components/block-mobile-toolbar/block-actions-menu.native.js +13 -6
  193. package/build-module/components/block-mobile-toolbar/block-actions-menu.native.js.map +1 -1
  194. package/build-module/components/block-pattern-setup/index.js +3 -2
  195. package/build-module/components/block-pattern-setup/index.js.map +1 -1
  196. package/build-module/components/block-patterns-list/index.js +35 -13
  197. package/build-module/components/block-patterns-list/index.js.map +1 -1
  198. package/build-module/components/block-preview/auto.js +9 -3
  199. package/build-module/components/block-preview/auto.js.map +1 -1
  200. package/build-module/components/block-preview/index.js +5 -8
  201. package/build-module/components/block-preview/index.js.map +1 -1
  202. package/build-module/components/block-settings-menu/block-settings-dropdown.js +5 -2
  203. package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  204. package/build-module/components/block-toolbar/index.js +6 -2
  205. package/build-module/components/block-toolbar/index.js.map +1 -1
  206. package/build-module/components/block-tools/insertion-point.js +8 -49
  207. package/build-module/components/block-tools/insertion-point.js.map +1 -1
  208. package/build-module/components/block-variation-picker/index.js +1 -2
  209. package/build-module/components/block-variation-picker/index.js.map +1 -1
  210. package/build-module/components/height-control/index.js +103 -0
  211. package/build-module/components/height-control/index.js.map +1 -0
  212. package/build-module/components/iframe/index.js +11 -8
  213. package/build-module/components/iframe/index.js.map +1 -1
  214. package/build-module/components/image-editor/use-save-image.js +2 -0
  215. package/build-module/components/image-editor/use-save-image.js.map +1 -1
  216. package/build-module/components/image-editor/zoom-dropdown.js +1 -0
  217. package/build-module/components/image-editor/zoom-dropdown.js.map +1 -1
  218. package/build-module/components/index.js +1 -0
  219. package/build-module/components/index.js.map +1 -1
  220. package/build-module/components/inner-blocks/index.js +22 -8
  221. package/build-module/components/inner-blocks/index.js.map +1 -1
  222. package/build-module/components/inner-blocks/use-inner-block-template-sync.js +23 -10
  223. package/build-module/components/inner-blocks/use-inner-block-template-sync.js.map +1 -1
  224. package/build-module/components/inserter/block-patterns-explorer/sidebar.js +1 -0
  225. package/build-module/components/inserter/block-patterns-explorer/sidebar.js.map +1 -1
  226. package/build-module/components/inserter/block-patterns-tab.js +27 -49
  227. package/build-module/components/inserter/block-patterns-tab.js.map +1 -1
  228. package/build-module/components/inserter/block-types-tab.js +3 -2
  229. package/build-module/components/inserter/block-types-tab.js.map +1 -1
  230. package/build-module/components/inserter/hooks/use-debounced-input.js +18 -0
  231. package/build-module/components/inserter/hooks/use-debounced-input.js.map +1 -0
  232. package/build-module/components/inserter/index.js +8 -3
  233. package/build-module/components/inserter/index.js.map +1 -1
  234. package/build-module/components/inserter/index.native.js +3 -5
  235. package/build-module/components/inserter/index.native.js.map +1 -1
  236. package/build-module/components/inserter/media-tab/hooks.js +89 -0
  237. package/build-module/components/inserter/media-tab/hooks.js.map +1 -0
  238. package/build-module/components/inserter/media-tab/index.js +4 -0
  239. package/build-module/components/inserter/media-tab/index.js.map +1 -0
  240. package/build-module/components/inserter/media-tab/media-list.js +86 -0
  241. package/build-module/components/inserter/media-tab/media-list.js.map +1 -0
  242. package/build-module/components/inserter/media-tab/media-panel.js +77 -0
  243. package/build-module/components/inserter/media-tab/media-panel.js.map +1 -0
  244. package/build-module/components/inserter/media-tab/media-tab.js +100 -0
  245. package/build-module/components/inserter/media-tab/media-tab.js.map +1 -0
  246. package/build-module/components/inserter/media-tab/utils.js +45 -0
  247. package/build-module/components/inserter/media-tab/utils.js.map +1 -0
  248. package/build-module/components/inserter/menu.js +33 -12
  249. package/build-module/components/inserter/menu.js.map +1 -1
  250. package/build-module/components/inserter/mobile-tab-navigation.js +61 -0
  251. package/build-module/components/inserter/mobile-tab-navigation.js.map +1 -0
  252. package/build-module/components/inserter/quick-inserter.js +1 -0
  253. package/build-module/components/inserter/quick-inserter.js.map +1 -1
  254. package/build-module/components/inserter/search-results.js +3 -2
  255. package/build-module/components/inserter/search-results.js.map +1 -1
  256. package/build-module/components/inserter/tabs.js +15 -2
  257. package/build-module/components/inserter/tabs.js.map +1 -1
  258. package/build-module/components/inserter-list-item/index.js +5 -2
  259. package/build-module/components/inserter-list-item/index.js.map +1 -1
  260. package/build-module/components/inspector-controls/groups.js +2 -0
  261. package/build-module/components/inspector-controls/groups.js.map +1 -1
  262. package/build-module/components/inspector-controls-tabs/advanced-controls-panel.js +32 -0
  263. package/build-module/components/inspector-controls-tabs/advanced-controls-panel.js.map +1 -0
  264. package/build-module/components/inspector-controls-tabs/index.js +56 -0
  265. package/build-module/components/inspector-controls-tabs/index.js.map +1 -0
  266. package/build-module/components/inspector-controls-tabs/settings-tab.js +17 -0
  267. package/build-module/components/inspector-controls-tabs/settings-tab.js.map +1 -0
  268. package/build-module/components/inspector-controls-tabs/styles-tab.js +46 -0
  269. package/build-module/components/inspector-controls-tabs/styles-tab.js.map +1 -0
  270. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js +81 -0
  271. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +1 -0
  272. package/build-module/components/inspector-controls-tabs/use-is-list-view-tab-disabled.js +8 -0
  273. package/build-module/components/inspector-controls-tabs/use-is-list-view-tab-disabled.js.map +1 -0
  274. package/build-module/components/inspector-controls-tabs/utils.js +26 -0
  275. package/build-module/components/inspector-controls-tabs/utils.js.map +1 -0
  276. package/build-module/components/link-control/index.js +1 -0
  277. package/build-module/components/link-control/index.js.map +1 -1
  278. package/build-module/components/link-control/search-input.js +0 -1
  279. package/build-module/components/link-control/search-input.js.map +1 -1
  280. package/build-module/components/link-control/use-internal-input-value.js +3 -3
  281. package/build-module/components/link-control/use-internal-input-value.js.map +1 -1
  282. package/build-module/components/list-view/block.js +5 -2
  283. package/build-module/components/list-view/block.js.map +1 -1
  284. package/build-module/components/list-view/branch.js +12 -11
  285. package/build-module/components/list-view/branch.js.map +1 -1
  286. package/build-module/components/media-upload/index.native.js +2 -4
  287. package/build-module/components/media-upload/index.native.js.map +1 -1
  288. package/build-module/components/off-canvas-editor/appender.js +89 -0
  289. package/build-module/components/off-canvas-editor/appender.js.map +1 -0
  290. package/build-module/components/off-canvas-editor/block-edit-button.js +35 -0
  291. package/build-module/components/off-canvas-editor/block-edit-button.js.map +1 -0
  292. package/build-module/components/off-canvas-editor/block.js +36 -6
  293. package/build-module/components/off-canvas-editor/block.js.map +1 -1
  294. package/build-module/components/off-canvas-editor/branch.js +3 -4
  295. package/build-module/components/off-canvas-editor/branch.js.map +1 -1
  296. package/build-module/components/off-canvas-editor/index.js +20 -12
  297. package/build-module/components/off-canvas-editor/index.js.map +1 -1
  298. package/build-module/components/off-canvas-editor/leaf.js +1 -1
  299. package/build-module/components/off-canvas-editor/leaf.js.map +1 -1
  300. package/build-module/components/off-canvas-editor/link-ui.js +165 -0
  301. package/build-module/components/off-canvas-editor/link-ui.js.map +1 -0
  302. package/build-module/components/off-canvas-editor/update-attributes.js +97 -0
  303. package/build-module/components/off-canvas-editor/update-attributes.js.map +1 -0
  304. package/build-module/components/rich-text/format-toolbar/index.js +6 -2
  305. package/build-module/components/rich-text/format-toolbar/index.js.map +1 -1
  306. package/build-module/components/rich-text/index.js +2 -3
  307. package/build-module/components/rich-text/index.js.map +1 -1
  308. package/build-module/components/rich-text/index.native.js +0 -2
  309. package/build-module/components/rich-text/index.native.js.map +1 -1
  310. package/build-module/components/rich-text/use-insert-replacement-text.js +33 -0
  311. package/build-module/components/rich-text/use-insert-replacement-text.js.map +1 -0
  312. package/build-module/components/rich-text/use-undo-automatic-change.js +9 -1
  313. package/build-module/components/rich-text/use-undo-automatic-change.js.map +1 -1
  314. package/build-module/components/rich-text/utils.js +1 -16
  315. package/build-module/components/rich-text/utils.js.map +1 -1
  316. package/build-module/components/spacing-sizes-control/spacing-input-control.js +12 -3
  317. package/build-module/components/spacing-sizes-control/spacing-input-control.js.map +1 -1
  318. package/build-module/components/ungroup-button/index.native.js +3 -2
  319. package/build-module/components/ungroup-button/index.native.js.map +1 -1
  320. package/build-module/components/url-input/index.js +46 -43
  321. package/build-module/components/url-input/index.js.map +1 -1
  322. package/build-module/components/use-block-display-information/index.js +9 -5
  323. package/build-module/components/use-block-display-information/index.js.map +1 -1
  324. package/build-module/components/use-setting/index.js +8 -1
  325. package/build-module/components/use-setting/index.js.map +1 -1
  326. package/build-module/hooks/child-layout.js +189 -0
  327. package/build-module/hooks/child-layout.js.map +1 -0
  328. package/build-module/hooks/content-lock-ui.js +1 -1
  329. package/build-module/hooks/content-lock-ui.js.map +1 -1
  330. package/build-module/hooks/dimensions.js +25 -8
  331. package/build-module/hooks/dimensions.js.map +1 -1
  332. package/build-module/hooks/layout.js +55 -0
  333. package/build-module/hooks/layout.js.map +1 -1
  334. package/build-module/hooks/min-height.js +3 -9
  335. package/build-module/hooks/min-height.js.map +1 -1
  336. package/build-module/store/reducer.js +391 -271
  337. package/build-module/store/reducer.js.map +1 -1
  338. package/build-module/store/selectors.js +54 -47
  339. package/build-module/store/selectors.js.map +1 -1
  340. package/build-module/utils/sorting.js +56 -0
  341. package/build-module/utils/sorting.js.map +1 -0
  342. package/build-style/content-rtl.css +701 -0
  343. package/build-style/content.css +701 -0
  344. package/build-style/default-editor-styles-rtl.css +14 -0
  345. package/build-style/default-editor-styles.css +14 -0
  346. package/build-style/style-rtl.css +286 -662
  347. package/build-style/style.css +286 -662
  348. package/package.json +32 -30
  349. package/src/autocompleters/block.js +2 -6
  350. package/src/autocompleters/link.js +2 -0
  351. package/src/components/alignment-control/test/index.js +4 -1
  352. package/src/components/block-alignment-control/test/index.js +4 -1
  353. package/src/components/block-card/index.js +46 -2
  354. package/src/components/block-card/style.scss +4 -0
  355. package/src/components/block-content-overlay/{style.scss → content.scss} +7 -1
  356. package/src/components/block-draggable/content.scss +20 -0
  357. package/src/components/block-draggable/index.native.js +54 -40
  358. package/src/components/block-draggable/style.scss +0 -21
  359. package/src/components/block-draggable/test/helpers.native.js +7 -9
  360. package/src/components/block-draggable/test/index.native.js +35 -45
  361. package/src/components/block-edit/edit.js +5 -2
  362. package/src/components/block-edit/edit.native.js +5 -6
  363. package/src/components/block-inspector/index.js +96 -81
  364. package/src/components/block-inspector/style.scss +9 -1
  365. package/src/components/block-list/block-list-context.native.js +5 -8
  366. package/src/components/block-list/block.js +74 -23
  367. package/src/components/block-list/block.native.js +78 -23
  368. package/src/components/block-list/{style.scss → content.scss} +1 -15
  369. package/src/components/block-list-appender/{style.scss → content.scss} +0 -0
  370. package/src/components/block-mobile-toolbar/block-actions-menu.native.js +24 -6
  371. package/src/components/block-mover/test/__snapshots__/index.native.js.snap +0 -2
  372. package/src/components/block-pattern-setup/index.js +2 -1
  373. package/src/components/block-patterns-list/index.js +47 -24
  374. package/src/components/block-preview/README.md +15 -10
  375. package/src/components/block-preview/auto.js +7 -1
  376. package/src/components/block-preview/content.scss +4 -0
  377. package/src/components/block-preview/index.js +7 -12
  378. package/src/components/block-preview/style.scss +0 -7
  379. package/src/components/block-preview/test/index.js +18 -35
  380. package/src/components/block-selection-clearer/test/index.js +12 -12
  381. package/src/components/block-settings-menu/block-settings-dropdown.js +32 -20
  382. package/src/components/block-switcher/test/index.js +4 -0
  383. package/src/components/block-toolbar/index.js +12 -5
  384. package/src/components/block-toolbar/style.scss +10 -0
  385. package/src/components/block-tools/insertion-point.js +3 -47
  386. package/src/components/block-tools/style.scss +12 -5
  387. package/src/components/block-variation-picker/index.js +1 -4
  388. package/src/components/block-vertical-alignment-control/test/index.js +4 -1
  389. package/src/components/default-block-appender/{style.scss → content.scss} +0 -0
  390. package/src/components/height-control/index.js +123 -0
  391. package/src/components/height-control/stories/index.js +21 -0
  392. package/src/components/height-control/style.scss +5 -0
  393. package/src/components/iframe/index.js +25 -18
  394. package/src/components/image-editor/use-save-image.js +2 -0
  395. package/src/components/image-editor/zoom-dropdown.js +1 -0
  396. package/src/components/index.js +1 -0
  397. package/src/components/inner-blocks/{style.scss → content.scss} +0 -0
  398. package/src/components/inner-blocks/index.js +23 -6
  399. package/src/components/inner-blocks/use-inner-block-template-sync.js +28 -10
  400. package/src/components/inserter/block-patterns-explorer/sidebar.js +1 -0
  401. package/src/components/inserter/block-patterns-tab.js +28 -71
  402. package/src/components/inserter/block-types-tab.js +3 -2
  403. package/src/components/inserter/hooks/use-debounced-input.js +17 -0
  404. package/src/components/inserter/index.js +10 -2
  405. package/src/components/inserter/index.native.js +1 -1
  406. package/src/components/inserter/media-tab/hooks.js +88 -0
  407. package/src/components/inserter/media-tab/index.js +3 -0
  408. package/src/components/inserter/media-tab/media-list.js +93 -0
  409. package/src/components/inserter/media-tab/media-panel.js +83 -0
  410. package/src/components/inserter/media-tab/media-tab.js +135 -0
  411. package/src/components/inserter/media-tab/utils.js +37 -0
  412. package/src/components/inserter/menu.js +55 -13
  413. package/src/components/inserter/mobile-tab-navigation.js +85 -0
  414. package/src/components/inserter/quick-inserter.js +1 -0
  415. package/src/components/inserter/search-results.js +3 -2
  416. package/src/components/inserter/stories/index.js +1 -1
  417. package/src/components/inserter/stories/{fixtures.js → utils/fixtures.js} +0 -0
  418. package/src/components/inserter/style.scss +176 -11
  419. package/src/components/inserter/tabs.js +12 -1
  420. package/src/components/inserter-list-item/index.js +11 -1
  421. package/src/components/inserter-list-item/style.scss +26 -0
  422. package/src/components/inspector-controls/groups.js +2 -0
  423. package/src/components/inspector-controls-tabs/advanced-controls-panel.js +37 -0
  424. package/src/components/inspector-controls-tabs/index.js +62 -0
  425. package/src/components/inspector-controls-tabs/settings-tab.js +18 -0
  426. package/src/components/inspector-controls-tabs/styles-tab.js +51 -0
  427. package/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js +89 -0
  428. package/src/components/inspector-controls-tabs/use-is-list-view-tab-disabled.js +9 -0
  429. package/src/components/inspector-controls-tabs/utils.js +28 -0
  430. package/src/components/line-height-control/test/index.js +5 -5
  431. package/src/components/link-control/README.md +1 -1
  432. package/src/components/link-control/index.js +1 -0
  433. package/src/components/link-control/search-input.js +0 -1
  434. package/src/components/link-control/test/index.js +188 -401
  435. package/src/components/link-control/use-internal-input-value.js +3 -3
  436. package/src/components/list-view/block.js +3 -0
  437. package/src/components/list-view/branch.js +10 -8
  438. package/src/components/list-view/style.scss +20 -9
  439. package/src/components/media-placeholder/{style.scss → content.scss} +0 -0
  440. package/src/components/media-replace-flow/test/index.js +37 -9
  441. package/src/components/media-upload/test/index.native.js +2 -0
  442. package/src/components/off-canvas-editor/appender.js +93 -0
  443. package/src/components/off-canvas-editor/block-edit-button.js +27 -0
  444. package/src/components/off-canvas-editor/block.js +88 -22
  445. package/src/components/off-canvas-editor/branch.js +3 -5
  446. package/src/components/off-canvas-editor/index.js +59 -33
  447. package/src/components/off-canvas-editor/leaf.js +5 -1
  448. package/src/components/off-canvas-editor/link-ui.js +166 -0
  449. package/src/components/off-canvas-editor/style.scss +17 -388
  450. package/src/components/off-canvas-editor/update-attributes.js +99 -0
  451. package/src/components/plain-text/{style.scss → content.scss} +0 -0
  452. package/src/components/recursion-provider/test/index.js +27 -29
  453. package/src/components/rich-text/content.scss +42 -0
  454. package/src/components/rich-text/format-toolbar/index.js +6 -4
  455. package/src/components/rich-text/index.js +2 -2
  456. package/src/components/rich-text/index.native.js +0 -2
  457. package/src/components/rich-text/style.scss +0 -43
  458. package/src/components/rich-text/use-insert-replacement-text.js +31 -0
  459. package/src/components/rich-text/use-undo-automatic-change.js +7 -1
  460. package/src/components/rich-text/utils.js +2 -21
  461. package/src/components/spacing-sizes-control/spacing-input-control.js +9 -0
  462. package/src/components/ungroup-button/index.native.js +6 -2
  463. package/src/components/url-input/index.js +57 -73
  464. package/src/components/url-popover/test/__snapshots__/index.js.snap +8 -6
  465. package/src/components/url-popover/test/index.js +21 -9
  466. package/src/components/use-block-display-information/index.js +14 -5
  467. package/src/components/use-setting/index.js +13 -1
  468. package/src/components/use-setting/test/index.js +99 -0
  469. package/src/content.scss +10 -0
  470. package/src/hooks/child-layout.js +190 -0
  471. package/src/hooks/content-lock-ui.js +1 -1
  472. package/src/hooks/dimensions.js +45 -7
  473. package/src/hooks/layout.js +60 -0
  474. package/src/hooks/min-height.js +2 -19
  475. package/src/store/reducer.js +459 -423
  476. package/src/store/selectors.js +56 -57
  477. package/src/store/test/performance.js +71 -0
  478. package/src/store/test/reducer.js +623 -491
  479. package/src/store/test/selectors.js +1820 -1306
  480. package/src/style.scss +4 -7
  481. package/src/utils/sorting.js +54 -0
  482. package/src/utils/test/sorting.js +49 -0
  483. package/tsconfig.tsbuildinfo +1 -1
  484. package/build/components/block-preview/live.js +0 -30
  485. package/build/components/block-preview/live.js.map +0 -1
  486. package/build-module/components/block-preview/live.js +0 -20
  487. package/build-module/components/block-preview/live.js.map +0 -1
  488. package/src/components/block-preview/live.js +0 -19
@@ -1,18 +1,21 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { act, fireEvent, render, screen, within } from '@testing-library/react';
4
+ import {
5
+ fireEvent,
6
+ render,
7
+ screen,
8
+ waitFor,
9
+ within,
10
+ } from '@testing-library/react';
5
11
  import userEvent from '@testing-library/user-event';
6
12
 
7
13
  /**
8
14
  * WordPress dependencies
9
15
  */
10
16
  import { useState } from '@wordpress/element';
11
-
12
- /**
13
- * WordPress dependencies
14
- */
15
17
  import { useSelect } from '@wordpress/data';
18
+
16
19
  /**
17
20
  * Internal dependencies
18
21
  */
@@ -23,14 +26,6 @@ import {
23
26
  uniqueId,
24
27
  } from './fixtures';
25
28
 
26
- // Mock debounce() so that it runs instantly.
27
- jest.mock( '@wordpress/compose/src/utils/debounce', () => ( {
28
- debounce: ( fn ) => {
29
- fn.cancel = jest.fn();
30
- return fn;
31
- },
32
- } ) );
33
-
34
29
  const mockFetchSearchSuggestions = jest.fn();
35
30
 
36
31
  /**
@@ -58,18 +53,6 @@ jest.mock( '@wordpress/data/src/components/use-dispatch', () => ( {
58
53
 
59
54
  jest.useRealTimers();
60
55
 
61
- /**
62
- * Wait for next tick of event loop. This is required
63
- * because the `fetchSearchSuggestions` Promise will
64
- * resolve on the next tick of the event loop (this is
65
- * inline with the Promise spec). As a result we need to
66
- * wait on this loop to "tick" before we can expect the UI
67
- * to have updated.
68
- */
69
- function eventLoopTick() {
70
- return new Promise( ( resolve ) => setImmediate( resolve ) );
71
- }
72
-
73
56
  beforeEach( () => {
74
57
  // Setup a DOM element as a render target.
75
58
  mockFetchSearchSuggestions.mockImplementation( fetchFauxEntitySuggestions );
@@ -186,8 +169,7 @@ describe( 'Basic rendering', () => {
186
169
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
187
170
 
188
171
  // Simulate searching for a term.
189
- searchInput.focus();
190
- await user.keyboard( searchTerm );
172
+ await user.type( searchInput, searchTerm );
191
173
 
192
174
  expect( screen.queryByText( '://' ) ).not.toBeInTheDocument();
193
175
  } );
@@ -289,6 +271,7 @@ describe( 'Basic rendering', () => {
289
271
  it( 'should show "Unlink" button if a onRemove handler is provided', async () => {
290
272
  const user = userEvent.setup();
291
273
  const mockOnRemove = jest.fn();
274
+
292
275
  render(
293
276
  <LinkControl
294
277
  value={ { url: 'https://example.com' } }
@@ -314,13 +297,12 @@ describe( 'Searching for a link', () => {
314
297
  const searchTerm = 'Hello';
315
298
 
316
299
  let resolver;
317
-
318
- const fauxRequest = () =>
319
- new Promise( ( resolve ) => {
320
- resolver = resolve;
321
- } );
322
-
323
- mockFetchSearchSuggestions.mockImplementation( fauxRequest );
300
+ mockFetchSearchSuggestions.mockImplementation(
301
+ () =>
302
+ new Promise( ( resolve ) => {
303
+ resolver = resolve;
304
+ } )
305
+ );
324
306
 
325
307
  render( <LinkControl /> );
326
308
 
@@ -328,35 +310,22 @@ describe( 'Searching for a link', () => {
328
310
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
329
311
 
330
312
  // Simulate searching for a term.
331
- searchInput.focus();
332
- await user.keyboard( searchTerm );
313
+ await user.type( searchInput, searchTerm );
333
314
 
334
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
335
- await eventLoopTick();
315
+ expect( await screen.findByRole( 'presentation' ) ).toBeVisible();
316
+ expect( screen.queryByRole( 'listbox' ) ).not.toBeInTheDocument();
336
317
 
337
- const searchResultsField = screen.queryByRole( 'listbox' );
338
-
339
- let loadingUI = screen.queryByRole( 'presentation' );
340
-
341
- expect( searchResultsField ).not.toBeInTheDocument();
342
-
343
- expect( loadingUI ).toBeVisible();
318
+ // make the search suggestions fetch return a response
319
+ resolver( fauxEntitySuggestions );
344
320
 
345
- act( () => {
346
- resolver( fauxEntitySuggestions );
347
- } );
348
-
349
- await eventLoopTick();
350
-
351
- loadingUI = screen.queryByRole( 'presentation' );
352
-
353
- expect( loadingUI ).not.toBeInTheDocument();
321
+ expect( await screen.findByRole( 'listbox' ) ).toBeVisible();
322
+ expect( screen.queryByRole( 'presentation' ) ).not.toBeInTheDocument();
354
323
  } );
355
324
 
356
325
  it( 'should display only search suggestions when current input value is not URL-like', async () => {
357
326
  const user = userEvent.setup();
358
327
  const searchTerm = 'Hello world';
359
- const firstFauxSuggestion = fauxEntitySuggestions[ 0 ];
328
+ const firstSuggestion = fauxEntitySuggestions[ 0 ];
360
329
 
361
330
  render( <LinkControl /> );
362
331
 
@@ -364,14 +333,10 @@ describe( 'Searching for a link', () => {
364
333
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
365
334
 
366
335
  // Simulate searching for a term.
367
- searchInput.focus();
368
- await user.keyboard( searchTerm );
369
-
370
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
371
- await eventLoopTick();
336
+ await user.type( searchInput, searchTerm );
372
337
 
373
338
  const searchResultElements = within(
374
- screen.getByRole( 'listbox', {
339
+ await screen.findByRole( 'listbox', {
375
340
  name: /Search results for.*/,
376
341
  } )
377
342
  ).getAllByRole( 'option' );
@@ -382,12 +347,12 @@ describe( 'Searching for a link', () => {
382
347
 
383
348
  expect( searchInput ).toHaveAttribute( 'aria-expanded', 'true' );
384
349
 
385
- // Sanity check that a search suggestion shows up corresponding to the data.
350
+ // Check that a search suggestion shows up corresponding to the data.
386
351
  expect( searchResultElements[ 0 ] ).toHaveTextContent(
387
- firstFauxSuggestion.title
352
+ firstSuggestion.title
388
353
  );
389
354
  expect( searchResultElements[ 0 ] ).toHaveTextContent(
390
- firstFauxSuggestion.type
355
+ firstSuggestion.type
391
356
  );
392
357
 
393
358
  // The fallback URL suggestion should not be shown when input is not URL-like.
@@ -400,26 +365,19 @@ describe( 'Searching for a link', () => {
400
365
  const user = userEvent.setup();
401
366
  const searchTerm = ' Hello ';
402
367
 
403
- const { container } = render( <LinkControl /> );
368
+ render( <LinkControl /> );
404
369
 
405
370
  // Search Input UI.
406
371
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
407
372
 
408
373
  // Simulate searching for a term.
409
- searchInput.focus();
410
- await user.keyboard( searchTerm );
411
-
412
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
413
- await eventLoopTick();
374
+ await user.type( searchInput, searchTerm );
414
375
 
376
+ const searchResults = await screen.findByRole( 'listbox', {
377
+ name: /Search results for.*/,
378
+ } );
415
379
  const searchResultTextHighlightElements = Array.from(
416
- container.querySelectorAll(
417
- '[role="listbox"] button[role="option"] mark'
418
- )
419
- );
420
-
421
- const invalidResults = searchResultTextHighlightElements.find(
422
- ( mark ) => mark.innerHTML !== 'Hello'
380
+ searchResults.querySelectorAll( 'button[role="option"] mark' )
423
381
  );
424
382
 
425
383
  // Given we're mocking out the results we should always have 4 mark elements.
@@ -427,7 +385,11 @@ describe( 'Searching for a link', () => {
427
385
 
428
386
  // Make sure there are no `mark` elements which contain anything other
429
387
  // than the trimmed search term (ie: no whitespace).
430
- expect( invalidResults ).toBeFalsy();
388
+ expect(
389
+ searchResultTextHighlightElements.every(
390
+ ( mark ) => mark.innerHTML === 'Hello'
391
+ )
392
+ ).toBe( true );
431
393
 
432
394
  // Implementation detail test to ensure that the fetch handler is called
433
395
  // with the trimmed search value. We do this because we are mocking out
@@ -447,14 +409,10 @@ describe( 'Searching for a link', () => {
447
409
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
448
410
 
449
411
  // Simulate searching for a term.
450
- searchInput.focus();
451
- await user.keyboard( 'anything' );
412
+ await user.type( searchInput, 'anything' );
452
413
 
453
414
  const searchResultsField = screen.queryByRole( 'listbox' );
454
415
 
455
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
456
- await eventLoopTick();
457
-
458
416
  expect( searchResultsField ).not.toBeInTheDocument();
459
417
  expect( mockFetchSearchSuggestions ).not.toHaveBeenCalled();
460
418
  } );
@@ -472,14 +430,10 @@ describe( 'Searching for a link', () => {
472
430
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
473
431
 
474
432
  // Simulate searching for a term.
475
- searchInput.focus();
476
- await user.keyboard( searchTerm );
477
-
478
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
479
- await eventLoopTick();
433
+ await user.type( searchInput, searchTerm );
480
434
 
481
435
  const searchResultElements = within(
482
- screen.getByRole( 'listbox', {
436
+ await screen.findByRole( 'listbox', {
483
437
  name: /Search results for.*/,
484
438
  } )
485
439
  ).getAllByRole( 'option' );
@@ -510,14 +464,10 @@ describe( 'Searching for a link', () => {
510
464
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
511
465
 
512
466
  // Simulate searching for a term.
513
- searchInput.focus();
514
- await user.keyboard( 'couldbeurlorentitysearchterm' );
515
-
516
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
517
- await eventLoopTick();
467
+ await user.type( searchInput, 'couldbeurlorentitysearchterm' );
518
468
 
519
469
  const searchResultElements = within(
520
- screen.getByRole( 'listbox', {
470
+ await screen.findByRole( 'listbox', {
521
471
  name: /Search results for.*/,
522
472
  } )
523
473
  ).getAllByRole( 'option' );
@@ -544,14 +494,10 @@ describe( 'Manual link entry', () => {
544
494
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
545
495
 
546
496
  // Simulate searching for a term.
547
- searchInput.focus();
548
- await user.keyboard( searchTerm );
549
-
550
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
551
- await eventLoopTick();
497
+ await user.type( searchInput, searchTerm );
552
498
 
553
499
  const searchResultElements = within(
554
- screen.getByRole( 'listbox', {
500
+ await screen.findByRole( 'listbox', {
555
501
  name: /Search results for.*/,
556
502
  } )
557
503
  ).getByRole( 'option' );
@@ -584,29 +530,25 @@ describe( 'Manual link entry', () => {
584
530
  name: 'URL',
585
531
  } );
586
532
 
587
- let submitButton = screen.queryByRole( 'button', {
533
+ let submitButton = screen.getByRole( 'button', {
588
534
  name: 'Submit',
589
535
  } );
590
536
 
591
537
  expect( submitButton ).toBeDisabled();
592
538
  expect( submitButton ).toBeVisible();
593
539
 
594
- searchInput.focus();
595
540
  if ( searchString.length ) {
596
541
  // Simulate searching for a term.
597
- await user.keyboard( searchString );
542
+ await user.type( searchInput, searchString );
598
543
  } else {
599
544
  // Simulate clearing the search term.
600
- await userEvent.clear( searchInput );
545
+ await user.clear( searchInput );
601
546
  }
602
547
 
603
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
604
- await eventLoopTick();
605
-
606
548
  // Attempt to submit the empty search value in the input.
607
549
  await user.keyboard( '[Enter]' );
608
550
 
609
- submitButton = screen.queryByRole( 'button', {
551
+ submitButton = screen.getByRole( 'button', {
610
552
  name: 'Submit',
611
553
  } );
612
554
 
@@ -637,18 +579,14 @@ describe( 'Manual link entry', () => {
637
579
  expect( submitButton ).toBeVisible();
638
580
 
639
581
  // Simulate searching for a term.
640
- searchInput.focus();
641
582
  if ( searchString.length ) {
642
583
  // Simulate searching for a term.
643
- await user.keyboard( searchString );
584
+ await user.type( searchInput, searchString );
644
585
  } else {
645
586
  // Simulate clearing the search term.
646
- await userEvent.clear( searchInput );
587
+ await user.clear( searchInput );
647
588
  }
648
589
 
649
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
650
- await eventLoopTick();
651
-
652
590
  // Attempt to submit the empty search value in the input.
653
591
  await user.click( submitButton );
654
592
 
@@ -681,14 +619,10 @@ describe( 'Manual link entry', () => {
681
619
  } );
682
620
 
683
621
  // Simulate searching for a term.
684
- searchInput.focus();
685
- await user.keyboard( searchTerm );
686
-
687
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
688
- await eventLoopTick();
622
+ await user.type( searchInput, searchTerm );
689
623
 
690
624
  const searchResultElements = within(
691
- screen.getByRole( 'listbox', {
625
+ await screen.findByRole( 'listbox', {
692
626
  name: /Search results for.*/,
693
627
  } )
694
628
  ).getByRole( 'option' );
@@ -706,14 +640,10 @@ describe( 'Manual link entry', () => {
706
640
 
707
641
  describe( 'Default search suggestions', () => {
708
642
  it( 'should display a list of initial search suggestions when there is no search value or suggestions', async () => {
709
- const expectedResultsLength = 3; // Set within `LinkControl`.
710
-
711
643
  render( <LinkControl showInitialSuggestions /> );
712
644
 
713
- await eventLoopTick();
714
-
715
645
  expect(
716
- screen.queryByRole( 'listbox', {
646
+ await screen.findByRole( 'listbox', {
717
647
  name: 'Recently updated',
718
648
  } )
719
649
  ).toBeVisible();
@@ -731,24 +661,16 @@ describe( 'Default search suggestions', () => {
731
661
  expect( mockFetchSearchSuggestions ).toHaveBeenCalledTimes( 1 );
732
662
 
733
663
  // Verify the search results already display the initial suggestions.
734
- expect( screen.queryAllByRole( 'option' ) ).toHaveLength(
735
- expectedResultsLength
736
- );
664
+ // `LinkControl` internally always limits the number of initial suggestions to 3.
665
+ expect( screen.queryAllByRole( 'option' ) ).toHaveLength( 3 );
737
666
  } );
738
667
 
739
668
  it( 'should not display initial suggestions when input value is present', async () => {
740
669
  const user = userEvent.setup();
741
670
 
742
- // Render with an initial value an ensure that no initial suggestions
743
- // are shown.
744
- render(
745
- <LinkControl
746
- showInitialSuggestions
747
- value={ fauxEntitySuggestions[ 0 ] }
748
- />
749
- );
750
-
751
- await eventLoopTick();
671
+ // Render with an initial value an ensure that no initial suggestions are shown.
672
+ const initialValue = fauxEntitySuggestions[ 0 ];
673
+ render( <LinkControl showInitialSuggestions value={ initialValue } /> );
752
674
 
753
675
  expect( mockFetchSearchSuggestions ).not.toHaveBeenCalled();
754
676
 
@@ -758,23 +680,21 @@ describe( 'Default search suggestions', () => {
758
680
  const currentLinkBtn = within( currentLinkUI ).getByRole( 'button', {
759
681
  name: 'Edit',
760
682
  } );
761
-
762
683
  await user.click( currentLinkBtn );
763
684
 
764
685
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
765
- searchInput.focus();
686
+ // Search input is set to the URL value.
687
+ expect( searchInput ).toHaveValue( initialValue.url );
766
688
 
767
- await eventLoopTick();
689
+ // Focus the search input to display suggestions
690
+ await user.click( searchInput );
768
691
 
769
692
  const searchResultElements = within(
770
- screen.getByRole( 'listbox', {
693
+ await screen.findByRole( 'listbox', {
771
694
  name: /Search results for.*/,
772
695
  } )
773
696
  ).getAllByRole( 'option' );
774
697
 
775
- // Search input is set to the URL value.
776
- expect( searchInput ).toHaveValue( fauxEntitySuggestions[ 0 ].url );
777
-
778
698
  // It should match any url that's like ?p= and also include a URL option.
779
699
  expect( searchResultElements ).toHaveLength( 5 );
780
700
 
@@ -789,63 +709,45 @@ describe( 'Default search suggestions', () => {
789
709
 
790
710
  render( <LinkControl showInitialSuggestions /> );
791
711
 
792
- let searchResultElements;
793
- let searchInput;
794
-
795
712
  // Search Input UI.
796
- searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
713
+ const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
797
714
 
798
715
  // Simulate searching for a term.
799
- searchInput.focus();
800
- await user.keyboard( searchTerm );
801
-
802
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
803
- await eventLoopTick();
716
+ await user.type( searchInput, searchTerm );
804
717
 
805
718
  expect( searchInput ).toHaveValue( searchTerm );
806
719
 
807
- searchResultElements = within(
808
- screen.getByRole( 'listbox', {
809
- name: /Search results for.*/,
810
- } )
811
- ).getAllByRole( 'option' );
812
-
813
- // Delete the text.
814
- await userEvent.clear( searchInput );
720
+ const searchResultsList = await screen.findByRole( 'listbox', {
721
+ name: /Search results for.*/,
722
+ } );
815
723
 
816
- await eventLoopTick();
724
+ expect( searchResultsList ).toBeVisible();
817
725
 
818
- searchResultElements = within(
819
- screen.getByRole( 'listbox', {
820
- name: 'Recently updated',
821
- } )
822
- ).getAllByRole( 'option' );
726
+ expect(
727
+ within( searchResultsList ).getAllByRole( 'option' )
728
+ ).toHaveLength( 4 );
823
729
 
824
- searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
730
+ // Delete the text.
731
+ await userEvent.clear( searchInput );
825
732
 
826
733
  // Check the input is empty now.
827
734
  expect( searchInput ).toHaveValue( '' );
828
735
 
829
- expect(
830
- screen.queryByRole( 'listbox', {
831
- name: 'Recently updated',
832
- } )
833
- ).toBeVisible();
736
+ const initialResultsList = await screen.findByRole( 'listbox', {
737
+ name: 'Recently updated',
738
+ } );
834
739
 
835
- expect( searchResultElements ).toHaveLength( 3 );
740
+ expect(
741
+ within( initialResultsList ).getAllByRole( 'option' )
742
+ ).toHaveLength( 3 );
836
743
  } );
837
744
 
838
745
  it( 'should not display initial suggestions when there are no recently updated pages/posts', async () => {
839
- const noResults = [];
840
746
  // Force API returning empty results for recently updated Pages.
841
- mockFetchSearchSuggestions.mockImplementation( () =>
842
- Promise.resolve( noResults )
843
- );
747
+ mockFetchSearchSuggestions.mockImplementation( async () => [] );
844
748
 
845
749
  render( <LinkControl showInitialSuggestions /> );
846
750
 
847
- await eventLoopTick();
848
-
849
751
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
850
752
 
851
753
  const searchResultsField = screen.queryByRole( 'listbox', {
@@ -876,19 +778,15 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
876
778
  async ( entityNameText ) => {
877
779
  const user = userEvent.setup();
878
780
  let resolver;
879
- let resolvedEntity;
880
-
881
781
  const createSuggestion = ( title ) =>
882
782
  new Promise( ( resolve ) => {
883
- resolver = ( arg ) => {
884
- resolve( arg );
885
- };
886
- resolvedEntity = {
887
- title,
888
- id: 123,
889
- url: '/?p=123',
890
- type: 'page',
891
- };
783
+ resolver = () =>
784
+ resolve( {
785
+ title,
786
+ id: 123,
787
+ url: '/?p=123',
788
+ type: 'page',
789
+ } );
892
790
  } );
893
791
 
894
792
  const LinkControlConsumer = () => {
@@ -911,16 +809,15 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
911
809
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
912
810
 
913
811
  // Simulate searching for a term.
914
- searchInput.focus();
915
- await user.keyboard( entityNameText );
916
-
917
- await eventLoopTick();
812
+ await user.type( searchInput, entityNameText );
918
813
 
919
- const searchResultElements = screen.queryAllByRole( 'option' );
814
+ const searchResults = await screen.findByRole( 'listbox', {
815
+ name: /Search results for.*/,
816
+ } );
920
817
 
921
- const createButton = Array.from( searchResultElements ).filter(
922
- ( result ) => result.innerHTML.includes( 'Create:' )
923
- )[ 0 ];
818
+ const createButton = within( searchResults ).getByRole( 'option', {
819
+ name: /^Create:/,
820
+ } );
924
821
 
925
822
  expect( createButton ).toBeVisible();
926
823
  expect( createButton ).toHaveTextContent( entityNameText );
@@ -929,8 +826,6 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
929
826
  // resolution manually via the `resolver` reference.
930
827
  await user.click( createButton );
931
828
 
932
- await eventLoopTick();
933
-
934
829
  // Check for loading indicator.
935
830
  const loadingIndicator = screen.getByText( 'Creating…' );
936
831
  const currentLinkLabel =
@@ -943,13 +838,11 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
943
838
  );
944
839
 
945
840
  // Resolve the `createSuggestion` promise.
946
- await act( async () => {
947
- resolver( resolvedEntity );
948
- } );
949
-
950
- await eventLoopTick();
841
+ resolver();
951
842
 
952
- const currentLink = screen.getByLabelText( 'Currently selected' );
843
+ const currentLink = await screen.findByLabelText(
844
+ 'Currently selected'
845
+ );
953
846
 
954
847
  expect( currentLink ).toHaveTextContent( entityNameText );
955
848
  expect( currentLink ).toHaveTextContent( '/?p=123' );
@@ -983,25 +876,18 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
983
876
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
984
877
 
985
878
  // Simulate searching for a term.
986
- searchInput.focus();
987
- await user.keyboard( 'Some new page to create' );
988
-
989
- await eventLoopTick();
879
+ await user.type( searchInput, 'Some new page to create' );
990
880
 
991
- const searchResultElements = within(
992
- screen.getByRole( 'listbox', {
993
- name: /Search results for.*/,
994
- } )
995
- ).getAllByRole( 'option' );
881
+ const searchResults = await screen.findByRole( 'listbox', {
882
+ name: /Search results for.*/,
883
+ } );
996
884
 
997
- const createButton = Array.from( searchResultElements ).filter(
998
- ( result ) => result.innerHTML.includes( 'Create:' )
999
- )[ 0 ];
885
+ const createButton = within( searchResults ).getByRole( 'option', {
886
+ name: /^Create:/,
887
+ } );
1000
888
 
1001
889
  await user.click( createButton );
1002
890
 
1003
- await eventLoopTick();
1004
-
1005
891
  const currentLink = screen.getByLabelText( 'Currently selected' );
1006
892
 
1007
893
  expect( currentLink ).toHaveTextContent( 'Some new page to create' );
@@ -1039,33 +925,27 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1039
925
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1040
926
 
1041
927
  // Simulate searching for a term.
1042
- searchInput.focus();
1043
- await user.keyboard( entityNameText );
928
+ await user.type( searchInput, entityNameText );
1044
929
 
1045
- await eventLoopTick();
1046
-
1047
- const searchResultElements = within(
1048
- screen.getByRole( 'listbox', {
1049
- name: /Search results for.*/,
1050
- } )
1051
- ).getAllByRole( 'option' );
1052
- const createButton = Array.from( searchResultElements ).filter(
1053
- ( result ) => result.innerHTML.includes( 'Create:' )
1054
- )[ 0 ];
930
+ const searchResults = await screen.findByRole( 'listbox', {
931
+ name: /Search results for.*/,
932
+ } );
1055
933
 
1056
- // Step down into the search results, highlighting the first result item.
934
+ // Step down into the search results, selecting the first result item.
1057
935
  triggerArrowDown( searchInput );
1058
936
 
1059
- createButton.focus();
1060
- await user.keyboard( '[Enter]' );
1061
-
1062
- searchInput.focus();
1063
- await user.keyboard( '[Enter]' );
937
+ // Check that the create button is in the results and that it's selected
938
+ const createButton = within( searchResults ).getByRole( 'option', {
939
+ name: /^Create:/,
940
+ selected: true,
941
+ } );
942
+ expect( createButton ).toBeVisible();
1064
943
 
1065
- await eventLoopTick();
944
+ expect( searchInput ).toHaveFocus();
945
+ triggerEnter( searchInput );
1066
946
 
1067
947
  expect(
1068
- screen.getByLabelText( 'Currently selected' )
948
+ await screen.findByLabelText( 'Currently selected' )
1069
949
  ).toHaveTextContent( entityNameText );
1070
950
  } );
1071
951
 
@@ -1088,20 +968,15 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1088
968
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1089
969
 
1090
970
  // Simulate searching for a term.
1091
- searchInput.focus();
1092
- await user.keyboard( entityNameText );
971
+ await user.type( searchInput, entityNameText );
1093
972
 
1094
- await eventLoopTick();
1095
-
1096
- const searchResultElements = within(
1097
- screen.getByRole( 'listbox', {
1098
- name: /Search results for.*/,
1099
- } )
1100
- ).getAllByRole( 'option' );
973
+ const searchResults = await screen.findByRole( 'listbox', {
974
+ name: /Search results for.*/,
975
+ } );
1101
976
 
1102
- const createButton = Array.from( searchResultElements ).filter(
1103
- ( result ) => result.innerHTML.includes( 'Custom suggestion text' )
1104
- )[ 0 ];
977
+ const createButton = within( searchResults ).getByRole( 'option', {
978
+ name: /Custom suggestion text/,
979
+ } );
1105
980
 
1106
981
  expect( createButton ).toBeVisible();
1107
982
  } );
@@ -1112,9 +987,6 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1112
987
  async ( handler ) => {
1113
988
  render( <LinkControl createSuggestion={ handler } /> );
1114
989
 
1115
- // Await the initial suggestions to be fetched.
1116
- await eventLoopTick();
1117
-
1118
990
  // Search Input UI.
1119
991
  const searchInput = screen.getByRole( 'combobox', {
1120
992
  name: 'URL',
@@ -1128,17 +1000,14 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1128
1000
  }
1129
1001
  );
1130
1002
 
1131
- it( 'should not show not show an option to create an entity when input is empty', async () => {
1003
+ it( 'should not show an option to create an entity when input is empty', async () => {
1132
1004
  render(
1133
1005
  <LinkControl
1134
- showInitialSuggestions={ true } // Should show even if we're not showing initial suggestions.
1006
+ showInitialSuggestions // Should show even if we're not showing initial suggestions.
1135
1007
  createSuggestion={ jest.fn() }
1136
1008
  />
1137
1009
  );
1138
1010
 
1139
- // Await the initial suggestions to be fetched.
1140
- await eventLoopTick();
1141
-
1142
1011
  // Search Input UI.
1143
1012
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1144
1013
 
@@ -1167,22 +1036,17 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1167
1036
  } );
1168
1037
 
1169
1038
  // Simulate searching for a term.
1170
- searchInput.focus();
1171
- await user.keyboard( inputText );
1172
-
1173
- await eventLoopTick();
1174
-
1175
- const searchResultElements = within(
1176
- screen.getByRole( 'listbox', {
1177
- name: /Search results for.*/,
1178
- } )
1179
- ).getAllByRole( 'option' );
1039
+ await user.type( searchInput, inputText );
1180
1040
 
1181
- const createButton = Array.from( searchResultElements ).filter(
1182
- ( result ) => result.innerHTML.includes( 'New page' )
1183
- )[ 0 ];
1041
+ const searchResults = await screen.findByRole( 'listbox', {
1042
+ name: /Search results for.*/,
1043
+ } );
1184
1044
 
1185
- expect( createButton ).toBeFalsy(); // Shouldn't exist!
1045
+ const createButton = within( searchResults ).queryByRole(
1046
+ 'option',
1047
+ { name: /New page/ }
1048
+ );
1049
+ expect( createButton ).not.toBeInTheDocument(); // Shouldn't exist!
1186
1050
  }
1187
1051
  );
1188
1052
  } );
@@ -1205,24 +1069,18 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1205
1069
  searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1206
1070
 
1207
1071
  // Simulate searching for a term.
1208
- searchInput.focus();
1209
- await user.keyboard( searchText );
1072
+ await user.type( searchInput, searchText );
1210
1073
 
1211
- await eventLoopTick();
1074
+ const searchResults = await screen.findByRole( 'listbox', {
1075
+ name: /Search results for.*/,
1076
+ } );
1212
1077
 
1213
- const searchResultElements = within(
1214
- screen.getByRole( 'listbox', {
1215
- name: /Search results for.*/,
1216
- } )
1217
- ).getAllByRole( 'option' );
1218
- const createButton = Array.from( searchResultElements ).filter(
1219
- ( result ) => result.innerHTML.includes( 'Create:' )
1220
- )[ 0 ];
1078
+ const createButton = within( searchResults ).getByRole( 'option', {
1079
+ name: /^Create:/,
1080
+ } );
1221
1081
 
1222
1082
  await user.click( createButton );
1223
1083
 
1224
- await eventLoopTick();
1225
-
1226
1084
  searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1227
1085
 
1228
1086
  const errorNotice = screen.getAllByText(
@@ -1340,14 +1198,10 @@ describe( 'Selecting links', () => {
1340
1198
  } );
1341
1199
 
1342
1200
  // Simulate searching for a term.
1343
- searchInput.focus();
1344
- await user.keyboard( searchTerm );
1345
-
1346
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
1347
- await eventLoopTick();
1201
+ await user.type( searchInput, searchTerm );
1348
1202
 
1349
1203
  const searchResultElements = within(
1350
- screen.getByRole( 'listbox', {
1204
+ await screen.findByRole( 'listbox', {
1351
1205
  name: /Search results for.*/,
1352
1206
  } )
1353
1207
  ).getAllByRole( 'option' );
@@ -1406,20 +1260,17 @@ describe( 'Selecting links', () => {
1406
1260
  } );
1407
1261
 
1408
1262
  // Simulate searching for a term.
1409
- searchInput.focus();
1410
- await user.keyboard( searchTerm );
1263
+ await user.type( searchInput, searchTerm );
1411
1264
 
1412
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
1413
- await eventLoopTick();
1265
+ const searchResults = await screen.findByRole( 'listbox', {
1266
+ name: /Search results for.*/,
1267
+ } );
1414
1268
 
1415
1269
  // Step down into the search results, highlighting the first result item.
1416
1270
  triggerArrowDown( searchInput );
1417
1271
 
1418
- const searchResultElements = within(
1419
- screen.getByRole( 'listbox', {
1420
- name: /Search results for.*/,
1421
- } )
1422
- ).getAllByRole( 'option' );
1272
+ const searchResultElements =
1273
+ within( searchResults ).getAllByRole( 'option' );
1423
1274
 
1424
1275
  const firstSearchSuggestion = searchResultElements[ 0 ];
1425
1276
  const secondSearchSuggestion = searchResultElements[ 1 ];
@@ -1429,7 +1280,7 @@ describe( 'Selecting links', () => {
1429
1280
  } );
1430
1281
 
1431
1282
  // We should have highlighted the first item using the keyboard.
1432
- expect( selectedSearchResultElement ).toEqual(
1283
+ expect( selectedSearchResultElement ).toBe(
1433
1284
  firstSearchSuggestion
1434
1285
  );
1435
1286
 
@@ -1444,7 +1295,7 @@ describe( 'Selecting links', () => {
1444
1295
 
1445
1296
  // We should have highlighted the first item using the keyboard
1446
1297
  // eslint-disable-next-line jest/no-conditional-expect
1447
- expect( selectedSearchResultElement ).toEqual(
1298
+ expect( selectedSearchResultElement ).toBe(
1448
1299
  secondSearchSuggestion
1449
1300
  );
1450
1301
 
@@ -1457,7 +1308,7 @@ describe( 'Selecting links', () => {
1457
1308
 
1458
1309
  // We should be back to highlighting the first search result again
1459
1310
  // eslint-disable-next-line jest/no-conditional-expect
1460
- expect( selectedSearchResultElement ).toEqual(
1311
+ expect( selectedSearchResultElement ).toBe(
1461
1312
  firstSearchSuggestion
1462
1313
  );
1463
1314
  }
@@ -1486,10 +1337,8 @@ describe( 'Selecting links', () => {
1486
1337
  it( 'should allow selection of initial search results via the keyboard', async () => {
1487
1338
  render( <LinkControl showInitialSuggestions /> );
1488
1339
 
1489
- await eventLoopTick();
1490
-
1491
1340
  expect(
1492
- screen.queryByRole( 'listbox', {
1341
+ await screen.findByRole( 'listbox', {
1493
1342
  name: 'Recently updated',
1494
1343
  } )
1495
1344
  ).toBeVisible();
@@ -1500,8 +1349,6 @@ describe( 'Selecting links', () => {
1500
1349
  // Step down into the search results, highlighting the first result item.
1501
1350
  triggerArrowDown( searchInput );
1502
1351
 
1503
- await eventLoopTick();
1504
-
1505
1352
  const searchResultElements = within(
1506
1353
  screen.getByRole( 'listbox', {
1507
1354
  name: 'Recently updated',
@@ -1626,14 +1473,10 @@ describe( 'Post types', () => {
1626
1473
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1627
1474
 
1628
1475
  // Simulate searching for a term.
1629
- searchInput.focus();
1630
- await user.keyboard( searchTerm );
1631
-
1632
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
1633
- await eventLoopTick();
1476
+ await user.type( searchInput, searchTerm );
1634
1477
 
1635
1478
  const searchResultElements = within(
1636
- screen.getByRole( 'listbox', {
1479
+ await screen.findByRole( 'listbox', {
1637
1480
  name: /Search results for.*/,
1638
1481
  } )
1639
1482
  ).getAllByRole( 'option' );
@@ -1657,14 +1500,10 @@ describe( 'Post types', () => {
1657
1500
  const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1658
1501
 
1659
1502
  // Simulate searching for a term.
1660
- searchInput.focus();
1661
- await user.keyboard( searchTerm );
1662
-
1663
- // fetchFauxEntitySuggestions resolves on next "tick" of event loop.
1664
- await eventLoopTick();
1503
+ await user.type( searchInput, searchTerm );
1665
1504
 
1666
1505
  const searchResultElements = within(
1667
- screen.getByRole( 'listbox', {
1506
+ await screen.findByRole( 'listbox', {
1668
1507
  name: /Search results for.*/,
1669
1508
  } )
1670
1509
  ).getAllByRole( 'option' );
@@ -1712,11 +1551,6 @@ describe( 'Rich link previews', () => {
1712
1551
 
1713
1552
  render( <LinkControl value={ selectedLink } /> );
1714
1553
 
1715
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1716
- await act( async () => {
1717
- await eventLoopTick();
1718
- } );
1719
-
1720
1554
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1721
1555
 
1722
1556
  const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
@@ -1738,16 +1572,9 @@ describe( 'Rich link previews', () => {
1738
1572
 
1739
1573
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1740
1574
 
1741
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1742
- await act( async () => {
1743
- await eventLoopTick();
1744
- } );
1745
-
1746
1575
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1747
1576
 
1748
- const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
1749
-
1750
- expect( isRichLinkPreview ).toBe( true );
1577
+ await waitFor( () => expect( linkPreview ).toHaveClass( 'is-rich' ) );
1751
1578
  } );
1752
1579
 
1753
1580
  it( 'should not display placeholders for the image and description if neither is available in the data', async () => {
@@ -1762,13 +1589,10 @@ describe( 'Rich link previews', () => {
1762
1589
 
1763
1590
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1764
1591
 
1765
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1766
- await act( async () => {
1767
- await eventLoopTick();
1768
- } );
1769
-
1770
1592
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1771
1593
 
1594
+ await waitFor( () => expect( linkPreview ).toHaveClass( 'is-rich' ) );
1595
+
1772
1596
  // Todo: refactor to use user-facing queries.
1773
1597
  const hasRichImagePreview = linkPreview.querySelector(
1774
1598
  '.block-editor-link-control__search-item-image'
@@ -1795,15 +1619,9 @@ describe( 'Rich link previews', () => {
1795
1619
 
1796
1620
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1797
1621
 
1798
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1799
- await act( async () => {
1800
- await eventLoopTick();
1801
- } );
1802
-
1803
1622
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1804
1623
 
1805
- const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
1806
- expect( isRichLinkPreview ).toBe( true );
1624
+ await waitFor( () => expect( linkPreview ).toHaveClass( 'is-rich' ) );
1807
1625
 
1808
1626
  const titlePreview = screen.getByText( selectedLink.title );
1809
1627
 
@@ -1824,15 +1642,9 @@ describe( 'Rich link previews', () => {
1824
1642
 
1825
1643
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1826
1644
 
1827
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1828
- await act( async () => {
1829
- await eventLoopTick();
1830
- } );
1831
-
1832
1645
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1833
1646
 
1834
- const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
1835
- expect( isRichLinkPreview ).toBe( true );
1647
+ await waitFor( () => expect( linkPreview ).toHaveClass( 'is-rich' ) );
1836
1648
 
1837
1649
  const iconPreview = linkPreview.querySelector(
1838
1650
  `.block-editor-link-control__search-item-icon`
@@ -1862,16 +1674,11 @@ describe( 'Rich link previews', () => {
1862
1674
 
1863
1675
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1864
1676
 
1865
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1866
- await act( async () => {
1867
- await eventLoopTick();
1868
- } );
1869
-
1870
1677
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1871
1678
 
1872
- const isRichLinkPreview =
1873
- linkPreview.classList.contains( 'is-rich' );
1874
- expect( isRichLinkPreview ).toBe( true );
1679
+ await waitFor( () =>
1680
+ expect( linkPreview ).toHaveClass( 'is-rich' )
1681
+ );
1875
1682
 
1876
1683
  const missingDataItem = linkPreview.querySelector(
1877
1684
  `.block-editor-link-control__search-item-${ dataItem }`
@@ -1887,23 +1694,19 @@ describe( 'Rich link previews', () => {
1887
1694
  ] )(
1888
1695
  'should not display a rich preview when data is %s',
1889
1696
  async ( _descriptor, data ) => {
1890
- mockFetchRichUrlData.mockImplementation( () =>
1891
- Promise.resolve( data )
1892
- );
1697
+ mockFetchRichUrlData.mockImplementation( async () => data );
1893
1698
 
1894
1699
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1895
1700
 
1896
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1897
- await act( async () => {
1898
- await eventLoopTick();
1899
- } );
1900
-
1901
1701
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1902
1702
 
1903
- const isRichLinkPreview =
1904
- linkPreview.classList.contains( 'is-rich' );
1703
+ expect( linkPreview ).toHaveClass( 'is-fetching' );
1905
1704
 
1906
- expect( isRichLinkPreview ).toBe( false );
1705
+ await waitFor( () =>
1706
+ expect( linkPreview ).not.toHaveClass( 'is-fetching' )
1707
+ );
1708
+
1709
+ expect( linkPreview ).not.toHaveClass( 'is-rich' );
1907
1710
  }
1908
1711
  );
1909
1712
 
@@ -1914,19 +1717,10 @@ describe( 'Rich link previews', () => {
1914
1717
 
1915
1718
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1916
1719
 
1917
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1918
- await act( async () => {
1919
- await eventLoopTick();
1920
- } );
1921
-
1922
1720
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1923
1721
 
1924
- const isFetchingRichPreview =
1925
- linkPreview.classList.contains( 'is-fetching' );
1926
- const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
1927
-
1928
- expect( isFetchingRichPreview ).toBe( true );
1929
- expect( isRichLinkPreview ).toBe( false );
1722
+ expect( linkPreview ).toHaveClass( 'is-fetching' );
1723
+ expect( linkPreview ).not.toHaveClass( 'is-rich' );
1930
1724
  } );
1931
1725
 
1932
1726
  it( 'should remove fetching UI indicators and fallback to standard preview if request for rich preview results in an error', async () => {
@@ -1936,20 +1730,15 @@ describe( 'Rich link previews', () => {
1936
1730
 
1937
1731
  render( <LinkControl value={ selectedLink } hasRichPreviews /> );
1938
1732
 
1939
- // mockFetchRichUrlData resolves on next "tick" of event loop.
1940
- await act( async () => {
1941
- await eventLoopTick();
1942
- } );
1943
-
1944
1733
  const linkPreview = screen.getByLabelText( 'Currently selected' );
1945
1734
 
1946
- const isFetchingRichPreview =
1947
- linkPreview.classList.contains( 'is-fetching' );
1735
+ expect( linkPreview ).toHaveClass( 'is-fetching' );
1948
1736
 
1949
- const isRichLinkPreview = linkPreview.classList.contains( 'is-rich' );
1737
+ await waitFor( () =>
1738
+ expect( linkPreview ).not.toHaveClass( 'is-fetching' )
1739
+ );
1950
1740
 
1951
- expect( isFetchingRichPreview ).toBe( false );
1952
- expect( isRichLinkPreview ).toBe( false );
1741
+ expect( linkPreview ).not.toHaveClass( 'is-rich' );
1953
1742
  } );
1954
1743
 
1955
1744
  afterAll( () => {
@@ -2050,8 +1839,7 @@ describe( 'Controlling link title text', () => {
2050
1839
 
2051
1840
  const textInput = screen.queryByRole( 'textbox', { name: 'Text' } );
2052
1841
 
2053
- textInput.focus();
2054
- await userEvent.clear( textInput );
1842
+ await user.clear( textInput );
2055
1843
  await user.keyboard( textValue );
2056
1844
 
2057
1845
  expect( textInput ).toHaveValue( textValue );
@@ -2087,8 +1875,7 @@ describe( 'Controlling link title text', () => {
2087
1875
 
2088
1876
  expect( textInput ).toBeVisible();
2089
1877
 
2090
- textInput.focus();
2091
- await userEvent.clear( textInput );
1878
+ await user.clear( textInput );
2092
1879
  await user.keyboard( textValue );
2093
1880
 
2094
1881
  // Attempt to submit the empty search value in the input.