@wordpress/components 23.3.5 → 23.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 (777) hide show
  1. package/CHANGELOG.md +35 -5
  2. package/build/alignment-matrix-control/utils.js +4 -4
  3. package/build/alignment-matrix-control/utils.js.map +1 -1
  4. package/build/angle-picker-control/angle-circle.js +37 -29
  5. package/build/angle-picker-control/angle-circle.js.map +1 -1
  6. package/build/angle-picker-control/index.js +44 -9
  7. package/build/angle-picker-control/index.js.map +1 -1
  8. package/build/angle-picker-control/styles/angle-picker-control-styles.js +13 -13
  9. package/build/angle-picker-control/styles/angle-picker-control-styles.js.map +1 -1
  10. package/build/angle-picker-control/types.js.map +1 -0
  11. package/build/autocomplete/autocompleter-ui.js +41 -17
  12. package/build/autocomplete/autocompleter-ui.js.map +1 -1
  13. package/build/autocomplete/autocompleter-ui.native.js +1 -0
  14. package/build/autocomplete/autocompleter-ui.native.js.map +1 -1
  15. package/build/autocomplete/index.js +31 -33
  16. package/build/autocomplete/index.js.map +1 -1
  17. package/build/base-control/hooks.js +1 -1
  18. package/build/base-control/hooks.js.map +1 -1
  19. package/build/border-box-control/utils.js +1 -1
  20. package/build/border-box-control/utils.js.map +1 -1
  21. package/build/box-control/all-input-control.js +2 -2
  22. package/build/box-control/all-input-control.js.map +1 -1
  23. package/build/box-control/axial-input-controls.js +1 -1
  24. package/build/box-control/axial-input-controls.js.map +1 -1
  25. package/build/box-control/icon.js.map +1 -1
  26. package/build/box-control/index.js +32 -3
  27. package/build/box-control/index.js.map +1 -1
  28. package/build/box-control/input-controls.js +5 -5
  29. package/build/box-control/input-controls.js.map +1 -1
  30. package/build/box-control/linked-button.js.map +1 -1
  31. package/build/box-control/styles/box-control-icon-styles.js +28 -28
  32. package/build/box-control/styles/box-control-icon-styles.js.map +1 -1
  33. package/build/box-control/styles/box-control-styles.js +23 -23
  34. package/build/box-control/styles/box-control-styles.js.map +1 -1
  35. package/build/box-control/styles/box-control-visualizer-styles.js +19 -19
  36. package/build/box-control/styles/box-control-visualizer-styles.js.map +1 -1
  37. package/build/box-control/types.js +6 -0
  38. package/build/box-control/types.js.map +1 -0
  39. package/build/box-control/unit-control.js.map +1 -1
  40. package/build/box-control/utils.js +23 -23
  41. package/build/box-control/utils.js.map +1 -1
  42. package/build/circular-option-picker/index.js +63 -14
  43. package/build/circular-option-picker/index.js.map +1 -1
  44. package/build/circular-option-picker/types.js +6 -0
  45. package/build/circular-option-picker/types.js.map +1 -0
  46. package/build/color-palette/index.js +8 -3
  47. package/build/color-palette/index.js.map +1 -1
  48. package/build/combobox-control/index.js +68 -12
  49. package/build/combobox-control/index.js.map +1 -1
  50. package/build/combobox-control/styles.js +2 -2
  51. package/build/combobox-control/styles.js.map +1 -1
  52. package/build/combobox-control/types.js +6 -0
  53. package/build/combobox-control/types.js.map +1 -0
  54. package/build/custom-gradient-picker/index.js +0 -1
  55. package/build/custom-gradient-picker/index.js.map +1 -1
  56. package/build/date-time/time/index.js +1 -1
  57. package/build/date-time/time/index.js.map +1 -1
  58. package/build/date-time/utils.js +1 -1
  59. package/build/date-time/utils.js.map +1 -1
  60. package/build/draggable/index.js +2 -2
  61. package/build/draggable/index.js.map +1 -1
  62. package/build/focal-point-picker/utils.js +3 -3
  63. package/build/focal-point-picker/utils.js.map +1 -1
  64. package/build/font-size-picker/utils.js +2 -2
  65. package/build/font-size-picker/utils.js.map +1 -1
  66. package/build/gradient-picker/index.js +9 -4
  67. package/build/gradient-picker/index.js.map +1 -1
  68. package/build/higher-order/with-constrained-tabbing/index.js +9 -0
  69. package/build/higher-order/with-constrained-tabbing/index.js.map +1 -1
  70. package/build/input-control/reducer/reducer.js +5 -5
  71. package/build/input-control/reducer/reducer.js.map +1 -1
  72. package/build/input-control/utils.js +1 -1
  73. package/build/input-control/utils.js.map +1 -1
  74. package/build/menu-items-choice/index.js +40 -3
  75. package/build/menu-items-choice/index.js.map +1 -1
  76. package/build/menu-items-choice/types.js +6 -0
  77. package/build/menu-items-choice/types.js.map +1 -0
  78. package/build/mobile/global-styles-context/utils.native.js +2 -1
  79. package/build/mobile/global-styles-context/utils.native.js.map +1 -1
  80. package/build/modal/index.js +41 -3
  81. package/build/modal/index.js.map +1 -1
  82. package/build/palette-edit/index.js +4 -1
  83. package/build/palette-edit/index.js.map +1 -1
  84. package/build/panel/header.js +9 -0
  85. package/build/panel/header.js.map +1 -1
  86. package/build/panel/index.js +21 -3
  87. package/build/panel/index.js.map +1 -1
  88. package/build/panel/row.js +10 -4
  89. package/build/panel/row.js.map +1 -1
  90. package/build/panel/types.js +6 -0
  91. package/build/panel/types.js.map +1 -0
  92. package/build/popover/index.js +15 -3
  93. package/build/popover/index.js.map +1 -1
  94. package/build/popover/overlay-middlewares.js +46 -0
  95. package/build/popover/overlay-middlewares.js.map +1 -0
  96. package/build/popover/utils.js +45 -6
  97. package/build/popover/utils.js.map +1 -1
  98. package/build/query-controls/terms.js +1 -1
  99. package/build/query-controls/terms.js.map +1 -1
  100. package/build/range-control/utils.js +4 -4
  101. package/build/range-control/utils.js.map +1 -1
  102. package/build/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js +12 -12
  103. package/build/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js.map +1 -1
  104. package/build/resizable-box/resize-tooltip/utils.js +14 -14
  105. package/build/resizable-box/resize-tooltip/utils.js.map +1 -1
  106. package/build/snackbar/index.js +2 -2
  107. package/build/snackbar/index.js.map +1 -1
  108. package/build/toolbar/toolbar/index.js +25 -14
  109. package/build/toolbar/toolbar/index.js.map +1 -1
  110. package/build/toolbar/toolbar/toolbar-container.js +5 -4
  111. package/build/toolbar/toolbar/toolbar-container.js.map +1 -1
  112. package/build/toolbar/toolbar/types.js +6 -0
  113. package/build/toolbar/toolbar/types.js.map +1 -0
  114. package/build/toolbar/toolbar-button/index.js +2 -0
  115. package/build/toolbar/toolbar-button/index.js.map +1 -1
  116. package/build/toolbar/toolbar-button/toolbar-button-container.js +1 -0
  117. package/build/toolbar/toolbar-button/toolbar-button-container.js.map +1 -1
  118. package/build/toolbar/toolbar-context/index.js +2 -0
  119. package/build/toolbar/toolbar-context/index.js.map +1 -1
  120. package/build/toolbar/toolbar-dropdown-menu/index.js +2 -0
  121. package/build/toolbar/toolbar-dropdown-menu/index.js.map +1 -1
  122. package/build/toolbar/toolbar-group/index.js +2 -0
  123. package/build/toolbar/toolbar-group/index.js.map +1 -1
  124. package/build/toolbar/toolbar-group/toolbar-group-collapsed.js +2 -0
  125. package/build/toolbar/toolbar-group/toolbar-group-collapsed.js.map +1 -1
  126. package/build/toolbar/toolbar-group/toolbar-group-container.js +1 -0
  127. package/build/toolbar/toolbar-group/toolbar-group-container.js.map +1 -1
  128. package/build/toolbar/toolbar-item/index.js +2 -0
  129. package/build/toolbar/toolbar-item/index.js.map +1 -1
  130. package/build/tools-panel/context.js +2 -0
  131. package/build/tools-panel/context.js.map +1 -1
  132. package/build/tools-panel/tools-panel/component.js +61 -5
  133. package/build/tools-panel/tools-panel/component.js.map +1 -1
  134. package/build/tools-panel/tools-panel/hook.js +22 -14
  135. package/build/tools-panel/tools-panel/hook.js.map +1 -1
  136. package/build/tools-panel/tools-panel-header/component.js +2 -1
  137. package/build/tools-panel/tools-panel-header/component.js.map +1 -1
  138. package/build/tools-panel/tools-panel-header/hook.js +2 -0
  139. package/build/tools-panel/tools-panel-header/hook.js.map +1 -1
  140. package/build/tools-panel/tools-panel-item/component.js +5 -4
  141. package/build/tools-panel/tools-panel-item/component.js.map +1 -1
  142. package/build/tools-panel/tools-panel-item/hook.js +18 -4
  143. package/build/tools-panel/tools-panel-item/hook.js.map +1 -1
  144. package/build/tree-grid/cell.js +15 -4
  145. package/build/tree-grid/cell.js.map +1 -1
  146. package/build/tree-grid/index.js +81 -19
  147. package/build/tree-grid/index.js.map +1 -1
  148. package/build/tree-grid/item.js +14 -3
  149. package/build/tree-grid/item.js.map +1 -1
  150. package/build/tree-grid/roving-tab-index-context.js +1 -1
  151. package/build/tree-grid/roving-tab-index-context.js.map +1 -1
  152. package/build/tree-grid/roving-tab-index-item.js +13 -6
  153. package/build/tree-grid/roving-tab-index-item.js.map +1 -1
  154. package/build/tree-grid/roving-tab-index.js +0 -3
  155. package/build/tree-grid/roving-tab-index.js.map +1 -1
  156. package/build/tree-grid/row.js +20 -18
  157. package/build/tree-grid/row.js.map +1 -1
  158. package/build/tree-grid/types.js +6 -0
  159. package/build/tree-grid/types.js.map +1 -0
  160. package/build/ui/context/context-connect.js +7 -7
  161. package/build/ui/context/context-connect.js.map +1 -1
  162. package/build/ui/context/context-system-provider.js +8 -4
  163. package/build/ui/context/context-system-provider.js.map +1 -1
  164. package/build/ui/context/get-styled-class-name-from-key.js +1 -1
  165. package/build/ui/context/get-styled-class-name-from-key.js.map +1 -1
  166. package/build/ui/utils/get-valid-children.js +1 -1
  167. package/build/ui/utils/get-valid-children.js.map +1 -1
  168. package/build/ui/utils/space.js +1 -1
  169. package/build/ui/utils/space.js.map +1 -1
  170. package/build/unit-control/index.js +2 -2
  171. package/build/unit-control/index.js.map +1 -1
  172. package/build/unit-control/utils.js +20 -20
  173. package/build/unit-control/utils.js.map +1 -1
  174. package/build/utils/events.js +4 -4
  175. package/build/utils/events.js.map +1 -1
  176. package/build/utils/hooks/use-controlled-state.js +2 -2
  177. package/build/utils/hooks/use-controlled-state.js.map +1 -1
  178. package/build/utils/hooks/use-controlled-value.js +4 -4
  179. package/build/utils/hooks/use-controlled-value.js.map +1 -1
  180. package/build/utils/hooks/use-latest-ref.js +1 -1
  181. package/build/utils/hooks/use-latest-ref.js.map +1 -1
  182. package/build/utils/unit-values.js +3 -3
  183. package/build/utils/unit-values.js.map +1 -1
  184. package/build-module/alignment-matrix-control/utils.js +4 -4
  185. package/build-module/alignment-matrix-control/utils.js.map +1 -1
  186. package/build-module/angle-picker-control/angle-circle.js +37 -29
  187. package/build-module/angle-picker-control/angle-circle.js.map +1 -1
  188. package/build-module/angle-picker-control/index.js +42 -8
  189. package/build-module/angle-picker-control/index.js.map +1 -1
  190. package/build-module/angle-picker-control/styles/angle-picker-control-styles.js +13 -13
  191. package/build-module/angle-picker-control/styles/angle-picker-control-styles.js.map +1 -1
  192. package/build-module/autocomplete/autocompleter-ui.js +40 -19
  193. package/build-module/autocomplete/autocompleter-ui.js.map +1 -1
  194. package/build-module/autocomplete/autocompleter-ui.native.js +1 -0
  195. package/build-module/autocomplete/autocompleter-ui.native.js.map +1 -1
  196. package/build-module/autocomplete/index.js +30 -32
  197. package/build-module/autocomplete/index.js.map +1 -1
  198. package/build-module/base-control/hooks.js +1 -1
  199. package/build-module/base-control/hooks.js.map +1 -1
  200. package/build-module/border-box-control/utils.js +1 -1
  201. package/build-module/border-box-control/utils.js.map +1 -1
  202. package/build-module/box-control/all-input-control.js +2 -2
  203. package/build-module/box-control/all-input-control.js.map +1 -1
  204. package/build-module/box-control/axial-input-controls.js +1 -1
  205. package/build-module/box-control/axial-input-controls.js.map +1 -1
  206. package/build-module/box-control/icon.js.map +1 -1
  207. package/build-module/box-control/index.js +31 -3
  208. package/build-module/box-control/index.js.map +1 -1
  209. package/build-module/box-control/input-controls.js +5 -5
  210. package/build-module/box-control/input-controls.js.map +1 -1
  211. package/build-module/box-control/linked-button.js.map +1 -1
  212. package/build-module/box-control/styles/box-control-icon-styles.js +28 -28
  213. package/build-module/box-control/styles/box-control-icon-styles.js.map +1 -1
  214. package/build-module/box-control/styles/box-control-styles.js +23 -23
  215. package/build-module/box-control/styles/box-control-styles.js.map +1 -1
  216. package/build-module/box-control/styles/box-control-visualizer-styles.js +19 -19
  217. package/build-module/box-control/styles/box-control-visualizer-styles.js.map +1 -1
  218. package/build-module/box-control/types.js +2 -0
  219. package/build-module/box-control/unit-control.js.map +1 -1
  220. package/build-module/box-control/utils.js +23 -23
  221. package/build-module/box-control/utils.js.map +1 -1
  222. package/build-module/circular-option-picker/index.js +59 -16
  223. package/build-module/circular-option-picker/index.js.map +1 -1
  224. package/build-module/circular-option-picker/types.js +2 -0
  225. package/build-module/color-palette/index.js +8 -3
  226. package/build-module/color-palette/index.js.map +1 -1
  227. package/build-module/combobox-control/index.js +68 -12
  228. package/build-module/combobox-control/index.js.map +1 -1
  229. package/build-module/combobox-control/styles.js +2 -2
  230. package/build-module/combobox-control/styles.js.map +1 -1
  231. package/build-module/combobox-control/types.js +2 -0
  232. package/build-module/custom-gradient-picker/index.js +0 -1
  233. package/build-module/custom-gradient-picker/index.js.map +1 -1
  234. package/build-module/date-time/time/index.js +1 -1
  235. package/build-module/date-time/time/index.js.map +1 -1
  236. package/build-module/date-time/utils.js +1 -1
  237. package/build-module/date-time/utils.js.map +1 -1
  238. package/build-module/draggable/index.js +2 -2
  239. package/build-module/draggable/index.js.map +1 -1
  240. package/build-module/focal-point-picker/utils.js +3 -3
  241. package/build-module/focal-point-picker/utils.js.map +1 -1
  242. package/build-module/font-size-picker/utils.js +2 -2
  243. package/build-module/font-size-picker/utils.js.map +1 -1
  244. package/build-module/gradient-picker/index.js +9 -4
  245. package/build-module/gradient-picker/index.js.map +1 -1
  246. package/build-module/higher-order/with-constrained-tabbing/index.js +9 -0
  247. package/build-module/higher-order/with-constrained-tabbing/index.js.map +1 -1
  248. package/build-module/input-control/reducer/reducer.js +5 -5
  249. package/build-module/input-control/reducer/reducer.js.map +1 -1
  250. package/build-module/input-control/utils.js +1 -1
  251. package/build-module/input-control/utils.js.map +1 -1
  252. package/build-module/menu-items-choice/index.js +40 -4
  253. package/build-module/menu-items-choice/index.js.map +1 -1
  254. package/build-module/menu-items-choice/types.js +2 -0
  255. package/build-module/menu-items-choice/types.js.map +1 -0
  256. package/build-module/mobile/global-styles-context/utils.native.js +2 -1
  257. package/build-module/mobile/global-styles-context/utils.native.js.map +1 -1
  258. package/build-module/modal/index.js +41 -4
  259. package/build-module/modal/index.js.map +1 -1
  260. package/build-module/palette-edit/index.js +4 -1
  261. package/build-module/palette-edit/index.js.map +1 -1
  262. package/build-module/panel/header.js +9 -0
  263. package/build-module/panel/header.js.map +1 -1
  264. package/build-module/panel/index.js +20 -2
  265. package/build-module/panel/index.js.map +1 -1
  266. package/build-module/panel/row.js +9 -3
  267. package/build-module/panel/row.js.map +1 -1
  268. package/build-module/panel/types.js +2 -0
  269. package/build-module/panel/types.js.map +1 -0
  270. package/build-module/popover/index.js +14 -4
  271. package/build-module/popover/index.js.map +1 -1
  272. package/build-module/popover/overlay-middlewares.js +38 -0
  273. package/build-module/popover/overlay-middlewares.js.map +1 -0
  274. package/build-module/popover/utils.js +41 -5
  275. package/build-module/popover/utils.js.map +1 -1
  276. package/build-module/query-controls/terms.js +1 -1
  277. package/build-module/query-controls/terms.js.map +1 -1
  278. package/build-module/range-control/utils.js +4 -4
  279. package/build-module/range-control/utils.js.map +1 -1
  280. package/build-module/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js +12 -12
  281. package/build-module/resizable-box/resize-tooltip/styles/resize-tooltip.styles.js.map +1 -1
  282. package/build-module/resizable-box/resize-tooltip/utils.js +14 -14
  283. package/build-module/resizable-box/resize-tooltip/utils.js.map +1 -1
  284. package/build-module/snackbar/index.js +2 -2
  285. package/build-module/snackbar/index.js.map +1 -1
  286. package/build-module/toolbar/toolbar/index.js +25 -13
  287. package/build-module/toolbar/toolbar/index.js.map +1 -1
  288. package/build-module/toolbar/toolbar/toolbar-container.js +4 -3
  289. package/build-module/toolbar/toolbar/toolbar-container.js.map +1 -1
  290. package/build-module/toolbar/toolbar/types.js +2 -0
  291. package/build-module/toolbar/toolbar/types.js.map +1 -0
  292. package/build-module/toolbar/toolbar-button/index.js +1 -0
  293. package/build-module/toolbar/toolbar-button/index.js.map +1 -1
  294. package/build-module/toolbar/toolbar-button/toolbar-button-container.js +1 -0
  295. package/build-module/toolbar/toolbar-button/toolbar-button-container.js.map +1 -1
  296. package/build-module/toolbar/toolbar-context/index.js +2 -0
  297. package/build-module/toolbar/toolbar-context/index.js.map +1 -1
  298. package/build-module/toolbar/toolbar-dropdown-menu/index.js +1 -0
  299. package/build-module/toolbar/toolbar-dropdown-menu/index.js.map +1 -1
  300. package/build-module/toolbar/toolbar-group/index.js +1 -0
  301. package/build-module/toolbar/toolbar-group/index.js.map +1 -1
  302. package/build-module/toolbar/toolbar-group/toolbar-group-collapsed.js +1 -0
  303. package/build-module/toolbar/toolbar-group/toolbar-group-collapsed.js.map +1 -1
  304. package/build-module/toolbar/toolbar-group/toolbar-group-container.js +1 -0
  305. package/build-module/toolbar/toolbar-group/toolbar-group-container.js.map +1 -1
  306. package/build-module/toolbar/toolbar-item/index.js +1 -0
  307. package/build-module/toolbar/toolbar-item/index.js.map +1 -1
  308. package/build-module/tools-panel/context.js +2 -0
  309. package/build-module/tools-panel/context.js.map +1 -1
  310. package/build-module/tools-panel/tools-panel/component.js +59 -4
  311. package/build-module/tools-panel/tools-panel/component.js.map +1 -1
  312. package/build-module/tools-panel/tools-panel/hook.js +22 -14
  313. package/build-module/tools-panel/tools-panel/hook.js.map +1 -1
  314. package/build-module/tools-panel/tools-panel-header/component.js +2 -1
  315. package/build-module/tools-panel/tools-panel-header/component.js.map +1 -1
  316. package/build-module/tools-panel/tools-panel-header/hook.js +2 -0
  317. package/build-module/tools-panel/tools-panel-header/hook.js.map +1 -1
  318. package/build-module/tools-panel/tools-panel-item/component.js +3 -3
  319. package/build-module/tools-panel/tools-panel-item/component.js.map +1 -1
  320. package/build-module/tools-panel/tools-panel-item/hook.js +19 -4
  321. package/build-module/tools-panel/tools-panel-item/hook.js.map +1 -1
  322. package/build-module/tree-grid/cell.js +16 -4
  323. package/build-module/tree-grid/cell.js.map +1 -1
  324. package/build-module/tree-grid/index.js +81 -21
  325. package/build-module/tree-grid/index.js.map +1 -1
  326. package/build-module/tree-grid/item.js +14 -2
  327. package/build-module/tree-grid/item.js.map +1 -1
  328. package/build-module/tree-grid/roving-tab-index-context.js +1 -1
  329. package/build-module/tree-grid/roving-tab-index-context.js.map +1 -1
  330. package/build-module/tree-grid/roving-tab-index-item.js +11 -4
  331. package/build-module/tree-grid/roving-tab-index-item.js.map +1 -1
  332. package/build-module/tree-grid/roving-tab-index.js +0 -3
  333. package/build-module/tree-grid/roving-tab-index.js.map +1 -1
  334. package/build-module/tree-grid/row.js +22 -17
  335. package/build-module/tree-grid/row.js.map +1 -1
  336. package/build-module/tree-grid/types.js +2 -0
  337. package/build-module/tree-grid/types.js.map +1 -0
  338. package/build-module/ui/context/context-connect.js +7 -7
  339. package/build-module/ui/context/context-connect.js.map +1 -1
  340. package/build-module/ui/context/context-system-provider.js +7 -4
  341. package/build-module/ui/context/context-system-provider.js.map +1 -1
  342. package/build-module/ui/context/get-styled-class-name-from-key.js +1 -1
  343. package/build-module/ui/context/get-styled-class-name-from-key.js.map +1 -1
  344. package/build-module/ui/utils/get-valid-children.js +1 -1
  345. package/build-module/ui/utils/get-valid-children.js.map +1 -1
  346. package/build-module/ui/utils/space.js +1 -1
  347. package/build-module/ui/utils/space.js.map +1 -1
  348. package/build-module/unit-control/index.js +2 -2
  349. package/build-module/unit-control/index.js.map +1 -1
  350. package/build-module/unit-control/utils.js +20 -20
  351. package/build-module/unit-control/utils.js.map +1 -1
  352. package/build-module/utils/events.js +4 -4
  353. package/build-module/utils/events.js.map +1 -1
  354. package/build-module/utils/hooks/use-controlled-state.js +2 -2
  355. package/build-module/utils/hooks/use-controlled-state.js.map +1 -1
  356. package/build-module/utils/hooks/use-controlled-value.js +4 -4
  357. package/build-module/utils/hooks/use-controlled-value.js.map +1 -1
  358. package/build-module/utils/hooks/use-latest-ref.js +1 -1
  359. package/build-module/utils/hooks/use-latest-ref.js.map +1 -1
  360. package/build-module/utils/unit-values.js +3 -3
  361. package/build-module/utils/unit-values.js.map +1 -1
  362. package/build-style/style-rtl.css +5 -0
  363. package/build-style/style.css +5 -0
  364. package/build-types/alignment-matrix-control/utils.d.ts +4 -4
  365. package/build-types/angle-picker-control/angle-circle.d.ts +6 -0
  366. package/build-types/angle-picker-control/angle-circle.d.ts.map +1 -0
  367. package/build-types/angle-picker-control/index.d.ts +29 -0
  368. package/build-types/angle-picker-control/index.d.ts.map +1 -0
  369. package/build-types/angle-picker-control/stories/index.d.ts +15 -0
  370. package/build-types/angle-picker-control/stories/index.d.ts.map +1 -0
  371. package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts +20 -0
  372. package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts.map +1 -0
  373. package/build-types/angle-picker-control/types.d.ts +26 -0
  374. package/build-types/angle-picker-control/types.d.ts.map +1 -0
  375. package/build-types/base-control/hooks.d.ts +1 -1
  376. package/build-types/border-box-control/border-box-control/component.d.ts +1 -1
  377. package/build-types/border-box-control/border-box-control/hook.d.ts +1 -1
  378. package/build-types/border-box-control/border-box-control-split-controls/component.d.ts +1 -1
  379. package/build-types/border-box-control/border-box-control-split-controls/hook.d.ts +1 -1
  380. package/build-types/border-box-control/stories/index.d.ts +1 -1
  381. package/build-types/border-box-control/test/index.d.ts.map +1 -0
  382. package/build-types/border-box-control/test/utils.d.ts +2 -0
  383. package/build-types/border-box-control/test/utils.d.ts.map +1 -0
  384. package/build-types/box-control/all-input-control.d.ts +4 -0
  385. package/build-types/box-control/all-input-control.d.ts.map +1 -0
  386. package/build-types/box-control/axial-input-controls.d.ts +4 -0
  387. package/build-types/box-control/axial-input-controls.d.ts.map +1 -0
  388. package/build-types/box-control/icon.d.ts +8 -0
  389. package/build-types/box-control/icon.d.ts.map +1 -0
  390. package/build-types/box-control/index.d.ts +31 -0
  391. package/build-types/box-control/index.d.ts.map +1 -0
  392. package/build-types/box-control/input-controls.d.ts +4 -0
  393. package/build-types/box-control/input-controls.d.ts.map +1 -0
  394. package/build-types/box-control/linked-button.d.ts +9 -0
  395. package/build-types/box-control/linked-button.d.ts.map +1 -0
  396. package/build-types/box-control/styles/box-control-icon-styles.d.ts +42 -0
  397. package/build-types/box-control/styles/box-control-icon-styles.d.ts.map +1 -0
  398. package/build-types/box-control/styles/box-control-styles.d.ts +42 -0
  399. package/build-types/box-control/styles/box-control-styles.d.ts.map +1 -0
  400. package/build-types/box-control/styles/box-control-visualizer-styles.d.ts +46 -0
  401. package/build-types/box-control/styles/box-control-visualizer-styles.d.ts.map +1 -0
  402. package/build-types/box-control/test/index.d.ts +2 -0
  403. package/build-types/box-control/test/index.d.ts.map +1 -0
  404. package/build-types/box-control/types.d.ts +99 -0
  405. package/build-types/box-control/types.d.ts.map +1 -0
  406. package/build-types/box-control/unit-control.d.ts +4 -0
  407. package/build-types/box-control/unit-control.d.ts.map +1 -0
  408. package/build-types/box-control/utils.d.ts +84 -0
  409. package/build-types/box-control/utils.d.ts.map +1 -0
  410. package/build-types/circular-option-picker/index.d.ts +56 -7
  411. package/build-types/circular-option-picker/index.d.ts.map +1 -1
  412. package/build-types/circular-option-picker/stories/index.d.ts +14 -0
  413. package/build-types/circular-option-picker/stories/index.d.ts.map +1 -0
  414. package/build-types/circular-option-picker/types.d.ts +49 -0
  415. package/build-types/circular-option-picker/types.d.ts.map +1 -0
  416. package/build-types/color-palette/index.d.ts +3 -1
  417. package/build-types/color-palette/index.d.ts.map +1 -1
  418. package/build-types/color-palette/stories/index.d.ts +6 -2
  419. package/build-types/color-palette/stories/index.d.ts.map +1 -1
  420. package/build-types/color-palette/types.d.ts +8 -0
  421. package/build-types/color-palette/types.d.ts.map +1 -1
  422. package/build-types/combobox-control/index.d.ts +51 -0
  423. package/build-types/combobox-control/index.d.ts.map +1 -0
  424. package/build-types/combobox-control/stories/index.d.ts +18 -0
  425. package/build-types/combobox-control/stories/index.d.ts.map +1 -0
  426. package/build-types/combobox-control/styles.d.ts +8 -0
  427. package/build-types/combobox-control/styles.d.ts.map +1 -0
  428. package/build-types/combobox-control/test/index.d.ts +2 -0
  429. package/build-types/combobox-control/test/index.d.ts.map +1 -0
  430. package/build-types/combobox-control/types.d.ts +62 -0
  431. package/build-types/combobox-control/types.d.ts.map +1 -0
  432. package/build-types/date-time/utils.d.ts +1 -1
  433. package/build-types/focal-point-picker/styles/focal-point-picker-style.d.ts +1 -1
  434. package/build-types/focal-point-picker/utils.d.ts +3 -3
  435. package/build-types/font-size-picker/utils.d.ts +2 -2
  436. package/build-types/h-stack/stories/e2e/index.d.ts +9 -0
  437. package/build-types/h-stack/stories/e2e/index.d.ts.map +1 -0
  438. package/build-types/higher-order/with-constrained-tabbing/index.d.ts +10 -1
  439. package/build-types/higher-order/with-constrained-tabbing/index.d.ts.map +1 -1
  440. package/build-types/input-control/reducer/reducer.d.ts +3 -3
  441. package/build-types/input-control/utils.d.ts +1 -1
  442. package/build-types/menu-items-choice/index.d.ts +38 -0
  443. package/build-types/menu-items-choice/index.d.ts.map +1 -0
  444. package/build-types/menu-items-choice/stories/index.d.ts +12 -0
  445. package/build-types/menu-items-choice/stories/index.d.ts.map +1 -0
  446. package/build-types/menu-items-choice/types.d.ts +53 -0
  447. package/build-types/menu-items-choice/types.d.ts.map +1 -0
  448. package/build-types/modal/index.d.ts.map +1 -1
  449. package/build-types/modal/types.d.ts +2 -0
  450. package/build-types/modal/types.d.ts.map +1 -1
  451. package/build-types/panel/header.d.ts +13 -0
  452. package/build-types/panel/header.d.ts.map +1 -0
  453. package/build-types/panel/index.d.ts +21 -0
  454. package/build-types/panel/index.d.ts.map +1 -0
  455. package/build-types/panel/row.d.ts +12 -0
  456. package/build-types/panel/row.d.ts.map +1 -0
  457. package/build-types/panel/test/header.d.ts +2 -0
  458. package/build-types/panel/test/header.d.ts.map +1 -0
  459. package/build-types/panel/test/index.d.ts +2 -0
  460. package/build-types/{base-field → panel}/test/index.d.ts.map +1 -1
  461. package/build-types/panel/test/row.d.ts +2 -0
  462. package/build-types/panel/test/row.d.ts.map +1 -0
  463. package/build-types/panel/types.d.ts +38 -0
  464. package/build-types/panel/types.d.ts.map +1 -0
  465. package/build-types/popover/index.d.ts.map +1 -1
  466. package/build-types/popover/overlay-middlewares.d.ts +9 -0
  467. package/build-types/popover/overlay-middlewares.d.ts.map +1 -0
  468. package/build-types/popover/stories/index.d.ts.map +1 -1
  469. package/build-types/popover/types.d.ts +3 -2
  470. package/build-types/popover/types.d.ts.map +1 -1
  471. package/build-types/popover/utils.d.ts +12 -4
  472. package/build-types/popover/utils.d.ts.map +1 -1
  473. package/build-types/query-controls/terms.d.ts +1 -1
  474. package/build-types/range-control/utils.d.ts +4 -4
  475. package/build-types/resizable-box/resize-tooltip/styles/resize-tooltip.styles.d.ts +5 -4
  476. package/build-types/resizable-box/resize-tooltip/styles/resize-tooltip.styles.d.ts.map +1 -1
  477. package/build-types/resizable-box/resize-tooltip/utils.d.ts +6 -6
  478. package/build-types/tab-panel/stories/index.d.ts +1 -0
  479. package/build-types/tab-panel/stories/index.d.ts.map +1 -1
  480. package/build-types/toolbar/index.d.ts +7 -0
  481. package/build-types/toolbar/index.d.ts.map +1 -0
  482. package/build-types/toolbar/stories/index.d.ts +14 -0
  483. package/build-types/toolbar/stories/index.d.ts.map +1 -0
  484. package/build-types/toolbar/test/index.d.ts +2 -0
  485. package/build-types/toolbar/test/index.d.ts.map +1 -0
  486. package/build-types/toolbar/test/toolbar-group.d.ts +2 -0
  487. package/build-types/toolbar/test/toolbar-group.d.ts.map +1 -0
  488. package/build-types/toolbar/toolbar/index.d.ts +25 -0
  489. package/build-types/toolbar/toolbar/index.d.ts.map +1 -0
  490. package/build-types/toolbar/toolbar/toolbar-container.d.ts +5 -0
  491. package/build-types/toolbar/toolbar/toolbar-container.d.ts.map +1 -0
  492. package/build-types/toolbar/toolbar/types.d.ts +15 -0
  493. package/build-types/toolbar/toolbar/types.d.ts.map +1 -0
  494. package/build-types/toolbar/toolbar-button/index.d.ts +12 -0
  495. package/build-types/toolbar/toolbar-button/index.d.ts.map +1 -0
  496. package/build-types/toolbar/toolbar-button/toolbar-button-container.d.ts +3 -0
  497. package/build-types/toolbar/toolbar-button/toolbar-button-container.d.ts.map +1 -0
  498. package/build-types/toolbar/toolbar-context/index.d.ts +3 -0
  499. package/build-types/toolbar/toolbar-context/index.d.ts.map +1 -0
  500. package/build-types/toolbar/toolbar-dropdown-menu/index.d.ts +3 -0
  501. package/build-types/toolbar/toolbar-dropdown-menu/index.d.ts.map +1 -0
  502. package/build-types/toolbar/toolbar-group/index.d.ts +39 -0
  503. package/build-types/toolbar/toolbar-group/index.d.ts.map +1 -0
  504. package/build-types/toolbar/toolbar-group/toolbar-group-collapsed.d.ts +7 -0
  505. package/build-types/toolbar/toolbar-group/toolbar-group-collapsed.d.ts.map +1 -0
  506. package/build-types/toolbar/toolbar-group/toolbar-group-container.d.ts +7 -0
  507. package/build-types/toolbar/toolbar-group/toolbar-group-container.d.ts.map +1 -0
  508. package/build-types/toolbar/toolbar-item/index.d.ts +7 -0
  509. package/build-types/toolbar/toolbar-item/index.d.ts.map +1 -0
  510. package/build-types/tools-panel/context.d.ts.map +1 -1
  511. package/build-types/tools-panel/stories/index.d.ts +17 -0
  512. package/build-types/tools-panel/stories/index.d.ts.map +1 -0
  513. package/build-types/tools-panel/test/index.d.ts +2 -0
  514. package/build-types/tools-panel/test/index.d.ts.map +1 -0
  515. package/build-types/tools-panel/tools-panel/component.d.ts +54 -2
  516. package/build-types/tools-panel/tools-panel/component.d.ts.map +1 -1
  517. package/build-types/tools-panel/tools-panel/hook.d.ts +5 -2
  518. package/build-types/tools-panel/tools-panel/hook.d.ts.map +1 -1
  519. package/build-types/tools-panel/tools-panel-header/component.d.ts.map +1 -1
  520. package/build-types/tools-panel/tools-panel-header/hook.d.ts +2 -1
  521. package/build-types/tools-panel/tools-panel-header/hook.d.ts.map +1 -1
  522. package/build-types/tools-panel/tools-panel-item/component.d.ts +3 -2
  523. package/build-types/tools-panel/tools-panel-item/component.d.ts.map +1 -1
  524. package/build-types/tools-panel/tools-panel-item/hook.d.ts.map +1 -1
  525. package/build-types/tools-panel/types.d.ts +49 -20
  526. package/build-types/tools-panel/types.d.ts.map +1 -1
  527. package/build-types/tree-grid/cell.d.ts +13 -0
  528. package/build-types/tree-grid/cell.d.ts.map +1 -0
  529. package/build-types/tree-grid/index.d.ts +70 -0
  530. package/build-types/tree-grid/index.d.ts.map +1 -0
  531. package/build-types/tree-grid/item.d.ts +12 -0
  532. package/build-types/tree-grid/item.d.ts.map +1 -0
  533. package/build-types/tree-grid/roving-tab-index-context.d.ts +10 -0
  534. package/build-types/tree-grid/roving-tab-index-context.d.ts.map +1 -0
  535. package/build-types/tree-grid/roving-tab-index-item.d.ts +5 -0
  536. package/build-types/tree-grid/roving-tab-index-item.d.ts.map +1 -0
  537. package/build-types/tree-grid/roving-tab-index.d.ts +10 -0
  538. package/build-types/tree-grid/roving-tab-index.d.ts.map +1 -0
  539. package/build-types/tree-grid/row.d.ts +12 -0
  540. package/build-types/tree-grid/row.d.ts.map +1 -0
  541. package/build-types/tree-grid/stories/index.d.ts +13 -0
  542. package/build-types/tree-grid/stories/index.d.ts.map +1 -0
  543. package/build-types/tree-grid/test/cell.d.ts +2 -0
  544. package/build-types/tree-grid/test/cell.d.ts.map +1 -0
  545. package/build-types/tree-grid/test/index.d.ts +2 -0
  546. package/build-types/tree-grid/test/index.d.ts.map +1 -0
  547. package/build-types/tree-grid/test/roving-tab-index-item.d.ts +2 -0
  548. package/build-types/tree-grid/test/roving-tab-index-item.d.ts.map +1 -0
  549. package/build-types/tree-grid/test/roving-tab-index.d.ts +2 -0
  550. package/build-types/tree-grid/test/roving-tab-index.d.ts.map +1 -0
  551. package/build-types/tree-grid/test/row.d.ts +2 -0
  552. package/build-types/tree-grid/test/row.d.ts.map +1 -0
  553. package/build-types/tree-grid/types.d.ts +109 -0
  554. package/build-types/tree-grid/types.d.ts.map +1 -0
  555. package/build-types/ui/context/context-connect.d.ts +7 -7
  556. package/build-types/ui/context/context-system-provider.d.ts.map +1 -1
  557. package/build-types/ui/context/get-styled-class-name-from-key.d.ts +1 -1
  558. package/build-types/ui/utils/get-valid-children.d.ts +1 -1
  559. package/build-types/ui/utils/space.d.ts +1 -1
  560. package/build-types/unit-control/index.d.ts +1 -1
  561. package/build-types/unit-control/utils.d.ts +20 -20
  562. package/build-types/utils/events.d.ts +2 -2
  563. package/build-types/utils/hooks/use-controlled-state.d.ts +1 -1
  564. package/build-types/utils/hooks/use-controlled-state.d.ts.map +1 -1
  565. package/build-types/utils/hooks/use-controlled-value.d.ts +4 -4
  566. package/build-types/utils/hooks/use-latest-ref.d.ts +1 -1
  567. package/build-types/utils/unit-values.d.ts +3 -3
  568. package/build-types/v-stack/stories/e2e/index.d.ts +9 -0
  569. package/build-types/v-stack/stories/e2e/index.d.ts.map +1 -0
  570. package/package.json +21 -19
  571. package/src/alignment-matrix-control/utils.tsx +4 -4
  572. package/src/angle-picker-control/README.md +17 -14
  573. package/src/angle-picker-control/{angle-circle.js → angle-circle.tsx} +44 -12
  574. package/src/angle-picker-control/{index.js → index.tsx} +54 -10
  575. package/src/angle-picker-control/stories/index.tsx +57 -0
  576. package/src/angle-picker-control/styles/{angle-picker-control-styles.js → angle-picker-control-styles.tsx} +5 -1
  577. package/src/angle-picker-control/types.ts +29 -0
  578. package/src/autocomplete/autocompleter-ui.js +72 -34
  579. package/src/autocomplete/autocompleter-ui.native.js +1 -0
  580. package/src/autocomplete/index.js +36 -36
  581. package/src/base-control/hooks.ts +1 -1
  582. package/src/border-box-control/test/{index.js → index.tsx} +76 -102
  583. package/src/border-box-control/test/{utils.js → utils.ts} +20 -0
  584. package/src/border-box-control/utils.ts +1 -1
  585. package/src/box-control/README.md +17 -26
  586. package/src/box-control/{all-input-control.js → all-input-control.tsx} +10 -6
  587. package/src/box-control/{axial-input-controls.js → axial-input-controls.tsx} +29 -24
  588. package/src/box-control/{icon.js → icon.tsx} +9 -4
  589. package/src/box-control/{index.js → index.tsx} +43 -8
  590. package/src/box-control/{input-controls.js → input-controls.tsx} +26 -16
  591. package/src/box-control/{linked-button.js → linked-button.tsx} +4 -1
  592. package/src/box-control/styles/{box-control-icon-styles.js → box-control-icon-styles.ts} +1 -1
  593. package/src/box-control/styles/{box-control-styles.js → box-control-styles.ts} +10 -2
  594. package/src/box-control/styles/{box-control-visualizer-styles.js → box-control-visualizer-styles.ts} +6 -2
  595. package/src/box-control/test/{index.js → index.tsx} +12 -9
  596. package/src/box-control/types.ts +121 -0
  597. package/src/box-control/{unit-control.js → unit-control.tsx} +9 -2
  598. package/src/box-control/{utils.js → utils.ts} +47 -38
  599. package/src/button/test/index.tsx +38 -30
  600. package/src/circular-option-picker/README.md +141 -0
  601. package/src/circular-option-picker/{index.js → index.tsx} +74 -14
  602. package/src/circular-option-picker/stories/index.tsx +134 -0
  603. package/src/circular-option-picker/types.ts +69 -0
  604. package/src/color-palette/README.md +7 -0
  605. package/src/color-palette/index.tsx +6 -1
  606. package/src/color-palette/test/__snapshots__/index.tsx.snap +1 -1
  607. package/src/color-palette/types.ts +8 -0
  608. package/src/combobox-control/README.md +8 -15
  609. package/src/combobox-control/{index.js → index.tsx} +91 -19
  610. package/src/combobox-control/stories/index.tsx +114 -0
  611. package/src/combobox-control/styles.ts +4 -1
  612. package/src/combobox-control/test/{index.js → index.tsx} +9 -7
  613. package/src/combobox-control/types.ts +69 -0
  614. package/src/custom-gradient-picker/index.js +0 -1
  615. package/src/custom-select-control/stories/index.js +1 -1
  616. package/src/date-time/time/index.tsx +1 -1
  617. package/src/date-time/utils.ts +1 -1
  618. package/src/draggable/index.tsx +2 -2
  619. package/src/dropdown-menu/test/index.js +3 -11
  620. package/src/focal-point-picker/utils.ts +3 -3
  621. package/src/font-size-picker/utils.ts +2 -2
  622. package/src/gradient-picker/README.md +8 -0
  623. package/src/gradient-picker/index.js +6 -1
  624. package/src/h-stack/stories/e2e/index.tsx +36 -0
  625. package/src/higher-order/with-constrained-tabbing/index.tsx +30 -0
  626. package/src/input-control/reducer/reducer.ts +5 -5
  627. package/src/input-control/utils.ts +1 -1
  628. package/src/menu-items-choice/index.tsx +83 -0
  629. package/src/menu-items-choice/stories/index.tsx +79 -0
  630. package/src/menu-items-choice/types.ts +54 -0
  631. package/src/mobile/global-styles-context/utils.native.js +1 -0
  632. package/src/modal/index.tsx +45 -1
  633. package/src/modal/style.scss +8 -0
  634. package/src/modal/types.ts +2 -0
  635. package/src/palette-edit/index.js +4 -1
  636. package/src/panel/README.md +2 -2
  637. package/src/panel/header.tsx +20 -0
  638. package/src/panel/index.tsx +48 -0
  639. package/src/panel/row.tsx +37 -0
  640. package/src/panel/stories/index.js +22 -0
  641. package/src/panel/test/{header.js → header.tsx} +1 -1
  642. package/src/panel/test/{index.js → index.tsx} +6 -4
  643. package/src/panel/test/{row.js → row.tsx} +4 -2
  644. package/src/panel/types.ts +38 -0
  645. package/src/popover/README.md +4 -1
  646. package/src/popover/index.tsx +17 -1
  647. package/src/popover/overlay-middlewares.tsx +29 -0
  648. package/src/popover/stories/index.tsx +7 -1
  649. package/src/popover/test/index.tsx +29 -21
  650. package/src/popover/types.ts +4 -2
  651. package/src/popover/utils.ts +39 -3
  652. package/src/query-controls/terms.ts +1 -1
  653. package/src/range-control/utils.ts +4 -4
  654. package/src/resizable-box/resize-tooltip/utils.ts +14 -14
  655. package/src/snackbar/index.tsx +2 -2
  656. package/src/tab-panel/stories/index.tsx +41 -0
  657. package/src/tab-panel/test/index.tsx +794 -262
  658. package/src/toolbar/stories/{index.js → index.tsx} +39 -26
  659. package/src/toolbar/test/{toolbar-group.js → toolbar-group.tsx} +2 -2
  660. package/src/toolbar/toolbar/README.md +7 -2
  661. package/src/toolbar/toolbar/{index.js → index.tsx} +33 -12
  662. package/src/toolbar/toolbar/{toolbar-container.js → toolbar-container.tsx} +9 -2
  663. package/src/toolbar/toolbar/types.ts +15 -0
  664. package/src/toolbar/toolbar-button/index.js +2 -0
  665. package/src/toolbar/toolbar-button/toolbar-button-container.js +2 -0
  666. package/src/toolbar/toolbar-context/index.js +2 -0
  667. package/src/toolbar/toolbar-dropdown-menu/index.js +2 -0
  668. package/src/toolbar/toolbar-group/index.js +2 -0
  669. package/src/toolbar/toolbar-group/toolbar-group-collapsed.js +2 -0
  670. package/src/toolbar/toolbar-group/toolbar-group-container.js +2 -0
  671. package/src/toolbar/toolbar-item/index.js +2 -0
  672. package/src/tools-panel/context.ts +2 -0
  673. package/src/tools-panel/stories/{index.js → index.tsx} +196 -95
  674. package/src/tools-panel/test/{index.js → index.tsx} +177 -67
  675. package/src/tools-panel/tools-panel/README.md +12 -4
  676. package/src/tools-panel/tools-panel/component.tsx +57 -3
  677. package/src/tools-panel/tools-panel/hook.ts +34 -13
  678. package/src/tools-panel/tools-panel-header/README.md +7 -0
  679. package/src/tools-panel/tools-panel-header/component.tsx +2 -1
  680. package/src/tools-panel/tools-panel-header/hook.ts +6 -4
  681. package/src/tools-panel/tools-panel-item/README.md +6 -4
  682. package/src/tools-panel/tools-panel-item/component.tsx +4 -4
  683. package/src/tools-panel/tools-panel-item/hook.ts +22 -4
  684. package/src/tools-panel/types.ts +51 -20
  685. package/src/tree-grid/README.md +18 -58
  686. package/src/tree-grid/cell.tsx +41 -0
  687. package/src/tree-grid/{index.js → index.tsx} +111 -35
  688. package/src/tree-grid/item.tsx +32 -0
  689. package/src/tree-grid/{roving-tab-index-context.js → roving-tab-index-context.ts} +9 -1
  690. package/src/tree-grid/roving-tab-index-item.tsx +50 -0
  691. package/src/tree-grid/{roving-tab-index.js → roving-tab-index.tsx} +7 -5
  692. package/src/tree-grid/row.tsx +47 -0
  693. package/src/tree-grid/stories/index.tsx +144 -0
  694. package/src/tree-grid/test/__snapshots__/index.tsx.snap +3 -0
  695. package/src/tree-grid/test/{cell.js → cell.tsx} +7 -4
  696. package/src/tree-grid/test/{index.js → index.tsx} +13 -5
  697. package/src/tree-grid/test/{roving-tab-index-item.js → roving-tab-index-item.tsx} +7 -4
  698. package/src/tree-grid/test/{row.js → row.tsx} +4 -4
  699. package/src/tree-grid/types.ts +116 -0
  700. package/src/ui/context/context-connect.ts +7 -7
  701. package/src/ui/context/context-system-provider.js +7 -4
  702. package/src/ui/context/get-styled-class-name-from-key.ts +1 -1
  703. package/src/ui/utils/get-valid-children.ts +1 -1
  704. package/src/ui/utils/space.ts +1 -1
  705. package/src/unit-control/index.tsx +2 -2
  706. package/src/unit-control/utils.ts +20 -20
  707. package/src/utils/events.ts +4 -4
  708. package/src/utils/hooks/use-controlled-state.js +2 -2
  709. package/src/utils/hooks/use-controlled-value.ts +4 -4
  710. package/src/utils/hooks/use-latest-ref.ts +1 -1
  711. package/src/utils/unit-values.ts +3 -3
  712. package/src/v-stack/stories/e2e/index.tsx +36 -0
  713. package/tsconfig.json +1 -7
  714. package/tsconfig.tsbuildinfo +1 -1
  715. package/build/base-field/hook.js +0 -54
  716. package/build/base-field/hook.js.map +0 -1
  717. package/build/base-field/index.js +0 -14
  718. package/build/base-field/index.js.map +0 -1
  719. package/build/base-field/styles.js +0 -33
  720. package/build/base-field/styles.js.map +0 -1
  721. package/build/resizable-box/styles/resizable-box.styles.js +0 -2
  722. package/build-module/base-field/hook.js +0 -37
  723. package/build-module/base-field/hook.js.map +0 -1
  724. package/build-module/base-field/index.js +0 -2
  725. package/build-module/base-field/index.js.map +0 -1
  726. package/build-module/base-field/styles.js +0 -18
  727. package/build-module/base-field/styles.js.map +0 -1
  728. package/build-module/resizable-box/styles/resizable-box.styles.js +0 -2
  729. package/build-types/base-field/hook.d.ts +0 -270
  730. package/build-types/base-field/hook.d.ts.map +0 -1
  731. package/build-types/base-field/index.d.ts +0 -2
  732. package/build-types/base-field/index.d.ts.map +0 -1
  733. package/build-types/base-field/styles.d.ts +0 -6
  734. package/build-types/base-field/styles.d.ts.map +0 -1
  735. package/build-types/base-field/types.d.ts +0 -29
  736. package/build-types/base-field/types.d.ts.map +0 -1
  737. package/build-types/resizable-box/styles/resizable-box.styles.d.ts +0 -1
  738. package/build-types/resizable-box/styles/resizable-box.styles.d.ts.map +0 -1
  739. package/src/angle-picker-control/stories/index.js +0 -29
  740. package/src/base-field/README.md +0 -66
  741. package/src/base-field/hook.ts +0 -51
  742. package/src/base-field/index.ts +0 -1
  743. package/src/base-field/styles.ts +0 -86
  744. package/src/base-field/test/__snapshots__/index.tsx.snap +0 -141
  745. package/src/base-field/test/index.tsx +0 -84
  746. package/src/base-field/types.ts +0 -29
  747. package/src/combobox-control/stories/index.js +0 -339
  748. package/src/higher-order/with-constrained-tabbing/index.js +0 -22
  749. package/src/menu-items-choice/index.js +0 -43
  750. package/src/panel/header.js +0 -10
  751. package/src/panel/index.js +0 -26
  752. package/src/panel/row.js +0 -20
  753. package/src/resizable-box/styles/resizable-box.styles.js +0 -0
  754. package/src/tools-panel/stories/utils/tools-panel-with-item-group-slot.js +0 -246
  755. package/src/tree-grid/cell.js +0 -24
  756. package/src/tree-grid/item.js +0 -20
  757. package/src/tree-grid/roving-tab-index-item.js +0 -33
  758. package/src/tree-grid/row.js +0 -31
  759. package/src/tree-grid/stories/index.js +0 -106
  760. package/src/tree-grid/test/__snapshots__/index.js.snap +0 -3
  761. /package/build/{base-field → angle-picker-control}/types.js +0 -0
  762. /package/build-module/{base-field → angle-picker-control}/types.js +0 -0
  763. /package/build-module/{base-field → angle-picker-control}/types.js.map +0 -0
  764. /package/{build/base-field → build-module/box-control}/types.js.map +0 -0
  765. /package/build-module/{resizable-box/styles/resizable-box.styles.js.map → circular-option-picker/types.js.map} +0 -0
  766. /package/{build/resizable-box/styles/resizable-box.styles.js.map → build-module/combobox-control/types.js.map} +0 -0
  767. /package/build-types/{base-field → border-box-control}/test/index.d.ts +0 -0
  768. /package/src/panel/test/__snapshots__/{header.js.snap → header.tsx.snap} +0 -0
  769. /package/src/panel/test/__snapshots__/{index.js.snap → index.tsx.snap} +0 -0
  770. /package/src/panel/test/__snapshots__/{row.js.snap → row.tsx.snap} +0 -0
  771. /package/src/resizable-box/resize-tooltip/styles/{resize-tooltip.styles.js → resize-tooltip.styles.ts} +0 -0
  772. /package/src/toolbar/test/{index.js → index.tsx} +0 -0
  773. /package/src/tree-grid/test/__snapshots__/{cell.js.snap → cell.tsx.snap} +0 -0
  774. /package/src/tree-grid/test/__snapshots__/{roving-tab-index-item.js.snap → roving-tab-index-item.tsx.snap} +0 -0
  775. /package/src/tree-grid/test/__snapshots__/{roving-tab-index.js.snap → roving-tab-index.tsx.snap} +0 -0
  776. /package/src/tree-grid/test/__snapshots__/{row.js.snap → row.tsx.snap} +0 -0
  777. /package/src/tree-grid/test/{roving-tab-index.js → roving-tab-index.tsx} +0 -0
@@ -1,15 +1,20 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render, screen } from '@testing-library/react';
4
+ import { render, screen, waitFor } from '@testing-library/react';
5
5
  import userEvent from '@testing-library/user-event';
6
6
 
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { wordpress, category, media } from '@wordpress/icons';
11
+
7
12
  /**
8
13
  * Internal dependencies
9
14
  */
10
15
  import TabPanel from '..';
11
-
12
- const setupUser = () => userEvent.setup();
16
+ import Popover from '../../popover';
17
+ import { Provider as SlotFillProvider } from '../../slot-fill';
13
18
 
14
19
  const TABS = [
15
20
  {
@@ -33,7 +38,14 @@ const getSelectedTab = () => screen.getByRole( 'tab', { selected: true } );
33
38
 
34
39
  let originalGetClientRects: () => DOMRectList;
35
40
 
36
- describe( 'TabPanel', () => {
41
+ describe.each( [
42
+ [ 'uncontrolled', TabPanel ],
43
+ // The controlled component tests will be added once we certify the
44
+ // uncontrolled component's behaviour on trunk.
45
+ // [ 'controlled', TabPanel ],
46
+ ] )( 'TabPanel %s', ( ...modeAndComponent ) => {
47
+ const [ , Component ] = modeAndComponent;
48
+
37
49
  beforeAll( () => {
38
50
  originalGetClientRects = window.HTMLElement.prototype.getClientRects;
39
51
  // Mocking `getClientRects()` is necessary to pass a check performed by
@@ -49,295 +61,589 @@ describe( 'TabPanel', () => {
49
61
  window.HTMLElement.prototype.getClientRects = originalGetClientRects;
50
62
  } );
51
63
 
52
- it( 'should render a tabpanel, and clicking should change tabs', async () => {
53
- const user = setupUser();
54
- const panelRenderFunction = jest.fn();
55
- const mockOnSelect = jest.fn();
56
-
57
- render(
58
- <TabPanel
59
- tabs={ TABS }
60
- children={ panelRenderFunction }
61
- onSelect={ mockOnSelect }
62
- />
63
- );
64
-
65
- expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
66
- expect(
67
- screen.getByRole( 'tabpanel', { name: 'Alpha' } )
68
- ).toBeInTheDocument();
69
- expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 0 ] );
70
- expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
71
-
72
- await user.click( screen.getByRole( 'tab', { name: 'Beta' } ) );
73
-
74
- expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
75
- expect(
76
- screen.getByRole( 'tabpanel', { name: 'Beta' } )
77
- ).toBeInTheDocument();
78
- expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 1 ] );
79
- expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
80
-
81
- await user.click( screen.getByRole( 'tab', { name: 'Alpha' } ) );
82
-
83
- expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
84
- expect(
85
- screen.getByRole( 'tabpanel', { name: 'Alpha' } )
86
- ).toBeInTheDocument();
87
- expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 0 ] );
88
- expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
89
- } );
64
+ describe( 'Accessibility and semantics', () => {
65
+ test( 'should use the correct aria attributes', () => {
66
+ const panelRenderFunction = jest.fn();
90
67
 
91
- it( 'should render with a tab initially selected by prop initialTabIndex', () => {
92
- render(
93
- <TabPanel
94
- initialTabName="beta"
95
- tabs={ TABS }
96
- children={ () => undefined }
97
- />
98
- );
99
- const selectedTab = screen.getByRole( 'tab', { selected: true } );
100
- expect( selectedTab ).toHaveTextContent( 'Beta' );
101
- } );
68
+ render(
69
+ <Component tabs={ TABS } children={ panelRenderFunction } />
70
+ );
102
71
 
103
- it( 'should apply the `activeClass` to the selected tab', async () => {
104
- const user = setupUser();
105
- const activeClass = 'my-active-tab';
106
-
107
- render(
108
- <TabPanel
109
- activeClass={ activeClass }
110
- tabs={ TABS }
111
- children={ () => undefined }
112
- />
113
- );
114
- expect( getSelectedTab() ).toHaveClass( activeClass );
115
- screen
116
- .getAllByRole( 'tab', { selected: false } )
117
- .forEach( ( unselectedTab ) => {
118
- expect( unselectedTab ).not.toHaveClass( activeClass );
119
- } );
120
-
121
- await user.click( screen.getByRole( 'tab', { name: 'Beta' } ) );
122
-
123
- expect( getSelectedTab() ).toHaveClass( activeClass );
124
- screen
125
- .getAllByRole( 'tab', { selected: false } )
126
- .forEach( ( unselectedTab ) => {
127
- expect( unselectedTab ).not.toHaveClass( activeClass );
128
- } );
129
- } );
72
+ const tabList = screen.getByRole( 'tablist' );
73
+ const allTabs = screen.getAllByRole( 'tab' );
74
+ const selectedTabPanel = screen.getByRole( 'tabpanel' );
130
75
 
131
- it( "should apply the tab's `className` to the tab button", () => {
132
- render( <TabPanel tabs={ TABS } children={ () => undefined } /> );
133
-
134
- expect( screen.getByRole( 'tab', { name: 'Alpha' } ) ).toHaveClass(
135
- 'alpha-class'
136
- );
137
- expect( screen.getByRole( 'tab', { name: 'Beta' } ) ).toHaveClass(
138
- 'beta-class'
139
- );
140
- expect( screen.getByRole( 'tab', { name: 'Gamma' } ) ).toHaveClass(
141
- 'gamma-class'
142
- );
143
- } );
76
+ expect( tabList ).toBeVisible();
77
+ expect( tabList ).toHaveAttribute(
78
+ 'aria-orientation',
79
+ 'horizontal'
80
+ );
144
81
 
145
- it( 'should select `initialTabName` if defined', () => {
146
- const mockOnSelect = jest.fn();
147
-
148
- render(
149
- <TabPanel
150
- tabs={ TABS }
151
- initialTabName="beta"
152
- children={ () => undefined }
153
- onSelect={ mockOnSelect }
154
- />
155
- );
156
- expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
157
- expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
158
- } );
82
+ expect( allTabs ).toHaveLength( TABS.length );
159
83
 
160
- it( 'waits for the tab with the `initialTabName` to become present in the `tabs` array before selecting it', () => {
161
- const mockOnSelect = jest.fn();
162
-
163
- const { rerender } = render(
164
- <TabPanel
165
- tabs={ TABS }
166
- initialTabName="delta"
167
- children={ () => undefined }
168
- onSelect={ mockOnSelect }
169
- />
170
- );
171
-
172
- // There should be no selected tab.
173
- expect(
174
- screen.queryByRole( 'tab', { selected: true } )
175
- ).not.toBeInTheDocument();
176
-
177
- rerender(
178
- <TabPanel
179
- tabs={ [
180
- { name: 'delta', title: 'Delta', className: 'delta-class' },
181
- ...TABS,
182
- ] }
183
- initialTabName="delta"
184
- children={ () => undefined }
185
- onSelect={ mockOnSelect }
186
- />
187
- );
188
-
189
- expect( getSelectedTab() ).toHaveTextContent( 'Delta' );
190
- expect( mockOnSelect ).toHaveBeenLastCalledWith( 'delta' );
191
- } );
84
+ // The selected `tab` aria-controls the active `tabpanel`,
85
+ // which is `aria-labelledby` the selected `tab`.
86
+ expect( selectedTabPanel ).toBeVisible();
87
+ expect( allTabs[ 0 ] ).toHaveAttribute(
88
+ 'aria-controls',
89
+ selectedTabPanel.getAttribute( 'id' )
90
+ );
91
+ expect( selectedTabPanel ).toHaveAttribute(
92
+ 'aria-labelledby',
93
+ allTabs[ 0 ].getAttribute( 'id' )
94
+ );
95
+ } );
192
96
 
193
- it( 'should disable the tab when `disabled` is true', async () => {
194
- const user = setupUser();
195
- const mockOnSelect = jest.fn();
196
-
197
- render(
198
- <TabPanel
199
- tabs={ [
200
- ...TABS,
201
- {
202
- name: 'delta',
203
- title: 'Delta',
204
- className: 'delta-class',
205
- disabled: true,
206
- },
207
- ] }
208
- children={ () => undefined }
209
- onSelect={ mockOnSelect }
210
- />
211
- );
212
-
213
- expect( screen.getByRole( 'tab', { name: 'Delta' } ) ).toHaveAttribute(
214
- 'aria-disabled',
215
- 'true'
216
- );
217
-
218
- // onSelect gets called on the initial render.
219
- expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
220
-
221
- // onSelect should not be called since the disabled tab is highlighted, but not selected.
222
- await user.keyboard( '[ArrowLeft]' );
223
- expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
224
- } );
97
+ test( 'should display a tooltip when hovering tabs provided with an icon', async () => {
98
+ const user = userEvent.setup();
225
99
 
226
- it( 'should select the first enabled tab when the inital tab is disabled', () => {
227
- const mockOnSelect = jest.fn();
228
-
229
- render(
230
- <TabPanel
231
- tabs={ [
232
- {
233
- name: 'alpha',
234
- title: 'Alpha',
235
- className: 'alpha-class',
236
- disabled: true,
237
- },
238
- {
239
- name: 'beta',
240
- title: 'Beta',
241
- className: 'beta-class',
242
- },
243
- ] }
244
- initialTabName="alpha"
245
- children={ () => undefined }
246
- onSelect={ mockOnSelect }
247
- />
248
- );
249
-
250
- expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
251
- } );
100
+ const panelRenderFunction = jest.fn();
252
101
 
253
- it( 'should select the first enabled tab when the currently selected becomes disabled', () => {
254
- const mockOnSelect = jest.fn();
102
+ const TABS_WITH_ICON = [
103
+ { ...TABS[ 0 ], icon: wordpress },
104
+ { ...TABS[ 1 ], icon: category },
105
+ { ...TABS[ 2 ], icon: media },
106
+ ];
255
107
 
256
- const { rerender } = render(
257
- <TabPanel
258
- tabs={ TABS }
259
- children={ () => undefined }
260
- onSelect={ mockOnSelect }
261
- />
262
- );
108
+ render(
109
+ // In order for the tooltip to display properly, there needs to be
110
+ // `Popover.Slot` in which the `Popover` renders outside of the
111
+ // `TabPanel` component, otherwise the tooltip renders inline.
112
+ <SlotFillProvider>
113
+ <Component
114
+ tabs={ TABS_WITH_ICON }
115
+ children={ panelRenderFunction }
116
+ />
117
+ { /* @ts-expect-error The 'Slot' component hasn't been typed yet. */ }
118
+ <Popover.Slot />
119
+ </SlotFillProvider>
120
+ );
263
121
 
264
- expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
122
+ const allTabs = screen.getAllByRole( 'tab' );
265
123
 
266
- rerender(
267
- <TabPanel
268
- tabs={ TABS.map( ( tab ) => {
269
- if ( tab.name === 'alpha' ) {
270
- return { ...tab, disabled: true };
271
- }
272
- return tab;
273
- } ) }
274
- children={ () => undefined }
275
- onSelect={ mockOnSelect }
276
- />
277
- );
278
-
279
- expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
124
+ for ( let i = 0; i < allTabs.length; i++ ) {
125
+ expect(
126
+ screen.queryByText( TABS_WITH_ICON[ i ].title )
127
+ ).not.toBeInTheDocument();
128
+
129
+ await user.hover( allTabs[ i ] );
130
+
131
+ await waitFor( () =>
132
+ expect(
133
+ screen.getByText( TABS_WITH_ICON[ i ].title )
134
+ ).toBeVisible()
135
+ );
136
+
137
+ await user.unhover( allTabs[ i ] );
138
+ }
139
+ } );
140
+
141
+ test( 'should display a tooltip when moving the selection via the keyboard on tabs provided with an icon', async () => {
142
+ const user = userEvent.setup();
143
+
144
+ const mockOnSelect = jest.fn();
145
+ const panelRenderFunction = jest.fn();
146
+
147
+ const TABS_WITH_ICON = [
148
+ { ...TABS[ 0 ], icon: wordpress },
149
+ { ...TABS[ 1 ], icon: category },
150
+ { ...TABS[ 2 ], icon: media },
151
+ ];
152
+
153
+ render(
154
+ // In order for the tooltip to display properly, there needs to be
155
+ // `Popover.Slot` in which the `Popover` renders outside of the
156
+ // `TabPanel` component, otherwise the tooltip renders inline.
157
+ <SlotFillProvider>
158
+ <Component
159
+ tabs={ TABS_WITH_ICON }
160
+ children={ panelRenderFunction }
161
+ onSelect={ mockOnSelect }
162
+ />
163
+ { /* @ts-expect-error The 'Slot' component hasn't been typed yet. */ }
164
+ <Popover.Slot />
165
+ </SlotFillProvider>
166
+ );
167
+
168
+ expect( getSelectedTab() ).not.toHaveTextContent( 'Alpha' );
169
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
170
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
171
+ await expect( getSelectedTab() ).not.toHaveFocus();
172
+
173
+ // Tab to focus the tablist. Make sure alpha is focused, and that the
174
+ // corresponding tooltip is shown.
175
+ expect( screen.queryByText( 'Alpha' ) ).not.toBeInTheDocument();
176
+ await user.keyboard( '[Tab]' );
177
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
178
+ expect( screen.getByText( 'Alpha' ) ).toBeInTheDocument();
179
+ await expect( getSelectedTab() ).toHaveFocus();
180
+
181
+ // Move selection with arrow keys. Make sure beta is focused, and that
182
+ // the corresponding tooltip is shown.
183
+ expect( screen.queryByText( 'Beta' ) ).not.toBeInTheDocument();
184
+ await user.keyboard( '[ArrowRight]' );
185
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
186
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
187
+ expect( screen.getByText( 'Beta' ) ).toBeInTheDocument();
188
+ await expect( getSelectedTab() ).toHaveFocus();
189
+
190
+ // Move selection with arrow keys. Make sure gamma is focused, and that
191
+ // the corresponding tooltip is shown.
192
+ expect( screen.queryByText( 'Gamma' ) ).not.toBeInTheDocument();
193
+ await user.keyboard( '[ArrowRight]' );
194
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
195
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
196
+ expect( screen.getByText( 'Gamma' ) ).toBeInTheDocument();
197
+ await expect( getSelectedTab() ).toHaveFocus();
198
+
199
+ // Move selection with arrow keys. Make sure beta is focused, and that
200
+ // the corresponding tooltip is shown.
201
+ expect( screen.queryByText( 'Beta' ) ).not.toBeInTheDocument();
202
+ await user.keyboard( '[ArrowLeft]' );
203
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 4 );
204
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
205
+ expect( screen.getByText( 'Beta' ) ).toBeInTheDocument();
206
+ await expect( getSelectedTab() ).toHaveFocus();
207
+ } );
280
208
  } );
281
209
 
282
- describe( 'fallbacks when new tab list invalidates current selection', () => {
283
- it( 'should select `initialTabName` if defined', async () => {
284
- const user = setupUser();
210
+ describe( 'Without `initialTabName`', () => {
211
+ it( 'should render first tab', async () => {
212
+ const panelRenderFunction = jest.fn();
213
+
214
+ render(
215
+ <Component tabs={ TABS } children={ panelRenderFunction } />
216
+ );
217
+
218
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
219
+ expect(
220
+ screen.getByRole( 'tabpanel', { name: 'Alpha' } )
221
+ ).toBeInTheDocument();
222
+ expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 0 ] );
223
+ } );
224
+
225
+ it( 'should fall back to first enabled tab if the active tab is removed', async () => {
285
226
  const mockOnSelect = jest.fn();
227
+ const { rerender } = render(
228
+ <Component
229
+ tabs={ TABS }
230
+ children={ () => undefined }
231
+ onSelect={ mockOnSelect }
232
+ />
233
+ );
234
+
235
+ rerender(
236
+ <Component
237
+ tabs={ TABS.slice( 1 ) /* remove alpha */ }
238
+ children={ () => undefined }
239
+ onSelect={ mockOnSelect }
240
+ />
241
+ );
242
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
243
+ } );
244
+ } );
286
245
 
246
+ describe( 'With `initialTabName`', () => {
247
+ it( 'should render the tab set by initialTabName prop', () => {
248
+ render(
249
+ <Component
250
+ initialTabName="beta"
251
+ tabs={ TABS }
252
+ children={ () => undefined }
253
+ />
254
+ );
255
+
256
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
257
+ } );
258
+
259
+ it( 'should not select a tab when `initialTabName` does not match any known tab', () => {
260
+ render(
261
+ <Component
262
+ initialTabName="does-not-exist"
263
+ tabs={ TABS }
264
+ children={ () => undefined }
265
+ />
266
+ );
267
+
268
+ // No tab should be selected i.e. it doesn't fall back to first tab.
269
+ expect(
270
+ screen.queryByRole( 'tab', { selected: true } )
271
+ ).not.toBeInTheDocument();
272
+
273
+ // No tabpanel should be rendered either
274
+ expect( screen.queryByRole( 'tabpanel' ) ).not.toBeInTheDocument();
275
+ } );
276
+
277
+ it( 'should not change tabs when initialTabName is changed', () => {
287
278
  const { rerender } = render(
288
- <TabPanel
279
+ <Component
280
+ initialTabName="beta"
281
+ tabs={ TABS }
282
+ children={ () => undefined }
283
+ />
284
+ );
285
+
286
+ rerender(
287
+ <Component
288
+ initialTabName="alpha"
289
289
  tabs={ TABS }
290
+ children={ () => undefined }
291
+ />
292
+ );
293
+
294
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
295
+ } );
296
+
297
+ it( 'should fall back to the tab associated to `initialTabName` if the currently active tab is removed', async () => {
298
+ const user = userEvent.setup();
299
+ const mockOnSelect = jest.fn();
300
+
301
+ const { rerender } = render(
302
+ <Component
290
303
  initialTabName="gamma"
304
+ tabs={ TABS }
291
305
  children={ () => undefined }
292
306
  onSelect={ mockOnSelect }
293
307
  />
294
308
  );
309
+
310
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
311
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
312
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
313
+
295
314
  await user.click( screen.getByRole( 'tab', { name: 'Alpha' } ) );
315
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
316
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
317
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
296
318
 
297
319
  rerender(
298
- <TabPanel
299
- tabs={ TABS.slice( 1 ) /* remove alpha */ }
320
+ <Component
300
321
  initialTabName="gamma"
322
+ tabs={ TABS.slice( 1 ) } // Remove alpha
301
323
  children={ () => undefined }
302
324
  onSelect={ mockOnSelect }
303
325
  />
304
326
  );
327
+
305
328
  expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
329
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
306
330
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
307
331
  } );
308
332
 
309
- it( 'should select first tab if `initialTabName` not defined', async () => {
310
- const user = setupUser();
333
+ it( 'should have no active tabs when the tab associated to `initialTabName` is removed while being the active tab', () => {
311
334
  const mockOnSelect = jest.fn();
312
335
 
313
336
  const { rerender } = render(
314
- <TabPanel
337
+ <Component
338
+ initialTabName="gamma"
315
339
  tabs={ TABS }
316
340
  children={ () => undefined }
317
341
  onSelect={ mockOnSelect }
318
342
  />
319
343
  );
320
- await user.click( screen.getByRole( 'tab', { name: 'Alpha' } ) );
344
+
345
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
346
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
347
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
321
348
 
322
349
  rerender(
323
- <TabPanel
324
- tabs={ TABS.slice( 1 ) /* remove alpha */ }
350
+ <Component
351
+ initialTabName="gamma"
352
+ tabs={ TABS.slice( 0, 2 ) } // Remove gamma
353
+ children={ () => undefined }
354
+ onSelect={ mockOnSelect }
355
+ />
356
+ );
357
+
358
+ expect( screen.getAllByRole( 'tab' ) ).toHaveLength( 2 );
359
+ expect(
360
+ screen.queryByRole( 'tab', { selected: true } )
361
+ ).not.toBeInTheDocument();
362
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
363
+ } );
364
+
365
+ it( 'waits for the tab with the `initialTabName` to be present in the `tabs` array before selecting it', () => {
366
+ const mockOnSelect = jest.fn();
367
+ const { rerender } = render(
368
+ <Component
369
+ initialTabName="delta"
370
+ tabs={ TABS }
371
+ children={ () => undefined }
372
+ onSelect={ mockOnSelect }
373
+ />
374
+ );
375
+
376
+ // There should be no selected tab yet.
377
+ expect(
378
+ screen.queryByRole( 'tab', { selected: true } )
379
+ ).not.toBeInTheDocument();
380
+
381
+ rerender(
382
+ <Component
383
+ initialTabName="delta"
384
+ tabs={ [
385
+ {
386
+ name: 'delta',
387
+ title: 'Delta',
388
+ className: 'delta-class',
389
+ },
390
+ ...TABS,
391
+ ] }
392
+ children={ () => undefined }
393
+ onSelect={ mockOnSelect }
394
+ />
395
+ );
396
+
397
+ expect( getSelectedTab() ).toHaveTextContent( 'Delta' );
398
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'delta' );
399
+ } );
400
+ } );
401
+
402
+ describe( 'Disabled Tab', () => {
403
+ it( 'should disable the tab when `disabled` is `true`', async () => {
404
+ const user = userEvent.setup();
405
+ const mockOnSelect = jest.fn();
406
+
407
+ render(
408
+ <Component
409
+ tabs={ [
410
+ ...TABS,
411
+ {
412
+ name: 'delta',
413
+ title: 'Delta',
414
+ className: 'delta-class',
415
+ disabled: true,
416
+ },
417
+ ] }
418
+ children={ () => undefined }
419
+ onSelect={ mockOnSelect }
420
+ />
421
+ );
422
+
423
+ expect(
424
+ screen.getByRole( 'tab', { name: 'Delta' } )
425
+ ).toHaveAttribute( 'aria-disabled', 'true' );
426
+
427
+ // onSelect gets called on the initial render.
428
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
429
+
430
+ // onSelect should not be called since the disabled tab is
431
+ // highlighted, but not selected.
432
+ await user.keyboard( '[ArrowLeft]' );
433
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
434
+ } );
435
+
436
+ it( 'should select first enabled tab when the initial tab is disabled', () => {
437
+ const mockOnSelect = jest.fn();
438
+
439
+ const { rerender } = render(
440
+ <Component
441
+ // Disable alpha
442
+ tabs={ TABS.map( ( tab ) => {
443
+ if ( tab.name !== 'alpha' ) {
444
+ return tab;
445
+ }
446
+ return { ...tab, disabled: true };
447
+ } ) }
325
448
  children={ () => undefined }
326
449
  onSelect={ mockOnSelect }
327
450
  />
328
451
  );
452
+
453
+ // As alpha (first tab) is disabled,
454
+ // the first enabled tab should be gamma.
329
455
  expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
456
+
457
+ // Re-enable all tabs
458
+ rerender(
459
+ <Component
460
+ tabs={ TABS }
461
+ children={ () => undefined }
462
+ onSelect={ mockOnSelect }
463
+ />
464
+ );
465
+
466
+ // Even if the initial tab becomes enabled again, the selected tab doesn't
467
+ // change.
468
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
469
+ } );
470
+
471
+ it( 'should select first enabled tab when the tab associated to `initialTabName` is disabled', () => {
472
+ const mockOnSelect = jest.fn();
473
+
474
+ const { rerender } = render(
475
+ <Component
476
+ tabs={ TABS.map( ( tab ) => {
477
+ if ( tab.name === 'gamma' ) {
478
+ return tab;
479
+ }
480
+ return { ...tab, disabled: true };
481
+ } ) }
482
+ initialTabName="beta"
483
+ children={ () => undefined }
484
+ onSelect={ mockOnSelect }
485
+ />
486
+ );
487
+
488
+ // As alpha (first tab), and beta (the initial tab), are both
489
+ // disabled the first enabled tab should be gamma.
490
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
491
+
492
+ // Re-enable all tabs
493
+ rerender(
494
+ <Component
495
+ tabs={ TABS }
496
+ initialTabName="beta"
497
+ children={ () => undefined }
498
+ onSelect={ mockOnSelect }
499
+ />
500
+ );
501
+
502
+ // Even if the initial tab becomes enabled again, the selected tab doesn't
503
+ // change.
504
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
505
+ } );
506
+
507
+ it( 'should select the first enabled tab when the selected tab becomes disabled', () => {
508
+ const mockOnSelect = jest.fn();
509
+ const { rerender } = render(
510
+ <Component
511
+ tabs={ TABS }
512
+ children={ () => undefined }
513
+ onSelect={ mockOnSelect }
514
+ />
515
+ );
516
+
517
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
518
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
519
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
520
+
521
+ rerender(
522
+ <Component
523
+ tabs={ TABS.map( ( tab ) => {
524
+ if ( tab.name === 'alpha' ) {
525
+ return { ...tab, disabled: true };
526
+ }
527
+ return tab;
528
+ } ) }
529
+ children={ () => undefined }
530
+ onSelect={ mockOnSelect }
531
+ />
532
+ );
533
+
534
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
535
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
330
536
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
537
+
538
+ rerender(
539
+ <Component
540
+ tabs={ TABS }
541
+ children={ () => undefined }
542
+ onSelect={ mockOnSelect }
543
+ />
544
+ );
545
+
546
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
547
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
548
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
549
+ } );
550
+
551
+ it( 'should select the first enabled tab when the tab associated to `initialTabName` becomes disabled while being the active tab', () => {
552
+ const mockOnSelect = jest.fn();
553
+
554
+ const { rerender } = render(
555
+ <Component
556
+ initialTabName="gamma"
557
+ tabs={ TABS }
558
+ children={ () => undefined }
559
+ onSelect={ mockOnSelect }
560
+ />
561
+ );
562
+
563
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
564
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
565
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
566
+
567
+ rerender(
568
+ <Component
569
+ initialTabName="gamma"
570
+ tabs={ [
571
+ TABS[ 0 ],
572
+ TABS[ 1 ],
573
+ { ...TABS[ 2 ], disabled: true },
574
+ ] } // Disable gamma
575
+ children={ () => undefined }
576
+ onSelect={ mockOnSelect }
577
+ />
578
+ );
579
+
580
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
581
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
582
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
583
+
584
+ rerender(
585
+ <Component
586
+ initialTabName="gamma"
587
+ tabs={ TABS }
588
+ children={ () => undefined }
589
+ onSelect={ mockOnSelect }
590
+ />
591
+ );
592
+
593
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
594
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
331
595
  } );
332
596
  } );
333
597
 
334
- describe( 'tab activation', () => {
335
- it( 'defaults to automatic tab activation', async () => {
336
- const user = setupUser();
598
+ describe( 'Tab Activation', () => {
599
+ it( 'defaults to automatic tab activation (pointer clicks)', async () => {
600
+ const user = userEvent.setup();
601
+ const panelRenderFunction = jest.fn();
337
602
  const mockOnSelect = jest.fn();
338
603
 
339
604
  render(
340
- <TabPanel
605
+ <Component
606
+ tabs={ TABS }
607
+ children={ panelRenderFunction }
608
+ onSelect={ mockOnSelect }
609
+ />
610
+ );
611
+
612
+ // Alpha is the initially selected tab
613
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
614
+ expect(
615
+ screen.getByRole( 'tabpanel', { name: 'Alpha' } )
616
+ ).toBeInTheDocument();
617
+ expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 0 ] );
618
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
619
+
620
+ // Click on Beta, make sure beta is the selected tab
621
+ await user.click( screen.getByRole( 'tab', { name: 'Beta' } ) );
622
+
623
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
624
+ expect(
625
+ screen.getByRole( 'tabpanel', { name: 'Beta' } )
626
+ ).toBeInTheDocument();
627
+ expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 1 ] );
628
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
629
+
630
+ // Click on Alpha, make sure beta is the selected tab
631
+ await user.click( screen.getByRole( 'tab', { name: 'Alpha' } ) );
632
+
633
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
634
+ expect(
635
+ screen.getByRole( 'tabpanel', { name: 'Alpha' } )
636
+ ).toBeInTheDocument();
637
+ expect( panelRenderFunction ).toHaveBeenLastCalledWith( TABS[ 0 ] );
638
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
639
+ } );
640
+
641
+ it( 'defaults to automatic tab activation (arrow keys)', async () => {
642
+ const user = userEvent.setup();
643
+ const mockOnSelect = jest.fn();
644
+
645
+ render(
646
+ <Component
341
647
  tabs={ TABS }
342
648
  children={ () => undefined }
343
649
  onSelect={ mockOnSelect }
@@ -347,42 +653,219 @@ describe( 'TabPanel', () => {
347
653
  // onSelect gets called on the initial render.
348
654
  expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
349
655
 
350
- // Click on Alpha, make sure Alpha is selected
351
- await user.click( screen.getByRole( 'tab', { name: 'Alpha' } ) );
656
+ // Tab to focus the tablist. Make sure alpha is focused.
657
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
658
+ await expect( getSelectedTab() ).not.toHaveFocus();
659
+ await user.keyboard( '[Tab]' );
660
+ await expect( getSelectedTab() ).toHaveFocus();
661
+
662
+ // Navigate forward with arrow keys and make sure the Beta tab is
663
+ // selected automatically.
664
+ await user.keyboard( '[ArrowRight]' );
665
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
666
+ await expect( getSelectedTab() ).toHaveFocus();
352
667
  expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
668
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
669
+
670
+ // Navigate backwards with arrow keys. Make sure alpha is
671
+ // selected automatically.
672
+ await user.keyboard( '[ArrowLeft]' );
673
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
674
+ await expect( getSelectedTab() ).toHaveFocus();
675
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
353
676
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
677
+ } );
678
+
679
+ it( 'wraps around the last/first tab when using arrow keys', async () => {
680
+ const user = userEvent.setup();
681
+ const mockOnSelect = jest.fn();
682
+
683
+ render(
684
+ <Component
685
+ tabs={ TABS }
686
+ children={ () => undefined }
687
+ onSelect={ mockOnSelect }
688
+ />
689
+ );
690
+
691
+ // onSelect gets called on the initial render.
692
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
693
+
694
+ // Tab to focus the tablist. Make sure Alpha is focused.
695
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
696
+ await expect( getSelectedTab() ).not.toHaveFocus();
697
+ await user.keyboard( '[Tab]' );
698
+ await expect( getSelectedTab() ).toHaveFocus();
699
+
700
+ // Navigate backwards with arrow keys and make sure that the Gamma tab
701
+ // (the last tab) is selected automatically.
702
+ await user.keyboard( '[ArrowLeft]' );
703
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
704
+ await expect( getSelectedTab() ).toHaveFocus();
705
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
706
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
354
707
 
355
- // Navigate forward with arrow keys,
356
- // make sure Beta is selected automatically.
708
+ // Navigate forward with arrow keys. Make sure alpha (the first tab) is
709
+ // selected automatically.
357
710
  await user.keyboard( '[ArrowRight]' );
711
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
712
+ await expect( getSelectedTab() ).toHaveFocus();
358
713
  expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
714
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
715
+ } );
716
+
717
+ it( 'should not move tab selection when pressing the up/down arrow keys, unless the orientation is changed to `vertical`', async () => {
718
+ const user = userEvent.setup();
719
+ const mockOnSelect = jest.fn();
720
+
721
+ const { rerender } = render(
722
+ <Component
723
+ tabs={ TABS }
724
+ children={ () => undefined }
725
+ onSelect={ mockOnSelect }
726
+ />
727
+ );
728
+
729
+ // onSelect gets called on the initial render.
730
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
731
+
732
+ // Tab to focus the tablist. Make sure alpha is focused.
733
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
734
+ await expect( getSelectedTab() ).not.toHaveFocus();
735
+ await user.keyboard( '[Tab]' );
736
+ await expect( getSelectedTab() ).toHaveFocus();
737
+
738
+ // Press the arrow up key, nothing happens.
739
+ await user.keyboard( '[ArrowUp]' );
740
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
741
+ await expect( getSelectedTab() ).toHaveFocus();
742
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
743
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
744
+
745
+ // Press the arrow down key, nothing happens
746
+ await user.keyboard( '[ArrowDown]' );
747
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
748
+ await expect( getSelectedTab() ).toHaveFocus();
749
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
750
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
751
+
752
+ // Change orientation to `vertical`. When the orientation is vertical,
753
+ // left/right arrow keys are replaced by up/down arrow keys.
754
+ rerender(
755
+ <Component
756
+ tabs={ TABS }
757
+ children={ () => undefined }
758
+ onSelect={ mockOnSelect }
759
+ orientation="vertical"
760
+ />
761
+ );
762
+
763
+ expect( screen.getByRole( 'tablist' ) ).toHaveAttribute(
764
+ 'aria-orientation',
765
+ 'vertical'
766
+ );
767
+
768
+ // Make sure alpha is still focused.
769
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
770
+ await expect( getSelectedTab() ).toHaveFocus();
771
+
772
+ // Navigate forward with arrow keys and make sure the Beta tab is
773
+ // selected automatically.
774
+ await user.keyboard( '[ArrowDown]' );
775
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
776
+ await expect( getSelectedTab() ).toHaveFocus();
777
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
359
778
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
360
779
 
361
- // Navigate forward with arrow keys,
362
- // make sure Gamma (last tab) is selected automatically.
363
- await user.keyboard( '[ArrowRight]' );
780
+ // Navigate backwards with arrow keys. Make sure alpha is
781
+ // selected automatically.
782
+ await user.keyboard( '[ArrowUp]' );
783
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
784
+ await expect( getSelectedTab() ).toHaveFocus();
785
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
786
+ expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
787
+
788
+ // Navigate backwards with arrow keys. Make sure alpha is
789
+ // selected automatically.
790
+ await user.keyboard( '[ArrowUp]' );
791
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
792
+ await expect( getSelectedTab() ).toHaveFocus();
364
793
  expect( mockOnSelect ).toHaveBeenCalledTimes( 4 );
365
794
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
366
795
 
367
- // Navigate forward with arrow keys,
368
- // make sure Alpha (first tab) is selected automatically.
369
- await user.keyboard( '[ArrowRight]' );
796
+ // Navigate backwards with arrow keys. Make sure alpha is
797
+ // selected automatically.
798
+ await user.keyboard( '[ArrowDown]' );
799
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
800
+ await expect( getSelectedTab() ).toHaveFocus();
370
801
  expect( mockOnSelect ).toHaveBeenCalledTimes( 5 );
371
802
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
803
+ } );
372
804
 
373
- // Navigate backwards with arrow keys,
374
- // make sure Gamma (last tab) is selected automatically
375
- await user.keyboard( '[ArrowLeft]' );
376
- expect( mockOnSelect ).toHaveBeenCalledTimes( 6 );
805
+ it( 'should move focus on a tab even if disabled with arrow key, but not with pointer clicks', async () => {
806
+ const user = userEvent.setup();
807
+ const mockOnSelect = jest.fn();
808
+
809
+ render(
810
+ <Component
811
+ tabs={ [
812
+ ...TABS,
813
+ {
814
+ name: 'delta',
815
+ title: 'Delta',
816
+ className: 'delta-class',
817
+ disabled: true,
818
+ },
819
+ ] }
820
+ children={ () => undefined }
821
+ onSelect={ mockOnSelect }
822
+ />
823
+ );
824
+
825
+ // onSelect gets called on the initial render.
826
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
827
+
828
+ // Tab to focus the tablist. Make sure Alpha is focused.
829
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
830
+ await expect( getSelectedTab() ).not.toHaveFocus();
831
+ await user.keyboard( '[Tab]' );
832
+ await expect( getSelectedTab() ).toHaveFocus();
833
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
834
+
835
+ // Press the right arrow key three times. Since the delta tab is disabled:
836
+ // - it won't be selected. The gamma tab will be selected instead, since
837
+ // it was the tab that was last selected before delta. Therefore, the
838
+ // `mockOnSelect` function gets called only twice (and not three times)
839
+ // - it will receive focus, when using arrow keys
840
+ await user.keyboard( '[ArrowRight][ArrowRight][ArrowRight]' );
841
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
842
+ await expect(
843
+ screen.getByRole( 'tab', { name: 'Delta' } )
844
+ ).toHaveFocus();
845
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
377
846
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
847
+
848
+ // Navigate backwards with arrow keys. The gamma tab receives focus.
849
+ await user.keyboard( '[ArrowLeft]' );
850
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
851
+ await expect( getSelectedTab() ).toHaveFocus();
852
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 4 );
853
+
854
+ // Click on on the disabled tab. Compared to using arrow keys to move the
855
+ // focus, disabled tabs ignore pointer clicks — and therefore, they don't
856
+ // receive focus, nor they cause the `mockOnSelect` function to fire.
857
+ await user.click( screen.getByRole( 'tab', { name: 'Delta' } ) );
858
+ expect( getSelectedTab() ).toHaveTextContent( 'Gamma' );
859
+ await expect( getSelectedTab() ).toHaveFocus();
860
+ expect( mockOnSelect ).toHaveBeenCalledTimes( 4 );
378
861
  } );
379
862
 
380
863
  it( 'switches to manual tab activation when the `selectOnMove` prop is set to `false`', async () => {
381
- const user = setupUser();
864
+ const user = userEvent.setup();
382
865
  const mockOnSelect = jest.fn();
383
866
 
384
867
  render(
385
- <TabPanel
868
+ <Component
386
869
  tabs={ TABS }
387
870
  children={ () => undefined }
388
871
  onSelect={ mockOnSelect }
@@ -393,35 +876,84 @@ describe( 'TabPanel', () => {
393
876
  // onSelect gets called on the initial render.
394
877
  expect( mockOnSelect ).toHaveBeenCalledTimes( 1 );
395
878
 
396
- // Click on Alpha, make sure Alpha is selected
879
+ // Click on Alpha and make sure it is selected.
397
880
  await user.click( screen.getByRole( 'tab', { name: 'Alpha' } ) );
398
881
  expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
399
882
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'alpha' );
400
883
 
401
- // Navigate forward with arrow keys.
402
- // Make sure Beta is focused, but that the tab selection happens only when
403
- // pressing the spacebar or the enter key.
884
+ // Navigate forward with arrow keys. Make sure Beta is focused, but
885
+ // that the tab selection happens only when pressing the spacebar
886
+ // or enter key.
404
887
  await user.keyboard( '[ArrowRight]' );
405
888
  expect( mockOnSelect ).toHaveBeenCalledTimes( 2 );
406
889
  expect( screen.getByRole( 'tab', { name: 'Beta' } ) ).toHaveFocus();
890
+
407
891
  await user.keyboard( '[Enter]' );
408
892
  expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
409
893
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'beta' );
410
894
 
411
- // Navigate forward with arrow keys.
412
- // Make sure Gamma (last tab) is focused, but that the tab selection
413
- // happens only when pressing the spacebar or the enter key.
895
+ // Navigate forward with arrow keys. Make sure Gamma (last tab) is
896
+ // focused, but that tab selection happens only when pressing the
897
+ // spacebar or enter key.
414
898
  await user.keyboard( '[ArrowRight]' );
415
899
  expect( mockOnSelect ).toHaveBeenCalledTimes( 3 );
416
900
  expect(
417
901
  screen.getByRole( 'tab', { name: 'Gamma' } )
418
902
  ).toHaveFocus();
903
+
419
904
  await user.keyboard( '[Space]' );
420
905
  expect( mockOnSelect ).toHaveBeenCalledTimes( 4 );
421
906
  expect( mockOnSelect ).toHaveBeenLastCalledWith( 'gamma' );
907
+ } );
908
+ } );
909
+
910
+ describe( 'Tab Attributes', () => {
911
+ it( "should apply the tab's `className` to the tab button", () => {
912
+ render( <Component tabs={ TABS } children={ () => undefined } /> );
422
913
 
423
- // No need to test the "wrap-around" behavior, as it's being tested in the
424
- // "automatic tab activation" test above.
914
+ expect( screen.getByRole( 'tab', { name: 'Alpha' } ) ).toHaveClass(
915
+ 'alpha-class'
916
+ );
917
+ expect( screen.getByRole( 'tab', { name: 'Beta' } ) ).toHaveClass(
918
+ 'beta-class'
919
+ );
920
+ expect( screen.getByRole( 'tab', { name: 'Gamma' } ) ).toHaveClass(
921
+ 'gamma-class'
922
+ );
923
+ } );
924
+
925
+ it( 'should apply the `activeClass` to the selected tab', async () => {
926
+ const user = userEvent.setup();
927
+ const activeClass = 'my-active-tab';
928
+
929
+ render(
930
+ <Component
931
+ activeClass={ activeClass }
932
+ tabs={ TABS }
933
+ children={ () => undefined }
934
+ />
935
+ );
936
+
937
+ // Make sure that only the selected tab has the active class
938
+ expect( getSelectedTab() ).toHaveTextContent( 'Alpha' );
939
+ expect( getSelectedTab() ).toHaveClass( activeClass );
940
+ screen
941
+ .getAllByRole( 'tab', { selected: false } )
942
+ .forEach( ( unselectedTab ) => {
943
+ expect( unselectedTab ).not.toHaveClass( activeClass );
944
+ } );
945
+
946
+ // Click the 'Beta' tab
947
+ await user.click( screen.getByRole( 'tab', { name: 'Beta' } ) );
948
+
949
+ // Make sure that only the selected tab has the active class
950
+ expect( getSelectedTab() ).toHaveTextContent( 'Beta' );
951
+ expect( getSelectedTab() ).toHaveClass( activeClass );
952
+ screen
953
+ .getAllByRole( 'tab', { selected: false } )
954
+ .forEach( ( unselectedTab ) => {
955
+ expect( unselectedTab ).not.toHaveClass( activeClass );
956
+ } );
425
957
  } );
426
958
  } );
427
959
  } );