@wordpress/ui 0.13.1-next.v.202605131032.0 → 0.15.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 (272) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/CONTRIBUTING.md +34 -0
  3. package/README.md +15 -0
  4. package/build/alert-dialog/portal.cjs.map +2 -2
  5. package/build/alert-dialog/types.cjs.map +1 -1
  6. package/build/button/button.cjs +1 -1
  7. package/build/button/button.cjs.map +2 -2
  8. package/build/card/content.cjs +1 -1
  9. package/build/card/content.cjs.map +2 -2
  10. package/build/card/full-bleed.cjs +1 -1
  11. package/build/card/full-bleed.cjs.map +2 -2
  12. package/build/card/header.cjs +1 -1
  13. package/build/card/header.cjs.map +2 -2
  14. package/build/card/root.cjs +1 -1
  15. package/build/card/root.cjs.map +2 -2
  16. package/build/collapsible-card/header.cjs.map +2 -2
  17. package/build/dialog/portal.cjs.map +2 -2
  18. package/build/dialog/types.cjs.map +1 -1
  19. package/build/drawer/portal.cjs.map +2 -2
  20. package/build/drawer/types.cjs.map +1 -1
  21. package/build/form/primitives/autocomplete/clear.cjs +4 -1
  22. package/build/form/primitives/autocomplete/clear.cjs.map +2 -2
  23. package/build/form/primitives/autocomplete/empty.cjs +1 -1
  24. package/build/form/primitives/autocomplete/empty.cjs.map +2 -2
  25. package/build/form/primitives/autocomplete/index.cjs +4 -1
  26. package/build/form/primitives/autocomplete/index.cjs.map +2 -2
  27. package/build/form/primitives/autocomplete/item.cjs +1 -1
  28. package/build/form/primitives/autocomplete/item.cjs.map +2 -2
  29. package/build/form/primitives/autocomplete/list-body.cjs +1 -1
  30. package/build/form/primitives/autocomplete/list-body.cjs.map +2 -2
  31. package/build/form/primitives/autocomplete/list.cjs +1 -1
  32. package/build/form/primitives/autocomplete/list.cjs.map +2 -2
  33. package/build/form/primitives/autocomplete/popup.cjs +14 -31
  34. package/build/form/primitives/autocomplete/popup.cjs.map +3 -3
  35. package/build/form/primitives/autocomplete/portal.cjs +10 -2
  36. package/build/form/primitives/autocomplete/portal.cjs.map +2 -2
  37. package/build/form/primitives/autocomplete/positioner.cjs +158 -0
  38. package/build/form/primitives/autocomplete/positioner.cjs.map +7 -0
  39. package/build/form/primitives/autocomplete/types.cjs.map +1 -1
  40. package/build/form/primitives/constants.cjs.map +2 -2
  41. package/build/form/primitives/select/index.cjs +4 -1
  42. package/build/form/primitives/select/index.cjs.map +2 -2
  43. package/build/form/primitives/select/item.cjs +1 -1
  44. package/build/form/primitives/select/item.cjs.map +2 -2
  45. package/build/form/primitives/select/popup.cjs +18 -36
  46. package/build/form/primitives/select/popup.cjs.map +3 -3
  47. package/build/form/primitives/select/portal.cjs +11 -5
  48. package/build/form/primitives/select/portal.cjs.map +2 -2
  49. package/build/form/primitives/select/positioner.cjs +159 -0
  50. package/build/form/primitives/select/positioner.cjs.map +7 -0
  51. package/build/form/primitives/select/types.cjs.map +1 -1
  52. package/build/icon-button/icon-button.cjs +1 -1
  53. package/build/icon-button/icon-button.cjs.map +2 -2
  54. package/build/index.cjs +7 -1
  55. package/build/index.cjs.map +2 -2
  56. package/build/popover/index.cjs +3 -0
  57. package/build/popover/index.cjs.map +2 -2
  58. package/build/popover/popup.cjs +23 -51
  59. package/build/popover/popup.cjs.map +3 -3
  60. package/build/popover/portal.cjs.map +2 -2
  61. package/build/popover/positioner.cjs +168 -0
  62. package/build/popover/positioner.cjs.map +7 -0
  63. package/build/popover/root.cjs.map +2 -2
  64. package/build/popover/types.cjs.map +1 -1
  65. package/build/tooltip/portal.cjs +10 -2
  66. package/build/tooltip/portal.cjs.map +2 -2
  67. package/build/tooltip/positioner.cjs.map +2 -2
  68. package/build/tooltip/types.cjs.map +1 -1
  69. package/build/utils/use-enable-wp-compat-overlay-slot.cjs +39 -0
  70. package/build/utils/use-enable-wp-compat-overlay-slot.cjs.map +7 -0
  71. package/build/utils/wp-compat-overlay-slot.cjs +177 -0
  72. package/build/utils/wp-compat-overlay-slot.cjs.map +7 -0
  73. package/build-module/alert-dialog/portal.mjs.map +2 -2
  74. package/build-module/button/button.mjs +1 -1
  75. package/build-module/button/button.mjs.map +2 -2
  76. package/build-module/card/content.mjs +1 -1
  77. package/build-module/card/content.mjs.map +2 -2
  78. package/build-module/card/full-bleed.mjs +1 -1
  79. package/build-module/card/full-bleed.mjs.map +2 -2
  80. package/build-module/card/header.mjs +1 -1
  81. package/build-module/card/header.mjs.map +2 -2
  82. package/build-module/card/root.mjs +1 -1
  83. package/build-module/card/root.mjs.map +2 -2
  84. package/build-module/collapsible-card/header.mjs.map +2 -2
  85. package/build-module/dialog/portal.mjs.map +2 -2
  86. package/build-module/drawer/portal.mjs.map +2 -2
  87. package/build-module/form/primitives/autocomplete/clear.mjs +4 -1
  88. package/build-module/form/primitives/autocomplete/clear.mjs.map +2 -2
  89. package/build-module/form/primitives/autocomplete/empty.mjs +1 -1
  90. package/build-module/form/primitives/autocomplete/empty.mjs.map +2 -2
  91. package/build-module/form/primitives/autocomplete/index.mjs +3 -1
  92. package/build-module/form/primitives/autocomplete/index.mjs.map +2 -2
  93. package/build-module/form/primitives/autocomplete/item.mjs +1 -1
  94. package/build-module/form/primitives/autocomplete/item.mjs.map +2 -2
  95. package/build-module/form/primitives/autocomplete/list-body.mjs +1 -1
  96. package/build-module/form/primitives/autocomplete/list-body.mjs.map +2 -2
  97. package/build-module/form/primitives/autocomplete/list.mjs +1 -1
  98. package/build-module/form/primitives/autocomplete/list.mjs.map +2 -2
  99. package/build-module/form/primitives/autocomplete/popup.mjs +14 -31
  100. package/build-module/form/primitives/autocomplete/popup.mjs.map +3 -3
  101. package/build-module/form/primitives/autocomplete/portal.mjs +10 -2
  102. package/build-module/form/primitives/autocomplete/portal.mjs.map +2 -2
  103. package/build-module/form/primitives/autocomplete/positioner.mjs +123 -0
  104. package/build-module/form/primitives/autocomplete/positioner.mjs.map +7 -0
  105. package/build-module/form/primitives/constants.mjs.map +2 -2
  106. package/build-module/form/primitives/select/index.mjs +3 -1
  107. package/build-module/form/primitives/select/index.mjs.map +2 -2
  108. package/build-module/form/primitives/select/item.mjs +1 -1
  109. package/build-module/form/primitives/select/item.mjs.map +2 -2
  110. package/build-module/form/primitives/select/popup.mjs +18 -36
  111. package/build-module/form/primitives/select/popup.mjs.map +3 -3
  112. package/build-module/form/primitives/select/portal.mjs +11 -5
  113. package/build-module/form/primitives/select/portal.mjs.map +2 -2
  114. package/build-module/form/primitives/select/positioner.mjs +124 -0
  115. package/build-module/form/primitives/select/positioner.mjs.map +7 -0
  116. package/build-module/icon-button/icon-button.mjs +1 -1
  117. package/build-module/icon-button/icon-button.mjs.map +2 -2
  118. package/build-module/index.mjs +5 -1
  119. package/build-module/index.mjs.map +2 -2
  120. package/build-module/popover/index.mjs +2 -0
  121. package/build-module/popover/index.mjs.map +2 -2
  122. package/build-module/popover/popup.mjs +23 -51
  123. package/build-module/popover/popup.mjs.map +3 -3
  124. package/build-module/popover/portal.mjs.map +2 -2
  125. package/build-module/popover/positioner.mjs +133 -0
  126. package/build-module/popover/positioner.mjs.map +7 -0
  127. package/build-module/popover/root.mjs.map +2 -2
  128. package/build-module/tooltip/portal.mjs +10 -2
  129. package/build-module/tooltip/portal.mjs.map +2 -2
  130. package/build-module/tooltip/positioner.mjs.map +2 -2
  131. package/build-module/utils/use-enable-wp-compat-overlay-slot.mjs +14 -0
  132. package/build-module/utils/use-enable-wp-compat-overlay-slot.mjs.map +7 -0
  133. package/build-module/utils/wp-compat-overlay-slot.mjs +148 -0
  134. package/build-module/utils/wp-compat-overlay-slot.mjs.map +7 -0
  135. package/build-types/alert-dialog/portal.d.ts +8 -5
  136. package/build-types/alert-dialog/portal.d.ts.map +1 -1
  137. package/build-types/alert-dialog/types.d.ts +2 -2
  138. package/build-types/alert-dialog/types.d.ts.map +1 -1
  139. package/build-types/badge/stories/e2e/index.story.d.ts +7 -0
  140. package/build-types/badge/stories/e2e/index.story.d.ts.map +1 -0
  141. package/build-types/button/stories/e2e/index.story.d.ts +8 -0
  142. package/build-types/button/stories/e2e/index.story.d.ts.map +1 -0
  143. package/build-types/card/full-bleed.d.ts +18 -0
  144. package/build-types/card/full-bleed.d.ts.map +1 -1
  145. package/build-types/card/stories/index.story.d.ts +23 -0
  146. package/build-types/card/stories/index.story.d.ts.map +1 -1
  147. package/build-types/collapsible-card/header.d.ts +2 -0
  148. package/build-types/collapsible-card/header.d.ts.map +1 -1
  149. package/build-types/collapsible-card/stories/index.story.d.ts +14 -0
  150. package/build-types/collapsible-card/stories/index.story.d.ts.map +1 -1
  151. package/build-types/dialog/portal.d.ts +8 -6
  152. package/build-types/dialog/portal.d.ts.map +1 -1
  153. package/build-types/dialog/types.d.ts +2 -2
  154. package/build-types/dialog/types.d.ts.map +1 -1
  155. package/build-types/drawer/portal.d.ts +8 -6
  156. package/build-types/drawer/portal.d.ts.map +1 -1
  157. package/build-types/drawer/types.d.ts +2 -2
  158. package/build-types/drawer/types.d.ts.map +1 -1
  159. package/build-types/form/primitives/autocomplete/clear.d.ts.map +1 -1
  160. package/build-types/form/primitives/autocomplete/index.d.ts +2 -1
  161. package/build-types/form/primitives/autocomplete/index.d.ts.map +1 -1
  162. package/build-types/form/primitives/autocomplete/popup.d.ts +1 -0
  163. package/build-types/form/primitives/autocomplete/popup.d.ts.map +1 -1
  164. package/build-types/form/primitives/autocomplete/portal.d.ts +9 -4
  165. package/build-types/form/primitives/autocomplete/portal.d.ts.map +1 -1
  166. package/build-types/form/primitives/autocomplete/positioner.d.ts +12 -0
  167. package/build-types/form/primitives/autocomplete/positioner.d.ts.map +1 -0
  168. package/build-types/form/primitives/autocomplete/stories/index.story.d.ts.map +1 -1
  169. package/build-types/form/primitives/autocomplete/types.d.ts +11 -9
  170. package/build-types/form/primitives/autocomplete/types.d.ts.map +1 -1
  171. package/build-types/form/primitives/constants.d.ts +9 -4
  172. package/build-types/form/primitives/constants.d.ts.map +1 -1
  173. package/build-types/form/primitives/select/index.d.ts +2 -1
  174. package/build-types/form/primitives/select/index.d.ts.map +1 -1
  175. package/build-types/form/primitives/select/popup.d.ts +1 -0
  176. package/build-types/form/primitives/select/popup.d.ts.map +1 -1
  177. package/build-types/form/primitives/select/portal.d.ts +9 -4
  178. package/build-types/form/primitives/select/portal.d.ts.map +1 -1
  179. package/build-types/form/primitives/select/positioner.d.ts +12 -0
  180. package/build-types/form/primitives/select/positioner.d.ts.map +1 -0
  181. package/build-types/form/primitives/select/stories/index.story.d.ts.map +1 -1
  182. package/build-types/form/primitives/select/types.d.ts +11 -2
  183. package/build-types/form/primitives/select/types.d.ts.map +1 -1
  184. package/build-types/icon/stories/index.story.d.ts.map +1 -1
  185. package/build-types/index.d.ts +2 -0
  186. package/build-types/index.d.ts.map +1 -1
  187. package/build-types/popover/index.d.ts +2 -1
  188. package/build-types/popover/index.d.ts.map +1 -1
  189. package/build-types/popover/popup.d.ts +2 -1
  190. package/build-types/popover/popup.d.ts.map +1 -1
  191. package/build-types/popover/portal.d.ts +8 -5
  192. package/build-types/popover/portal.d.ts.map +1 -1
  193. package/build-types/popover/positioner.d.ts +12 -0
  194. package/build-types/popover/positioner.d.ts.map +1 -0
  195. package/build-types/popover/root.d.ts +5 -2
  196. package/build-types/popover/root.d.ts.map +1 -1
  197. package/build-types/popover/stories/index.story.d.ts +10 -21
  198. package/build-types/popover/stories/index.story.d.ts.map +1 -1
  199. package/build-types/popover/types.d.ts +12 -3
  200. package/build-types/popover/types.d.ts.map +1 -1
  201. package/build-types/tooltip/portal.d.ts +9 -4
  202. package/build-types/tooltip/portal.d.ts.map +1 -1
  203. package/build-types/tooltip/positioner.d.ts +8 -5
  204. package/build-types/tooltip/positioner.d.ts.map +1 -1
  205. package/build-types/tooltip/types.d.ts +3 -3
  206. package/build-types/tooltip/types.d.ts.map +1 -1
  207. package/build-types/utils/test/use-enable-wp-compat-overlay-slot.test.d.ts +2 -0
  208. package/build-types/utils/test/use-enable-wp-compat-overlay-slot.test.d.ts.map +1 -0
  209. package/build-types/utils/test/wp-compat-overlay-slot.test.d.ts +2 -0
  210. package/build-types/utils/test/wp-compat-overlay-slot.test.d.ts.map +1 -0
  211. package/build-types/utils/use-enable-wp-compat-overlay-slot.d.ts +17 -0
  212. package/build-types/utils/use-enable-wp-compat-overlay-slot.d.ts.map +1 -0
  213. package/build-types/utils/wp-compat-overlay-slot.d.ts +30 -0
  214. package/build-types/utils/wp-compat-overlay-slot.d.ts.map +1 -0
  215. package/package.json +12 -12
  216. package/src/alert-dialog/portal.tsx +1 -4
  217. package/src/alert-dialog/types.ts +2 -4
  218. package/src/badge/stories/e2e/index.story.tsx +20 -0
  219. package/src/button/stories/e2e/index.story.tsx +130 -0
  220. package/src/button/stories/index.story.tsx +1 -1
  221. package/src/button/style.module.css +17 -12
  222. package/src/card/full-bleed.tsx +18 -0
  223. package/src/card/stories/index.story.tsx +115 -1
  224. package/src/card/style.module.css +16 -0
  225. package/src/card/test/index.test.tsx +18 -1
  226. package/src/collapsible-card/header.tsx +2 -0
  227. package/src/collapsible-card/stories/index.story.tsx +66 -0
  228. package/src/dialog/portal.tsx +1 -5
  229. package/src/dialog/types.ts +2 -2
  230. package/src/drawer/portal.tsx +1 -5
  231. package/src/drawer/types.ts +2 -2
  232. package/src/form/primitives/autocomplete/clear.tsx +10 -4
  233. package/src/form/primitives/autocomplete/index.ts +2 -1
  234. package/src/form/primitives/autocomplete/popup.tsx +17 -21
  235. package/src/form/primitives/autocomplete/portal.tsx +11 -5
  236. package/src/form/primitives/autocomplete/positioner.tsx +29 -0
  237. package/src/form/primitives/autocomplete/stories/index.story.tsx +1 -0
  238. package/src/form/primitives/autocomplete/test/index.test.tsx +219 -0
  239. package/src/form/primitives/autocomplete/types.ts +15 -15
  240. package/src/form/primitives/constants.ts +7 -4
  241. package/src/form/primitives/select/index.ts +2 -1
  242. package/src/form/primitives/select/popup.tsx +30 -34
  243. package/src/form/primitives/select/portal.tsx +15 -8
  244. package/src/form/primitives/select/positioner.tsx +33 -0
  245. package/src/form/primitives/select/stories/index.story.tsx +1 -0
  246. package/src/form/primitives/select/test/index.test.tsx +134 -0
  247. package/src/form/primitives/select/types.ts +12 -2
  248. package/src/form/select-control/test/index.test.tsx +64 -0
  249. package/src/icon/stories/index.story.tsx +3 -2
  250. package/src/icon-button/icon-button.tsx +1 -1
  251. package/src/icon-button/test/index.test.tsx +10 -10
  252. package/src/index.ts +2 -0
  253. package/src/popover/index.ts +12 -1
  254. package/src/popover/popup.tsx +28 -45
  255. package/src/popover/portal.tsx +1 -4
  256. package/src/popover/positioner.tsx +42 -0
  257. package/src/popover/root.tsx +5 -2
  258. package/src/popover/stories/index.story.tsx +85 -138
  259. package/src/popover/test/index.test.tsx +36 -1
  260. package/src/popover/types.ts +13 -15
  261. package/src/tabs/stories/index.story.tsx +2 -2
  262. package/src/tooltip/portal.tsx +11 -5
  263. package/src/tooltip/positioner.tsx +1 -4
  264. package/src/tooltip/style.module.css +1 -1
  265. package/src/tooltip/test/index.test.tsx +110 -0
  266. package/src/tooltip/types.ts +3 -5
  267. package/src/utils/css/item-popup.module.css +7 -4
  268. package/src/utils/css/wp-compat-overlay-slot.module.css +35 -0
  269. package/src/utils/test/use-enable-wp-compat-overlay-slot.test.tsx +74 -0
  270. package/src/utils/test/wp-compat-overlay-slot.test.ts +300 -0
  271. package/src/utils/use-enable-wp-compat-overlay-slot.ts +32 -0
  272. package/src/utils/wp-compat-overlay-slot.ts +129 -0
@@ -1 +1 @@
1
- {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/tooltip/portal.tsx"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,QAAA,MAAM,MAAM,kNAIX,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
1
+ {"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/tooltip/portal.tsx"],"names":[],"mappings":"AAKA;;;GAGG;AACH,QAAA,MAAM,MAAM;;;;;;kDAUX,CAAC;AAEF,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -1,9 +1,12 @@
1
1
  /**
2
- * Positions the floating tooltip content relative to the trigger. Pass to
3
- * `Tooltip.Popup`'s `positioner` prop to customize `side`, `align`,
4
- * `sideOffset`, collision behavior, etc. When `positioner` is omitted,
5
- * `Tooltip.Popup` uses this component with default props.
2
+ * Used to apply custom positioning to `Tooltip`'s floating content.
6
3
  */
7
- declare const Positioner: import("react").ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react").TooltipPositionerProps, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
4
+ declare const Positioner: import("react").ForwardRefExoticComponent<Omit<Omit<Omit<import("@base-ui/react").TooltipPositionerProps, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref">, "children" | "className" | "render" | "style"> & {
5
+ className?: string;
6
+ style?: React.CSSProperties;
7
+ render?: ((props: import("react").HTMLAttributes<any> & {
8
+ ref?: import("react").Ref<any> | undefined;
9
+ }) => React.ReactElement<unknown>) | React.ReactElement<Record<string, unknown>>;
10
+ } & import("react").RefAttributes<HTMLDivElement>>;
8
11
  export { Positioner };
9
12
  //# sourceMappingURL=positioner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"positioner.d.ts","sourceRoot":"","sources":["../../src/tooltip/positioner.tsx"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,QAAA,MAAM,UAAU,sNAoBf,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"positioner.d.ts","sourceRoot":"","sources":["../../src/tooltip/positioner.tsx"],"names":[],"mappings":"AAOA;;GAEG;AACH,QAAA,MAAM,UAAU;;;;;;kDAoBf,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -1,8 +1,8 @@
1
- import type { ComponentPropsWithoutRef, ReactElement, ReactNode } from 'react';
1
+ import type { ReactElement, ReactNode } from 'react';
2
2
  import type { Tooltip as _Tooltip } from '@base-ui/react/tooltip';
3
3
  import type { ComponentProps } from '../utils/types';
4
- export type PortalProps = ComponentPropsWithoutRef<typeof _Tooltip.Portal>;
5
- export type PositionerProps = ComponentPropsWithoutRef<typeof _Tooltip.Positioner>;
4
+ export type PortalProps = ComponentProps<typeof _Tooltip.Portal>;
5
+ export type PositionerProps = ComponentProps<typeof _Tooltip.Positioner>;
6
6
  export type RootProps = Pick<_Tooltip.Root.Props, 'disabled' | 'children'>;
7
7
  export type ProviderProps = Pick<_Tooltip.Provider.Props, 'delay' | 'children'>;
8
8
  export interface TriggerProps extends ComponentProps<'button'> {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tooltip/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG,wBAAwB,CAAE,OAAO,QAAQ,CAAC,MAAM,CAAE,CAAC;AAE7E,MAAM,MAAM,eAAe,GAAG,wBAAwB,CACrD,OAAO,QAAQ,CAAC,UAAU,CAC1B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,IAAI,CAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAE,CAAC;AAE7E,MAAM,MAAM,aAAa,GAAG,IAAI,CAC/B,QAAQ,CAAC,QAAQ,CAAC,KAAK,EACvB,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,UAAW,SAAQ,cAAc,CAAE,KAAK,CAAE;IAC1D;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,CAAE,IAAI,CAAE,WAAW,EAAE,UAAU,CAAE,CAAE,CAAC;IAEzD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,YAAY,CAAE,IAAI,CAAE,eAAe,EAAE,UAAU,CAAE,CAAE,CAAC;CACjE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tooltip/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG,cAAc,CAAE,OAAO,QAAQ,CAAC,MAAM,CAAE,CAAC;AAEnE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAE,OAAO,QAAQ,CAAC,UAAU,CAAE,CAAC;AAE3E,MAAM,MAAM,SAAS,GAAG,IAAI,CAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAAE,CAAC;AAE7E,MAAM,MAAM,aAAa,GAAG,IAAI,CAC/B,QAAQ,CAAC,QAAQ,CAAC,KAAK,EACvB,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,UAAW,SAAQ,cAAc,CAAE,KAAK,CAAE;IAC1D;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,CAAE,IAAI,CAAE,WAAW,EAAE,UAAU,CAAE,CAAE,CAAC;IAEzD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,YAAY,CAAE,IAAI,CAAE,eAAe,EAAE,UAAU,CAAE,CAAE,CAAC;CACjE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=use-enable-wp-compat-overlay-slot.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-enable-wp-compat-overlay-slot.test.d.ts","sourceRoot":"","sources":["../../../src/utils/test/use-enable-wp-compat-overlay-slot.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wp-compat-overlay-slot.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wp-compat-overlay-slot.test.d.ts","sourceRoot":"","sources":["../../../src/utils/test/wp-compat-overlay-slot.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Opts the host application into the `@wordpress/ui` compat overlay slot —
3
+ * a body-level container into which `@wordpress/ui` overlays portal so they
4
+ * reliably stack above `@wordpress/components` overlays in mixed-library
5
+ * compositions.
6
+ *
7
+ * Call once from a component that mounts for the lifetime of the app
8
+ * (typically the root). Idempotent and one-way: a single caller should not
9
+ * be able to turn off shared infrastructure for everyone else; if the slot
10
+ * isn't wanted, simply don't call this hook.
11
+ *
12
+ * Where `window.wp.components` is on the global — the typical setup for
13
+ * plugins enqueueing `wp-components` through WordPress's script-loader —
14
+ * the slot auto-enables and this hook is a no-op.
15
+ */
16
+ export declare function useEnableWpCompatOverlaySlot(): void;
17
+ //# sourceMappingURL=use-enable-wp-compat-overlay-slot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-enable-wp-compat-overlay-slot.d.ts","sourceRoot":"","sources":["../../src/utils/use-enable-wp-compat-overlay-slot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAgBnD"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Marker attribute on the compat overlay slot element.
3
+ */
4
+ export declare const WP_COMPAT_OVERLAY_SLOT_ATTRIBUTE = "data-wp-compat-overlay-slot";
5
+ /**
6
+ * Returns the body-level compat overlay slot when the runtime opts in,
7
+ * lazily creating it on first call. Returns `undefined` otherwise — so the
8
+ * return value can be forwarded straight to a `container` prop, leaving the
9
+ * default portal container in effect.
10
+ *
11
+ * Two opt-in paths:
12
+ *
13
+ * - Auto-detected when `window.wp.components` is on the global — the
14
+ * typical script-loader setup for WordPress plugins and admin screens.
15
+ * - Explicit, via `useEnableWpCompatOverlaySlot()` — for hosts that bundle
16
+ * `@wordpress/components` (or only `@wordpress/ui`) directly rather than
17
+ * relying on the global.
18
+ *
19
+ * The slot is a single `<div data-wp-compat-overlay-slot>` appended to the
20
+ * local document's body. Subsequent calls return the same element; if it's
21
+ * been removed it's recreated, and a slot created by another
22
+ * `@wordpress/ui` instance in the same document is adopted rather than
23
+ * duplicated.
24
+ */
25
+ export declare function getWpCompatOverlaySlot(): HTMLDivElement | undefined;
26
+ /**
27
+ * Test-only escape hatch that drops the cached singleton.
28
+ */
29
+ export declare function __resetWpCompatOverlaySlotCacheForTests(): void;
30
+ //# sourceMappingURL=wp-compat-overlay-slot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wp-compat-overlay-slot.d.ts","sourceRoot":"","sources":["../../src/utils/wp-compat-overlay-slot.ts"],"names":[],"mappings":"AAcA;;GAEG;AACH,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAuC9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,IAAI,cAAc,GAAG,SAAS,CA6CnE;AAED;;GAEG;AACH,wBAAgB,uCAAuC,IAAI,IAAI,CAE9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/ui",
3
- "version": "0.13.1-next.v.202605131032.0+f6d6e7149",
3
+ "version": "0.15.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",
@@ -44,16 +44,16 @@
44
44
  "sideEffects": false,
45
45
  "dependencies": {
46
46
  "@base-ui/react": "^1.4.1",
47
- "@wordpress/a11y": "^4.45.1-next.v.202605131032.0+f6d6e7149",
48
- "@wordpress/compose": "^7.45.1-next.v.202605131032.0+f6d6e7149",
49
- "@wordpress/element": "^6.45.1-next.v.202605131032.0+f6d6e7149",
50
- "@wordpress/i18n": "^6.18.1-next.v.202605131032.0+f6d6e7149",
51
- "@wordpress/icons": "^13.0.1-next.v.202605131032.0+f6d6e7149",
52
- "@wordpress/keycodes": "^4.45.1-next.v.202605131032.0+f6d6e7149",
53
- "@wordpress/primitives": "^4.45.1-next.v.202605131032.0+f6d6e7149",
54
- "@wordpress/private-apis": "^1.45.1-next.v.202605131032.0+f6d6e7149",
55
- "@wordpress/style-runtime": "^0.1.2-next.v.202605131032.0+f6d6e7149",
56
- "@wordpress/theme": "^0.13.1-next.v.202605131032.0+f6d6e7149",
47
+ "@wordpress/a11y": "^4.48.0",
48
+ "@wordpress/compose": "^8.1.0",
49
+ "@wordpress/element": "^8.0.0",
50
+ "@wordpress/i18n": "^6.21.0",
51
+ "@wordpress/icons": "^13.3.0",
52
+ "@wordpress/keycodes": "^4.48.0",
53
+ "@wordpress/primitives": "^4.48.0",
54
+ "@wordpress/private-apis": "^1.48.0",
55
+ "@wordpress/style-runtime": "^0.4.0",
56
+ "@wordpress/theme": "^0.15.0",
57
57
  "clsx": "^2.1.1",
58
58
  "tabbable": "^6.4.0"
59
59
  },
@@ -72,5 +72,5 @@
72
72
  "publishConfig": {
73
73
  "access": "public"
74
74
  },
75
- "gitHead": "0e198c7ac7ca634e73ded9220ce048c0302174dd"
75
+ "gitHead": "e7856693aeb4e2522d13608cd32c994e4a97cb9c"
76
76
  }
@@ -3,10 +3,7 @@ import { forwardRef } from '@wordpress/element';
3
3
  import type { PortalProps } from './types';
4
4
 
5
5
  /**
6
- * Root element that portals `AlertDialog` overlay content. Pass to
7
- * `AlertDialog.Popup`'s `portal` prop to customize the portal target and
8
- * wrapper. When `portal` is omitted, `AlertDialog.Popup` uses this component
9
- * with default props.
6
+ * Used to apply custom portal behavior to `AlertDialog`'s overlay content.
10
7
  */
11
8
  const Portal = forwardRef< HTMLDivElement, PortalProps >(
12
9
  function AlertDialogPortal( props, ref ) {
@@ -1,11 +1,9 @@
1
1
  import type { AlertDialog as _AlertDialog } from '@base-ui/react/alert-dialog';
2
- import type { ComponentPropsWithoutRef, ReactElement, ReactNode } from 'react';
2
+ import type { ReactElement, ReactNode } from 'react';
3
3
 
4
4
  import type { ComponentProps } from '../utils/types';
5
5
 
6
- export type PortalProps = ComponentPropsWithoutRef<
7
- typeof _AlertDialog.Portal
8
- >;
6
+ export type PortalProps = ComponentProps< typeof _AlertDialog.Portal >;
9
7
 
10
8
  /**
11
9
  * The return type of `onConfirm`. Return `void` (or nothing) to auto-close
@@ -0,0 +1,20 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Badge } from '../..';
3
+
4
+ const meta: Meta< typeof Badge > = {
5
+ title: 'Design System/Components/Badge',
6
+ component: Badge,
7
+ };
8
+ export default meta;
9
+
10
+ type Story = StoryObj< typeof Badge >;
11
+
12
+ export const TextOverflow: Story = {
13
+ args: {
14
+ children:
15
+ 'This is an extremely long label thatshoulddemonstratetextoverflow behavior',
16
+ },
17
+ parameters: {
18
+ textOverflowContainers: true,
19
+ },
20
+ };
@@ -0,0 +1,130 @@
1
+ import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite';
2
+ import { Button } from '../..';
3
+ import type { ButtonProps } from '../../types';
4
+
5
+ const meta: Meta< typeof Button > = {
6
+ title: 'Design System/Components/Button',
7
+ component: Button,
8
+ };
9
+ export default meta;
10
+
11
+ type Story = StoryObj< typeof Button >;
12
+
13
+ const variants: NonNullable< ButtonProps[ 'variant' ] >[] = [
14
+ 'solid',
15
+ 'outline',
16
+ 'minimal',
17
+ 'unstyled',
18
+ ];
19
+
20
+ export const VariantStates: StoryFn< typeof Button > = (
21
+ props: ButtonProps
22
+ ) => {
23
+ const VariantsRow = ( {
24
+ buttonProps,
25
+ name,
26
+ }: {
27
+ buttonProps?: ButtonProps;
28
+ name: string;
29
+ } ) => {
30
+ return (
31
+ <tr>
32
+ <th
33
+ style={ {
34
+ fontSize: 13,
35
+ fontWeight: 'normal',
36
+ padding: 8,
37
+ background: '#f3f4f5',
38
+ } }
39
+ >
40
+ { name }
41
+ </th>
42
+ { variants.map( ( variant ) => (
43
+ <td key={ variant } style={ { padding: 4 } }>
44
+ <Button
45
+ { ...props }
46
+ variant={ variant }
47
+ { ...buttonProps }
48
+ />
49
+ </td>
50
+ ) ) }
51
+ </tr>
52
+ );
53
+ };
54
+
55
+ return (
56
+ <table>
57
+ <thead>
58
+ <tr style={ { background: '#f3f4f5' } }>
59
+ <th />
60
+ { variants.map( ( variant ) => (
61
+ <th key={ variant } style={ { padding: 8 } }>
62
+ { variant }
63
+ </th>
64
+ ) ) }
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <VariantsRow name="(default)" />
69
+ <VariantsRow
70
+ name="disabled"
71
+ buttonProps={ { disabled: true } }
72
+ />
73
+ <VariantsRow
74
+ name="disabled unfocusable"
75
+ buttonProps={ {
76
+ focusableWhenDisabled: false,
77
+ disabled: true,
78
+ } }
79
+ />
80
+ <VariantsRow
81
+ name="loading"
82
+ buttonProps={ {
83
+ loading: true,
84
+ } }
85
+ />
86
+ <VariantsRow
87
+ name="loading disabled"
88
+ buttonProps={ {
89
+ loading: true,
90
+ disabled: true,
91
+ } }
92
+ />
93
+ <VariantsRow
94
+ name="neutral"
95
+ buttonProps={ {
96
+ tone: 'neutral',
97
+ } }
98
+ />
99
+ <VariantsRow
100
+ name="pressed"
101
+ buttonProps={ {
102
+ tone: 'neutral',
103
+ 'aria-pressed': true,
104
+ } }
105
+ />
106
+ <VariantsRow
107
+ name="pressed disabled"
108
+ buttonProps={ {
109
+ tone: 'neutral',
110
+ 'aria-pressed': true,
111
+ disabled: true,
112
+ } }
113
+ />
114
+ </tbody>
115
+ </table>
116
+ );
117
+ };
118
+ VariantStates.args = {
119
+ children: 'Code is poetry',
120
+ };
121
+
122
+ export const TextOverflow: Story = {
123
+ args: {
124
+ children:
125
+ 'This is an extremely long label thatshoulddemonstratetextoverflow behavior',
126
+ },
127
+ parameters: {
128
+ textOverflowContainers: true,
129
+ },
130
+ };
@@ -95,7 +95,7 @@ export const AllTonesAndVariants: Story = {
95
95
  <div
96
96
  style={ {
97
97
  display: 'grid',
98
- gridTemplateColumns: 'max-content repeat(2, min-content)',
98
+ gridTemplateColumns: 'max-content repeat(2, max-content)',
99
99
  color: 'var(--wpds-color-fg-content-neutral)',
100
100
  } }
101
101
  >
@@ -17,6 +17,7 @@
17
17
  --wp-ui-button-foreground-color: var(--wpds-color-fg-interactive-brand-strong);
18
18
  --wp-ui-button-foreground-color-active: var(--wpds-color-fg-interactive-brand-strong-active);
19
19
  --wp-ui-button-foreground-color-disabled: var(--wpds-color-fg-interactive-neutral-strong-disabled);
20
+ --wp-ui-button-padding-block: var(--wpds-dimension-padding-xs);
20
21
  --wp-ui-button-padding-inline: var(--wpds-dimension-padding-md);
21
22
  --wp-ui-button-height: 40px;
22
23
  --wp-ui-button-aspect-ratio: auto; /* Useful for overrides such as icon buttons */
@@ -40,7 +41,9 @@
40
41
  gap: var(--wpds-dimension-gap-sm);
41
42
  aspect-ratio: var(--wp-ui-button-aspect-ratio);
42
43
  min-width: var(--wp-ui-button-min-width);
43
- height: var(--wp-ui-button-height);
44
+ max-width: 100%;
45
+ min-height: var(--wp-ui-button-height);
46
+ padding-block: var(--wp-ui-button-padding-block);
44
47
  padding-inline: var(--wp-ui-button-padding-inline);
45
48
  border-style: solid;
46
49
  border-width: 1px;
@@ -52,9 +55,14 @@
52
55
  font-size: var(--wp-ui-button-font-size);
53
56
  font-weight: var(--wp-ui-button-font-weight);
54
57
  line-height: var(--wpds-typography-line-height-sm);
58
+ text-align: center;
55
59
  text-decoration: none;
56
60
  color: var(--wp-ui-button-foreground-color);
57
- cursor: var(--wpds-cursor-control);
61
+ overflow-wrap: anywhere;
62
+
63
+ &:not([data-disabled]) {
64
+ cursor: var(--wpds-cursor-control);
65
+ }
58
66
 
59
67
  @media not ( prefers-reduced-motion ) {
60
68
  transition: color 0.1s ease-out;
@@ -129,6 +137,7 @@
129
137
  }
130
138
 
131
139
  .is-small {
140
+ --wp-ui-button-padding-block: 0;
132
141
  --wp-ui-button-padding-inline: var(--wpds-dimension-padding-sm);
133
142
  --wp-ui-button-height: 24px;
134
143
  }
@@ -164,7 +173,9 @@
164
173
  }
165
174
 
166
175
  .is-neutral {
167
- &.is-solid {
176
+ /* Solid and pressed minimal share the strong appearance */
177
+ &.is-solid,
178
+ &.is-minimal[aria-pressed="true"] {
168
179
  --wp-ui-button-background-color: var(--wpds-color-bg-interactive-neutral-strong);
169
180
  --wp-ui-button-background-color-active: var(--wpds-color-bg-interactive-neutral-strong-active);
170
181
  --wp-ui-button-background-color-disabled: var(--wpds-color-bg-interactive-neutral-strong-disabled);
@@ -173,9 +184,9 @@
173
184
  --wp-ui-button-foreground-color-disabled: var(--wpds-color-fg-interactive-neutral-strong-disabled);
174
185
  }
175
186
 
176
- /* Outline and minimal buttons use the same foreground color */
187
+ /* Outline and unpressed minimal buttons use the same foreground color */
177
188
  &.is-outline,
178
- &.is-minimal {
189
+ &.is-minimal:not([aria-pressed="true"]) {
179
190
  --wp-ui-button-foreground-color: var(--wpds-color-fg-interactive-neutral);
180
191
  --wp-ui-button-foreground-color-active: var(--wpds-color-fg-interactive-neutral-active);
181
192
  --wp-ui-button-foreground-color-disabled: var(--wpds-color-fg-interactive-neutral-disabled);
@@ -190,7 +201,7 @@
190
201
  --wp-ui-button-border-color-disabled: var(--wpds-color-stroke-interactive-neutral-disabled);
191
202
  }
192
203
 
193
- &.is-minimal {
204
+ &.is-minimal:not([aria-pressed="true"]) {
194
205
  --wp-ui-button-background-color: var(--wpds-color-bg-interactive-neutral-weak);
195
206
  --wp-ui-button-background-color-active: var(--wpds-color-bg-interactive-neutral-weak-active);
196
207
  --wp-ui-button-background-color-disabled: var(--wpds-color-bg-interactive-neutral-weak-disabled);
@@ -230,12 +241,6 @@
230
241
  }
231
242
  }
232
243
 
233
- [aria-pressed="true"].is-minimal.is-neutral {
234
- --wp-ui-button-background-color: var(--wpds-color-bg-interactive-neutral-strong);
235
- --wp-ui-button-background-color-active: var(--wpds-color-bg-interactive-neutral-strong);
236
- --wp-ui-button-foreground-color: var(--wpds-color-fg-interactive-neutral-strong);
237
- --wp-ui-button-foreground-color-active: var(--wpds-color-fg-interactive-neutral-strong);
238
- }
239
244
  }
240
245
 
241
246
  @keyframes loading-animation {
@@ -7,6 +7,24 @@ import type { FullBleedProps } from './types';
7
7
  * A container that breaks out of the card's padding to span edge-to-edge.
8
8
  * Useful for full-width images, dividers, or embedded content.
9
9
  *
10
+ * Additional edge-bumping behavior based on placement:
11
+ *
12
+ * - As the **first child** of `Card.Header`, it extends flush to the card's
13
+ * top edge — ideal for hero images.
14
+ * - As the **only child** of `Card.Content`, it extends flush to the card's
15
+ * top edge when `Content` is the first card section, and to the bottom edge
16
+ * when it is the last.
17
+ *
18
+ * Inter-sibling spacing inside `Card.Header` / `Card.Content` is consumer-
19
+ * managed. To add space between a hero `FullBleed` and the following
20
+ * siblings, compose the parent with `Stack` via the `render` prop:
21
+ * `<Card.Header render={ <Stack direction="column" gap="lg" /> }>`. This
22
+ * keeps `FullBleed` a direct child of `Card.Header` so the edge-bump still
23
+ * fires, while `Stack` provides the gap.
24
+ *
25
+ * Inside `CollapsibleCard`, place full-bleed media in `CollapsibleCard.Content`
26
+ * (not the header). The trigger/panel gap is preserved by design.
27
+ *
10
28
  * Must be used as a direct child of `Card.Content` or `Card.Header`.
11
29
  */
12
30
  export const FullBleed = forwardRef< HTMLDivElement, FullBleedProps >(
@@ -1,4 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Stack } from '@wordpress/ui';
2
3
  import * as Card from '../index';
3
4
 
4
5
  /**
@@ -71,6 +72,56 @@ export const Default: Story = {
71
72
  },
72
73
  };
73
74
 
75
+ /**
76
+ * `Card.FullBleed` as the sole child of `Card.Content` spans edge-to-edge
77
+ * with no padding around it.
78
+ */
79
+ export const FullBleedCoverOnly: Story = {
80
+ args: {
81
+ children: (
82
+ <Card.Content>
83
+ <Card.FullBleed>
84
+ <div
85
+ style={ {
86
+ height: 180,
87
+ background:
88
+ 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
89
+ } }
90
+ />
91
+ </Card.FullBleed>
92
+ </Card.Content>
93
+ ),
94
+ },
95
+ };
96
+
97
+ /**
98
+ * When `Card.FullBleed` is the sole child of `Card.Content` and a
99
+ * `Card.Header` sits above it, the image bumps against the card's side and
100
+ * bottom edges while the header retains its normal padding.
101
+ */
102
+ export const FullBleedCoverWithHeader: Story = {
103
+ args: {
104
+ children: (
105
+ <>
106
+ <Card.Header>
107
+ <Card.Title>Card title</Card.Title>
108
+ </Card.Header>
109
+ <Card.Content>
110
+ <Card.FullBleed>
111
+ <div
112
+ style={ {
113
+ height: 180,
114
+ background:
115
+ 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
116
+ } }
117
+ />
118
+ </Card.FullBleed>
119
+ </Card.Content>
120
+ </>
121
+ ),
122
+ },
123
+ };
124
+
74
125
  /**
75
126
  * `Card.FullBleed` breaks out of the card's padding to span
76
127
  * edge-to-edge. Useful for images, dividers, or embedded content.
@@ -82,7 +133,7 @@ export const WithFullBleed: Story = {
82
133
  <Card.Header>
83
134
  <Card.Title>Featured image</Card.Title>
84
135
  </Card.Header>
85
- <Card.Content>
136
+ <Card.Content render={ <Stack direction="column" gap="lg" /> }>
86
137
  <Card.FullBleed>
87
138
  <div
88
139
  style={ {
@@ -112,6 +163,69 @@ export const HeaderOnly: Story = {
112
163
  },
113
164
  };
114
165
 
166
+ /**
167
+ * When `Card.FullBleed` is the **first child** of `Card.Header`, it extends
168
+ * flush to the card's top and side edges — ideal for hero images. Content
169
+ * that follows inside the header is padded normally.
170
+ */
171
+ export const FullBleedHeroWithTitle: Story = {
172
+ args: {
173
+ children: (
174
+ <>
175
+ <Card.Header render={ <Stack direction="column" gap="lg" /> }>
176
+ <Card.FullBleed>
177
+ <div
178
+ style={ {
179
+ height: 180,
180
+ background:
181
+ 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
182
+ } }
183
+ />
184
+ </Card.FullBleed>
185
+ <Card.Title>Hero image card</Card.Title>
186
+ </Card.Header>
187
+ <Card.Content>
188
+ <Text>
189
+ The image above bleeds to the card&apos;s top and side
190
+ edges.
191
+ </Text>
192
+ </Card.Content>
193
+ </>
194
+ ),
195
+ },
196
+ };
197
+
198
+ /**
199
+ * When `Card.FullBleed` is the **only child** of `Card.Header`, it fills the
200
+ * header entirely — top and sides flush to the card edges, no extra padding
201
+ * below.
202
+ */
203
+ export const FullBleedHeroOnly: Story = {
204
+ args: {
205
+ children: (
206
+ <>
207
+ <Card.Header>
208
+ <Card.FullBleed>
209
+ <div
210
+ style={ {
211
+ height: 180,
212
+ background:
213
+ 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
214
+ } }
215
+ />
216
+ </Card.FullBleed>
217
+ </Card.Header>
218
+ <Card.Content>
219
+ <Text>
220
+ The image above bleeds to the card&apos;s top and side
221
+ edges.
222
+ </Text>
223
+ </Card.Content>
224
+ </>
225
+ ),
226
+ },
227
+ };
228
+
115
229
  /**
116
230
  * Use the `render` prop to change the underlying HTML elements for
117
231
  * better semantics. Here, `Card.Root` renders as a `<section>` and
@@ -38,4 +38,20 @@
38
38
  margin-inline: calc(-1 * var(--wp-ui-card-padding));
39
39
  width: calc(100% + 2 * var(--wp-ui-card-padding));
40
40
  }
41
+
42
+ /*
43
+ * When FullBleed sits at the start of the first *root* card section, extend
44
+ * it flush to the card's top edge. Must use `.root >` so `Card.Content`
45
+ * nested inside `CollapsibleCard`'s panel is not treated as `:first-child`
46
+ * (which would pull FullBleed up into the header gap).
47
+ */
48
+ .root > :is(.header, .content):first-child > .fullbleed:first-child {
49
+ margin-block-start: calc(-1 * var(--wp-ui-card-padding));
50
+ }
51
+
52
+ /* When FullBleed sits at the end of the last card section, extend it flush to the card's bottom edge. */
53
+ :is(.header, .content):last-child > .fullbleed:last-child {
54
+ margin-block-end: calc(-1 * var(--wp-ui-card-padding));
55
+ }
56
+
41
57
  }
@@ -49,7 +49,7 @@ describe( 'Card', () => {
49
49
  } );
50
50
 
51
51
  describe( 'fullbleed', () => {
52
- it( 'renders children', () => {
52
+ it( 'renders children inside Content', () => {
53
53
  render(
54
54
  <Card.Root>
55
55
  <Card.Content>
@@ -65,6 +65,23 @@ describe( 'Card', () => {
65
65
 
66
66
  expect( screen.getByRole( 'img', { name: 'test' } ) ).toBeVisible();
67
67
  } );
68
+
69
+ it( 'renders children inside Header', () => {
70
+ render(
71
+ <Card.Root>
72
+ <Card.Header>
73
+ <Card.FullBleed>
74
+ <img
75
+ src="https://example.com/hero.jpg"
76
+ alt="hero"
77
+ />
78
+ </Card.FullBleed>
79
+ </Card.Header>
80
+ </Card.Root>
81
+ );
82
+
83
+ expect( screen.getByRole( 'img', { name: 'hero' } ) ).toBeVisible();
84
+ } );
68
85
  } );
69
86
 
70
87
  describe( 'render prop', () => {