@wordpress/ui 0.9.1-next.v.202603102151.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 (529) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/CONTRIBUTING.md +31 -0
  3. package/README.md +106 -0
  4. package/build/alert-dialog/context.cjs +34 -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 +93 -0
  9. package/build/alert-dialog/popup.cjs.map +7 -0
  10. package/build/alert-dialog/root.cjs +52 -0
  11. package/build/alert-dialog/root.cjs.map +7 -0
  12. package/build/alert-dialog/trigger.cjs +48 -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 +3 -3
  17. package/build/badge/badge.cjs.map +2 -2
  18. package/build/button/button.cjs +9 -9
  19. package/build/button/button.cjs.map +2 -2
  20. package/build/card/content.cjs +3 -3
  21. package/build/card/content.cjs.map +2 -2
  22. package/build/card/full-bleed.cjs +3 -3
  23. package/build/card/full-bleed.cjs.map +2 -2
  24. package/build/card/header.cjs +3 -3
  25. package/build/card/header.cjs.map +2 -2
  26. package/build/card/root.cjs +5 -5
  27. package/build/card/root.cjs.map +2 -2
  28. package/build/card/title.cjs +26 -13
  29. package/build/card/title.cjs.map +3 -3
  30. package/build/collapsible/index.cjs +37 -0
  31. package/build/collapsible/index.cjs.map +7 -0
  32. package/build/collapsible/panel.cjs +38 -0
  33. package/build/collapsible/panel.cjs.map +7 -0
  34. package/build/collapsible/root.cjs +38 -0
  35. package/build/collapsible/root.cjs.map +7 -0
  36. package/build/collapsible/trigger.cjs +38 -0
  37. package/build/collapsible/trigger.cjs.map +7 -0
  38. package/build/collapsible/types.cjs +19 -0
  39. package/build/collapsible/types.cjs.map +7 -0
  40. package/build/collapsible-card/content.cjs +26 -5
  41. package/build/collapsible-card/content.cjs.map +4 -4
  42. package/build/collapsible-card/context.cjs +35 -0
  43. package/build/collapsible-card/context.cjs.map +7 -0
  44. package/build/collapsible-card/header-description.cjs +52 -0
  45. package/build/collapsible-card/header-description.cjs.map +7 -0
  46. package/build/collapsible-card/header.cjs +57 -38
  47. package/build/collapsible-card/header.cjs.map +3 -3
  48. package/build/collapsible-card/index.cjs +3 -0
  49. package/build/collapsible-card/index.cjs.map +2 -2
  50. package/build/collapsible-card/root.cjs +4 -4
  51. package/build/collapsible-card/root.cjs.map +2 -2
  52. package/build/collapsible-card/types.cjs.map +1 -1
  53. package/build/dialog/action.cjs +4 -2
  54. package/build/dialog/action.cjs.map +2 -2
  55. package/build/dialog/close-icon.cjs +2 -1
  56. package/build/dialog/close-icon.cjs.map +2 -2
  57. package/build/dialog/footer.cjs +3 -3
  58. package/build/dialog/footer.cjs.map +2 -2
  59. package/build/dialog/header.cjs +3 -3
  60. package/build/dialog/header.cjs.map +2 -2
  61. package/build/dialog/popup.cjs +22 -5
  62. package/build/dialog/popup.cjs.map +2 -2
  63. package/build/dialog/title.cjs +3 -3
  64. package/build/dialog/title.cjs.map +2 -2
  65. package/build/dialog/types.cjs.map +1 -1
  66. package/build/empty-state/actions.cjs +66 -0
  67. package/build/empty-state/actions.cjs.map +7 -0
  68. package/build/empty-state/description.cjs +66 -0
  69. package/build/empty-state/description.cjs.map +7 -0
  70. package/build/empty-state/icon.cjs +69 -0
  71. package/build/empty-state/icon.cjs.map +7 -0
  72. package/build/empty-state/index.cjs +46 -0
  73. package/build/empty-state/index.cjs.map +7 -0
  74. package/build/empty-state/root.cjs +66 -0
  75. package/build/empty-state/root.cjs.map +7 -0
  76. package/build/empty-state/title.cjs +68 -0
  77. package/build/empty-state/title.cjs.map +7 -0
  78. package/build/empty-state/types.cjs +19 -0
  79. package/build/empty-state/types.cjs.map +7 -0
  80. package/build/empty-state/visual.cjs +66 -0
  81. package/build/empty-state/visual.cjs.map +7 -0
  82. package/build/form/index.cjs +27 -0
  83. package/build/form/index.cjs.map +7 -0
  84. package/build/form/input-control/index.cjs +31 -0
  85. package/build/form/input-control/index.cjs.map +7 -0
  86. package/build/form/input-control/input-control.cjs +50 -0
  87. package/build/form/input-control/input-control.cjs.map +7 -0
  88. package/build/form/input-control/types.cjs +19 -0
  89. package/build/form/input-control/types.cjs.map +7 -0
  90. package/build/form/primitives/field/description.cjs +2 -2
  91. package/build/form/primitives/field/description.cjs.map +1 -1
  92. package/build/form/primitives/field/details.cjs +2 -2
  93. package/build/form/primitives/field/details.cjs.map +1 -1
  94. package/build/form/primitives/field/label.cjs +2 -2
  95. package/build/form/primitives/field/label.cjs.map +1 -1
  96. package/build/form/primitives/field/root.cjs +4 -4
  97. package/build/form/primitives/field/root.cjs.map +2 -2
  98. package/build/form/primitives/fieldset/description.cjs +2 -2
  99. package/build/form/primitives/fieldset/description.cjs.map +1 -1
  100. package/build/form/primitives/fieldset/details.cjs +2 -2
  101. package/build/form/primitives/fieldset/details.cjs.map +1 -1
  102. package/build/form/primitives/fieldset/legend.cjs +2 -2
  103. package/build/form/primitives/fieldset/legend.cjs.map +1 -1
  104. package/build/form/primitives/fieldset/root.cjs +2 -2
  105. package/build/form/primitives/fieldset/root.cjs.map +1 -1
  106. package/build/form/primitives/input/input.cjs +6 -6
  107. package/build/form/primitives/input/input.cjs.map +2 -2
  108. package/build/form/primitives/input-layout/input-layout.cjs +4 -4
  109. package/build/form/primitives/input-layout/input-layout.cjs.map +1 -1
  110. package/build/form/primitives/input-layout/slot.cjs +5 -4
  111. package/build/form/primitives/input-layout/slot.cjs.map +2 -2
  112. package/build/form/primitives/select/item.cjs +5 -5
  113. package/build/form/primitives/select/item.cjs.map +2 -2
  114. package/build/form/primitives/select/popup.cjs +7 -7
  115. package/build/form/primitives/select/popup.cjs.map +2 -2
  116. package/build/form/primitives/select/trigger.cjs +7 -7
  117. package/build/form/primitives/select/trigger.cjs.map +2 -2
  118. package/build/form/primitives/textarea/textarea.cjs +3 -3
  119. package/build/form/primitives/textarea/textarea.cjs.map +2 -2
  120. package/build/form/types.cjs +19 -0
  121. package/build/form/types.cjs.map +7 -0
  122. package/build/icon-button/icon-button.cjs +2 -2
  123. package/build/icon-button/icon-button.cjs.map +1 -1
  124. package/build/index.cjs +11 -2
  125. package/build/index.cjs.map +2 -2
  126. package/build/link/link.cjs +8 -8
  127. package/build/link/link.cjs.map +2 -2
  128. package/build/notice/action-button.cjs +2 -2
  129. package/build/notice/action-button.cjs.map +1 -1
  130. package/build/notice/action-link.cjs +2 -2
  131. package/build/notice/action-link.cjs.map +1 -1
  132. package/build/notice/actions.cjs +2 -2
  133. package/build/notice/actions.cjs.map +1 -1
  134. package/build/notice/close-icon.cjs +2 -2
  135. package/build/notice/close-icon.cjs.map +1 -1
  136. package/build/notice/description.cjs +2 -2
  137. package/build/notice/description.cjs.map +1 -1
  138. package/build/notice/index.cjs.map +1 -1
  139. package/build/notice/root.cjs +4 -4
  140. package/build/notice/root.cjs.map +1 -1
  141. package/build/notice/title.cjs +2 -2
  142. package/build/notice/title.cjs.map +1 -1
  143. package/build/stack/stack.cjs +2 -2
  144. package/build/stack/stack.cjs.map +1 -1
  145. package/build/tabs/context.cjs +121 -0
  146. package/build/tabs/context.cjs.map +7 -0
  147. package/build/tabs/list.cjs +3 -3
  148. package/build/tabs/list.cjs.map +2 -2
  149. package/build/tabs/panel.cjs +5 -3
  150. package/build/tabs/panel.cjs.map +2 -2
  151. package/build/tabs/root.cjs +2 -1
  152. package/build/tabs/root.cjs.map +2 -2
  153. package/build/tabs/tab.cjs +5 -3
  154. package/build/tabs/tab.cjs.map +2 -2
  155. package/build/text/text.cjs +2 -2
  156. package/build/text/text.cjs.map +1 -1
  157. package/build/tooltip/popup.cjs +4 -4
  158. package/build/tooltip/popup.cjs.map +1 -1
  159. package/build/tooltip/root.cjs.map +2 -2
  160. package/build/utils/use-deprioritized-initial-focus.cjs +64 -0
  161. package/build/utils/use-deprioritized-initial-focus.cjs.map +7 -0
  162. package/build/visually-hidden/visually-hidden.cjs +2 -2
  163. package/build/visually-hidden/visually-hidden.cjs.map +1 -1
  164. package/build-module/alert-dialog/context.mjs +9 -0
  165. package/build-module/alert-dialog/context.mjs.map +7 -0
  166. package/build-module/alert-dialog/index.mjs +10 -0
  167. package/build-module/alert-dialog/index.mjs.map +7 -0
  168. package/build-module/alert-dialog/popup.mjs +58 -0
  169. package/build-module/alert-dialog/popup.mjs.map +7 -0
  170. package/build-module/alert-dialog/root.mjs +27 -0
  171. package/build-module/alert-dialog/root.mjs.map +7 -0
  172. package/build-module/alert-dialog/trigger.mjs +13 -0
  173. package/build-module/alert-dialog/trigger.mjs.map +7 -0
  174. package/build-module/alert-dialog/types.mjs +1 -0
  175. package/build-module/alert-dialog/types.mjs.map +7 -0
  176. package/build-module/badge/badge.mjs +3 -3
  177. package/build-module/badge/badge.mjs.map +2 -2
  178. package/build-module/button/button.mjs +9 -9
  179. package/build-module/button/button.mjs.map +2 -2
  180. package/build-module/card/content.mjs +3 -3
  181. package/build-module/card/content.mjs.map +2 -2
  182. package/build-module/card/full-bleed.mjs +3 -3
  183. package/build-module/card/full-bleed.mjs.map +2 -2
  184. package/build-module/card/header.mjs +3 -3
  185. package/build-module/card/header.mjs.map +2 -2
  186. package/build-module/card/root.mjs +5 -5
  187. package/build-module/card/root.mjs.map +2 -2
  188. package/build-module/card/title.mjs +16 -13
  189. package/build-module/card/title.mjs.map +2 -2
  190. package/build-module/collapsible/index.mjs +10 -0
  191. package/build-module/collapsible/index.mjs.map +7 -0
  192. package/build-module/collapsible/panel.mjs +13 -0
  193. package/build-module/collapsible/panel.mjs.map +7 -0
  194. package/build-module/collapsible/root.mjs +13 -0
  195. package/build-module/collapsible/root.mjs.map +7 -0
  196. package/build-module/collapsible/trigger.mjs +13 -0
  197. package/build-module/collapsible/trigger.mjs.map +7 -0
  198. package/build-module/collapsible/types.mjs +1 -0
  199. package/build-module/collapsible/types.mjs.map +7 -0
  200. package/build-module/collapsible-card/content.mjs +25 -4
  201. package/build-module/collapsible-card/content.mjs.map +3 -3
  202. package/build-module/collapsible-card/context.mjs +10 -0
  203. package/build-module/collapsible-card/context.mjs.map +7 -0
  204. package/build-module/collapsible-card/header-description.mjs +27 -0
  205. package/build-module/collapsible-card/header-description.mjs.map +7 -0
  206. package/build-module/collapsible-card/header.mjs +59 -40
  207. package/build-module/collapsible-card/header.mjs.map +3 -3
  208. package/build-module/collapsible-card/index.mjs +2 -0
  209. package/build-module/collapsible-card/index.mjs.map +2 -2
  210. package/build-module/collapsible-card/root.mjs +3 -3
  211. package/build-module/collapsible-card/root.mjs.map +2 -2
  212. package/build-module/dialog/action.mjs +4 -2
  213. package/build-module/dialog/action.mjs.map +2 -2
  214. package/build-module/dialog/close-icon.mjs +2 -1
  215. package/build-module/dialog/close-icon.mjs.map +2 -2
  216. package/build-module/dialog/footer.mjs +3 -3
  217. package/build-module/dialog/footer.mjs.map +2 -2
  218. package/build-module/dialog/header.mjs +3 -3
  219. package/build-module/dialog/header.mjs.map +2 -2
  220. package/build-module/dialog/popup.mjs +22 -5
  221. package/build-module/dialog/popup.mjs.map +2 -2
  222. package/build-module/dialog/title.mjs +3 -3
  223. package/build-module/dialog/title.mjs.map +2 -2
  224. package/build-module/empty-state/actions.mjs +31 -0
  225. package/build-module/empty-state/actions.mjs.map +7 -0
  226. package/build-module/empty-state/description.mjs +31 -0
  227. package/build-module/empty-state/description.mjs.map +7 -0
  228. package/build-module/empty-state/icon.mjs +34 -0
  229. package/build-module/empty-state/icon.mjs.map +7 -0
  230. package/build-module/empty-state/index.mjs +16 -0
  231. package/build-module/empty-state/index.mjs.map +7 -0
  232. package/build-module/empty-state/root.mjs +31 -0
  233. package/build-module/empty-state/root.mjs.map +7 -0
  234. package/build-module/empty-state/title.mjs +33 -0
  235. package/build-module/empty-state/title.mjs.map +7 -0
  236. package/build-module/empty-state/types.mjs +1 -0
  237. package/build-module/empty-state/types.mjs.map +7 -0
  238. package/build-module/empty-state/visual.mjs +31 -0
  239. package/build-module/empty-state/visual.mjs.map +7 -0
  240. package/build-module/form/index.mjs +4 -0
  241. package/build-module/form/index.mjs.map +7 -0
  242. package/build-module/form/input-control/index.mjs +6 -0
  243. package/build-module/form/input-control/index.mjs.map +7 -0
  244. package/build-module/form/input-control/input-control.mjs +25 -0
  245. package/build-module/form/input-control/input-control.mjs.map +7 -0
  246. package/build-module/form/input-control/types.mjs +1 -0
  247. package/build-module/form/input-control/types.mjs.map +7 -0
  248. package/build-module/form/primitives/field/description.mjs +2 -2
  249. package/build-module/form/primitives/field/description.mjs.map +1 -1
  250. package/build-module/form/primitives/field/details.mjs +2 -2
  251. package/build-module/form/primitives/field/details.mjs.map +1 -1
  252. package/build-module/form/primitives/field/label.mjs +2 -2
  253. package/build-module/form/primitives/field/label.mjs.map +1 -1
  254. package/build-module/form/primitives/field/root.mjs +4 -4
  255. package/build-module/form/primitives/field/root.mjs.map +2 -2
  256. package/build-module/form/primitives/fieldset/description.mjs +2 -2
  257. package/build-module/form/primitives/fieldset/description.mjs.map +1 -1
  258. package/build-module/form/primitives/fieldset/details.mjs +2 -2
  259. package/build-module/form/primitives/fieldset/details.mjs.map +1 -1
  260. package/build-module/form/primitives/fieldset/legend.mjs +2 -2
  261. package/build-module/form/primitives/fieldset/legend.mjs.map +1 -1
  262. package/build-module/form/primitives/fieldset/root.mjs +2 -2
  263. package/build-module/form/primitives/fieldset/root.mjs.map +1 -1
  264. package/build-module/form/primitives/input/input.mjs +6 -6
  265. package/build-module/form/primitives/input/input.mjs.map +2 -2
  266. package/build-module/form/primitives/input-layout/input-layout.mjs +4 -4
  267. package/build-module/form/primitives/input-layout/input-layout.mjs.map +1 -1
  268. package/build-module/form/primitives/input-layout/slot.mjs +5 -4
  269. package/build-module/form/primitives/input-layout/slot.mjs.map +2 -2
  270. package/build-module/form/primitives/select/item.mjs +5 -5
  271. package/build-module/form/primitives/select/item.mjs.map +2 -2
  272. package/build-module/form/primitives/select/popup.mjs +7 -7
  273. package/build-module/form/primitives/select/popup.mjs.map +2 -2
  274. package/build-module/form/primitives/select/trigger.mjs +7 -7
  275. package/build-module/form/primitives/select/trigger.mjs.map +2 -2
  276. package/build-module/form/primitives/textarea/textarea.mjs +3 -3
  277. package/build-module/form/primitives/textarea/textarea.mjs.map +2 -2
  278. package/build-module/form/types.mjs +1 -0
  279. package/build-module/form/types.mjs.map +7 -0
  280. package/build-module/icon-button/icon-button.mjs +2 -2
  281. package/build-module/icon-button/icon-button.mjs.map +1 -1
  282. package/build-module/index.mjs +7 -1
  283. package/build-module/index.mjs.map +2 -2
  284. package/build-module/link/link.mjs +8 -8
  285. package/build-module/link/link.mjs.map +2 -2
  286. package/build-module/notice/action-button.mjs +2 -2
  287. package/build-module/notice/action-button.mjs.map +1 -1
  288. package/build-module/notice/action-link.mjs +2 -2
  289. package/build-module/notice/action-link.mjs.map +1 -1
  290. package/build-module/notice/actions.mjs +2 -2
  291. package/build-module/notice/actions.mjs.map +1 -1
  292. package/build-module/notice/close-icon.mjs +2 -2
  293. package/build-module/notice/close-icon.mjs.map +1 -1
  294. package/build-module/notice/description.mjs +2 -2
  295. package/build-module/notice/description.mjs.map +1 -1
  296. package/build-module/notice/index.mjs.map +1 -1
  297. package/build-module/notice/root.mjs +4 -4
  298. package/build-module/notice/root.mjs.map +1 -1
  299. package/build-module/notice/title.mjs +2 -2
  300. package/build-module/notice/title.mjs.map +1 -1
  301. package/build-module/stack/stack.mjs +2 -2
  302. package/build-module/stack/stack.mjs.map +1 -1
  303. package/build-module/tabs/context.mjs +101 -0
  304. package/build-module/tabs/context.mjs.map +7 -0
  305. package/build-module/tabs/list.mjs +3 -3
  306. package/build-module/tabs/list.mjs.map +2 -2
  307. package/build-module/tabs/panel.mjs +5 -3
  308. package/build-module/tabs/panel.mjs.map +2 -2
  309. package/build-module/tabs/root.mjs +2 -1
  310. package/build-module/tabs/root.mjs.map +2 -2
  311. package/build-module/tabs/tab.mjs +5 -3
  312. package/build-module/tabs/tab.mjs.map +2 -2
  313. package/build-module/text/text.mjs +2 -2
  314. package/build-module/text/text.mjs.map +1 -1
  315. package/build-module/tooltip/popup.mjs +4 -4
  316. package/build-module/tooltip/popup.mjs.map +1 -1
  317. package/build-module/tooltip/root.mjs.map +2 -2
  318. package/build-module/utils/use-deprioritized-initial-focus.mjs +39 -0
  319. package/build-module/utils/use-deprioritized-initial-focus.mjs.map +7 -0
  320. package/build-module/visually-hidden/visually-hidden.mjs +2 -2
  321. package/build-module/visually-hidden/visually-hidden.mjs.map +1 -1
  322. package/build-types/alert-dialog/context.d.ts +8 -0
  323. package/build-types/alert-dialog/context.d.ts.map +1 -0
  324. package/build-types/alert-dialog/index.d.ts +4 -0
  325. package/build-types/alert-dialog/index.d.ts.map +1 -0
  326. package/build-types/alert-dialog/popup.d.ts +4 -0
  327. package/build-types/alert-dialog/popup.d.ts.map +1 -0
  328. package/build-types/alert-dialog/root.d.ts +24 -0
  329. package/build-types/alert-dialog/root.d.ts.map +1 -0
  330. package/build-types/alert-dialog/stories/index.story.d.ts +44 -0
  331. package/build-types/alert-dialog/stories/index.story.d.ts.map +1 -0
  332. package/build-types/alert-dialog/test/index.test.d.ts +2 -0
  333. package/build-types/alert-dialog/test/index.test.d.ts.map +1 -0
  334. package/build-types/alert-dialog/trigger.d.ts +6 -0
  335. package/build-types/alert-dialog/trigger.d.ts.map +1 -0
  336. package/build-types/alert-dialog/types.d.ts +70 -0
  337. package/build-types/alert-dialog/types.d.ts.map +1 -0
  338. package/build-types/card/title.d.ts.map +1 -1
  339. package/build-types/collapsible/index.d.ts +5 -0
  340. package/build-types/collapsible/index.d.ts.map +1 -0
  341. package/build-types/collapsible/panel.d.ts +16 -0
  342. package/build-types/collapsible/panel.d.ts.map +1 -0
  343. package/build-types/collapsible/root.d.ts +15 -0
  344. package/build-types/collapsible/root.d.ts.map +1 -0
  345. package/build-types/collapsible/stories/index.story.d.ts +18 -0
  346. package/build-types/collapsible/stories/index.story.d.ts.map +1 -0
  347. package/build-types/collapsible/test/index.test.d.ts +2 -0
  348. package/build-types/collapsible/test/index.test.d.ts.map +1 -0
  349. package/build-types/collapsible/trigger.d.ts +15 -0
  350. package/build-types/collapsible/trigger.d.ts.map +1 -0
  351. package/build-types/collapsible/types.d.ts +22 -0
  352. package/build-types/collapsible/types.d.ts.map +1 -0
  353. package/build-types/collapsible-card/content.d.ts.map +1 -1
  354. package/build-types/collapsible-card/context.d.ts +4 -0
  355. package/build-types/collapsible-card/context.d.ts.map +1 -0
  356. package/build-types/collapsible-card/header-description.d.ts +15 -0
  357. package/build-types/collapsible-card/header-description.d.ts.map +1 -0
  358. package/build-types/collapsible-card/header.d.ts.map +1 -1
  359. package/build-types/collapsible-card/index.d.ts +2 -1
  360. package/build-types/collapsible-card/index.d.ts.map +1 -1
  361. package/build-types/collapsible-card/stories/index.story.d.ts +10 -0
  362. package/build-types/collapsible-card/stories/index.story.d.ts.map +1 -1
  363. package/build-types/collapsible-card/types.d.ts +21 -0
  364. package/build-types/collapsible-card/types.d.ts.map +1 -1
  365. package/build-types/dialog/action.d.ts.map +1 -1
  366. package/build-types/dialog/close-icon.d.ts.map +1 -1
  367. package/build-types/dialog/popup.d.ts.map +1 -1
  368. package/build-types/dialog/stories/index.story.d.ts +0 -6
  369. package/build-types/dialog/stories/index.story.d.ts.map +1 -1
  370. package/build-types/dialog/types.d.ts +5 -5
  371. package/build-types/dialog/types.d.ts.map +1 -1
  372. package/build-types/empty-state/actions.d.ts +7 -0
  373. package/build-types/empty-state/actions.d.ts.map +1 -0
  374. package/build-types/empty-state/description.d.ts +7 -0
  375. package/build-types/empty-state/description.d.ts.map +1 -0
  376. package/build-types/empty-state/icon.d.ts +7 -0
  377. package/build-types/empty-state/icon.d.ts.map +1 -0
  378. package/build-types/empty-state/index.d.ts +8 -0
  379. package/build-types/empty-state/index.d.ts.map +1 -0
  380. package/build-types/empty-state/root.d.ts +6 -0
  381. package/build-types/empty-state/root.d.ts.map +1 -0
  382. package/build-types/empty-state/stories/index.story.d.ts +8 -0
  383. package/build-types/empty-state/stories/index.story.d.ts.map +1 -0
  384. package/build-types/empty-state/test/actions.test.d.ts +2 -0
  385. package/build-types/empty-state/test/actions.test.d.ts.map +1 -0
  386. package/build-types/empty-state/test/description.test.d.ts +2 -0
  387. package/build-types/empty-state/test/description.test.d.ts.map +1 -0
  388. package/build-types/empty-state/test/icon.test.d.ts +2 -0
  389. package/build-types/empty-state/test/icon.test.d.ts.map +1 -0
  390. package/build-types/empty-state/test/root.test.d.ts +2 -0
  391. package/build-types/empty-state/test/root.test.d.ts.map +1 -0
  392. package/build-types/empty-state/test/title.test.d.ts +2 -0
  393. package/build-types/empty-state/test/title.test.d.ts.map +1 -0
  394. package/build-types/empty-state/test/visual.test.d.ts +2 -0
  395. package/build-types/empty-state/test/visual.test.d.ts.map +1 -0
  396. package/build-types/empty-state/title.d.ts +6 -0
  397. package/build-types/empty-state/title.d.ts.map +1 -0
  398. package/build-types/empty-state/types.d.ts +40 -0
  399. package/build-types/empty-state/types.d.ts.map +1 -0
  400. package/build-types/empty-state/visual.d.ts +7 -0
  401. package/build-types/empty-state/visual.d.ts.map +1 -0
  402. package/build-types/form/index.d.ts +3 -0
  403. package/build-types/form/index.d.ts.map +1 -0
  404. package/build-types/form/input-control/index.d.ts +2 -0
  405. package/build-types/form/input-control/index.d.ts.map +1 -0
  406. package/build-types/form/input-control/input-control.d.ts +6 -0
  407. package/build-types/form/input-control/input-control.d.ts.map +1 -0
  408. package/build-types/form/input-control/stories/index.story.d.ts +16 -0
  409. package/build-types/form/input-control/stories/index.story.d.ts.map +1 -0
  410. package/build-types/form/input-control/test/index.test.d.ts +2 -0
  411. package/build-types/form/input-control/test/index.test.d.ts.map +1 -0
  412. package/build-types/form/input-control/types.d.ts +4 -0
  413. package/build-types/form/input-control/types.d.ts.map +1 -0
  414. package/build-types/form/primitives/field/stories/index.story.d.ts.map +1 -1
  415. package/build-types/form/primitives/fieldset/stories/index.story.d.ts.map +1 -1
  416. package/build-types/form/primitives/input/stories/index.story.d.ts +2 -0
  417. package/build-types/form/primitives/input/stories/index.story.d.ts.map +1 -1
  418. package/build-types/form/primitives/input-layout/slot.d.ts.map +1 -1
  419. package/build-types/form/primitives/input-layout/stories/index.story.d.ts +5 -0
  420. package/build-types/form/primitives/input-layout/stories/index.story.d.ts.map +1 -1
  421. package/build-types/form/stories/shared.d.ts +3 -0
  422. package/build-types/form/stories/shared.d.ts.map +1 -0
  423. package/build-types/form/types.d.ts +30 -0
  424. package/build-types/form/types.d.ts.map +1 -0
  425. package/build-types/index.d.ts +4 -1
  426. package/build-types/index.d.ts.map +1 -1
  427. package/build-types/notice/index.d.ts +0 -1
  428. package/build-types/notice/index.d.ts.map +1 -1
  429. package/build-types/tabs/context.d.ts +26 -0
  430. package/build-types/tabs/context.d.ts.map +1 -0
  431. package/build-types/tabs/panel.d.ts.map +1 -1
  432. package/build-types/tabs/root.d.ts.map +1 -1
  433. package/build-types/tabs/tab.d.ts.map +1 -1
  434. package/build-types/tooltip/root.d.ts +12 -0
  435. package/build-types/tooltip/root.d.ts.map +1 -1
  436. package/build-types/tooltip/stories/index.story.d.ts.map +1 -1
  437. package/build-types/utils/test/use-deprioritized-initial-focus.test.d.ts +2 -0
  438. package/build-types/utils/test/use-deprioritized-initial-focus.test.d.ts.map +1 -0
  439. package/build-types/utils/use-deprioritized-initial-focus.d.ts +35 -0
  440. package/build-types/utils/use-deprioritized-initial-focus.d.ts.map +1 -0
  441. package/package.json +17 -16
  442. package/src/alert-dialog/context.tsx +14 -0
  443. package/src/alert-dialog/index.ts +3 -0
  444. package/src/alert-dialog/popup.tsx +58 -0
  445. package/src/alert-dialog/root.tsx +48 -0
  446. package/src/alert-dialog/stories/index.story.tsx +254 -0
  447. package/src/alert-dialog/style.module.css +10 -0
  448. package/src/alert-dialog/test/index.test.tsx +537 -0
  449. package/src/alert-dialog/trigger.tsx +15 -0
  450. package/src/alert-dialog/types.ts +83 -0
  451. package/src/badge/style.module.css +5 -2
  452. package/src/button/style.module.css +2 -0
  453. package/src/card/stories/index.story.tsx +1 -1
  454. package/src/card/style.module.css +5 -7
  455. package/src/card/title.tsx +12 -11
  456. package/src/collapsible/index.ts +5 -0
  457. package/src/collapsible/panel.tsx +16 -0
  458. package/src/collapsible/root.tsx +15 -0
  459. package/src/collapsible/stories/index.story.tsx +108 -0
  460. package/src/collapsible/test/index.test.tsx +228 -0
  461. package/src/collapsible/trigger.tsx +15 -0
  462. package/src/collapsible/types.ts +24 -0
  463. package/src/collapsible-card/content.tsx +17 -4
  464. package/src/collapsible-card/context.ts +7 -0
  465. package/src/collapsible-card/header-description.tsx +43 -0
  466. package/src/collapsible-card/header.tsx +50 -45
  467. package/src/collapsible-card/index.ts +2 -1
  468. package/src/collapsible-card/root.tsx +1 -1
  469. package/src/collapsible-card/stories/index.story.tsx +99 -1
  470. package/src/collapsible-card/style.module.css +49 -4
  471. package/src/collapsible-card/test/index.test.tsx +107 -40
  472. package/src/collapsible-card/types.ts +22 -0
  473. package/src/dialog/action.tsx +8 -2
  474. package/src/dialog/close-icon.tsx +1 -0
  475. package/src/dialog/popup.tsx +21 -2
  476. package/src/dialog/stories/index.story.tsx +0 -28
  477. package/src/dialog/style.module.css +5 -5
  478. package/src/dialog/test/index.test.tsx +117 -0
  479. package/src/dialog/types.ts +11 -5
  480. package/src/empty-state/actions.tsx +24 -0
  481. package/src/empty-state/description.tsx +27 -0
  482. package/src/empty-state/icon.tsx +24 -0
  483. package/src/empty-state/index.ts +8 -0
  484. package/src/empty-state/root.tsx +23 -0
  485. package/src/empty-state/stories/index.story.tsx +64 -0
  486. package/src/empty-state/style.module.css +53 -0
  487. package/src/empty-state/test/actions.test.tsx +18 -0
  488. package/src/empty-state/test/description.test.tsx +13 -0
  489. package/src/empty-state/test/icon.test.tsx +13 -0
  490. package/src/empty-state/test/root.test.tsx +13 -0
  491. package/src/empty-state/test/title.test.tsx +13 -0
  492. package/src/empty-state/test/visual.test.tsx +17 -0
  493. package/src/empty-state/title.tsx +23 -0
  494. package/src/empty-state/types.ts +45 -0
  495. package/src/empty-state/visual.tsx +24 -0
  496. package/src/form/index.ts +3 -0
  497. package/src/form/input-control/index.ts +1 -0
  498. package/src/form/input-control/input-control.tsx +33 -0
  499. package/src/form/input-control/stories/index.story.tsx +163 -0
  500. package/src/form/input-control/test/index.test.tsx +53 -0
  501. package/src/form/input-control/types.ts +5 -0
  502. package/src/form/primitives/field/root.tsx +2 -2
  503. package/src/form/primitives/field/stories/index.story.tsx +2 -7
  504. package/src/form/primitives/fieldset/stories/index.story.tsx +2 -7
  505. package/src/form/primitives/input/stories/index.story.tsx +7 -0
  506. package/src/form/primitives/input-layout/slot.tsx +6 -2
  507. package/src/form/primitives/input-layout/stories/index.story.tsx +22 -1
  508. package/src/form/primitives/stories/overview.mdx +15 -0
  509. package/src/form/primitives/textarea/textarea.tsx +1 -1
  510. package/src/form/stories/shared.tsx +19 -0
  511. package/src/form/types.ts +34 -0
  512. package/src/index.ts +4 -1
  513. package/src/notice/index.ts +0 -2
  514. package/src/notice/style.module.css +1 -1
  515. package/src/tabs/context.tsx +170 -0
  516. package/src/tabs/panel.tsx +3 -0
  517. package/src/tabs/root.tsx +6 -1
  518. package/src/tabs/style.module.css +1 -1
  519. package/src/tabs/tab.tsx +3 -0
  520. package/src/tabs/test/index.test.tsx +162 -0
  521. package/src/tooltip/root.tsx +12 -0
  522. package/src/tooltip/stories/index.story.tsx +20 -15
  523. package/src/utils/css/focus.module.css +4 -2
  524. package/src/utils/css/item-popup.module.css +1 -0
  525. package/src/utils/css/select-trigger.module.css +1 -0
  526. package/src/utils/test/use-deprioritized-initial-focus.test.tsx +230 -0
  527. package/src/utils/use-deprioritized-initial-focus.ts +83 -0
  528. package/AGENTS.md +0 -9
  529. package/CLAUDE.md +0 -1
@@ -0,0 +1,163 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from '@wordpress/element';
3
+ import { plus, reset, seen, unseen } from '@wordpress/icons';
4
+ import { IconButton, InputControl, InputLayout, Stack } from '../../..';
5
+ import {
6
+ WithPrefix,
7
+ WithSuffixControl,
8
+ } from '../../primitives/input/stories/index.story';
9
+ import {
10
+ WITH_DETAILS_DESCRIPTION,
11
+ DETAILS_EXAMPLE,
12
+ } from '../../stories/shared';
13
+
14
+ const meta: Meta< typeof InputControl > = {
15
+ title: 'Design System/Components/Form/InputControl',
16
+ component: InputControl,
17
+ argTypes: {
18
+ defaultValue: { control: false },
19
+ onValueChange: { action: 'onValueChange' },
20
+ value: { control: false },
21
+ type: { control: 'text' },
22
+ },
23
+ };
24
+ export default meta;
25
+
26
+ type Story = StoryObj< typeof InputControl >;
27
+
28
+ export const Default: Story = {
29
+ args: {
30
+ label: 'Label',
31
+ description: 'This is the description.',
32
+ placeholder: 'Placeholder',
33
+ },
34
+ };
35
+
36
+ export const VisuallyHiddenLabel: Story = {
37
+ args: {
38
+ ...Default.args,
39
+ hideLabelFromVision: true,
40
+ },
41
+ };
42
+
43
+ export const WithDetails: Story = {
44
+ parameters: {
45
+ docs: { description: { story: WITH_DETAILS_DESCRIPTION } },
46
+ },
47
+ args: {
48
+ ...Default.args,
49
+ description: undefined,
50
+ details: DETAILS_EXAMPLE,
51
+ },
52
+ };
53
+
54
+ WithPrefix.args = {
55
+ ...WithPrefix.args,
56
+ ...Default.args,
57
+ };
58
+ WithSuffixControl.args = {
59
+ ...WithSuffixControl.args,
60
+ ...Default.args,
61
+ };
62
+ export { WithPrefix, WithSuffixControl };
63
+
64
+ export const Password: Story = {
65
+ render: function Template( args ) {
66
+ const [ show, setShow ] = useState( false );
67
+
68
+ return (
69
+ <InputControl
70
+ { ...args }
71
+ type={ show ? 'text' : 'password' }
72
+ suffix={
73
+ <InputLayout.Slot padding="minimal">
74
+ <IconButton
75
+ label={ show ? 'Hide password' : 'Show password' }
76
+ onClick={ () => setShow( ! show ) }
77
+ icon={ show ? unseen : seen }
78
+ size="small"
79
+ variant="minimal"
80
+ />
81
+ </InputLayout.Slot>
82
+ }
83
+ />
84
+ );
85
+ },
86
+ args: {
87
+ ...Default.args,
88
+ defaultValue: 'password',
89
+ },
90
+ };
91
+
92
+ export const Date: Story = {
93
+ args: {
94
+ ...Default.args,
95
+ type: 'date',
96
+ },
97
+ };
98
+
99
+ export const Number: Story = {
100
+ args: {
101
+ ...Default.args,
102
+ placeholder: '0',
103
+ type: 'number',
104
+ },
105
+ };
106
+
107
+ export const NumberWithSteppers: Story = {
108
+ render: function Template( args ) {
109
+ const [ value, setValue ] = useState( 0 );
110
+
111
+ return (
112
+ <>
113
+ <style>
114
+ { `
115
+ .my-number-with-steppers input[type='number'] {
116
+ -moz-appearance: textfield;
117
+ }
118
+ .my-number-with-steppers ::-webkit-inner-spin-button {
119
+ appearance: none;
120
+ }
121
+ ` }
122
+ </style>
123
+ <InputControl
124
+ { ...args }
125
+ value={ value }
126
+ onValueChange={ ( v ) => setValue( parseInt( v, 10 ) ) }
127
+ className="my-number-with-steppers"
128
+ suffix={
129
+ <InputLayout.Slot padding="minimal">
130
+ <Stack direction="row" gap="xs">
131
+ <IconButton
132
+ label="Increment"
133
+ icon={ plus }
134
+ onClick={ () => setValue( value + 1 ) }
135
+ size="small"
136
+ variant="minimal"
137
+ />
138
+ <IconButton
139
+ label="Decrement"
140
+ icon={ reset }
141
+ onClick={ () => setValue( value - 1 ) }
142
+ size="small"
143
+ variant="minimal"
144
+ />
145
+ </Stack>
146
+ </InputLayout.Slot>
147
+ }
148
+ />
149
+ </>
150
+ );
151
+ },
152
+ args: {
153
+ ...Number.args,
154
+ type: 'number',
155
+ },
156
+ };
157
+
158
+ export const Disabled: Story = {
159
+ args: {
160
+ ...Default.args,
161
+ disabled: true,
162
+ },
163
+ };
@@ -0,0 +1,53 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { createRef } from '@wordpress/element';
3
+ import { InputControl } from '../index';
4
+
5
+ describe( 'InputControl', () => {
6
+ it( 'forwards ref', () => {
7
+ const ref = createRef< HTMLInputElement >();
8
+
9
+ render( <InputControl ref={ ref } label="Username" /> );
10
+
11
+ expect( ref.current ).toBeInstanceOf( HTMLInputElement );
12
+ } );
13
+
14
+ it( 'renders with a visible label', () => {
15
+ render( <InputControl label="Email" /> );
16
+
17
+ expect(
18
+ screen.getByRole( 'textbox', { name: 'Email' } )
19
+ ).toBeVisible();
20
+ expect( screen.getByText( 'Email' ) ).toBeVisible();
21
+ } );
22
+
23
+ it( 'renders with a visually hidden label', () => {
24
+ render( <InputControl label="Search" hideLabelFromVision /> );
25
+
26
+ expect(
27
+ screen.getByRole( 'textbox', { name: 'Search' } )
28
+ ).toBeVisible();
29
+ } );
30
+
31
+ it( 'renders with a description', () => {
32
+ render(
33
+ <InputControl label="Name" description="Enter your full name." />
34
+ );
35
+
36
+ expect( screen.getByText( 'Enter your full name.' ) ).toBeVisible();
37
+ } );
38
+
39
+ it( 'renders with details', () => {
40
+ render(
41
+ <InputControl
42
+ label="Website"
43
+ details={
44
+ <span>
45
+ Must start with <code>https://</code>
46
+ </span>
47
+ }
48
+ />
49
+ );
50
+
51
+ expect( screen.getByText( /Must start with/ ) ).toBeVisible();
52
+ } );
53
+ } );
@@ -0,0 +1,5 @@
1
+ import type { Input } from '../primitives';
2
+ import type { ControlProps } from '../types';
3
+
4
+ export type InputControlProps = React.ComponentProps< typeof Input > &
5
+ ControlProps;
@@ -5,7 +5,7 @@ import resetStyles from '../../../utils/css/resets.module.css';
5
5
  import type { FieldRootProps } from './types';
6
6
  import { Stack } from '../../../stack';
7
7
 
8
- const DEFAULT_RENDER = ( props: React.ComponentProps< typeof Stack > ) => (
8
+ const defaultRender = ( props: React.ComponentProps< typeof Stack > ) => (
9
9
  <Stack { ...props } direction="column" gap="sm" />
10
10
  );
11
11
 
@@ -19,7 +19,7 @@ const DEFAULT_RENDER = ( props: React.ComponentProps< typeof Stack > ) => (
19
19
  * accessible labeling. See examples for how to associate the label in different cases.
20
20
  */
21
21
  export const Root = forwardRef< HTMLDivElement, FieldRootProps >( function Root(
22
- { className, render = DEFAULT_RENDER, ...restProps },
22
+ { className, render = defaultRender, ...restProps },
23
23
  ref
24
24
  ) {
25
25
  return (
@@ -1,6 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { useId } from '@wordpress/element';
3
3
  import { Field } from '../../../..';
4
+ import { DETAILS_EXAMPLE } from '../../../stories/shared';
4
5
 
5
6
  const meta: Meta< typeof Field.Root > = {
6
7
  title: 'Design System/Components/Form/Primitives/Field',
@@ -135,13 +136,7 @@ export const WithDetails: StoryObj< typeof Field.Root > = {
135
136
  <Field.Control
136
137
  render={ <input type="text" placeholder="Placeholder" /> }
137
138
  />
138
- <Field.Details>
139
- Details can include{ ' ' }
140
- <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a">
141
- links to more information
142
- </a>{ ' ' }
143
- and other semantic elements.
144
- </Field.Details>
139
+ <Field.Details>{ DETAILS_EXAMPLE }</Field.Details>
145
140
  </>
146
141
  ),
147
142
  },
@@ -1,5 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { Fieldset } from '../../../..';
3
+ import { DETAILS_EXAMPLE } from '../../../stories/shared';
3
4
 
4
5
  const meta: Meta< typeof Fieldset.Root > = {
5
6
  title: 'Design System/Components/Form/Primitives/Fieldset',
@@ -74,13 +75,7 @@ export const WithDetails: Story = {
74
75
  <input type="checkbox" /> { fruit }
75
76
  </label>
76
77
  ) ) }
77
- <Fieldset.Details>
78
- Details can include{ ' ' }
79
- <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a">
80
- links to more information
81
- </a>{ ' ' }
82
- and other semantic elements.
83
- </Fieldset.Details>
78
+ <Fieldset.Details>{ DETAILS_EXAMPLE }</Fieldset.Details>
84
79
  </>
85
80
  ),
86
81
  },
@@ -1,5 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
2
  import { Input, InputLayout } from '../../../..';
3
+ import { WithSuffixControl } from '../../input-layout/stories/index.story';
3
4
 
4
5
  const meta: Meta< typeof Input > = {
5
6
  title: 'Design System/Components/Form/Primitives/Input',
@@ -32,6 +33,12 @@ export const WithPrefix: Story = {
32
33
  },
33
34
  };
34
35
 
36
+ WithSuffixControl.args = {
37
+ ...WithSuffixControl.args,
38
+ children: undefined,
39
+ };
40
+ export { WithSuffixControl };
41
+
35
42
  export const Disabled: Story = {
36
43
  args: {
37
44
  ...Default.args,
@@ -9,13 +9,17 @@ import type { InputLayoutSlotProps } from './types';
9
9
  export const InputLayoutSlot = forwardRef<
10
10
  HTMLDivElement,
11
11
  InputLayoutSlotProps
12
- >( function InputLayoutSlot( { padding = 'default', ...restProps }, ref ) {
12
+ >( function InputLayoutSlot(
13
+ { padding = 'default', className, ...restProps },
14
+ ref
15
+ ) {
13
16
  return (
14
17
  <div
15
18
  ref={ ref }
16
19
  className={ clsx(
17
20
  styles[ 'input-layout-slot' ],
18
- styles[ `is-padding-${ padding }` ]
21
+ styles[ `is-padding-${ padding }` ],
22
+ className
19
23
  ) }
20
24
  { ...restProps }
21
25
  />
@@ -1,5 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { InputLayout } from '../../../..';
2
+ import { copy } from '@wordpress/icons';
3
+ import { IconButton, InputLayout } from '../../../..';
3
4
 
4
5
  const meta: Meta< typeof InputLayout > = {
5
6
  title: 'Design System/Components/Form/Primitives/InputLayout',
@@ -50,6 +51,26 @@ export const WithPaddedPrefix: Story = {
50
51
  },
51
52
  };
52
53
 
54
+ /**
55
+ * The `padding="minimal"` setting on `InputLayout.Slot` will work best when
56
+ * the slot content is a button or icon.
57
+ */
58
+ export const WithSuffixControl: Story = {
59
+ args: {
60
+ children: <div style={ { flex: 1 } } />,
61
+ suffix: (
62
+ <InputLayout.Slot padding="minimal">
63
+ <IconButton
64
+ size="small"
65
+ variant="minimal"
66
+ icon={ copy }
67
+ label="Copy"
68
+ />
69
+ </InputLayout.Slot>
70
+ ),
71
+ },
72
+ };
73
+
53
74
  export const Compact: Story = {
54
75
  args: {
55
76
  size: 'compact',
@@ -0,0 +1,15 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks';
2
+
3
+ # Form Primitives
4
+
5
+ <Meta title="Design System/Components/Form/Primitives" name="Overview" />
6
+
7
+ These form primitives are the low-level building blocks for form-related components. Outside of rare, special use cases, a normal developer should not need to use these primitives directly.
8
+
9
+ ## When to use these primitives
10
+
11
+ 1. First check if there is a higher-level `*Control` component that meets your needs, either in this package, or if not, in [`@wordpress/components`](https://wordpress.github.io/gutenberg/?path=/docs/components-introduction--docs). Also consider using [`DataForm`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#dataform), an even higher-level abstraction.
12
+ 2. If not, discuss with your designer whether the design can be altered to not require these primitives.
13
+ 3. If not, then these primitives are the next best option. Keep in mind that you are responsible for ensuring that your implementation is accessible, and adheres to Design System guidelines.
14
+
15
+ Feel free to reach out to the `#design-system` channel on the [Make WordPress Slack](https://make.wordpress.org/chat/) for guidance.
@@ -9,7 +9,7 @@ const wrappedRender = (
9
9
  render: NonNullable< TextareaProps[ 'render' ] >,
10
10
  restProps: TextareaProps & { ref: React.Ref< HTMLTextAreaElement > }
11
11
  ) => {
12
- return function Render(
12
+ return function textareaRender(
13
13
  props: React.HTMLAttributes< HTMLTextAreaElement >
14
14
  ) {
15
15
  return typeof render === 'function'
@@ -0,0 +1,19 @@
1
+ export const WITH_DETAILS_DESCRIPTION = `\
2
+ To add rich content (such as links) to the description, use the \`details\` prop.
3
+
4
+ Although this content is not associated with the field using direct semantics,
5
+ it is made discoverable to screen reader users via a visually hidden description,
6
+ alerting them to the presence of additional information below.
7
+
8
+ **Important:** If the content only includes plain text, use \`description\` instead,
9
+ so the readout is not unnecessarily verbose for screen reader users.`;
10
+
11
+ export const DETAILS_EXAMPLE = (
12
+ <>
13
+ Details can include{ ' ' }
14
+ <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a">
15
+ links to more information
16
+ </a>{ ' ' }
17
+ and other semantic elements.
18
+ </>
19
+ );
@@ -0,0 +1,34 @@
1
+ import type { Field } from './primitives';
2
+
3
+ export type ControlProps = {
4
+ /**
5
+ * The accessible label. All controls must be labeled.
6
+ */
7
+ label: React.ComponentProps< typeof Field.Label >[ 'children' ];
8
+ /**
9
+ * The accessible description, associated using `aria-describedby`.
10
+ *
11
+ * For screen reader accessibility, this should only contain plain text,
12
+ * and no semantics such as links.
13
+ */
14
+ description?: React.ComponentProps<
15
+ typeof Field.Description
16
+ >[ 'children' ];
17
+ /**
18
+ * Additional information about the field, which unlike a normal description,
19
+ * can include links and other semantic elements.
20
+ *
21
+ * Do not use this prop when the content is only plain text;
22
+ * use `description` instead.
23
+ */
24
+ details?: React.ComponentProps< typeof Field.Details >[ 'children' ];
25
+ /**
26
+ * Whether to visually hide the label while keeping it accessible
27
+ * to screen readers.
28
+ *
29
+ * @default false
30
+ */
31
+ hideLabelFromVision?: React.ComponentProps<
32
+ typeof Field.Label
33
+ >[ 'hideFromVision' ];
34
+ };
package/src/index.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  export * from './badge';
2
2
  export * from './button';
3
3
  export * as Card from './card';
4
+ export * as Collapsible from './collapsible';
4
5
  export * as CollapsibleCard from './collapsible-card';
6
+ export * as AlertDialog from './alert-dialog';
5
7
  export * as Dialog from './dialog';
6
- export * from './form/primitives';
8
+ export * as EmptyState from './empty-state';
9
+ export * from './form';
7
10
  export * from './icon';
8
11
  export * from './icon-button';
9
12
  export * from './link';
@@ -15,5 +15,3 @@ export {
15
15
  ActionButton,
16
16
  ActionLink,
17
17
  };
18
-
19
- export type { NoticeIntent } from './types';
@@ -115,7 +115,7 @@
115
115
  --wp-ui-notice-decorative-icon-color: var(--wpds-color-fg-content-error-weak);
116
116
  }
117
117
 
118
- /* TODO: Replace 320px with a measure token from the Theme package. */
118
+ /* Matches --wpds-dimension-surface-width-sm (container queries don't support custom properties). */
119
119
  @container (max-width: 320px) {
120
120
  .notice:has(.title) .description,
121
121
  .notice:has(.title) .actions {
@@ -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;
@@ -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
  );