@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,47 @@
1
+ import { Popover as _Popover } from '@base-ui/react/popover';
2
+ import { useMergeRefs } from '@wordpress/compose';
3
+ import { forwardRef, useLayoutEffect, useRef } from '@wordpress/element';
4
+ import { Text } from '../text';
5
+ import { usePopoverValidationContext } from './context';
6
+ import type { TitleProps } from './types';
7
+
8
+ /**
9
+ * Renders a heading that labels the popover for accessibility.
10
+ *
11
+ * **Required** — every popover must include a `Popover.Title`, even if
12
+ * visually hidden. The rendered element is linked to the popup via
13
+ * `aria-labelledby`. Uses the `heading-xl` text variant, matching Dialog.
14
+ *
15
+ * To visually hide the title while keeping it accessible, wrap it with
16
+ * `VisuallyHidden` using the `render` prop:
17
+ *
18
+ * ```jsx
19
+ * <VisuallyHidden render={ <Popover.Title /> }>
20
+ * Accessible title text
21
+ * </VisuallyHidden>
22
+ * ```
23
+ */
24
+ const Title = forwardRef< HTMLHeadingElement, TitleProps >(
25
+ function PopoverTitle( { className, children, ...props }, forwardedRef ) {
26
+ const validationContext = usePopoverValidationContext();
27
+ const internalRef = useRef< HTMLHeadingElement >( null );
28
+ const mergedRef = useMergeRefs( [ internalRef, forwardedRef ] );
29
+
30
+ useLayoutEffect( () => {
31
+ validationContext?.registerTitle( internalRef.current );
32
+ }, [ validationContext ] );
33
+
34
+ return (
35
+ <Text
36
+ ref={ mergedRef }
37
+ variant="heading-xl"
38
+ render={ <_Popover.Title { ...props } /> }
39
+ className={ className }
40
+ >
41
+ { children }
42
+ </Text>
43
+ );
44
+ }
45
+ );
46
+
47
+ export { Title };
@@ -0,0 +1,17 @@
1
+ import { Popover as _Popover } from '@base-ui/react/popover';
2
+ import { forwardRef } from '@wordpress/element';
3
+ import type { TriggerProps } from './types';
4
+
5
+ /**
6
+ * Renders a button that toggles the popover popup when clicked.
7
+ *
8
+ * Renders as a `<button>` by default. Also supports hover-triggered
9
+ * popovers via the `openOnHover`, `delay`, and `closeDelay` props.
10
+ */
11
+ const Trigger = forwardRef< HTMLButtonElement, TriggerProps >(
12
+ function PopoverTrigger( props, ref ) {
13
+ return <_Popover.Trigger ref={ ref } { ...props } />;
14
+ }
15
+ );
16
+
17
+ export { Trigger };
@@ -0,0 +1,113 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { Popover as _Popover } from '@base-ui/react/popover';
3
+ import type { ComponentProps } from '../utils/types';
4
+
5
+ export interface RootProps
6
+ extends Pick<
7
+ _Popover.Root.Props,
8
+ 'open' | 'onOpenChange' | 'defaultOpen' | 'modal'
9
+ > {
10
+ /**
11
+ * The popover sub-components (`Popover.Trigger`, `Popover.Popup`, etc.).
12
+ */
13
+ children?: ReactNode;
14
+ }
15
+
16
+ export interface TriggerProps
17
+ extends ComponentProps< 'button' >,
18
+ Pick< _Popover.Trigger.Props, 'openOnHover' | 'delay' | 'closeDelay' > {
19
+ /**
20
+ * The content to be rendered inside the component.
21
+ */
22
+ children?: ReactNode;
23
+ }
24
+
25
+ /**
26
+ * `Popover.Popup` maps to two Base UI elements internally: the
27
+ * **Positioner** (outer, handles fixed positioning and z-index) and the
28
+ * **Popup** (inner, holds content and visual styles).
29
+ *
30
+ * `style` and `className` are forwarded to the **Positioner** so that
31
+ * z-index overrides (`--wp-ui-popover-z-index`) and Base UI CSS variables
32
+ * (`--available-height`, `--available-width`) work correctly. All other
33
+ * HTML attributes are forwarded to the inner **Popup** element.
34
+ */
35
+ export interface PopupProps
36
+ extends ComponentProps< 'div' >,
37
+ Pick<
38
+ _Popover.Positioner.Props,
39
+ | 'align'
40
+ | 'alignOffset'
41
+ | 'anchor'
42
+ | 'arrowPadding'
43
+ | 'collisionAvoidance'
44
+ | 'collisionBoundary'
45
+ | 'collisionPadding'
46
+ | 'side'
47
+ | 'sideOffset'
48
+ | 'sticky'
49
+ >,
50
+ Pick< _Popover.Popup.Props, 'initialFocus' | 'finalFocus' > {
51
+ /**
52
+ * Whether to render a backdrop overlay behind the popover.
53
+ *
54
+ * Typically used with `modal` to signal that interaction with the rest
55
+ * of the page is blocked. The backdrop is a semi-transparent dark overlay.
56
+ *
57
+ * @default false
58
+ */
59
+ backdrop?: boolean;
60
+
61
+ /**
62
+ * The content to be rendered inside the component.
63
+ */
64
+ children?: ReactNode;
65
+
66
+ /**
67
+ * A parent element to render the portal into.
68
+ *
69
+ * Useful for cross-document rendering, such as rendering a popover
70
+ * in a parent document when the trigger is inside an iframe.
71
+ */
72
+ container?: _Popover.Portal.Props[ 'container' ];
73
+
74
+ /**
75
+ * The visual style variant of the popup.
76
+ *
77
+ * - `'default'` — standard surface styling with background, padding,
78
+ * border radius, and shadow.
79
+ * - `'unstyled'` — no visual treatment; useful as a blank positioning
80
+ * container for fully custom content.
81
+ *
82
+ * @default 'default'
83
+ */
84
+ variant?: 'default' | 'unstyled';
85
+ }
86
+
87
+ export interface ArrowProps extends ComponentProps< 'div' > {
88
+ /**
89
+ * Custom arrow visuals to render inside the positioned container.
90
+ */
91
+ children?: ReactNode;
92
+ }
93
+
94
+ export interface TitleProps extends ComponentProps< 'h2' > {
95
+ /**
96
+ * The title content to be rendered.
97
+ */
98
+ children?: ReactNode;
99
+ }
100
+
101
+ export interface DescriptionProps extends ComponentProps< 'p' > {
102
+ /**
103
+ * The description content to be rendered.
104
+ */
105
+ children?: ReactNode;
106
+ }
107
+
108
+ export interface CloseProps extends ComponentProps< 'button' > {
109
+ /**
110
+ * The content to be rendered inside the component.
111
+ */
112
+ children?: ReactNode;
113
+ }
package/src/tabs/list.tsx CHANGED
@@ -21,7 +21,6 @@ export const List = forwardRef< HTMLDivElement, TabListProps >(
21
21
  variant = 'default',
22
22
  className,
23
23
  activateOnFocus,
24
- render,
25
24
  ...otherProps
26
25
  },
27
26
  forwardedRef
@@ -122,8 +122,8 @@
122
122
  cursor: var(--wpds-cursor-control);
123
123
 
124
124
  /* Typography */
125
- font-family: var(--wpds-font-family-body);
126
- font-size: var(--wpds-font-size-md);
125
+ font-family: var(--wpds-typography-font-family-body);
126
+ font-size: var(--wpds-typography-font-size-md);
127
127
  white-space: nowrap;
128
128
 
129
129
  /* Characters in some languages (e.g. Japanese) may have a native higher line-height. */
@@ -1,4 +1,3 @@
1
- /* eslint-disable jsx-a11y/heading-has-content */
2
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
3
2
  import { Text } from '../index';
4
3
  import { Stack } from '../../stack';
@@ -18,6 +17,10 @@ export const Default: Story = {
18
17
  },
19
18
  };
20
19
 
20
+ /**
21
+ * Important: Setting the `variant` prop to a `heading` variant will not automatically render a heading element.
22
+ * Use the `render` prop to render a heading element with the appropriate level.
23
+ */
21
24
  export const AllVariants: Story = {
22
25
  render: () => (
23
26
  <Stack
@@ -65,4 +68,3 @@ export const WithRenderProp: Story = {
65
68
  </Stack>
66
69
  ),
67
70
  };
68
- /* eslint-enable jsx-a11y/heading-has-content */
@@ -1,67 +1,93 @@
1
1
  @layer wp-ui-utilities, wp-ui-components, wp-ui-compositions, wp-ui-overrides;
2
2
 
3
3
  @layer wp-ui-components {
4
+ .text {
5
+ margin: 0;
6
+ }
7
+
4
8
  .heading-2xl {
5
- font-family: var(--wpds-font-family-heading);
6
- font-size: var(--wpds-font-size-2xl);
7
- line-height: var(--wpds-font-line-height-2xl);
8
- font-weight: var(--wpds-font-weight-medium);
9
+ --_gcd-heading-font-size: var(--wpds-typography-font-size-2xl);
10
+
11
+ font-family: var(--wpds-typography-font-family-heading);
12
+ font-size: var(--wpds-typography-font-size-2xl);
13
+ line-height: var(--wpds-typography-line-height-2xl);
14
+ font-weight: var(--wpds-typography-font-weight-medium);
9
15
  }
10
16
 
11
17
  .heading-xl {
12
- font-family: var(--wpds-font-family-heading);
13
- font-size: var(--wpds-font-size-xl);
14
- line-height: var(--wpds-font-line-height-md);
15
- font-weight: var(--wpds-font-weight-medium);
18
+ --_gcd-heading-font-size: var(--wpds-typography-font-size-xl);
19
+
20
+ font-family: var(--wpds-typography-font-family-heading);
21
+ font-size: var(--wpds-typography-font-size-xl);
22
+ line-height: var(--wpds-typography-line-height-md);
23
+ font-weight: var(--wpds-typography-font-weight-medium);
16
24
  }
17
25
 
18
26
  .heading-lg {
19
- font-family: var(--wpds-font-family-heading);
20
- font-size: var(--wpds-font-size-lg);
21
- line-height: var(--wpds-font-line-height-sm);
22
- font-weight: var(--wpds-font-weight-medium);
27
+ --_gcd-heading-font-size: var(--wpds-typography-font-size-lg);
28
+
29
+ font-family: var(--wpds-typography-font-family-heading);
30
+ font-size: var(--wpds-typography-font-size-lg);
31
+ line-height: var(--wpds-typography-line-height-sm);
32
+ font-weight: var(--wpds-typography-font-weight-medium);
23
33
  }
24
34
 
25
35
  .heading-md {
26
- font-family: var(--wpds-font-family-heading);
27
- font-size: var(--wpds-font-size-md);
28
- line-height: var(--wpds-font-line-height-sm);
29
- font-weight: var(--wpds-font-weight-medium);
36
+ --_gcd-heading-font-size: var(--wpds-typography-font-size-md);
37
+
38
+ font-family: var(--wpds-typography-font-family-heading);
39
+ font-size: var(--wpds-typography-font-size-md);
40
+ line-height: var(--wpds-typography-line-height-sm);
41
+ font-weight: var(--wpds-typography-font-weight-medium);
30
42
  }
31
43
 
32
44
  .heading-sm {
33
- font-family: var(--wpds-font-family-heading);
34
- font-size: var(--wpds-font-size-xs);
35
- line-height: var(--wpds-font-line-height-xs);
36
- font-weight: var(--wpds-font-weight-medium);
45
+ --_gcd-heading-font-size: var(--wpds-typography-font-size-xs);
46
+
47
+ font-family: var(--wpds-typography-font-family-heading);
48
+ font-size: var(--wpds-typography-font-size-xs);
49
+ line-height: var(--wpds-typography-line-height-xs);
50
+ font-weight: var(--wpds-typography-font-weight-medium);
37
51
  text-transform: uppercase;
38
52
  }
39
53
 
40
54
  .body-xl {
41
- font-family: var(--wpds-font-family-body);
42
- font-size: var(--wpds-font-size-xl);
43
- line-height: var(--wpds-font-line-height-xl);
44
- font-weight: var(--wpds-font-weight-regular);
55
+ --_gcd-p-font-size: var(--wpds-typography-font-size-xl);
56
+ --_gcd-p-line-height: var(--wpds-typography-line-height-xl);
57
+
58
+ font-family: var(--wpds-typography-font-family-body);
59
+ font-size: var(--wpds-typography-font-size-xl);
60
+ line-height: var(--wpds-typography-line-height-xl);
61
+ font-weight: var(--wpds-typography-font-weight-regular);
45
62
  }
46
63
 
47
64
  .body-lg {
48
- font-family: var(--wpds-font-family-body);
49
- font-size: var(--wpds-font-size-lg);
50
- line-height: var(--wpds-font-line-height-md);
51
- font-weight: var(--wpds-font-weight-regular);
65
+ --_gcd-p-font-size: var(--wpds-typography-font-size-lg);
66
+ --_gcd-p-line-height: var(--wpds-typography-line-height-md);
67
+
68
+ font-family: var(--wpds-typography-font-family-body);
69
+ font-size: var(--wpds-typography-font-size-lg);
70
+ line-height: var(--wpds-typography-line-height-md);
71
+ font-weight: var(--wpds-typography-font-weight-regular);
52
72
  }
53
73
 
54
74
  .body-md {
55
- font-family: var(--wpds-font-family-body);
56
- font-size: var(--wpds-font-size-md);
57
- line-height: var(--wpds-font-line-height-sm);
58
- font-weight: var(--wpds-font-weight-regular);
75
+ --_gcd-p-font-size: var(--wpds-typography-font-size-md);
76
+ --_gcd-p-line-height: var(--wpds-typography-line-height-sm);
77
+
78
+ font-family: var(--wpds-typography-font-family-body);
79
+ font-size: var(--wpds-typography-font-size-md);
80
+ line-height: var(--wpds-typography-line-height-sm);
81
+ font-weight: var(--wpds-typography-font-weight-regular);
59
82
  }
60
83
 
61
84
  .body-sm {
62
- font-family: var(--wpds-font-family-body);
63
- font-size: var(--wpds-font-size-sm);
64
- line-height: var(--wpds-font-line-height-xs);
65
- font-weight: var(--wpds-font-weight-regular);
85
+ --_gcd-p-font-size: var(--wpds-typography-font-size-sm);
86
+ --_gcd-p-line-height: var(--wpds-typography-line-height-xs);
87
+
88
+ font-family: var(--wpds-typography-font-family-body);
89
+ font-size: var(--wpds-typography-font-size-sm);
90
+ line-height: var(--wpds-typography-line-height-xs);
91
+ font-weight: var(--wpds-typography-font-weight-regular);
66
92
  }
67
93
  }
@@ -34,10 +34,7 @@ describe( 'Text', () => {
34
34
  } );
35
35
 
36
36
  it( 'supports the render prop', () => {
37
- render(
38
- // eslint-disable-next-line jsx-a11y/heading-has-content
39
- <Text render={ <h2 /> }>Section title</Text>
40
- );
37
+ render( <Text render={ <h2 /> }>Section title</Text> );
41
38
 
42
39
  expect(
43
40
  screen.getByRole( 'heading', { level: 2, name: 'Section title' } )
package/src/text/text.tsx CHANGED
@@ -3,6 +3,7 @@ import clsx from 'clsx';
3
3
  import { forwardRef } from '@wordpress/element';
4
4
  import { type TextProps } from './types';
5
5
  import styles from './style.module.css';
6
+ import defenseStyles from '../utils/css/global-css-defense.module.css';
6
7
 
7
8
  /**
8
9
  * A text component for rendering content with predefined typographic variants.
@@ -17,7 +18,13 @@ export const Text = forwardRef< HTMLSpanElement, TextProps >( function Text(
17
18
  defaultTagName: 'span',
18
19
  ref,
19
20
  props: mergeProps< 'span' >( props, {
20
- className: clsx( styles[ variant ], className ),
21
+ className: clsx(
22
+ styles.text,
23
+ variant.startsWith( 'heading-' ) && defenseStyles.heading,
24
+ variant.startsWith( 'body-' ) && defenseStyles.p,
25
+ styles[ variant ],
26
+ className
27
+ ),
21
28
  } ),
22
29
  } );
23
30
 
@@ -16,6 +16,7 @@ const ThemeProvider: typeof ThemeProviderType =
16
16
  const Popup = forwardRef< HTMLDivElement, PopupProps >( function TooltipPopup(
17
17
  {
18
18
  align = 'center',
19
+ container,
19
20
  side = 'top',
20
21
  sideOffset = 4,
21
22
  children,
@@ -26,7 +27,7 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function TooltipPopup(
26
27
  ref
27
28
  ) {
28
29
  return (
29
- <Tooltip.Portal>
30
+ <Tooltip.Portal container={ container }>
30
31
  <Tooltip.Positioner
31
32
  align={ align }
32
33
  side={ side }
@@ -2,16 +2,17 @@ import { Tooltip } from '@base-ui/react/tooltip';
2
2
  import type { RootProps } from './types';
3
3
 
4
4
  /**
5
- * `Tooltip` is used to visually show the label of an icon button, or other such interactive controls
6
- * that don't have a visual text label.
5
+ * `Tooltip` is used to visually show the label of an icon button, or other such
6
+ * interactive controls that don't have a visual text label.
7
7
  *
8
- * Tooltips are not available on touch devices, and thus should not be used for infotips,
9
- * descriptions, or dynamic status messages.
8
+ * Tooltip popups are visual-only and not exposed to assistive technologies.
9
+ * The trigger's accessible name (e.g. `aria-label`) is the source of truth
10
+ * for screen reader users. Tooltips are not available on touch devices,
11
+ * and thus should not be used for infotips, descriptions, or dynamic status
12
+ * messages.
10
13
  *
11
- * The tooltip itself does not provide any accessible labeling, so when using the
12
- * `Tooltip` primitive you must ensure that the trigger is accessibly labeled (e.g. with an `aria-label`).
13
- *
14
- * See also: [IconButton](https://wordpress.github.io/gutenberg/?path=/docs/design-system-components-iconbutton--docs)
14
+ * @see {@link https://wordpress.github.io/gutenberg/?path=/docs/design-system-components-tooltip-usage-guidelines--docs Usage Guidelines}
15
+ * @see {@link https://wordpress.github.io/gutenberg/?path=/docs/design-system-components-iconbutton--docs IconButton}
15
16
  */
16
17
  function Root( props: RootProps ) {
17
18
  return <Tooltip.Root { ...props } />;
@@ -0,0 +1,91 @@
1
+ import { Canvas, Meta } from '@storybook/addon-docs/blocks';
2
+ import * as UsageGuidelinesStories from './usage-guidelines.story';
3
+
4
+ <Meta of={ UsageGuidelinesStories } />
5
+
6
+ # Tooltip usage guidelines
7
+
8
+ ## Usage guidelines
9
+
10
+ - **Use tooltips as visual labels only.** Tooltips should act as
11
+ supplementary visual labels for sighted mouse and keyboard users.
12
+ Tooltip popups are not exposed to assistive technologies — the
13
+ trigger's accessible name (e.g. `aria-label`) is what provides the
14
+ label for screen reader users.
15
+ See [_Alternatives to tooltips_](#alternatives-to-tooltips) below for
16
+ more details.
17
+ - **Provide an accessible name for the trigger.** Tooltips are visual-only
18
+ elements and are not a replacement for labeling the trigger. The
19
+ tooltip's trigger must have an `aria-label` that matches or is a concise
20
+ equivalent of the tooltip's content to ensure consistency for screen
21
+ reader users. If the tooltip also displays a keyboard shortcut, use
22
+ `aria-keyshortcuts` on the trigger.
23
+
24
+ <Canvas of={ UsageGuidelinesStories.RecommendedUsage } />
25
+
26
+ `IconButton` has built-in tooltip support via the `label` prop, making it
27
+ the easiest way to provide a tooltip for icon-only actions.
28
+
29
+ <Canvas of={ UsageGuidelinesStories.IconButtonWithTooltip } />
30
+
31
+ ## Alternatives to tooltips
32
+
33
+ Tooltips should be supplementary popups that provide non-essential clarity in
34
+ high-density UIs. A user should not miss critical information if they never
35
+ see a tooltip.
36
+
37
+ Tooltips don't work well with touch input. Unlike mouse pointers with hover
38
+ capability, there's no easily discoverable way to reveal a tooltip before
39
+ tapping its trigger on a touch device.
40
+
41
+ iOS doesn't provide a system-standard, touch-friendly tooltip affordance,
42
+ while Android may show a tooltip on long press. However, on the web,
43
+ long press is often used to trigger contextual menus in the browser, which
44
+ can lead to potential conflicts. For this reason, tooltips are disabled on
45
+ touch devices.
46
+
47
+ ### Infotips
48
+
49
+ Popups that open when hovering an info icon should use
50
+ [Popover](?path=/docs/design-system-components-popover--docs) with the
51
+ `openOnHover` prop on the trigger instead of a tooltip. This way, touch
52
+ users and screen reader users can access the content.
53
+
54
+ To know when to reach for a popover instead of a tooltip, consider the
55
+ **purpose** of the trigger element: if the trigger's purpose is to open the
56
+ popup itself, it's a popover. If the trigger's purpose is unrelated to
57
+ opening the popup, it's a tooltip.
58
+
59
+ <Canvas of={ UsageGuidelinesStories.InfotipWithPopover } />
60
+
61
+ See also the [Popover Infotip story](?path=/story/design-system-components-popover--infotip).
62
+
63
+ Infotips opened on hover can be dismissed by pressing `Escape`.
64
+
65
+ ### Description text
66
+
67
+ Tooltips are designed for sighted mouse and keyboard users and are not a reliable way to deliver
68
+ important information to touch users or assistive technologies. If the
69
+ description is important to understanding the element, don't hide it behind a
70
+ tooltip — use inline text or
71
+ [Popover](?path=/docs/design-system-components-popover--docs) if space is
72
+ limited, so the information is accessible to everyone.
73
+
74
+ Since tooltips serve sighted mouse and keyboard users, iconography should
75
+ clearly communicate the purpose of icon-only triggers, especially on mobile
76
+ where the text label may not be visible.
77
+
78
+ If the description is not critical, a tooltip can still be used to provide
79
+ extra clarity for sighted mouse or keyboard users.
80
+
81
+ ### Contextual feedback messages
82
+
83
+ For contextual feedback after an action (e.g. "Copied!"), prefer a pattern
84
+ that ensures the message is announced to screen readers and supports complex
85
+ content, such as a
86
+ [Notice](?path=/docs/design-system-components-notice--docs).
87
+
88
+ ## References
89
+
90
+ - [WCAG 1.4.13: Content on Hover or Focus](https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html) — tooltips must be dismissible (Escape), hoverable, and persistent.
91
+ - [WAI-ARIA APG: Tooltip pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/) — note that this component intentionally diverges from the traditional `role="tooltip"` + `aria-describedby` pattern. The trigger's `aria-label` is the source of truth for assistive technologies, and the tooltip popup is a visual-only supplement.
@@ -0,0 +1,119 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import {
3
+ formatBold,
4
+ formatItalic,
5
+ formatUnderline,
6
+ info,
7
+ } from '@wordpress/icons';
8
+ import { Icon, IconButton, Popover, Tooltip, VisuallyHidden } from '../..';
9
+
10
+ const meta: Meta = {
11
+ title: 'Design System/Components/Tooltip/Usage Guidelines',
12
+ parameters: {
13
+ controls: { disable: true },
14
+ },
15
+ tags: [ '!dev' ],
16
+ };
17
+ export default meta;
18
+
19
+ type Story = StoryObj;
20
+
21
+ /**
22
+ * Tooltips work best as visual labels for icon-only controls. Each trigger
23
+ * must have its own accessible name via `aria-label`.
24
+ */
25
+ export const RecommendedUsage: Story = {
26
+ render: () => (
27
+ <Tooltip.Provider delay={ 0 }>
28
+ <div style={ { display: 'flex', gap: '0.25rem' } }>
29
+ <Tooltip.Root>
30
+ <Tooltip.Trigger aria-label="Bold">
31
+ <Icon icon={ formatBold } />
32
+ </Tooltip.Trigger>
33
+ <Tooltip.Popup>Bold</Tooltip.Popup>
34
+ </Tooltip.Root>
35
+
36
+ <Tooltip.Root>
37
+ <Tooltip.Trigger aria-label="Italic">
38
+ <Icon icon={ formatItalic } />
39
+ </Tooltip.Trigger>
40
+ <Tooltip.Popup>Italic</Tooltip.Popup>
41
+ </Tooltip.Root>
42
+
43
+ <Tooltip.Root>
44
+ <Tooltip.Trigger aria-label="Underline">
45
+ <Icon icon={ formatUnderline } />
46
+ </Tooltip.Trigger>
47
+ <Tooltip.Popup>Underline</Tooltip.Popup>
48
+ </Tooltip.Root>
49
+ </div>
50
+ </Tooltip.Provider>
51
+ ),
52
+ };
53
+
54
+ /**
55
+ * Popups that open when hovering an info icon should use `Popover` with
56
+ * `openOnHover` instead of a Tooltip. This ensures the content is accessible
57
+ * to touch and screen reader users.
58
+ */
59
+ export const InfotipWithPopover: Story = {
60
+ render: () => (
61
+ <div
62
+ style={ {
63
+ display: 'flex',
64
+ alignItems: 'center',
65
+ gap: 'var(--wpds-dimension-gap-xs)',
66
+ } }
67
+ >
68
+ <span>Label</span>
69
+ <Popover.Root>
70
+ <Popover.Trigger
71
+ openOnHover
72
+ delay={ 200 }
73
+ closeDelay={ 200 }
74
+ aria-label="More information"
75
+ style={ {
76
+ background: 'none',
77
+ border: 'none',
78
+ padding: 0,
79
+ cursor: 'var(--wpds-cursor-control)',
80
+ display: 'inline-flex',
81
+ alignItems: 'center',
82
+ borderRadius: 'var(--wpds-border-radius-sm)',
83
+ } }
84
+ >
85
+ <Icon icon={ info } size={ 20 } />
86
+ </Popover.Trigger>
87
+ <Popover.Popup>
88
+ <Popover.Arrow />
89
+ <VisuallyHidden render={ <Popover.Title /> }>
90
+ More information
91
+ </VisuallyHidden>
92
+ <Popover.Description>
93
+ This is additional context about the label. Unlike
94
+ tooltips, this content is accessible to touch and screen
95
+ reader users.
96
+ </Popover.Description>
97
+ </Popover.Popup>
98
+ </Popover.Root>
99
+ </div>
100
+ ),
101
+ };
102
+
103
+ /**
104
+ * `IconButton` has built-in tooltip support via the `label` prop,
105
+ * making it the easiest way to provide a tooltip for icon-only actions.
106
+ */
107
+ export const IconButtonWithTooltip: Story = {
108
+ render: () => (
109
+ <div style={ { display: 'flex', gap: '0.25rem' } }>
110
+ <IconButton icon={ formatBold } label="Bold" size="compact" />
111
+ <IconButton icon={ formatItalic } label="Italic" size="compact" />
112
+ <IconButton
113
+ icon={ formatUnderline }
114
+ label="Underline"
115
+ size="compact"
116
+ />
117
+ </div>
118
+ ),
119
+ };
@@ -11,8 +11,8 @@
11
11
  var(--wpds-dimension-padding-xs)
12
12
  var(--wpds-dimension-padding-sm);
13
13
  border-radius: var(--wpds-border-radius-sm);
14
- font-family: var(--wpds-font-family-body);
15
- font-size: var(--wpds-font-size-sm);
14
+ font-family: var(--wpds-typography-font-family-body);
15
+ font-size: var(--wpds-typography-font-size-sm);
16
16
  line-height: 1.4; /* TODO: use DS token for line height */
17
17
  color: var(--wpds-color-fg-content-neutral);
18
18
  box-shadow: var(--wpds-elevation-sm);