@wordpress/ui 0.10.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 (454) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/CONTRIBUTING.md +149 -0
  3. package/README.md +34 -6
  4. package/build/alert-dialog/context.cjs +6 -1
  5. package/build/alert-dialog/context.cjs.map +2 -2
  6. package/build/alert-dialog/popup.cjs +105 -33
  7. package/build/alert-dialog/popup.cjs.map +4 -4
  8. package/build/alert-dialog/root.cjs +106 -6
  9. package/build/alert-dialog/root.cjs.map +2 -2
  10. package/build/alert-dialog/trigger.cjs +4 -14
  11. package/build/alert-dialog/trigger.cjs.map +3 -3
  12. package/build/alert-dialog/types.cjs.map +1 -1
  13. package/build/badge/badge.cjs +14 -14
  14. package/build/badge/badge.cjs.map +2 -2
  15. package/build/button/button.cjs +16 -6
  16. package/build/button/button.cjs.map +3 -3
  17. package/build/card/content.cjs +4 -4
  18. package/build/card/content.cjs.map +2 -2
  19. package/build/card/full-bleed.cjs +4 -4
  20. package/build/card/full-bleed.cjs.map +2 -2
  21. package/build/card/header.cjs +4 -4
  22. package/build/card/header.cjs.map +2 -2
  23. package/build/card/root.cjs +4 -4
  24. package/build/card/root.cjs.map +2 -2
  25. package/build/card/title.cjs +5 -25
  26. package/build/card/title.cjs.map +4 -4
  27. package/build/collapsible-card/content.cjs +3 -3
  28. package/build/collapsible-card/content.cjs.map +1 -1
  29. package/build/collapsible-card/header.cjs +6 -6
  30. package/build/collapsible-card/header.cjs.map +2 -2
  31. package/build/dialog/footer.cjs +3 -3
  32. package/build/dialog/footer.cjs.map +2 -2
  33. package/build/dialog/header.cjs +3 -3
  34. package/build/dialog/header.cjs.map +2 -2
  35. package/build/dialog/popup.cjs +5 -4
  36. package/build/dialog/popup.cjs.map +2 -2
  37. package/build/dialog/title.cjs +10 -19
  38. package/build/dialog/title.cjs.map +3 -3
  39. package/build/dialog/types.cjs.map +1 -1
  40. package/build/empty-state/actions.cjs +3 -3
  41. package/build/empty-state/actions.cjs.map +2 -2
  42. package/build/empty-state/description.cjs +8 -5
  43. package/build/empty-state/description.cjs.map +2 -2
  44. package/build/empty-state/icon.cjs +3 -3
  45. package/build/empty-state/icon.cjs.map +2 -2
  46. package/build/empty-state/root.cjs +3 -3
  47. package/build/empty-state/root.cjs.map +2 -2
  48. package/build/empty-state/title.cjs +8 -5
  49. package/build/empty-state/title.cjs.map +2 -2
  50. package/build/empty-state/visual.cjs +3 -3
  51. package/build/empty-state/visual.cjs.map +2 -2
  52. package/build/form/primitives/field/description.cjs +17 -4
  53. package/build/form/primitives/field/description.cjs.map +3 -3
  54. package/build/form/primitives/field/details.cjs +4 -4
  55. package/build/form/primitives/field/details.cjs.map +2 -2
  56. package/build/form/primitives/field/label.cjs +8 -8
  57. package/build/form/primitives/field/label.cjs.map +2 -2
  58. package/build/form/primitives/field/root.cjs +2 -2
  59. package/build/form/primitives/field/root.cjs.map +2 -2
  60. package/build/form/primitives/fieldset/description.cjs +20 -4
  61. package/build/form/primitives/fieldset/description.cjs.map +3 -3
  62. package/build/form/primitives/fieldset/details.cjs +3 -3
  63. package/build/form/primitives/fieldset/details.cjs.map +2 -2
  64. package/build/form/primitives/fieldset/legend.cjs +8 -7
  65. package/build/form/primitives/fieldset/legend.cjs.map +2 -2
  66. package/build/form/primitives/input/input.cjs +23 -7
  67. package/build/form/primitives/input/input.cjs.map +3 -3
  68. package/build/form/primitives/input-layout/input-layout.cjs +13 -3
  69. package/build/form/primitives/input-layout/input-layout.cjs.map +3 -3
  70. package/build/form/primitives/input-layout/slot.cjs +3 -3
  71. package/build/form/primitives/input-layout/slot.cjs.map +2 -2
  72. package/build/form/primitives/select/item.cjs +3 -3
  73. package/build/form/primitives/select/item.cjs.map +2 -2
  74. package/build/form/primitives/select/popup.cjs +5 -5
  75. package/build/form/primitives/select/popup.cjs.map +2 -2
  76. package/build/form/primitives/select/trigger.cjs +6 -6
  77. package/build/form/primitives/select/trigger.cjs.map +2 -2
  78. package/build/form/primitives/select/types.cjs.map +1 -1
  79. package/build/form/primitives/textarea/textarea.cjs +20 -1
  80. package/build/form/primitives/textarea/textarea.cjs.map +3 -3
  81. package/build/index.cjs +3 -0
  82. package/build/index.cjs.map +2 -2
  83. package/build/link/link.cjs +16 -6
  84. package/build/link/link.cjs.map +3 -3
  85. package/build/notice/action-button.cjs +3 -3
  86. package/build/notice/action-button.cjs.map +2 -2
  87. package/build/notice/action-link.cjs +3 -3
  88. package/build/notice/action-link.cjs.map +2 -2
  89. package/build/notice/actions.cjs +3 -3
  90. package/build/notice/actions.cjs.map +2 -2
  91. package/build/notice/close-icon.cjs +3 -3
  92. package/build/notice/close-icon.cjs.map +2 -2
  93. package/build/notice/description.cjs +3 -3
  94. package/build/notice/description.cjs.map +2 -2
  95. package/build/notice/root.cjs +3 -3
  96. package/build/notice/root.cjs.map +2 -2
  97. package/build/notice/title.cjs +3 -3
  98. package/build/notice/title.cjs.map +2 -2
  99. package/build/popover/arrow.cjs +94 -0
  100. package/build/popover/arrow.cjs.map +7 -0
  101. package/build/popover/close.cjs +45 -0
  102. package/build/popover/close.cjs.map +7 -0
  103. package/build/popover/context.cjs +76 -0
  104. package/build/popover/context.cjs.map +7 -0
  105. package/build/popover/description.cjs +70 -0
  106. package/build/popover/description.cjs.map +7 -0
  107. package/build/popover/index.cjs +49 -0
  108. package/build/popover/index.cjs.map +7 -0
  109. package/build/popover/popup.cjs +138 -0
  110. package/build/popover/popup.cjs.map +7 -0
  111. package/build/popover/root.cjs +35 -0
  112. package/build/popover/root.cjs.map +7 -0
  113. package/build/popover/title.cjs +56 -0
  114. package/build/popover/title.cjs.map +7 -0
  115. package/build/popover/trigger.cjs +38 -0
  116. package/build/popover/trigger.cjs.map +7 -0
  117. package/build/popover/types.cjs +19 -0
  118. package/build/popover/types.cjs.map +7 -0
  119. package/build/tabs/list.cjs +3 -4
  120. package/build/tabs/list.cjs.map +2 -2
  121. package/build/tabs/panel.cjs +3 -3
  122. package/build/tabs/panel.cjs.map +2 -2
  123. package/build/tabs/tab.cjs +3 -3
  124. package/build/tabs/tab.cjs.map +2 -2
  125. package/build/text/text.cjs +20 -5
  126. package/build/text/text.cjs.map +3 -3
  127. package/build/tooltip/popup.cjs +5 -4
  128. package/build/tooltip/popup.cjs.map +2 -2
  129. package/build/tooltip/root.cjs.map +2 -2
  130. package/build/tooltip/types.cjs.map +1 -1
  131. package/build/utils/types.cjs.map +1 -1
  132. package/build/utils/use-deprioritized-initial-focus.cjs.map +2 -2
  133. package/build/visually-hidden/visually-hidden.cjs.map +2 -2
  134. package/build-module/alert-dialog/context.mjs +6 -1
  135. package/build-module/alert-dialog/context.mjs.map +2 -2
  136. package/build-module/alert-dialog/popup.mjs +107 -33
  137. package/build-module/alert-dialog/popup.mjs.map +4 -4
  138. package/build-module/alert-dialog/root.mjs +113 -7
  139. package/build-module/alert-dialog/root.mjs.map +2 -2
  140. package/build-module/alert-dialog/trigger.mjs +4 -4
  141. package/build-module/alert-dialog/trigger.mjs.map +3 -3
  142. package/build-module/badge/badge.mjs +14 -14
  143. package/build-module/badge/badge.mjs.map +2 -2
  144. package/build-module/button/button.mjs +16 -6
  145. package/build-module/button/button.mjs.map +3 -3
  146. package/build-module/card/content.mjs +4 -4
  147. package/build-module/card/content.mjs.map +2 -2
  148. package/build-module/card/full-bleed.mjs +4 -4
  149. package/build-module/card/full-bleed.mjs.map +2 -2
  150. package/build-module/card/header.mjs +4 -4
  151. package/build-module/card/header.mjs.map +2 -2
  152. package/build-module/card/root.mjs +4 -4
  153. package/build-module/card/root.mjs.map +2 -2
  154. package/build-module/card/title.mjs +5 -15
  155. package/build-module/card/title.mjs.map +3 -3
  156. package/build-module/collapsible-card/content.mjs +3 -3
  157. package/build-module/collapsible-card/content.mjs.map +1 -1
  158. package/build-module/collapsible-card/header.mjs +6 -6
  159. package/build-module/collapsible-card/header.mjs.map +2 -2
  160. package/build-module/dialog/footer.mjs +3 -3
  161. package/build-module/dialog/footer.mjs.map +2 -2
  162. package/build-module/dialog/header.mjs +3 -3
  163. package/build-module/dialog/header.mjs.map +2 -2
  164. package/build-module/dialog/popup.mjs +5 -4
  165. package/build-module/dialog/popup.mjs.map +2 -2
  166. package/build-module/dialog/title.mjs +10 -9
  167. package/build-module/dialog/title.mjs.map +2 -2
  168. package/build-module/empty-state/actions.mjs +3 -3
  169. package/build-module/empty-state/actions.mjs.map +2 -2
  170. package/build-module/empty-state/description.mjs +8 -5
  171. package/build-module/empty-state/description.mjs.map +2 -2
  172. package/build-module/empty-state/icon.mjs +3 -3
  173. package/build-module/empty-state/icon.mjs.map +2 -2
  174. package/build-module/empty-state/root.mjs +3 -3
  175. package/build-module/empty-state/root.mjs.map +2 -2
  176. package/build-module/empty-state/title.mjs +8 -5
  177. package/build-module/empty-state/title.mjs.map +2 -2
  178. package/build-module/empty-state/visual.mjs +3 -3
  179. package/build-module/empty-state/visual.mjs.map +2 -2
  180. package/build-module/form/primitives/field/description.mjs +17 -4
  181. package/build-module/form/primitives/field/description.mjs.map +3 -3
  182. package/build-module/form/primitives/field/details.mjs +4 -4
  183. package/build-module/form/primitives/field/details.mjs.map +2 -2
  184. package/build-module/form/primitives/field/label.mjs +8 -8
  185. package/build-module/form/primitives/field/label.mjs.map +2 -2
  186. package/build-module/form/primitives/field/root.mjs +2 -2
  187. package/build-module/form/primitives/field/root.mjs.map +2 -2
  188. package/build-module/form/primitives/fieldset/description.mjs +20 -4
  189. package/build-module/form/primitives/fieldset/description.mjs.map +3 -3
  190. package/build-module/form/primitives/fieldset/details.mjs +3 -3
  191. package/build-module/form/primitives/fieldset/details.mjs.map +2 -2
  192. package/build-module/form/primitives/fieldset/legend.mjs +8 -7
  193. package/build-module/form/primitives/fieldset/legend.mjs.map +2 -2
  194. package/build-module/form/primitives/input/input.mjs +23 -7
  195. package/build-module/form/primitives/input/input.mjs.map +3 -3
  196. package/build-module/form/primitives/input-layout/input-layout.mjs +13 -3
  197. package/build-module/form/primitives/input-layout/input-layout.mjs.map +3 -3
  198. package/build-module/form/primitives/input-layout/slot.mjs +3 -3
  199. package/build-module/form/primitives/input-layout/slot.mjs.map +2 -2
  200. package/build-module/form/primitives/select/item.mjs +3 -3
  201. package/build-module/form/primitives/select/item.mjs.map +2 -2
  202. package/build-module/form/primitives/select/popup.mjs +5 -5
  203. package/build-module/form/primitives/select/popup.mjs.map +2 -2
  204. package/build-module/form/primitives/select/trigger.mjs +6 -6
  205. package/build-module/form/primitives/select/trigger.mjs.map +2 -2
  206. package/build-module/form/primitives/textarea/textarea.mjs +20 -1
  207. package/build-module/form/primitives/textarea/textarea.mjs.map +3 -3
  208. package/build-module/index.mjs +2 -0
  209. package/build-module/index.mjs.map +2 -2
  210. package/build-module/link/link.mjs +16 -6
  211. package/build-module/link/link.mjs.map +3 -3
  212. package/build-module/notice/action-button.mjs +3 -3
  213. package/build-module/notice/action-button.mjs.map +2 -2
  214. package/build-module/notice/action-link.mjs +3 -3
  215. package/build-module/notice/action-link.mjs.map +2 -2
  216. package/build-module/notice/actions.mjs +3 -3
  217. package/build-module/notice/actions.mjs.map +2 -2
  218. package/build-module/notice/close-icon.mjs +3 -3
  219. package/build-module/notice/close-icon.mjs.map +2 -2
  220. package/build-module/notice/description.mjs +3 -3
  221. package/build-module/notice/description.mjs.map +2 -2
  222. package/build-module/notice/root.mjs +3 -3
  223. package/build-module/notice/root.mjs.map +2 -2
  224. package/build-module/notice/title.mjs +3 -3
  225. package/build-module/notice/title.mjs.map +2 -2
  226. package/build-module/popover/arrow.mjs +59 -0
  227. package/build-module/popover/arrow.mjs.map +7 -0
  228. package/build-module/popover/close.mjs +20 -0
  229. package/build-module/popover/close.mjs.map +7 -0
  230. package/build-module/popover/context.mjs +57 -0
  231. package/build-module/popover/context.mjs.map +7 -0
  232. package/build-module/popover/description.mjs +35 -0
  233. package/build-module/popover/description.mjs.map +7 -0
  234. package/build-module/popover/index.mjs +18 -0
  235. package/build-module/popover/index.mjs.map +7 -0
  236. package/build-module/popover/popup.mjs +105 -0
  237. package/build-module/popover/popup.mjs.map +7 -0
  238. package/build-module/popover/root.mjs +10 -0
  239. package/build-module/popover/root.mjs.map +7 -0
  240. package/build-module/popover/title.mjs +31 -0
  241. package/build-module/popover/title.mjs.map +7 -0
  242. package/build-module/popover/trigger.mjs +13 -0
  243. package/build-module/popover/trigger.mjs.map +7 -0
  244. package/build-module/popover/types.mjs +1 -0
  245. package/build-module/popover/types.mjs.map +7 -0
  246. package/build-module/tabs/list.mjs +3 -4
  247. package/build-module/tabs/list.mjs.map +2 -2
  248. package/build-module/tabs/panel.mjs +3 -3
  249. package/build-module/tabs/panel.mjs.map +2 -2
  250. package/build-module/tabs/tab.mjs +3 -3
  251. package/build-module/tabs/tab.mjs.map +2 -2
  252. package/build-module/text/text.mjs +20 -5
  253. package/build-module/text/text.mjs.map +3 -3
  254. package/build-module/tooltip/popup.mjs +5 -4
  255. package/build-module/tooltip/popup.mjs.map +2 -2
  256. package/build-module/tooltip/root.mjs.map +2 -2
  257. package/build-module/utils/use-deprioritized-initial-focus.mjs.map +2 -2
  258. package/build-module/visually-hidden/visually-hidden.mjs.map +2 -2
  259. package/build-types/alert-dialog/context.d.ts +6 -3
  260. package/build-types/alert-dialog/context.d.ts.map +1 -1
  261. package/build-types/alert-dialog/popup.d.ts.map +1 -1
  262. package/build-types/alert-dialog/root.d.ts +2 -8
  263. package/build-types/alert-dialog/root.d.ts.map +1 -1
  264. package/build-types/alert-dialog/stories/index.story.d.ts +18 -6
  265. package/build-types/alert-dialog/stories/index.story.d.ts.map +1 -1
  266. package/build-types/alert-dialog/trigger.d.ts +2 -1
  267. package/build-types/alert-dialog/trigger.d.ts.map +1 -1
  268. package/build-types/alert-dialog/types.d.ts +61 -26
  269. package/build-types/alert-dialog/types.d.ts.map +1 -1
  270. package/build-types/badge/badge.d.ts.map +1 -1
  271. package/build-types/button/button.d.ts.map +1 -1
  272. package/build-types/card/stories/index.story.d.ts.map +1 -1
  273. package/build-types/card/title.d.ts.map +1 -1
  274. package/build-types/collapsible/panel.d.ts +2 -1
  275. package/build-types/collapsible/panel.d.ts.map +1 -1
  276. package/build-types/collapsible/root.d.ts +2 -1
  277. package/build-types/collapsible/root.d.ts.map +1 -1
  278. package/build-types/collapsible/trigger.d.ts +2 -1
  279. package/build-types/collapsible/trigger.d.ts.map +1 -1
  280. package/build-types/dialog/popup.d.ts.map +1 -1
  281. package/build-types/dialog/stories/index.story.d.ts +8 -0
  282. package/build-types/dialog/stories/index.story.d.ts.map +1 -1
  283. package/build-types/dialog/title.d.ts +12 -2
  284. package/build-types/dialog/title.d.ts.map +1 -1
  285. package/build-types/dialog/types.d.ts +8 -1
  286. package/build-types/dialog/types.d.ts.map +1 -1
  287. package/build-types/empty-state/description.d.ts.map +1 -1
  288. package/build-types/empty-state/title.d.ts.map +1 -1
  289. package/build-types/form/primitives/field/description.d.ts +2 -1
  290. package/build-types/form/primitives/field/description.d.ts.map +1 -1
  291. package/build-types/form/primitives/field/details.d.ts +2 -1
  292. package/build-types/form/primitives/field/details.d.ts.map +1 -1
  293. package/build-types/form/primitives/field/label.d.ts +2 -1
  294. package/build-types/form/primitives/field/label.d.ts.map +1 -1
  295. package/build-types/form/primitives/fieldset/description.d.ts +2 -1
  296. package/build-types/form/primitives/fieldset/description.d.ts.map +1 -1
  297. package/build-types/form/primitives/fieldset/details.d.ts +2 -1
  298. package/build-types/form/primitives/fieldset/details.d.ts.map +1 -1
  299. package/build-types/form/primitives/fieldset/legend.d.ts +2 -1
  300. package/build-types/form/primitives/fieldset/legend.d.ts.map +1 -1
  301. package/build-types/form/primitives/fieldset/root.d.ts +2 -1
  302. package/build-types/form/primitives/fieldset/root.d.ts.map +1 -1
  303. package/build-types/form/primitives/input/input.d.ts.map +1 -1
  304. package/build-types/form/primitives/input-layout/input-layout.d.ts.map +1 -1
  305. package/build-types/form/primitives/select/item.d.ts +6 -2
  306. package/build-types/form/primitives/select/item.d.ts.map +1 -1
  307. package/build-types/form/primitives/select/popup.d.ts +11 -1
  308. package/build-types/form/primitives/select/popup.d.ts.map +1 -1
  309. package/build-types/form/primitives/select/trigger.d.ts +12 -2
  310. package/build-types/form/primitives/select/trigger.d.ts.map +1 -1
  311. package/build-types/form/primitives/select/types.d.ts +13 -3
  312. package/build-types/form/primitives/select/types.d.ts.map +1 -1
  313. package/build-types/form/primitives/textarea/textarea.d.ts.map +1 -1
  314. package/build-types/form/stories/shared.d.ts.map +1 -1
  315. package/build-types/index.d.ts +1 -0
  316. package/build-types/index.d.ts.map +1 -1
  317. package/build-types/link/link.d.ts.map +1 -1
  318. package/build-types/popover/arrow.d.ts +10 -0
  319. package/build-types/popover/arrow.d.ts.map +1 -0
  320. package/build-types/popover/close.d.ts +11 -0
  321. package/build-types/popover/close.d.ts.map +1 -0
  322. package/build-types/popover/context.d.ts +22 -0
  323. package/build-types/popover/context.d.ts.map +1 -0
  324. package/build-types/popover/description.d.ts +10 -0
  325. package/build-types/popover/description.d.ts.map +1 -0
  326. package/build-types/popover/index.d.ts +9 -0
  327. package/build-types/popover/index.d.ts.map +1 -0
  328. package/build-types/popover/popup.d.ts +11 -0
  329. package/build-types/popover/popup.d.ts.map +1 -0
  330. package/build-types/popover/root.d.ts +37 -0
  331. package/build-types/popover/root.d.ts.map +1 -0
  332. package/build-types/popover/stories/index.story.d.ts +211 -0
  333. package/build-types/popover/stories/index.story.d.ts.map +1 -0
  334. package/build-types/popover/stories/utils.d.ts +25 -0
  335. package/build-types/popover/stories/utils.d.ts.map +1 -0
  336. package/build-types/popover/test/index.test.d.ts +2 -0
  337. package/build-types/popover/test/index.test.d.ts.map +1 -0
  338. package/build-types/popover/title.d.ts +20 -0
  339. package/build-types/popover/title.d.ts.map +1 -0
  340. package/build-types/popover/trigger.d.ts +10 -0
  341. package/build-types/popover/trigger.d.ts.map +1 -0
  342. package/build-types/popover/types.d.ts +83 -0
  343. package/build-types/popover/types.d.ts.map +1 -0
  344. package/build-types/tabs/list.d.ts +2 -1
  345. package/build-types/tabs/list.d.ts.map +1 -1
  346. package/build-types/tabs/panel.d.ts +2 -1
  347. package/build-types/tabs/panel.d.ts.map +1 -1
  348. package/build-types/tabs/root.d.ts +2 -1
  349. package/build-types/tabs/root.d.ts.map +1 -1
  350. package/build-types/tabs/tab.d.ts +2 -1
  351. package/build-types/tabs/tab.d.ts.map +1 -1
  352. package/build-types/text/stories/index.story.d.ts +4 -0
  353. package/build-types/text/stories/index.story.d.ts.map +1 -1
  354. package/build-types/text/text.d.ts.map +1 -1
  355. package/build-types/tooltip/popup.d.ts.map +1 -1
  356. package/build-types/tooltip/root.d.ts +9 -8
  357. package/build-types/tooltip/root.d.ts.map +1 -1
  358. package/build-types/tooltip/stories/usage-guidelines.story.d.ts +21 -0
  359. package/build-types/tooltip/stories/usage-guidelines.story.d.ts.map +1 -0
  360. package/build-types/tooltip/types.d.ts +4 -0
  361. package/build-types/tooltip/types.d.ts.map +1 -1
  362. package/build-types/utils/types.d.ts +6 -2
  363. package/build-types/utils/types.d.ts.map +1 -1
  364. package/build-types/utils/use-deprioritized-initial-focus.d.ts +6 -5
  365. package/build-types/utils/use-deprioritized-initial-focus.d.ts.map +1 -1
  366. package/build-types/visually-hidden/stories/index.story.d.ts +7 -0
  367. package/build-types/visually-hidden/stories/index.story.d.ts.map +1 -1
  368. package/build-types/visually-hidden/visually-hidden.d.ts +34 -0
  369. package/build-types/visually-hidden/visually-hidden.d.ts.map +1 -1
  370. package/package.json +12 -12
  371. package/src/alert-dialog/context.tsx +12 -4
  372. package/src/alert-dialog/popup.tsx +91 -33
  373. package/src/alert-dialog/root.tsx +191 -13
  374. package/src/alert-dialog/stories/index.story.tsx +116 -65
  375. package/src/alert-dialog/style.module.css +11 -0
  376. package/src/alert-dialog/test/index.test.tsx +1319 -347
  377. package/src/alert-dialog/trigger.tsx +2 -2
  378. package/src/alert-dialog/types.ts +64 -28
  379. package/src/badge/badge.tsx +11 -14
  380. package/src/badge/style.module.css +0 -4
  381. package/src/button/button.tsx +2 -0
  382. package/src/button/style.module.css +7 -3
  383. package/src/card/stories/index.story.tsx +4 -5
  384. package/src/card/style.module.css +1 -5
  385. package/src/card/test/index.test.tsx +17 -1
  386. package/src/card/title.tsx +6 -5
  387. package/src/collapsible-card/stories/index.story.tsx +5 -5
  388. package/src/dialog/popup.tsx +2 -1
  389. package/src/dialog/stories/index.story.tsx +33 -0
  390. package/src/dialog/style.module.css +13 -9
  391. package/src/dialog/test/index.test.tsx +63 -4
  392. package/src/dialog/title.tsx +21 -9
  393. package/src/dialog/types.ts +9 -1
  394. package/src/empty-state/description.tsx +6 -2
  395. package/src/empty-state/style.module.css +1 -1
  396. package/src/empty-state/test/description.test.tsx +13 -0
  397. package/src/empty-state/test/title.test.tsx +13 -0
  398. package/src/empty-state/title.tsx +9 -3
  399. package/src/form/primitives/field/description.tsx +6 -1
  400. package/src/form/primitives/field/details.tsx +4 -2
  401. package/src/form/primitives/field/label.tsx +9 -5
  402. package/src/form/primitives/field/root.tsx +2 -2
  403. package/src/form/primitives/field/test/index.test.tsx +11 -0
  404. package/src/form/primitives/fieldset/description.tsx +9 -1
  405. package/src/form/primitives/fieldset/legend.tsx +9 -4
  406. package/src/form/primitives/fieldset/test/index.test.tsx +22 -0
  407. package/src/form/primitives/input/input.tsx +6 -1
  408. package/src/form/primitives/input/style.module.css +4 -0
  409. package/src/form/primitives/input-layout/input-layout.tsx +2 -0
  410. package/src/form/primitives/input-layout/style.module.css +3 -3
  411. package/src/form/primitives/select/popup.tsx +5 -2
  412. package/src/form/primitives/select/test/index.test.tsx +60 -1
  413. package/src/form/primitives/select/types.ts +14 -4
  414. package/src/form/primitives/textarea/textarea.tsx +10 -1
  415. package/src/form/stories/shared.tsx +4 -2
  416. package/src/index.ts +1 -0
  417. package/src/link/link.tsx +2 -0
  418. package/src/link/style.module.css +11 -1
  419. package/src/notice/style.module.css +5 -5
  420. package/src/popover/arrow.tsx +49 -0
  421. package/src/popover/close.tsx +24 -0
  422. package/src/popover/context.tsx +100 -0
  423. package/src/popover/description.tsx +29 -0
  424. package/src/popover/index.ts +9 -0
  425. package/src/popover/popup.tsx +106 -0
  426. package/src/popover/root.tsx +41 -0
  427. package/src/popover/stories/index.story.tsx +1315 -0
  428. package/src/popover/stories/utils.tsx +91 -0
  429. package/src/popover/style.module.css +64 -0
  430. package/src/popover/test/index.test.tsx +727 -0
  431. package/src/popover/title.tsx +47 -0
  432. package/src/popover/trigger.tsx +17 -0
  433. package/src/popover/types.ts +113 -0
  434. package/src/tabs/list.tsx +0 -1
  435. package/src/tabs/style.module.css +2 -2
  436. package/src/text/stories/index.story.tsx +4 -2
  437. package/src/text/style.module.css +62 -36
  438. package/src/text/test/index.test.tsx +1 -4
  439. package/src/text/text.tsx +8 -1
  440. package/src/tooltip/popup.tsx +2 -1
  441. package/src/tooltip/root.tsx +9 -8
  442. package/src/tooltip/stories/usage-guidelines.mdx +91 -0
  443. package/src/tooltip/stories/usage-guidelines.story.tsx +119 -0
  444. package/src/tooltip/style.module.css +2 -2
  445. package/src/tooltip/test/index.test.tsx +61 -0
  446. package/src/tooltip/types.ts +5 -0
  447. package/src/utils/css/field.module.css +12 -9
  448. package/src/utils/css/focus.module.css +7 -5
  449. package/src/utils/css/global-css-defense.module.css +117 -0
  450. package/src/utils/css/item-popup.module.css +2 -2
  451. package/src/utils/types.ts +7 -2
  452. package/src/utils/use-deprioritized-initial-focus.ts +5 -4
  453. package/src/visually-hidden/stories/index.story.tsx +25 -0
  454. package/src/visually-hidden/visually-hidden.tsx +34 -0
@@ -0,0 +1,21 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ declare const meta: Meta;
3
+ export default meta;
4
+ type Story = StoryObj;
5
+ /**
6
+ * Tooltips work best as visual labels for icon-only controls. Each trigger
7
+ * must have its own accessible name via `aria-label`.
8
+ */
9
+ export declare const RecommendedUsage: Story;
10
+ /**
11
+ * Popups that open when hovering an info icon should use `Popover` with
12
+ * `openOnHover` instead of a Tooltip. This ensures the content is accessible
13
+ * to touch and screen reader users.
14
+ */
15
+ export declare const InfotipWithPopover: Story;
16
+ /**
17
+ * `IconButton` has built-in tooltip support via the `label` prop,
18
+ * making it the easiest way to provide a tooltip for icon-only actions.
19
+ */
20
+ export declare const IconButtonWithTooltip: Story;
21
+ //# sourceMappingURL=usage-guidelines.story.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-guidelines.story.d.ts","sourceRoot":"","sources":["../../../src/tooltip/stories/usage-guidelines.story.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAS5D,QAAA,MAAM,IAAI,EAAE,IAMX,CAAC;AACF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAC;AAEtB;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,KA2B9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,KA0ChC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAYnC,CAAC"}
@@ -14,5 +14,9 @@ export interface PopupProps extends ComponentProps<'div'>, Pick<Tooltip.Position
14
14
  * The content to be rendered inside the component.
15
15
  */
16
16
  children?: ReactNode;
17
+ /**
18
+ * A parent element to render the portal into.
19
+ */
20
+ container?: Tooltip.Portal.Props['container'];
17
21
  }
18
22
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tooltip/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,SAAS,GAAG,IAAI,CAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAE,CAAC;AAE5E,MAAM,MAAM,aAAa,GAAG,IAAI,CAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,EACtB,OAAO,GAAG,UAAU,CACpB,CAAC;AAEF,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAE,QAAQ,CAAE;IAC/D;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,UAChB,SAAQ,cAAc,CAAE,KAAK,CAAE,EAC9B,IAAI,CAAE,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,CAAE;IAClE;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tooltip/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,SAAS,GAAG,IAAI,CAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAE,CAAC;AAE5E,MAAM,MAAM,aAAa,GAAG,IAAI,CAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,EACtB,OAAO,GAAG,UAAU,CACpB,CAAC;AAEF,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAE,QAAQ,CAAE;IAC/D;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,UAChB,SAAQ,cAAc,CAAE,KAAK,CAAE,EAC9B,IAAI,CAAE,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,CAAE;IAClE;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAE,WAAW,CAAE,CAAC;CAChD"}
@@ -3,11 +3,15 @@ type HTMLAttributesWithRef<T extends ElementType = any> = HTMLAttributes<T> & {
3
3
  ref?: Ref<T> | undefined;
4
4
  };
5
5
  type ComponentRenderFn<Props> = (props: Props) => React.ReactElement<unknown>;
6
- export type ComponentProps<E extends ElementType> = Omit<ComponentPropsWithoutRef<E>, 'className' | 'children' | 'render'> & {
6
+ export type ComponentProps<E extends ElementType> = Omit<ComponentPropsWithoutRef<E>, 'className' | 'children' | 'render' | 'style'> & {
7
7
  /**
8
- * CSS class name to apply to the component.
8
+ * CSS class name to apply to the element.
9
9
  */
10
10
  className?: string;
11
+ /**
12
+ * CSS style to apply to the element.
13
+ */
14
+ style?: React.CSSProperties;
11
15
  /**
12
16
  * Replaces the component's default HTML element using a given React
13
17
  * element, or a function that returns a React element.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,MAAM,OAAO,CAAC;AAEf,KAAK,qBAAqB,CAAE,CAAC,SAAS,WAAW,GAAG,GAAG,IACtD,cAAc,CAAE,CAAC,CAAE,GAAG;IAAE,GAAG,CAAC,EAAE,GAAG,CAAE,CAAC,CAAE,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,KAAK,iBAAiB,CAAE,KAAK,IAAK,CACjC,KAAK,EAAE,KAAK,KACR,KAAK,CAAC,YAAY,CAAE,OAAO,CAAE,CAAC;AAEnC,MAAM,MAAM,cAAc,CAAE,CAAC,SAAS,WAAW,IAAK,IAAI,CACzD,wBAAwB,CAAE,CAAC,CAAE,EAC7B,WAAW,GAAG,UAAU,GAAG,QAAQ,CACnC,GAAG;IACH;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,MAAM,CAAC,EACJ,iBAAiB,CAAE,qBAAqB,CAAE,GAC1C,KAAK,CAAC,YAAY,CAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAE,CAAC;CACnD,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,MAAM,OAAO,CAAC;AAEf,KAAK,qBAAqB,CAAE,CAAC,SAAS,WAAW,GAAG,GAAG,IACtD,cAAc,CAAE,CAAC,CAAE,GAAG;IAAE,GAAG,CAAC,EAAE,GAAG,CAAE,CAAC,CAAE,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,KAAK,iBAAiB,CAAE,KAAK,IAAK,CACjC,KAAK,EAAE,KAAK,KACR,KAAK,CAAC,YAAY,CAAE,OAAO,CAAE,CAAC;AAEnC,MAAM,MAAM,cAAc,CAAE,CAAC,SAAS,WAAW,IAAK,IAAI,CACzD,wBAAwB,CAAE,CAAC,CAAE,EAC7B,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAC7C,GAAG;IACH;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAE5B;;;OAGG;IACH,MAAM,CAAC,EACJ,iBAAiB,CAAE,qBAAqB,CAAE,GAC1C,KAAK,CAAC,YAAY,CAAE,MAAM,CAAE,MAAM,EAAE,OAAO,CAAE,CAAE,CAAC;CACnD,CAAC"}
@@ -1,9 +1,10 @@
1
- import type { Dialog as _Dialog } from '@base-ui/react/dialog';
1
+ import type { Popover as _Popover } from '@base-ui/react/popover';
2
2
  /**
3
- * Derived from Base UI's `Dialog.Popup.Props['initialFocus']`.
4
- * The same type is shared by all Base UI overlay popups (Dialog, Popover, etc.).
3
+ * The `initialFocus` type shared by Base UI overlay popups (Dialog, Popover,
4
+ * AlertDialog, etc.). We derive it from `Popover.Popup.Props` here, but it
5
+ * is identical across all overlay components.
5
6
  */
6
- type InitialFocus = _Dialog.Popup.Props['initialFocus'];
7
+ type InitialFocus = _Popover.Popup.Props['initialFocus'];
7
8
  /**
8
9
  * Returns a resolved `initialFocus` value that deprioritizes elements
9
10
  * marked with a given data attribute (e.g. a close icon), and an internal
@@ -28,7 +29,7 @@ export declare function useDeprioritizedInitialFocus({ initialFocus, deprioritiz
28
29
  initialFocus: InitialFocus;
29
30
  deprioritizedAttribute: string;
30
31
  }): {
31
- resolvedInitialFocus: boolean | import("react").RefObject<HTMLElement | null> | ((openType: import("@base-ui/utils/useEnhancedClickHandler").InteractionType) => boolean | HTMLElement | null | void) | undefined;
32
+ resolvedInitialFocus: boolean | import("react").RefObject<HTMLElement | null> | ((openType: import("@base-ui/utils/useEnhancedClickHandler").InteractionType) => void | boolean | HTMLElement | null) | undefined;
32
33
  popupRef: import("react").RefObject<HTMLDivElement>;
33
34
  };
34
35
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"use-deprioritized-initial-focus.d.ts","sourceRoot":"","sources":["../../src/utils/use-deprioritized-initial-focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAI/D;;;GAGG;AACH,KAAK,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAE,cAAc,CAAE,CAAC;AAe1D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAAE,EAC7C,YAAY,EACZ,sBAAsB,GACtB,EAAE;IACF,YAAY,EAAE,YAAY,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;CAC/B;;;EAiCA"}
1
+ {"version":3,"file":"use-deprioritized-initial-focus.d.ts","sourceRoot":"","sources":["../../src/utils/use-deprioritized-initial-focus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAIlE;;;;GAIG;AACH,KAAK,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAE,cAAc,CAAE,CAAC;AAe3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAAE,EAC7C,YAAY,EACZ,sBAAsB,GACtB,EAAE;IACF,YAAY,EAAE,YAAY,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;CAC/B;;;EAiCA"}
@@ -4,4 +4,11 @@ declare const meta: Meta<typeof VisuallyHidden>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof VisuallyHidden>;
6
6
  export declare const Default: Story;
7
+ /**
8
+ * Use the `render` prop to change the underlying HTML element.
9
+ * By default, `VisuallyHidden` renders a `<div>`. Here it renders
10
+ * a `<label>` instead, keeping the native label–input association
11
+ * while hiding the label text visually.
12
+ */
13
+ export declare const WithCustomElement: Story;
7
14
  //# sourceMappingURL=index.story.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.story.d.ts","sourceRoot":"","sources":["../../../src/visually-hidden/stories/index.story.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAErC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAE,OAAO,cAAc,CAGtC,CAAC;AACF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAE,OAAO,cAAc,CAAE,CAAC;AAE/C,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC"}
1
+ {"version":3,"file":"index.story.d.ts","sourceRoot":"","sources":["../../../src/visually-hidden/stories/index.story.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAErC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAE,OAAO,cAAc,CAGtC,CAAC;AACF,eAAe,IAAI,CAAC;AAEpB,KAAK,KAAK,GAAG,QAAQ,CAAE,OAAO,cAAc,CAAE,CAAC;AAE/C,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAgB/B,CAAC"}
@@ -2,6 +2,40 @@ import type { VisuallyHiddenProps } from './types';
2
2
  /**
3
3
  * Visually hides content while keeping it accessible to screen readers.
4
4
  * Useful when providing context that's only meaningful to assistive technology.
5
+ *
6
+ * Renders a `<div>` by default. Use the `render` prop to swap the
7
+ * underlying element while preserving the visually-hidden behavior.
8
+ *
9
+ * ## Composing with other components
10
+ *
11
+ * When composing with another component that uses the `render` prop
12
+ * pattern, there are two directions — and they produce different results.
13
+ *
14
+ * Most of the time you'll want `VisuallyHidden` as the **host** (outer
15
+ * component) and pass the other component via `render`. This keeps the
16
+ * other component's HTML element and semantics intact, while
17
+ * `VisuallyHidden` only adds its hiding styles:
18
+ *
19
+ * ```jsx
20
+ * // OtherComponent keeps its semantic element (e.g. <h2>).
21
+ * <VisuallyHidden render={ <OtherComponent /> }>
22
+ * Accessible text
23
+ * </VisuallyHidden>
24
+ * ```
25
+ *
26
+ * The opposite direction is also possible, but be aware that it replaces
27
+ * the other component's element with VisuallyHidden's default `<div>`:
28
+ *
29
+ * ```jsx
30
+ * // OtherComponent's element becomes a <div>.
31
+ * <OtherComponent render={ <VisuallyHidden /> }>
32
+ * Accessible text
33
+ * </OtherComponent>
34
+ * ```
35
+ *
36
+ * Choose based on what you need: if the other component's semantic
37
+ * element matters (e.g. `<label>`, `<legend>`, `<h2>`), keep
38
+ * `VisuallyHidden` as the host so the element is preserved.
5
39
  */
6
40
  export declare const VisuallyHidden: import("react").ForwardRefExoticComponent<VisuallyHiddenProps & import("react").RefAttributes<HTMLDivElement>>;
7
41
  //# sourceMappingURL=visually-hidden.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"visually-hidden.d.ts","sourceRoot":"","sources":["../../src/visually-hidden/visually-hidden.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGnD;;;GAGG;AACH,eAAO,MAAM,cAAc,gHAa1B,CAAC"}
1
+ {"version":3,"file":"visually-hidden.d.ts","sourceRoot":"","sources":["../../src/visually-hidden/visually-hidden.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,cAAc,gHAa1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/ui",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Themeable React UI components for the WordPress Design System.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -43,16 +43,16 @@
43
43
  "types": "build-types",
44
44
  "sideEffects": false,
45
45
  "dependencies": {
46
- "@base-ui/react": "^1.3.0",
47
- "@wordpress/a11y": "^4.43.0",
48
- "@wordpress/compose": "^7.43.0",
49
- "@wordpress/element": "^6.43.0",
50
- "@wordpress/i18n": "^6.16.0",
51
- "@wordpress/icons": "^12.1.0",
52
- "@wordpress/keycodes": "^4.43.0",
53
- "@wordpress/primitives": "^4.43.0",
54
- "@wordpress/private-apis": "^1.43.0",
55
- "@wordpress/theme": "^0.10.0",
46
+ "@base-ui/react": "^1.4.0",
47
+ "@wordpress/a11y": "^4.44.0",
48
+ "@wordpress/compose": "^7.44.0",
49
+ "@wordpress/element": "^6.44.0",
50
+ "@wordpress/i18n": "^6.17.0",
51
+ "@wordpress/icons": "^12.2.0",
52
+ "@wordpress/keycodes": "^4.44.0",
53
+ "@wordpress/primitives": "^4.44.0",
54
+ "@wordpress/private-apis": "^1.44.0",
55
+ "@wordpress/theme": "^0.11.0",
56
56
  "clsx": "^2.1.1",
57
57
  "tabbable": "^6.4.0"
58
58
  },
@@ -71,5 +71,5 @@
71
71
  "publishConfig": {
72
72
  "access": "public"
73
73
  },
74
- "gitHead": "2cea90674d11aa521ec3f71652fb3a6a4c383969"
74
+ "gitHead": "b862d8c84121a47bbeff882f6c87e61681ce2e0d"
75
75
  }
@@ -1,14 +1,22 @@
1
1
  import { createContext } from '@wordpress/element';
2
- import type { RootProps } from './types';
3
2
 
4
- type Intent = NonNullable< RootProps[ 'intent' ] >;
3
+ type Phase = 'idle' | 'pending' | 'closing';
5
4
 
6
5
  interface AlertDialogContextValue {
7
- intent: Intent;
6
+ phase: Phase;
7
+ showSpinner: boolean;
8
+ errorMessage?: string;
9
+ confirm: () => Promise< void >;
8
10
  }
9
11
 
12
+ const noop = async () => {};
13
+
10
14
  const AlertDialogContext = createContext< AlertDialogContextValue >( {
11
- intent: 'default',
15
+ phase: 'idle',
16
+ showSpinner: false,
17
+ errorMessage: undefined,
18
+ confirm: noop,
12
19
  } );
13
20
 
14
21
  export { AlertDialogContext };
22
+ export type { Phase };
@@ -1,56 +1,114 @@
1
+ import { AlertDialog as _AlertDialog } from '@base-ui/react/alert-dialog';
2
+ import clsx from 'clsx';
1
3
  import { forwardRef, useContext } from '@wordpress/element';
2
4
  import { __ } from '@wordpress/i18n';
5
+ import {
6
+ type ThemeProvider as ThemeProviderType,
7
+ privateApis as themePrivateApis,
8
+ } from '@wordpress/theme';
9
+
3
10
  import { Button } from '../button';
4
- import * as Dialog from '../dialog';
11
+ import dialogStyles from '../dialog/style.module.css';
12
+ import { unlock } from '../lock-unlock';
13
+ import { Stack } from '../stack';
14
+ import { Text } from '../text';
5
15
  import { AlertDialogContext } from './context';
6
- import styles from './style.module.css';
16
+ import alertDialogStyles from './style.module.css';
7
17
  import type { PopupProps } from './types';
8
18
 
19
+ const ThemeProvider: typeof ThemeProviderType =
20
+ unlock( themePrivateApis ).ThemeProvider;
21
+
9
22
  const Popup = forwardRef< HTMLDivElement, PopupProps >(
10
23
  function AlertDialogPopup(
11
24
  {
25
+ className,
26
+ container,
27
+ intent = 'default',
12
28
  title,
29
+ description,
13
30
  children,
14
- onConfirm,
15
31
  confirmButtonText = __( 'OK' ),
16
32
  cancelButtonText = __( 'Cancel' ),
17
- loading,
33
+ ...props
18
34
  },
19
35
  ref
20
36
  ) {
21
- const { intent } = useContext( AlertDialogContext );
37
+ const { phase, showSpinner, errorMessage, confirm } =
38
+ useContext( AlertDialogContext );
22
39
 
23
- // When `loading` is provided, the consumer controls when the dialog
24
- // closes (async flow). Use a plain Button so clicking confirm doesn't
25
- // auto-close — the consumer sets `open={false}` after their operation.
26
- const ConfirmButton = loading !== undefined ? Button : Dialog.Action;
40
+ const confirmClassName =
41
+ intent === 'irreversible'
42
+ ? alertDialogStyles[ 'irreversible-action' ]
43
+ : undefined;
44
+
45
+ const buttonsDisabled = phase !== 'idle' || undefined;
27
46
 
28
47
  return (
29
- <Dialog.Popup ref={ ref }>
30
- <Dialog.Header>
31
- <Dialog.Title>{ title }</Dialog.Title>
32
- </Dialog.Header>
33
- { children }
34
- <Dialog.Footer>
35
- <Dialog.Action
36
- variant="minimal"
37
- disabled={ loading || undefined }
38
- >
39
- { cancelButtonText }
40
- </Dialog.Action>
41
- <ConfirmButton
42
- className={
43
- intent === 'irreversible'
44
- ? styles[ 'irreversible-action' ]
45
- : undefined
46
- }
47
- onClick={ onConfirm }
48
- loading={ loading }
48
+ <_AlertDialog.Portal container={ container }>
49
+ <_AlertDialog.Backdrop className={ dialogStyles.backdrop } />
50
+ <ThemeProvider>
51
+ <_AlertDialog.Popup
52
+ ref={ ref }
53
+ className={ clsx(
54
+ dialogStyles.popup,
55
+ className,
56
+ dialogStyles[ 'is-medium' ]
57
+ ) }
58
+ { ...props }
49
59
  >
50
- { confirmButtonText }
51
- </ConfirmButton>
52
- </Dialog.Footer>
53
- </Dialog.Popup>
60
+ <Stack
61
+ direction="column"
62
+ gap="sm"
63
+ className={ alertDialogStyles.header }
64
+ >
65
+ <Text
66
+ variant="heading-xl"
67
+ render={ <_AlertDialog.Title /> }
68
+ >
69
+ { title }
70
+ </Text>
71
+ { description && (
72
+ <Text
73
+ variant="body-md"
74
+ render={ <_AlertDialog.Description /> }
75
+ >
76
+ { description }
77
+ </Text>
78
+ ) }
79
+ </Stack>
80
+ { children }
81
+ <Stack direction="column" gap="md">
82
+ <div className={ dialogStyles.footer }>
83
+ <_AlertDialog.Close
84
+ render={ <Button variant="minimal" /> }
85
+ disabled={ buttonsDisabled }
86
+ >
87
+ { cancelButtonText }
88
+ </_AlertDialog.Close>
89
+ <Button
90
+ className={ confirmClassName }
91
+ onClick={ confirm }
92
+ loading={ showSpinner || undefined }
93
+ disabled={ buttonsDisabled }
94
+ >
95
+ { confirmButtonText }
96
+ </Button>
97
+ </div>
98
+ { errorMessage && (
99
+ <Text
100
+ variant="body-sm"
101
+ className={
102
+ alertDialogStyles[ 'error-message' ]
103
+ }
104
+ >
105
+ { errorMessage }
106
+ </Text>
107
+ ) }
108
+ </Stack>
109
+ </_AlertDialog.Popup>
110
+ </ThemeProvider>
111
+ </_AlertDialog.Portal>
54
112
  );
55
113
  }
56
114
  );
@@ -1,8 +1,25 @@
1
1
  import { AlertDialog as _AlertDialog } from '@base-ui/react/alert-dialog';
2
- import { useMemo } from '@wordpress/element';
2
+ import { speak } from '@wordpress/a11y';
3
+ import {
4
+ useCallback,
5
+ useEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ } from '@wordpress/element';
10
+
3
11
  import { AlertDialogContext } from './context';
12
+ import type { Phase } from './context';
4
13
  import type { RootProps } from './types';
5
14
 
15
+ function isThenable( value: unknown ): value is PromiseLike< unknown > {
16
+ return (
17
+ value !== null &&
18
+ value !== undefined &&
19
+ typeof ( value as PromiseLike< unknown > ).then === 'function'
20
+ );
21
+ }
22
+
6
23
  /**
7
24
  * A dialog that requires a user response to proceed.
8
25
  *
@@ -11,32 +28,193 @@ import type { RootProps } from './types';
11
28
  * The `AlertDialog.Trigger` is optional — the dialog can also be controlled
12
29
  * via `open` / `onOpenChange` props.
13
30
  *
14
- * ## Use cases
15
- *
16
- * - **Default intent**: Standard confirmation dialog for reversible actions.
17
- * - **Irreversible intent**: Confirmation dialog for irreversible actions that
18
- * cannot be undone. The confirm button uses error/danger coloring.
19
- *
20
31
  * For use cases outside the standard confirm/cancel pattern, use the lower-level
21
32
  * `Dialog` component directly.
22
33
  *
23
- * See the [Destructive Actions guidelines](?path=/docs/design-system-patterns-destructive-actions--docs)
34
+ * See the [Destructive Actions guidelines](https://wordpress.github.io/gutenberg/?path=/docs/design-system-patterns-destructive-actions--docs)
24
35
  * for more details on when to use each pattern.
25
36
  */
26
37
  function Root( {
27
- intent = 'default',
28
38
  children,
29
- open,
39
+ open: openProp,
30
40
  onOpenChange,
31
41
  defaultOpen,
42
+ onConfirm,
32
43
  }: RootProps ) {
33
- const contextValue = useMemo( () => ( { intent } ), [ intent ] );
44
+ const [ internalOpen, setInternalOpen ] = useState( defaultOpen ?? false );
45
+
46
+ // Internal state machine for the confirm-and-close lifecycle.
47
+ //
48
+ // Phase transitions:
49
+ //
50
+ // idle ──> pending ──> closing ──> idle
51
+ // (confirm (success, (animation
52
+ // clicked) close) complete)
53
+ //
54
+ // idle ──> pending ──> idle
55
+ // (confirm (error, or
56
+ // clicked) {close:false})
57
+ //
58
+ // idle ──> closing ──> idle
59
+ // (cancel/ (animation
60
+ // escape) complete)
61
+ //
62
+ // `showSpinner` tracks whether the confirm button shows a loading
63
+ // indicator. It is orthogonal to `phase`:
64
+ //
65
+ // Scenario | pending | closing
66
+ // --------------------------+---------+---------
67
+ // Sync onConfirm | false | false
68
+ // Async onConfirm (success) | true | true
69
+ // Async onConfirm (error) | true | n/a (-> idle)
70
+ // Cancel / Escape | n/a | false
71
+ //
72
+ // Buttons are disabled whenever phase !== 'idle'.
73
+ // Dismiss (Escape / Cancel) is blocked during 'pending'.
74
+ const [ phase, setPhase ] = useState< Phase >( 'idle' );
75
+ const [ showSpinner, setShowSpinner ] = useState( false );
76
+ const [ errorMessage, setErrorMessage ] = useState< string >();
77
+
78
+ const actionsRef = useRef< _AlertDialog.Root.Actions | null >( null );
79
+
80
+ const onConfirmRef = useRef( onConfirm );
81
+ onConfirmRef.current = onConfirm;
82
+
83
+ // Ref keeps phase accessible synchronously from callbacks that may
84
+ // run between a setState call and the subsequent React re-render.
85
+ const phaseRef = useRef( phase );
86
+ phaseRef.current = phase;
87
+
88
+ // Generation counter — safety net for the edge case where the component
89
+ // unmounts while an async confirm is in flight. Also incremented when
90
+ // the dialog finishes closing, so a stale promise settling after a
91
+ // dismiss+reopen cycle is silently discarded.
92
+ const confirmIdRef = useRef( 0 );
93
+
94
+ const effectiveOpen = openProp ?? internalOpen;
95
+
96
+ // Safety net: if the consumer keeps `open={true}` after a confirm
97
+ // (i.e. does not react to `onOpenChange`), the phase would be stuck
98
+ // at 'closing'. Detect the contradiction and reset to idle.
99
+ useEffect( () => {
100
+ if ( effectiveOpen && phase === 'closing' ) {
101
+ phaseRef.current = 'idle';
102
+ setPhase( 'idle' );
103
+ setShowSpinner( false );
104
+ }
105
+ }, [ effectiveOpen, phase ] );
106
+
107
+ const handleOpenChange = useCallback(
108
+ (
109
+ nextOpen: boolean,
110
+ eventDetails: _AlertDialog.Root.ChangeEventDetails
111
+ ) => {
112
+ // Block dismiss while a confirm action is pending.
113
+ if ( ! nextOpen && phaseRef.current === 'pending' ) {
114
+ return;
115
+ }
116
+
117
+ if ( ! nextOpen && phaseRef.current === 'idle' ) {
118
+ phaseRef.current = 'closing';
119
+ setPhase( 'closing' );
120
+ }
121
+
122
+ setInternalOpen( nextOpen );
123
+ onOpenChange?.( nextOpen, eventDetails );
124
+ },
125
+ [ onOpenChange ]
126
+ );
127
+
128
+ const confirm = useCallback( async () => {
129
+ if ( phaseRef.current !== 'idle' ) {
130
+ return;
131
+ }
132
+
133
+ phaseRef.current = 'pending';
134
+ setPhase( 'pending' );
135
+ setErrorMessage( undefined );
136
+
137
+ const id = ++confirmIdRef.current;
138
+
139
+ try {
140
+ const rawResult = onConfirmRef.current?.();
141
+
142
+ // Show spinner only for async handlers (Promises).
143
+ // Sync handlers resolve in the same tick — no spinner needed.
144
+ if ( isThenable( rawResult ) ) {
145
+ setShowSpinner( true );
146
+ }
147
+
148
+ const result = await Promise.resolve( rawResult );
149
+
150
+ // Discard if the component unmounted or the dialog was
151
+ // dismissed and reopened while the promise was in flight.
152
+ if ( confirmIdRef.current !== id ) {
153
+ return;
154
+ }
155
+
156
+ // An error message implies the dialog should stay open.
157
+ if ( result?.error ) {
158
+ phaseRef.current = 'idle';
159
+ setPhase( 'idle' );
160
+ setShowSpinner( false );
161
+ setErrorMessage( result.error );
162
+ speak( result.error, 'assertive' );
163
+ return;
164
+ }
165
+
166
+ const shouldClose = result?.close !== false;
167
+
168
+ if ( shouldClose ) {
169
+ phaseRef.current = 'closing';
170
+ setPhase( 'closing' );
171
+ actionsRef.current?.close();
172
+ } else {
173
+ phaseRef.current = 'idle';
174
+ setPhase( 'idle' );
175
+ setShowSpinner( false );
176
+ }
177
+ } catch ( error ) {
178
+ if ( confirmIdRef.current !== id ) {
179
+ return;
180
+ }
181
+ phaseRef.current = 'idle';
182
+ setPhase( 'idle' );
183
+ setShowSpinner( false );
184
+ // eslint-disable-next-line no-console
185
+ console.error( error );
186
+ }
187
+ }, [] );
188
+
189
+ const handleOpenChangeComplete = useCallback( ( open: boolean ) => {
190
+ if ( ! open ) {
191
+ // Invalidate any in-flight async so a stale promise settling
192
+ // after dismiss+reopen doesn't close the new session.
193
+ confirmIdRef.current++;
194
+ phaseRef.current = 'idle';
195
+ setPhase( 'idle' );
196
+ setShowSpinner( false );
197
+ setErrorMessage( undefined );
198
+ }
199
+ }, [] );
200
+
201
+ const contextValue = useMemo(
202
+ () => ( {
203
+ phase,
204
+ showSpinner,
205
+ errorMessage,
206
+ confirm,
207
+ } ),
208
+ [ phase, showSpinner, errorMessage, confirm ]
209
+ );
34
210
 
35
211
  return (
36
212
  <_AlertDialog.Root
37
- open={ open }
38
- onOpenChange={ onOpenChange }
213
+ open={ effectiveOpen }
39
214
  defaultOpen={ defaultOpen }
215
+ onOpenChange={ handleOpenChange }
216
+ onOpenChangeComplete={ handleOpenChangeComplete }
217
+ actionsRef={ actionsRef }
40
218
  >
41
219
  <AlertDialogContext.Provider value={ contextValue }>
42
220
  { children }