@wordpress/components 40.0.0 → 40.1.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 (472) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/CONTRIBUTING.md +2 -0
  3. package/build/border-box-control/border-box-control/component.cjs +37 -5
  4. package/build/border-box-control/border-box-control/component.cjs.map +3 -3
  5. package/build/border-box-control/border-box-control/hook.cjs +24 -3
  6. package/build/border-box-control/border-box-control/hook.cjs.map +3 -3
  7. package/build/border-box-control/border-box-control-linked-button/hook.cjs +2 -2
  8. package/build/border-box-control/border-box-control-linked-button/hook.cjs.map +2 -2
  9. package/build/border-box-control/border-box-control-split-controls/hook.cjs +2 -2
  10. package/build/border-box-control/border-box-control-split-controls/hook.cjs.map +2 -2
  11. package/build/border-box-control/border-box-control-visualizer/hook.cjs +2 -2
  12. package/build/border-box-control/border-box-control-visualizer/hook.cjs.map +2 -2
  13. package/build/color-palette/index.cjs +1 -1
  14. package/build/color-palette/index.cjs.map +2 -2
  15. package/build/composite/context.cjs +9 -2
  16. package/build/composite/context.cjs.map +2 -2
  17. package/build/composite/group-label.cjs +4 -0
  18. package/build/composite/group-label.cjs.map +2 -2
  19. package/build/composite/group.cjs +10 -2
  20. package/build/composite/group.cjs.map +2 -2
  21. package/build/composite/item.cjs +4 -0
  22. package/build/composite/item.cjs.map +3 -3
  23. package/build/context/context-system-provider.cjs +2 -5
  24. package/build/context/context-system-provider.cjs.map +3 -3
  25. package/build/context/use-context-system.cjs +7 -2
  26. package/build/context/use-context-system.cjs.map +2 -2
  27. package/build/disabled/index.cjs +1 -1
  28. package/build/disabled/index.cjs.map +2 -2
  29. package/build/draggable/index.cjs.map +1 -1
  30. package/build/form-token-field/index.cjs +1 -1
  31. package/build/form-token-field/index.cjs.map +2 -2
  32. package/build/icon/index.cjs +30 -12
  33. package/build/icon/index.cjs.map +2 -2
  34. package/build/input-control/styles/input-control-styles.cjs +42 -27
  35. package/build/input-control/styles/input-control-styles.cjs.map +2 -2
  36. package/build/item-group/context.cjs +1 -0
  37. package/build/item-group/context.cjs.map +2 -2
  38. package/build/item-group/item/component.cjs +12 -0
  39. package/build/item-group/item/component.cjs.map +3 -3
  40. package/build/item-group/item/hook.cjs +7 -6
  41. package/build/item-group/item/hook.cjs.map +2 -2
  42. package/build/item-group/item-group/component.cjs +1 -0
  43. package/build/item-group/item-group/component.cjs.map +2 -2
  44. package/build/item-group/item-group/hook.cjs +1 -1
  45. package/build/item-group/item-group/hook.cjs.map +2 -2
  46. package/build/progress-bar/index.cjs +1 -1
  47. package/build/progress-bar/index.cjs.map +2 -2
  48. package/build/resizable-box/index.cjs.map +1 -1
  49. package/build/snackbar/index.cjs +8 -5
  50. package/build/snackbar/index.cjs.map +2 -2
  51. package/build/textarea-control/index.cjs +1 -1
  52. package/build/textarea-control/index.cjs.map +2 -2
  53. package/build/toggle-group-control/context.cjs +8 -2
  54. package/build/toggle-group-control/context.cjs.map +2 -2
  55. package/build/toggle-group-control/toggle-group-control/as-button-group.cjs +5 -2
  56. package/build/toggle-group-control/toggle-group-control/as-button-group.cjs.map +2 -2
  57. package/build/toggle-group-control/toggle-group-control/as-radio-group.cjs +5 -2
  58. package/build/toggle-group-control/toggle-group-control/as-radio-group.cjs.map +2 -2
  59. package/build/toggle-group-control/toggle-group-control/component.cjs +3 -1
  60. package/build/toggle-group-control/toggle-group-control/component.cjs.map +2 -2
  61. package/build/toggle-group-control/toggle-group-control-option/component.cjs +2 -0
  62. package/build/toggle-group-control/toggle-group-control-option/component.cjs.map +2 -2
  63. package/build/toggle-group-control/toggle-group-control-option-base/component.cjs +2 -1
  64. package/build/toggle-group-control/toggle-group-control-option-base/component.cjs.map +2 -2
  65. package/build/toggle-group-control/toggle-group-control-option-icon/component.cjs +2 -0
  66. package/build/toggle-group-control/toggle-group-control-option-icon/component.cjs.map +2 -2
  67. package/build/tools-panel/tools-panel/hook.cjs +102 -106
  68. package/build/tools-panel/tools-panel/hook.cjs.map +2 -2
  69. package/build/tools-panel/tools-panel-item/hook.cjs +33 -33
  70. package/build/tools-panel/tools-panel-item/hook.cjs.map +2 -2
  71. package/build/tree-grid/cell.cjs +4 -0
  72. package/build/tree-grid/cell.cjs.map +2 -2
  73. package/build/tree-grid/roving-tab-index-item.cjs +5 -1
  74. package/build/tree-grid/roving-tab-index-item.cjs.map +2 -2
  75. package/build/tree-grid/row.cjs +6 -1
  76. package/build/tree-grid/row.cjs.map +2 -2
  77. package/build/tree-grid/use-validate-tree-grid-structure.cjs +81 -0
  78. package/build/tree-grid/use-validate-tree-grid-structure.cjs.map +7 -0
  79. package/build/utils/colors-values.cjs +3 -2
  80. package/build/utils/colors-values.cjs.map +2 -2
  81. package/build-module/border-box-control/border-box-control/component.mjs +38 -6
  82. package/build-module/border-box-control/border-box-control/component.mjs.map +2 -2
  83. package/build-module/border-box-control/border-box-control/hook.mjs +14 -3
  84. package/build-module/border-box-control/border-box-control/hook.mjs.map +2 -2
  85. package/build-module/border-box-control/border-box-control-linked-button/hook.mjs +2 -2
  86. package/build-module/border-box-control/border-box-control-linked-button/hook.mjs.map +2 -2
  87. package/build-module/border-box-control/border-box-control-split-controls/hook.mjs +2 -2
  88. package/build-module/border-box-control/border-box-control-split-controls/hook.mjs.map +2 -2
  89. package/build-module/border-box-control/border-box-control-visualizer/hook.mjs +2 -2
  90. package/build-module/border-box-control/border-box-control-visualizer/hook.mjs.map +2 -2
  91. package/build-module/color-palette/index.mjs +1 -1
  92. package/build-module/color-palette/index.mjs.map +2 -2
  93. package/build-module/composite/context.mjs +6 -1
  94. package/build-module/composite/context.mjs.map +2 -2
  95. package/build-module/composite/group-label.mjs +5 -1
  96. package/build-module/composite/group-label.mjs.map +2 -2
  97. package/build-module/composite/group.mjs +11 -3
  98. package/build-module/composite/group.mjs.map +2 -2
  99. package/build-module/composite/item.mjs +4 -0
  100. package/build-module/composite/item.mjs.map +2 -2
  101. package/build-module/context/context-system-provider.mjs +2 -5
  102. package/build-module/context/context-system-provider.mjs.map +3 -3
  103. package/build-module/context/use-context-system.mjs +7 -2
  104. package/build-module/context/use-context-system.mjs.map +2 -2
  105. package/build-module/disabled/index.mjs +1 -1
  106. package/build-module/disabled/index.mjs.map +2 -2
  107. package/build-module/draggable/index.mjs.map +1 -1
  108. package/build-module/form-token-field/index.mjs +1 -1
  109. package/build-module/form-token-field/index.mjs.map +2 -2
  110. package/build-module/icon/index.mjs +30 -12
  111. package/build-module/icon/index.mjs.map +2 -2
  112. package/build-module/input-control/styles/input-control-styles.mjs +42 -27
  113. package/build-module/input-control/styles/input-control-styles.mjs.map +2 -2
  114. package/build-module/item-group/context.mjs +1 -0
  115. package/build-module/item-group/context.mjs.map +2 -2
  116. package/build-module/item-group/item/component.mjs +12 -0
  117. package/build-module/item-group/item/component.mjs.map +2 -2
  118. package/build-module/item-group/item/hook.mjs +7 -6
  119. package/build-module/item-group/item/hook.mjs.map +2 -2
  120. package/build-module/item-group/item-group/component.mjs +1 -0
  121. package/build-module/item-group/item-group/component.mjs.map +2 -2
  122. package/build-module/item-group/item-group/hook.mjs +1 -1
  123. package/build-module/item-group/item-group/hook.mjs.map +2 -2
  124. package/build-module/progress-bar/index.mjs +1 -1
  125. package/build-module/progress-bar/index.mjs.map +2 -2
  126. package/build-module/resizable-box/index.mjs.map +1 -1
  127. package/build-module/snackbar/index.mjs +8 -5
  128. package/build-module/snackbar/index.mjs.map +2 -2
  129. package/build-module/textarea-control/index.mjs +1 -1
  130. package/build-module/textarea-control/index.mjs.map +2 -2
  131. package/build-module/toggle-group-control/context.mjs +8 -2
  132. package/build-module/toggle-group-control/context.mjs.map +2 -2
  133. package/build-module/toggle-group-control/toggle-group-control/as-button-group.mjs +5 -2
  134. package/build-module/toggle-group-control/toggle-group-control/as-button-group.mjs.map +2 -2
  135. package/build-module/toggle-group-control/toggle-group-control/as-radio-group.mjs +5 -2
  136. package/build-module/toggle-group-control/toggle-group-control/as-radio-group.mjs.map +2 -2
  137. package/build-module/toggle-group-control/toggle-group-control/component.mjs +3 -1
  138. package/build-module/toggle-group-control/toggle-group-control/component.mjs.map +2 -2
  139. package/build-module/toggle-group-control/toggle-group-control-option/component.mjs +2 -0
  140. package/build-module/toggle-group-control/toggle-group-control-option/component.mjs.map +2 -2
  141. package/build-module/toggle-group-control/toggle-group-control-option-base/component.mjs +2 -1
  142. package/build-module/toggle-group-control/toggle-group-control-option-base/component.mjs.map +2 -2
  143. package/build-module/toggle-group-control/toggle-group-control-option-icon/component.mjs +2 -0
  144. package/build-module/toggle-group-control/toggle-group-control-option-icon/component.mjs.map +2 -2
  145. package/build-module/tools-panel/tools-panel/hook.mjs +103 -107
  146. package/build-module/tools-panel/tools-panel/hook.mjs.map +2 -2
  147. package/build-module/tools-panel/tools-panel-item/hook.mjs +35 -35
  148. package/build-module/tools-panel/tools-panel-item/hook.mjs.map +2 -2
  149. package/build-module/tree-grid/cell.mjs +5 -1
  150. package/build-module/tree-grid/cell.mjs.map +2 -2
  151. package/build-module/tree-grid/roving-tab-index-item.mjs +5 -1
  152. package/build-module/tree-grid/roving-tab-index-item.mjs.map +2 -2
  153. package/build-module/tree-grid/row.mjs +7 -2
  154. package/build-module/tree-grid/row.mjs.map +2 -2
  155. package/build-module/tree-grid/use-validate-tree-grid-structure.mjs +56 -0
  156. package/build-module/tree-grid/use-validate-tree-grid-structure.mjs.map +7 -0
  157. package/build-module/utils/colors-values.mjs +3 -2
  158. package/build-module/utils/colors-values.mjs.map +2 -2
  159. package/build-style/style-rtl.css +27 -85
  160. package/build-style/style.css +27 -85
  161. package/build-types/border-box-control/border-box-control/component.d.ts +4 -0
  162. package/build-types/border-box-control/border-box-control/component.d.ts.map +1 -1
  163. package/build-types/border-box-control/border-box-control/hook.d.ts +4 -2
  164. package/build-types/border-box-control/border-box-control/hook.d.ts.map +1 -1
  165. package/build-types/border-box-control/types.d.ts +6 -2
  166. package/build-types/border-box-control/types.d.ts.map +1 -1
  167. package/build-types/composite/context.d.ts +2 -0
  168. package/build-types/composite/context.d.ts.map +1 -1
  169. package/build-types/composite/group-label.d.ts.map +1 -1
  170. package/build-types/composite/group.d.ts.map +1 -1
  171. package/build-types/composite/item.d.ts.map +1 -1
  172. package/build-types/composite/types.d.ts +1 -1
  173. package/build-types/context/context-system-provider.d.ts +8 -6
  174. package/build-types/context/context-system-provider.d.ts.map +1 -1
  175. package/build-types/context/use-context-system.d.ts.map +1 -1
  176. package/build-types/icon/index.d.ts.map +1 -1
  177. package/build-types/input-control/styles/input-control-styles.d.ts.map +1 -1
  178. package/build-types/item-group/context.d.ts.map +1 -1
  179. package/build-types/item-group/item/component.d.ts.map +1 -1
  180. package/build-types/item-group/item/hook.d.ts +1 -1
  181. package/build-types/item-group/item/hook.d.ts.map +1 -1
  182. package/build-types/item-group/item-group/component.d.ts.map +1 -1
  183. package/build-types/item-group/types.d.ts +4 -0
  184. package/build-types/item-group/types.d.ts.map +1 -1
  185. package/build-types/popover/types.d.ts +6 -2
  186. package/build-types/popover/types.d.ts.map +1 -1
  187. package/build-types/snackbar/index.d.ts.map +1 -1
  188. package/build-types/toggle-group-control/context.d.ts +2 -2
  189. package/build-types/toggle-group-control/context.d.ts.map +1 -1
  190. package/build-types/toggle-group-control/toggle-group-control/as-button-group.d.ts +1 -1
  191. package/build-types/toggle-group-control/toggle-group-control/as-button-group.d.ts.map +1 -1
  192. package/build-types/toggle-group-control/toggle-group-control/as-radio-group.d.ts +1 -1
  193. package/build-types/toggle-group-control/toggle-group-control/as-radio-group.d.ts.map +1 -1
  194. package/build-types/toggle-group-control/toggle-group-control/component.d.ts.map +1 -1
  195. package/build-types/toggle-group-control/toggle-group-control-option/component.d.ts +2 -2
  196. package/build-types/toggle-group-control/toggle-group-control-option/component.d.ts.map +1 -1
  197. package/build-types/toggle-group-control/toggle-group-control-option-base/component.d.ts.map +1 -1
  198. package/build-types/toggle-group-control/toggle-group-control-option-icon/component.d.ts +2 -2
  199. package/build-types/toggle-group-control/toggle-group-control-option-icon/component.d.ts.map +1 -1
  200. package/build-types/toggle-group-control/types.d.ts +12 -3
  201. package/build-types/toggle-group-control/types.d.ts.map +1 -1
  202. package/build-types/tools-panel/tools-panel/hook.d.ts +4 -4
  203. package/build-types/tools-panel/tools-panel/hook.d.ts.map +1 -1
  204. package/build-types/tools-panel/tools-panel-item/hook.d.ts.map +1 -1
  205. package/build-types/tools-panel/types.d.ts +52 -9
  206. package/build-types/tools-panel/types.d.ts.map +1 -1
  207. package/build-types/tree-grid/cell.d.ts.map +1 -1
  208. package/build-types/tree-grid/roving-tab-index-item.d.ts.map +1 -1
  209. package/build-types/tree-grid/row.d.ts.map +1 -1
  210. package/build-types/tree-grid/use-validate-tree-grid-structure.d.ts +2 -0
  211. package/build-types/tree-grid/use-validate-tree-grid-structure.d.ts.map +1 -0
  212. package/build-types/utils/colors-values.d.ts.map +1 -1
  213. package/emotion-to-scss-modules.md +149 -0
  214. package/package.json +28 -27
  215. package/src/alignment-matrix-control/test/{index.tsx → index.jsdom.test.tsx} +5 -4
  216. package/src/angle-picker-control/style.module.scss +1 -1
  217. package/src/autocomplete/test/get-autocomplete-match.ts +2 -1
  218. package/src/autocomplete/test/{index.tsx → index.jsdom.test.tsx} +2 -1
  219. package/src/badge/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  220. package/src/base-control/stories/index.story.tsx +2 -2
  221. package/src/base-control/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  222. package/src/border-box-control/border-box-control/README.md +5 -3
  223. package/src/border-box-control/border-box-control/component.tsx +83 -15
  224. package/src/border-box-control/border-box-control/hook.ts +19 -1
  225. package/src/border-box-control/stories/index.story.tsx +10 -0
  226. package/src/border-box-control/style.module.scss +34 -3
  227. package/src/border-box-control/test/{index.tsx → index.jsdom.test.tsx} +138 -2
  228. package/src/border-box-control/test/utils.ts +11 -0
  229. package/src/border-box-control/types.ts +6 -2
  230. package/src/border-control/test/{index.js → index.jsdom.test.tsx} +44 -24
  231. package/src/box-control/test/{index.tsx → index.jsdom.test.tsx} +6 -3
  232. package/src/button/style.scss +0 -6
  233. package/src/button/test/{index.tsx → index.jsdom.test.tsx} +6 -2
  234. package/src/checkbox-control/stories/index.story.tsx +1 -1
  235. package/src/checkbox-control/style.scss +2 -2
  236. package/src/checkbox-control/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +10 -7
  237. package/src/checkbox-control/test/{index.tsx → index.jsdom.test.tsx} +4 -1
  238. package/src/circular-option-picker/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  239. package/src/color-indicator/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +2 -2
  240. package/src/color-indicator/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  241. package/src/color-palette/index.tsx +1 -1
  242. package/src/color-palette/test/{index.tsx → index.jsdom.test.tsx} +25 -22
  243. package/src/color-palette/test/{utils.ts → utils.jsdom.test.ts} +1 -0
  244. package/src/combobox-control/test/{index.tsx → index.jsdom.test.tsx} +12 -7
  245. package/src/composite/README.md +1 -1
  246. package/src/composite/context.tsx +6 -0
  247. package/src/composite/group-label.tsx +8 -1
  248. package/src/composite/group.tsx +9 -2
  249. package/src/composite/item.tsx +6 -0
  250. package/src/composite/legacy/test/{index.tsx → index.jsdom.test.tsx} +6 -13
  251. package/src/composite/test/{index.tsx → index.jsdom.test.tsx} +60 -17
  252. package/src/composite/types.ts +1 -1
  253. package/src/confirm-dialog/test/{index.tsx → index.jsdom.test.tsx} +16 -14
  254. package/src/content-editable-control/test/{index.tsx → index.jsdom.test.tsx} +4 -3
  255. package/src/context/{context-system-provider.js → context-system-provider.tsx} +19 -5
  256. package/src/context/stories/{ComponentsProvider.stories.jsx → ComponentsProvider.stories.tsx} +2 -2
  257. package/src/context/test/context-connect.tsx +1 -2
  258. package/src/context/test/{context-system-provider.js → context-system-provider.jsdom.test.tsx} +93 -51
  259. package/src/context/test/wordpress-component.tsx +1 -2
  260. package/src/context/use-context-system.js +13 -4
  261. package/src/custom-gradient-picker/gradient-bar/test/{utils.ts → utils.jsdom.test.ts} +6 -5
  262. package/src/custom-gradient-picker/test/serializer.ts +1 -0
  263. package/src/custom-select-control-v2/test/{index.tsx → index.jsdom.test.tsx} +4 -1
  264. package/src/date-time/date-picker/test/{index.tsx → index.jsdom.test.tsx} +6 -3
  265. package/src/date-time/date-picker/test/{use-lilius.ts → use-lilius.jsdom.test.ts} +1 -0
  266. package/src/date-time/date-time/test/{index.tsx → index.jsdom.test.tsx} +20 -11
  267. package/src/date-time/test/utils.test.ts +9 -0
  268. package/src/date-time/time-picker/test/{index.tsx → index.jsdom.test.tsx} +37 -27
  269. package/src/date-time/time-picker/time-input/test/{index.tsx → index.jsdom.test.tsx} +8 -3
  270. package/src/disabled/index.tsx +7 -7
  271. package/src/disabled/test/{index.tsx → index.jsdom.test.tsx} +26 -0
  272. package/src/draggable/index.tsx +1 -1
  273. package/src/draggable/style.module.scss +1 -1
  274. package/src/dropdown/style.module.scss +2 -2
  275. package/src/dropdown/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  276. package/src/dropdown-menu/test/{index.tsx → index.jsdom.test.tsx} +5 -4
  277. package/src/duotone-picker/test/{custom-duotone-bar.tsx → custom-duotone-bar.jsdom.test.tsx} +11 -8
  278. package/src/duotone-picker/test/{index.tsx → index.jsdom.test.tsx} +11 -10
  279. package/src/external-link/test/{index.tsx → index.jsdom.test.tsx} +5 -4
  280. package/src/focal-point-picker/test/{index.tsx → index.jsdom.test.tsx} +12 -9
  281. package/src/focal-point-picker/test/{media.tsx → media.jsdom.test.tsx} +1 -0
  282. package/src/font-size-picker/test/{font-size-picker-select.tsx → font-size-picker-select.jsdom.test.tsx} +19 -16
  283. package/src/font-size-picker/test/{font-size-picker-toggle-group.tsx → font-size-picker-toggle-group.jsdom.test.tsx} +13 -11
  284. package/src/font-size-picker/test/{index.tsx → index.jsdom.test.tsx} +19 -14
  285. package/src/font-size-picker/test/utils.ts +1 -0
  286. package/src/form-toggle/style.scss +1 -1
  287. package/src/form-toggle/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +4 -4
  288. package/src/form-toggle/test/{index.tsx → index.jsdom.test.tsx} +2 -1
  289. package/src/form-token-field/index.tsx +1 -1
  290. package/src/form-token-field/test/{index.tsx → index.jsdom.test.tsx} +86 -44
  291. package/src/gradient-picker/test/{index.tsx → index.jsdom.test.tsx} +12 -9
  292. package/src/guide/test/{index.tsx → index.jsdom.test.tsx} +4 -2
  293. package/src/h-stack/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +4 -4
  294. package/src/h-stack/test/{index.tsx → index.jsdom.test.tsx} +3 -0
  295. package/src/higher-order/with-fallback-styles/test/{index.tsx → index.jsdom.test.tsx} +3 -2
  296. package/src/higher-order/with-filters/test/__snapshots__/index.jsdom.test.tsx.snap +87 -0
  297. package/src/higher-order/with-filters/test/{index.tsx → index.jsdom.test.tsx} +6 -5
  298. package/src/higher-order/with-focus-outside/test/{index.tsx → index.jsdom.test.tsx} +2 -1
  299. package/src/higher-order/with-focus-return/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  300. package/src/higher-order/with-notices/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  301. package/src/higher-order/with-spoken-messages/test/{index.tsx → index.jsdom.test.tsx} +3 -2
  302. package/src/icon/index.tsx +28 -12
  303. package/src/icon/test/{index.tsx → index.jsdom.test.tsx} +66 -0
  304. package/src/input-control/styles/input-control-styles.tsx +38 -7
  305. package/src/input-control/test/{index.js → index.jsdom.test.tsx} +16 -10
  306. package/src/isolated-event-container/test/{index.tsx → index.jsdom.test.tsx} +4 -3
  307. package/src/item-group/context.ts +1 -0
  308. package/src/item-group/item/component.tsx +19 -1
  309. package/src/item-group/item/hook.ts +2 -3
  310. package/src/item-group/item-group/component.tsx +1 -0
  311. package/src/item-group/style.module.scss +1 -2
  312. package/src/item-group/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +9 -9
  313. package/src/item-group/test/{index.js → index.jsdom.test.tsx} +99 -2
  314. package/src/item-group/types.ts +4 -0
  315. package/src/keyboard-shortcuts/test/{index.tsx → index.jsdom.test.tsx} +5 -4
  316. package/src/menu/test/{index.tsx → index.jsdom.test.tsx} +67 -23
  317. package/src/menu-group/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  318. package/src/menu-item/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +5 -5
  319. package/src/menu-item/test/{index.js → index.jsdom.test.tsx} +1 -0
  320. package/src/modal/test/{aria-helper.ts → aria-helper.jsdom.test.ts} +1 -0
  321. package/src/modal/test/{index.tsx → index.jsdom.test.tsx} +9 -5
  322. package/src/navigable-container/test/{navigable-menu.tsx → navigable-menu.jsdom.test.tsx} +7 -5
  323. package/src/navigable-container/test/{tababble-container.tsx → tababble-container.jsdom.test.tsx} +5 -3
  324. package/src/navigator/test/{index.tsx → index.jsdom.test.tsx} +5 -2
  325. package/src/navigator/test/router.ts +1 -0
  326. package/src/notice/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +7 -4
  327. package/src/notice/test/{index.tsx → index.jsdom.test.tsx} +8 -4
  328. package/src/notice/test/{list.tsx → list.jsdom.test.tsx} +1 -0
  329. package/src/number-control/test/{index.tsx → index.jsdom.test.tsx} +9 -6
  330. package/src/palette-edit/test/{index.tsx → index.jsdom.test.tsx} +16 -13
  331. package/src/panel/test/__snapshots__/body.jsdom.test.tsx.snap +9 -0
  332. package/src/panel/test/__snapshots__/header.jsdom.test.tsx.snap +9 -0
  333. package/src/panel/test/__snapshots__/index.jsdom.test.tsx.snap +17 -0
  334. package/src/panel/test/__snapshots__/row.jsdom.test.tsx.snap +17 -0
  335. package/src/panel/test/{body.tsx → body.jsdom.test.tsx} +2 -1
  336. package/src/panel/test/{header.tsx → header.jsdom.test.tsx} +1 -0
  337. package/src/panel/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  338. package/src/panel/test/{row.tsx → row.jsdom.test.tsx} +1 -0
  339. package/src/placeholder/style.scss +0 -5
  340. package/src/placeholder/test/{index.tsx → index.jsdom.test.tsx} +19 -14
  341. package/src/popover/README.md +2 -2
  342. package/src/popover/test/{index.tsx → index.jsdom.test.tsx} +23 -0
  343. package/src/popover/types.ts +9 -3
  344. package/src/progress-bar/style.module.scss +9 -1
  345. package/src/query-controls/test/terms.ts +1 -0
  346. package/src/radio-control/test/{index.tsx → index.jsdom.test.tsx} +14 -11
  347. package/src/range-control/test/{index.tsx → index.jsdom.test.tsx} +10 -7
  348. package/src/resizable-box/index.tsx +1 -1
  349. package/src/sandbox/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  350. package/src/scroll-lock/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  351. package/src/shortcut/test/__snapshots__/index.jsdom.test.tsx.snap +15 -0
  352. package/src/shortcut/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  353. package/src/slot-fill/test/{index.js → index.jsdom.test.tsx} +4 -3
  354. package/src/slot-fill/test/{slot.js → slot.jsdom.test.tsx} +17 -9
  355. package/src/snackbar/index.tsx +10 -6
  356. package/src/snackbar/test/{index.tsx → index.jsdom.test.tsx} +41 -11
  357. package/src/snackbar/test/list.jsdom.test.tsx +100 -0
  358. package/src/style-provider/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  359. package/src/surface/style.module.scss +2 -2
  360. package/src/surface/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  361. package/src/tab-panel/style.scss +4 -23
  362. package/src/tab-panel/test/{index.tsx → index.jsdom.test.tsx} +22 -21
  363. package/src/tabs/test/{index.tsx → index.jsdom.test.tsx} +21 -19
  364. package/src/text-control/test/{text-control.tsx → text-control.jsdom.test.tsx} +1 -0
  365. package/src/text-highlight/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  366. package/src/textarea-control/style.module.scss +9 -4
  367. package/src/tip/style.scss +1 -1
  368. package/src/toggle-control/test/{index.tsx → index.jsdom.test.tsx} +4 -1
  369. package/src/toggle-group-control/context.ts +14 -5
  370. package/src/toggle-group-control/stories/index.story.tsx +15 -2
  371. package/src/toggle-group-control/test/{index.tsx → index.jsdom.test.tsx} +283 -9
  372. package/src/toggle-group-control/toggle-group-control/README.md +8 -5
  373. package/src/toggle-group-control/toggle-group-control/as-button-group.tsx +4 -0
  374. package/src/toggle-group-control/toggle-group-control/as-radio-group.tsx +4 -0
  375. package/src/toggle-group-control/toggle-group-control/component.tsx +2 -0
  376. package/src/toggle-group-control/toggle-group-control/style.module.scss +8 -2
  377. package/src/toggle-group-control/toggle-group-control-option/README.md +8 -5
  378. package/src/toggle-group-control/toggle-group-control-option/component.tsx +2 -0
  379. package/src/toggle-group-control/toggle-group-control-option-base/component.tsx +4 -1
  380. package/src/toggle-group-control/toggle-group-control-option-icon/README.md +7 -0
  381. package/src/toggle-group-control/toggle-group-control-option-icon/component.tsx +2 -0
  382. package/src/toggle-group-control/types.ts +12 -3
  383. package/src/toolbar/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  384. package/src/toolbar/test/{toolbar-group.tsx → toolbar-group.jsdom.test.tsx} +2 -1
  385. package/src/tools-panel/test/{index.tsx → index.jsdom.test.tsx} +595 -47
  386. package/src/tools-panel/tools-panel/hook.ts +195 -180
  387. package/src/tools-panel/tools-panel-item/README.md +42 -1
  388. package/src/tools-panel/tools-panel-item/hook.ts +97 -69
  389. package/src/tools-panel/types.ts +54 -9
  390. package/src/tooltip/test/{index.tsx → index.jsdom.test.tsx} +5 -3
  391. package/src/tree-grid/cell.tsx +6 -2
  392. package/src/tree-grid/roving-tab-index-item.tsx +7 -3
  393. package/src/tree-grid/row.tsx +8 -2
  394. package/src/tree-grid/test/__snapshots__/{cell.tsx.snap → cell.jsdom.test.tsx.snap} +2 -2
  395. package/src/tree-grid/test/__snapshots__/index.jsdom.test.tsx.snap +3 -0
  396. package/src/tree-grid/test/__snapshots__/roving-tab-index-item.jsdom.test.tsx.snap +27 -0
  397. package/src/tree-grid/test/__snapshots__/roving-tab-index.jsdom.test.tsx.snap +9 -0
  398. package/src/tree-grid/test/__snapshots__/{row.tsx.snap → row.jsdom.test.tsx.snap} +9 -5
  399. package/src/tree-grid/test/cell.jsdom.test.tsx +149 -0
  400. package/src/tree-grid/test/{index.tsx → index.jsdom.test.tsx} +9 -7
  401. package/src/tree-grid/test/{roving-tab-index-item.tsx → roving-tab-index-item.jsdom.test.tsx} +4 -1
  402. package/src/tree-grid/test/{roving-tab-index.tsx → roving-tab-index.jsdom.test.tsx} +1 -0
  403. package/src/tree-grid/test/row.jsdom.test.tsx +132 -0
  404. package/src/tree-grid/use-validate-tree-grid-structure.ts +104 -0
  405. package/src/truncate/style.module.scss +0 -1
  406. package/src/truncate/test/{index.tsx → index.jsdom.test.tsx} +1 -0
  407. package/src/unit-control/test/{index.tsx → index.jsdom.test.tsx} +22 -19
  408. package/src/unit-control/test/utils.ts +1 -0
  409. package/src/utils/colors-values.js +5 -4
  410. package/src/utils/hooks/test/{use-controlled-state.js → use-controlled-state.jsdom.test.tsx} +22 -7
  411. package/src/utils/hooks/test/{use-controlled-value.js → use-controlled-value.jsdom.test.tsx} +6 -3
  412. package/src/utils/hooks/test/{use-cx.js → use-cx.jsdom.test.tsx} +8 -5
  413. package/src/utils/test/colors.js +1 -0
  414. package/src/utils/test/{get-node-text.js → get-node-text.tsx} +1 -0
  415. package/src/utils/test/math.js +1 -0
  416. package/src/utils/test/rtl.js +1 -0
  417. package/src/utils/test/space.js +1 -0
  418. package/src/utils/test/strings.js +1 -0
  419. package/src/utils/test/unit-values.js +1 -0
  420. package/src/v-stack/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +4 -4
  421. package/src/v-stack/test/{index.tsx → index.jsdom.test.tsx} +3 -0
  422. package/src/validated-form-controls/style.scss +11 -15
  423. package/src/validated-form-controls/test/{content-editable-control.tsx → content-editable-control.jsdom.test.tsx} +1 -1
  424. package/src/validated-form-controls/test/{custom-select-control.tsx → custom-select-control.jsdom.test.tsx} +3 -0
  425. package/src/validated-form-controls/test/{input-control.tsx → input-control.jsdom.test.tsx} +3 -0
  426. package/src/validated-form-controls/test/{range-control.tsx → range-control.jsdom.test.tsx} +3 -0
  427. package/src/validated-form-controls/test/{textarea-control.tsx → textarea-control.jsdom.test.tsx} +1 -0
  428. package/src/view/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +7 -7
  429. package/src/view/test/{index.js → index.jsdom.test.tsx} +7 -2
  430. package/src/context/test/__snapshots__/context-system-provider.js.snap +0 -35
  431. package/src/higher-order/with-filters/test/__snapshots__/index.tsx.snap +0 -87
  432. package/src/panel/test/__snapshots__/body.tsx.snap +0 -9
  433. package/src/panel/test/__snapshots__/header.tsx.snap +0 -9
  434. package/src/panel/test/__snapshots__/index.tsx.snap +0 -17
  435. package/src/panel/test/__snapshots__/row.tsx.snap +0 -17
  436. package/src/shortcut/test/__snapshots__/index.tsx.snap +0 -15
  437. package/src/snackbar/test/list.tsx +0 -39
  438. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +0 -359
  439. package/src/tree-grid/test/__snapshots__/index.tsx.snap +0 -3
  440. package/src/tree-grid/test/__snapshots__/roving-tab-index-item.tsx.snap +0 -27
  441. package/src/tree-grid/test/__snapshots__/roving-tab-index.tsx.snap +0 -9
  442. package/src/tree-grid/test/cell.tsx +0 -46
  443. package/src/tree-grid/test/row.tsx +0 -37
  444. /package/src/card/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  445. /package/src/card/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  446. /package/src/color-picker/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  447. /package/src/custom-gradient-picker/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  448. /package/src/custom-select-control/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  449. /package/src/custom-select-control/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  450. /package/src/divider/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  451. /package/src/elevation/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  452. /package/src/elevation/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  453. /package/src/flex/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  454. /package/src/flex/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  455. /package/src/form-file-upload/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  456. /package/src/grid/test/{grid.tsx → grid.jsdom.test.tsx} +0 -0
  457. /package/src/heading/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  458. /package/src/heading/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  459. /package/src/input-control/test/__snapshots__/{index.js.snap → index.jsdom.test.tsx.snap} +0 -0
  460. /package/src/progress-bar/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  461. /package/src/resizable-box/resize-tooltip/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  462. /package/src/resizable-box/resize-tooltip/test/{label.tsx → label.jsdom.test.tsx} +0 -0
  463. /package/src/scrollable/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  464. /package/src/search-control/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  465. /package/src/select-control/test/__snapshots__/{select-control.tsx.snap → select-control.jsdom.test.tsx.snap} +0 -0
  466. /package/src/select-control/test/{select-control.tsx → select-control.jsdom.test.tsx} +0 -0
  467. /package/src/slot-fill/test/__snapshots__/{slot.js.snap → slot.jsdom.test.tsx.snap} +0 -0
  468. /package/src/spacer/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  469. /package/src/spacer/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  470. /package/src/text/test/__snapshots__/{index.tsx.snap → index.jsdom.test.tsx.snap} +0 -0
  471. /package/src/text/test/{index.tsx → index.jsdom.test.tsx} +0 -0
  472. /package/src/utils/test/{polymorphic-element.tsx → polymorphic-element.jsdom.test.tsx} +0 -0
@@ -1,6 +1,11 @@
1
1
  import clsx from 'clsx';
2
- import { usePrevious } from '@wordpress/compose';
3
- import { useCallback, useEffect, useLayoutEffect } from '@wordpress/element';
2
+ import { useEvent } from '@wordpress/compose';
3
+ import {
4
+ useCallback,
5
+ useEffect,
6
+ useLayoutEffect,
7
+ useRef,
8
+ } from '@wordpress/element';
4
9
  import styles from '../style.module.scss';
5
10
  import { useToolsPanelContext } from '../context';
6
11
  import type { WordPressComponentProps } from '../../context';
@@ -14,6 +19,7 @@ export function useToolsPanelItem(
14
19
  ) {
15
20
  const {
16
21
  className,
22
+ defaultShown,
17
23
  hasValue,
18
24
  isShownByDefault = false,
19
25
  label,
@@ -21,14 +27,13 @@ export function useToolsPanelItem(
21
27
  resetAllFilter = noop,
22
28
  onDeselect,
23
29
  onSelect,
30
+ onShownChange,
24
31
  ...otherProps
25
32
  } = useContextSystem( props, 'ToolsPanelItem' );
26
33
 
27
34
  const {
28
35
  panelId: currentPanelId,
29
36
  menuItems,
30
- registerResetAllFilter,
31
- deregisterResetAllFilter,
32
37
  registerPanelItem,
33
38
  deregisterPanelItem,
34
39
  flagItemCustomization,
@@ -40,100 +45,127 @@ export function useToolsPanelItem(
40
45
  __experimentalLastVisibleItemClass,
41
46
  } = useToolsPanelContext();
42
47
 
43
- // hasValue is a new function on every render, so do not add it as a
44
- // dependency to the useCallback hook! If needed, we should use a ref.
48
+ // `hasValue` is a new function every render. It can't use `useEvent`
49
+ // because the panel calls it while deriving the menu during render, which
50
+ // `useEvent` forbids, so it stays keyed on the panel it was captured for.
45
51
  const hasValueCallback = useCallback( hasValue, [ panelId ] );
46
- // resetAllFilter is a new function on every render, so do not add it as a
47
- // dependency to the useCallback hook! If needed, we should use a ref.
48
- const resetAllFilterCallback = useCallback( resetAllFilter, [ panelId ] );
49
- const previousPanelId = usePrevious( currentPanelId );
52
+ // `resetAllFilter` only runs from the reset handler, so a stable identity
53
+ // that always sees the latest props is both safe and more correct than
54
+ // freezing it per panel.
55
+ const resetAllFilterCallback = useEvent( resetAllFilter );
56
+
57
+ // `defaultShown` seeds an item's visibility when it registers, and is
58
+ // deliberately not reactive. Holding it in a ref keeps it out of the
59
+ // registration effect below, so a change on its own cannot deregister and
60
+ // re-register the item, which would discard the visibility the user chose
61
+ // from the menu.
62
+ //
63
+ // The ref still tracks the latest value, so that a re-registration caused
64
+ // by something else, such as `panelId` changing, seeds from the current
65
+ // preference rather than a stale one.
66
+ const defaultShownRef = useRef( defaultShown );
67
+ // Declared before the registration effect below so that it has already
68
+ // run by the time that effect reads the ref in the same commit.
69
+ useLayoutEffect( () => {
70
+ defaultShownRef.current = defaultShown;
71
+ } );
50
72
 
73
+ // `onShownChange` is a new function every render. `useEvent` gives the item
74
+ // a stable callback to register, while the panel still invokes the latest.
75
+ const onShownChangeCallback = useEvent( onShownChange );
76
+
77
+ // A panel spanning a multi-selection has no id of its own, so every item
78
+ // belongs to it.
51
79
  const hasMatchingPanel =
52
80
  currentPanelId === panelId || currentPanelId === null;
53
81
 
54
- // Registering the panel item allows the panel to include it in its
55
- // automatically generated menu and determine its initial checked status.
56
- //
57
- // This is performed in a layout effect to ensure that the panel item
58
- // is registered before it is rendered preventing a rendering glitch.
82
+ // A layout effect so the item is registered before it renders, avoiding a
83
+ // glitch, and so a whole panel's worth of registrations land in one commit
84
+ // for React to batch.
59
85
  // See: https://github.com/WordPress/gutenberg/issues/56470
60
86
  useLayoutEffect( () => {
61
- if ( hasMatchingPanel && previousPanelId !== null ) {
62
- registerPanelItem( {
63
- hasValue: hasValueCallback,
64
- isShownByDefault,
65
- label,
66
- panelId,
67
- } );
87
+ if ( ! hasMatchingPanel ) {
88
+ return;
68
89
  }
69
90
 
91
+ const item = {
92
+ defaultShown: defaultShownRef.current,
93
+ hasValue: hasValueCallback,
94
+ isShownByDefault,
95
+ label,
96
+ onShownChange: onShownChangeCallback,
97
+ panelId,
98
+ resetAllFilter: resetAllFilterCallback,
99
+ };
100
+ registerPanelItem( item );
101
+
102
+ // Passing the registration back lets the panel ignore this cleanup if
103
+ // a replacement has already claimed the label, which happens when a
104
+ // panel switches while its items arrive through a Slot.
70
105
  return () => {
71
- if (
72
- ( previousPanelId === null && !! currentPanelId ) ||
73
- currentPanelId === panelId
74
- ) {
75
- deregisterPanelItem( label );
76
- }
106
+ deregisterPanelItem( label, item );
77
107
  };
78
108
  }, [
79
- currentPanelId,
109
+ deregisterPanelItem,
80
110
  hasMatchingPanel,
111
+ hasValueCallback,
81
112
  isShownByDefault,
82
113
  label,
83
- hasValueCallback,
114
+ onShownChangeCallback,
84
115
  panelId,
85
- previousPanelId,
86
116
  registerPanelItem,
87
- deregisterPanelItem,
88
- ] );
89
-
90
- useEffect( () => {
91
- if ( hasMatchingPanel ) {
92
- registerResetAllFilter( resetAllFilterCallback );
93
- }
94
- return () => {
95
- if ( hasMatchingPanel ) {
96
- deregisterResetAllFilter( resetAllFilterCallback );
97
- }
98
- };
99
- }, [
100
- registerResetAllFilter,
101
- deregisterResetAllFilter,
102
117
  resetAllFilterCallback,
103
- hasMatchingPanel,
104
118
  ] );
105
119
 
106
- // Note: `label` is used as a key when building menu item state in
107
- // `ToolsPanel`.
108
120
  const menuGroup = isShownByDefault ? 'default' : 'optional';
109
121
  const isMenuItemChecked = menuItems?.[ menuGroup ]?.[ label ];
110
- const wasMenuItemChecked = usePrevious( isMenuItemChecked );
111
- const isRegistered = menuItems?.[ menuGroup ]?.[ label ] !== undefined;
122
+ const isRegistered = isMenuItemChecked !== undefined;
123
+ // Tracks the effect below rather than the render, so renders that leave
124
+ // the checked state alone can't desync it.
125
+ const wasMenuItemCheckedRef = useRef< boolean | undefined >( undefined );
112
126
 
113
127
  const isValueSet = hasValue();
114
- // Notify the panel when an item's value has changed except for optional
115
- // items without value because the item should not cause itself to hide.
116
- useEffect( () => {
117
- if ( ! isShownByDefault && ! isValueSet ) {
128
+
129
+ // An optional item losing its value must not hide itself, so only default
130
+ // items report a value going away. Items belonging to another panel stay
131
+ // silent or they would leave an orphaned entry in this panel's menu.
132
+ //
133
+ // Shares the layout phase with registration above so it runs against an
134
+ // already registered item and batches with it.
135
+ useLayoutEffect( () => {
136
+ if ( ! hasMatchingPanel || ( ! isShownByDefault && ! isValueSet ) ) {
118
137
  return;
119
138
  }
120
139
 
121
- flagItemCustomization( isValueSet, label, menuGroup );
140
+ flagItemCustomization( isValueSet, label );
122
141
  }, [
142
+ hasMatchingPanel,
123
143
  isValueSet,
124
- menuGroup,
125
144
  label,
126
145
  flagItemCustomization,
127
146
  isShownByDefault,
128
147
  ] );
129
148
 
130
- // Determine if the panel item's corresponding menu is being toggled and
131
- // trigger appropriate callback if it is.
149
+ // Passive so consumer callbacks don't run before the browser has painted.
132
150
  useEffect( () => {
133
- // We check whether this item is currently registered as items rendered
134
- // via fills can persist through the parent panel being remounted.
151
+ const wasMenuItemChecked = wasMenuItemCheckedRef.current;
152
+ wasMenuItemCheckedRef.current = isMenuItemChecked;
153
+
154
+ // An item has no menu entry until it registers, so the first time
155
+ // through there is no previous checked state. Items that register
156
+ // already shown, because they have a value or `defaultShown` was set,
157
+ // must not look as though the user just selected them.
158
+ const wasRegistered = wasMenuItemChecked !== undefined;
159
+
160
+ // Items rendered via fills can outlive a remount of the panel they
161
+ // belong to, leaving them unregistered.
135
162
  // See: https://github.com/WordPress/gutenberg/pull/45673
136
- if ( ! isRegistered || isResetting || ! hasMatchingPanel ) {
163
+ if (
164
+ ! isRegistered ||
165
+ ! wasRegistered ||
166
+ isResetting ||
167
+ ! hasMatchingPanel
168
+ ) {
137
169
  return;
138
170
  }
139
171
 
@@ -150,17 +182,13 @@ export function useToolsPanelItem(
150
182
  isRegistered,
151
183
  isResetting,
152
184
  isValueSet,
153
- wasMenuItemChecked,
154
185
  onSelect,
155
186
  onDeselect,
156
187
  ] );
157
188
 
158
- // The item is shown if it is a default control regardless of whether it
159
- // has a value. Optional items are shown when they are checked or have
160
- // a value.
161
- const isShown = isShownByDefault
162
- ? menuItems?.[ menuGroup ]?.[ label ] !== undefined
163
- : isMenuItemChecked;
189
+ // A default control shows whether or not it has a value; an optional one
190
+ // shows once checked.
191
+ const isShown = isShownByDefault ? isRegistered : isMenuItemChecked;
164
192
 
165
193
  const shouldApplyPlaceholderStyles = shouldRenderPlaceholder && ! isShown;
166
194
  const classes = clsx(
@@ -103,6 +103,16 @@ export type ToolsPanelHeaderProps = {
103
103
  };
104
104
 
105
105
  export type ToolsPanelItem = {
106
+ /**
107
+ * For optional items only, this determines whether the item is shown on
108
+ * first render even when `hasValue()` returns `false`.
109
+ *
110
+ * An item is always shown while it has a value, so this only controls the
111
+ * initial state of items without one.
112
+ *
113
+ * @default false
114
+ */
115
+ defaultShown?: boolean;
106
116
  /**
107
117
  * This is called when building the `ToolsPanel` menu to determine the
108
118
  * item's initial checked state.
@@ -125,6 +135,27 @@ export type ToolsPanelItem = {
125
135
  * panel.
126
136
  */
127
137
  label: string;
138
+ /**
139
+ * A callback executed when the user shows or hides the item via the
140
+ * `ToolsPanel` menu, passed `true` when it was shown and `false` when it
141
+ * was hidden.
142
+ *
143
+ * Unlike `onDeselect`, this fires whether or not the item has a value, and
144
+ * only in response to an explicit menu action. Visibility changes with
145
+ * another cause do not trigger it, such as an item becoming visible
146
+ * because it received a value or because `defaultShown` was set, or
147
+ * hiding because `Reset all` ran.
148
+ *
149
+ * Items flagged with `isShownByDefault` are always visible and stay so when
150
+ * toggled off, so this is never called for them.
151
+ *
152
+ * A single menu action may also call `onSelect` or `onDeselect`, which are
153
+ * unchanged. Showing an item without a value calls this with `true` and
154
+ * `onSelect`; hiding an item that has a value calls this with `false` and
155
+ * `onDeselect`. Use this callback to track visibility and `onDeselect` to
156
+ * reset a value, rather than treating them as interchangeable.
157
+ */
158
+ onShownChange?: ( isShown: boolean ) => void;
128
159
  /**
129
160
  * Panel items will ensure they are only registering with their intended panel
130
161
  * by comparing the `panelId` props set on both the item and the panel itself,
@@ -160,6 +191,19 @@ export type ToolsPanelItemProps = ToolsPanelItem & {
160
191
  resetAllFilter?: ResetAllFilter;
161
192
  };
162
193
 
194
+ /**
195
+ * The shape of an item as it is held in `ToolsPanel` state. It extends
196
+ * `ToolsPanelItem` with the data the panel needs but that isn't part of the
197
+ * item's own API surface.
198
+ */
199
+ export type RegisteredToolsPanelItem = ToolsPanelItem & {
200
+ /**
201
+ * The item's `resetAllFilter`, collected at registration time so the panel
202
+ * doesn't need a second round of effects to gather them.
203
+ */
204
+ resetAllFilter?: ResetAllFilter;
205
+ };
206
+
163
207
  export type ToolsPanelMenuItemKey = 'default' | 'optional';
164
208
 
165
209
  export type ToolsPanelMenuItems = {
@@ -170,13 +214,21 @@ export type ToolsPanelContext = {
170
214
  panelId?: string | null;
171
215
  menuItems: ToolsPanelMenuItems;
172
216
  hasMenuItems: boolean;
173
- registerPanelItem: ( item: ToolsPanelItem ) => void;
174
- deregisterPanelItem: ( label: string ) => void;
217
+ registerPanelItem: ( item: RegisteredToolsPanelItem ) => void;
218
+ deregisterPanelItem: (
219
+ label: string,
220
+ item?: RegisteredToolsPanelItem
221
+ ) => void;
175
222
  registerResetAllFilter: ( filter: ResetAllFilter ) => void;
176
223
  deregisterResetAllFilter: ( filter: ResetAllFilter ) => void;
177
224
  flagItemCustomization: (
178
225
  value: boolean,
179
226
  label: string,
227
+ /**
228
+ * Ignored, and kept only so that existing three argument callers
229
+ * still typecheck. The group a value lands in now follows from the
230
+ * registered item's `isShownByDefault` rather than from the caller.
231
+ */
180
232
  group?: ToolsPanelMenuItemKey
181
233
  ) => void;
182
234
  isResetting: boolean;
@@ -193,10 +245,3 @@ export type ToolsPanelControlsGroupProps = {
193
245
  items: [ string, boolean ][];
194
246
  toggleItem: ( label: string ) => void;
195
247
  };
196
-
197
- export type ToolsPanelMenuItemsConfig = {
198
- panelItems: ToolsPanelItem[];
199
- shouldReset: boolean;
200
- currentMenuItems?: ToolsPanelMenuItems;
201
- menuItemOrder: string[];
202
- };
@@ -1,8 +1,10 @@
1
+ import { describe, expect, it, vi } from 'vitest';
1
2
  import { render, screen, waitFor } from '@testing-library/react';
2
3
  import { press, hover, click, sleep } from '@ariakit/test';
3
4
  import { shortcutAriaLabel } from '@wordpress/keycodes';
4
5
  import Modal from '../../modal';
5
6
  import Tooltip, { TOOLTIP_DELAY } from '..';
7
+ globalThis.wpVitest.mockMatchMedia();
6
8
 
7
9
  const props = {
8
10
  children: <button>Tooltip anchor</button>,
@@ -315,8 +317,8 @@ describe( 'Tooltip', () => {
315
317
  }, 10_000 );
316
318
 
317
319
  it( 'should not show tooltip if the mouse leaves the tooltip anchor before set delay', async () => {
318
- const onMouseEnterMock = jest.fn();
319
- const onMouseLeaveMock = jest.fn();
320
+ const onMouseEnterMock = vi.fn();
321
+ const onMouseLeaveMock = vi.fn();
320
322
  const HOVER_OUTSIDE_ANTICIPATION = 200;
321
323
 
322
324
  render(
@@ -417,7 +419,7 @@ describe( 'Tooltip', () => {
417
419
 
418
420
  describe( 'event propagation', () => {
419
421
  it( 'should close the parent dialog component when pressing the Escape key while the tooltip is visible', async () => {
420
- const onRequestClose = jest.fn();
422
+ const onRequestClose = vi.fn();
421
423
  render(
422
424
  <Modal onRequestClose={ onRequestClose }>
423
425
  <p>Modal content</p>
@@ -1,7 +1,8 @@
1
- import { forwardRef } from '@wordpress/element';
1
+ import { forwardRef, useRef } from '@wordpress/element';
2
2
  import TreeGridItem from './item';
3
3
  import type { WordPressComponentProps } from '../context';
4
4
  import type { TreeGridCellProps } from './types';
5
+ import { useValidateTreeGridStructure } from './use-validate-tree-grid-structure';
5
6
 
6
7
  function UnforwardedTreeGridCell(
7
8
  {
@@ -11,8 +12,11 @@ function UnforwardedTreeGridCell(
11
12
  }: WordPressComponentProps< TreeGridCellProps, 'td', false >,
12
13
  ref: React.ForwardedRef< any >
13
14
  ) {
15
+ const cellRef = useRef< HTMLTableCellElement >( null );
16
+ useValidateTreeGridStructure( 'TreeGridCell', cellRef );
17
+
14
18
  return (
15
- <td { ...props } role="gridcell">
19
+ <td ref={ cellRef } { ...props } role="gridcell">
16
20
  { withoutGridItem ? (
17
21
  <>
18
22
  { typeof children === 'function'
@@ -9,9 +9,13 @@ export const RovingTabIndexItem = forwardRef(
9
9
  ) {
10
10
  const localRef = useRef< any >( null );
11
11
  const ref = forwardedRef || localRef;
12
- // @ts-expect-error - We actually want to throw an error if this is undefined.
13
- const { lastFocusedElement, setLastFocusedElement } =
14
- useRovingTabIndexContext();
12
+ const context = useRovingTabIndexContext();
13
+ if ( ! context ) {
14
+ throw new Error(
15
+ 'TreeGridItem can only be rendered inside a TreeGrid component.'
16
+ );
17
+ }
18
+ const { lastFocusedElement, setLastFocusedElement } = context;
15
19
  let tabIndex;
16
20
 
17
21
  if ( lastFocusedElement ) {
@@ -1,6 +1,8 @@
1
- import { forwardRef } from '@wordpress/element';
1
+ import { useMergeRefs } from '@wordpress/compose';
2
+ import { forwardRef, useRef } from '@wordpress/element';
2
3
  import type { WordPressComponentProps } from '../context';
3
4
  import type { TreeGridRowProps } from './types';
5
+ import { useValidateTreeGridStructure } from './use-validate-tree-grid-structure';
4
6
 
5
7
  function UnforwardedTreeGridRow(
6
8
  {
@@ -13,10 +15,14 @@ function UnforwardedTreeGridRow(
13
15
  }: WordPressComponentProps< TreeGridRowProps, 'tr', false >,
14
16
  ref: React.ForwardedRef< HTMLTableRowElement >
15
17
  ) {
18
+ const rowRef = useRef< HTMLTableRowElement >( null );
19
+ const refs = useMergeRefs( [ rowRef, ref ] );
20
+ useValidateTreeGridStructure( 'TreeGridRow', rowRef );
21
+
16
22
  return (
17
23
  <tr
18
24
  { ...props }
19
- ref={ ref }
25
+ ref={ refs }
20
26
  role="row"
21
27
  aria-level={ level }
22
28
  aria-posinset={ positionInSet }
@@ -1,6 +1,6 @@
1
- // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`TreeGridCell uses a child render function to render children 1`] = `
3
+ exports[`TreeGridCell > uses a child render function to render children 1`] = `
4
4
  <div>
5
5
  <div
6
6
  role="application"
@@ -0,0 +1,3 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`TreeGrid > simple rendering > renders a table, tbody and any child elements 1`] = `"<div role="application"><table role="treegrid"><tbody><tr role="row" aria-level="1" aria-posinset="1" aria-setsize="1"><td role="gridcell">Test</td></tr></tbody></table></div>"`;
@@ -0,0 +1,27 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`RovingTabIndexItem > allows another component to be specified as the rendered component using the \`as\` prop 1`] = `
4
+ <div>
5
+ <button />
6
+ </div>
7
+ `;
8
+
9
+ exports[`RovingTabIndexItem > allows children to be declared using a child render function as an alternative to \`as\` 1`] = `
10
+ <div>
11
+ <button
12
+ class="my-button"
13
+ >
14
+ Click Me!
15
+ </button>
16
+ </div>
17
+ `;
18
+
19
+ exports[`RovingTabIndexItem > forwards props to the \`as\` component 1`] = `
20
+ <div>
21
+ <button
22
+ class="my-button"
23
+ >
24
+ Click Me!
25
+ </button>
26
+ </div>
27
+ `;
@@ -0,0 +1,9 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`RovingTabIndex > does not render any elements other than its children 1`] = `
4
+ <div>
5
+ <div>
6
+ child element
7
+ </div>
8
+ </div>
9
+ `;
@@ -1,8 +1,10 @@
1
- // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`TreeGridRow forwards other props to the rendered tr element 1`] = `
3
+ exports[`TreeGridRow > forwards other props to the rendered tr element 1`] = `
4
4
  <div>
5
- <table>
5
+ <table
6
+ role="treegrid"
7
+ >
6
8
  <tbody>
7
9
  <tr
8
10
  aria-level="1"
@@ -20,9 +22,11 @@ exports[`TreeGridRow forwards other props to the rendered tr element 1`] = `
20
22
  </div>
21
23
  `;
22
24
 
23
- exports[`TreeGridRow renders a tr with support for level, positionInSet and setSize props 1`] = `
25
+ exports[`TreeGridRow > renders a tr with support for level, positionInSet and setSize props 1`] = `
24
26
  <div>
25
- <table>
27
+ <table
28
+ role="treegrid"
29
+ >
26
30
  <tbody>
27
31
  <tr
28
32
  aria-level="1"
@@ -0,0 +1,149 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ /* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
3
+ import { render, screen } from '@testing-library/react';
4
+ import { createPortal, forwardRef, useId } from '@wordpress/element';
5
+ import TreeGrid from '..';
6
+ import TreeGridCell from '../cell';
7
+ import TreeGridRow from '../row';
8
+
9
+ const TestButton = forwardRef(
10
+ (
11
+ { ...props }: React.ComponentPropsWithoutRef< 'button' >,
12
+ ref: React.ForwardedRef< HTMLButtonElement >
13
+ ) => <button { ...props } ref={ ref }></button>
14
+ );
15
+
16
+ describe( 'TreeGridCell', () => {
17
+ it( 'throws outside a treegrid', () => {
18
+ expect( () =>
19
+ render(
20
+ <table>
21
+ <tbody>
22
+ <tr>
23
+ <TreeGridCell withoutGridItem>Test</TreeGridCell>
24
+ </tr>
25
+ </tbody>
26
+ </table>
27
+ )
28
+ ).toThrow(
29
+ 'TreeGridCell must be rendered as a cell in a row that belongs to an element with role="treegrid".'
30
+ );
31
+ expect( console ).toHaveErrored();
32
+ } );
33
+
34
+ it( 'supports a custom semantic treegrid structure without a TreeGrid parent', () => {
35
+ render(
36
+ <table role="treegrid">
37
+ <tbody>
38
+ <tr>
39
+ <TreeGridCell withoutGridItem>Test</TreeGridCell>
40
+ </tr>
41
+ </tbody>
42
+ </table>
43
+ );
44
+
45
+ expect( screen.getByRole( 'gridcell' ) ).toHaveTextContent( 'Test' );
46
+ } );
47
+
48
+ it( 'accepts a cell explicitly owned by a valid treegrid row', () => {
49
+ const portalTable = document.createElement( 'table' );
50
+ const portalBody = document.createElement( 'tbody' );
51
+ const portalRow = document.createElement( 'tr' );
52
+ portalRow.setAttribute( 'role', 'presentation' );
53
+ portalBody.append( portalRow );
54
+ portalTable.append( portalBody );
55
+ document.body.append( portalTable );
56
+
57
+ function AriaOwnedCell() {
58
+ const cellId = useId();
59
+
60
+ return (
61
+ <TreeGrid>
62
+ <TreeGridRow
63
+ level={ 1 }
64
+ positionInSet={ 1 }
65
+ setSize={ 1 }
66
+ aria-owns={ cellId }
67
+ >
68
+ { createPortal(
69
+ <TreeGridCell id={ cellId } withoutGridItem>
70
+ Test
71
+ </TreeGridCell>,
72
+ portalRow
73
+ ) }
74
+ </TreeGridRow>
75
+ </TreeGrid>
76
+ );
77
+ }
78
+
79
+ try {
80
+ render( <AriaOwnedCell /> );
81
+
82
+ expect( screen.getByRole( 'gridcell' ) ).toHaveTextContent(
83
+ 'Test'
84
+ );
85
+ } finally {
86
+ portalTable.remove();
87
+ }
88
+ } );
89
+
90
+ it( 'accepts a cell inside a wrapper explicitly owned by a valid treegrid row', () => {
91
+ const portalTable = document.createElement( 'table' );
92
+ const portalBody = document.createElement( 'tbody' );
93
+ portalTable.append( portalBody );
94
+ document.body.append( portalTable );
95
+
96
+ function AriaOwnedCellWrapper() {
97
+ const wrapperId = useId();
98
+
99
+ return (
100
+ <TreeGrid>
101
+ <TreeGridRow
102
+ level={ 1 }
103
+ positionInSet={ 1 }
104
+ setSize={ 1 }
105
+ aria-owns={ wrapperId }
106
+ >
107
+ { createPortal(
108
+ <tr id={ wrapperId } role="presentation">
109
+ <TreeGridCell withoutGridItem>
110
+ Test
111
+ </TreeGridCell>
112
+ </tr>,
113
+ portalBody
114
+ ) }
115
+ </TreeGridRow>
116
+ </TreeGrid>
117
+ );
118
+ }
119
+
120
+ try {
121
+ render( <AriaOwnedCellWrapper /> );
122
+
123
+ expect( screen.getByRole( 'gridcell' ) ).toHaveTextContent(
124
+ 'Test'
125
+ );
126
+ } finally {
127
+ portalTable.remove();
128
+ }
129
+ } );
130
+
131
+ it( 'uses a child render function to render children', () => {
132
+ const { container } = render(
133
+ <TreeGrid>
134
+ <tr>
135
+ <TreeGridCell>
136
+ { ( props ) => (
137
+ <TestButton className="my-button" { ...props }>
138
+ Click Me!
139
+ </TestButton>
140
+ ) }
141
+ </TreeGridCell>
142
+ </tr>
143
+ </TreeGrid>
144
+ );
145
+
146
+ expect( container ).toMatchSnapshot();
147
+ } );
148
+ } );
149
+ /* eslint-enable jsx-a11y/no-noninteractive-element-to-interactive-role */