@wordpress/components 23.2.0 → 23.3.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 (377) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/CONTRIBUTING.md +1 -1
  3. package/build/alignment-matrix-control/utils.js +2 -2
  4. package/build/alignment-matrix-control/utils.js.map +1 -1
  5. package/build/autocomplete/autocompleter-ui.js +1 -3
  6. package/build/autocomplete/autocompleter-ui.js.map +1 -1
  7. package/build/border-box-control/border-box-control-linked-button/component.js.map +1 -1
  8. package/build/border-box-control/border-box-control-linked-button/hook.js.map +1 -1
  9. package/build/border-control/border-control-dropdown/component.js +8 -4
  10. package/build/border-control/border-control-dropdown/component.js.map +1 -1
  11. package/build/button/deprecated.js +8 -6
  12. package/build/button/deprecated.js.map +1 -1
  13. package/build/button/index.js +52 -23
  14. package/build/button/index.js.map +1 -1
  15. package/build/button/types.js +6 -0
  16. package/build/button/types.js.map +1 -0
  17. package/build/color-list-picker/index.js.map +1 -1
  18. package/build/color-list-picker/types.js +6 -0
  19. package/build/color-list-picker/types.js.map +1 -0
  20. package/build/color-palette/index.js +9 -61
  21. package/build/color-palette/index.js.map +1 -1
  22. package/build/color-palette/index.native.js +24 -9
  23. package/build/color-palette/index.native.js.map +1 -1
  24. package/build/color-palette/utils.js +103 -0
  25. package/build/color-palette/utils.js.map +1 -0
  26. package/build/custom-gradient-picker/gradient-bar/utils.js +1 -1
  27. package/build/custom-gradient-picker/gradient-bar/utils.js.map +1 -1
  28. package/build/date-time/date/index.js.map +1 -1
  29. package/build/dropdown/index.js +20 -8
  30. package/build/dropdown/index.js.map +1 -1
  31. package/build/form-token-field/token.js +1 -1
  32. package/build/form-token-field/token.js.map +1 -1
  33. package/build/gradient-picker/index.js +9 -1
  34. package/build/gradient-picker/index.js.map +1 -1
  35. package/build/h-stack/component.js +0 -1
  36. package/build/h-stack/component.js.map +1 -1
  37. package/build/input-control/input-field.js +4 -2
  38. package/build/input-control/input-field.js.map +1 -1
  39. package/build/keyboard-shortcuts/index.js +44 -16
  40. package/build/keyboard-shortcuts/index.js.map +1 -1
  41. package/build/keyboard-shortcuts/types.js +6 -0
  42. package/build/keyboard-shortcuts/types.js.map +1 -0
  43. package/build/modal/index.js +1 -1
  44. package/build/modal/index.js.map +1 -1
  45. package/build/notice/index.js +16 -18
  46. package/build/notice/index.js.map +1 -1
  47. package/build/notice/list.js +23 -8
  48. package/build/notice/list.js.map +1 -1
  49. package/build/notice/types.js +6 -0
  50. package/build/notice/types.js.map +1 -0
  51. package/build/number-control/index.js +1 -1
  52. package/build/number-control/index.js.map +1 -1
  53. package/build/query-controls/author-select.js +7 -3
  54. package/build/query-controls/author-select.js.map +1 -1
  55. package/build/query-controls/category-select.js +7 -3
  56. package/build/query-controls/category-select.js.map +1 -1
  57. package/build/query-controls/index.js +68 -20
  58. package/build/query-controls/index.js.map +1 -1
  59. package/build/query-controls/terms.js +4 -3
  60. package/build/query-controls/terms.js.map +1 -1
  61. package/build/query-controls/types.js +6 -0
  62. package/build/query-controls/types.js.map +1 -0
  63. package/build/slot-fill/bubbles-virtually/fill.js +1 -0
  64. package/build/slot-fill/bubbles-virtually/fill.js.map +1 -1
  65. package/build/slot-fill/slot.js +1 -0
  66. package/build/slot-fill/slot.js.map +1 -1
  67. package/build/slot-fill/use-slot.js +1 -11
  68. package/build/slot-fill/use-slot.js.map +1 -1
  69. package/build/snackbar/index.js.map +1 -1
  70. package/build/snackbar/list.js.map +1 -1
  71. package/build/tab-panel/index.js +36 -8
  72. package/build/tab-panel/index.js.map +1 -1
  73. package/build/tree-grid/index.js +1 -1
  74. package/build/tree-grid/index.js.map +1 -1
  75. package/build/tree-select/index.js +2 -6
  76. package/build/tree-select/index.js.map +1 -1
  77. package/build-module/alignment-matrix-control/utils.js +2 -2
  78. package/build-module/alignment-matrix-control/utils.js.map +1 -1
  79. package/build-module/autocomplete/autocompleter-ui.js +1 -2
  80. package/build-module/autocomplete/autocompleter-ui.js.map +1 -1
  81. package/build-module/border-box-control/border-box-control-linked-button/component.js.map +1 -1
  82. package/build-module/border-box-control/border-box-control-linked-button/hook.js.map +1 -1
  83. package/build-module/border-control/border-control-dropdown/component.js +7 -4
  84. package/build-module/border-control/border-control-dropdown/component.js.map +1 -1
  85. package/build-module/button/deprecated.js +8 -5
  86. package/build-module/button/deprecated.js.map +1 -1
  87. package/build-module/button/index.js +51 -22
  88. package/build-module/button/index.js.map +1 -1
  89. package/build-module/button/types.js +2 -0
  90. package/build-module/button/types.js.map +1 -0
  91. package/build-module/color-list-picker/index.js.map +1 -1
  92. package/build-module/color-list-picker/types.js +2 -0
  93. package/build-module/color-list-picker/types.js.map +1 -0
  94. package/build-module/color-palette/index.js +7 -54
  95. package/build-module/color-palette/index.js.map +1 -1
  96. package/build-module/color-palette/index.native.js +24 -8
  97. package/build-module/color-palette/index.native.js.map +1 -1
  98. package/build-module/color-palette/utils.js +79 -0
  99. package/build-module/color-palette/utils.js.map +1 -0
  100. package/build-module/custom-gradient-picker/gradient-bar/utils.js +1 -1
  101. package/build-module/custom-gradient-picker/gradient-bar/utils.js.map +1 -1
  102. package/build-module/date-time/date/index.js +1 -1
  103. package/build-module/date-time/date/index.js.map +1 -1
  104. package/build-module/dropdown/index.js +19 -8
  105. package/build-module/dropdown/index.js.map +1 -1
  106. package/build-module/form-token-field/token.js +1 -1
  107. package/build-module/form-token-field/token.js.map +1 -1
  108. package/build-module/gradient-picker/index.js +9 -2
  109. package/build-module/gradient-picker/index.js.map +1 -1
  110. package/build-module/h-stack/component.js +0 -1
  111. package/build-module/h-stack/component.js.map +1 -1
  112. package/build-module/input-control/input-field.js +4 -2
  113. package/build-module/input-control/input-field.js.map +1 -1
  114. package/build-module/keyboard-shortcuts/index.js +48 -16
  115. package/build-module/keyboard-shortcuts/index.js.map +1 -1
  116. package/build-module/keyboard-shortcuts/types.js +2 -0
  117. package/build-module/keyboard-shortcuts/types.js.map +1 -0
  118. package/build-module/modal/index.js +1 -1
  119. package/build-module/modal/index.js.map +1 -1
  120. package/build-module/notice/index.js +14 -15
  121. package/build-module/notice/index.js.map +1 -1
  122. package/build-module/notice/list.js +23 -8
  123. package/build-module/notice/list.js.map +1 -1
  124. package/build-module/notice/types.js +2 -0
  125. package/build-module/notice/types.js.map +1 -0
  126. package/build-module/number-control/index.js +1 -1
  127. package/build-module/number-control/index.js.map +1 -1
  128. package/build-module/query-controls/author-select.js +7 -3
  129. package/build-module/query-controls/author-select.js.map +1 -1
  130. package/build-module/query-controls/category-select.js +8 -4
  131. package/build-module/query-controls/category-select.js.map +1 -1
  132. package/build-module/query-controls/index.js +64 -20
  133. package/build-module/query-controls/index.js.map +1 -1
  134. package/build-module/query-controls/terms.js +8 -4
  135. package/build-module/query-controls/terms.js.map +1 -1
  136. package/build-module/query-controls/types.js +2 -0
  137. package/build-module/query-controls/types.js.map +1 -0
  138. package/build-module/slot-fill/bubbles-virtually/fill.js +1 -0
  139. package/build-module/slot-fill/bubbles-virtually/fill.js.map +1 -1
  140. package/build-module/slot-fill/slot.js +1 -0
  141. package/build-module/slot-fill/slot.js.map +1 -1
  142. package/build-module/slot-fill/use-slot.js +2 -12
  143. package/build-module/slot-fill/use-slot.js.map +1 -1
  144. package/build-module/snackbar/index.js.map +1 -1
  145. package/build-module/snackbar/list.js.map +1 -1
  146. package/build-module/tab-panel/index.js +36 -8
  147. package/build-module/tab-panel/index.js.map +1 -1
  148. package/build-module/tree-grid/index.js +1 -1
  149. package/build-module/tree-grid/index.js.map +1 -1
  150. package/build-module/tree-select/index.js +2 -6
  151. package/build-module/tree-select/index.js.map +1 -1
  152. package/build-style/style-rtl.css +5 -0
  153. package/build-style/style.css +5 -0
  154. package/build-types/border-box-control/border-box-control/hook.d.ts +1 -1
  155. package/build-types/border-box-control/border-box-control-linked-button/component.d.ts +1 -1
  156. package/build-types/border-box-control/border-box-control-linked-button/hook.d.ts +171 -160
  157. package/build-types/border-box-control/border-box-control-linked-button/hook.d.ts.map +1 -1
  158. package/build-types/border-box-control/border-box-control-split-controls/hook.d.ts +1 -1
  159. package/build-types/border-control/border-control/hook.d.ts +1 -1
  160. package/build-types/border-control/border-control-dropdown/component.d.ts.map +1 -1
  161. package/build-types/border-control/border-control-dropdown/hook.d.ts +1 -1
  162. package/build-types/button/deprecated.d.ts +143 -7
  163. package/build-types/button/deprecated.d.ts.map +1 -1
  164. package/build-types/button/index.d.ts +20 -3
  165. package/build-types/button/index.d.ts.map +1 -1
  166. package/build-types/button/stories/index.d.ts +20 -0
  167. package/build-types/button/stories/index.d.ts.map +1 -0
  168. package/build-types/button/test/index.d.ts +2 -0
  169. package/build-types/button/test/index.d.ts.map +1 -0
  170. package/build-types/button/types.d.ts +134 -0
  171. package/build-types/button/types.d.ts.map +1 -0
  172. package/build-types/color-list-picker/index.d.ts +5 -0
  173. package/build-types/color-list-picker/index.d.ts.map +1 -0
  174. package/build-types/color-list-picker/types.d.ts +42 -0
  175. package/build-types/color-list-picker/types.d.ts.map +1 -0
  176. package/build-types/color-palette/index.d.ts +2 -4
  177. package/build-types/color-palette/index.d.ts.map +1 -1
  178. package/build-types/color-palette/stories/index.d.ts +2 -2
  179. package/build-types/color-palette/styles.d.ts +1 -1
  180. package/build-types/color-palette/types.d.ts +1 -1
  181. package/build-types/color-palette/types.d.ts.map +1 -1
  182. package/build-types/color-palette/utils.d.ts +14 -0
  183. package/build-types/color-palette/utils.d.ts.map +1 -0
  184. package/build-types/color-picker/styles.d.ts +2 -2
  185. package/build-types/date-time/date/index.d.ts.map +1 -1
  186. package/build-types/date-time/date/styles.d.ts +3 -3
  187. package/build-types/dropdown/index.d.ts +4 -4
  188. package/build-types/dropdown/index.d.ts.map +1 -1
  189. package/build-types/dropdown/stories/index.d.ts.map +1 -1
  190. package/build-types/dropdown/types.d.ts +9 -10
  191. package/build-types/dropdown/types.d.ts.map +1 -1
  192. package/build-types/font-size-picker/styles.d.ts +2 -2
  193. package/build-types/h-stack/component.d.ts +0 -1
  194. package/build-types/h-stack/component.d.ts.map +1 -1
  195. package/build-types/input-control/input-field.d.ts.map +1 -1
  196. package/build-types/keyboard-shortcuts/index.d.ts +38 -0
  197. package/build-types/keyboard-shortcuts/index.d.ts.map +1 -0
  198. package/build-types/keyboard-shortcuts/stories/index.d.ts +12 -0
  199. package/build-types/keyboard-shortcuts/stories/index.d.ts.map +1 -0
  200. package/build-types/keyboard-shortcuts/test/index.d.ts +2 -0
  201. package/build-types/keyboard-shortcuts/test/index.d.ts.map +1 -0
  202. package/build-types/keyboard-shortcuts/types.d.ts +48 -0
  203. package/build-types/keyboard-shortcuts/types.d.ts.map +1 -0
  204. package/build-types/modal/index.d.ts.map +1 -1
  205. package/build-types/navigator/navigator-back-button/component.d.ts +1 -1
  206. package/build-types/navigator/navigator-back-button/hook.d.ts +2 -2
  207. package/build-types/navigator/navigator-button/component.d.ts +1 -1
  208. package/build-types/navigator/navigator-button/hook.d.ts +2 -2
  209. package/build-types/notice/index.d.ts +16 -0
  210. package/build-types/notice/index.d.ts.map +1 -0
  211. package/build-types/notice/list.d.ts +32 -0
  212. package/build-types/notice/list.d.ts.map +1 -0
  213. package/build-types/notice/stories/index.d.ts +17 -0
  214. package/build-types/notice/stories/index.d.ts.map +1 -0
  215. package/build-types/notice/test/index.d.ts +2 -0
  216. package/build-types/notice/test/index.d.ts.map +1 -0
  217. package/build-types/notice/test/list.d.ts +2 -0
  218. package/build-types/notice/test/list.d.ts.map +1 -0
  219. package/build-types/notice/types.d.ts +128 -0
  220. package/build-types/notice/types.d.ts.map +1 -0
  221. package/build-types/number-control/styles/number-control-styles.d.ts +2 -2
  222. package/build-types/number-control/styles/number-control-styles.d.ts.map +1 -1
  223. package/build-types/placeholder/stories/index.d.ts.map +1 -1
  224. package/build-types/query-controls/author-select.d.ts +4 -0
  225. package/build-types/query-controls/author-select.d.ts.map +1 -0
  226. package/build-types/query-controls/category-select.d.ts +4 -0
  227. package/build-types/query-controls/category-select.d.ts.map +1 -0
  228. package/build-types/query-controls/index.d.ts +30 -0
  229. package/build-types/query-controls/index.d.ts.map +1 -0
  230. package/build-types/query-controls/stories/index.d.ts +13 -0
  231. package/build-types/query-controls/stories/index.d.ts.map +1 -0
  232. package/build-types/query-controls/terms.d.ts +13 -0
  233. package/build-types/query-controls/terms.d.ts.map +1 -0
  234. package/build-types/query-controls/test/terms.d.ts +2 -0
  235. package/build-types/query-controls/test/terms.d.ts.map +1 -0
  236. package/build-types/query-controls/types.d.ts +131 -0
  237. package/build-types/query-controls/types.d.ts.map +1 -0
  238. package/build-types/range-control/index.d.ts +1 -1
  239. package/build-types/slot-fill/bubbles-virtually/fill.d.ts.map +1 -1
  240. package/build-types/slot-fill/use-slot.d.ts.map +1 -1
  241. package/build-types/snackbar/index.d.ts +9 -2
  242. package/build-types/snackbar/index.d.ts.map +1 -1
  243. package/build-types/snackbar/list.d.ts.map +1 -1
  244. package/build-types/snackbar/types.d.ts +15 -88
  245. package/build-types/snackbar/types.d.ts.map +1 -1
  246. package/build-types/tab-panel/index.d.ts.map +1 -1
  247. package/build-types/tab-panel/types.d.ts +1 -1
  248. package/build-types/tab-panel/types.d.ts.map +1 -1
  249. package/build-types/toggle-group-control/stories/index.d.ts.map +1 -1
  250. package/build-types/tree-select/index.d.ts.map +1 -1
  251. package/build-types/ui/form-group/form-group.d.ts +2 -2
  252. package/package.json +18 -17
  253. package/src/alignment-matrix-control/utils.tsx +2 -2
  254. package/src/autocomplete/autocompleter-ui.js +1 -2
  255. package/src/autocomplete/test/index.js +1 -5
  256. package/src/border-box-control/border-box-control-linked-button/component.tsx +1 -1
  257. package/src/border-box-control/border-box-control-linked-button/hook.ts +1 -1
  258. package/src/border-control/border-control-dropdown/component.tsx +9 -8
  259. package/src/box-control/test/index.js +11 -35
  260. package/src/button/README.md +49 -55
  261. package/src/button/{deprecated.js → deprecated.tsx} +19 -4
  262. package/src/button/{index.js → index.tsx} +95 -34
  263. package/src/button/stories/index.tsx +106 -0
  264. package/src/button/style.scss +3 -2
  265. package/src/button/test/{index.js → index.tsx} +30 -7
  266. package/src/button/types.ts +138 -0
  267. package/src/checkbox-control/test/index.tsx +1 -5
  268. package/src/color-list-picker/{index.js → index.tsx} +3 -2
  269. package/src/color-list-picker/types.ts +46 -0
  270. package/src/color-palette/README.md +1 -1
  271. package/src/color-palette/index.native.js +11 -4
  272. package/src/color-palette/index.tsx +11 -67
  273. package/src/color-palette/test/index.tsx +4 -14
  274. package/src/color-palette/test/utils.ts +1 -1
  275. package/src/color-palette/types.ts +1 -1
  276. package/src/color-palette/utils.ts +98 -0
  277. package/src/color-picker/test/index.js +6 -15
  278. package/src/combobox-control/test/index.js +1 -6
  279. package/src/confirm-dialog/test/index.js +9 -29
  280. package/src/custom-gradient-picker/gradient-bar/utils.js +1 -1
  281. package/src/date-time/date/index.tsx +2 -1
  282. package/src/date-time/date/test/index.tsx +2 -8
  283. package/src/date-time/time/test/index.tsx +9 -29
  284. package/src/dimension-control/test/index.test.js +2 -8
  285. package/src/disabled/test/index.tsx +1 -5
  286. package/src/draggable/test/index.native.js +4 -4
  287. package/src/dropdown/README.md +1 -8
  288. package/src/dropdown/index.tsx +17 -6
  289. package/src/dropdown/stories/index.tsx +3 -3
  290. package/src/dropdown/test/index.tsx +2 -8
  291. package/src/dropdown/types.ts +9 -10
  292. package/src/dropdown-menu/README.md +1 -1
  293. package/src/dropdown-menu/stories/index.js +96 -27
  294. package/src/dropdown-menu/test/index.js +2 -8
  295. package/src/external-link/test/index.tsx +1 -6
  296. package/src/focal-point-picker/test/index.js +3 -11
  297. package/src/font-size-picker/test/index.tsx +14 -44
  298. package/src/form-file-upload/test/index.tsx +2 -17
  299. package/src/form-toggle/test/index.tsx +1 -5
  300. package/src/form-token-field/test/index.tsx +80 -163
  301. package/src/form-token-field/token.tsx +1 -1
  302. package/src/gradient-picker/index.js +15 -4
  303. package/src/guide/test/index.js +5 -17
  304. package/src/h-stack/component.tsx +0 -1
  305. package/src/higher-order/with-filters/test/index.js +24 -24
  306. package/src/higher-order/with-focus-outside/test/index.js +11 -25
  307. package/src/higher-order/with-focus-return/test/index.js +1 -5
  308. package/src/input-control/input-field.tsx +3 -1
  309. package/src/input-control/test/index.js +1 -6
  310. package/src/isolated-event-container/test/index.js +2 -8
  311. package/src/keyboard-shortcuts/README.md +1 -1
  312. package/src/keyboard-shortcuts/index.tsx +93 -0
  313. package/src/keyboard-shortcuts/stories/index.tsx +60 -0
  314. package/src/keyboard-shortcuts/test/{index.js → index.tsx} +16 -6
  315. package/src/keyboard-shortcuts/types.ts +51 -0
  316. package/src/modal/index.tsx +1 -2
  317. package/src/navigable-container/test/navigable-menu.js +5 -17
  318. package/src/navigable-container/test/tababble-container.js +3 -11
  319. package/src/navigation/test/index.js +3 -11
  320. package/src/navigator/test/index.tsx +6 -20
  321. package/src/notice/README.md +89 -42
  322. package/src/notice/{index.js → index.tsx} +28 -20
  323. package/src/notice/list.tsx +72 -0
  324. package/src/notice/stories/index.tsx +119 -0
  325. package/src/notice/test/__snapshots__/{index.js.snap → index.tsx.snap} +0 -0
  326. package/src/notice/test/{index.js → index.tsx} +7 -4
  327. package/src/notice/test/{list.js → list.tsx} +0 -0
  328. package/src/notice/types.ts +136 -0
  329. package/src/number-control/index.tsx +1 -1
  330. package/src/number-control/test/index.tsx +28 -86
  331. package/src/panel/test/body.js +2 -8
  332. package/src/placeholder/stories/index.tsx +1 -0
  333. package/src/query-controls/README.md +56 -56
  334. package/src/query-controls/author-select.tsx +37 -0
  335. package/src/query-controls/category-select.tsx +46 -0
  336. package/src/query-controls/index.tsx +192 -0
  337. package/src/query-controls/stories/index.tsx +205 -0
  338. package/src/query-controls/terms.ts +57 -0
  339. package/src/query-controls/test/{terms.js → terms.ts} +36 -20
  340. package/src/query-controls/types.ts +150 -0
  341. package/src/select-control/test/select-control.tsx +1 -6
  342. package/src/slot-fill/bubbles-virtually/fill.js +1 -0
  343. package/src/slot-fill/slot.js +1 -1
  344. package/src/slot-fill/use-slot.js +6 -16
  345. package/src/snackbar/index.tsx +6 -5
  346. package/src/snackbar/list.tsx +4 -2
  347. package/src/snackbar/types.ts +18 -92
  348. package/src/tab-panel/index.tsx +38 -16
  349. package/src/tab-panel/style.scss +8 -0
  350. package/src/tab-panel/test/index.tsx +35 -7
  351. package/src/tab-panel/types.ts +1 -1
  352. package/src/theme/test/index.tsx +4 -4
  353. package/src/toggle-group-control/stories/index.tsx +1 -0
  354. package/src/toggle-group-control/test/index.tsx +7 -23
  355. package/src/toolbar/stories/index.js +75 -72
  356. package/src/tools-panel/stories/index.js +3 -0
  357. package/src/tools-panel/test/index.js +1 -1
  358. package/src/tree-grid/index.js +1 -1
  359. package/src/tree-select/index.tsx +3 -6
  360. package/src/ui/context/test/context-connect.tsx +2 -0
  361. package/src/ui/context/test/wordpress-component.tsx +2 -0
  362. package/src/unit-control/test/index.tsx +21 -74
  363. package/src/utils/hooks/test/use-latest-ref.js +15 -18
  364. package/tsconfig.json +1 -4
  365. package/tsconfig.tsbuildinfo +1 -1
  366. package/build-types/radio-context/index.d.ts +0 -6
  367. package/build-types/radio-context/index.d.ts.map +0 -1
  368. package/src/button/stories/index.js +0 -179
  369. package/src/keyboard-shortcuts/index.js +0 -56
  370. package/src/notice/list.js +0 -48
  371. package/src/notice/stories/index.js +0 -46
  372. package/src/query-controls/author-select.js +0 -23
  373. package/src/query-controls/category-select.js +0 -31
  374. package/src/query-controls/index.js +0 -122
  375. package/src/query-controls/terms.js +0 -40
  376. package/src/toolbar/stories/toolbar-button.js +0 -32
  377. package/src/toolbar/stories/toolbar-group.js +0 -33
@@ -0,0 +1,57 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { groupBy } from 'lodash';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type {
10
+ Author,
11
+ Category,
12
+ TermWithParentAndChildren,
13
+ TermsByParent,
14
+ } from './types';
15
+
16
+ /**
17
+ * Returns terms in a tree form.
18
+ *
19
+ * @param flatTerms Array of terms in flat format.
20
+ *
21
+ * @return Terms in tree format.
22
+ */
23
+ export function buildTermsTree( flatTerms: readonly ( Author | Category )[] ) {
24
+ const flatTermsWithParentAndChildren: TermWithParentAndChildren[] =
25
+ flatTerms.map( ( term ) => {
26
+ return {
27
+ children: [],
28
+ parent: null,
29
+ ...term,
30
+ id: String( term.id ),
31
+ };
32
+ } );
33
+
34
+ const termsByParent: TermsByParent = groupBy(
35
+ flatTermsWithParentAndChildren,
36
+ 'parent'
37
+ );
38
+ if ( termsByParent.null && termsByParent.null.length ) {
39
+ return flatTermsWithParentAndChildren;
40
+ }
41
+ const fillWithChildren = (
42
+ terms: TermWithParentAndChildren[]
43
+ ): TermWithParentAndChildren[] => {
44
+ return terms.map( ( term ) => {
45
+ const children = termsByParent[ term.id ];
46
+ return {
47
+ ...term,
48
+ children:
49
+ children && children.length
50
+ ? fillWithChildren( children )
51
+ : [],
52
+ };
53
+ } );
54
+ };
55
+
56
+ return fillWithChildren( termsByParent[ '0' ] || [] );
57
+ }
@@ -6,38 +6,53 @@ import { buildTermsTree } from '../terms';
6
6
  describe( 'buildTermsTree()', () => {
7
7
  it( 'Should return same array as input with null parent and empty children added if parent is never specified.', () => {
8
8
  const input = Object.freeze( [
9
- { id: 2232, dummy: true },
10
- { id: 2245, dummy: true },
9
+ { id: 2232, name: 'foo', dummy: true },
10
+ { id: 2245, name: 'baz', dummy: true },
11
11
  ] );
12
12
  const output = Object.freeze( [
13
- { id: 2232, parent: null, children: [], dummy: true },
14
- { id: 2245, parent: null, children: [], dummy: true },
13
+ {
14
+ id: '2232',
15
+ name: 'foo',
16
+ parent: null,
17
+ children: [],
18
+ dummy: true,
19
+ },
20
+ {
21
+ id: '2245',
22
+ name: 'baz',
23
+ parent: null,
24
+ children: [],
25
+ dummy: true,
26
+ },
15
27
  ] );
16
28
  const termsTreem = buildTermsTree( input );
17
29
  expect( termsTreem ).toEqual( output );
18
30
  } );
19
31
  it( 'Should return same array as input with empty children added if all the elements are top level', () => {
20
32
  const input = Object.freeze( [
21
- { id: 2232, parent: 0, dummy: true },
22
- { id: 2245, parent: 0, dummy: false },
33
+ { id: 2232, name: 'foo', parent: 0, dummy: true },
34
+ { id: 2245, name: 'baz', parent: 0, dummy: false },
23
35
  ] );
24
36
  const output = [
25
- { id: 2232, parent: 0, children: [], dummy: true },
26
- { id: 2245, parent: 0, children: [], dummy: false },
37
+ { id: '2232', name: 'foo', parent: 0, children: [], dummy: true },
38
+ { id: '2245', name: 'baz', parent: 0, children: [], dummy: false },
27
39
  ];
28
40
  const termsTreem = buildTermsTree( input );
29
41
  expect( termsTreem ).toEqual( output );
30
42
  } );
31
43
  it( 'Should return element with its child if a child exists', () => {
32
44
  const input = Object.freeze( [
33
- { id: 2232, parent: 0 },
34
- { id: 2245, parent: 2232 },
45
+ { id: 2232, name: 'foo', parent: 0 },
46
+ { id: 2245, name: 'baz', parent: 2232 },
35
47
  ] );
36
48
  const output = [
37
49
  {
38
- id: 2232,
50
+ id: '2232',
51
+ name: 'foo',
39
52
  parent: 0,
40
- children: [ { id: 2245, parent: 2232, children: [] } ],
53
+ children: [
54
+ { id: '2245', name: 'baz', parent: 2232, children: [] },
55
+ ],
41
56
  },
42
57
  ];
43
58
  const termsTreem = buildTermsTree( input );
@@ -45,21 +60,22 @@ describe( 'buildTermsTree()', () => {
45
60
  } );
46
61
  it( 'Should return elements with multiple children and elements with no children', () => {
47
62
  const input = Object.freeze( [
48
- { id: 2232, parent: 0 },
49
- { id: 2245, parent: 2232 },
50
- { id: 2249, parent: 0 },
51
- { id: 2246, parent: 2232 },
63
+ { id: 2232, name: 'a', parent: 0 },
64
+ { id: 2245, name: 'b', parent: 2232 },
65
+ { id: 2249, name: 'c', parent: 0 },
66
+ { id: 2246, name: 'd', parent: 2232 },
52
67
  ] );
53
68
  const output = [
54
69
  {
55
- id: 2232,
70
+ id: '2232',
71
+ name: 'a',
56
72
  parent: 0,
57
73
  children: [
58
- { id: 2245, parent: 2232, children: [] },
59
- { id: 2246, parent: 2232, children: [] },
74
+ { id: '2245', name: 'b', parent: 2232, children: [] },
75
+ { id: '2246', name: 'd', parent: 2232, children: [] },
60
76
  ],
61
77
  },
62
- { id: 2249, parent: 0, children: [] },
78
+ { id: '2249', name: 'c', parent: 0, children: [] },
63
79
  ];
64
80
  const termsTreem = buildTermsTree( input );
65
81
  expect( termsTreem ).toEqual( output );
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { FormTokenFieldProps } from '../form-token-field/types';
5
+ import type { TreeSelectProps } from '../tree-select/types';
6
+
7
+ export type Author = {
8
+ id: number;
9
+ name: string;
10
+ };
11
+
12
+ export type Category = {
13
+ id: number;
14
+ name: string;
15
+ parent: number;
16
+ };
17
+
18
+ export type TermWithParentAndChildren = {
19
+ id: string;
20
+ name: string;
21
+ parent: number | null;
22
+ children: TermWithParentAndChildren[];
23
+ };
24
+
25
+ export type TermsByParent = Record< string, TermWithParentAndChildren[] >;
26
+
27
+ export type CategorySelectProps = Pick<
28
+ TreeSelectProps,
29
+ 'label' | 'noOptionLabel'
30
+ > & {
31
+ categoriesList: Category[];
32
+ onChange: ( newCategory: string ) => void;
33
+ selectedCategoryId?: Category[ 'id' ];
34
+ };
35
+
36
+ export type AuthorSelectProps = Pick<
37
+ TreeSelectProps,
38
+ 'label' | 'noOptionLabel'
39
+ > & {
40
+ authorList?: Author[];
41
+ onChange: ( newAuthor: string ) => void;
42
+ selectedAuthorId?: Author[ 'id' ];
43
+ };
44
+
45
+ type Order = 'asc' | 'desc';
46
+ type OrderBy = 'date' | 'title';
47
+
48
+ type BaseQueryControlsProps = {
49
+ /**
50
+ * An array of the authors to select from.
51
+ */
52
+ authorList?: AuthorSelectProps[ 'authorList' ];
53
+ /**
54
+ * The maximum number of items.
55
+ *
56
+ * @default 100
57
+ */
58
+ maxItems?: number;
59
+ /**
60
+ * The minimum number of items.
61
+ *
62
+ * @default 1
63
+ */
64
+ minItems?: number;
65
+ /**
66
+ * The selected number of items to retrieve via the query.
67
+ */
68
+ numberOfItems?: number;
69
+ /**
70
+ * A function that receives the new author value.
71
+ * If not specified, the author controls are not rendered.
72
+ */
73
+ onAuthorChange?: AuthorSelectProps[ 'onChange' ];
74
+ /**
75
+ * A function that receives the new number of items.
76
+ * If not specified, then the number of items
77
+ * range control is not rendered.
78
+ */
79
+ onNumberOfItemsChange?: ( newNumber?: number ) => void;
80
+ /**
81
+ * A function that receives the new order value.
82
+ * If this prop or the `onOrderByChange` prop are not specified,
83
+ * then the order controls are not rendered.
84
+ */
85
+ onOrderChange?: ( newOrder: Order ) => void;
86
+ /**
87
+ * A function that receives the new orderby value.
88
+ * If this prop or the `onOrderChange` prop are not specified,
89
+ * then the order controls are not rendered.
90
+ */
91
+ onOrderByChange?: ( newOrderBy: OrderBy ) => void;
92
+ /**
93
+ * The order in which to retrieve posts.
94
+ */
95
+ order?: Order;
96
+ /**
97
+ * The meta key by which to order posts.
98
+ */
99
+ orderBy?: OrderBy;
100
+ /**
101
+ * The selected author ID.
102
+ */
103
+ selectedAuthorId?: AuthorSelectProps[ 'selectedAuthorId' ];
104
+ };
105
+
106
+ export type QueryControlsWithSingleCategorySelectionProps =
107
+ BaseQueryControlsProps & {
108
+ /**
109
+ * An array of categories. When passed in conjunction with the
110
+ * `onCategoryChange` prop, it causes the component to render UI that allows
111
+ * selecting one category at a time.
112
+ */
113
+ categoriesList?: CategorySelectProps[ 'categoriesList' ];
114
+ /**
115
+ * The selected category for the `categoriesList` prop.
116
+ */
117
+ selectedCategoryId?: CategorySelectProps[ 'selectedCategoryId' ];
118
+ /**
119
+ * A function that receives the new category value. If not specified, the
120
+ * category controls are not rendered.
121
+ * The function's signature changes depending on whether multiple category
122
+ * selection is enabled or not.
123
+ */
124
+ onCategoryChange?: CategorySelectProps[ 'onChange' ];
125
+ };
126
+
127
+ export type QueryControlsWithMultipleCategorySelectionProps =
128
+ BaseQueryControlsProps & {
129
+ /**
130
+ * An object of categories with the category name as the key. When passed in
131
+ * conjunction with the `onCategoryChange` prop, it causes the component to
132
+ * render UI that enables multiple selection.
133
+ */
134
+ categorySuggestions?: Record< Category[ 'name' ], Category >;
135
+ /**
136
+ * The selected categories for the `categorySuggestions` prop.
137
+ */
138
+ selectedCategories?: Category[];
139
+ /**
140
+ * A function that receives the new category value. If not specified, the
141
+ * category controls are not rendered.
142
+ * The function's signature changes depending on whether multiple category
143
+ * selection is enabled or not.
144
+ */
145
+ onCategoryChange?: FormTokenFieldProps[ 'onChange' ];
146
+ };
147
+
148
+ export type QueryControlsProps =
149
+ | QueryControlsWithSingleCategorySelectionProps
150
+ | QueryControlsWithMultipleCategorySelectionProps;
@@ -9,12 +9,7 @@ import userEvent from '@testing-library/user-event';
9
9
  */
10
10
  import SelectControl from '..';
11
11
 
12
- jest.useFakeTimers();
13
-
14
- const setupUser = () =>
15
- userEvent.setup( {
16
- advanceTimers: jest.advanceTimersByTime,
17
- } );
12
+ const setupUser = () => userEvent.setup();
18
13
 
19
14
  describe( 'SelectControl', () => {
20
15
  it( 'should not render when no options or children are provided', () => {
@@ -15,6 +15,7 @@ function useForceUpdate() {
15
15
  const mounted = useRef( true );
16
16
 
17
17
  useEffect( () => {
18
+ mounted.current = true;
18
19
  return () => {
19
20
  mounted.current = false;
20
21
  };
@@ -34,7 +34,7 @@ class SlotComponent extends Component {
34
34
 
35
35
  componentDidMount() {
36
36
  const { registerSlot } = this.props;
37
-
37
+ this.isUnmounted = false;
38
38
  registerSlot( this.props.name, this );
39
39
  }
40
40
 
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * WordPress dependencies
4
4
  */
5
- import { useContext, useState, useEffect } from '@wordpress/element';
5
+ import { useContext, useSyncExternalStore } from '@wordpress/element';
6
6
 
7
7
  /**
8
8
  * Internal dependencies
@@ -17,21 +17,11 @@ import SlotFillContext from './context';
17
17
  */
18
18
  const useSlot = ( name ) => {
19
19
  const { getSlot, subscribe } = useContext( SlotFillContext );
20
- const [ slot, setSlot ] = useState( getSlot( name ) );
21
-
22
- useEffect( () => {
23
- setSlot( getSlot( name ) );
24
- const unsubscribe = subscribe( () => {
25
- setSlot( getSlot( name ) );
26
- } );
27
-
28
- return unsubscribe;
29
- // Ignore reason: Modifying this dep array could introduce unexpected changes in behavior,
30
- // so we'll leave it as=is until the hook can be properly refactored for exhaustive-deps.
31
- // eslint-disable-next-line react-hooks/exhaustive-deps
32
- }, [ name ] );
33
-
34
- return slot;
20
+ return useSyncExternalStore(
21
+ subscribe,
22
+ () => getSlot( name ),
23
+ () => getSlot( name )
24
+ );
35
25
  };
36
26
 
37
27
  export default useSlot;
@@ -16,7 +16,8 @@ import warning from '@wordpress/warning';
16
16
  * Internal dependencies
17
17
  */
18
18
  import Button from '../button';
19
- import type { NoticeAction, SnackbarProps } from './types';
19
+ import type { SnackbarProps } from './types';
20
+ import type { NoticeAction } from '../notice/types';
20
21
  import type { WordPressComponentProps } from '../ui/context';
21
22
 
22
23
  const NOTICE_TIMEOUT = 10000;
@@ -73,7 +74,7 @@ function UnforwardedSnackbar(
73
74
  }
74
75
 
75
76
  function onActionClick(
76
- event: MouseEvent,
77
+ event: MouseEvent< HTMLButtonElement >,
77
78
  onClick: NoticeAction[ 'onClick' ]
78
79
  ) {
79
80
  event.stopPropagation();
@@ -139,9 +140,9 @@ function UnforwardedSnackbar(
139
140
  key={ index }
140
141
  href={ url }
141
142
  variant="tertiary"
142
- onClick={ ( event: MouseEvent ) =>
143
- onActionClick( event, onClick )
144
- }
143
+ onClick={ (
144
+ event: MouseEvent< HTMLButtonElement >
145
+ ) => onActionClick( event, onClick ) }
145
146
  className="components-snackbar__action"
146
147
  >
147
148
  { label }
@@ -17,7 +17,7 @@ import {
17
17
  __unstableMotion as motion,
18
18
  __unstableAnimatePresence as AnimatePresence,
19
19
  } from '../animation';
20
- import type { Notice, SnackbarListProps } from './types';
20
+ import type { SnackbarListProps } from './types';
21
21
  import type { WordPressComponentProps } from '../ui/context';
22
22
 
23
23
  const SNACKBAR_VARIANTS = {
@@ -61,7 +61,9 @@ export function SnackbarList( {
61
61
  const listRef = useRef< HTMLDivElement | null >( null );
62
62
  const isReducedMotion = useReducedMotion();
63
63
  className = classnames( 'components-snackbar-list', className );
64
- const removeNotice = ( notice: Notice ) => () => onRemove?.( notice.id );
64
+ const removeNotice =
65
+ ( notice: SnackbarListProps[ 'notices' ][ number ] ) => () =>
66
+ onRemove?.( notice.id );
65
67
  return (
66
68
  <div className={ className } tabIndex={ -1 } ref={ listRef }>
67
69
  { children }
@@ -1,116 +1,42 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import type { MutableRefObject, ReactNode, SyntheticEvent } from 'react';
4
+ import type { MutableRefObject, ReactNode } from 'react';
5
5
 
6
- export type NoticeActionWithURL = {
7
- label: string;
8
- url: string;
9
- onClick?: ( event: SyntheticEvent ) => void;
10
- };
11
-
12
- type NoticeActionWithOnClick = {
13
- label: string;
14
- url?: string;
15
- onClick: ( event: SyntheticEvent ) => void;
16
- };
17
-
18
- // TODO: move this type to the Notice component once it gets typed.
19
- export type NoticeAction = NoticeActionWithURL | NoticeActionWithOnClick;
20
-
21
- export type Notice = {
22
- id: string;
23
- spokenMessage: string;
24
- actions: NoticeAction[];
25
- icon?: ReactNode;
26
- onDismiss?: () => void;
27
- content: string;
28
- isDismissible: boolean;
29
- explicitDismiss: boolean;
30
- };
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type { NoticeProps, NoticeChildren } from '../notice/types';
31
10
 
32
- export type SnackbarProps = {
33
- /**
34
- * The displayed message of a notice.
35
- *
36
- * Also used as the spoken message for assistive technology,
37
- * unless `spokenMessage` is provided as an alternative message.
38
- */
39
- children: string;
40
- /**
41
- * Used to provide a custom spoken message.
42
- *
43
- * @default children
44
- */
45
- spokenMessage?: Notice[ 'spokenMessage' ];
46
- /**
47
- * A politeness level for the notice's spoken message. Should be provided as
48
- * one of the valid options for an `aria-live` attribute value. Note that this
49
- * value should be considered a suggestion; assistive technologies may
50
- * override it based on internal heuristics.
51
- *
52
- * A value of `'assertive'` is to be used for important, and usually
53
- * time-sensitive, information. It will interrupt anything else the screen
54
- * reader is announcing in that moment.
55
- * A value of `'polite'` is to be used for advisory information. It should
56
- * not interrupt what the screen reader is announcing in that moment
57
- * (the "speech queue") or interrupt the current task.
58
- *
59
- * @see https://www.w3.org/TR/wai-aria-1.1/#aria-live
60
- *
61
- * @default 'polite'
62
- */
63
- politeness?: 'polite' | 'assertive';
64
- /**
65
- * An array of action objects.
66
- *
67
- * Each member object should contain
68
- * a `label` and either a `url` link string or `onClick` callback function.
69
- *
70
- * @default []
71
- */
72
- actions?: Notice[ 'actions' ];
73
- /**
74
- * Called to remove the snackbar from the UI.
75
- */
76
- onRemove?: () => void;
11
+ type SnackbarOnlyProps = {
77
12
  /**
78
13
  * The icon to render in the snackbar.
79
14
  *
80
15
  * @default null
81
16
  */
82
- icon?: Notice[ 'icon' ];
17
+ icon?: ReactNode;
83
18
  /**
84
19
  * Whether to require user action to dismiss the snackbar.
85
20
  * By default, this is dismissed on a timeout, without user interaction.
86
21
  *
87
22
  * @default false
88
23
  */
89
- explicitDismiss?: Notice[ 'explicitDismiss' ];
90
- /**
91
- * A callback executed when the snackbar is dismissed.
92
- *
93
- * It is distinct from onRemove, which _looks_ like a callback but is
94
- * actually the function to call to remove the snackbar from the UI.
95
- */
96
- onDismiss?: Notice[ 'onDismiss' ];
24
+ explicitDismiss?: boolean;
97
25
  /**
98
26
  * A ref to the list that contains the snackbar.
99
27
  */
100
28
  listRef?: MutableRefObject< HTMLDivElement | null >;
101
29
  };
102
30
 
31
+ export type SnackbarProps = NoticeProps & SnackbarOnlyProps;
32
+
103
33
  export type SnackbarListProps = {
104
- /**
105
- * Array of notices to render.
106
- */
107
- notices: Notice[];
108
- /**
109
- * Children to be rendered inside the notice list.
110
- */
111
- children?: ReactNode;
112
- /**
113
- * Function called when a notice should be removed / dismissed.
114
- */
115
- onRemove?: ( id: Notice[ 'id' ] ) => void;
34
+ notices: Array<
35
+ Omit< SnackbarProps, 'children' > & {
36
+ id: string;
37
+ content: string;
38
+ }
39
+ >;
40
+ onRemove: ( id: string ) => void;
41
+ children?: NoticeChildren | Array< NoticeChildren >;
116
42
  };
@@ -25,7 +25,7 @@ const TabButton = ( {
25
25
  }: TabButtonProps ) => (
26
26
  <Button
27
27
  role="tab"
28
- tabIndex={ selected ? null : -1 }
28
+ tabIndex={ selected ? undefined : -1 }
29
29
  aria-selected={ selected }
30
30
  id={ tabId }
31
31
  __experimentalIsFocusable
@@ -103,25 +103,47 @@ export function TabPanel( {
103
103
  const selectedTab = tabs.find( ( { name } ) => name === selected );
104
104
  const selectedId = `${ instanceId }-${ selectedTab?.name ?? 'none' }`;
105
105
 
106
+ // Handle selecting the initial tab.
106
107
  useEffect( () => {
107
- const firstEnabledTab = tabs.find( ( tab ) => ! tab.disabled );
108
+ // If there's a selected tab, don't override it.
109
+ if ( selectedTab ) {
110
+ return;
111
+ }
112
+
108
113
  const initialTab = tabs.find( ( tab ) => tab.name === initialTabName );
109
- if ( ! selectedTab?.name && firstEnabledTab ) {
110
- handleTabSelection(
111
- initialTab && ! initialTab.disabled
112
- ? initialTab.name
113
- : firstEnabledTab.name
114
- );
115
- } else if ( selectedTab?.disabled && firstEnabledTab ) {
114
+
115
+ // Wait for the denoted initial tab to be declared before making a
116
+ // selection. This ensures that if a tab is declared lazily it can
117
+ // still receive initial selection.
118
+ if ( initialTabName && ! initialTab ) {
119
+ return;
120
+ }
121
+
122
+ if ( initialTab && ! initialTab.disabled ) {
123
+ // Select the initial tab if it's not disabled.
124
+ handleTabSelection( initialTab.name );
125
+ } else {
126
+ // Fallback to the first enabled tab when the initial is disabled.
127
+ const firstEnabledTab = tabs.find( ( tab ) => ! tab.disabled );
128
+ if ( firstEnabledTab ) handleTabSelection( firstEnabledTab.name );
129
+ }
130
+ }, [ tabs, selectedTab, initialTabName, handleTabSelection ] );
131
+
132
+ // Handle the currently selected tab becoming disabled.
133
+ useEffect( () => {
134
+ // This effect only runs when the selected tab is defined and becomes disabled.
135
+ if ( ! selectedTab?.disabled ) {
136
+ return;
137
+ }
138
+
139
+ const firstEnabledTab = tabs.find( ( tab ) => ! tab.disabled );
140
+
141
+ // If the currently selected tab becomes disabled, select the first enabled tab.
142
+ // (if there is one).
143
+ if ( firstEnabledTab ) {
116
144
  handleTabSelection( firstEnabledTab.name );
117
145
  }
118
- }, [
119
- tabs,
120
- selectedTab?.name,
121
- selectedTab?.disabled,
122
- initialTabName,
123
- handleTabSelection,
124
- ] );
146
+ }, [ tabs, selectedTab?.disabled, handleTabSelection ] );
125
147
 
126
148
  return (
127
149
  <div className={ className }>
@@ -24,6 +24,7 @@
24
24
  &:focus:not(:disabled) {
25
25
  position: relative;
26
26
  box-shadow: none;
27
+ outline: none;
27
28
  }
28
29
 
29
30
  // Tab indicator
@@ -48,6 +49,10 @@
48
49
  // Active.
49
50
  &.is-active::after {
50
51
  height: calc(1 * var(--wp-admin-border-width-focus));
52
+
53
+ // Windows high contrast mode.
54
+ outline: 2px solid transparent;
55
+ outline-offset: -1px;
51
56
  }
52
57
 
53
58
  // Focus.
@@ -71,5 +76,8 @@
71
76
 
72
77
  &:focus-visible::before {
73
78
  box-shadow: 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
79
+
80
+ // Windows high contrast mode.
81
+ outline: 2px solid transparent;
74
82
  }
75
83
  }