@wordpress/components 27.0.0 → 27.2.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 (314) hide show
  1. package/CHANGELOG.md +50 -2
  2. package/build/base-control/index.native.js.map +1 -1
  3. package/build/border-box-control/border-box-control/component.js.map +1 -1
  4. package/build/border-box-control/border-box-control-split-controls/component.js.map +1 -1
  5. package/build/border-control/border-control-dropdown/component.js.map +1 -1
  6. package/build/button/index.js +4 -5
  7. package/build/button/index.js.map +1 -1
  8. package/build/button/index.native.js.map +1 -1
  9. package/build/button/types.js.map +1 -1
  10. package/build/confirm-dialog/component.js.map +1 -1
  11. package/build/custom-select-control-v2/default-component/index.js.map +1 -1
  12. package/build/custom-select-control-v2/index.js +2 -2
  13. package/build/custom-select-control-v2/index.js.map +1 -1
  14. package/build/custom-select-control-v2/types.js.map +1 -1
  15. package/build/date-time/date/styles.js +7 -7
  16. package/build/date-time/date/styles.js.map +1 -1
  17. package/build/draggable/index.native.js +2 -2
  18. package/build/draggable/index.native.js.map +1 -1
  19. package/build/dropdown-menu/index.native.js.map +1 -1
  20. package/build/flex/flex/hook.js +1 -1
  21. package/build/flex/flex/hook.js.map +1 -1
  22. package/build/font-size-picker/index.native.js.map +1 -1
  23. package/build/form-token-field/index.js +1 -1
  24. package/build/form-token-field/index.js.map +1 -1
  25. package/build/h-stack/hook.js +6 -1
  26. package/build/h-stack/hook.js.map +1 -1
  27. package/build/input-control/index.js +1 -1
  28. package/build/input-control/index.js.map +1 -1
  29. package/build/mobile/bottom-sheet/button.native.js.map +1 -1
  30. package/build/mobile/bottom-sheet/index.native.js.map +1 -1
  31. package/build/mobile/bottom-sheet/range-cell.native.js.map +1 -1
  32. package/build/mobile/bottom-sheet/stepper-cell/index.native.js.map +1 -1
  33. package/build/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  34. package/build/mobile/bottom-sheet-text-control/index.native.js.map +1 -1
  35. package/build/mobile/gradient/index.native.js.map +1 -1
  36. package/build/mobile/image/index.native.js +4 -13
  37. package/build/mobile/image/index.native.js.map +1 -1
  38. package/build/mobile/media-edit/index.native.js.map +1 -1
  39. package/build/palette-edit/index.js +18 -12
  40. package/build/palette-edit/index.js.map +1 -1
  41. package/build/query-controls/index.native.js.map +1 -1
  42. package/build/range-control/index.js.map +1 -1
  43. package/build/search-control/index.native.js.map +1 -1
  44. package/build/snackbar/index.js +3 -2
  45. package/build/snackbar/index.js.map +1 -1
  46. package/build/snackbar/list.js +2 -1
  47. package/build/snackbar/list.js.map +1 -1
  48. package/build/snackbar/types.js.map +1 -1
  49. package/build/tabs/index.js +7 -7
  50. package/build/tabs/index.js.map +1 -1
  51. package/build/tabs/types.js.map +1 -1
  52. package/build/text-control/types.js.map +1 -1
  53. package/build/toggle-group-control/toggle-group-control-option-base/component.js +4 -1
  54. package/build/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
  55. package/build/tools-panel/tools-panel-header/component.js +1 -1
  56. package/build/tools-panel/tools-panel-header/component.js.map +1 -1
  57. package/build/utils/config-values.js +1 -1
  58. package/build/utils/config-values.js.map +1 -1
  59. package/build/utils/hooks/index.js +0 -7
  60. package/build/utils/hooks/index.js.map +1 -1
  61. package/build/utils/input/base.js +2 -2
  62. package/build/utils/input/base.js.map +1 -1
  63. package/build-module/base-control/index.native.js.map +1 -1
  64. package/build-module/border-box-control/border-box-control/component.js.map +1 -1
  65. package/build-module/border-box-control/border-box-control-split-controls/component.js.map +1 -1
  66. package/build-module/border-control/border-control-dropdown/component.js.map +1 -1
  67. package/build-module/button/index.js +4 -5
  68. package/build-module/button/index.js.map +1 -1
  69. package/build-module/button/index.native.js.map +1 -1
  70. package/build-module/button/types.js.map +1 -1
  71. package/build-module/confirm-dialog/component.js.map +1 -1
  72. package/build-module/custom-select-control-v2/default-component/index.js.map +1 -1
  73. package/build-module/custom-select-control-v2/index.js +1 -1
  74. package/build-module/custom-select-control-v2/index.js.map +1 -1
  75. package/build-module/custom-select-control-v2/types.js.map +1 -1
  76. package/build-module/date-time/date/styles.js +7 -7
  77. package/build-module/date-time/date/styles.js.map +1 -1
  78. package/build-module/draggable/index.native.js +2 -2
  79. package/build-module/draggable/index.native.js.map +1 -1
  80. package/build-module/dropdown-menu/index.native.js.map +1 -1
  81. package/build-module/flex/flex/hook.js +1 -1
  82. package/build-module/flex/flex/hook.js.map +1 -1
  83. package/build-module/font-size-picker/index.native.js.map +1 -1
  84. package/build-module/form-token-field/index.js +1 -1
  85. package/build-module/form-token-field/index.js.map +1 -1
  86. package/build-module/h-stack/hook.js +6 -1
  87. package/build-module/h-stack/hook.js.map +1 -1
  88. package/build-module/input-control/index.js +1 -1
  89. package/build-module/input-control/index.js.map +1 -1
  90. package/build-module/mobile/bottom-sheet/button.native.js.map +1 -1
  91. package/build-module/mobile/bottom-sheet/index.native.js.map +1 -1
  92. package/build-module/mobile/bottom-sheet/range-cell.native.js.map +1 -1
  93. package/build-module/mobile/bottom-sheet/stepper-cell/index.native.js.map +1 -1
  94. package/build-module/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  95. package/build-module/mobile/bottom-sheet-text-control/index.native.js.map +1 -1
  96. package/build-module/mobile/gradient/index.native.js.map +1 -1
  97. package/build-module/mobile/image/index.native.js +6 -15
  98. package/build-module/mobile/image/index.native.js.map +1 -1
  99. package/build-module/mobile/media-edit/index.native.js.map +1 -1
  100. package/build-module/palette-edit/index.js +17 -11
  101. package/build-module/palette-edit/index.js.map +1 -1
  102. package/build-module/query-controls/index.native.js.map +1 -1
  103. package/build-module/range-control/index.js.map +1 -1
  104. package/build-module/search-control/index.native.js.map +1 -1
  105. package/build-module/snackbar/index.js +3 -2
  106. package/build-module/snackbar/index.js.map +1 -1
  107. package/build-module/snackbar/list.js +2 -1
  108. package/build-module/snackbar/list.js.map +1 -1
  109. package/build-module/snackbar/types.js.map +1 -1
  110. package/build-module/tabs/index.js +7 -7
  111. package/build-module/tabs/index.js.map +1 -1
  112. package/build-module/tabs/types.js.map +1 -1
  113. package/build-module/text-control/types.js.map +1 -1
  114. package/build-module/toggle-group-control/toggle-group-control-option-base/component.js +4 -1
  115. package/build-module/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
  116. package/build-module/tools-panel/tools-panel-header/component.js +1 -1
  117. package/build-module/tools-panel/tools-panel-header/component.js.map +1 -1
  118. package/build-module/utils/config-values.js +1 -1
  119. package/build-module/utils/config-values.js.map +1 -1
  120. package/build-module/utils/hooks/index.js +0 -1
  121. package/build-module/utils/hooks/index.js.map +1 -1
  122. package/build-module/utils/input/base.js +2 -2
  123. package/build-module/utils/input/base.js.map +1 -1
  124. package/build-style/style-rtl.css +33 -23
  125. package/build-style/style.css +33 -23
  126. package/build-types/box-control/styles/box-control-styles.d.ts +1 -1
  127. package/build-types/button/deprecated.d.ts +4 -10
  128. package/build-types/button/deprecated.d.ts.map +1 -1
  129. package/build-types/button/index.d.ts +3 -3
  130. package/build-types/button/index.d.ts.map +1 -1
  131. package/build-types/button/stories/e2e/index.story.d.ts +1 -1
  132. package/build-types/button/stories/e2e/index.story.d.ts.map +1 -1
  133. package/build-types/button/stories/index.story.d.ts +7 -7
  134. package/build-types/button/stories/index.story.d.ts.map +1 -1
  135. package/build-types/button/types.d.ts +37 -8
  136. package/build-types/button/types.d.ts.map +1 -1
  137. package/build-types/color-picker/styles.d.ts +1 -1
  138. package/build-types/custom-select-control-v2/default-component/index.d.ts +2 -1
  139. package/build-types/custom-select-control-v2/default-component/index.d.ts.map +1 -1
  140. package/build-types/custom-select-control-v2/index.d.ts +1 -1
  141. package/build-types/custom-select-control-v2/index.d.ts.map +1 -1
  142. package/build-types/custom-select-control-v2/legacy-component/test/index.d.ts +2 -0
  143. package/build-types/custom-select-control-v2/legacy-component/test/index.d.ts.map +1 -0
  144. package/build-types/custom-select-control-v2/stories/default.story.d.ts +4 -3
  145. package/build-types/custom-select-control-v2/stories/default.story.d.ts.map +1 -1
  146. package/build-types/custom-select-control-v2/stories/legacy.story.d.ts +2 -2
  147. package/build-types/custom-select-control-v2/stories/legacy.story.d.ts.map +1 -1
  148. package/build-types/custom-select-control-v2/types.d.ts +0 -1
  149. package/build-types/custom-select-control-v2/types.d.ts.map +1 -1
  150. package/build-types/date-time/date/styles.d.ts +1 -1
  151. package/build-types/dropdown/stories/index.story.d.ts +1 -0
  152. package/build-types/dropdown/stories/index.story.d.ts.map +1 -1
  153. package/build-types/flex/flex/hook.d.ts +2 -3
  154. package/build-types/flex/flex/hook.d.ts.map +1 -1
  155. package/build-types/font-size-picker/styles.d.ts +1 -1
  156. package/build-types/form-token-field/index.d.ts +1 -1
  157. package/build-types/h-stack/hook.d.ts +2 -4
  158. package/build-types/h-stack/hook.d.ts.map +1 -1
  159. package/build-types/input-control/index.d.ts +1 -1
  160. package/build-types/input-control/stories/index.story.d.ts.map +1 -1
  161. package/build-types/navigation/stories/utils/hide-if-empty.d.ts.map +1 -1
  162. package/build-types/navigation/styles/navigation-styles.d.ts +1 -1
  163. package/build-types/navigator/navigator-back-button/component.d.ts +0 -1
  164. package/build-types/navigator/navigator-back-button/component.d.ts.map +1 -1
  165. package/build-types/navigator/navigator-back-button/hook.d.ts +1 -2
  166. package/build-types/navigator/navigator-back-button/hook.d.ts.map +1 -1
  167. package/build-types/navigator/navigator-button/component.d.ts +0 -1
  168. package/build-types/navigator/navigator-button/component.d.ts.map +1 -1
  169. package/build-types/navigator/navigator-button/hook.d.ts +1 -2
  170. package/build-types/navigator/navigator-button/hook.d.ts.map +1 -1
  171. package/build-types/navigator/navigator-to-parent-button/component.d.ts +0 -1
  172. package/build-types/navigator/navigator-to-parent-button/component.d.ts.map +1 -1
  173. package/build-types/number-control/styles/number-control-styles.d.ts +1 -1
  174. package/build-types/palette-edit/index.d.ts +6 -3
  175. package/build-types/palette-edit/index.d.ts.map +1 -1
  176. package/build-types/palette-edit/styles.d.ts +2 -2
  177. package/build-types/radio-group/stories/index.story.d.ts.map +1 -1
  178. package/build-types/snackbar/index.d.ts +5 -2
  179. package/build-types/snackbar/index.d.ts.map +1 -1
  180. package/build-types/snackbar/list.d.ts.map +1 -1
  181. package/build-types/snackbar/test/index.d.ts +2 -0
  182. package/build-types/snackbar/test/index.d.ts.map +1 -0
  183. package/build-types/snackbar/test/list.d.ts +2 -0
  184. package/build-types/snackbar/test/list.d.ts.map +1 -0
  185. package/build-types/snackbar/types.d.ts +18 -2
  186. package/build-types/snackbar/types.d.ts.map +1 -1
  187. package/build-types/tabs/index.d.ts +1 -1
  188. package/build-types/tabs/types.d.ts +1 -1
  189. package/build-types/text-control/index.d.ts +1 -1
  190. package/build-types/text-control/types.d.ts +1 -1
  191. package/build-types/text-control/types.d.ts.map +1 -1
  192. package/build-types/toggle-group-control/toggle-group-control-option-base/component.d.ts.map +1 -1
  193. package/build-types/toolbar/toolbar-button/index.d.ts +4 -10
  194. package/build-types/toolbar/toolbar-button/index.d.ts.map +1 -1
  195. package/build-types/utils/hooks/index.d.ts +0 -1
  196. package/build-types/v-stack/hook.d.ts +2 -4
  197. package/build-types/v-stack/hook.d.ts.map +1 -1
  198. package/package.json +19 -19
  199. package/src/base-control/index.native.js +1 -1
  200. package/src/base-control/test/index.tsx +1 -1
  201. package/src/border-box-control/border-box-control/component.tsx +1 -1
  202. package/src/border-box-control/border-box-control-split-controls/component.tsx +4 -4
  203. package/src/border-control/border-control-dropdown/component.tsx +1 -1
  204. package/src/button/index.native.js +1 -1
  205. package/src/button/index.tsx +3 -4
  206. package/src/button/style.scss +1 -3
  207. package/src/button/test/index.tsx +6 -6
  208. package/src/button/types.ts +37 -9
  209. package/src/circular-option-picker/test/index.tsx +2 -4
  210. package/src/combobox-control/test/index.tsx +1 -1
  211. package/src/confirm-dialog/README.md +7 -0
  212. package/src/confirm-dialog/component.tsx +1 -1
  213. package/src/confirm-dialog/test/index.tsx +5 -21
  214. package/src/custom-select-control-v2/default-component/index.tsx +4 -1
  215. package/src/custom-select-control-v2/index.tsx +1 -1
  216. package/src/custom-select-control-v2/legacy-component/test/index.tsx +457 -0
  217. package/src/custom-select-control-v2/stories/legacy.story.tsx +5 -6
  218. package/src/custom-select-control-v2/test/index.tsx +279 -749
  219. package/src/custom-select-control-v2/types.ts +0 -1
  220. package/src/date-time/date/styles.ts +2 -2
  221. package/src/dimension-control/test/__snapshots__/index.test.js.snap +4 -4
  222. package/src/disabled/test/index.tsx +1 -1
  223. package/src/draggable/index.native.js +2 -2
  224. package/src/draggable/test/index.native.js +6 -2
  225. package/src/dropdown/stories/index.story.tsx +19 -0
  226. package/src/dropdown/style.scss +26 -0
  227. package/src/dropdown-menu/index.native.js +2 -2
  228. package/src/dropdown-menu/style.scss +0 -25
  229. package/src/flex/flex/README.md +2 -2
  230. package/src/flex/flex/hook.ts +1 -1
  231. package/src/font-size-picker/index.native.js +2 -2
  232. package/src/form-token-field/README.md +1 -1
  233. package/src/form-token-field/index.tsx +2 -2
  234. package/src/grid/README.md +11 -11
  235. package/src/h-stack/README.md +6 -6
  236. package/src/h-stack/hook.tsx +2 -1
  237. package/src/h-stack/test/index.tsx +10 -0
  238. package/src/heading/README.md +1 -1
  239. package/src/heading/test/__snapshots__/index.tsx.snap +3 -3
  240. package/src/input-control/README.md +1 -1
  241. package/src/input-control/index.tsx +1 -1
  242. package/src/input-control/stories/index.story.tsx +1 -0
  243. package/src/item-group/test/__snapshots__/index.js.snap +11 -11
  244. package/src/item-group/test/index.js +2 -2
  245. package/src/mobile/bottom-sheet/bottom-sheet-navigation/test/navigation-container.native.js +10 -15
  246. package/src/mobile/bottom-sheet/button.native.js +1 -5
  247. package/src/mobile/bottom-sheet/index.native.js +2 -2
  248. package/src/mobile/bottom-sheet/range-cell.native.js +1 -1
  249. package/src/mobile/bottom-sheet/stepper-cell/index.native.js +2 -2
  250. package/src/mobile/bottom-sheet-select-control/README.md +1 -1
  251. package/src/mobile/bottom-sheet-select-control/index.native.js +1 -1
  252. package/src/mobile/bottom-sheet-text-control/index.native.js +1 -1
  253. package/src/mobile/gradient/index.native.js +1 -1
  254. package/src/mobile/image/index.native.js +8 -23
  255. package/src/mobile/media-edit/index.native.js +1 -1
  256. package/src/modal/test/index.tsx +1 -1
  257. package/src/navigation/stories/utils/hide-if-empty.tsx +2 -6
  258. package/src/palette-edit/index.tsx +23 -23
  259. package/src/palette-edit/test/index.tsx +21 -17
  260. package/src/placeholder/style.scss +5 -1
  261. package/src/popover/test/index.tsx +1 -4
  262. package/src/progress-bar/README.md +1 -1
  263. package/src/query-controls/index.native.js +2 -2
  264. package/src/radio-control/README.md +3 -3
  265. package/src/radio-group/stories/index.story.tsx +1 -0
  266. package/src/range-control/index.tsx +3 -3
  267. package/src/range-control/test/index.tsx +2 -2
  268. package/src/resizable-box/resize-tooltip/README.md +2 -2
  269. package/src/search-control/index.native.js +1 -1
  270. package/src/snackbar/index.tsx +5 -2
  271. package/src/snackbar/list.tsx +6 -1
  272. package/src/snackbar/stories/list.story.tsx +0 -3
  273. package/src/snackbar/test/index.tsx +267 -0
  274. package/src/snackbar/test/list.tsx +46 -0
  275. package/src/snackbar/types.ts +31 -3
  276. package/src/tabs/README.md +18 -18
  277. package/src/tabs/index.tsx +7 -7
  278. package/src/tabs/stories/index.story.tsx +1 -1
  279. package/src/tabs/test/index.tsx +30 -30
  280. package/src/tabs/types.ts +1 -1
  281. package/src/text/test/__snapshots__/index.tsx.snap +3 -3
  282. package/src/text-control/types.ts +12 -1
  283. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +14 -10
  284. package/src/toggle-group-control/test/index.tsx +1 -1
  285. package/src/toggle-group-control/toggle-group-control-option-base/component.tsx +12 -10
  286. package/src/tools-panel/stories/index.story.tsx +8 -8
  287. package/src/tools-panel/test/index.tsx +10 -28
  288. package/src/tools-panel/tools-panel-header/component.tsx +1 -1
  289. package/src/tooltip/style.scss +2 -1
  290. package/src/tooltip/test/index.native.js +3 -3
  291. package/src/tree-grid/test/index.tsx +1 -1
  292. package/src/truncate/README.md +5 -5
  293. package/src/utils/config-values.js +1 -1
  294. package/src/utils/hooks/index.js +0 -1
  295. package/src/utils/input/base.js +1 -1
  296. package/src/v-stack/README.md +6 -6
  297. package/src/v-stack/test/index.tsx +10 -0
  298. package/tsconfig.json +1 -0
  299. package/tsconfig.tsbuildinfo +1 -1
  300. package/build/custom-select-control-v2/legacy-adapter.js +0 -29
  301. package/build/custom-select-control-v2/legacy-adapter.js.map +0 -1
  302. package/build/utils/hooks/use-latest-ref.js +0 -33
  303. package/build/utils/hooks/use-latest-ref.js.map +0 -1
  304. package/build-module/custom-select-control-v2/legacy-adapter.js +0 -21
  305. package/build-module/custom-select-control-v2/legacy-adapter.js.map +0 -1
  306. package/build-module/utils/hooks/use-latest-ref.js +0 -27
  307. package/build-module/utils/hooks/use-latest-ref.js.map +0 -1
  308. package/build-types/custom-select-control-v2/legacy-adapter.d.ts +0 -6
  309. package/build-types/custom-select-control-v2/legacy-adapter.d.ts.map +0 -1
  310. package/build-types/utils/hooks/use-latest-ref.d.ts +0 -15
  311. package/build-types/utils/hooks/use-latest-ref.d.ts.map +0 -1
  312. package/src/custom-select-control-v2/legacy-adapter.tsx +0 -25
  313. package/src/utils/hooks/test/use-latest-ref.js +0 -119
  314. package/src/utils/hooks/use-latest-ref.ts +0 -29
@@ -0,0 +1,457 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+ import { click, press, sleep, type, waitFor } from '@ariakit/test';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { useState } from '@wordpress/element';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import UncontrolledCustomSelect from '..';
16
+
17
+ const customClass = 'amber-skies';
18
+
19
+ const legacyProps = {
20
+ label: 'label!',
21
+ options: [
22
+ {
23
+ key: 'flower1',
24
+ name: 'violets',
25
+ },
26
+ {
27
+ key: 'flower2',
28
+ name: 'crimson clover',
29
+ className: customClass,
30
+ },
31
+ {
32
+ key: 'flower3',
33
+ name: 'poppy',
34
+ },
35
+ {
36
+ key: 'color1',
37
+ name: 'amber',
38
+ className: customClass,
39
+ },
40
+ {
41
+ key: 'color2',
42
+ name: 'aquamarine',
43
+ style: {
44
+ backgroundColor: 'rgb(127, 255, 212)',
45
+ rotate: '13deg',
46
+ },
47
+ },
48
+ ],
49
+ };
50
+
51
+ const LegacyControlledCustomSelect = ( {
52
+ options,
53
+ onChange,
54
+ ...restProps
55
+ }: React.ComponentProps< typeof UncontrolledCustomSelect > ) => {
56
+ const [ value, setValue ] = useState( options[ 0 ] );
57
+ return (
58
+ <UncontrolledCustomSelect
59
+ { ...restProps }
60
+ options={ options }
61
+ onChange={ ( args: any ) => {
62
+ onChange?.( args );
63
+ setValue( args.selectedItem );
64
+ } }
65
+ value={ options.find(
66
+ ( option: any ) => option.key === value.key
67
+ ) }
68
+ />
69
+ );
70
+ };
71
+
72
+ describe.each( [
73
+ [ 'Uncontrolled', UncontrolledCustomSelect ],
74
+ [ 'Controlled', LegacyControlledCustomSelect ],
75
+ ] )( 'CustomSelectControl (%s)', ( ...modeAndComponent ) => {
76
+ const [ , Component ] = modeAndComponent;
77
+
78
+ it( 'Should replace the initial selection when a new item is selected', async () => {
79
+ render( <Component { ...legacyProps } /> );
80
+
81
+ const currentSelectedItem = screen.getByRole( 'combobox', {
82
+ expanded: false,
83
+ } );
84
+
85
+ await click( currentSelectedItem );
86
+
87
+ await click(
88
+ screen.getByRole( 'option', {
89
+ name: 'crimson clover',
90
+ } )
91
+ );
92
+
93
+ expect( currentSelectedItem ).toHaveTextContent( 'crimson clover' );
94
+
95
+ await click( currentSelectedItem );
96
+
97
+ await click(
98
+ screen.getByRole( 'option', {
99
+ name: 'poppy',
100
+ } )
101
+ );
102
+
103
+ expect( currentSelectedItem ).toHaveTextContent( 'poppy' );
104
+ } );
105
+
106
+ it( 'Should keep current selection if dropdown is closed without changing selection', async () => {
107
+ render( <Component { ...legacyProps } /> );
108
+
109
+ const currentSelectedItem = screen.getByRole( 'combobox', {
110
+ expanded: false,
111
+ } );
112
+
113
+ await sleep();
114
+ await press.Tab();
115
+ await press.Enter();
116
+ expect(
117
+ screen.getByRole( 'listbox', {
118
+ name: 'label!',
119
+ } )
120
+ ).toBeVisible();
121
+
122
+ await press.Escape();
123
+ expect(
124
+ screen.queryByRole( 'listbox', {
125
+ name: 'label!',
126
+ } )
127
+ ).not.toBeInTheDocument();
128
+
129
+ expect( currentSelectedItem ).toHaveTextContent(
130
+ legacyProps.options[ 0 ].name
131
+ );
132
+ } );
133
+
134
+ it( 'Should apply class only to options that have a className defined', async () => {
135
+ render( <Component { ...legacyProps } /> );
136
+
137
+ await click(
138
+ screen.getByRole( 'combobox', {
139
+ expanded: false,
140
+ } )
141
+ );
142
+
143
+ // return an array of items _with_ a className added
144
+ const itemsWithClass = legacyProps.options.filter(
145
+ ( option ) => option.className !== undefined
146
+ );
147
+
148
+ // assert against filtered array
149
+ itemsWithClass.map( ( { name } ) =>
150
+ expect( screen.getByRole( 'option', { name } ) ).toHaveClass(
151
+ customClass
152
+ )
153
+ );
154
+
155
+ // return an array of items _without_ a className added
156
+ const itemsWithoutClass = legacyProps.options.filter(
157
+ ( option ) => option.className === undefined
158
+ );
159
+
160
+ // assert against filtered array
161
+ itemsWithoutClass.map( ( { name } ) =>
162
+ expect( screen.getByRole( 'option', { name } ) ).not.toHaveClass(
163
+ customClass
164
+ )
165
+ );
166
+ } );
167
+
168
+ it( 'Should apply styles only to options that have styles defined', async () => {
169
+ const customStyles =
170
+ 'background-color: rgb(127, 255, 212); rotate: 13deg;';
171
+
172
+ render( <Component { ...legacyProps } /> );
173
+
174
+ await click(
175
+ screen.getByRole( 'combobox', {
176
+ expanded: false,
177
+ } )
178
+ );
179
+
180
+ // return an array of items _with_ styles added
181
+ const styledItems = legacyProps.options.filter(
182
+ ( option ) => option.style !== undefined
183
+ );
184
+
185
+ // assert against filtered array
186
+ styledItems.map( ( { name } ) =>
187
+ expect( screen.getByRole( 'option', { name } ) ).toHaveStyle(
188
+ customStyles
189
+ )
190
+ );
191
+
192
+ // return an array of items _without_ styles added
193
+ const unstyledItems = legacyProps.options.filter(
194
+ ( option ) => option.style === undefined
195
+ );
196
+
197
+ // assert against filtered array
198
+ unstyledItems.map( ( { name } ) =>
199
+ expect( screen.getByRole( 'option', { name } ) ).not.toHaveStyle(
200
+ customStyles
201
+ )
202
+ );
203
+ } );
204
+
205
+ it( 'does not show selected hint by default', async () => {
206
+ render(
207
+ <Component
208
+ { ...legacyProps }
209
+ label="Custom select"
210
+ options={ [
211
+ {
212
+ key: 'one',
213
+ name: 'One',
214
+ __experimentalHint: 'Hint',
215
+ },
216
+ ] }
217
+ />
218
+ );
219
+ await waitFor( () =>
220
+ expect(
221
+ screen.getByRole( 'combobox', { name: 'Custom select' } )
222
+ ).not.toHaveTextContent( 'Hint' )
223
+ );
224
+ } );
225
+
226
+ it( 'shows selected hint when __experimentalShowSelectedHint is set', async () => {
227
+ render(
228
+ <Component
229
+ { ...legacyProps }
230
+ label="Custom select"
231
+ options={ [
232
+ {
233
+ key: 'one',
234
+ name: 'One',
235
+ __experimentalHint: 'Hint',
236
+ },
237
+ ] }
238
+ __experimentalShowSelectedHint
239
+ />
240
+ );
241
+
242
+ await waitFor( () =>
243
+ expect(
244
+ screen.getByRole( 'combobox', {
245
+ expanded: false,
246
+ } )
247
+ ).toHaveTextContent( /hint/i )
248
+ );
249
+ } );
250
+
251
+ it( 'shows selected hint in list of options when added', async () => {
252
+ render(
253
+ <Component
254
+ { ...legacyProps }
255
+ label="Custom select"
256
+ options={ [
257
+ {
258
+ key: 'one',
259
+ name: 'One',
260
+ __experimentalHint: 'Hint',
261
+ },
262
+ ] }
263
+ __experimentalShowSelectedHint
264
+ />
265
+ );
266
+
267
+ await click(
268
+ screen.getByRole( 'combobox', { name: 'Custom select' } )
269
+ );
270
+
271
+ expect( screen.getByRole( 'option', { name: /hint/i } ) ).toBeVisible();
272
+ } );
273
+
274
+ it( 'Should return object onChange', async () => {
275
+ const mockOnChange = jest.fn();
276
+
277
+ render( <Component { ...legacyProps } onChange={ mockOnChange } /> );
278
+
279
+ await click(
280
+ screen.getByRole( 'combobox', {
281
+ expanded: false,
282
+ } )
283
+ );
284
+
285
+ expect( mockOnChange ).toHaveBeenNthCalledWith(
286
+ 1,
287
+ expect.objectContaining( {
288
+ inputValue: '',
289
+ isOpen: false,
290
+ selectedItem: { key: 'violets', name: 'violets' },
291
+ type: '',
292
+ } )
293
+ );
294
+
295
+ await click(
296
+ screen.getByRole( 'option', {
297
+ name: 'aquamarine',
298
+ } )
299
+ );
300
+
301
+ expect( mockOnChange ).toHaveBeenNthCalledWith(
302
+ 2,
303
+ expect.objectContaining( {
304
+ inputValue: '',
305
+ isOpen: false,
306
+ selectedItem: expect.objectContaining( {
307
+ name: 'aquamarine',
308
+ } ),
309
+ type: '',
310
+ } )
311
+ );
312
+ } );
313
+
314
+ it( 'Should return selectedItem object when specified onChange', async () => {
315
+ const mockOnChange = jest.fn(
316
+ ( { selectedItem } ) => selectedItem.key
317
+ );
318
+
319
+ render( <Component { ...legacyProps } onChange={ mockOnChange } /> );
320
+
321
+ await sleep();
322
+ await press.Tab();
323
+ expect(
324
+ screen.getByRole( 'combobox', {
325
+ expanded: false,
326
+ } )
327
+ ).toHaveFocus();
328
+
329
+ await type( 'p' );
330
+ await press.Enter();
331
+
332
+ expect( mockOnChange ).toHaveReturnedWith( 'poppy' );
333
+ } );
334
+
335
+ describe( 'Keyboard behavior and accessibility', () => {
336
+ it( 'Should be able to change selection using keyboard', async () => {
337
+ render( <Component { ...legacyProps } /> );
338
+
339
+ const currentSelectedItem = screen.getByRole( 'combobox', {
340
+ expanded: false,
341
+ } );
342
+
343
+ await sleep();
344
+ await press.Tab();
345
+ expect( currentSelectedItem ).toHaveFocus();
346
+
347
+ await press.Enter();
348
+ expect(
349
+ screen.getByRole( 'listbox', {
350
+ name: 'label!',
351
+ } )
352
+ ).toHaveFocus();
353
+
354
+ await press.ArrowDown();
355
+ await press.Enter();
356
+
357
+ expect( currentSelectedItem ).toHaveTextContent( 'crimson clover' );
358
+ } );
359
+
360
+ it( 'Should be able to type characters to select matching options', async () => {
361
+ render( <Component { ...legacyProps } /> );
362
+
363
+ const currentSelectedItem = screen.getByRole( 'combobox', {
364
+ expanded: false,
365
+ } );
366
+
367
+ await sleep();
368
+ await press.Tab();
369
+ await press.Enter();
370
+ expect(
371
+ screen.getByRole( 'listbox', {
372
+ name: 'label!',
373
+ } )
374
+ ).toHaveFocus();
375
+
376
+ await type( 'a' );
377
+ await press.Enter();
378
+ expect( currentSelectedItem ).toHaveTextContent( 'amber' );
379
+ } );
380
+
381
+ it( 'Can change selection with a focused input and closed dropdown if typed characters match an option', async () => {
382
+ render( <Component { ...legacyProps } /> );
383
+
384
+ const currentSelectedItem = screen.getByRole( 'combobox', {
385
+ expanded: false,
386
+ } );
387
+
388
+ await sleep();
389
+ await press.Tab();
390
+ expect( currentSelectedItem ).toHaveFocus();
391
+
392
+ await type( 'aq' );
393
+
394
+ expect(
395
+ screen.queryByRole( 'listbox', {
396
+ name: 'label!',
397
+ hidden: true,
398
+ } )
399
+ ).not.toBeInTheDocument();
400
+
401
+ await press.Enter();
402
+ expect( currentSelectedItem ).toHaveTextContent( 'aquamarine' );
403
+ } );
404
+
405
+ it( 'Should have correct aria-selected value for selections', async () => {
406
+ render( <Component { ...legacyProps } /> );
407
+
408
+ const currentSelectedItem = screen.getByRole( 'combobox', {
409
+ expanded: false,
410
+ } );
411
+
412
+ await click( currentSelectedItem );
413
+
414
+ // get all items except for first option
415
+ const unselectedItems = legacyProps.options.filter(
416
+ ( { name } ) => name !== legacyProps.options[ 0 ].name
417
+ );
418
+
419
+ // assert that all other items have aria-selected="false"
420
+ unselectedItems.map( ( { name } ) =>
421
+ expect(
422
+ screen.getByRole( 'option', { name, selected: false } )
423
+ ).toBeVisible()
424
+ );
425
+
426
+ // assert that first item has aria-selected="true"
427
+ expect(
428
+ screen.getByRole( 'option', {
429
+ name: legacyProps.options[ 0 ].name,
430
+ selected: true,
431
+ } )
432
+ ).toBeVisible();
433
+
434
+ // change the current selection
435
+ await click( screen.getByRole( 'option', { name: 'poppy' } ) );
436
+
437
+ // click combobox to mount listbox with options again
438
+ await click( currentSelectedItem );
439
+
440
+ // check that first item is has aria-selected="false" after new selection
441
+ expect(
442
+ screen.getByRole( 'option', {
443
+ name: legacyProps.options[ 0 ].name,
444
+ selected: false,
445
+ } )
446
+ ).toBeVisible();
447
+
448
+ // check that new selected item now has aria-selected="true"
449
+ expect(
450
+ screen.getByRole( 'option', {
451
+ name: 'poppy',
452
+ selected: true,
453
+ } )
454
+ ).toBeVisible();
455
+ } );
456
+ } );
457
+ } );
@@ -11,12 +11,11 @@ import { useState } from '@wordpress/element';
11
11
  /**
12
12
  * Internal dependencies
13
13
  */
14
- import _LegacyCustomSelect from '../legacy-component';
15
- import { CustomSelect } from '..';
14
+ import CustomSelect from '../legacy-component';
16
15
 
17
- const meta: Meta< typeof _LegacyCustomSelect > = {
16
+ const meta: Meta< typeof CustomSelect > = {
18
17
  title: 'Components (Experimental)/CustomSelectControl v2/Legacy',
19
- component: _LegacyCustomSelect,
18
+ component: CustomSelect,
20
19
  argTypes: {
21
20
  onChange: { control: { type: null } },
22
21
  value: { control: { type: null } },
@@ -43,11 +42,11 @@ const meta: Meta< typeof _LegacyCustomSelect > = {
43
42
  };
44
43
  export default meta;
45
44
 
46
- const Template: StoryFn< typeof _LegacyCustomSelect > = ( props ) => {
45
+ const Template: StoryFn< typeof CustomSelect > = ( props ) => {
47
46
  const [ fontSize, setFontSize ] = useState( props.options[ 0 ] );
48
47
 
49
48
  const onChange: React.ComponentProps<
50
- typeof _LegacyCustomSelect
49
+ typeof CustomSelect
51
50
  >[ 'onChange' ] = ( changeObject ) => {
52
51
  setFontSize( changeObject.selectedItem );
53
52
  props.onChange?.( changeObject );