@wordpress/block-editor 12.4.0 → 12.5.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 (316) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +5 -0
  3. package/build/components/block-heading-level-dropdown/heading-level-icon.js +10 -2
  4. package/build/components/block-heading-level-dropdown/heading-level-icon.js.map +1 -1
  5. package/build/components/block-heading-level-dropdown/index.native.js +4 -3
  6. package/build/components/block-heading-level-dropdown/index.native.js.map +1 -1
  7. package/build/components/block-lock/toolbar.js +25 -6
  8. package/build/components/block-lock/toolbar.js.map +1 -1
  9. package/build/components/block-mobile-toolbar/block-actions-menu.native.js +3 -6
  10. package/build/components/block-mobile-toolbar/block-actions-menu.native.js.map +1 -1
  11. package/build/components/block-parent-selector/index.js +8 -5
  12. package/build/components/block-parent-selector/index.js.map +1 -1
  13. package/build/components/block-removal-warning-modal/index.js +18 -25
  14. package/build/components/block-removal-warning-modal/index.js.map +1 -1
  15. package/build/components/block-toolbar/index.js +8 -5
  16. package/build/components/block-toolbar/index.js.map +1 -1
  17. package/build/components/block-tools/block-contextual-toolbar.js +7 -11
  18. package/build/components/block-tools/block-contextual-toolbar.js.map +1 -1
  19. package/build/components/dimensions-tool/aspect-ratio-tool.js +99 -0
  20. package/build/components/dimensions-tool/aspect-ratio-tool.js.map +1 -0
  21. package/build/components/dimensions-tool/index.js +207 -0
  22. package/build/components/dimensions-tool/index.js.map +1 -0
  23. package/build/components/dimensions-tool/scale-tool.js +111 -0
  24. package/build/components/dimensions-tool/scale-tool.js.map +1 -0
  25. package/build/components/dimensions-tool/width-height-tool.js +125 -0
  26. package/build/components/dimensions-tool/width-height-tool.js.map +1 -0
  27. package/build/components/global-styles/color-panel.js +1 -1
  28. package/build/components/global-styles/color-panel.js.map +1 -1
  29. package/build/components/global-styles/filters-panel.js +1 -1
  30. package/build/components/global-styles/filters-panel.js.map +1 -1
  31. package/build/components/global-styles/hooks.js +2 -2
  32. package/build/components/global-styles/hooks.js.map +1 -1
  33. package/build/components/global-styles/typography-panel.js +34 -2
  34. package/build/components/global-styles/typography-panel.js.map +1 -1
  35. package/build/components/image-editor/aspect-ratio-dropdown.js +1 -1
  36. package/build/components/image-editor/aspect-ratio-dropdown.js.map +1 -1
  37. package/build/components/image-editor/use-save-image.js +1 -2
  38. package/build/components/image-editor/use-save-image.js.map +1 -1
  39. package/build/components/image-size-control/index.js +6 -0
  40. package/build/components/image-size-control/index.js.map +1 -1
  41. package/build/components/index.js +19 -1
  42. package/build/components/index.js.map +1 -1
  43. package/build/components/inserter/block-patterns-explorer/patterns-list.js +2 -2
  44. package/build/components/inserter/block-patterns-explorer/patterns-list.js.map +1 -1
  45. package/build/components/inserter/block-patterns-tab.js +7 -35
  46. package/build/components/inserter/block-patterns-tab.js.map +1 -1
  47. package/build/components/inserter/hooks/use-block-types-state.js +3 -4
  48. package/build/components/inserter/hooks/use-block-types-state.js.map +1 -1
  49. package/build/components/inserter/hooks/use-patterns-state.js +9 -3
  50. package/build/components/inserter/hooks/use-patterns-state.js.map +1 -1
  51. package/build/components/inserter/media-tab/hooks.js +2 -21
  52. package/build/components/inserter/media-tab/hooks.js.map +1 -1
  53. package/build/components/inserter/reusable-block-rename-hint.js +62 -0
  54. package/build/components/inserter/reusable-block-rename-hint.js.map +1 -0
  55. package/build/components/inserter/reusable-blocks-tab.js +6 -2
  56. package/build/components/inserter/reusable-blocks-tab.js.map +1 -1
  57. package/build/components/inserter/reusable-blocks-tab.native.js +2 -2
  58. package/build/components/inserter/reusable-blocks-tab.native.js.map +1 -1
  59. package/build/components/inserter/tabs.native.js +1 -1
  60. package/build/components/inserter/tabs.native.js.map +1 -1
  61. package/build/components/inserter-draggable-blocks/index.js +9 -1
  62. package/build/components/inserter-draggable-blocks/index.js.map +1 -1
  63. package/build/components/link-control/constants.js +1 -1
  64. package/build/components/link-control/constants.js.map +1 -1
  65. package/build/components/link-control/index.js +17 -15
  66. package/build/components/link-control/index.js.map +1 -1
  67. package/build/components/link-control/search-create-button.js +5 -21
  68. package/build/components/link-control/search-create-button.js.map +1 -1
  69. package/build/components/link-control/search-input.js +4 -4
  70. package/build/components/link-control/search-input.js.map +1 -1
  71. package/build/components/link-control/search-item.js +13 -30
  72. package/build/components/link-control/search-item.js.map +1 -1
  73. package/build/components/link-control/search-results.js +2 -2
  74. package/build/components/link-control/search-results.js.map +1 -1
  75. package/build/components/link-control/settings-drawer.js +2 -3
  76. package/build/components/link-control/settings-drawer.js.map +1 -1
  77. package/build/components/list-view/appender.js +2 -6
  78. package/build/components/list-view/appender.js.map +1 -1
  79. package/build/components/provider/index.js +5 -2
  80. package/build/components/provider/index.js.map +1 -1
  81. package/build/components/provider/use-block-sync.js +21 -0
  82. package/build/components/provider/use-block-sync.js.map +1 -1
  83. package/build/components/resolution-tool/index.js +55 -0
  84. package/build/components/resolution-tool/index.js.map +1 -0
  85. package/build/components/url-input/index.js +4 -2
  86. package/build/components/url-input/index.js.map +1 -1
  87. package/build/components/writing-flow/use-tab-nav.js +10 -27
  88. package/build/components/writing-flow/use-tab-nav.js.map +1 -1
  89. package/build/components/writing-mode-control/index.js +70 -0
  90. package/build/components/writing-mode-control/index.js.map +1 -0
  91. package/build/hooks/behaviors.js +25 -20
  92. package/build/hooks/behaviors.js.map +1 -1
  93. package/build/hooks/supports.js +7 -1
  94. package/build/hooks/supports.js.map +1 -1
  95. package/build/hooks/typography.js +2 -1
  96. package/build/hooks/typography.js.map +1 -1
  97. package/build/hooks/utils.js +4 -2
  98. package/build/hooks/utils.js.map +1 -1
  99. package/build/private-apis.js +10 -1
  100. package/build/private-apis.js.map +1 -1
  101. package/build/private-apis.native.js +3 -0
  102. package/build/private-apis.native.js.map +1 -1
  103. package/build/store/actions.js +195 -1
  104. package/build/store/actions.js.map +1 -1
  105. package/build/store/defaults.js +1 -0
  106. package/build/store/defaults.js.map +1 -1
  107. package/build/store/index.js +10 -1
  108. package/build/store/index.js.map +1 -1
  109. package/build/store/private-actions.js +46 -40
  110. package/build/store/private-actions.js.map +1 -1
  111. package/build/store/private-selectors.js +3 -3
  112. package/build/store/private-selectors.js.map +1 -1
  113. package/build/store/reducer.js +22 -8
  114. package/build/store/reducer.js.map +1 -1
  115. package/build/store/selectors.js +33 -15
  116. package/build/store/selectors.js.map +1 -1
  117. package/build-module/components/block-heading-level-dropdown/heading-level-icon.js +9 -2
  118. package/build-module/components/block-heading-level-dropdown/heading-level-icon.js.map +1 -1
  119. package/build-module/components/block-heading-level-dropdown/index.native.js +4 -3
  120. package/build-module/components/block-heading-level-dropdown/index.native.js.map +1 -1
  121. package/build-module/components/block-lock/toolbar.js +25 -7
  122. package/build-module/components/block-lock/toolbar.js.map +1 -1
  123. package/build-module/components/block-mobile-toolbar/block-actions-menu.native.js +4 -6
  124. package/build-module/components/block-mobile-toolbar/block-actions-menu.native.js.map +1 -1
  125. package/build-module/components/block-parent-selector/index.js +7 -5
  126. package/build-module/components/block-parent-selector/index.js.map +1 -1
  127. package/build-module/components/block-removal-warning-modal/index.js +20 -24
  128. package/build-module/components/block-removal-warning-modal/index.js.map +1 -1
  129. package/build-module/components/block-toolbar/index.js +8 -5
  130. package/build-module/components/block-toolbar/index.js.map +1 -1
  131. package/build-module/components/block-tools/block-contextual-toolbar.js +8 -11
  132. package/build-module/components/block-tools/block-contextual-toolbar.js.map +1 -1
  133. package/build-module/components/dimensions-tool/aspect-ratio-tool.js +87 -0
  134. package/build-module/components/dimensions-tool/aspect-ratio-tool.js.map +1 -0
  135. package/build-module/components/dimensions-tool/index.js +195 -0
  136. package/build-module/components/dimensions-tool/index.js.map +1 -0
  137. package/build-module/components/dimensions-tool/scale-tool.js +103 -0
  138. package/build-module/components/dimensions-tool/scale-tool.js.map +1 -0
  139. package/build-module/components/dimensions-tool/width-height-tool.js +122 -0
  140. package/build-module/components/dimensions-tool/width-height-tool.js.map +1 -0
  141. package/build-module/components/global-styles/color-panel.js +1 -1
  142. package/build-module/components/global-styles/color-panel.js.map +1 -1
  143. package/build-module/components/global-styles/filters-panel.js +2 -2
  144. package/build-module/components/global-styles/filters-panel.js.map +1 -1
  145. package/build-module/components/global-styles/hooks.js +2 -2
  146. package/build-module/components/global-styles/hooks.js.map +1 -1
  147. package/build-module/components/global-styles/typography-panel.js +33 -2
  148. package/build-module/components/global-styles/typography-panel.js.map +1 -1
  149. package/build-module/components/image-editor/aspect-ratio-dropdown.js +1 -1
  150. package/build-module/components/image-editor/aspect-ratio-dropdown.js.map +1 -1
  151. package/build-module/components/image-editor/use-save-image.js +1 -2
  152. package/build-module/components/image-editor/use-save-image.js.map +1 -1
  153. package/build-module/components/image-size-control/index.js +5 -0
  154. package/build-module/components/image-size-control/index.js.map +1 -1
  155. package/build-module/components/index.js +6 -0
  156. package/build-module/components/index.js.map +1 -1
  157. package/build-module/components/inserter/block-patterns-explorer/patterns-list.js +2 -2
  158. package/build-module/components/inserter/block-patterns-explorer/patterns-list.js.map +1 -1
  159. package/build-module/components/inserter/block-patterns-tab.js +7 -33
  160. package/build-module/components/inserter/block-patterns-tab.js.map +1 -1
  161. package/build-module/components/inserter/hooks/use-block-types-state.js +3 -4
  162. package/build-module/components/inserter/hooks/use-block-types-state.js.map +1 -1
  163. package/build-module/components/inserter/hooks/use-patterns-state.js +9 -3
  164. package/build-module/components/inserter/hooks/use-patterns-state.js.map +1 -1
  165. package/build-module/components/inserter/media-tab/hooks.js +2 -21
  166. package/build-module/components/inserter/media-tab/hooks.js.map +1 -1
  167. package/build-module/components/inserter/reusable-block-rename-hint.js +48 -0
  168. package/build-module/components/inserter/reusable-block-rename-hint.js.map +1 -0
  169. package/build-module/components/inserter/reusable-blocks-tab.js +5 -2
  170. package/build-module/components/inserter/reusable-blocks-tab.js.map +1 -1
  171. package/build-module/components/inserter/reusable-blocks-tab.native.js +2 -2
  172. package/build-module/components/inserter/reusable-blocks-tab.native.js.map +1 -1
  173. package/build-module/components/inserter/tabs.native.js +1 -1
  174. package/build-module/components/inserter/tabs.native.js.map +1 -1
  175. package/build-module/components/inserter-draggable-blocks/index.js +9 -2
  176. package/build-module/components/inserter-draggable-blocks/index.js.map +1 -1
  177. package/build-module/components/link-control/constants.js +1 -1
  178. package/build-module/components/link-control/constants.js.map +1 -1
  179. package/build-module/components/link-control/index.js +17 -15
  180. package/build-module/components/link-control/index.js.map +1 -1
  181. package/build-module/components/link-control/search-create-button.js +7 -20
  182. package/build-module/components/link-control/search-create-button.js.map +1 -1
  183. package/build-module/components/link-control/search-input.js +4 -4
  184. package/build-module/components/link-control/search-input.js.map +1 -1
  185. package/build-module/components/link-control/search-item.js +14 -28
  186. package/build-module/components/link-control/search-item.js.map +1 -1
  187. package/build-module/components/link-control/search-results.js +3 -3
  188. package/build-module/components/link-control/search-results.js.map +1 -1
  189. package/build-module/components/link-control/settings-drawer.js +4 -5
  190. package/build-module/components/link-control/settings-drawer.js.map +1 -1
  191. package/build-module/components/list-view/appender.js +2 -6
  192. package/build-module/components/list-view/appender.js.map +1 -1
  193. package/build-module/components/provider/index.js +5 -2
  194. package/build-module/components/provider/index.js.map +1 -1
  195. package/build-module/components/provider/use-block-sync.js +21 -0
  196. package/build-module/components/provider/use-block-sync.js.map +1 -1
  197. package/build-module/components/resolution-tool/index.js +45 -0
  198. package/build-module/components/resolution-tool/index.js.map +1 -0
  199. package/build-module/components/url-input/index.js +4 -2
  200. package/build-module/components/url-input/index.js.map +1 -1
  201. package/build-module/components/writing-flow/use-tab-nav.js +8 -26
  202. package/build-module/components/writing-flow/use-tab-nav.js.map +1 -1
  203. package/build-module/components/writing-mode-control/index.js +57 -0
  204. package/build-module/components/writing-mode-control/index.js.map +1 -0
  205. package/build-module/hooks/behaviors.js +26 -20
  206. package/build-module/hooks/behaviors.js.map +1 -1
  207. package/build-module/hooks/supports.js +7 -1
  208. package/build-module/hooks/supports.js.map +1 -1
  209. package/build-module/hooks/typography.js +2 -1
  210. package/build-module/hooks/typography.js.map +1 -1
  211. package/build-module/hooks/utils.js +4 -2
  212. package/build-module/hooks/utils.js.map +1 -1
  213. package/build-module/private-apis.js +7 -1
  214. package/build-module/private-apis.js.map +1 -1
  215. package/build-module/private-apis.native.js +2 -0
  216. package/build-module/private-apis.native.js.map +1 -1
  217. package/build-module/store/actions.js +191 -1
  218. package/build-module/store/actions.js.map +1 -1
  219. package/build-module/store/defaults.js +1 -0
  220. package/build-module/store/defaults.js.map +1 -1
  221. package/build-module/store/index.js +10 -1
  222. package/build-module/store/index.js.map +1 -1
  223. package/build-module/store/private-actions.js +45 -36
  224. package/build-module/store/private-actions.js.map +1 -1
  225. package/build-module/store/private-selectors.js +2 -2
  226. package/build-module/store/private-selectors.js.map +1 -1
  227. package/build-module/store/reducer.js +22 -8
  228. package/build-module/store/reducer.js.map +1 -1
  229. package/build-module/store/selectors.js +33 -15
  230. package/build-module/store/selectors.js.map +1 -1
  231. package/build-style/content-rtl.css +3 -0
  232. package/build-style/content.css +3 -0
  233. package/build-style/style-rtl.css +131 -129
  234. package/build-style/style.css +131 -129
  235. package/package.json +32 -31
  236. package/src/components/alignment-control/test/__snapshots__/index.js.snap +6 -6
  237. package/src/components/block-alignment-control/test/__snapshots__/index.js.snap +5 -5
  238. package/src/components/block-draggable/style.scss +1 -0
  239. package/src/components/block-heading-level-dropdown/heading-level-icon.js +6 -1
  240. package/src/components/block-heading-level-dropdown/index.native.js +8 -4
  241. package/src/components/block-inspector/style.scss +2 -1
  242. package/src/components/block-lock/toolbar.js +34 -6
  243. package/src/components/block-mobile-toolbar/block-actions-menu.native.js +4 -8
  244. package/src/components/block-parent-selector/index.js +13 -8
  245. package/src/components/block-removal-warning-modal/index.js +20 -33
  246. package/src/components/block-toolbar/index.js +9 -6
  247. package/src/components/block-tools/block-contextual-toolbar.js +5 -11
  248. package/src/components/block-tools/style.scss +73 -26
  249. package/src/components/default-block-appender/content.scss +11 -0
  250. package/src/components/dimensions-tool/aspect-ratio-tool.js +124 -0
  251. package/src/components/dimensions-tool/index.js +212 -0
  252. package/src/components/dimensions-tool/scale-tool.js +124 -0
  253. package/src/components/dimensions-tool/stories/aspect-ratio-tool.js +52 -0
  254. package/src/components/dimensions-tool/stories/index.js +54 -0
  255. package/src/components/dimensions-tool/stories/scale-tool.js +48 -0
  256. package/src/components/dimensions-tool/stories/width-height-tool.js +54 -0
  257. package/src/components/dimensions-tool/test/index.js +641 -0
  258. package/src/components/dimensions-tool/width-height-tool.js +113 -0
  259. package/src/components/font-family/README.md +71 -0
  260. package/src/components/global-styles/color-panel.js +1 -1
  261. package/src/components/global-styles/filters-panel.js +2 -2
  262. package/src/components/global-styles/hooks.js +2 -0
  263. package/src/components/global-styles/typography-panel.js +40 -0
  264. package/src/components/image-editor/aspect-ratio-dropdown.js +1 -1
  265. package/src/components/image-editor/use-save-image.js +0 -1
  266. package/src/components/image-size-control/index.js +6 -0
  267. package/src/components/index.js +6 -0
  268. package/src/components/inserter/block-patterns-explorer/patterns-list.js +8 -2
  269. package/src/components/inserter/block-patterns-tab.js +8 -56
  270. package/src/components/inserter/hooks/use-block-types-state.js +3 -4
  271. package/src/components/inserter/hooks/use-patterns-state.js +35 -19
  272. package/src/components/inserter/media-tab/hooks.js +2 -22
  273. package/src/components/inserter/reusable-block-rename-hint.js +52 -0
  274. package/src/components/inserter/reusable-blocks-tab.js +5 -1
  275. package/src/components/inserter/reusable-blocks-tab.native.js +2 -2
  276. package/src/components/inserter/style.scss +28 -0
  277. package/src/components/inserter/tabs.native.js +5 -1
  278. package/src/components/inserter-draggable-blocks/index.js +13 -2
  279. package/src/components/link-control/constants.js +1 -1
  280. package/src/components/link-control/index.js +32 -28
  281. package/src/components/link-control/search-create-button.js +8 -26
  282. package/src/components/link-control/search-input.js +4 -3
  283. package/src/components/link-control/search-item.js +21 -43
  284. package/src/components/link-control/search-results.js +48 -46
  285. package/src/components/link-control/settings-drawer.js +6 -5
  286. package/src/components/link-control/style.scss +51 -123
  287. package/src/components/link-control/test/index.js +135 -123
  288. package/src/components/list-view/appender.js +5 -6
  289. package/src/components/list-view/style.scss +1 -2
  290. package/src/components/media-replace-flow/test/index.js +1 -1
  291. package/src/components/panel-color-settings/README.md +98 -0
  292. package/src/components/provider/index.js +9 -2
  293. package/src/components/provider/test/use-block-sync.js +21 -6
  294. package/src/components/provider/use-block-sync.js +19 -0
  295. package/src/components/recursion-provider/README.md +101 -0
  296. package/src/components/resolution-tool/index.js +56 -0
  297. package/src/components/resolution-tool/stories/index.js +48 -0
  298. package/src/components/url-input/index.js +2 -0
  299. package/src/components/writing-flow/use-tab-nav.js +10 -33
  300. package/src/components/writing-mode-control/index.js +68 -0
  301. package/src/components/writing-mode-control/style.scss +18 -0
  302. package/src/hooks/behaviors.js +25 -16
  303. package/src/hooks/supports.js +7 -0
  304. package/src/hooks/typography.js +2 -0
  305. package/src/hooks/utils.js +3 -0
  306. package/src/private-apis.js +6 -0
  307. package/src/private-apis.native.js +2 -0
  308. package/src/store/actions.js +194 -1
  309. package/src/store/defaults.js +1 -0
  310. package/src/store/index.js +10 -0
  311. package/src/store/private-actions.js +39 -39
  312. package/src/store/private-selectors.js +2 -2
  313. package/src/store/reducer.js +22 -8
  314. package/src/store/selectors.js +54 -20
  315. package/src/store/test/actions.js +111 -0
  316. package/src/store/test/private-actions.js +56 -0
@@ -0,0 +1,641 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components';
11
+ import { useState } from '@wordpress/element';
12
+
13
+ /**
14
+ * Internal dependencies
15
+ */
16
+ import DimensionsTool from '../';
17
+
18
+ const EMPTY_OBJECT = {};
19
+
20
+ function Example( { initialValue, onChange, ...props } ) {
21
+ const [ value, setValue ] = useState( initialValue );
22
+ const resetAll = () => {
23
+ setValue( EMPTY_OBJECT );
24
+ onChange( EMPTY_OBJECT );
25
+ };
26
+ return (
27
+ <ToolsPanel label="Dimensions" panelId="panel-id" resetAll={ resetAll }>
28
+ <DimensionsTool
29
+ panelId="panel-id"
30
+ onChange={ ( nextValue ) => {
31
+ setValue( nextValue );
32
+ onChange( nextValue );
33
+ } }
34
+ defaultScale="cover"
35
+ defaultAspectRatio="auto"
36
+ value={ value }
37
+ { ...props }
38
+ />
39
+ </ToolsPanel>
40
+ );
41
+ }
42
+
43
+ // (xxxx) -> (yyyy) is a shorthand for categorizing the test cases by initial
44
+ // state (xxxx) and final state (yyyy). Each digit represents whether or not the
45
+ // value is set, in the order: [aspectRatio, scale, width, height].
46
+ //
47
+ // See https://github.com/WordPress/gutenberg/pull/51545#issuecomment-1601326289
48
+
49
+ // Using expect( onChange.mock.calls ).toStrictEqual(...) so undefined
50
+ // properties are treated differently from missing properties.
51
+
52
+ describe( 'DimensionsTool', () => {
53
+ describe( 'updating aspectRatio', () => {
54
+ it( 'when starting with empty initial state, setting aspectRatio also sets scale (0000) -> (1100)', async () => {
55
+ const user = userEvent.setup();
56
+ const onChange = jest.fn();
57
+
58
+ const initialValue = {
59
+ // aspectRatio,
60
+ // scale,
61
+ // width,
62
+ // height,
63
+ };
64
+
65
+ render(
66
+ <Example initialValue={ initialValue } onChange={ onChange } />
67
+ );
68
+
69
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
70
+ name: 'Aspect ratio',
71
+ } );
72
+
73
+ await user.selectOptions( aspectRatioSelect, '16/9' );
74
+
75
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
76
+
77
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
78
+ name: 'Scale',
79
+ } );
80
+
81
+ expect( scaleRadioGroup ).toBeInTheDocument();
82
+
83
+ const scaleCoverRadio = screen.getByRole( 'radio', {
84
+ name: 'Cover',
85
+ } );
86
+
87
+ expect( scaleCoverRadio ).toBeChecked();
88
+
89
+ expect( onChange.mock.calls ).toStrictEqual( [
90
+ [ { aspectRatio: '16/9', scale: 'cover' } ],
91
+ ] );
92
+ } );
93
+
94
+ it( 'when starting with just height, setting aspectRatio also sets scale (0001) -> (1101)', async () => {
95
+ const user = userEvent.setup();
96
+ const onChange = jest.fn();
97
+
98
+ const initialValue = {
99
+ // aspectRatio,
100
+ // scale,
101
+ // width,
102
+ height: '6px',
103
+ };
104
+
105
+ render(
106
+ <Example initialValue={ initialValue } onChange={ onChange } />
107
+ );
108
+
109
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
110
+ name: 'Aspect ratio',
111
+ } );
112
+
113
+ await user.selectOptions( aspectRatioSelect, '16/9' );
114
+
115
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
116
+
117
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
118
+ name: 'Scale',
119
+ } );
120
+
121
+ expect( scaleRadioGroup ).toBeInTheDocument();
122
+
123
+ const scaleCoverRadio = screen.getByRole( 'radio', {
124
+ name: 'Cover',
125
+ } );
126
+
127
+ expect( scaleCoverRadio ).toBeChecked();
128
+
129
+ expect( onChange.mock.calls ).toStrictEqual( [
130
+ [ { aspectRatio: '16/9', scale: 'cover', height: '6px' } ],
131
+ ] );
132
+ } );
133
+
134
+ it( 'when starting with just width, setting aspectRatio also sets scale (0010) -> (1110)', async () => {
135
+ const user = userEvent.setup();
136
+ const onChange = jest.fn();
137
+
138
+ const initialValue = {
139
+ // aspectRatio,
140
+ // scale,
141
+ width: '8px',
142
+ // height,
143
+ };
144
+
145
+ render(
146
+ <Example initialValue={ initialValue } onChange={ onChange } />
147
+ );
148
+
149
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
150
+ name: 'Aspect ratio',
151
+ } );
152
+
153
+ await user.selectOptions( aspectRatioSelect, '16/9' );
154
+
155
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
156
+
157
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
158
+ name: 'Scale',
159
+ } );
160
+
161
+ expect( scaleRadioGroup ).toBeInTheDocument();
162
+
163
+ const scaleCoverRadio = screen.getByRole( 'radio', {
164
+ name: 'Cover',
165
+ } );
166
+
167
+ expect( scaleCoverRadio ).toBeChecked();
168
+
169
+ expect( onChange.mock.calls ).toStrictEqual( [
170
+ [ { aspectRatio: '16/9', scale: 'cover', width: '8px' } ],
171
+ ] );
172
+ } );
173
+
174
+ it( 'when starting with scale, width, and height, setting aspectRatio also clears height (0111) -> (1110)', async () => {
175
+ const user = userEvent.setup();
176
+ const onChange = jest.fn();
177
+
178
+ const initialValue = {
179
+ // aspectRatio,
180
+ scale: 'cover',
181
+ width: '8px',
182
+ height: '6px',
183
+ };
184
+
185
+ render(
186
+ <Example initialValue={ initialValue } onChange={ onChange } />
187
+ );
188
+
189
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
190
+ name: 'Aspect ratio',
191
+ } );
192
+
193
+ await user.selectOptions( aspectRatioSelect, '16/9' );
194
+
195
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
196
+
197
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
198
+ name: 'Scale',
199
+ } );
200
+
201
+ expect( scaleRadioGroup ).toBeInTheDocument();
202
+
203
+ const scaleCoverRadio = screen.getByRole( 'radio', {
204
+ name: 'Cover',
205
+ } );
206
+
207
+ expect( scaleCoverRadio ).toBeChecked();
208
+
209
+ expect( onChange.mock.calls ).toStrictEqual( [
210
+ [ { aspectRatio: '16/9', scale: 'cover', width: '8px' } ],
211
+ ] );
212
+ } );
213
+
214
+ it( 'when starting with aspectRatio and scale, setting aspectRatio to "Original" also clears scale (1100) -> (0000)', async () => {
215
+ const user = userEvent.setup();
216
+ const onChange = jest.fn();
217
+
218
+ const initialValue = {
219
+ aspectRatio: '16/9',
220
+ scale: 'cover',
221
+ // width,
222
+ // height,
223
+ };
224
+
225
+ render(
226
+ <Example initialValue={ initialValue } onChange={ onChange } />
227
+ );
228
+
229
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
230
+ name: 'Aspect ratio',
231
+ } );
232
+
233
+ await user.selectOptions( aspectRatioSelect, 'auto' );
234
+
235
+ expect( aspectRatioSelect ).toHaveValue( 'auto' );
236
+
237
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
238
+ name: 'Scale',
239
+ } );
240
+
241
+ expect( scaleRadioGroup ).not.toBeInTheDocument();
242
+
243
+ expect( onChange.mock.calls ).toStrictEqual( [ [ {} ] ] );
244
+ } );
245
+
246
+ it( 'when starting with aspectRatio, scale, and height, setting aspectRatio to "Original" also clears scale (1101) -> (0001)', async () => {
247
+ const user = userEvent.setup();
248
+ const onChange = jest.fn();
249
+
250
+ const initialValue = {
251
+ aspectRatio: '16/9',
252
+ scale: 'cover',
253
+ // width,
254
+ height: '6px',
255
+ };
256
+
257
+ render(
258
+ <Example initialValue={ initialValue } onChange={ onChange } />
259
+ );
260
+
261
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
262
+ name: 'Aspect ratio',
263
+ } );
264
+
265
+ await user.selectOptions( aspectRatioSelect, 'auto' );
266
+
267
+ expect( aspectRatioSelect ).toHaveValue( 'auto' );
268
+
269
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
270
+ name: 'Scale',
271
+ } );
272
+
273
+ expect( scaleRadioGroup ).not.toBeInTheDocument();
274
+
275
+ expect( onChange.mock.calls ).toStrictEqual( [
276
+ [ { height: '6px' } ],
277
+ ] );
278
+ } );
279
+
280
+ it( 'when starting with aspectRatio, scale, and width, setting aspectRatio to "Original" also clears scale (1110) -> (0010)', async () => {
281
+ const user = userEvent.setup();
282
+ const onChange = jest.fn();
283
+
284
+ const initialValue = {
285
+ aspectRatio: '16/9',
286
+ scale: 'cover',
287
+ width: '8px',
288
+ // height,
289
+ };
290
+
291
+ render(
292
+ <Example initialValue={ initialValue } onChange={ onChange } />
293
+ );
294
+
295
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
296
+ name: 'Aspect ratio',
297
+ } );
298
+
299
+ await user.selectOptions( aspectRatioSelect, 'auto' );
300
+
301
+ expect( aspectRatioSelect ).toHaveValue( 'auto' );
302
+
303
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
304
+ name: 'Scale',
305
+ } );
306
+
307
+ expect( scaleRadioGroup ).not.toBeInTheDocument();
308
+
309
+ expect( onChange.mock.calls ).toStrictEqual( [
310
+ [ { width: '8px' } ],
311
+ ] );
312
+ } );
313
+ } );
314
+
315
+ describe( 'updating scale', () => {
316
+ // No custom interactions here. Things should just update normally.
317
+ } );
318
+
319
+ describe( 'updating dimensions', () => {
320
+ it( 'when starting with just height, setting width also sets scale (0001) -> (0111)', async () => {
321
+ const user = userEvent.setup();
322
+ const onChange = jest.fn();
323
+
324
+ const initialValue = {
325
+ // aspectRatio,
326
+ // scale,
327
+ // width,
328
+ height: '6px',
329
+ };
330
+
331
+ render(
332
+ <Example initialValue={ initialValue } onChange={ onChange } />
333
+ );
334
+
335
+ const widthInput = screen.getByRole( 'spinbutton', {
336
+ name: 'Width',
337
+ } );
338
+
339
+ await user.type( widthInput, '8' );
340
+
341
+ expect( widthInput ).toHaveValue( 8 );
342
+
343
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
344
+ name: 'Scale',
345
+ } );
346
+
347
+ expect( scaleRadioGroup ).toBeInTheDocument();
348
+
349
+ const scaleCoverRadio = screen.getByRole( 'radio', {
350
+ name: 'Cover',
351
+ } );
352
+
353
+ expect( scaleCoverRadio ).toBeChecked();
354
+
355
+ expect( onChange.mock.calls ).toStrictEqual( [
356
+ [ { scale: 'cover', width: '8px', height: '6px' } ],
357
+ ] );
358
+ } );
359
+
360
+ it( 'when starting with just width, setting height also sets scale (0010) -> (0111)', async () => {
361
+ const user = userEvent.setup();
362
+ const onChange = jest.fn();
363
+
364
+ const initialValue = {
365
+ // aspectRatio,
366
+ // scale,
367
+ width: '8px',
368
+ // height,
369
+ };
370
+
371
+ render(
372
+ <Example initialValue={ initialValue } onChange={ onChange } />
373
+ );
374
+
375
+ const heightInput = screen.getByRole( 'spinbutton', {
376
+ name: 'Height',
377
+ } );
378
+
379
+ await user.type( heightInput, '6' );
380
+
381
+ expect( heightInput ).toHaveValue( 6 );
382
+
383
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
384
+ name: 'Scale',
385
+ } );
386
+
387
+ expect( scaleRadioGroup ).toBeInTheDocument();
388
+
389
+ const scaleCoverRadio = screen.getByRole( 'radio', {
390
+ name: 'Cover',
391
+ } );
392
+
393
+ expect( scaleCoverRadio ).toBeChecked();
394
+
395
+ expect( onChange.mock.calls ).toStrictEqual( [
396
+ [ { scale: 'cover', width: '8px', height: '6px' } ],
397
+ ] );
398
+ } );
399
+
400
+ it( 'when starting with scale, width, and height, clearing width also clears scale (0111) -> (0001)', async () => {
401
+ const user = userEvent.setup();
402
+ const onChange = jest.fn();
403
+
404
+ const initialValue = {
405
+ // aspectRatio,
406
+ scale: 'cover',
407
+ width: '8px',
408
+ height: '6px',
409
+ };
410
+
411
+ render(
412
+ <Example initialValue={ initialValue } onChange={ onChange } />
413
+ );
414
+
415
+ const widthInput = screen.getByRole( 'spinbutton', {
416
+ name: 'Width',
417
+ } );
418
+
419
+ await user.clear( widthInput );
420
+
421
+ expect( widthInput ).toHaveValue( null );
422
+
423
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
424
+ name: 'Scale',
425
+ } );
426
+
427
+ expect( scaleRadioGroup ).not.toBeInTheDocument();
428
+
429
+ expect( onChange.mock.calls ).toStrictEqual( [
430
+ [ { height: '6px' } ],
431
+ ] );
432
+ } );
433
+
434
+ it( 'when starting with scale, width, and height, clearing height also clears scale (0111) -> (0010)', async () => {
435
+ const user = userEvent.setup();
436
+ const onChange = jest.fn();
437
+
438
+ const initialValue = {
439
+ // aspectRatio,
440
+ scale: 'cover',
441
+ width: '8px',
442
+ height: '6px',
443
+ };
444
+
445
+ render(
446
+ <Example initialValue={ initialValue } onChange={ onChange } />
447
+ );
448
+
449
+ const heightInput = screen.getByRole( 'spinbutton', {
450
+ name: 'Height',
451
+ } );
452
+
453
+ await user.clear( heightInput );
454
+
455
+ expect( heightInput ).toHaveValue( null );
456
+
457
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
458
+ name: 'Scale',
459
+ } );
460
+
461
+ expect( scaleRadioGroup ).not.toBeInTheDocument();
462
+
463
+ expect( onChange.mock.calls ).toStrictEqual( [
464
+ [ { width: '8px' } ],
465
+ ] );
466
+ } );
467
+
468
+ it( 'when starting with aspectRatio, scale, and height, setting width also clears aspectRatio (1101) -> (0111)', async () => {
469
+ const user = userEvent.setup();
470
+ const onChange = jest.fn();
471
+
472
+ const initialValue = {
473
+ aspectRatio: '16/9',
474
+ scale: 'cover',
475
+ // width,
476
+ height: '6px',
477
+ };
478
+
479
+ render(
480
+ <Example initialValue={ initialValue } onChange={ onChange } />
481
+ );
482
+
483
+ const widthInput = screen.getByRole( 'spinbutton', {
484
+ name: 'Width',
485
+ } );
486
+
487
+ await user.type( widthInput, '8' );
488
+
489
+ expect( widthInput ).toHaveValue( 8 );
490
+
491
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
492
+ name: 'Aspect ratio',
493
+ } );
494
+
495
+ expect( aspectRatioSelect ).toHaveValue( 'custom' );
496
+
497
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
498
+ name: 'Scale',
499
+ } );
500
+
501
+ expect( scaleRadioGroup ).toBeInTheDocument();
502
+
503
+ const scaleCoverRadio = screen.getByRole( 'radio', {
504
+ name: 'Cover',
505
+ } );
506
+
507
+ expect( scaleCoverRadio ).toBeChecked();
508
+
509
+ expect( onChange.mock.calls ).toStrictEqual( [
510
+ [ { scale: 'cover', width: '8px', height: '6px' } ],
511
+ ] );
512
+ } );
513
+
514
+ it( 'when starting with aspectRatio, scale, and width, setting height also clears aspectRatio (1110) -> (0111)', async () => {
515
+ const user = userEvent.setup();
516
+ const onChange = jest.fn();
517
+
518
+ const initialValue = {
519
+ aspectRatio: '16/9',
520
+ scale: 'cover',
521
+ width: '8px',
522
+ // height,
523
+ };
524
+
525
+ render(
526
+ <Example initialValue={ initialValue } onChange={ onChange } />
527
+ );
528
+
529
+ const heightInput = screen.getByRole( 'spinbutton', {
530
+ name: 'Height',
531
+ } );
532
+
533
+ await user.type( heightInput, '6' );
534
+
535
+ expect( heightInput ).toHaveValue( 6 );
536
+
537
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
538
+ name: 'Aspect ratio',
539
+ } );
540
+
541
+ expect( aspectRatioSelect ).toHaveValue( 'custom' );
542
+
543
+ const scaleRadioGroup = screen.queryByRole( 'radiogroup', {
544
+ name: 'Scale',
545
+ } );
546
+
547
+ expect( scaleRadioGroup ).toBeInTheDocument();
548
+
549
+ const scaleCoverRadio = screen.getByRole( 'radio', {
550
+ name: 'Cover',
551
+ } );
552
+
553
+ expect( scaleCoverRadio ).toBeChecked();
554
+
555
+ expect( onChange.mock.calls ).toStrictEqual( [
556
+ [ { scale: 'cover', width: '8px', height: '6px' } ],
557
+ ] );
558
+ } );
559
+ } );
560
+
561
+ describe( 'internal component state', () => {
562
+ it( 'when aspect ratio is change to custom by setting width and height then removing a width value should return the original aspect ratio (1100) -> (1110) -> (0111) -> (1101)', async () => {
563
+ const user = userEvent.setup();
564
+ const onChange = jest.fn();
565
+
566
+ const value = {
567
+ aspectRatio: '16/9',
568
+ scale: 'cover',
569
+ };
570
+
571
+ render( <Example initialValue={ value } onChange={ onChange } /> );
572
+
573
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
574
+ name: 'Aspect ratio',
575
+ } );
576
+
577
+ const widthInput = screen.getByRole( 'spinbutton', {
578
+ name: 'Width',
579
+ } );
580
+
581
+ const heightInput = screen.getByRole( 'spinbutton', {
582
+ name: 'Height',
583
+ } );
584
+
585
+ await user.type( widthInput, '8' );
586
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
587
+
588
+ await user.type( heightInput, '6' );
589
+ expect( aspectRatioSelect ).toHaveValue( 'custom' );
590
+
591
+ await user.clear( widthInput, '' );
592
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
593
+
594
+ expect( onChange.mock.calls ).toStrictEqual( [
595
+ [ { aspectRatio: '16/9', scale: 'cover', width: '8px' } ],
596
+ [ { scale: 'cover', width: '8px', height: '6px' } ],
597
+ [ { aspectRatio: '16/9', scale: 'cover', height: '6px' } ],
598
+ ] );
599
+ } );
600
+
601
+ it( 'when custom scale is set then aspect ratio is set to original and then aspect ratio is changed back (1100) -> (1100) -> (0000) -> (1100)', async () => {
602
+ const user = userEvent.setup();
603
+ const onChange = jest.fn();
604
+
605
+ const value = {
606
+ aspectRatio: '16/9',
607
+ scale: 'cover',
608
+ };
609
+
610
+ render( <Example initialValue={ value } onChange={ onChange } /> );
611
+
612
+ const aspectRatioSelect = screen.getByRole( 'combobox', {
613
+ name: 'Aspect ratio',
614
+ } );
615
+
616
+ const scaleContainRadio = screen.getByRole( 'radio', {
617
+ name: 'Contain',
618
+ } );
619
+
620
+ await user.click( scaleContainRadio );
621
+ expect( scaleContainRadio ).toBeChecked();
622
+
623
+ await user.selectOptions( aspectRatioSelect, 'auto' );
624
+ expect( aspectRatioSelect ).toHaveValue( 'auto' );
625
+
626
+ await user.selectOptions( aspectRatioSelect, '16/9' );
627
+ expect( aspectRatioSelect ).toHaveValue( '16/9' );
628
+
629
+ expect( onChange.mock.calls ).toStrictEqual( [
630
+ [ { aspectRatio: '16/9', scale: 'contain' } ],
631
+ [ {} ],
632
+ [
633
+ {
634
+ aspectRatio: '16/9',
635
+ scale: 'contain',
636
+ },
637
+ ],
638
+ ] );
639
+ } );
640
+ } );
641
+ } );