@wordpress/components 19.8.3 → 19.10.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 (256) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/CONTRIBUTING.md +80 -7
  3. package/build/alignment-matrix-control/styles/alignment-matrix-control-styles.js +11 -11
  4. package/build/alignment-matrix-control/styles/alignment-matrix-control-styles.js.map +1 -1
  5. package/build/angle-picker-control/angle-circle.js +5 -7
  6. package/build/angle-picker-control/angle-circle.js.map +1 -1
  7. package/build/box-control/index.js +0 -21
  8. package/build/box-control/index.js.map +1 -1
  9. package/build/box-control/utils.js +1 -8
  10. package/build/box-control/utils.js.map +1 -1
  11. package/build/button/index.js +3 -5
  12. package/build/button/index.js.map +1 -1
  13. package/build/circular-option-picker/index.js +1 -2
  14. package/build/circular-option-picker/index.js.map +1 -1
  15. package/build/disabled/index.js +4 -76
  16. package/build/disabled/index.js.map +1 -1
  17. package/build/heading/hook.js +1 -1
  18. package/build/heading/hook.js.map +1 -1
  19. package/build/input-control/index.js +27 -4
  20. package/build/input-control/index.js.map +1 -1
  21. package/build/input-control/styles/input-control-styles.js +42 -30
  22. package/build/input-control/styles/input-control-styles.js.map +1 -1
  23. package/build/mobile/bottom-sheet-select-control/index.native.js +1 -0
  24. package/build/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  25. package/build/navigation/styles/navigation-styles.js +12 -12
  26. package/build/navigation/styles/navigation-styles.js.map +1 -1
  27. package/build/notice/index.native.js +44 -40
  28. package/build/notice/index.native.js.map +1 -1
  29. package/build/notice/list.native.js +27 -45
  30. package/build/notice/list.native.js.map +1 -1
  31. package/build/popover/index.js +6 -52
  32. package/build/popover/index.js.map +1 -1
  33. package/build/sandbox/index.js +2 -2
  34. package/build/sandbox/index.js.map +1 -1
  35. package/build/select-control/index.js +31 -4
  36. package/build/select-control/index.js.map +1 -1
  37. package/build/select-control/styles/select-control-styles.js +8 -8
  38. package/build/select-control/styles/select-control-styles.js.map +1 -1
  39. package/build/surface/styles.js +8 -8
  40. package/build/surface/styles.js.map +1 -1
  41. package/build/text/hook.js +5 -5
  42. package/build/text/hook.js.map +1 -1
  43. package/build/text/styles/text-mixins.native.js +1 -1
  44. package/build/text/styles/text-mixins.native.js.map +1 -1
  45. package/build/text/styles.js +7 -7
  46. package/build/text/styles.js.map +1 -1
  47. package/build/text-control/index.js +35 -28
  48. package/build/text-control/index.js.map +1 -1
  49. package/build/text-control/types.js +6 -0
  50. package/build/text-control/types.js.map +1 -0
  51. package/build/toggle-group-control/toggle-group-control-option-icon/component.js +6 -4
  52. package/build/toggle-group-control/toggle-group-control-option-icon/component.js.map +1 -1
  53. package/build/tools-panel/tools-panel-header/component.js +52 -36
  54. package/build/tools-panel/tools-panel-header/component.js.map +1 -1
  55. package/build/ui/spinner/component.js +1 -1
  56. package/build/ui/spinner/component.js.map +1 -1
  57. package/build/unit-control/index.js +3 -3
  58. package/build/unit-control/index.js.map +1 -1
  59. package/build/unit-control/styles/unit-control-styles.js +11 -20
  60. package/build/unit-control/styles/unit-control-styles.js.map +1 -1
  61. package/build/unit-control/utils.js.map +1 -1
  62. package/build/utils/colors-values.js +9 -24
  63. package/build/utils/colors-values.js.map +1 -1
  64. package/build-module/alignment-matrix-control/styles/alignment-matrix-control-styles.js +11 -11
  65. package/build-module/alignment-matrix-control/styles/alignment-matrix-control-styles.js.map +1 -1
  66. package/build-module/angle-picker-control/angle-circle.js +5 -7
  67. package/build-module/angle-picker-control/angle-circle.js.map +1 -1
  68. package/build-module/box-control/index.js +1 -20
  69. package/build-module/box-control/index.js.map +1 -1
  70. package/build-module/box-control/utils.js +0 -6
  71. package/build-module/box-control/utils.js.map +1 -1
  72. package/build-module/button/index.js +3 -4
  73. package/build-module/button/index.js.map +1 -1
  74. package/build-module/circular-option-picker/index.js +1 -2
  75. package/build-module/circular-option-picker/index.js.map +1 -1
  76. package/build-module/disabled/index.js +5 -76
  77. package/build-module/disabled/index.js.map +1 -1
  78. package/build-module/heading/hook.js +1 -1
  79. package/build-module/heading/hook.js.map +1 -1
  80. package/build-module/input-control/index.js +24 -3
  81. package/build-module/input-control/index.js.map +1 -1
  82. package/build-module/input-control/styles/input-control-styles.js +42 -30
  83. package/build-module/input-control/styles/input-control-styles.js.map +1 -1
  84. package/build-module/mobile/bottom-sheet-select-control/index.native.js +1 -0
  85. package/build-module/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  86. package/build-module/navigation/styles/navigation-styles.js +13 -13
  87. package/build-module/navigation/styles/navigation-styles.js.map +1 -1
  88. package/build-module/notice/index.native.js +45 -41
  89. package/build-module/notice/index.native.js.map +1 -1
  90. package/build-module/notice/list.native.js +28 -46
  91. package/build-module/notice/list.native.js.map +1 -1
  92. package/build-module/popover/index.js +6 -52
  93. package/build-module/popover/index.js.map +1 -1
  94. package/build-module/sandbox/index.js +2 -2
  95. package/build-module/sandbox/index.js.map +1 -1
  96. package/build-module/select-control/index.js +29 -3
  97. package/build-module/select-control/index.js.map +1 -1
  98. package/build-module/select-control/styles/select-control-styles.js +8 -8
  99. package/build-module/select-control/styles/select-control-styles.js.map +1 -1
  100. package/build-module/surface/styles.js +8 -8
  101. package/build-module/surface/styles.js.map +1 -1
  102. package/build-module/text/hook.js +5 -5
  103. package/build-module/text/hook.js.map +1 -1
  104. package/build-module/text/styles/text-mixins.native.js +2 -2
  105. package/build-module/text/styles/text-mixins.native.js.map +1 -1
  106. package/build-module/text/styles.js +7 -7
  107. package/build-module/text/styles.js.map +1 -1
  108. package/build-module/text-control/index.js +35 -27
  109. package/build-module/text-control/index.js.map +1 -1
  110. package/build-module/text-control/types.js +2 -0
  111. package/build-module/text-control/types.js.map +1 -0
  112. package/build-module/toggle-group-control/toggle-group-control-option-icon/component.js +1 -5
  113. package/build-module/toggle-group-control/toggle-group-control-option-icon/component.js.map +1 -1
  114. package/build-module/tools-panel/tools-panel-header/component.js +51 -36
  115. package/build-module/tools-panel/tools-panel-header/component.js.map +1 -1
  116. package/build-module/ui/spinner/component.js +1 -1
  117. package/build-module/ui/spinner/component.js.map +1 -1
  118. package/build-module/unit-control/index.js +3 -3
  119. package/build-module/unit-control/index.js.map +1 -1
  120. package/build-module/unit-control/styles/unit-control-styles.js +11 -20
  121. package/build-module/unit-control/styles/unit-control-styles.js.map +1 -1
  122. package/build-module/unit-control/utils.js.map +1 -1
  123. package/build-module/utils/colors-values.js +19 -23
  124. package/build-module/utils/colors-values.js.map +1 -1
  125. package/build-style/style-rtl.css +24 -0
  126. package/build-style/style.css +24 -0
  127. package/build-types/button/index.d.ts.map +1 -1
  128. package/build-types/circular-option-picker/index.d.ts.map +1 -1
  129. package/build-types/color-picker/styles.d.ts +3 -3
  130. package/build-types/disabled/index.d.ts.map +1 -1
  131. package/build-types/input-control/index.d.ts +23 -3
  132. package/build-types/input-control/index.d.ts.map +1 -1
  133. package/build-types/input-control/input-field.d.ts +1 -1
  134. package/build-types/input-control/input-field.d.ts.map +1 -1
  135. package/build-types/input-control/stories/index.d.ts +5 -5
  136. package/build-types/input-control/styles/input-control-styles.d.ts +1 -0
  137. package/build-types/input-control/styles/input-control-styles.d.ts.map +1 -1
  138. package/build-types/input-control/types.d.ts +79 -3
  139. package/build-types/input-control/types.d.ts.map +1 -1
  140. package/build-types/number-control/styles/number-control-styles.d.ts +1 -1
  141. package/build-types/popover/index.d.ts +0 -1
  142. package/build-types/popover/index.d.ts.map +1 -1
  143. package/build-types/select-control/index.d.ts +30 -26
  144. package/build-types/select-control/index.d.ts.map +1 -1
  145. package/build-types/select-control/stories/index.d.ts +23 -0
  146. package/build-types/select-control/stories/index.d.ts.map +1 -0
  147. package/build-types/select-control/styles/select-control-styles.d.ts +3 -4
  148. package/build-types/select-control/styles/select-control-styles.d.ts.map +1 -1
  149. package/build-types/select-control/test/select-control.d.ts +2 -0
  150. package/build-types/select-control/test/select-control.d.ts.map +1 -0
  151. package/build-types/select-control/types.d.ts +52 -1
  152. package/build-types/select-control/types.d.ts.map +1 -1
  153. package/build-types/text-control/index.d.ts +32 -0
  154. package/build-types/text-control/index.d.ts.map +1 -0
  155. package/build-types/text-control/stories/index.d.ts +13 -0
  156. package/build-types/text-control/stories/index.d.ts.map +1 -0
  157. package/build-types/text-control/types.d.ts +25 -0
  158. package/build-types/text-control/types.d.ts.map +1 -0
  159. package/build-types/toggle-group-control/toggle-group-control-option-icon/component.d.ts.map +1 -1
  160. package/build-types/tools-panel/tools-panel-header/component.d.ts.map +1 -1
  161. package/build-types/tools-panel/types.d.ts +0 -1
  162. package/build-types/tools-panel/types.d.ts.map +1 -1
  163. package/build-types/unit-control/index.d.ts +2 -2
  164. package/build-types/unit-control/index.d.ts.map +1 -1
  165. package/build-types/unit-control/styles/unit-control-styles.d.ts.map +1 -1
  166. package/build-types/unit-control/test/index.d.ts +2 -0
  167. package/build-types/unit-control/test/index.d.ts.map +1 -0
  168. package/build-types/unit-control/test/utils.d.ts +2 -0
  169. package/build-types/unit-control/test/utils.d.ts.map +1 -0
  170. package/build-types/unit-control/types.d.ts +1 -1
  171. package/build-types/unit-control/types.d.ts.map +1 -1
  172. package/build-types/unit-control/utils.d.ts +3 -3
  173. package/build-types/unit-control/utils.d.ts.map +1 -1
  174. package/build-types/utils/colors-values.d.ts +6 -146
  175. package/build-types/utils/colors-values.d.ts.map +1 -1
  176. package/package.json +17 -17
  177. package/src/alignment-matrix-control/styles/alignment-matrix-control-styles.js +5 -3
  178. package/src/angle-picker-control/angle-circle.js +3 -3
  179. package/src/box-control/README.md +0 -74
  180. package/src/box-control/index.js +0 -15
  181. package/src/box-control/stories/index.js +0 -29
  182. package/src/box-control/utils.js +0 -7
  183. package/src/button/index.js +2 -4
  184. package/src/button/test/index.js +16 -1
  185. package/src/circular-option-picker/index.js +1 -2
  186. package/src/color-palette/README.md +0 -1
  187. package/src/color-palette/test/__snapshots__/index.js.snap +2 -3
  188. package/src/confirm-dialog/stories/index.js +87 -99
  189. package/src/date-time/stories/index.js +19 -0
  190. package/src/date-time/test/date.js +107 -78
  191. package/src/dimension-control/test/__snapshots__/index.test.js.snap +4 -4
  192. package/src/disabled/index.js +5 -90
  193. package/src/form-file-upload/test/index.js +15 -12
  194. package/src/heading/hook.ts +1 -1
  195. package/src/heading/test/__snapshots__/index.js.snap +3 -3
  196. package/src/input-control/README.md +3 -3
  197. package/src/input-control/index.tsx +23 -3
  198. package/src/input-control/stories/index.tsx +63 -0
  199. package/src/input-control/styles/input-control-styles.tsx +20 -7
  200. package/src/input-control/types.ts +79 -2
  201. package/src/menu-item/style.scss +10 -0
  202. package/src/mobile/bottom-sheet/bottom-sheet-navigation/test/navigation-container.native.js +8 -1
  203. package/src/mobile/bottom-sheet-select-control/index.native.js +1 -0
  204. package/src/mobile/html-text-input/style.android.scss +1 -0
  205. package/src/mobile/html-text-input/style.ios.scss +1 -0
  206. package/src/mobile/link-settings/test/link-settings-navigation.native.js +9 -1
  207. package/src/navigation/styles/navigation-styles.js +5 -5
  208. package/src/notice/index.native.js +44 -54
  209. package/src/notice/list.native.js +27 -51
  210. package/src/notice/style.native.scss +1 -0
  211. package/src/popover/index.js +5 -51
  212. package/src/query-controls/README.md +2 -2
  213. package/src/sandbox/index.js +2 -2
  214. package/src/select-control/README.md +2 -2
  215. package/src/select-control/index.tsx +30 -29
  216. package/src/select-control/stories/index.tsx +90 -0
  217. package/src/select-control/styles/select-control-styles.ts +10 -9
  218. package/src/select-control/test/{select-control.js → select-control.tsx} +2 -2
  219. package/src/select-control/types.ts +66 -1
  220. package/src/surface/styles.js +1 -1
  221. package/src/text/hook.js +1 -1
  222. package/src/text/styles/text-mixins.native.js +2 -2
  223. package/src/text/styles.js +1 -1
  224. package/src/text/test/__snapshots__/{index.js.snap → index.tsx.snap} +16 -0
  225. package/src/text/test/{index.js → index.tsx} +12 -6
  226. package/src/text-control/index.tsx +84 -0
  227. package/src/text-control/stories/index.tsx +66 -0
  228. package/src/text-control/types.ts +29 -0
  229. package/src/toggle-group-control/toggle-group-control-option-icon/component.tsx +1 -5
  230. package/src/toolbar-group/style.scss +20 -0
  231. package/src/tools-panel/test/__snapshots__/index.js.snap +2 -2
  232. package/src/tools-panel/test/index.js +71 -18
  233. package/src/tools-panel/tools-panel-header/component.tsx +75 -33
  234. package/src/tools-panel/types.ts +0 -1
  235. package/src/tooltip/test/index.js +6 -0
  236. package/src/ui/spinner/component.js +1 -1
  237. package/src/ui/spinner/test/__snapshots__/index.js.snap +3 -3
  238. package/src/unit-control/index.tsx +2 -5
  239. package/src/unit-control/styles/unit-control-styles.ts +3 -13
  240. package/src/unit-control/test/__snapshots__/index.tsx.snap +33 -0
  241. package/src/unit-control/test/{index.js → index.tsx} +214 -165
  242. package/src/unit-control/test/{utils.js → utils.ts} +38 -19
  243. package/src/unit-control/types.ts +4 -1
  244. package/src/unit-control/utils.ts +5 -3
  245. package/src/utils/colors-values.js +18 -22
  246. package/tsconfig.json +9 -2
  247. package/tsconfig.tsbuildinfo +1 -1
  248. package/build/box-control/visualizer.js +0 -165
  249. package/build/box-control/visualizer.js.map +0 -1
  250. package/build-module/box-control/visualizer.js +0 -154
  251. package/build-module/box-control/visualizer.js.map +0 -1
  252. package/src/box-control/visualizer.js +0 -116
  253. package/src/input-control/stories/index.js +0 -71
  254. package/src/select-control/stories/index.js +0 -104
  255. package/src/text-control/index.js +0 -72
  256. package/src/text-control/stories/index.js +0 -46
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render as RTLrender, screen, waitFor } from '@testing-library/react';
4
+ import { render, screen } from '@testing-library/react';
5
5
  import userEvent from '@testing-library/user-event';
6
6
 
7
7
  /**
@@ -12,43 +12,52 @@ import { useState } from '@wordpress/element';
12
12
  /**
13
13
  * Internal dependencies
14
14
  */
15
- import UnitControl from '../';
15
+ import UnitControl from '..';
16
16
  import { parseQuantityAndUnitFromRawValue } from '../utils';
17
+ import type { UnitControlOnChangeCallback } from '../types';
17
18
 
18
- function render( jsx ) {
19
- return {
20
- user: userEvent.setup( {
21
- // Avoids timeout errors (https://github.com/testing-library/user-event/issues/565#issuecomment-1064579531).
22
- delay: null,
23
- } ),
24
- ...RTLrender( jsx ),
25
- };
26
- }
19
+ const user = userEvent.setup( {
20
+ advanceTimers: jest.advanceTimersByTime,
21
+ } );
27
22
 
28
- const getComponent = () =>
29
- document.body.querySelector( '.components-unit-control' );
30
- const getInput = () =>
31
- document.body.querySelector( '.components-unit-control input' );
32
- const getSelect = () =>
33
- document.body.querySelector( '.components-unit-control select' );
34
- const getUnitLabel = () =>
35
- document.body.querySelector( '.components-unit-control__unit-label' );
23
+ const getInput = ( {
24
+ isInputTypeText = false,
25
+ }: {
26
+ isInputTypeText?: boolean;
27
+ } = {} ) =>
28
+ screen.getByRole(
29
+ isInputTypeText ? 'textbox' : 'spinbutton'
30
+ ) as HTMLInputElement;
31
+ const getSelect = () => screen.getByRole( 'combobox' ) as HTMLSelectElement;
32
+ const getSelectOptions = () =>
33
+ screen.getAllByRole( 'option' ) as HTMLOptionElement[];
36
34
 
37
35
  const ControlledSyncUnits = () => {
38
- const [ state, setState ] = useState( { valueA: '', valueB: '' } );
36
+ const [ state, setState ] = useState( {
37
+ valueA: '',
38
+ valueB: '',
39
+ } );
39
40
 
40
41
  // Keep the unit sync'd between the two `UnitControl` instances.
41
- const onUnitControlChange = ( fieldName, newValue ) => {
42
- // eslint-disable-next-line @wordpress/no-unused-vars-before-return
43
- const [ quantity, newUnit ] = parseQuantityAndUnitFromRawValue(
42
+ const onUnitControlChange = (
43
+ fieldName: 'valueA' | 'valueB',
44
+ newValue?: string | number
45
+ ) => {
46
+ const parsedQuantityAndUnit = parseQuantityAndUnitFromRawValue(
44
47
  newValue
45
48
  );
49
+ const quantity = parsedQuantityAndUnit[ 0 ];
46
50
 
47
51
  if ( ! Number.isFinite( quantity ) ) {
48
52
  return;
49
53
  }
50
54
 
51
- const nextState = { ...state, [ fieldName ]: newValue };
55
+ const newUnit = parsedQuantityAndUnit[ 1 ];
56
+
57
+ const nextState = {
58
+ ...state,
59
+ [ fieldName ]: newValue,
60
+ };
52
61
 
53
62
  Object.entries( state ).forEach( ( [ stateProp, stateValue ] ) => {
54
63
  const [
@@ -57,7 +66,9 @@ const ControlledSyncUnits = () => {
57
66
  ] = parseQuantityAndUnitFromRawValue( stateValue );
58
67
 
59
68
  if ( stateProp !== fieldName && stateUnit !== newUnit ) {
60
- nextState[ stateProp ] = `${ stateQuantity }${ newUnit }`;
69
+ nextState[
70
+ stateProp as 'valueA' | 'valueB'
71
+ ] = `${ stateQuantity }${ newUnit }`;
61
72
  }
62
73
  } );
63
74
 
@@ -81,41 +92,56 @@ const ControlledSyncUnits = () => {
81
92
  };
82
93
 
83
94
  describe( 'UnitControl', () => {
95
+ beforeEach( () => {
96
+ jest.useFakeTimers();
97
+ } );
98
+
99
+ afterEach( () => {
100
+ jest.runOnlyPendingTimers();
101
+ jest.useRealTimers();
102
+ } );
103
+
84
104
  describe( 'Basic rendering', () => {
85
105
  it( 'should render', () => {
86
106
  render( <UnitControl /> );
87
107
  const input = getInput();
88
108
  const select = getSelect();
89
109
 
90
- expect( input ).toBeTruthy();
91
- expect( select ).toBeTruthy();
110
+ expect( input ).toBeInTheDocument();
111
+ expect( select ).toBeInTheDocument();
92
112
  } );
93
113
 
94
114
  it( 'should render custom className', () => {
95
- render( <UnitControl className="hello" /> );
115
+ const { container: withoutClassName } = render( <UnitControl /> );
96
116
 
97
- const el = getComponent();
117
+ const { container: withClassName } = render(
118
+ <UnitControl className="hello" />
119
+ );
98
120
 
99
- expect( el.classList.contains( 'hello' ) ).toBe( true );
121
+ expect( withoutClassName.firstChild ).toMatchDiffSnapshot(
122
+ withClassName.firstChild
123
+ );
100
124
  } );
101
125
 
102
126
  it( 'should not render select, if units are disabled', () => {
103
127
  render( <UnitControl value="3em" units={ [] } /> );
104
128
  const input = getInput();
105
- const select = getSelect();
129
+ // Using `queryByRole` instead of `getSelect` because we need to test
130
+ // for this element NOT to be in the document.
131
+ const select = screen.queryByRole( 'combobox' );
106
132
 
107
- expect( input ).toBeTruthy();
108
- expect( select ).toBeFalsy();
133
+ expect( input ).toBeInTheDocument();
134
+ expect( select ).not.toBeInTheDocument();
109
135
  } );
110
136
 
111
137
  it( 'should render label if single units', () => {
112
138
  render( <UnitControl units={ [ { value: '%', label: '%' } ] } /> );
113
139
 
114
- const select = getSelect();
115
- const label = getUnitLabel();
140
+ const select = screen.queryByRole( 'combobox' );
141
+ const label = screen.getByText( '%' );
116
142
 
117
- expect( select ).toBeFalsy();
118
- expect( label ).toBeTruthy();
143
+ expect( select ).not.toBeInTheDocument();
144
+ expect( label ).toBeInTheDocument();
119
145
  } );
120
146
  } );
121
147
 
@@ -124,9 +150,7 @@ describe( 'UnitControl', () => {
124
150
  let state = '50px';
125
151
  const setState = jest.fn( ( value ) => ( state = value ) );
126
152
 
127
- const { user } = render(
128
- <UnitControl value={ state } onChange={ setState } />
129
- );
153
+ render( <UnitControl value={ state } onChange={ setState } /> );
130
154
 
131
155
  const input = getInput();
132
156
  await user.clear( input );
@@ -141,12 +165,11 @@ describe( 'UnitControl', () => {
141
165
  } );
142
166
 
143
167
  it( 'should increment value on UP press', async () => {
144
- let state = '50px';
145
- const setState = ( nextState ) => ( state = nextState );
168
+ let state: string | undefined = '50px';
169
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
170
+ ( state = nextState );
146
171
 
147
- const { user } = render(
148
- <UnitControl value={ state } onChange={ setState } />
149
- );
172
+ render( <UnitControl value={ state } onChange={ setState } /> );
150
173
 
151
174
  const input = getInput();
152
175
  await user.type( input, '{ArrowUp}' );
@@ -155,12 +178,11 @@ describe( 'UnitControl', () => {
155
178
  } );
156
179
 
157
180
  it( 'should increment value on UP + SHIFT press, with step', async () => {
158
- let state = '50px';
159
- const setState = ( nextState ) => ( state = nextState );
181
+ let state: string | undefined = '50px';
182
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
183
+ ( state = nextState );
160
184
 
161
- const { user } = render(
162
- <UnitControl value={ state } onChange={ setState } />
163
- );
185
+ render( <UnitControl value={ state } onChange={ setState } /> );
164
186
 
165
187
  const input = getInput();
166
188
  await user.type( input, '{Shift>}{ArrowUp}{/Shift}' );
@@ -169,12 +191,11 @@ describe( 'UnitControl', () => {
169
191
  } );
170
192
 
171
193
  it( 'should decrement value on DOWN press', async () => {
172
- let state = 50;
173
- const setState = ( nextState ) => ( state = nextState );
194
+ let state: string | number | undefined = 50;
195
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
196
+ ( state = nextState );
174
197
 
175
- const { user } = render(
176
- <UnitControl value={ state } onChange={ setState } />
177
- );
198
+ render( <UnitControl value={ state } onChange={ setState } /> );
178
199
 
179
200
  const input = getInput();
180
201
  await user.type( input, '{ArrowDown}' );
@@ -183,12 +204,11 @@ describe( 'UnitControl', () => {
183
204
  } );
184
205
 
185
206
  it( 'should decrement value on DOWN + SHIFT press, with step', async () => {
186
- let state = 50;
187
- const setState = ( nextState ) => ( state = nextState );
207
+ let state: string | number | undefined = 50;
208
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
209
+ ( state = nextState );
188
210
 
189
- const { user } = render(
190
- <UnitControl value={ state } onChange={ setState } />
191
- );
211
+ render( <UnitControl value={ state } onChange={ setState } /> );
192
212
 
193
213
  const input = getInput();
194
214
  await user.type( input, '{Shift>}{ArrowDown}{/Shift}' );
@@ -197,10 +217,11 @@ describe( 'UnitControl', () => {
197
217
  } );
198
218
 
199
219
  it( 'should cancel change when ESCAPE key is pressed', async () => {
200
- let state = 50;
201
- const setState = ( nextState ) => ( state = nextState );
220
+ let state: string | number | undefined = 50;
221
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
222
+ ( state = nextState );
202
223
 
203
- const { user } = render(
224
+ render(
204
225
  <UnitControl
205
226
  value={ state }
206
227
  onChange={ setState }
@@ -208,95 +229,83 @@ describe( 'UnitControl', () => {
208
229
  />
209
230
  );
210
231
 
211
- const input = getInput();
232
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
233
+ const input = getInput( { isInputTypeText: true } );
212
234
  await user.clear( input );
213
235
  await user.type( input, '300px' );
214
236
 
215
237
  expect( input.value ).toBe( '300px' );
216
238
  expect( state ).toBe( 50 );
217
239
 
218
- user.keyboard( '{Escape}' );
240
+ await user.keyboard( '{Escape}' );
219
241
 
220
242
  expect( input.value ).toBe( '50' );
221
243
  expect( state ).toBe( 50 );
222
244
  } );
223
245
 
224
246
  it( 'should run onBlur callback when quantity input is blurred', async () => {
225
- let state = '33%';
226
247
  const onChangeSpy = jest.fn();
227
248
  const onBlurSpy = jest.fn();
228
- const setState = ( nextState ) => {
249
+
250
+ let state: string | undefined = '33%';
251
+ const setState: UnitControlOnChangeCallback = ( nextState ) => {
229
252
  onChangeSpy( nextState );
230
253
  state = nextState;
231
254
  };
232
255
 
233
- const { user } = render(
234
- <>
235
- <button>Click me</button>
236
- <UnitControl
237
- value={ state }
238
- onChange={ setState }
239
- onBlur={ onBlurSpy }
240
- />
241
- </>
256
+ render(
257
+ <UnitControl
258
+ value={ state }
259
+ onChange={ setState }
260
+ onBlur={ onBlurSpy }
261
+ />
242
262
  );
243
263
 
244
264
  const input = getInput();
245
265
  await user.clear( input );
246
266
  await user.type( input, '41' );
247
267
 
248
- await waitFor( () =>
249
- expect( onChangeSpy ).toHaveBeenCalledTimes( 3 )
250
- );
268
+ expect( onChangeSpy ).toHaveBeenCalledTimes( 3 );
251
269
  expect( onChangeSpy ).toHaveBeenLastCalledWith( '41%' );
252
270
 
253
- // Clicking on the button should cause the `onBlur` callback to fire.
254
- const button = screen.getByRole( 'button' );
255
- await user.click( button );
271
+ // Clicking document.body to trigger a blur event on the input.
272
+ await user.click( document.body );
256
273
 
257
- await waitFor( () =>
258
- expect( onBlurSpy ).toHaveBeenCalledTimes( 1 )
259
- );
274
+ expect( onBlurSpy ).toHaveBeenCalledTimes( 1 );
260
275
  } );
261
276
 
262
277
  it( 'should invoke onChange and onUnitChange callbacks when isPressEnterToChange is true and the component is blurred with an uncommitted value', async () => {
263
- let state = '15px';
264
-
265
278
  const onUnitChangeSpy = jest.fn();
266
279
  const onChangeSpy = jest.fn();
267
280
 
268
- const setState = ( nextState ) => {
281
+ let state: string | undefined = '15px';
282
+ const setState: UnitControlOnChangeCallback = ( nextState ) => {
269
283
  onChangeSpy( nextState );
270
284
  state = nextState;
271
285
  };
272
286
 
273
- const { user } = render(
274
- <>
275
- <button>Click me</button>
276
- <UnitControl
277
- value={ state }
278
- onChange={ setState }
279
- onUnitChange={ onUnitChangeSpy }
280
- isPressEnterToChange
281
- />
282
- </>
287
+ render(
288
+ <UnitControl
289
+ value={ state }
290
+ onChange={ setState }
291
+ onUnitChange={ onUnitChangeSpy }
292
+ isPressEnterToChange
293
+ />
283
294
  );
284
295
 
285
- const input = getInput();
296
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
297
+ const input = getInput( { isInputTypeText: true } );
286
298
  await user.clear( input );
287
299
  await user.type( input, '41vh' );
288
300
 
289
301
  // This is because `isPressEnterToChange` is `true`
290
302
  expect( onChangeSpy ).not.toHaveBeenCalled();
303
+ expect( onUnitChangeSpy ).not.toHaveBeenCalled();
291
304
 
292
- // Clicking on the button should cause the `onBlur` callback to fire.
293
- const button = screen.getByRole( 'button' );
294
- await user.click( button );
295
-
296
- await waitFor( () =>
297
- expect( onChangeSpy ).toHaveBeenCalledTimes( 1 )
298
- );
305
+ // Clicking document.body to trigger a blur event on the input.
306
+ await user.click( document.body );
299
307
 
308
+ expect( onChangeSpy ).toHaveBeenCalledTimes( 1 );
300
309
  expect( onChangeSpy ).toHaveBeenLastCalledWith( '41vh' );
301
310
 
302
311
  expect( onUnitChangeSpy ).toHaveBeenCalledTimes( 1 );
@@ -305,16 +314,47 @@ describe( 'UnitControl', () => {
305
314
  expect.anything()
306
315
  );
307
316
  } );
317
+
318
+ it( 'should update value correctly when typed and blurred when a single unit is passed', async () => {
319
+ const onChangeSpy = jest.fn();
320
+ render(
321
+ <>
322
+ <button>Click me</button>
323
+ <UnitControl
324
+ units={ [ { value: '%', label: '%' } ] }
325
+ onChange={ onChangeSpy }
326
+ />
327
+ </>
328
+ );
329
+
330
+ const input = getInput();
331
+ await user.type( input, '62' );
332
+
333
+ expect( onChangeSpy ).toHaveBeenLastCalledWith(
334
+ '62%',
335
+ expect.anything()
336
+ );
337
+
338
+ // Start counting again calls to `onChangeSpy`.
339
+ onChangeSpy.mockClear();
340
+
341
+ // Clicking on the button should cause the `onBlur` callback to fire.
342
+ const button = screen.getByRole( 'button' );
343
+ await user.click( button );
344
+
345
+ expect( onChangeSpy ).not.toHaveBeenCalled();
346
+ } );
308
347
  } );
309
348
 
310
349
  describe( 'Unit', () => {
311
350
  it( 'should update unit value on change', async () => {
312
- let state = '14rem';
313
- const setState = ( nextState ) => ( state = nextState );
351
+ let state: string | undefined = '14rem';
352
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
353
+ ( state = nextState );
314
354
 
315
355
  const spy = jest.fn();
316
356
 
317
- const { user } = render(
357
+ render(
318
358
  <UnitControl
319
359
  value={ state }
320
360
  onChange={ setState }
@@ -337,8 +377,7 @@ describe( 'UnitControl', () => {
337
377
 
338
378
  render( <UnitControl units={ units } /> );
339
379
 
340
- const select = getSelect();
341
- const options = select.querySelectorAll( 'option' );
380
+ const options = getSelectOptions();
342
381
 
343
382
  expect( options.length ).toBe( 2 );
344
383
 
@@ -349,15 +388,16 @@ describe( 'UnitControl', () => {
349
388
  } );
350
389
 
351
390
  it( 'should reset value on unit change, if unit has default value', async () => {
352
- let state = 50;
353
- const setState = ( nextState ) => ( state = nextState );
391
+ let state: string | number | undefined = 50;
392
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
393
+ ( state = nextState );
354
394
 
355
395
  const units = [
356
396
  { value: 'pt', label: 'pt', default: 25 },
357
397
  { value: 'vmax', label: 'vmax', default: 75 },
358
398
  ];
359
399
 
360
- const { user } = render(
400
+ render(
361
401
  <UnitControl
362
402
  isResetValueOnUnitChange
363
403
  units={ units }
@@ -377,15 +417,16 @@ describe( 'UnitControl', () => {
377
417
  } );
378
418
 
379
419
  it( 'should not reset value on unit change, if disabled', async () => {
380
- let state = 50;
381
- const setState = ( nextState ) => ( state = nextState );
420
+ let state: string | number | undefined = 50;
421
+ const setState: UnitControlOnChangeCallback = ( nextState ) =>
422
+ ( state = nextState );
382
423
 
383
424
  const units = [
384
425
  { value: 'pt', label: 'pt', default: 25 },
385
426
  { value: 'vmax', label: 'vmax', default: 75 },
386
427
  ];
387
428
 
388
- const { user } = render(
429
+ render(
389
430
  <UnitControl
390
431
  isResetValueOnUnitChange={ false }
391
432
  value={ state }
@@ -405,10 +446,11 @@ describe( 'UnitControl', () => {
405
446
  } );
406
447
 
407
448
  it( 'should set correct unit if single units', async () => {
408
- let state = '50%';
409
- const setState = ( value ) => ( state = value );
449
+ let state: string | undefined = '50%';
450
+ const setState: UnitControlOnChangeCallback = ( value ) =>
451
+ ( state = value );
410
452
 
411
- const { user } = render(
453
+ render(
412
454
  <UnitControl
413
455
  value={ state }
414
456
  units={ [ { value: '%', label: '%' } ] }
@@ -420,11 +462,11 @@ describe( 'UnitControl', () => {
420
462
  await user.clear( input );
421
463
  await user.type( input, '62' );
422
464
 
423
- await waitFor( () => expect( state ).toBe( '62%' ) );
465
+ expect( state ).toBe( '62%' );
424
466
  } );
425
467
 
426
468
  it( 'should update unit value when a new raw value is passed', async () => {
427
- const { user } = render( <ControlledSyncUnits /> );
469
+ render( <ControlledSyncUnits /> );
428
470
 
429
471
  const [ inputA, inputB ] = screen.getAllByRole( 'spinbutton' );
430
472
  const [ selectA, selectB ] = screen.getAllByRole( 'combobox' );
@@ -442,12 +484,12 @@ describe( 'UnitControl', () => {
442
484
 
443
485
  await user.selectOptions( selectA, remOptionA );
444
486
 
445
- await waitFor( () => expect( selectB ).toHaveValue( 'rem' ) );
487
+ expect( selectB ).toHaveValue( 'rem' );
446
488
  expect( selectA ).toHaveValue( 'rem' );
447
489
 
448
490
  await user.selectOptions( selectB, vwOptionB );
449
491
 
450
- await waitFor( () => expect( selectA ).toHaveValue( 'vw' ) );
492
+ expect( selectA ).toHaveValue( 'vw' );
451
493
  expect( selectB ).toHaveValue( 'vw' );
452
494
  } );
453
495
 
@@ -457,9 +499,7 @@ describe( 'UnitControl', () => {
457
499
  { value: 'vmax', label: 'vmax' },
458
500
  ];
459
501
 
460
- const { user } = render(
461
- <UnitControl units={ units } value="5" />
462
- );
502
+ render( <UnitControl units={ units } value="5" /> );
463
503
 
464
504
  const select = getSelect();
465
505
  await user.selectOptions( select, [ 'vmax' ] );
@@ -474,44 +514,36 @@ describe( 'UnitControl', () => {
474
514
  const onUnitChangeSpy = jest.fn();
475
515
  const onBlurSpy = jest.fn();
476
516
 
477
- const { user } = render(
478
- <>
479
- <button>Click me</button>
480
- <UnitControl
481
- value="15px"
482
- onUnitChange={ onUnitChangeSpy }
483
- onBlur={ onBlurSpy }
484
- />
485
- </>
517
+ render(
518
+ <UnitControl
519
+ value="15px"
520
+ onUnitChange={ onUnitChangeSpy }
521
+ onBlur={ onBlurSpy }
522
+ />
486
523
  );
487
524
 
488
525
  const select = getSelect();
489
526
  await user.selectOptions( select, [ 'em' ] );
490
527
 
491
- await waitFor( () =>
492
- expect( onUnitChangeSpy ).toHaveBeenCalledTimes( 1 )
493
- );
528
+ expect( onUnitChangeSpy ).toHaveBeenCalledTimes( 1 );
494
529
  expect( onUnitChangeSpy ).toHaveBeenLastCalledWith(
495
530
  'em',
496
531
  expect.anything()
497
532
  );
498
533
 
499
- // Clicking on the button should cause the `onBlur` callback to fire.
500
- const button = screen.getByRole( 'button' );
501
- await user.click( button );
534
+ // Clicking document.body to trigger a blur event on the input.
535
+ await user.click( document.body );
502
536
 
503
- await waitFor( () =>
504
- expect( onBlurSpy ).toHaveBeenCalledTimes( 1 )
505
- );
537
+ expect( onBlurSpy ).toHaveBeenCalledTimes( 1 );
506
538
  } );
507
539
  } );
508
540
 
509
541
  describe( 'Unit Parser', () => {
510
- let state = '10px';
511
- const setState = jest.fn( ( nextState ) => ( state = nextState ) );
512
-
513
542
  it( 'should parse unit from input', async () => {
514
- const { user } = render(
543
+ let state = '10px';
544
+ const setState = jest.fn( ( nextState ) => ( state = nextState ) );
545
+
546
+ render(
515
547
  <UnitControl
516
548
  value={ state }
517
549
  onChange={ setState }
@@ -519,16 +551,20 @@ describe( 'UnitControl', () => {
519
551
  />
520
552
  );
521
553
 
522
- const input = getInput();
554
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
555
+ const input = getInput( { isInputTypeText: true } );
523
556
  await user.clear( input );
524
557
  await user.type( input, '55 em' );
525
- user.keyboard( '{Enter}' );
558
+ await user.keyboard( '{Enter}' );
526
559
 
527
560
  expect( state ).toBe( '55em' );
528
561
  } );
529
562
 
530
563
  it( 'should parse PX unit from input', async () => {
531
- const { user } = render(
564
+ let state = '10px';
565
+ const setState = jest.fn( ( nextState ) => ( state = nextState ) );
566
+
567
+ render(
532
568
  <UnitControl
533
569
  value={ state }
534
570
  onChange={ setState }
@@ -536,16 +572,20 @@ describe( 'UnitControl', () => {
536
572
  />
537
573
  );
538
574
 
539
- const input = getInput();
575
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
576
+ const input = getInput( { isInputTypeText: true } );
540
577
  await user.clear( input );
541
578
  await user.type( input, '61 PX' );
542
- user.keyboard( '{Enter}' );
579
+ await user.keyboard( '{Enter}' );
543
580
 
544
581
  expect( state ).toBe( '61px' );
545
582
  } );
546
583
 
547
584
  it( 'should parse EM unit from input', async () => {
548
- const { user } = render(
585
+ let state = '10px';
586
+ const setState = jest.fn( ( nextState ) => ( state = nextState ) );
587
+
588
+ render(
549
589
  <UnitControl
550
590
  value={ state }
551
591
  onChange={ setState }
@@ -553,16 +593,20 @@ describe( 'UnitControl', () => {
553
593
  />
554
594
  );
555
595
 
556
- const input = getInput();
596
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
597
+ const input = getInput( { isInputTypeText: true } );
557
598
  await user.clear( input );
558
599
  await user.type( input, '55 em' );
559
- user.keyboard( '{Enter}' );
600
+ await user.keyboard( '{Enter}' );
560
601
 
561
602
  expect( state ).toBe( '55em' );
562
603
  } );
563
604
 
564
605
  it( 'should parse % unit from input', async () => {
565
- const { user } = render(
606
+ let state = '10px';
607
+ const setState = jest.fn( ( nextState ) => ( state = nextState ) );
608
+
609
+ render(
566
610
  <UnitControl
567
611
  value={ state }
568
612
  onChange={ setState }
@@ -570,16 +614,20 @@ describe( 'UnitControl', () => {
570
614
  />
571
615
  );
572
616
 
573
- const input = getInput();
617
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
618
+ const input = getInput( { isInputTypeText: true } );
574
619
  await user.clear( input );
575
620
  await user.type( input, '-10 %' );
576
- user.keyboard( '{Enter}' );
621
+ await user.keyboard( '{Enter}' );
577
622
 
578
623
  expect( state ).toBe( '-10%' );
579
624
  } );
580
625
 
581
626
  it( 'should parse REM unit from input', async () => {
582
- const { user } = render(
627
+ let state = '10px';
628
+ const setState = jest.fn( ( nextState ) => ( state = nextState ) );
629
+
630
+ render(
583
631
  <UnitControl
584
632
  value={ state }
585
633
  onChange={ setState }
@@ -587,10 +635,11 @@ describe( 'UnitControl', () => {
587
635
  />
588
636
  );
589
637
 
590
- const input = getInput();
638
+ // Input type is `text` when the `isPressEnterToChange` prop is passed
639
+ const input = getInput( { isInputTypeText: true } );
591
640
  await user.clear( input );
592
641
  await user.type( input, '123 rEm ' );
593
- user.keyboard( '{Enter}' );
642
+ await user.keyboard( '{Enter}' );
594
643
 
595
644
  expect( state ).toBe( '123rem' );
596
645
  } );
@@ -604,7 +653,7 @@ describe( 'UnitControl', () => {
604
653
 
605
654
  rerender( <UnitControl value={ '20vh' } /> );
606
655
 
607
- await waitFor( () => expect( select.value ).toBe( 'vh' ) );
656
+ expect( select.value ).toBe( 'vh' );
608
657
  } );
609
658
 
610
659
  it( 'should fallback to default unit if parsed unit is invalid', () => {
@@ -625,7 +674,7 @@ describe( 'UnitControl', () => {
625
674
  );
626
675
 
627
676
  const select = getSelect();
628
- const options = select.querySelectorAll( 'option' );
677
+ const options = getSelectOptions();
629
678
 
630
679
  expect( select.value ).toBe( '%' );
631
680
  expect( options.length ).toBe( 3 );