@wordpress/ui 0.9.1-next.v.202603161435.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/CONTRIBUTING.md +31 -0
  3. package/build/alert-dialog/context.cjs +34 -0
  4. package/build/alert-dialog/context.cjs.map +7 -0
  5. package/build/alert-dialog/index.cjs +37 -0
  6. package/build/alert-dialog/index.cjs.map +7 -0
  7. package/build/alert-dialog/popup.cjs +93 -0
  8. package/build/alert-dialog/popup.cjs.map +7 -0
  9. package/build/alert-dialog/root.cjs +52 -0
  10. package/build/alert-dialog/root.cjs.map +7 -0
  11. package/build/alert-dialog/trigger.cjs +48 -0
  12. package/build/alert-dialog/trigger.cjs.map +7 -0
  13. package/build/alert-dialog/types.cjs +19 -0
  14. package/build/alert-dialog/types.cjs.map +7 -0
  15. package/build/badge/badge.cjs +2 -2
  16. package/build/badge/badge.cjs.map +1 -1
  17. package/build/button/button.cjs +7 -7
  18. package/build/button/button.cjs.map +2 -2
  19. package/build/card/content.cjs +3 -3
  20. package/build/card/content.cjs.map +2 -2
  21. package/build/card/full-bleed.cjs +3 -3
  22. package/build/card/full-bleed.cjs.map +2 -2
  23. package/build/card/header.cjs +3 -3
  24. package/build/card/header.cjs.map +2 -2
  25. package/build/card/root.cjs +5 -5
  26. package/build/card/root.cjs.map +2 -2
  27. package/build/card/title.cjs +26 -13
  28. package/build/card/title.cjs.map +3 -3
  29. package/build/collapsible-card/content.cjs +24 -3
  30. package/build/collapsible-card/content.cjs.map +4 -4
  31. package/build/collapsible-card/context.cjs +35 -0
  32. package/build/collapsible-card/context.cjs.map +7 -0
  33. package/build/collapsible-card/header-description.cjs +52 -0
  34. package/build/collapsible-card/header-description.cjs.map +7 -0
  35. package/build/collapsible-card/header.cjs +38 -17
  36. package/build/collapsible-card/header.cjs.map +2 -2
  37. package/build/collapsible-card/index.cjs +3 -0
  38. package/build/collapsible-card/index.cjs.map +2 -2
  39. package/build/collapsible-card/types.cjs.map +1 -1
  40. package/build/dialog/action.cjs +4 -2
  41. package/build/dialog/action.cjs.map +2 -2
  42. package/build/dialog/close-icon.cjs +2 -1
  43. package/build/dialog/close-icon.cjs.map +2 -2
  44. package/build/dialog/footer.cjs +3 -3
  45. package/build/dialog/footer.cjs.map +2 -2
  46. package/build/dialog/header.cjs +3 -3
  47. package/build/dialog/header.cjs.map +2 -2
  48. package/build/dialog/popup.cjs +22 -5
  49. package/build/dialog/popup.cjs.map +2 -2
  50. package/build/dialog/title.cjs +3 -3
  51. package/build/dialog/title.cjs.map +2 -2
  52. package/build/dialog/types.cjs.map +1 -1
  53. package/build/empty-state/actions.cjs +66 -0
  54. package/build/empty-state/actions.cjs.map +7 -0
  55. package/build/empty-state/description.cjs +66 -0
  56. package/build/empty-state/description.cjs.map +7 -0
  57. package/build/empty-state/icon.cjs +69 -0
  58. package/build/empty-state/icon.cjs.map +7 -0
  59. package/build/empty-state/index.cjs +46 -0
  60. package/build/empty-state/index.cjs.map +7 -0
  61. package/build/empty-state/root.cjs +66 -0
  62. package/build/empty-state/root.cjs.map +7 -0
  63. package/build/empty-state/title.cjs +68 -0
  64. package/build/empty-state/title.cjs.map +7 -0
  65. package/build/empty-state/types.cjs +19 -0
  66. package/build/empty-state/types.cjs.map +7 -0
  67. package/build/empty-state/visual.cjs +66 -0
  68. package/build/empty-state/visual.cjs.map +7 -0
  69. package/build/form/index.cjs +27 -0
  70. package/build/form/index.cjs.map +7 -0
  71. package/build/form/input-control/index.cjs +31 -0
  72. package/build/form/input-control/index.cjs.map +7 -0
  73. package/build/form/input-control/input-control.cjs +50 -0
  74. package/build/form/input-control/input-control.cjs.map +7 -0
  75. package/build/form/input-control/types.cjs +19 -0
  76. package/build/form/input-control/types.cjs.map +7 -0
  77. package/build/form/primitives/field/description.cjs +2 -2
  78. package/build/form/primitives/field/description.cjs.map +1 -1
  79. package/build/form/primitives/field/details.cjs +2 -2
  80. package/build/form/primitives/field/details.cjs.map +1 -1
  81. package/build/form/primitives/field/label.cjs +2 -2
  82. package/build/form/primitives/field/label.cjs.map +1 -1
  83. package/build/form/primitives/field/root.cjs +4 -4
  84. package/build/form/primitives/field/root.cjs.map +2 -2
  85. package/build/form/primitives/fieldset/description.cjs +2 -2
  86. package/build/form/primitives/fieldset/description.cjs.map +1 -1
  87. package/build/form/primitives/fieldset/details.cjs +2 -2
  88. package/build/form/primitives/fieldset/details.cjs.map +1 -1
  89. package/build/form/primitives/fieldset/legend.cjs +2 -2
  90. package/build/form/primitives/fieldset/legend.cjs.map +1 -1
  91. package/build/form/primitives/fieldset/root.cjs +2 -2
  92. package/build/form/primitives/fieldset/root.cjs.map +1 -1
  93. package/build/form/primitives/input/input.cjs +4 -4
  94. package/build/form/primitives/input/input.cjs.map +1 -1
  95. package/build/form/primitives/input-layout/input-layout.cjs +4 -4
  96. package/build/form/primitives/input-layout/input-layout.cjs.map +1 -1
  97. package/build/form/primitives/input-layout/slot.cjs +5 -4
  98. package/build/form/primitives/input-layout/slot.cjs.map +2 -2
  99. package/build/form/primitives/select/item.cjs +5 -5
  100. package/build/form/primitives/select/item.cjs.map +2 -2
  101. package/build/form/primitives/select/popup.cjs +7 -7
  102. package/build/form/primitives/select/popup.cjs.map +2 -2
  103. package/build/form/primitives/select/trigger.cjs +5 -5
  104. package/build/form/primitives/select/trigger.cjs.map +2 -2
  105. package/build/form/primitives/textarea/textarea.cjs +3 -3
  106. package/build/form/primitives/textarea/textarea.cjs.map +2 -2
  107. package/build/form/types.cjs +19 -0
  108. package/build/form/types.cjs.map +7 -0
  109. package/build/icon-button/icon-button.cjs +2 -2
  110. package/build/icon-button/icon-button.cjs.map +1 -1
  111. package/build/index.cjs +8 -2
  112. package/build/index.cjs.map +2 -2
  113. package/build/link/link.cjs +6 -6
  114. package/build/link/link.cjs.map +1 -1
  115. package/build/notice/action-button.cjs +2 -2
  116. package/build/notice/action-button.cjs.map +1 -1
  117. package/build/notice/action-link.cjs +2 -2
  118. package/build/notice/action-link.cjs.map +1 -1
  119. package/build/notice/actions.cjs +2 -2
  120. package/build/notice/actions.cjs.map +1 -1
  121. package/build/notice/close-icon.cjs +2 -2
  122. package/build/notice/close-icon.cjs.map +1 -1
  123. package/build/notice/description.cjs +2 -2
  124. package/build/notice/description.cjs.map +1 -1
  125. package/build/notice/index.cjs.map +1 -1
  126. package/build/notice/root.cjs +4 -4
  127. package/build/notice/root.cjs.map +1 -1
  128. package/build/notice/title.cjs +2 -2
  129. package/build/notice/title.cjs.map +1 -1
  130. package/build/stack/stack.cjs +2 -2
  131. package/build/stack/stack.cjs.map +1 -1
  132. package/build/tabs/context.cjs +121 -0
  133. package/build/tabs/context.cjs.map +7 -0
  134. package/build/tabs/list.cjs +3 -3
  135. package/build/tabs/list.cjs.map +2 -2
  136. package/build/tabs/panel.cjs +5 -3
  137. package/build/tabs/panel.cjs.map +2 -2
  138. package/build/tabs/root.cjs +2 -1
  139. package/build/tabs/root.cjs.map +2 -2
  140. package/build/tabs/tab.cjs +5 -3
  141. package/build/tabs/tab.cjs.map +2 -2
  142. package/build/text/text.cjs +2 -2
  143. package/build/text/text.cjs.map +1 -1
  144. package/build/tooltip/popup.cjs +4 -4
  145. package/build/tooltip/popup.cjs.map +1 -1
  146. package/build/tooltip/root.cjs.map +2 -2
  147. package/build/utils/use-deprioritized-initial-focus.cjs +64 -0
  148. package/build/utils/use-deprioritized-initial-focus.cjs.map +7 -0
  149. package/build/visually-hidden/visually-hidden.cjs +2 -2
  150. package/build/visually-hidden/visually-hidden.cjs.map +1 -1
  151. package/build-module/alert-dialog/context.mjs +9 -0
  152. package/build-module/alert-dialog/context.mjs.map +7 -0
  153. package/build-module/alert-dialog/index.mjs +10 -0
  154. package/build-module/alert-dialog/index.mjs.map +7 -0
  155. package/build-module/alert-dialog/popup.mjs +58 -0
  156. package/build-module/alert-dialog/popup.mjs.map +7 -0
  157. package/build-module/alert-dialog/root.mjs +27 -0
  158. package/build-module/alert-dialog/root.mjs.map +7 -0
  159. package/build-module/alert-dialog/trigger.mjs +13 -0
  160. package/build-module/alert-dialog/trigger.mjs.map +7 -0
  161. package/build-module/alert-dialog/types.mjs +1 -0
  162. package/build-module/alert-dialog/types.mjs.map +7 -0
  163. package/build-module/badge/badge.mjs +2 -2
  164. package/build-module/badge/badge.mjs.map +1 -1
  165. package/build-module/button/button.mjs +7 -7
  166. package/build-module/button/button.mjs.map +2 -2
  167. package/build-module/card/content.mjs +3 -3
  168. package/build-module/card/content.mjs.map +2 -2
  169. package/build-module/card/full-bleed.mjs +3 -3
  170. package/build-module/card/full-bleed.mjs.map +2 -2
  171. package/build-module/card/header.mjs +3 -3
  172. package/build-module/card/header.mjs.map +2 -2
  173. package/build-module/card/root.mjs +5 -5
  174. package/build-module/card/root.mjs.map +2 -2
  175. package/build-module/card/title.mjs +16 -13
  176. package/build-module/card/title.mjs.map +2 -2
  177. package/build-module/collapsible-card/content.mjs +24 -3
  178. package/build-module/collapsible-card/content.mjs.map +3 -3
  179. package/build-module/collapsible-card/context.mjs +10 -0
  180. package/build-module/collapsible-card/context.mjs.map +7 -0
  181. package/build-module/collapsible-card/header-description.mjs +27 -0
  182. package/build-module/collapsible-card/header-description.mjs.map +7 -0
  183. package/build-module/collapsible-card/header.mjs +39 -18
  184. package/build-module/collapsible-card/header.mjs.map +2 -2
  185. package/build-module/collapsible-card/index.mjs +2 -0
  186. package/build-module/collapsible-card/index.mjs.map +2 -2
  187. package/build-module/dialog/action.mjs +4 -2
  188. package/build-module/dialog/action.mjs.map +2 -2
  189. package/build-module/dialog/close-icon.mjs +2 -1
  190. package/build-module/dialog/close-icon.mjs.map +2 -2
  191. package/build-module/dialog/footer.mjs +3 -3
  192. package/build-module/dialog/footer.mjs.map +2 -2
  193. package/build-module/dialog/header.mjs +3 -3
  194. package/build-module/dialog/header.mjs.map +2 -2
  195. package/build-module/dialog/popup.mjs +22 -5
  196. package/build-module/dialog/popup.mjs.map +2 -2
  197. package/build-module/dialog/title.mjs +3 -3
  198. package/build-module/dialog/title.mjs.map +2 -2
  199. package/build-module/empty-state/actions.mjs +31 -0
  200. package/build-module/empty-state/actions.mjs.map +7 -0
  201. package/build-module/empty-state/description.mjs +31 -0
  202. package/build-module/empty-state/description.mjs.map +7 -0
  203. package/build-module/empty-state/icon.mjs +34 -0
  204. package/build-module/empty-state/icon.mjs.map +7 -0
  205. package/build-module/empty-state/index.mjs +16 -0
  206. package/build-module/empty-state/index.mjs.map +7 -0
  207. package/build-module/empty-state/root.mjs +31 -0
  208. package/build-module/empty-state/root.mjs.map +7 -0
  209. package/build-module/empty-state/title.mjs +33 -0
  210. package/build-module/empty-state/title.mjs.map +7 -0
  211. package/build-module/empty-state/types.mjs +1 -0
  212. package/build-module/empty-state/types.mjs.map +7 -0
  213. package/build-module/empty-state/visual.mjs +31 -0
  214. package/build-module/empty-state/visual.mjs.map +7 -0
  215. package/build-module/form/index.mjs +4 -0
  216. package/build-module/form/index.mjs.map +7 -0
  217. package/build-module/form/input-control/index.mjs +6 -0
  218. package/build-module/form/input-control/index.mjs.map +7 -0
  219. package/build-module/form/input-control/input-control.mjs +25 -0
  220. package/build-module/form/input-control/input-control.mjs.map +7 -0
  221. package/build-module/form/input-control/types.mjs +1 -0
  222. package/build-module/form/input-control/types.mjs.map +7 -0
  223. package/build-module/form/primitives/field/description.mjs +2 -2
  224. package/build-module/form/primitives/field/description.mjs.map +1 -1
  225. package/build-module/form/primitives/field/details.mjs +2 -2
  226. package/build-module/form/primitives/field/details.mjs.map +1 -1
  227. package/build-module/form/primitives/field/label.mjs +2 -2
  228. package/build-module/form/primitives/field/label.mjs.map +1 -1
  229. package/build-module/form/primitives/field/root.mjs +4 -4
  230. package/build-module/form/primitives/field/root.mjs.map +2 -2
  231. package/build-module/form/primitives/fieldset/description.mjs +2 -2
  232. package/build-module/form/primitives/fieldset/description.mjs.map +1 -1
  233. package/build-module/form/primitives/fieldset/details.mjs +2 -2
  234. package/build-module/form/primitives/fieldset/details.mjs.map +1 -1
  235. package/build-module/form/primitives/fieldset/legend.mjs +2 -2
  236. package/build-module/form/primitives/fieldset/legend.mjs.map +1 -1
  237. package/build-module/form/primitives/fieldset/root.mjs +2 -2
  238. package/build-module/form/primitives/fieldset/root.mjs.map +1 -1
  239. package/build-module/form/primitives/input/input.mjs +4 -4
  240. package/build-module/form/primitives/input/input.mjs.map +1 -1
  241. package/build-module/form/primitives/input-layout/input-layout.mjs +4 -4
  242. package/build-module/form/primitives/input-layout/input-layout.mjs.map +1 -1
  243. package/build-module/form/primitives/input-layout/slot.mjs +5 -4
  244. package/build-module/form/primitives/input-layout/slot.mjs.map +2 -2
  245. package/build-module/form/primitives/select/item.mjs +5 -5
  246. package/build-module/form/primitives/select/item.mjs.map +2 -2
  247. package/build-module/form/primitives/select/popup.mjs +7 -7
  248. package/build-module/form/primitives/select/popup.mjs.map +2 -2
  249. package/build-module/form/primitives/select/trigger.mjs +5 -5
  250. package/build-module/form/primitives/select/trigger.mjs.map +2 -2
  251. package/build-module/form/primitives/textarea/textarea.mjs +3 -3
  252. package/build-module/form/primitives/textarea/textarea.mjs.map +2 -2
  253. package/build-module/form/types.mjs +1 -0
  254. package/build-module/form/types.mjs.map +7 -0
  255. package/build-module/icon-button/icon-button.mjs +2 -2
  256. package/build-module/icon-button/icon-button.mjs.map +1 -1
  257. package/build-module/index.mjs +5 -1
  258. package/build-module/index.mjs.map +2 -2
  259. package/build-module/link/link.mjs +6 -6
  260. package/build-module/link/link.mjs.map +1 -1
  261. package/build-module/notice/action-button.mjs +2 -2
  262. package/build-module/notice/action-button.mjs.map +1 -1
  263. package/build-module/notice/action-link.mjs +2 -2
  264. package/build-module/notice/action-link.mjs.map +1 -1
  265. package/build-module/notice/actions.mjs +2 -2
  266. package/build-module/notice/actions.mjs.map +1 -1
  267. package/build-module/notice/close-icon.mjs +2 -2
  268. package/build-module/notice/close-icon.mjs.map +1 -1
  269. package/build-module/notice/description.mjs +2 -2
  270. package/build-module/notice/description.mjs.map +1 -1
  271. package/build-module/notice/index.mjs.map +1 -1
  272. package/build-module/notice/root.mjs +4 -4
  273. package/build-module/notice/root.mjs.map +1 -1
  274. package/build-module/notice/title.mjs +2 -2
  275. package/build-module/notice/title.mjs.map +1 -1
  276. package/build-module/stack/stack.mjs +2 -2
  277. package/build-module/stack/stack.mjs.map +1 -1
  278. package/build-module/tabs/context.mjs +101 -0
  279. package/build-module/tabs/context.mjs.map +7 -0
  280. package/build-module/tabs/list.mjs +3 -3
  281. package/build-module/tabs/list.mjs.map +2 -2
  282. package/build-module/tabs/panel.mjs +5 -3
  283. package/build-module/tabs/panel.mjs.map +2 -2
  284. package/build-module/tabs/root.mjs +2 -1
  285. package/build-module/tabs/root.mjs.map +2 -2
  286. package/build-module/tabs/tab.mjs +5 -3
  287. package/build-module/tabs/tab.mjs.map +2 -2
  288. package/build-module/text/text.mjs +2 -2
  289. package/build-module/text/text.mjs.map +1 -1
  290. package/build-module/tooltip/popup.mjs +4 -4
  291. package/build-module/tooltip/popup.mjs.map +1 -1
  292. package/build-module/tooltip/root.mjs.map +2 -2
  293. package/build-module/utils/use-deprioritized-initial-focus.mjs +39 -0
  294. package/build-module/utils/use-deprioritized-initial-focus.mjs.map +7 -0
  295. package/build-module/visually-hidden/visually-hidden.mjs +2 -2
  296. package/build-module/visually-hidden/visually-hidden.mjs.map +1 -1
  297. package/build-types/alert-dialog/context.d.ts +8 -0
  298. package/build-types/alert-dialog/context.d.ts.map +1 -0
  299. package/build-types/alert-dialog/index.d.ts +4 -0
  300. package/build-types/alert-dialog/index.d.ts.map +1 -0
  301. package/build-types/alert-dialog/popup.d.ts +4 -0
  302. package/build-types/alert-dialog/popup.d.ts.map +1 -0
  303. package/build-types/alert-dialog/root.d.ts +24 -0
  304. package/build-types/alert-dialog/root.d.ts.map +1 -0
  305. package/build-types/alert-dialog/stories/index.story.d.ts +44 -0
  306. package/build-types/alert-dialog/stories/index.story.d.ts.map +1 -0
  307. package/build-types/alert-dialog/test/index.test.d.ts +2 -0
  308. package/build-types/alert-dialog/test/index.test.d.ts.map +1 -0
  309. package/build-types/alert-dialog/trigger.d.ts +6 -0
  310. package/build-types/alert-dialog/trigger.d.ts.map +1 -0
  311. package/build-types/alert-dialog/types.d.ts +70 -0
  312. package/build-types/alert-dialog/types.d.ts.map +1 -0
  313. package/build-types/card/title.d.ts.map +1 -1
  314. package/build-types/collapsible-card/content.d.ts.map +1 -1
  315. package/build-types/collapsible-card/context.d.ts +4 -0
  316. package/build-types/collapsible-card/context.d.ts.map +1 -0
  317. package/build-types/collapsible-card/header-description.d.ts +15 -0
  318. package/build-types/collapsible-card/header-description.d.ts.map +1 -0
  319. package/build-types/collapsible-card/header.d.ts.map +1 -1
  320. package/build-types/collapsible-card/index.d.ts +2 -1
  321. package/build-types/collapsible-card/index.d.ts.map +1 -1
  322. package/build-types/collapsible-card/stories/index.story.d.ts +10 -0
  323. package/build-types/collapsible-card/stories/index.story.d.ts.map +1 -1
  324. package/build-types/collapsible-card/types.d.ts +21 -0
  325. package/build-types/collapsible-card/types.d.ts.map +1 -1
  326. package/build-types/dialog/action.d.ts.map +1 -1
  327. package/build-types/dialog/close-icon.d.ts.map +1 -1
  328. package/build-types/dialog/popup.d.ts.map +1 -1
  329. package/build-types/dialog/stories/index.story.d.ts +0 -6
  330. package/build-types/dialog/stories/index.story.d.ts.map +1 -1
  331. package/build-types/dialog/types.d.ts +5 -5
  332. package/build-types/dialog/types.d.ts.map +1 -1
  333. package/build-types/empty-state/actions.d.ts +7 -0
  334. package/build-types/empty-state/actions.d.ts.map +1 -0
  335. package/build-types/empty-state/description.d.ts +7 -0
  336. package/build-types/empty-state/description.d.ts.map +1 -0
  337. package/build-types/empty-state/icon.d.ts +7 -0
  338. package/build-types/empty-state/icon.d.ts.map +1 -0
  339. package/build-types/empty-state/index.d.ts +8 -0
  340. package/build-types/empty-state/index.d.ts.map +1 -0
  341. package/build-types/empty-state/root.d.ts +6 -0
  342. package/build-types/empty-state/root.d.ts.map +1 -0
  343. package/build-types/empty-state/stories/index.story.d.ts +8 -0
  344. package/build-types/empty-state/stories/index.story.d.ts.map +1 -0
  345. package/build-types/empty-state/test/actions.test.d.ts +2 -0
  346. package/build-types/empty-state/test/actions.test.d.ts.map +1 -0
  347. package/build-types/empty-state/test/description.test.d.ts +2 -0
  348. package/build-types/empty-state/test/description.test.d.ts.map +1 -0
  349. package/build-types/empty-state/test/icon.test.d.ts +2 -0
  350. package/build-types/empty-state/test/icon.test.d.ts.map +1 -0
  351. package/build-types/empty-state/test/root.test.d.ts +2 -0
  352. package/build-types/empty-state/test/root.test.d.ts.map +1 -0
  353. package/build-types/empty-state/test/title.test.d.ts +2 -0
  354. package/build-types/empty-state/test/title.test.d.ts.map +1 -0
  355. package/build-types/empty-state/test/visual.test.d.ts +2 -0
  356. package/build-types/empty-state/test/visual.test.d.ts.map +1 -0
  357. package/build-types/empty-state/title.d.ts +6 -0
  358. package/build-types/empty-state/title.d.ts.map +1 -0
  359. package/build-types/empty-state/types.d.ts +40 -0
  360. package/build-types/empty-state/types.d.ts.map +1 -0
  361. package/build-types/empty-state/visual.d.ts +7 -0
  362. package/build-types/empty-state/visual.d.ts.map +1 -0
  363. package/build-types/form/index.d.ts +3 -0
  364. package/build-types/form/index.d.ts.map +1 -0
  365. package/build-types/form/input-control/index.d.ts +2 -0
  366. package/build-types/form/input-control/index.d.ts.map +1 -0
  367. package/build-types/form/input-control/input-control.d.ts +6 -0
  368. package/build-types/form/input-control/input-control.d.ts.map +1 -0
  369. package/build-types/form/input-control/stories/index.story.d.ts +16 -0
  370. package/build-types/form/input-control/stories/index.story.d.ts.map +1 -0
  371. package/build-types/form/input-control/test/index.test.d.ts +2 -0
  372. package/build-types/form/input-control/test/index.test.d.ts.map +1 -0
  373. package/build-types/form/input-control/types.d.ts +4 -0
  374. package/build-types/form/input-control/types.d.ts.map +1 -0
  375. package/build-types/form/primitives/field/stories/index.story.d.ts.map +1 -1
  376. package/build-types/form/primitives/fieldset/stories/index.story.d.ts.map +1 -1
  377. package/build-types/form/primitives/input/stories/index.story.d.ts +2 -0
  378. package/build-types/form/primitives/input/stories/index.story.d.ts.map +1 -1
  379. package/build-types/form/primitives/input-layout/slot.d.ts.map +1 -1
  380. package/build-types/form/primitives/input-layout/stories/index.story.d.ts +5 -0
  381. package/build-types/form/primitives/input-layout/stories/index.story.d.ts.map +1 -1
  382. package/build-types/form/stories/shared.d.ts +3 -0
  383. package/build-types/form/stories/shared.d.ts.map +1 -0
  384. package/build-types/form/types.d.ts +30 -0
  385. package/build-types/form/types.d.ts.map +1 -0
  386. package/build-types/index.d.ts +3 -1
  387. package/build-types/index.d.ts.map +1 -1
  388. package/build-types/notice/index.d.ts +0 -1
  389. package/build-types/notice/index.d.ts.map +1 -1
  390. package/build-types/tabs/context.d.ts +26 -0
  391. package/build-types/tabs/context.d.ts.map +1 -0
  392. package/build-types/tabs/panel.d.ts.map +1 -1
  393. package/build-types/tabs/root.d.ts.map +1 -1
  394. package/build-types/tabs/tab.d.ts.map +1 -1
  395. package/build-types/tooltip/root.d.ts +12 -0
  396. package/build-types/tooltip/root.d.ts.map +1 -1
  397. package/build-types/tooltip/stories/index.story.d.ts.map +1 -1
  398. package/build-types/utils/test/use-deprioritized-initial-focus.test.d.ts +2 -0
  399. package/build-types/utils/test/use-deprioritized-initial-focus.test.d.ts.map +1 -0
  400. package/build-types/utils/use-deprioritized-initial-focus.d.ts +35 -0
  401. package/build-types/utils/use-deprioritized-initial-focus.d.ts.map +1 -0
  402. package/package.json +17 -16
  403. package/src/alert-dialog/context.tsx +14 -0
  404. package/src/alert-dialog/index.ts +3 -0
  405. package/src/alert-dialog/popup.tsx +58 -0
  406. package/src/alert-dialog/root.tsx +48 -0
  407. package/src/alert-dialog/stories/index.story.tsx +254 -0
  408. package/src/alert-dialog/style.module.css +10 -0
  409. package/src/alert-dialog/test/index.test.tsx +537 -0
  410. package/src/alert-dialog/trigger.tsx +15 -0
  411. package/src/alert-dialog/types.ts +83 -0
  412. package/src/button/style.module.css +2 -0
  413. package/src/card/stories/index.story.tsx +1 -1
  414. package/src/card/style.module.css +3 -5
  415. package/src/card/title.tsx +12 -11
  416. package/src/collapsible-card/content.tsx +16 -3
  417. package/src/collapsible-card/context.ts +7 -0
  418. package/src/collapsible-card/header-description.tsx +43 -0
  419. package/src/collapsible-card/header.tsx +47 -24
  420. package/src/collapsible-card/index.ts +2 -1
  421. package/src/collapsible-card/stories/index.story.tsx +99 -1
  422. package/src/collapsible-card/style.module.css +34 -2
  423. package/src/collapsible-card/test/index.test.tsx +96 -9
  424. package/src/collapsible-card/types.ts +22 -0
  425. package/src/dialog/action.tsx +8 -2
  426. package/src/dialog/close-icon.tsx +1 -0
  427. package/src/dialog/popup.tsx +21 -2
  428. package/src/dialog/stories/index.story.tsx +0 -28
  429. package/src/dialog/style.module.css +5 -5
  430. package/src/dialog/test/index.test.tsx +117 -0
  431. package/src/dialog/types.ts +11 -5
  432. package/src/empty-state/actions.tsx +24 -0
  433. package/src/empty-state/description.tsx +27 -0
  434. package/src/empty-state/icon.tsx +24 -0
  435. package/src/empty-state/index.ts +8 -0
  436. package/src/empty-state/root.tsx +23 -0
  437. package/src/empty-state/stories/index.story.tsx +64 -0
  438. package/src/empty-state/style.module.css +53 -0
  439. package/src/empty-state/test/actions.test.tsx +18 -0
  440. package/src/empty-state/test/description.test.tsx +13 -0
  441. package/src/empty-state/test/icon.test.tsx +13 -0
  442. package/src/empty-state/test/root.test.tsx +13 -0
  443. package/src/empty-state/test/title.test.tsx +13 -0
  444. package/src/empty-state/test/visual.test.tsx +17 -0
  445. package/src/empty-state/title.tsx +23 -0
  446. package/src/empty-state/types.ts +45 -0
  447. package/src/empty-state/visual.tsx +24 -0
  448. package/src/form/index.ts +3 -0
  449. package/src/form/input-control/index.ts +1 -0
  450. package/src/form/input-control/input-control.tsx +33 -0
  451. package/src/form/input-control/stories/index.story.tsx +163 -0
  452. package/src/form/input-control/test/index.test.tsx +53 -0
  453. package/src/form/input-control/types.ts +5 -0
  454. package/src/form/primitives/field/root.tsx +2 -2
  455. package/src/form/primitives/field/stories/index.story.tsx +2 -7
  456. package/src/form/primitives/fieldset/stories/index.story.tsx +2 -7
  457. package/src/form/primitives/input/stories/index.story.tsx +7 -0
  458. package/src/form/primitives/input-layout/slot.tsx +6 -2
  459. package/src/form/primitives/input-layout/stories/index.story.tsx +22 -1
  460. package/src/form/primitives/stories/overview.mdx +15 -0
  461. package/src/form/primitives/textarea/textarea.tsx +1 -1
  462. package/src/form/stories/shared.tsx +19 -0
  463. package/src/form/types.ts +34 -0
  464. package/src/index.ts +3 -1
  465. package/src/notice/index.ts +0 -2
  466. package/src/notice/style.module.css +1 -1
  467. package/src/tabs/context.tsx +170 -0
  468. package/src/tabs/panel.tsx +3 -0
  469. package/src/tabs/root.tsx +6 -1
  470. package/src/tabs/style.module.css +1 -1
  471. package/src/tabs/tab.tsx +3 -0
  472. package/src/tabs/test/index.test.tsx +162 -0
  473. package/src/tooltip/root.tsx +12 -0
  474. package/src/tooltip/stories/index.story.tsx +20 -15
  475. package/src/utils/css/item-popup.module.css +1 -0
  476. package/src/utils/css/select-trigger.module.css +1 -0
  477. package/src/utils/test/use-deprioritized-initial-focus.test.tsx +230 -0
  478. package/src/utils/use-deprioritized-initial-focus.ts +83 -0
@@ -1,5 +1,6 @@
1
- import { mergeProps, useRender } from '@base-ui/react';
2
1
  import { forwardRef } from '@wordpress/element';
2
+ import clsx from 'clsx';
3
+ import { Text } from '../text';
3
4
  import styles from './style.module.css';
4
5
  import type { TitleProps } from './types';
5
6
 
@@ -8,15 +9,15 @@ import type { TitleProps } from './types';
8
9
  * prop to swap in a semantic heading element when appropriate.
9
10
  */
10
11
  export const Title = forwardRef< HTMLDivElement, TitleProps >(
11
- function CardTitle( { render, ...props }, ref ) {
12
- const element = useRender( {
13
- defaultTagName: 'div',
14
- render,
15
- ref,
16
- // TODO: use `Text` component instead, when ready
17
- props: mergeProps< 'div' >( { className: styles.title }, props ),
18
- } );
19
-
20
- return element;
12
+ function CardTitle( { className, render, children, ...props }, ref ) {
13
+ return (
14
+ <Text
15
+ variant="heading-lg"
16
+ render={ render ?? <div ref={ ref } { ...props } /> }
17
+ className={ clsx( styles.title, className ) }
18
+ >
19
+ { children }
20
+ </Text>
21
+ );
21
22
  }
22
23
  );
@@ -1,6 +1,8 @@
1
1
  import { forwardRef } from '@wordpress/element';
2
+ import clsx from 'clsx';
2
3
  import * as Card from '../card';
3
4
  import * as Collapsible from '../collapsible';
5
+ import styles from './style.module.css';
4
6
  import type { ContentProps } from './types';
5
7
 
6
8
  /**
@@ -8,13 +10,24 @@ import type { ContentProps } from './types';
8
10
  * visible when expanded.
9
11
  */
10
12
  export const Content = forwardRef< HTMLDivElement, ContentProps >(
11
- function CollapsibleCardContent( { render, ...restProps }, ref ) {
13
+ function CollapsibleCardContent(
14
+ { className, render, children, hiddenUntilFound = true, ...restProps },
15
+ ref
16
+ ) {
12
17
  return (
13
18
  <Collapsible.Panel
14
19
  ref={ ref }
15
- render={ <Card.Content render={ render } /> }
20
+ className={ clsx( styles.content, className ) }
21
+ hiddenUntilFound={ hiddenUntilFound }
16
22
  { ...restProps }
17
- />
23
+ >
24
+ <Card.Content
25
+ className={ styles[ 'content-inner' ] }
26
+ render={ render }
27
+ >
28
+ { children }
29
+ </Card.Content>
30
+ </Collapsible.Panel>
18
31
  );
19
32
  }
20
33
  );
@@ -0,0 +1,7 @@
1
+ import { createContext } from '@wordpress/element';
2
+
3
+ export const HeaderDescriptionIdContext = createContext< {
4
+ setDescriptionId: ( id: string | undefined ) => void;
5
+ } >( {
6
+ setDescriptionId: () => {},
7
+ } );
@@ -0,0 +1,43 @@
1
+ import { forwardRef, useContext, useEffect, useId } from '@wordpress/element';
2
+ import { HeaderDescriptionIdContext } from './context';
3
+ import type { HeaderDescriptionProps } from './types';
4
+
5
+ /**
6
+ * Secondary content placed in the collapsible card header that describes
7
+ * the trigger button via `aria-describedby`. Use it for supplementary
8
+ * information such as status badges or summary values.
9
+ *
10
+ * The content is visually rendered but marked `aria-hidden` so that
11
+ * assistive technologies consume it only through the `aria-describedby`
12
+ * relationship on the trigger, avoiding double announcements.
13
+ *
14
+ * Avoid interactive elements (buttons, links, inputs) inside this
15
+ * component — the entire header is the toggle trigger.
16
+ */
17
+ export const HeaderDescription = forwardRef<
18
+ HTMLDivElement,
19
+ HeaderDescriptionProps
20
+ >( function CollapsibleCardHeaderDescription(
21
+ { children, className, ...restProps },
22
+ ref
23
+ ) {
24
+ const descriptionId = useId();
25
+ const { setDescriptionId } = useContext( HeaderDescriptionIdContext );
26
+
27
+ useEffect( () => {
28
+ setDescriptionId( descriptionId );
29
+ return () => setDescriptionId( undefined );
30
+ }, [ descriptionId, setDescriptionId ] );
31
+
32
+ return (
33
+ <div
34
+ ref={ ref }
35
+ id={ descriptionId }
36
+ aria-hidden="true"
37
+ className={ className }
38
+ { ...restProps }
39
+ >
40
+ { children }
41
+ </div>
42
+ );
43
+ } );
@@ -1,11 +1,12 @@
1
1
  import clsx from 'clsx';
2
- import { forwardRef } from '@wordpress/element';
2
+ import { forwardRef, useMemo, useState } from '@wordpress/element';
3
3
  import { chevronDown } from '@wordpress/icons';
4
4
  import * as Card from '../card';
5
5
  import * as Collapsible from '../collapsible';
6
6
  import { Icon } from '../icon';
7
7
  import styles from './style.module.css';
8
8
  import focusStyles from '../utils/css/focus.module.css';
9
+ import { HeaderDescriptionIdContext } from './context';
9
10
  import type { HeaderProps } from './types';
10
11
 
11
12
  /**
@@ -22,32 +23,54 @@ export const Header = forwardRef< HTMLDivElement, HeaderProps >(
22
23
  { children, className, render, ...restProps },
23
24
  ref
24
25
  ) {
26
+ const [ descriptionId, setDescriptionId ] = useState< string >();
27
+
28
+ const contextValue = useMemo(
29
+ () => ( { setDescriptionId } ),
30
+ [ setDescriptionId ]
31
+ );
32
+
25
33
  return (
26
- <Collapsible.Trigger
27
- className={ clsx( styles.header, className ) }
28
- render={
29
- <Card.Header
30
- ref={ ref }
31
- render={ render }
32
- { ...restProps }
33
- />
34
- }
35
- nativeButton={ false }
36
- >
37
- <div className={ styles[ 'header-content' ] }>{ children }</div>
38
- <div className={ styles[ 'header-trigger-wrapper' ] }>
39
- <Icon
40
- icon={ chevronDown }
34
+ <HeaderDescriptionIdContext.Provider value={ contextValue }>
35
+ <Collapsible.Trigger
36
+ className={ clsx( styles.header, className ) }
37
+ render={
38
+ <Card.Header
39
+ ref={ ref }
40
+ render={ render }
41
+ { ...restProps }
42
+ />
43
+ }
44
+ nativeButton={ false }
45
+ aria-describedby={ descriptionId }
46
+ >
47
+ <div className={ styles[ 'header-content' ] }>
48
+ { children }
49
+ </div>
50
+ <div
41
51
  className={ clsx(
42
- styles[ 'header-trigger' ],
43
- // While the interactive trigger element is the whole header,
44
- // the focus ring will be displayed only on the icon to visually
45
- // emulate it being the button.
46
- focusStyles[ 'outset-ring--focus-parent-visible' ]
52
+ styles[ 'header-trigger-positioner' ]
47
53
  ) }
48
- />
49
- </div>
50
- </Collapsible.Trigger>
54
+ >
55
+ <div
56
+ className={ clsx(
57
+ styles[ 'header-trigger-wrapper' ],
58
+ // While the interactive trigger element is the whole header,
59
+ // the focus ring will be displayed only on the icon to visually
60
+ // emulate it being the button.
61
+ focusStyles[
62
+ 'outset-ring--focus-parent-visible'
63
+ ]
64
+ ) }
65
+ >
66
+ <Icon
67
+ icon={ chevronDown }
68
+ className={ styles[ 'header-trigger' ] }
69
+ />
70
+ </div>
71
+ </div>
72
+ </Collapsible.Trigger>
73
+ </HeaderDescriptionIdContext.Provider>
51
74
  );
52
75
  }
53
76
  );
@@ -1,5 +1,6 @@
1
1
  import { Root } from './root';
2
2
  import { Header } from './header';
3
+ import { HeaderDescription } from './header-description';
3
4
  import { Content } from './content';
4
5
 
5
- export { Root, Header, Content };
6
+ export { Root, Header, HeaderDescription, Content };
@@ -1,6 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import * as Card from '../../card';
3
3
  import * as CollapsibleCard from '../index';
4
+ import { Stack } from '../../stack';
4
5
 
5
6
  /**
6
7
  * Temporary text component for story examples. This will be replaced by an
@@ -11,7 +12,7 @@ function Text( { children }: { children: React.ReactNode } ) {
11
12
  <p
12
13
  style={ {
13
14
  margin: 0,
14
- fontFamily: [ 'var(--wp', 'ds-font-family-body)' ].join( '' ),
15
+ fontFamily: 'var(--wpds-font-family-body)',
15
16
  fontSize: 'var(--wpds-font-size-md)',
16
17
  fontWeight: 'var(--wpds-font-weight-regular)',
17
18
  lineHeight: 'var(--wpds-font-line-height-sm)',
@@ -29,6 +30,7 @@ const meta: Meta< typeof CollapsibleCard.Root > = {
29
30
  component: CollapsibleCard.Root,
30
31
  subcomponents: {
31
32
  'CollapsibleCard.Header': CollapsibleCard.Header,
33
+ 'CollapsibleCard.HeaderDescription': CollapsibleCard.HeaderDescription,
32
34
  'CollapsibleCard.Content': CollapsibleCard.Content,
33
35
  },
34
36
  };
@@ -105,6 +107,102 @@ export const Disabled: Story = {
105
107
  },
106
108
  };
107
109
 
110
+ /**
111
+ * Multiple collapsible cards stacked vertically, simulating a typical
112
+ * settings-panel or FAQ-style layout.
113
+ */
114
+ export const Stacked: Story = {
115
+ parameters: { controls: { disable: true } },
116
+ render: () => (
117
+ <div
118
+ style={ {
119
+ display: 'flex',
120
+ flexDirection: 'column',
121
+ gap: 'var(--wpds-dimension-gap-lg)',
122
+ } }
123
+ >
124
+ { [
125
+ 'General',
126
+ 'Advanced',
127
+ 'Accessibility',
128
+ 'Performance',
129
+ 'Privacy',
130
+ 'Notifications',
131
+ ].map( ( title ) => (
132
+ <CollapsibleCard.Root key={ title }>
133
+ <CollapsibleCard.Header>
134
+ <Card.Title>{ title }</Card.Title>
135
+ </CollapsibleCard.Header>
136
+ <CollapsibleCard.Content>
137
+ <Text>
138
+ Configure all { title.toLowerCase() } settings for
139
+ your site. Changes here affect how your site behaves
140
+ across all pages and posts.
141
+ </Text>
142
+ <Text>
143
+ Review each option carefully before saving. Some
144
+ changes may require a page reload to take effect.
145
+ Hover over individual options for more details about
146
+ what they control.
147
+ </Text>
148
+ <Text>
149
+ If you&apos;re unsure about a setting, you can
150
+ always reset to defaults using the button at the
151
+ bottom of this section. Your previous configuration
152
+ will be saved as a backup.
153
+ </Text>
154
+ </CollapsibleCard.Content>
155
+ </CollapsibleCard.Root>
156
+ ) ) }
157
+ </div>
158
+ ),
159
+ };
160
+
161
+ /**
162
+ * A collapsible card with a `HeaderDescription` that provides supplementary
163
+ * information (e.g. status, summary) as an `aria-describedby` relationship.
164
+ */
165
+ export const WithHeaderDescription: Story = {
166
+ // `defaultOpen` (uncontrolled) and `open` (controlled) should not be
167
+ // used together — disable the `open` control to avoid confusion.
168
+ argTypes: { open: { control: false } },
169
+ args: {
170
+ defaultOpen: true,
171
+ },
172
+ render: ( { open, defaultOpen, onOpenChange, disabled, ...restArgs } ) => (
173
+ <CollapsibleCard.Root
174
+ open={ open }
175
+ defaultOpen={ defaultOpen }
176
+ onOpenChange={ onOpenChange }
177
+ disabled={ disabled }
178
+ { ...restArgs }
179
+ >
180
+ <CollapsibleCard.Header>
181
+ <Stack justify="space-between">
182
+ <Card.Title>Settings</Card.Title>
183
+ <CollapsibleCard.HeaderDescription>
184
+ <span
185
+ style={ {
186
+ fontSize: 'var(--wpds-font-size-sm)',
187
+ color: 'var(--wpds-color-fg-content-neutral-weak)',
188
+ } }
189
+ >
190
+ 3 items configured
191
+ </span>
192
+ </CollapsibleCard.HeaderDescription>
193
+ </Stack>
194
+ </CollapsibleCard.Header>
195
+ <CollapsibleCard.Content>
196
+ <Text>
197
+ The header description provides supplementary context to the
198
+ trigger button. Assistive technologies will announce the
199
+ description alongside the button label.
200
+ </Text>
201
+ </CollapsibleCard.Content>
202
+ </CollapsibleCard.Root>
203
+ ),
204
+ };
205
+
108
206
  /**
109
207
  * Visual comparison: a `CollapsibleCard` (open) next to a regular `Card`
110
208
  * to verify identical spacing and layout.
@@ -6,7 +6,7 @@
6
6
  min-width: 0;
7
7
  }
8
8
 
9
- .header-trigger-wrapper {
9
+ .header-trigger-positioner {
10
10
  flex-shrink: 0;
11
11
  align-self: center;
12
12
  /* Prevent the trigger from making the header taller than its content,
@@ -15,7 +15,9 @@
15
15
  overflow: visible;
16
16
  }
17
17
 
18
- .header-trigger {
18
+ .header-trigger-wrapper {
19
+ display: flex;
20
+
19
21
  /* Offset by half the button's own height so it visually centers
20
22
  at the wrapper's midpoint (which `align-self: center` places at
21
23
  the vertical center of the header). */
@@ -25,6 +27,12 @@
25
27
  border-radius: var(--wpds-border-radius-sm);
26
28
  }
27
29
 
30
+ .header-trigger {
31
+ @media not (prefers-reduced-motion) {
32
+ transition: rotate 0.15s ease-out;
33
+ }
34
+ }
35
+
28
36
  .header[data-panel-open] .header-trigger {
29
37
  rotate: 180deg;
30
38
  }
@@ -33,9 +41,33 @@
33
41
  .header[data-disabled] .header-trigger {
34
42
  color: var(--wpds-color-fg-interactive-neutral-disabled);
35
43
  }
44
+
45
+ .content {
46
+ height: var(--collapsible-panel-height);
47
+ overflow: hidden;
48
+ margin-block-start: var(--wp-ui-card-header-content-margin);
49
+
50
+ &[hidden]:not([hidden="until-found"]) {
51
+ display: none;
52
+ }
53
+
54
+ &[data-starting-style],
55
+ &[data-ending-style] {
56
+ height: 0;
57
+ }
58
+
59
+ @media not (prefers-reduced-motion) {
60
+ transition: all 150ms ease-out;
61
+ }
62
+ }
63
+
36
64
  }
37
65
 
38
66
  @layer wp-ui-compositions {
67
+ .content-inner {
68
+ padding-block-start: 0;
69
+ }
70
+
39
71
  .header {
40
72
  display: flex;
41
73
  flex-direction: row;
@@ -53,9 +53,7 @@ describe( 'CollapsibleCard', () => {
53
53
  </CollapsibleCard.Root>
54
54
  );
55
55
 
56
- expect(
57
- screen.queryByText( 'Hidden content' )
58
- ).not.toBeInTheDocument();
56
+ expect( screen.getByText( 'Hidden content' ) ).not.toBeVisible();
59
57
  } );
60
58
 
61
59
  it( 'shows content when defaultOpen is true', () => {
@@ -87,9 +85,7 @@ describe( 'CollapsibleCard', () => {
87
85
  </CollapsibleCard.Root>
88
86
  );
89
87
 
90
- expect(
91
- screen.queryByText( 'Toggle content' )
92
- ).not.toBeInTheDocument();
88
+ expect( screen.getByText( 'Toggle content' ) ).not.toBeVisible();
93
89
 
94
90
  await user.click(
95
91
  screen.getByRole( 'button', {
@@ -107,9 +103,7 @@ describe( 'CollapsibleCard', () => {
107
103
  } )
108
104
  );
109
105
 
110
- expect(
111
- screen.queryByText( 'Toggle content' )
112
- ).not.toBeInTheDocument();
106
+ expect( screen.getByText( 'Toggle content' ) ).not.toBeVisible();
113
107
  } );
114
108
 
115
109
  it( 'calls onOpenChange when toggled', async () => {
@@ -184,4 +178,97 @@ describe( 'CollapsibleCard', () => {
184
178
  ).toBeVisible();
185
179
  } );
186
180
  } );
181
+
182
+ describe( 'HeaderDescription', () => {
183
+ it( 'sets aria-describedby on the trigger pointing to the description', () => {
184
+ render(
185
+ <CollapsibleCard.Root>
186
+ <CollapsibleCard.Header>
187
+ <Card.Title>Settings</Card.Title>
188
+ <CollapsibleCard.HeaderDescription data-testid="desc">
189
+ 3 errors
190
+ </CollapsibleCard.HeaderDescription>
191
+ </CollapsibleCard.Header>
192
+ <CollapsibleCard.Content>
193
+ <p>Content</p>
194
+ </CollapsibleCard.Content>
195
+ </CollapsibleCard.Root>
196
+ );
197
+
198
+ const trigger = screen.getByRole( 'button', {
199
+ name: 'Settings',
200
+ } );
201
+ const descriptionElement = screen.getByTestId( 'desc' );
202
+
203
+ expect( descriptionElement ).toHaveAttribute( 'id' );
204
+ expect( trigger ).toHaveAttribute(
205
+ 'aria-describedby',
206
+ descriptionElement.id
207
+ );
208
+ } );
209
+
210
+ it( 'marks the description content as aria-hidden', () => {
211
+ render(
212
+ <CollapsibleCard.Root>
213
+ <CollapsibleCard.Header>
214
+ <Card.Title>Settings</Card.Title>
215
+ <CollapsibleCard.HeaderDescription data-testid="desc">
216
+ <span>Status: OK</span>
217
+ </CollapsibleCard.HeaderDescription>
218
+ </CollapsibleCard.Header>
219
+ </CollapsibleCard.Root>
220
+ );
221
+
222
+ const descriptionWrapper = screen.getByTestId( 'desc' );
223
+ expect( descriptionWrapper ).toHaveAttribute(
224
+ 'aria-hidden',
225
+ 'true'
226
+ );
227
+ } );
228
+
229
+ it( 'does not set aria-describedby when HeaderDescription is absent', () => {
230
+ render(
231
+ <CollapsibleCard.Root>
232
+ <CollapsibleCard.Header>
233
+ <Card.Title>Title</Card.Title>
234
+ </CollapsibleCard.Header>
235
+ </CollapsibleCard.Root>
236
+ );
237
+
238
+ const trigger = screen.getByRole( 'button', { name: 'Title' } );
239
+ expect( trigger ).not.toHaveAttribute( 'aria-describedby' );
240
+ } );
241
+
242
+ it( 'forwards ref on HeaderDescription', () => {
243
+ const descRef = createRef< HTMLDivElement >();
244
+
245
+ render(
246
+ <CollapsibleCard.Root>
247
+ <CollapsibleCard.Header>
248
+ <Card.Title>Title</Card.Title>
249
+ <CollapsibleCard.HeaderDescription ref={ descRef }>
250
+ Description
251
+ </CollapsibleCard.HeaderDescription>
252
+ </CollapsibleCard.Header>
253
+ </CollapsibleCard.Root>
254
+ );
255
+
256
+ expect( descRef.current ).toBeInstanceOf( HTMLDivElement );
257
+ } );
258
+
259
+ it( 'renders description content visually', () => {
260
+ render(
261
+ <CollapsibleCard.Root>
262
+ <CollapsibleCard.Header>
263
+ <Card.Title>Title</Card.Title>
264
+ <CollapsibleCard.HeaderDescription>
265
+ Badge content
266
+ </CollapsibleCard.HeaderDescription>
267
+ </CollapsibleCard.Header>
268
+ </CollapsibleCard.Root>
269
+ );
270
+
271
+ expect( screen.getByText( 'Badge content' ) ).toBeVisible();
272
+ } );
273
+ } );
187
274
  } );
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
+ import type { PanelProps } from '../collapsible/types';
2
3
  import type { ComponentProps } from '../utils/types';
3
4
 
4
5
  export interface RootProps extends ComponentProps< 'div' > {
@@ -36,9 +37,30 @@ export interface HeaderProps extends ComponentProps< 'div' > {
36
37
  children?: ReactNode;
37
38
  }
38
39
 
40
+ export interface HeaderDescriptionProps extends ComponentProps< 'div' > {
41
+ /**
42
+ * Secondary content that describes the header trigger via
43
+ * `aria-describedby`. Rendered visually but marked `aria-hidden`
44
+ * so assistive technologies consume it only through the description
45
+ * relationship, avoiding double announcements.
46
+ *
47
+ * Avoid interactive elements — the entire header is the toggle trigger.
48
+ */
49
+ children?: ReactNode;
50
+ }
51
+
39
52
  export interface ContentProps extends ComponentProps< 'div' > {
40
53
  /**
41
54
  * The content to be rendered inside the collapsible content area.
42
55
  */
43
56
  children?: ReactNode;
57
+ /**
58
+ * Allows the browser’s built-in page search to find and expand the panel contents.
59
+ *
60
+ * Overrides the `keepMounted` prop and uses `hidden="until-found"`
61
+ * to hide the element without removing it from the DOM.
62
+ *
63
+ * @default true
64
+ */
65
+ hiddenUntilFound?: PanelProps[ 'hiddenUntilFound' ];
44
66
  }
@@ -8,11 +8,17 @@ import type { ActionProps } from './types';
8
8
  * Accepts all Button component props for styling.
9
9
  */
10
10
  const Action = forwardRef< HTMLButtonElement, ActionProps >(
11
- function DialogAction( { render, ...props }, ref ) {
11
+ function DialogAction( { render, disabled, loading, ...props }, ref ) {
12
+ // Resolve `disabled` the same way Button does so that
13
+ // _Dialog.Close's internal useButton (which controls
14
+ // aria-disabled) stays in sync with the rendered Button.
15
+ const resolvedDisabled = disabled ?? loading;
16
+
12
17
  return (
13
18
  <_Dialog.Close
14
19
  ref={ ref }
15
- render={ <Button render={ render } /> }
20
+ render={ <Button render={ render } loading={ loading } /> }
21
+ disabled={ resolvedDisabled }
16
22
  { ...props }
17
23
  />
18
24
  );
@@ -22,6 +22,7 @@ const CloseIcon = forwardRef< HTMLButtonElement, CloseIconProps >(
22
22
  { ...props }
23
23
  icon={ icon ?? close }
24
24
  label={ label ?? __( 'Close' ) }
25
+ data-wp-ui-dialog-close-icon=""
25
26
  />
26
27
  }
27
28
  />
@@ -1,11 +1,13 @@
1
1
  import { Dialog as _Dialog } from '@base-ui/react/dialog';
2
2
  import clsx from 'clsx';
3
3
  import { forwardRef } from '@wordpress/element';
4
+ import { useMergeRefs } from '@wordpress/compose';
4
5
  import {
5
6
  type ThemeProvider as ThemeProviderType,
6
7
  privateApis as themePrivateApis,
7
8
  } from '@wordpress/theme';
8
9
  import { unlock } from '../lock-unlock';
10
+ import { useDeprioritizedInitialFocus } from '../utils/use-deprioritized-initial-focus';
9
11
  import { DialogValidationProvider } from './context';
10
12
  import styles from './style.module.css';
11
13
  import type { PopupProps } from './types';
@@ -13,25 +15,42 @@ import type { PopupProps } from './types';
13
15
  const ThemeProvider: typeof ThemeProviderType =
14
16
  unlock( themePrivateApis ).ThemeProvider;
15
17
 
18
+ const CLOSE_ICON_ATTR = 'data-wp-ui-dialog-close-icon';
19
+
16
20
  /**
17
21
  * Renders the dialog popup element that contains the dialog content.
18
22
  * Uses a portal to render outside the DOM hierarchy.
19
23
  */
20
24
  const Popup = forwardRef< HTMLDivElement, PopupProps >( function DialogPopup(
21
- { className, size = 'medium', children, ...props },
25
+ {
26
+ className,
27
+ size = 'medium',
28
+ initialFocus,
29
+ finalFocus,
30
+ children,
31
+ ...props
32
+ },
22
33
  ref
23
34
  ) {
35
+ const { resolvedInitialFocus, popupRef } = useDeprioritizedInitialFocus( {
36
+ initialFocus,
37
+ deprioritizedAttribute: CLOSE_ICON_ATTR,
38
+ } );
39
+ const mergedRef = useMergeRefs( [ ref, popupRef ] );
40
+
24
41
  return (
25
42
  <_Dialog.Portal>
26
43
  <_Dialog.Backdrop className={ styles.backdrop } />
27
44
  <ThemeProvider>
28
45
  <_Dialog.Popup
29
- ref={ ref }
46
+ ref={ mergedRef }
30
47
  className={ clsx(
31
48
  styles.popup,
32
49
  className,
33
50
  styles[ `is-${ size }` ]
34
51
  ) }
52
+ initialFocus={ resolvedInitialFocus }
53
+ finalFocus={ finalFocus }
35
54
  { ...props }
36
55
  >
37
56
  <DialogValidationProvider>