@wordpress/ui 0.9.1-next.v.202603161435.0 → 0.11.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 (655) hide show
  1. package/CHANGELOG.md +76 -1
  2. package/CONTRIBUTING.md +180 -0
  3. package/README.md +34 -6
  4. package/build/alert-dialog/context.cjs +39 -0
  5. package/build/alert-dialog/context.cjs.map +7 -0
  6. package/build/alert-dialog/index.cjs +37 -0
  7. package/build/alert-dialog/index.cjs.map +7 -0
  8. package/build/alert-dialog/popup.cjs +165 -0
  9. package/build/alert-dialog/popup.cjs.map +7 -0
  10. package/build/alert-dialog/root.cjs +152 -0
  11. package/build/alert-dialog/root.cjs.map +7 -0
  12. package/build/alert-dialog/trigger.cjs +38 -0
  13. package/build/alert-dialog/trigger.cjs.map +7 -0
  14. package/build/alert-dialog/types.cjs +19 -0
  15. package/build/alert-dialog/types.cjs.map +7 -0
  16. package/build/badge/badge.cjs +14 -14
  17. package/build/badge/badge.cjs.map +2 -2
  18. package/build/button/button.cjs +18 -8
  19. package/build/button/button.cjs.map +3 -3
  20. package/build/card/content.cjs +4 -4
  21. package/build/card/content.cjs.map +2 -2
  22. package/build/card/full-bleed.cjs +4 -4
  23. package/build/card/full-bleed.cjs.map +2 -2
  24. package/build/card/header.cjs +4 -4
  25. package/build/card/header.cjs.map +2 -2
  26. package/build/card/root.cjs +6 -6
  27. package/build/card/root.cjs.map +2 -2
  28. package/build/card/title.cjs +14 -21
  29. package/build/card/title.cjs.map +3 -3
  30. package/build/collapsible-card/content.cjs +24 -3
  31. package/build/collapsible-card/content.cjs.map +4 -4
  32. package/build/collapsible-card/context.cjs +35 -0
  33. package/build/collapsible-card/context.cjs.map +7 -0
  34. package/build/collapsible-card/header-description.cjs +52 -0
  35. package/build/collapsible-card/header-description.cjs.map +7 -0
  36. package/build/collapsible-card/header.cjs +39 -18
  37. package/build/collapsible-card/header.cjs.map +2 -2
  38. package/build/collapsible-card/index.cjs +3 -0
  39. package/build/collapsible-card/index.cjs.map +2 -2
  40. package/build/collapsible-card/types.cjs.map +1 -1
  41. package/build/dialog/action.cjs +4 -2
  42. package/build/dialog/action.cjs.map +2 -2
  43. package/build/dialog/close-icon.cjs +2 -1
  44. package/build/dialog/close-icon.cjs.map +2 -2
  45. package/build/dialog/footer.cjs +3 -3
  46. package/build/dialog/footer.cjs.map +2 -2
  47. package/build/dialog/header.cjs +3 -3
  48. package/build/dialog/header.cjs.map +2 -2
  49. package/build/dialog/popup.cjs +24 -6
  50. package/build/dialog/popup.cjs.map +2 -2
  51. package/build/dialog/title.cjs +10 -19
  52. package/build/dialog/title.cjs.map +3 -3
  53. package/build/dialog/types.cjs.map +1 -1
  54. package/build/empty-state/actions.cjs +66 -0
  55. package/build/empty-state/actions.cjs.map +7 -0
  56. package/build/empty-state/description.cjs +69 -0
  57. package/build/empty-state/description.cjs.map +7 -0
  58. package/build/empty-state/icon.cjs +69 -0
  59. package/build/empty-state/icon.cjs.map +7 -0
  60. package/build/empty-state/index.cjs +46 -0
  61. package/build/empty-state/index.cjs.map +7 -0
  62. package/build/empty-state/root.cjs +66 -0
  63. package/build/empty-state/root.cjs.map +7 -0
  64. package/build/empty-state/title.cjs +71 -0
  65. package/build/empty-state/title.cjs.map +7 -0
  66. package/build/empty-state/types.cjs +19 -0
  67. package/build/empty-state/types.cjs.map +7 -0
  68. package/build/empty-state/visual.cjs +66 -0
  69. package/build/empty-state/visual.cjs.map +7 -0
  70. package/build/form/index.cjs +27 -0
  71. package/build/form/index.cjs.map +7 -0
  72. package/build/form/input-control/index.cjs +31 -0
  73. package/build/form/input-control/index.cjs.map +7 -0
  74. package/build/form/input-control/input-control.cjs +50 -0
  75. package/build/form/input-control/input-control.cjs.map +7 -0
  76. package/build/form/input-control/types.cjs +19 -0
  77. package/build/form/input-control/types.cjs.map +7 -0
  78. package/build/form/primitives/field/description.cjs +17 -4
  79. package/build/form/primitives/field/description.cjs.map +3 -3
  80. package/build/form/primitives/field/details.cjs +4 -4
  81. package/build/form/primitives/field/details.cjs.map +2 -2
  82. package/build/form/primitives/field/label.cjs +8 -8
  83. package/build/form/primitives/field/label.cjs.map +2 -2
  84. package/build/form/primitives/field/root.cjs +2 -2
  85. package/build/form/primitives/field/root.cjs.map +1 -1
  86. package/build/form/primitives/fieldset/description.cjs +20 -4
  87. package/build/form/primitives/fieldset/description.cjs.map +3 -3
  88. package/build/form/primitives/fieldset/details.cjs +3 -3
  89. package/build/form/primitives/fieldset/details.cjs.map +2 -2
  90. package/build/form/primitives/fieldset/legend.cjs +8 -7
  91. package/build/form/primitives/fieldset/legend.cjs.map +2 -2
  92. package/build/form/primitives/fieldset/root.cjs +2 -2
  93. package/build/form/primitives/fieldset/root.cjs.map +1 -1
  94. package/build/form/primitives/input/input.cjs +23 -7
  95. package/build/form/primitives/input/input.cjs.map +3 -3
  96. package/build/form/primitives/input-layout/input-layout.cjs +15 -5
  97. package/build/form/primitives/input-layout/input-layout.cjs.map +3 -3
  98. package/build/form/primitives/input-layout/slot.cjs +6 -5
  99. package/build/form/primitives/input-layout/slot.cjs.map +2 -2
  100. package/build/form/primitives/select/item.cjs +5 -5
  101. package/build/form/primitives/select/item.cjs.map +2 -2
  102. package/build/form/primitives/select/popup.cjs +9 -9
  103. package/build/form/primitives/select/popup.cjs.map +2 -2
  104. package/build/form/primitives/select/trigger.cjs +6 -6
  105. package/build/form/primitives/select/trigger.cjs.map +2 -2
  106. package/build/form/primitives/select/types.cjs.map +1 -1
  107. package/build/form/primitives/textarea/textarea.cjs +23 -4
  108. package/build/form/primitives/textarea/textarea.cjs.map +3 -3
  109. package/build/form/types.cjs +19 -0
  110. package/build/form/types.cjs.map +7 -0
  111. package/build/icon-button/icon-button.cjs +2 -2
  112. package/build/icon-button/icon-button.cjs.map +1 -1
  113. package/build/index.cjs +11 -2
  114. package/build/index.cjs.map +2 -2
  115. package/build/link/link.cjs +18 -8
  116. package/build/link/link.cjs.map +3 -3
  117. package/build/notice/action-button.cjs +3 -3
  118. package/build/notice/action-button.cjs.map +2 -2
  119. package/build/notice/action-link.cjs +3 -3
  120. package/build/notice/action-link.cjs.map +2 -2
  121. package/build/notice/actions.cjs +3 -3
  122. package/build/notice/actions.cjs.map +2 -2
  123. package/build/notice/close-icon.cjs +3 -3
  124. package/build/notice/close-icon.cjs.map +2 -2
  125. package/build/notice/description.cjs +3 -3
  126. package/build/notice/description.cjs.map +2 -2
  127. package/build/notice/index.cjs.map +1 -1
  128. package/build/notice/root.cjs +5 -5
  129. package/build/notice/root.cjs.map +2 -2
  130. package/build/notice/title.cjs +3 -3
  131. package/build/notice/title.cjs.map +2 -2
  132. package/build/popover/arrow.cjs +94 -0
  133. package/build/popover/arrow.cjs.map +7 -0
  134. package/build/popover/close.cjs +45 -0
  135. package/build/popover/close.cjs.map +7 -0
  136. package/build/popover/context.cjs +76 -0
  137. package/build/popover/context.cjs.map +7 -0
  138. package/build/popover/description.cjs +70 -0
  139. package/build/popover/description.cjs.map +7 -0
  140. package/build/popover/index.cjs +49 -0
  141. package/build/popover/index.cjs.map +7 -0
  142. package/build/popover/popup.cjs +138 -0
  143. package/build/popover/popup.cjs.map +7 -0
  144. package/build/popover/root.cjs +35 -0
  145. package/build/popover/root.cjs.map +7 -0
  146. package/build/popover/title.cjs +56 -0
  147. package/build/popover/title.cjs.map +7 -0
  148. package/build/popover/trigger.cjs +38 -0
  149. package/build/popover/trigger.cjs.map +7 -0
  150. package/build/popover/types.cjs +19 -0
  151. package/build/popover/types.cjs.map +7 -0
  152. package/build/stack/stack.cjs +2 -2
  153. package/build/stack/stack.cjs.map +1 -1
  154. package/build/tabs/context.cjs +121 -0
  155. package/build/tabs/context.cjs.map +7 -0
  156. package/build/tabs/list.cjs +3 -4
  157. package/build/tabs/list.cjs.map +2 -2
  158. package/build/tabs/panel.cjs +5 -3
  159. package/build/tabs/panel.cjs.map +2 -2
  160. package/build/tabs/root.cjs +2 -1
  161. package/build/tabs/root.cjs.map +2 -2
  162. package/build/tabs/tab.cjs +5 -3
  163. package/build/tabs/tab.cjs.map +2 -2
  164. package/build/text/text.cjs +20 -5
  165. package/build/text/text.cjs.map +3 -3
  166. package/build/tooltip/popup.cjs +7 -6
  167. package/build/tooltip/popup.cjs.map +2 -2
  168. package/build/tooltip/root.cjs.map +2 -2
  169. package/build/tooltip/types.cjs.map +1 -1
  170. package/build/utils/types.cjs.map +1 -1
  171. package/build/utils/use-deprioritized-initial-focus.cjs +64 -0
  172. package/build/utils/use-deprioritized-initial-focus.cjs.map +7 -0
  173. package/build/visually-hidden/visually-hidden.cjs +2 -2
  174. package/build/visually-hidden/visually-hidden.cjs.map +2 -2
  175. package/build-module/alert-dialog/context.mjs +14 -0
  176. package/build-module/alert-dialog/context.mjs.map +7 -0
  177. package/build-module/alert-dialog/index.mjs +10 -0
  178. package/build-module/alert-dialog/index.mjs.map +7 -0
  179. package/build-module/alert-dialog/popup.mjs +132 -0
  180. package/build-module/alert-dialog/popup.mjs.map +7 -0
  181. package/build-module/alert-dialog/root.mjs +133 -0
  182. package/build-module/alert-dialog/root.mjs.map +7 -0
  183. package/build-module/alert-dialog/trigger.mjs +13 -0
  184. package/build-module/alert-dialog/trigger.mjs.map +7 -0
  185. package/build-module/alert-dialog/types.mjs +1 -0
  186. package/build-module/alert-dialog/types.mjs.map +7 -0
  187. package/build-module/badge/badge.mjs +14 -14
  188. package/build-module/badge/badge.mjs.map +2 -2
  189. package/build-module/button/button.mjs +18 -8
  190. package/build-module/button/button.mjs.map +3 -3
  191. package/build-module/card/content.mjs +4 -4
  192. package/build-module/card/content.mjs.map +2 -2
  193. package/build-module/card/full-bleed.mjs +4 -4
  194. package/build-module/card/full-bleed.mjs.map +2 -2
  195. package/build-module/card/header.mjs +4 -4
  196. package/build-module/card/header.mjs.map +2 -2
  197. package/build-module/card/root.mjs +6 -6
  198. package/build-module/card/root.mjs.map +2 -2
  199. package/build-module/card/title.mjs +14 -21
  200. package/build-module/card/title.mjs.map +3 -3
  201. package/build-module/collapsible-card/content.mjs +24 -3
  202. package/build-module/collapsible-card/content.mjs.map +3 -3
  203. package/build-module/collapsible-card/context.mjs +10 -0
  204. package/build-module/collapsible-card/context.mjs.map +7 -0
  205. package/build-module/collapsible-card/header-description.mjs +27 -0
  206. package/build-module/collapsible-card/header-description.mjs.map +7 -0
  207. package/build-module/collapsible-card/header.mjs +40 -19
  208. package/build-module/collapsible-card/header.mjs.map +2 -2
  209. package/build-module/collapsible-card/index.mjs +2 -0
  210. package/build-module/collapsible-card/index.mjs.map +2 -2
  211. package/build-module/dialog/action.mjs +4 -2
  212. package/build-module/dialog/action.mjs.map +2 -2
  213. package/build-module/dialog/close-icon.mjs +2 -1
  214. package/build-module/dialog/close-icon.mjs.map +2 -2
  215. package/build-module/dialog/footer.mjs +3 -3
  216. package/build-module/dialog/footer.mjs.map +2 -2
  217. package/build-module/dialog/header.mjs +3 -3
  218. package/build-module/dialog/header.mjs.map +2 -2
  219. package/build-module/dialog/popup.mjs +24 -6
  220. package/build-module/dialog/popup.mjs.map +2 -2
  221. package/build-module/dialog/title.mjs +10 -9
  222. package/build-module/dialog/title.mjs.map +2 -2
  223. package/build-module/empty-state/actions.mjs +31 -0
  224. package/build-module/empty-state/actions.mjs.map +7 -0
  225. package/build-module/empty-state/description.mjs +34 -0
  226. package/build-module/empty-state/description.mjs.map +7 -0
  227. package/build-module/empty-state/icon.mjs +34 -0
  228. package/build-module/empty-state/icon.mjs.map +7 -0
  229. package/build-module/empty-state/index.mjs +16 -0
  230. package/build-module/empty-state/index.mjs.map +7 -0
  231. package/build-module/empty-state/root.mjs +31 -0
  232. package/build-module/empty-state/root.mjs.map +7 -0
  233. package/build-module/empty-state/title.mjs +36 -0
  234. package/build-module/empty-state/title.mjs.map +7 -0
  235. package/build-module/empty-state/types.mjs +1 -0
  236. package/build-module/empty-state/types.mjs.map +7 -0
  237. package/build-module/empty-state/visual.mjs +31 -0
  238. package/build-module/empty-state/visual.mjs.map +7 -0
  239. package/build-module/form/index.mjs +4 -0
  240. package/build-module/form/index.mjs.map +7 -0
  241. package/build-module/form/input-control/index.mjs +6 -0
  242. package/build-module/form/input-control/index.mjs.map +7 -0
  243. package/build-module/form/input-control/input-control.mjs +25 -0
  244. package/build-module/form/input-control/input-control.mjs.map +7 -0
  245. package/build-module/form/input-control/types.mjs +1 -0
  246. package/build-module/form/input-control/types.mjs.map +7 -0
  247. package/build-module/form/primitives/field/description.mjs +17 -4
  248. package/build-module/form/primitives/field/description.mjs.map +3 -3
  249. package/build-module/form/primitives/field/details.mjs +4 -4
  250. package/build-module/form/primitives/field/details.mjs.map +2 -2
  251. package/build-module/form/primitives/field/label.mjs +8 -8
  252. package/build-module/form/primitives/field/label.mjs.map +2 -2
  253. package/build-module/form/primitives/field/root.mjs +2 -2
  254. package/build-module/form/primitives/field/root.mjs.map +1 -1
  255. package/build-module/form/primitives/fieldset/description.mjs +20 -4
  256. package/build-module/form/primitives/fieldset/description.mjs.map +3 -3
  257. package/build-module/form/primitives/fieldset/details.mjs +3 -3
  258. package/build-module/form/primitives/fieldset/details.mjs.map +2 -2
  259. package/build-module/form/primitives/fieldset/legend.mjs +8 -7
  260. package/build-module/form/primitives/fieldset/legend.mjs.map +2 -2
  261. package/build-module/form/primitives/fieldset/root.mjs +2 -2
  262. package/build-module/form/primitives/fieldset/root.mjs.map +1 -1
  263. package/build-module/form/primitives/input/input.mjs +23 -7
  264. package/build-module/form/primitives/input/input.mjs.map +3 -3
  265. package/build-module/form/primitives/input-layout/input-layout.mjs +15 -5
  266. package/build-module/form/primitives/input-layout/input-layout.mjs.map +3 -3
  267. package/build-module/form/primitives/input-layout/slot.mjs +6 -5
  268. package/build-module/form/primitives/input-layout/slot.mjs.map +2 -2
  269. package/build-module/form/primitives/select/item.mjs +5 -5
  270. package/build-module/form/primitives/select/item.mjs.map +2 -2
  271. package/build-module/form/primitives/select/popup.mjs +9 -9
  272. package/build-module/form/primitives/select/popup.mjs.map +2 -2
  273. package/build-module/form/primitives/select/trigger.mjs +6 -6
  274. package/build-module/form/primitives/select/trigger.mjs.map +2 -2
  275. package/build-module/form/primitives/textarea/textarea.mjs +23 -4
  276. package/build-module/form/primitives/textarea/textarea.mjs.map +3 -3
  277. package/build-module/form/types.mjs +1 -0
  278. package/build-module/form/types.mjs.map +7 -0
  279. package/build-module/icon-button/icon-button.mjs +2 -2
  280. package/build-module/icon-button/icon-button.mjs.map +1 -1
  281. package/build-module/index.mjs +7 -1
  282. package/build-module/index.mjs.map +2 -2
  283. package/build-module/link/link.mjs +18 -8
  284. package/build-module/link/link.mjs.map +3 -3
  285. package/build-module/notice/action-button.mjs +3 -3
  286. package/build-module/notice/action-button.mjs.map +2 -2
  287. package/build-module/notice/action-link.mjs +3 -3
  288. package/build-module/notice/action-link.mjs.map +2 -2
  289. package/build-module/notice/actions.mjs +3 -3
  290. package/build-module/notice/actions.mjs.map +2 -2
  291. package/build-module/notice/close-icon.mjs +3 -3
  292. package/build-module/notice/close-icon.mjs.map +2 -2
  293. package/build-module/notice/description.mjs +3 -3
  294. package/build-module/notice/description.mjs.map +2 -2
  295. package/build-module/notice/index.mjs.map +1 -1
  296. package/build-module/notice/root.mjs +5 -5
  297. package/build-module/notice/root.mjs.map +2 -2
  298. package/build-module/notice/title.mjs +3 -3
  299. package/build-module/notice/title.mjs.map +2 -2
  300. package/build-module/popover/arrow.mjs +59 -0
  301. package/build-module/popover/arrow.mjs.map +7 -0
  302. package/build-module/popover/close.mjs +20 -0
  303. package/build-module/popover/close.mjs.map +7 -0
  304. package/build-module/popover/context.mjs +57 -0
  305. package/build-module/popover/context.mjs.map +7 -0
  306. package/build-module/popover/description.mjs +35 -0
  307. package/build-module/popover/description.mjs.map +7 -0
  308. package/build-module/popover/index.mjs +18 -0
  309. package/build-module/popover/index.mjs.map +7 -0
  310. package/build-module/popover/popup.mjs +105 -0
  311. package/build-module/popover/popup.mjs.map +7 -0
  312. package/build-module/popover/root.mjs +10 -0
  313. package/build-module/popover/root.mjs.map +7 -0
  314. package/build-module/popover/title.mjs +31 -0
  315. package/build-module/popover/title.mjs.map +7 -0
  316. package/build-module/popover/trigger.mjs +13 -0
  317. package/build-module/popover/trigger.mjs.map +7 -0
  318. package/build-module/popover/types.mjs +1 -0
  319. package/build-module/popover/types.mjs.map +7 -0
  320. package/build-module/stack/stack.mjs +2 -2
  321. package/build-module/stack/stack.mjs.map +1 -1
  322. package/build-module/tabs/context.mjs +101 -0
  323. package/build-module/tabs/context.mjs.map +7 -0
  324. package/build-module/tabs/list.mjs +3 -4
  325. package/build-module/tabs/list.mjs.map +2 -2
  326. package/build-module/tabs/panel.mjs +5 -3
  327. package/build-module/tabs/panel.mjs.map +2 -2
  328. package/build-module/tabs/root.mjs +2 -1
  329. package/build-module/tabs/root.mjs.map +2 -2
  330. package/build-module/tabs/tab.mjs +5 -3
  331. package/build-module/tabs/tab.mjs.map +2 -2
  332. package/build-module/text/text.mjs +20 -5
  333. package/build-module/text/text.mjs.map +3 -3
  334. package/build-module/tooltip/popup.mjs +7 -6
  335. package/build-module/tooltip/popup.mjs.map +2 -2
  336. package/build-module/tooltip/root.mjs.map +2 -2
  337. package/build-module/utils/use-deprioritized-initial-focus.mjs +39 -0
  338. package/build-module/utils/use-deprioritized-initial-focus.mjs.map +7 -0
  339. package/build-module/visually-hidden/visually-hidden.mjs +2 -2
  340. package/build-module/visually-hidden/visually-hidden.mjs.map +2 -2
  341. package/build-types/alert-dialog/context.d.ts +11 -0
  342. package/build-types/alert-dialog/context.d.ts.map +1 -0
  343. package/build-types/alert-dialog/index.d.ts +4 -0
  344. package/build-types/alert-dialog/index.d.ts.map +1 -0
  345. package/build-types/alert-dialog/popup.d.ts +4 -0
  346. package/build-types/alert-dialog/popup.d.ts.map +1 -0
  347. package/build-types/alert-dialog/root.d.ts +18 -0
  348. package/build-types/alert-dialog/root.d.ts.map +1 -0
  349. package/build-types/alert-dialog/stories/index.story.d.ts +56 -0
  350. package/build-types/alert-dialog/stories/index.story.d.ts.map +1 -0
  351. package/build-types/alert-dialog/test/index.test.d.ts +2 -0
  352. package/build-types/alert-dialog/test/index.test.d.ts.map +1 -0
  353. package/build-types/alert-dialog/trigger.d.ts +7 -0
  354. package/build-types/alert-dialog/trigger.d.ts.map +1 -0
  355. package/build-types/alert-dialog/types.d.ts +105 -0
  356. package/build-types/alert-dialog/types.d.ts.map +1 -0
  357. package/build-types/badge/badge.d.ts.map +1 -1
  358. package/build-types/button/button.d.ts.map +1 -1
  359. package/build-types/card/stories/index.story.d.ts.map +1 -1
  360. package/build-types/card/title.d.ts.map +1 -1
  361. package/build-types/collapsible/panel.d.ts +2 -1
  362. package/build-types/collapsible/panel.d.ts.map +1 -1
  363. package/build-types/collapsible/root.d.ts +2 -1
  364. package/build-types/collapsible/root.d.ts.map +1 -1
  365. package/build-types/collapsible/trigger.d.ts +2 -1
  366. package/build-types/collapsible/trigger.d.ts.map +1 -1
  367. package/build-types/collapsible-card/content.d.ts.map +1 -1
  368. package/build-types/collapsible-card/context.d.ts +4 -0
  369. package/build-types/collapsible-card/context.d.ts.map +1 -0
  370. package/build-types/collapsible-card/header-description.d.ts +15 -0
  371. package/build-types/collapsible-card/header-description.d.ts.map +1 -0
  372. package/build-types/collapsible-card/header.d.ts.map +1 -1
  373. package/build-types/collapsible-card/index.d.ts +2 -1
  374. package/build-types/collapsible-card/index.d.ts.map +1 -1
  375. package/build-types/collapsible-card/stories/index.story.d.ts +10 -0
  376. package/build-types/collapsible-card/stories/index.story.d.ts.map +1 -1
  377. package/build-types/collapsible-card/types.d.ts +21 -0
  378. package/build-types/collapsible-card/types.d.ts.map +1 -1
  379. package/build-types/dialog/action.d.ts.map +1 -1
  380. package/build-types/dialog/close-icon.d.ts.map +1 -1
  381. package/build-types/dialog/popup.d.ts.map +1 -1
  382. package/build-types/dialog/stories/index.story.d.ts +8 -6
  383. package/build-types/dialog/stories/index.story.d.ts.map +1 -1
  384. package/build-types/dialog/title.d.ts +12 -2
  385. package/build-types/dialog/title.d.ts.map +1 -1
  386. package/build-types/dialog/types.d.ts +13 -6
  387. package/build-types/dialog/types.d.ts.map +1 -1
  388. package/build-types/empty-state/actions.d.ts +7 -0
  389. package/build-types/empty-state/actions.d.ts.map +1 -0
  390. package/build-types/empty-state/description.d.ts +7 -0
  391. package/build-types/empty-state/description.d.ts.map +1 -0
  392. package/build-types/empty-state/icon.d.ts +7 -0
  393. package/build-types/empty-state/icon.d.ts.map +1 -0
  394. package/build-types/empty-state/index.d.ts +8 -0
  395. package/build-types/empty-state/index.d.ts.map +1 -0
  396. package/build-types/empty-state/root.d.ts +6 -0
  397. package/build-types/empty-state/root.d.ts.map +1 -0
  398. package/build-types/empty-state/stories/index.story.d.ts +8 -0
  399. package/build-types/empty-state/stories/index.story.d.ts.map +1 -0
  400. package/build-types/empty-state/test/actions.test.d.ts +2 -0
  401. package/build-types/empty-state/test/actions.test.d.ts.map +1 -0
  402. package/build-types/empty-state/test/description.test.d.ts +2 -0
  403. package/build-types/empty-state/test/description.test.d.ts.map +1 -0
  404. package/build-types/empty-state/test/icon.test.d.ts +2 -0
  405. package/build-types/empty-state/test/icon.test.d.ts.map +1 -0
  406. package/build-types/empty-state/test/root.test.d.ts +2 -0
  407. package/build-types/empty-state/test/root.test.d.ts.map +1 -0
  408. package/build-types/empty-state/test/title.test.d.ts +2 -0
  409. package/build-types/empty-state/test/title.test.d.ts.map +1 -0
  410. package/build-types/empty-state/test/visual.test.d.ts +2 -0
  411. package/build-types/empty-state/test/visual.test.d.ts.map +1 -0
  412. package/build-types/empty-state/title.d.ts +6 -0
  413. package/build-types/empty-state/title.d.ts.map +1 -0
  414. package/build-types/empty-state/types.d.ts +40 -0
  415. package/build-types/empty-state/types.d.ts.map +1 -0
  416. package/build-types/empty-state/visual.d.ts +7 -0
  417. package/build-types/empty-state/visual.d.ts.map +1 -0
  418. package/build-types/form/index.d.ts +3 -0
  419. package/build-types/form/index.d.ts.map +1 -0
  420. package/build-types/form/input-control/index.d.ts +2 -0
  421. package/build-types/form/input-control/index.d.ts.map +1 -0
  422. package/build-types/form/input-control/input-control.d.ts +6 -0
  423. package/build-types/form/input-control/input-control.d.ts.map +1 -0
  424. package/build-types/form/input-control/stories/index.story.d.ts +16 -0
  425. package/build-types/form/input-control/stories/index.story.d.ts.map +1 -0
  426. package/build-types/form/input-control/test/index.test.d.ts +2 -0
  427. package/build-types/form/input-control/test/index.test.d.ts.map +1 -0
  428. package/build-types/form/input-control/types.d.ts +4 -0
  429. package/build-types/form/input-control/types.d.ts.map +1 -0
  430. package/build-types/form/primitives/field/description.d.ts +2 -1
  431. package/build-types/form/primitives/field/description.d.ts.map +1 -1
  432. package/build-types/form/primitives/field/details.d.ts +2 -1
  433. package/build-types/form/primitives/field/details.d.ts.map +1 -1
  434. package/build-types/form/primitives/field/label.d.ts +2 -1
  435. package/build-types/form/primitives/field/label.d.ts.map +1 -1
  436. package/build-types/form/primitives/field/stories/index.story.d.ts.map +1 -1
  437. package/build-types/form/primitives/fieldset/description.d.ts +2 -1
  438. package/build-types/form/primitives/fieldset/description.d.ts.map +1 -1
  439. package/build-types/form/primitives/fieldset/details.d.ts +2 -1
  440. package/build-types/form/primitives/fieldset/details.d.ts.map +1 -1
  441. package/build-types/form/primitives/fieldset/legend.d.ts +2 -1
  442. package/build-types/form/primitives/fieldset/legend.d.ts.map +1 -1
  443. package/build-types/form/primitives/fieldset/root.d.ts +2 -1
  444. package/build-types/form/primitives/fieldset/root.d.ts.map +1 -1
  445. package/build-types/form/primitives/fieldset/stories/index.story.d.ts.map +1 -1
  446. package/build-types/form/primitives/input/input.d.ts.map +1 -1
  447. package/build-types/form/primitives/input/stories/index.story.d.ts +2 -0
  448. package/build-types/form/primitives/input/stories/index.story.d.ts.map +1 -1
  449. package/build-types/form/primitives/input-layout/input-layout.d.ts.map +1 -1
  450. package/build-types/form/primitives/input-layout/slot.d.ts.map +1 -1
  451. package/build-types/form/primitives/input-layout/stories/index.story.d.ts +5 -0
  452. package/build-types/form/primitives/input-layout/stories/index.story.d.ts.map +1 -1
  453. package/build-types/form/primitives/select/item.d.ts +6 -2
  454. package/build-types/form/primitives/select/item.d.ts.map +1 -1
  455. package/build-types/form/primitives/select/popup.d.ts +11 -1
  456. package/build-types/form/primitives/select/popup.d.ts.map +1 -1
  457. package/build-types/form/primitives/select/trigger.d.ts +12 -2
  458. package/build-types/form/primitives/select/trigger.d.ts.map +1 -1
  459. package/build-types/form/primitives/select/types.d.ts +13 -3
  460. package/build-types/form/primitives/select/types.d.ts.map +1 -1
  461. package/build-types/form/primitives/textarea/textarea.d.ts.map +1 -1
  462. package/build-types/form/stories/shared.d.ts +3 -0
  463. package/build-types/form/stories/shared.d.ts.map +1 -0
  464. package/build-types/form/types.d.ts +30 -0
  465. package/build-types/form/types.d.ts.map +1 -0
  466. package/build-types/index.d.ts +4 -1
  467. package/build-types/index.d.ts.map +1 -1
  468. package/build-types/link/link.d.ts.map +1 -1
  469. package/build-types/notice/index.d.ts +0 -1
  470. package/build-types/notice/index.d.ts.map +1 -1
  471. package/build-types/popover/arrow.d.ts +10 -0
  472. package/build-types/popover/arrow.d.ts.map +1 -0
  473. package/build-types/popover/close.d.ts +11 -0
  474. package/build-types/popover/close.d.ts.map +1 -0
  475. package/build-types/popover/context.d.ts +22 -0
  476. package/build-types/popover/context.d.ts.map +1 -0
  477. package/build-types/popover/description.d.ts +10 -0
  478. package/build-types/popover/description.d.ts.map +1 -0
  479. package/build-types/popover/index.d.ts +9 -0
  480. package/build-types/popover/index.d.ts.map +1 -0
  481. package/build-types/popover/popup.d.ts +11 -0
  482. package/build-types/popover/popup.d.ts.map +1 -0
  483. package/build-types/popover/root.d.ts +37 -0
  484. package/build-types/popover/root.d.ts.map +1 -0
  485. package/build-types/popover/stories/index.story.d.ts +211 -0
  486. package/build-types/popover/stories/index.story.d.ts.map +1 -0
  487. package/build-types/popover/stories/utils.d.ts +25 -0
  488. package/build-types/popover/stories/utils.d.ts.map +1 -0
  489. package/build-types/popover/test/index.test.d.ts +2 -0
  490. package/build-types/popover/test/index.test.d.ts.map +1 -0
  491. package/build-types/popover/title.d.ts +20 -0
  492. package/build-types/popover/title.d.ts.map +1 -0
  493. package/build-types/popover/trigger.d.ts +10 -0
  494. package/build-types/popover/trigger.d.ts.map +1 -0
  495. package/build-types/popover/types.d.ts +83 -0
  496. package/build-types/popover/types.d.ts.map +1 -0
  497. package/build-types/tabs/context.d.ts +26 -0
  498. package/build-types/tabs/context.d.ts.map +1 -0
  499. package/build-types/tabs/list.d.ts +2 -1
  500. package/build-types/tabs/list.d.ts.map +1 -1
  501. package/build-types/tabs/panel.d.ts +2 -1
  502. package/build-types/tabs/panel.d.ts.map +1 -1
  503. package/build-types/tabs/root.d.ts +2 -1
  504. package/build-types/tabs/root.d.ts.map +1 -1
  505. package/build-types/tabs/tab.d.ts +2 -1
  506. package/build-types/tabs/tab.d.ts.map +1 -1
  507. package/build-types/text/stories/index.story.d.ts +4 -0
  508. package/build-types/text/stories/index.story.d.ts.map +1 -1
  509. package/build-types/text/text.d.ts.map +1 -1
  510. package/build-types/tooltip/popup.d.ts.map +1 -1
  511. package/build-types/tooltip/root.d.ts +13 -0
  512. package/build-types/tooltip/root.d.ts.map +1 -1
  513. package/build-types/tooltip/stories/index.story.d.ts.map +1 -1
  514. package/build-types/tooltip/stories/usage-guidelines.story.d.ts +21 -0
  515. package/build-types/tooltip/stories/usage-guidelines.story.d.ts.map +1 -0
  516. package/build-types/tooltip/types.d.ts +4 -0
  517. package/build-types/tooltip/types.d.ts.map +1 -1
  518. package/build-types/utils/test/use-deprioritized-initial-focus.test.d.ts +2 -0
  519. package/build-types/utils/test/use-deprioritized-initial-focus.test.d.ts.map +1 -0
  520. package/build-types/utils/types.d.ts +6 -2
  521. package/build-types/utils/types.d.ts.map +1 -1
  522. package/build-types/utils/use-deprioritized-initial-focus.d.ts +36 -0
  523. package/build-types/utils/use-deprioritized-initial-focus.d.ts.map +1 -0
  524. package/build-types/visually-hidden/stories/index.story.d.ts +7 -0
  525. package/build-types/visually-hidden/stories/index.story.d.ts.map +1 -1
  526. package/build-types/visually-hidden/visually-hidden.d.ts +34 -0
  527. package/build-types/visually-hidden/visually-hidden.d.ts.map +1 -1
  528. package/package.json +17 -16
  529. package/src/alert-dialog/context.tsx +22 -0
  530. package/src/alert-dialog/index.ts +3 -0
  531. package/src/alert-dialog/popup.tsx +116 -0
  532. package/src/alert-dialog/root.tsx +226 -0
  533. package/src/alert-dialog/stories/index.story.tsx +305 -0
  534. package/src/alert-dialog/style.module.css +21 -0
  535. package/src/alert-dialog/test/index.test.tsx +1509 -0
  536. package/src/alert-dialog/trigger.tsx +15 -0
  537. package/src/alert-dialog/types.ts +119 -0
  538. package/src/badge/badge.tsx +11 -14
  539. package/src/badge/style.module.css +0 -4
  540. package/src/button/button.tsx +2 -0
  541. package/src/button/style.module.css +9 -3
  542. package/src/card/stories/index.story.tsx +4 -5
  543. package/src/card/style.module.css +4 -10
  544. package/src/card/test/index.test.tsx +17 -1
  545. package/src/card/title.tsx +14 -12
  546. package/src/collapsible-card/content.tsx +16 -3
  547. package/src/collapsible-card/context.ts +7 -0
  548. package/src/collapsible-card/header-description.tsx +43 -0
  549. package/src/collapsible-card/header.tsx +47 -24
  550. package/src/collapsible-card/index.ts +2 -1
  551. package/src/collapsible-card/stories/index.story.tsx +102 -4
  552. package/src/collapsible-card/style.module.css +34 -2
  553. package/src/collapsible-card/test/index.test.tsx +96 -9
  554. package/src/collapsible-card/types.ts +22 -0
  555. package/src/dialog/action.tsx +8 -2
  556. package/src/dialog/close-icon.tsx +1 -0
  557. package/src/dialog/popup.tsx +23 -3
  558. package/src/dialog/stories/index.story.tsx +33 -28
  559. package/src/dialog/style.module.css +18 -14
  560. package/src/dialog/test/index.test.tsx +180 -4
  561. package/src/dialog/title.tsx +21 -9
  562. package/src/dialog/types.ts +20 -6
  563. package/src/empty-state/actions.tsx +24 -0
  564. package/src/empty-state/description.tsx +31 -0
  565. package/src/empty-state/icon.tsx +24 -0
  566. package/src/empty-state/index.ts +8 -0
  567. package/src/empty-state/root.tsx +23 -0
  568. package/src/empty-state/stories/index.story.tsx +64 -0
  569. package/src/empty-state/style.module.css +53 -0
  570. package/src/empty-state/test/actions.test.tsx +18 -0
  571. package/src/empty-state/test/description.test.tsx +26 -0
  572. package/src/empty-state/test/icon.test.tsx +13 -0
  573. package/src/empty-state/test/root.test.tsx +13 -0
  574. package/src/empty-state/test/title.test.tsx +26 -0
  575. package/src/empty-state/test/visual.test.tsx +17 -0
  576. package/src/empty-state/title.tsx +29 -0
  577. package/src/empty-state/types.ts +45 -0
  578. package/src/empty-state/visual.tsx +24 -0
  579. package/src/form/index.ts +3 -0
  580. package/src/form/input-control/index.ts +1 -0
  581. package/src/form/input-control/input-control.tsx +33 -0
  582. package/src/form/input-control/stories/index.story.tsx +163 -0
  583. package/src/form/input-control/test/index.test.tsx +53 -0
  584. package/src/form/input-control/types.ts +5 -0
  585. package/src/form/primitives/field/description.tsx +6 -1
  586. package/src/form/primitives/field/details.tsx +4 -2
  587. package/src/form/primitives/field/label.tsx +9 -5
  588. package/src/form/primitives/field/stories/index.story.tsx +2 -7
  589. package/src/form/primitives/field/test/index.test.tsx +11 -0
  590. package/src/form/primitives/fieldset/description.tsx +9 -1
  591. package/src/form/primitives/fieldset/legend.tsx +9 -4
  592. package/src/form/primitives/fieldset/stories/index.story.tsx +2 -7
  593. package/src/form/primitives/fieldset/test/index.test.tsx +22 -0
  594. package/src/form/primitives/input/input.tsx +6 -1
  595. package/src/form/primitives/input/stories/index.story.tsx +7 -0
  596. package/src/form/primitives/input/style.module.css +4 -0
  597. package/src/form/primitives/input-layout/input-layout.tsx +2 -0
  598. package/src/form/primitives/input-layout/slot.tsx +6 -2
  599. package/src/form/primitives/input-layout/stories/index.story.tsx +22 -1
  600. package/src/form/primitives/input-layout/style.module.css +3 -3
  601. package/src/form/primitives/select/popup.tsx +5 -2
  602. package/src/form/primitives/select/test/index.test.tsx +60 -1
  603. package/src/form/primitives/select/types.ts +14 -4
  604. package/src/form/primitives/stories/overview.mdx +15 -0
  605. package/src/form/primitives/textarea/textarea.tsx +11 -2
  606. package/src/form/stories/shared.tsx +21 -0
  607. package/src/form/types.ts +34 -0
  608. package/src/index.ts +4 -1
  609. package/src/link/link.tsx +2 -0
  610. package/src/link/style.module.css +11 -1
  611. package/src/notice/index.ts +0 -2
  612. package/src/notice/style.module.css +6 -6
  613. package/src/popover/arrow.tsx +49 -0
  614. package/src/popover/close.tsx +24 -0
  615. package/src/popover/context.tsx +100 -0
  616. package/src/popover/description.tsx +29 -0
  617. package/src/popover/index.ts +9 -0
  618. package/src/popover/popup.tsx +106 -0
  619. package/src/popover/root.tsx +41 -0
  620. package/src/popover/stories/index.story.tsx +1315 -0
  621. package/src/popover/stories/utils.tsx +91 -0
  622. package/src/popover/style.module.css +64 -0
  623. package/src/popover/test/index.test.tsx +727 -0
  624. package/src/popover/title.tsx +47 -0
  625. package/src/popover/trigger.tsx +17 -0
  626. package/src/popover/types.ts +113 -0
  627. package/src/tabs/context.tsx +170 -0
  628. package/src/tabs/list.tsx +0 -1
  629. package/src/tabs/panel.tsx +3 -0
  630. package/src/tabs/root.tsx +6 -1
  631. package/src/tabs/style.module.css +3 -3
  632. package/src/tabs/tab.tsx +3 -0
  633. package/src/tabs/test/index.test.tsx +162 -0
  634. package/src/text/stories/index.story.tsx +4 -2
  635. package/src/text/style.module.css +62 -36
  636. package/src/text/test/index.test.tsx +1 -4
  637. package/src/text/text.tsx +8 -1
  638. package/src/tooltip/popup.tsx +2 -1
  639. package/src/tooltip/root.tsx +13 -0
  640. package/src/tooltip/stories/index.story.tsx +20 -15
  641. package/src/tooltip/stories/usage-guidelines.mdx +91 -0
  642. package/src/tooltip/stories/usage-guidelines.story.tsx +119 -0
  643. package/src/tooltip/style.module.css +2 -2
  644. package/src/tooltip/test/index.test.tsx +61 -0
  645. package/src/tooltip/types.ts +5 -0
  646. package/src/utils/css/field.module.css +12 -9
  647. package/src/utils/css/focus.module.css +7 -5
  648. package/src/utils/css/global-css-defense.module.css +117 -0
  649. package/src/utils/css/item-popup.module.css +3 -2
  650. package/src/utils/css/select-trigger.module.css +1 -0
  651. package/src/utils/test/use-deprioritized-initial-focus.test.tsx +230 -0
  652. package/src/utils/types.ts +7 -2
  653. package/src/utils/use-deprioritized-initial-focus.ts +84 -0
  654. package/src/visually-hidden/stories/index.story.tsx +25 -0
  655. package/src/visually-hidden/visually-hidden.tsx +34 -0
@@ -0,0 +1,47 @@
1
+ import { Popover as _Popover } from '@base-ui/react/popover';
2
+ import { useMergeRefs } from '@wordpress/compose';
3
+ import { forwardRef, useLayoutEffect, useRef } from '@wordpress/element';
4
+ import { Text } from '../text';
5
+ import { usePopoverValidationContext } from './context';
6
+ import type { TitleProps } from './types';
7
+
8
+ /**
9
+ * Renders a heading that labels the popover for accessibility.
10
+ *
11
+ * **Required** — every popover must include a `Popover.Title`, even if
12
+ * visually hidden. The rendered element is linked to the popup via
13
+ * `aria-labelledby`. Uses the `heading-xl` text variant, matching Dialog.
14
+ *
15
+ * To visually hide the title while keeping it accessible, wrap it with
16
+ * `VisuallyHidden` using the `render` prop:
17
+ *
18
+ * ```jsx
19
+ * <VisuallyHidden render={ <Popover.Title /> }>
20
+ * Accessible title text
21
+ * </VisuallyHidden>
22
+ * ```
23
+ */
24
+ const Title = forwardRef< HTMLHeadingElement, TitleProps >(
25
+ function PopoverTitle( { className, children, ...props }, forwardedRef ) {
26
+ const validationContext = usePopoverValidationContext();
27
+ const internalRef = useRef< HTMLHeadingElement >( null );
28
+ const mergedRef = useMergeRefs( [ internalRef, forwardedRef ] );
29
+
30
+ useLayoutEffect( () => {
31
+ validationContext?.registerTitle( internalRef.current );
32
+ }, [ validationContext ] );
33
+
34
+ return (
35
+ <Text
36
+ ref={ mergedRef }
37
+ variant="heading-xl"
38
+ render={ <_Popover.Title { ...props } /> }
39
+ className={ className }
40
+ >
41
+ { children }
42
+ </Text>
43
+ );
44
+ }
45
+ );
46
+
47
+ export { Title };
@@ -0,0 +1,17 @@
1
+ import { Popover as _Popover } from '@base-ui/react/popover';
2
+ import { forwardRef } from '@wordpress/element';
3
+ import type { TriggerProps } from './types';
4
+
5
+ /**
6
+ * Renders a button that toggles the popover popup when clicked.
7
+ *
8
+ * Renders as a `<button>` by default. Also supports hover-triggered
9
+ * popovers via the `openOnHover`, `delay`, and `closeDelay` props.
10
+ */
11
+ const Trigger = forwardRef< HTMLButtonElement, TriggerProps >(
12
+ function PopoverTrigger( props, ref ) {
13
+ return <_Popover.Trigger ref={ ref } { ...props } />;
14
+ }
15
+ );
16
+
17
+ export { Trigger };
@@ -0,0 +1,113 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { Popover as _Popover } from '@base-ui/react/popover';
3
+ import type { ComponentProps } from '../utils/types';
4
+
5
+ export interface RootProps
6
+ extends Pick<
7
+ _Popover.Root.Props,
8
+ 'open' | 'onOpenChange' | 'defaultOpen' | 'modal'
9
+ > {
10
+ /**
11
+ * The popover sub-components (`Popover.Trigger`, `Popover.Popup`, etc.).
12
+ */
13
+ children?: ReactNode;
14
+ }
15
+
16
+ export interface TriggerProps
17
+ extends ComponentProps< 'button' >,
18
+ Pick< _Popover.Trigger.Props, 'openOnHover' | 'delay' | 'closeDelay' > {
19
+ /**
20
+ * The content to be rendered inside the component.
21
+ */
22
+ children?: ReactNode;
23
+ }
24
+
25
+ /**
26
+ * `Popover.Popup` maps to two Base UI elements internally: the
27
+ * **Positioner** (outer, handles fixed positioning and z-index) and the
28
+ * **Popup** (inner, holds content and visual styles).
29
+ *
30
+ * `style` and `className` are forwarded to the **Positioner** so that
31
+ * z-index overrides (`--wp-ui-popover-z-index`) and Base UI CSS variables
32
+ * (`--available-height`, `--available-width`) work correctly. All other
33
+ * HTML attributes are forwarded to the inner **Popup** element.
34
+ */
35
+ export interface PopupProps
36
+ extends ComponentProps< 'div' >,
37
+ Pick<
38
+ _Popover.Positioner.Props,
39
+ | 'align'
40
+ | 'alignOffset'
41
+ | 'anchor'
42
+ | 'arrowPadding'
43
+ | 'collisionAvoidance'
44
+ | 'collisionBoundary'
45
+ | 'collisionPadding'
46
+ | 'side'
47
+ | 'sideOffset'
48
+ | 'sticky'
49
+ >,
50
+ Pick< _Popover.Popup.Props, 'initialFocus' | 'finalFocus' > {
51
+ /**
52
+ * Whether to render a backdrop overlay behind the popover.
53
+ *
54
+ * Typically used with `modal` to signal that interaction with the rest
55
+ * of the page is blocked. The backdrop is a semi-transparent dark overlay.
56
+ *
57
+ * @default false
58
+ */
59
+ backdrop?: boolean;
60
+
61
+ /**
62
+ * The content to be rendered inside the component.
63
+ */
64
+ children?: ReactNode;
65
+
66
+ /**
67
+ * A parent element to render the portal into.
68
+ *
69
+ * Useful for cross-document rendering, such as rendering a popover
70
+ * in a parent document when the trigger is inside an iframe.
71
+ */
72
+ container?: _Popover.Portal.Props[ 'container' ];
73
+
74
+ /**
75
+ * The visual style variant of the popup.
76
+ *
77
+ * - `'default'` — standard surface styling with background, padding,
78
+ * border radius, and shadow.
79
+ * - `'unstyled'` — no visual treatment; useful as a blank positioning
80
+ * container for fully custom content.
81
+ *
82
+ * @default 'default'
83
+ */
84
+ variant?: 'default' | 'unstyled';
85
+ }
86
+
87
+ export interface ArrowProps extends ComponentProps< 'div' > {
88
+ /**
89
+ * Custom arrow visuals to render inside the positioned container.
90
+ */
91
+ children?: ReactNode;
92
+ }
93
+
94
+ export interface TitleProps extends ComponentProps< 'h2' > {
95
+ /**
96
+ * The title content to be rendered.
97
+ */
98
+ children?: ReactNode;
99
+ }
100
+
101
+ export interface DescriptionProps extends ComponentProps< 'p' > {
102
+ /**
103
+ * The description content to be rendered.
104
+ */
105
+ children?: ReactNode;
106
+ }
107
+
108
+ export interface CloseProps extends ComponentProps< 'button' > {
109
+ /**
110
+ * The content to be rendered inside the component.
111
+ */
112
+ children?: ReactNode;
113
+ }
@@ -0,0 +1,170 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useCallback,
5
+ useMemo,
6
+ useRef,
7
+ useEffect,
8
+ } from '@wordpress/element';
9
+
10
+ type TabsValidationContextType = {
11
+ registerTab: () => () => void;
12
+ registerPanel: () => () => void;
13
+ };
14
+
15
+ /**
16
+ * Whether validation is enabled. This is a build-time constant that allows
17
+ * bundlers to tree-shake all validation code in production builds.
18
+ */
19
+ const VALIDATION_ENABLED = process.env.NODE_ENV !== 'production';
20
+
21
+ const TabsValidationContext = VALIDATION_ENABLED
22
+ ? createContext< TabsValidationContextType | null >( null )
23
+ : ( null as unknown as React.Context< TabsValidationContextType | null > );
24
+
25
+ function useRegisterTabDev() {
26
+ const context = useContext( TabsValidationContext );
27
+
28
+ useEffect( () => {
29
+ if ( context ) {
30
+ return context.registerTab();
31
+ }
32
+ return undefined;
33
+ }, [ context ] );
34
+ }
35
+
36
+ function useRegisterTabProd() {
37
+ // No-op in production.
38
+ }
39
+
40
+ /**
41
+ * Hook that registers a Tab for count validation in development mode.
42
+ */
43
+ export const useRegisterTab = VALIDATION_ENABLED
44
+ ? useRegisterTabDev
45
+ : useRegisterTabProd;
46
+
47
+ function useRegisterPanelDev() {
48
+ const context = useContext( TabsValidationContext );
49
+
50
+ useEffect( () => {
51
+ if ( context ) {
52
+ return context.registerPanel();
53
+ }
54
+ return undefined;
55
+ }, [ context ] );
56
+ }
57
+
58
+ function useRegisterPanelProd() {
59
+ // No-op in production.
60
+ }
61
+
62
+ /**
63
+ * Hook that registers a Panel for count validation in development mode.
64
+ */
65
+ export const useRegisterPanel = VALIDATION_ENABLED
66
+ ? useRegisterPanelDev
67
+ : useRegisterPanelProd;
68
+
69
+ /**
70
+ * Development-only provider that tracks the number of registered tabs and
71
+ * panels, and warns when the counts don't match.
72
+ */
73
+ function TabsValidationProviderDev( {
74
+ children,
75
+ }: {
76
+ children: React.ReactNode;
77
+ } ) {
78
+ const tabCountRef = useRef( 0 );
79
+ const panelCountRef = useRef( 0 );
80
+ const validationScheduledRef = useRef< ReturnType<
81
+ typeof setTimeout
82
+ > | null >( null );
83
+
84
+ const scheduleValidation = useCallback( () => {
85
+ if ( validationScheduledRef.current ) {
86
+ clearTimeout( validationScheduledRef.current );
87
+ }
88
+
89
+ // Schedule validation for the next tick to allow all
90
+ // registrations/unregistrations to complete.
91
+ validationScheduledRef.current = setTimeout( () => {
92
+ const tabCount = tabCountRef.current;
93
+ const panelCount = panelCountRef.current;
94
+
95
+ if ( tabCount !== panelCount ) {
96
+ throw new Error(
97
+ `Tabs: Tab/Panel count mismatch (${ tabCount } Tabs, ${ panelCount } Panels). ` +
98
+ `Each Tab must be associated with exactly one Panel. ` +
99
+ `Mismatched or missing associations can break screen reader navigation ` +
100
+ `and violate WAI-ARIA Tabs pattern requirements.`
101
+ );
102
+ }
103
+
104
+ validationScheduledRef.current = null;
105
+ }, 0 );
106
+ }, [] );
107
+
108
+ const registerTab = useCallback( () => {
109
+ tabCountRef.current += 1;
110
+ scheduleValidation();
111
+
112
+ return () => {
113
+ tabCountRef.current -= 1;
114
+ scheduleValidation();
115
+ };
116
+ }, [ scheduleValidation ] );
117
+
118
+ const registerPanel = useCallback( () => {
119
+ panelCountRef.current += 1;
120
+ scheduleValidation();
121
+
122
+ return () => {
123
+ panelCountRef.current -= 1;
124
+ scheduleValidation();
125
+ };
126
+ }, [ scheduleValidation ] );
127
+
128
+ useEffect( () => {
129
+ return () => {
130
+ if ( validationScheduledRef.current ) {
131
+ clearTimeout( validationScheduledRef.current );
132
+ }
133
+ };
134
+ }, [] );
135
+
136
+ const contextValue = useMemo(
137
+ () => ( {
138
+ registerTab,
139
+ registerPanel,
140
+ } ),
141
+ [ registerTab, registerPanel ]
142
+ );
143
+
144
+ return (
145
+ <TabsValidationContext.Provider value={ contextValue }>
146
+ { children }
147
+ </TabsValidationContext.Provider>
148
+ );
149
+ }
150
+
151
+ /**
152
+ * Production no-op provider that just renders children.
153
+ */
154
+ function TabsValidationProviderProd( {
155
+ children,
156
+ }: {
157
+ children: React.ReactNode;
158
+ } ) {
159
+ return <>{ children }</>;
160
+ }
161
+
162
+ /**
163
+ * Provider component that validates the number of tabs matches the number
164
+ * of panels in development mode.
165
+ *
166
+ * In production, this component is a no-op and just renders children.
167
+ */
168
+ export const TabsValidationProvider = VALIDATION_ENABLED
169
+ ? TabsValidationProviderDev
170
+ : TabsValidationProviderProd;
package/src/tabs/list.tsx CHANGED
@@ -21,7 +21,6 @@ export const List = forwardRef< HTMLDivElement, TabListProps >(
21
21
  variant = 'default',
22
22
  className,
23
23
  activateOnFocus,
24
- render,
25
24
  ...otherProps
26
25
  },
27
26
  forwardedRef
@@ -1,6 +1,7 @@
1
1
  import { forwardRef } from '@wordpress/element';
2
2
  import clsx from 'clsx';
3
3
  import { Tabs as _Tabs } from '@base-ui/react/tabs';
4
+ import { useRegisterPanel } from './context';
4
5
  import styles from './style.module.css';
5
6
  import type { TabPanelProps } from './types';
6
7
 
@@ -12,6 +13,8 @@ import type { TabPanelProps } from './types';
12
13
  */
13
14
  export const Panel = forwardRef< HTMLDivElement, TabPanelProps >(
14
15
  function TabPanel( { className, ...otherProps }, forwardedRef ) {
16
+ useRegisterPanel();
17
+
15
18
  return (
16
19
  <_Tabs.Panel
17
20
  ref={ forwardedRef }
package/src/tabs/root.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import { forwardRef } from '@wordpress/element';
2
2
  import { Tabs as _Tabs } from '@base-ui/react/tabs';
3
+ import { TabsValidationProvider } from './context';
3
4
  import type { TabRootProps } from './types';
4
5
 
5
6
  /**
@@ -10,6 +11,10 @@ import type { TabRootProps } from './types';
10
11
  */
11
12
  export const Root = forwardRef< HTMLDivElement, TabRootProps >(
12
13
  function TabsRoot( { ...otherProps }, forwardedRef ) {
13
- return <_Tabs.Root ref={ forwardedRef } { ...otherProps } />;
14
+ return (
15
+ <TabsValidationProvider>
16
+ <_Tabs.Root ref={ forwardedRef } { ...otherProps } />
17
+ </TabsValidationProvider>
18
+ );
14
19
  }
15
20
  );
@@ -119,11 +119,11 @@
119
119
  align-items: center;
120
120
 
121
121
  /* Appearance */
122
- cursor: pointer;
122
+ cursor: var(--wpds-cursor-control);
123
123
 
124
124
  /* Typography */
125
- font-family: var(--wpds-font-family-body);
126
- font-size: var(--wpds-font-size-md);
125
+ font-family: var(--wpds-typography-font-family-body);
126
+ font-size: var(--wpds-typography-font-size-md);
127
127
  white-space: nowrap;
128
128
 
129
129
  /* Characters in some languages (e.g. Japanese) may have a native higher line-height. */
package/src/tabs/tab.tsx CHANGED
@@ -3,6 +3,7 @@ import clsx from 'clsx';
3
3
  import { Tabs as _Tabs } from '@base-ui/react/tabs';
4
4
  import { chevronRight } from '@wordpress/icons';
5
5
  import { Icon } from '../icon';
6
+ import { useRegisterTab } from './context';
6
7
  import styles from './style.module.css';
7
8
  import type { TabProps } from './types';
8
9
 
@@ -16,6 +17,8 @@ export const Tab = forwardRef< HTMLButtonElement, TabProps >( function Tab(
16
17
  { className, children, ...otherProps },
17
18
  forwardedRef
18
19
  ) {
20
+ useRegisterTab();
21
+
19
22
  return (
20
23
  <_Tabs.Tab
21
24
  ref={ forwardedRef }
@@ -2256,5 +2256,167 @@ describe( 'Tabs', () => {
2256
2256
  );
2257
2257
  } );
2258
2258
  } );
2259
+
2260
+ describe( 'Development mode validation', () => {
2261
+ function collectUncaughtErrors() {
2262
+ const errors: Error[] = [];
2263
+ const handler = ( event: ErrorEvent ) => {
2264
+ event.preventDefault();
2265
+ errors.push( event.error );
2266
+ };
2267
+ window.addEventListener( 'error', handler );
2268
+ return {
2269
+ errors,
2270
+ cleanup: () => window.removeEventListener( 'error', handler ),
2271
+ };
2272
+ }
2273
+
2274
+ it( 'should throw when there are more Tabs than Panels', async () => {
2275
+ const { errors, cleanup } = collectUncaughtErrors();
2276
+
2277
+ render(
2278
+ <Tabs.Root defaultValue="one">
2279
+ <Tabs.List>
2280
+ <Tabs.Tab value="one">One</Tabs.Tab>
2281
+ <Tabs.Tab value="two">Two</Tabs.Tab>
2282
+ <Tabs.Tab value="three">Three</Tabs.Tab>
2283
+ </Tabs.List>
2284
+ <Tabs.Panel value="one">First panel</Tabs.Panel>
2285
+ <Tabs.Panel value="two">Second panel</Tabs.Panel>
2286
+ </Tabs.Root>
2287
+ );
2288
+
2289
+ await waitForComponentToBeInitializedWithSelectedTab( 'One' );
2290
+
2291
+ await waitFor( () => {
2292
+ expect( errors.length ).toBeGreaterThan( 0 );
2293
+ } );
2294
+
2295
+ expect( errors[ 0 ].message ).toBe(
2296
+ 'Tabs: Tab/Panel count mismatch (3 Tabs, 2 Panels). Each Tab must be associated with exactly one Panel. Mismatched or missing associations can break screen reader navigation and violate WAI-ARIA Tabs pattern requirements.'
2297
+ );
2298
+
2299
+ cleanup();
2300
+ } );
2301
+
2302
+ it( 'should throw when there are more Panels than Tabs', async () => {
2303
+ const { errors, cleanup } = collectUncaughtErrors();
2304
+
2305
+ render(
2306
+ <Tabs.Root defaultValue="one">
2307
+ <Tabs.List>
2308
+ <Tabs.Tab value="one">One</Tabs.Tab>
2309
+ <Tabs.Tab value="two">Two</Tabs.Tab>
2310
+ </Tabs.List>
2311
+ <Tabs.Panel value="one">First panel</Tabs.Panel>
2312
+ <Tabs.Panel value="two">Second panel</Tabs.Panel>
2313
+ <Tabs.Panel value="three">Third panel</Tabs.Panel>
2314
+ </Tabs.Root>
2315
+ );
2316
+
2317
+ await waitForComponentToBeInitializedWithSelectedTab( 'One' );
2318
+
2319
+ await waitFor( () => {
2320
+ expect( errors.length ).toBeGreaterThan( 0 );
2321
+ } );
2322
+
2323
+ expect( errors[ 0 ].message ).toBe(
2324
+ 'Tabs: Tab/Panel count mismatch (2 Tabs, 3 Panels). Each Tab must be associated with exactly one Panel. Mismatched or missing associations can break screen reader navigation and violate WAI-ARIA Tabs pattern requirements.'
2325
+ );
2326
+
2327
+ cleanup();
2328
+ } );
2329
+
2330
+ it( 'should not throw when Tab and Panel counts match', async () => {
2331
+ const { errors, cleanup } = collectUncaughtErrors();
2332
+
2333
+ render(
2334
+ <Tabs.Root defaultValue="one">
2335
+ <Tabs.List>
2336
+ <Tabs.Tab value="one">One</Tabs.Tab>
2337
+ <Tabs.Tab value="two">Two</Tabs.Tab>
2338
+ </Tabs.List>
2339
+ <Tabs.Panel value="one">First panel</Tabs.Panel>
2340
+ <Tabs.Panel value="two">Second panel</Tabs.Panel>
2341
+ </Tabs.Root>
2342
+ );
2343
+
2344
+ await waitForComponentToBeInitializedWithSelectedTab( 'One' );
2345
+
2346
+ // Wait a bit to ensure validation has run
2347
+ await new Promise( ( resolve ) => setTimeout( resolve, 50 ) );
2348
+
2349
+ expect( errors ).toHaveLength( 0 );
2350
+
2351
+ cleanup();
2352
+ } );
2353
+
2354
+ it( 'should throw when tabs are used without any panels', async () => {
2355
+ const { errors, cleanup } = collectUncaughtErrors();
2356
+
2357
+ render(
2358
+ <Tabs.Root>
2359
+ <Tabs.List>
2360
+ <Tabs.Tab value="one">One</Tabs.Tab>
2361
+ <Tabs.Tab value="two">Two</Tabs.Tab>
2362
+ </Tabs.List>
2363
+ </Tabs.Root>
2364
+ );
2365
+
2366
+ await waitFor( () => {
2367
+ expect( errors.length ).toBeGreaterThan( 0 );
2368
+ } );
2369
+
2370
+ expect( errors[ 0 ].message ).toBe(
2371
+ 'Tabs: Tab/Panel count mismatch (2 Tabs, 0 Panels). Each Tab must be associated with exactly one Panel. Mismatched or missing associations can break screen reader navigation and violate WAI-ARIA Tabs pattern requirements.'
2372
+ );
2373
+
2374
+ cleanup();
2375
+ } );
2376
+
2377
+ it( 'should detect count mismatch after dynamic changes', async () => {
2378
+ const { errors, cleanup } = collectUncaughtErrors();
2379
+
2380
+ const { rerender } = render(
2381
+ <Tabs.Root defaultValue="one">
2382
+ <Tabs.List>
2383
+ <Tabs.Tab value="one">One</Tabs.Tab>
2384
+ <Tabs.Tab value="two">Two</Tabs.Tab>
2385
+ </Tabs.List>
2386
+ <Tabs.Panel value="one">First panel</Tabs.Panel>
2387
+ <Tabs.Panel value="two">Second panel</Tabs.Panel>
2388
+ </Tabs.Root>
2389
+ );
2390
+
2391
+ await waitForComponentToBeInitializedWithSelectedTab( 'One' );
2392
+
2393
+ // Wait for validation
2394
+ await new Promise( ( resolve ) => setTimeout( resolve, 50 ) );
2395
+
2396
+ // No errors since counts match
2397
+ expect( errors ).toHaveLength( 0 );
2398
+
2399
+ // Remove a panel to create a mismatch
2400
+ rerender(
2401
+ <Tabs.Root defaultValue="one">
2402
+ <Tabs.List>
2403
+ <Tabs.Tab value="one">One</Tabs.Tab>
2404
+ <Tabs.Tab value="two">Two</Tabs.Tab>
2405
+ </Tabs.List>
2406
+ <Tabs.Panel value="one">First panel</Tabs.Panel>
2407
+ </Tabs.Root>
2408
+ );
2409
+
2410
+ await waitFor( () => {
2411
+ expect( errors.length ).toBeGreaterThan( 0 );
2412
+ } );
2413
+
2414
+ expect( errors[ 0 ].message ).toBe(
2415
+ 'Tabs: Tab/Panel count mismatch (2 Tabs, 1 Panels). Each Tab must be associated with exactly one Panel. Mismatched or missing associations can break screen reader navigation and violate WAI-ARIA Tabs pattern requirements.'
2416
+ );
2417
+
2418
+ cleanup();
2419
+ } );
2420
+ } );
2259
2421
  } );
2260
2422
  /* eslint-enable jest/no-conditional-expect */
@@ -1,4 +1,3 @@
1
- /* eslint-disable jsx-a11y/heading-has-content */
2
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
3
2
  import { Text } from '../index';
4
3
  import { Stack } from '../../stack';
@@ -18,6 +17,10 @@ export const Default: Story = {
18
17
  },
19
18
  };
20
19
 
20
+ /**
21
+ * Important: Setting the `variant` prop to a `heading` variant will not automatically render a heading element.
22
+ * Use the `render` prop to render a heading element with the appropriate level.
23
+ */
21
24
  export const AllVariants: Story = {
22
25
  render: () => (
23
26
  <Stack
@@ -65,4 +68,3 @@ export const WithRenderProp: Story = {
65
68
  </Stack>
66
69
  ),
67
70
  };
68
- /* eslint-enable jsx-a11y/heading-has-content */