@wordpress/components 32.2.1-next.v.202602191100.0 → 32.2.1

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 (337) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/build/alignment-matrix-control/cell.cjs +2 -2
  3. package/build/alignment-matrix-control/cell.cjs.map +1 -1
  4. package/build/alignment-matrix-control/index.cjs +2 -2
  5. package/build/alignment-matrix-control/index.cjs.map +1 -1
  6. package/build/angle-picker-control/angle-circle.cjs +2 -2
  7. package/build/angle-picker-control/angle-circle.cjs.map +1 -1
  8. package/build/autocomplete/index.cjs +15 -7
  9. package/build/autocomplete/index.cjs.map +2 -2
  10. package/build/date-time/time/index.cjs +1 -1
  11. package/build/date-time/time/index.cjs.map +2 -2
  12. package/build/date-time/utils.cjs +9 -0
  13. package/build/date-time/utils.cjs.map +2 -2
  14. package/build/private-apis.cjs +0 -4
  15. package/build/private-apis.cjs.map +3 -3
  16. package/build/sandbox/index.cjs +125 -1
  17. package/build/sandbox/index.cjs.map +2 -2
  18. package/build/select-control/styles/select-control-styles.cjs +8 -8
  19. package/build/select-control/styles/select-control-styles.cjs.map +2 -2
  20. package/build/snackbar/list.cjs +4 -1
  21. package/build/snackbar/list.cjs.map +2 -2
  22. package/build/toggle-group-control/toggle-group-control-option-base/styles.cjs +8 -8
  23. package/build/toggle-group-control/toggle-group-control-option-base/styles.cjs.map +2 -2
  24. package/build/validated-form-controls/control-with-error.cjs +26 -3
  25. package/build/validated-form-controls/control-with-error.cjs.map +2 -2
  26. package/build/validated-form-controls/validity-indicator.cjs +2 -0
  27. package/build/validated-form-controls/validity-indicator.cjs.map +2 -2
  28. package/build-module/alignment-matrix-control/cell.mjs +2 -2
  29. package/build-module/alignment-matrix-control/cell.mjs.map +1 -1
  30. package/build-module/alignment-matrix-control/index.mjs +2 -2
  31. package/build-module/alignment-matrix-control/index.mjs.map +1 -1
  32. package/build-module/angle-picker-control/angle-circle.mjs +2 -2
  33. package/build-module/angle-picker-control/angle-circle.mjs.map +1 -1
  34. package/build-module/autocomplete/index.mjs +13 -6
  35. package/build-module/autocomplete/index.mjs.map +2 -2
  36. package/build-module/date-time/time/index.mjs +2 -2
  37. package/build-module/date-time/time/index.mjs.map +2 -2
  38. package/build-module/date-time/utils.mjs +8 -0
  39. package/build-module/date-time/utils.mjs.map +2 -2
  40. package/build-module/private-apis.mjs +0 -4
  41. package/build-module/private-apis.mjs.map +2 -2
  42. package/build-module/sandbox/index.mjs +126 -2
  43. package/build-module/sandbox/index.mjs.map +2 -2
  44. package/build-module/select-control/styles/select-control-styles.mjs +8 -8
  45. package/build-module/select-control/styles/select-control-styles.mjs.map +2 -2
  46. package/build-module/snackbar/list.mjs +4 -1
  47. package/build-module/snackbar/list.mjs.map +2 -2
  48. package/build-module/toggle-group-control/toggle-group-control-option-base/styles.mjs +8 -8
  49. package/build-module/toggle-group-control/toggle-group-control-option-base/styles.mjs.map +2 -2
  50. package/build-module/validated-form-controls/control-with-error.mjs +27 -4
  51. package/build-module/validated-form-controls/control-with-error.mjs.map +2 -2
  52. package/build-module/validated-form-controls/validity-indicator.mjs +2 -0
  53. package/build-module/validated-form-controls/validity-indicator.mjs.map +2 -2
  54. package/build-style/style-rtl.css +7 -183
  55. package/build-style/style.css +7 -183
  56. package/build-types/alignment-matrix-control/styles/alignment-matrix-control-icon-styles.d.ts +19 -0
  57. package/build-types/alignment-matrix-control/styles/alignment-matrix-control-icon-styles.d.ts.map +1 -0
  58. package/build-types/alignment-matrix-control/styles/alignment-matrix-control-styles.d.ts +23 -0
  59. package/build-types/alignment-matrix-control/styles/alignment-matrix-control-styles.d.ts.map +1 -0
  60. package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts +25 -0
  61. package/build-types/angle-picker-control/styles/angle-picker-control-styles.d.ts.map +1 -0
  62. package/build-types/autocomplete/get-autocomplete-match.d.ts +20 -0
  63. package/build-types/autocomplete/get-autocomplete-match.d.ts.map +1 -0
  64. package/build-types/autocomplete/index.d.ts +8 -0
  65. package/build-types/autocomplete/index.d.ts.map +1 -1
  66. package/build-types/autocomplete/test/get-autocomplete-match.d.ts +2 -0
  67. package/build-types/autocomplete/test/get-autocomplete-match.d.ts.map +1 -0
  68. package/build-types/badge/stories/e2e/index.story.d.ts +7 -0
  69. package/build-types/badge/stories/e2e/index.story.d.ts.map +1 -0
  70. package/build-types/border-control/border-control-style-picker/hook.d.ts +267 -0
  71. package/build-types/border-control/border-control-style-picker/hook.d.ts.map +1 -0
  72. package/build-types/box-control/all-input-control.d.ts +4 -0
  73. package/build-types/box-control/all-input-control.d.ts.map +1 -0
  74. package/build-types/box-control/axial-input-controls.d.ts +4 -0
  75. package/build-types/box-control/axial-input-controls.d.ts.map +1 -0
  76. package/build-types/box-control/input-controls.d.ts +4 -0
  77. package/build-types/box-control/input-controls.d.ts.map +1 -0
  78. package/build-types/box-control/styles/box-control-visualizer-styles.d.ts +46 -0
  79. package/build-types/box-control/styles/box-control-visualizer-styles.d.ts.map +1 -0
  80. package/build-types/box-control/unit-control.d.ts +4 -0
  81. package/build-types/box-control/unit-control.d.ts.map +1 -0
  82. package/build-types/custom-gradient-picker/test/index.d.ts +2 -0
  83. package/build-types/custom-gradient-picker/test/index.d.ts.map +1 -0
  84. package/build-types/custom-select-control/styles.d.ts +11 -0
  85. package/build-types/custom-select-control/styles.d.ts.map +1 -0
  86. package/build-types/date-time/date-picker/index.d.ts +23 -0
  87. package/build-types/date-time/date-picker/index.d.ts.map +1 -0
  88. package/build-types/date-time/date-picker/styles.d.ts +45 -0
  89. package/build-types/date-time/date-picker/styles.d.ts.map +1 -0
  90. package/build-types/date-time/date-picker/test/index.d.ts +2 -0
  91. package/build-types/date-time/date-picker/test/index.d.ts.map +1 -0
  92. package/build-types/date-time/date-picker/test/use-lilius.d.ts +2 -0
  93. package/build-types/date-time/date-picker/test/use-lilius.d.ts.map +1 -0
  94. package/build-types/date-time/date-picker/use-lilius/index.d.ts +169 -0
  95. package/build-types/date-time/date-picker/use-lilius/index.d.ts.map +1 -0
  96. package/build-types/date-time/time/index.d.ts.map +1 -1
  97. package/build-types/date-time/time-picker/index.d.ts +27 -0
  98. package/build-types/date-time/time-picker/index.d.ts.map +1 -0
  99. package/build-types/date-time/time-picker/styles.d.ts +93 -0
  100. package/build-types/date-time/time-picker/styles.d.ts.map +1 -0
  101. package/build-types/date-time/time-picker/test/index.d.ts +2 -0
  102. package/build-types/date-time/time-picker/test/index.d.ts.map +1 -0
  103. package/build-types/date-time/time-picker/time-input/index.d.ts +4 -0
  104. package/build-types/date-time/time-picker/time-input/index.d.ts.map +1 -0
  105. package/build-types/date-time/time-picker/time-input/test/index.d.ts +2 -0
  106. package/build-types/date-time/time-picker/time-input/test/index.d.ts.map +1 -0
  107. package/build-types/date-time/time-picker/timezone.d.ts +7 -0
  108. package/build-types/date-time/time-picker/timezone.d.ts.map +1 -0
  109. package/build-types/date-time/utils.d.ts +9 -0
  110. package/build-types/date-time/utils.d.ts.map +1 -1
  111. package/build-types/dimension-control/index.d.ts +28 -0
  112. package/build-types/dimension-control/index.d.ts.map +1 -0
  113. package/build-types/dimension-control/sizes.d.ts +26 -0
  114. package/build-types/dimension-control/sizes.d.ts.map +1 -0
  115. package/build-types/dimension-control/stories/index.story.d.ts +4 -0
  116. package/build-types/dimension-control/stories/index.story.d.ts.map +1 -0
  117. package/build-types/dimension-control/types.d.ts +47 -0
  118. package/build-types/dimension-control/types.d.ts.map +1 -0
  119. package/build-types/dropdown-menu-v2/index.d.ts +17 -0
  120. package/build-types/dropdown-menu-v2/index.d.ts.map +1 -0
  121. package/build-types/dropdown-menu-v2/stories/index.story.d.ts +11 -0
  122. package/build-types/dropdown-menu-v2/stories/index.story.d.ts.map +1 -0
  123. package/build-types/dropdown-menu-v2/styles.d.ts +42 -0
  124. package/build-types/dropdown-menu-v2/styles.d.ts.map +1 -0
  125. package/build-types/dropdown-menu-v2/test/index.d.ts +2 -0
  126. package/build-types/dropdown-menu-v2/test/index.d.ts.map +1 -0
  127. package/build-types/dropdown-menu-v2/types.d.ts +252 -0
  128. package/build-types/dropdown-menu-v2/types.d.ts.map +1 -0
  129. package/build-types/external-link/styles/external-link-styles.d.ts +10 -0
  130. package/build-types/external-link/styles/external-link-styles.d.ts.map +1 -0
  131. package/build-types/mobile/inserter-button/sparkles.d.ts +3 -0
  132. package/build-types/mobile/inserter-button/sparkles.d.ts.map +1 -0
  133. package/build-types/navigator/navigator-back-button/index.d.ts +2 -0
  134. package/build-types/navigator/navigator-back-button/index.d.ts.map +1 -0
  135. package/build-types/navigator/navigator-button/index.d.ts +2 -0
  136. package/build-types/navigator/navigator-button/index.d.ts.map +1 -0
  137. package/build-types/navigator/navigator-provider/component.d.ts +38 -0
  138. package/build-types/navigator/navigator-provider/component.d.ts.map +1 -0
  139. package/build-types/navigator/navigator-provider/index.d.ts +2 -0
  140. package/build-types/navigator/navigator-provider/index.d.ts.map +1 -0
  141. package/build-types/navigator/navigator-screen/index.d.ts +2 -0
  142. package/build-types/navigator/navigator-screen/index.d.ts.map +1 -0
  143. package/build-types/navigator/navigator-to-parent-button/index.d.ts +2 -0
  144. package/build-types/navigator/navigator-to-parent-button/index.d.ts.map +1 -0
  145. package/build-types/private-apis.d.ts.map +1 -1
  146. package/build-types/radio-group/radio/index.d.ts +7 -0
  147. package/build-types/radio-group/radio/index.d.ts.map +1 -0
  148. package/build-types/radio-group/radio-context/index.d.ts +6 -0
  149. package/build-types/radio-group/radio-context/index.d.ts.map +1 -0
  150. package/build-types/sandbox/index.d.ts +1 -1
  151. package/build-types/sandbox/index.d.ts.map +1 -1
  152. package/build-types/sandbox/types.d.ts +11 -0
  153. package/build-types/sandbox/types.d.ts.map +1 -1
  154. package/build-types/select-control/styles/select-control-styles.d.ts.map +1 -1
  155. package/build-types/slot-fill/bubbles-virtually/fill.d.ts +5 -0
  156. package/build-types/slot-fill/bubbles-virtually/fill.d.ts.map +1 -0
  157. package/build-types/slot-fill/bubbles-virtually/slot-fill-context.d.ts +12 -0
  158. package/build-types/slot-fill/bubbles-virtually/slot-fill-context.d.ts.map +1 -0
  159. package/build-types/slot-fill/bubbles-virtually/slot-fill-provider.d.ts +4 -0
  160. package/build-types/slot-fill/bubbles-virtually/slot-fill-provider.d.ts.map +1 -0
  161. package/build-types/slot-fill/use-slot.d.ts +9 -0
  162. package/build-types/slot-fill/use-slot.d.ts.map +1 -0
  163. package/build-types/snackbar/list.d.ts.map +1 -1
  164. package/build-types/style-provider/test/index.d.ts +2 -0
  165. package/build-types/style-provider/test/index.d.ts.map +1 -0
  166. package/build-types/toggle-group-control/toggle-group-control-option-base/styles.d.ts.map +1 -1
  167. package/build-types/ui/context/constants.d.ts +8 -0
  168. package/build-types/ui/context/constants.d.ts.map +1 -0
  169. package/build-types/ui/context/context-connect.d.ts +40 -0
  170. package/build-types/ui/context/context-connect.d.ts.map +1 -0
  171. package/build-types/ui/context/context-system-provider.d.ts +7 -0
  172. package/build-types/ui/context/context-system-provider.d.ts.map +1 -0
  173. package/build-types/ui/context/get-styled-class-name-from-key.d.ts +2 -0
  174. package/build-types/ui/context/get-styled-class-name-from-key.d.ts.map +1 -0
  175. package/build-types/ui/context/index.d.ts +5 -0
  176. package/build-types/ui/context/index.d.ts.map +1 -0
  177. package/build-types/ui/context/test/context-connect.d.ts +2 -0
  178. package/build-types/ui/context/test/context-connect.d.ts.map +1 -0
  179. package/build-types/ui/context/test/wordpress-component.d.ts +2 -0
  180. package/build-types/ui/context/test/wordpress-component.d.ts.map +1 -0
  181. package/build-types/ui/context/use-context-system.d.ts +20 -0
  182. package/build-types/ui/context/use-context-system.d.ts.map +1 -0
  183. package/build-types/ui/context/utils.d.ts +26 -0
  184. package/build-types/ui/context/utils.d.ts.map +1 -0
  185. package/build-types/ui/context/wordpress-component.d.ts +32 -0
  186. package/build-types/ui/context/wordpress-component.d.ts.map +1 -0
  187. package/build-types/ui/shortcut/component.d.ts +12 -0
  188. package/build-types/ui/shortcut/component.d.ts.map +1 -0
  189. package/build-types/ui/shortcut/index.d.ts +3 -0
  190. package/build-types/ui/shortcut/index.d.ts.map +1 -0
  191. package/build-types/ui/tooltip/component.d.ts +29 -0
  192. package/build-types/ui/tooltip/component.d.ts.map +1 -0
  193. package/build-types/ui/tooltip/content.d.ts +9 -0
  194. package/build-types/ui/tooltip/content.d.ts.map +1 -0
  195. package/build-types/ui/tooltip/context.d.ts +10 -0
  196. package/build-types/ui/tooltip/context.d.ts.map +1 -0
  197. package/build-types/ui/tooltip/index.d.ts +3 -0
  198. package/build-types/ui/tooltip/index.d.ts.map +1 -0
  199. package/build-types/ui/tooltip/styles.d.ts +12 -0
  200. package/build-types/ui/tooltip/styles.d.ts.map +1 -0
  201. package/build-types/ui/tooltip/types.d.ts +62 -0
  202. package/build-types/ui/tooltip/types.d.ts.map +1 -0
  203. package/build-types/ui/utils/colors.d.ts +17 -0
  204. package/build-types/ui/utils/colors.d.ts.map +1 -0
  205. package/build-types/ui/utils/font-size.d.ts +18 -0
  206. package/build-types/ui/utils/font-size.d.ts.map +1 -0
  207. package/build-types/ui/utils/get-valid-children.d.ts +13 -0
  208. package/build-types/ui/utils/get-valid-children.d.ts.map +1 -0
  209. package/build-types/ui/utils/index.d.ts +2 -0
  210. package/build-types/ui/utils/index.d.ts.map +1 -0
  211. package/build-types/ui/utils/space.d.ts +23 -0
  212. package/build-types/ui/utils/space.d.ts.map +1 -0
  213. package/build-types/ui/utils/types.d.ts +14 -0
  214. package/build-types/ui/utils/types.d.ts.map +1 -0
  215. package/build-types/ui/utils/use-responsive-value.d.ts +5 -0
  216. package/build-types/ui/utils/use-responsive-value.d.ts.map +1 -0
  217. package/build-types/utils/hooks/use-latest-ref.d.ts +15 -0
  218. package/build-types/utils/hooks/use-latest-ref.d.ts.map +1 -0
  219. package/build-types/utils/input/base.d.ts +3 -0
  220. package/build-types/utils/input/base.d.ts.map +1 -0
  221. package/build-types/utils/input/index.d.ts +2 -0
  222. package/build-types/utils/input/index.d.ts.map +1 -0
  223. package/build-types/utils/input/input-control.d.ts +2 -0
  224. package/build-types/utils/input/input-control.d.ts.map +1 -0
  225. package/build-types/utils/reduce-motion.d.ts +8 -0
  226. package/build-types/utils/reduce-motion.d.ts.map +1 -0
  227. package/build-types/utils/z-index.d.ts +3 -0
  228. package/build-types/utils/z-index.d.ts.map +1 -0
  229. package/build-types/validated-form-controls/control-with-error.d.ts.map +1 -1
  230. package/build-types/validated-form-controls/test/checkbox-control.d.ts +2 -0
  231. package/build-types/validated-form-controls/test/checkbox-control.d.ts.map +1 -0
  232. package/build-types/validated-form-controls/test/combobox-control.d.ts +2 -0
  233. package/build-types/validated-form-controls/test/combobox-control.d.ts.map +1 -0
  234. package/build-types/validated-form-controls/test/custom-select-control.d.ts +2 -0
  235. package/build-types/validated-form-controls/test/custom-select-control.d.ts.map +1 -0
  236. package/build-types/validated-form-controls/test/form-token-field.d.ts +2 -0
  237. package/build-types/validated-form-controls/test/form-token-field.d.ts.map +1 -0
  238. package/build-types/validated-form-controls/test/input-control.d.ts +2 -0
  239. package/build-types/validated-form-controls/test/input-control.d.ts.map +1 -0
  240. package/build-types/validated-form-controls/test/number-control.d.ts +2 -0
  241. package/build-types/validated-form-controls/test/number-control.d.ts.map +1 -0
  242. package/build-types/validated-form-controls/test/radio-control.d.ts +2 -0
  243. package/build-types/validated-form-controls/test/radio-control.d.ts.map +1 -0
  244. package/build-types/validated-form-controls/test/range-control.d.ts +2 -0
  245. package/build-types/validated-form-controls/test/range-control.d.ts.map +1 -0
  246. package/build-types/validated-form-controls/test/select-control.d.ts +2 -0
  247. package/build-types/validated-form-controls/test/select-control.d.ts.map +1 -0
  248. package/build-types/validated-form-controls/test/text-control.d.ts +2 -0
  249. package/build-types/validated-form-controls/test/text-control.d.ts.map +1 -0
  250. package/build-types/validated-form-controls/test/textarea-control.d.ts +2 -0
  251. package/build-types/validated-form-controls/test/textarea-control.d.ts.map +1 -0
  252. package/build-types/validated-form-controls/test/toggle-control.d.ts +2 -0
  253. package/build-types/validated-form-controls/test/toggle-control.d.ts.map +1 -0
  254. package/build-types/validated-form-controls/test/toggle-group-control.d.ts +2 -0
  255. package/build-types/validated-form-controls/test/toggle-group-control.d.ts.map +1 -0
  256. package/build-types/validated-form-controls/validity-indicator.d.ts +2 -1
  257. package/build-types/validated-form-controls/validity-indicator.d.ts.map +1 -1
  258. package/build-types/view/types.d.ts +8 -0
  259. package/build-types/view/types.d.ts.map +1 -0
  260. package/package.json +21 -21
  261. package/src/autocomplete/index.tsx +30 -6
  262. package/src/autocomplete/test/index.tsx +110 -1
  263. package/src/button/style.scss +8 -5
  264. package/src/date-time/test/utils.test.ts +8 -11
  265. package/src/date-time/time/index.tsx +2 -12
  266. package/src/date-time/time/test/index.tsx +69 -0
  267. package/src/date-time/utils.ts +18 -0
  268. package/src/form-token-field/style.scss +1 -0
  269. package/src/private-apis.ts +0 -4
  270. package/src/sandbox/index.tsx +189 -9
  271. package/src/sandbox/test/index.tsx +65 -24
  272. package/src/sandbox/types.ts +11 -0
  273. package/src/select-control/styles/select-control-styles.ts +1 -0
  274. package/src/snackbar/list.tsx +6 -1
  275. package/src/style.scss +0 -2
  276. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +18 -16
  277. package/src/toggle-group-control/toggle-group-control-option-base/styles.ts +4 -6
  278. package/src/validated-form-controls/control-with-error.tsx +44 -4
  279. package/src/validated-form-controls/test/checkbox-control.tsx +49 -0
  280. package/src/validated-form-controls/test/combobox-control.tsx +61 -0
  281. package/src/validated-form-controls/test/control-with-error.tsx +182 -1
  282. package/src/validated-form-controls/test/custom-select-control.tsx +60 -0
  283. package/src/validated-form-controls/test/form-token-field.tsx +52 -0
  284. package/src/validated-form-controls/test/input-control.tsx +42 -0
  285. package/src/validated-form-controls/test/number-control.tsx +44 -0
  286. package/src/validated-form-controls/test/radio-control.tsx +61 -0
  287. package/src/validated-form-controls/test/range-control.tsx +73 -0
  288. package/src/validated-form-controls/test/select-control.tsx +57 -0
  289. package/src/validated-form-controls/test/text-control.tsx +49 -0
  290. package/src/validated-form-controls/test/textarea-control.tsx +51 -0
  291. package/src/validated-form-controls/test/toggle-control.tsx +49 -0
  292. package/src/validated-form-controls/test/toggle-group-control.tsx +28 -0
  293. package/src/validated-form-controls/validity-indicator.tsx +3 -0
  294. package/build/avatar/component.cjs +0 -99
  295. package/build/avatar/component.cjs.map +0 -7
  296. package/build/avatar/index.cjs +0 -37
  297. package/build/avatar/index.cjs.map +0 -7
  298. package/build/avatar/types.cjs +0 -19
  299. package/build/avatar/types.cjs.map +0 -7
  300. package/build/avatar-group/component.cjs +0 -60
  301. package/build/avatar-group/component.cjs.map +0 -7
  302. package/build/avatar-group/index.cjs +0 -37
  303. package/build/avatar-group/index.cjs.map +0 -7
  304. package/build/avatar-group/types.cjs +0 -19
  305. package/build/avatar-group/types.cjs.map +0 -7
  306. package/build-module/avatar/component.mjs +0 -68
  307. package/build-module/avatar/component.mjs.map +0 -7
  308. package/build-module/avatar/index.mjs +0 -6
  309. package/build-module/avatar/index.mjs.map +0 -7
  310. package/build-module/avatar/types.mjs +0 -1
  311. package/build-module/avatar/types.mjs.map +0 -7
  312. package/build-module/avatar-group/component.mjs +0 -29
  313. package/build-module/avatar-group/component.mjs.map +0 -7
  314. package/build-module/avatar-group/index.mjs +0 -6
  315. package/build-module/avatar-group/index.mjs.map +0 -7
  316. package/build-module/avatar-group/types.mjs +0 -1
  317. package/build-module/avatar-group/types.mjs.map +0 -7
  318. package/build-types/avatar/component.d.ts +0 -5
  319. package/build-types/avatar/component.d.ts.map +0 -1
  320. package/build-types/avatar/index.d.ts +0 -3
  321. package/build-types/avatar/index.d.ts.map +0 -1
  322. package/build-types/avatar/types.d.ts +0 -59
  323. package/build-types/avatar/types.d.ts.map +0 -1
  324. package/build-types/avatar-group/component.d.ts +0 -8
  325. package/build-types/avatar-group/component.d.ts.map +0 -1
  326. package/build-types/avatar-group/index.d.ts +0 -3
  327. package/build-types/avatar-group/index.d.ts.map +0 -1
  328. package/build-types/avatar-group/types.d.ts +0 -14
  329. package/build-types/avatar-group/types.d.ts.map +0 -1
  330. package/src/avatar/component.tsx +0 -82
  331. package/src/avatar/index.ts +0 -2
  332. package/src/avatar/styles.scss +0 -152
  333. package/src/avatar/types.ts +0 -59
  334. package/src/avatar-group/component.tsx +0 -46
  335. package/src/avatar-group/index.ts +0 -2
  336. package/src/avatar-group/styles.scss +0 -32
  337. package/src/avatar-group/types.ts +0 -13
@@ -6,6 +6,7 @@ import {
6
6
  useRef,
7
7
  useState,
8
8
  useEffect,
9
+ useMemo,
9
10
  } from '@wordpress/element';
10
11
  import { useFocusableIframe, useMergeRefs } from '@wordpress/compose';
11
12
 
@@ -14,6 +15,8 @@ import { useFocusableIframe, useMergeRefs } from '@wordpress/compose';
14
15
  */
15
16
  import type { SandBoxProps } from './types';
16
17
 
18
+ type SandBoxContentProps = Omit< SandBoxProps, 'allowSameOrigin' >;
19
+
17
20
  const observeAndResizeJS = function () {
18
21
  const { MutationObserver } = window;
19
22
 
@@ -115,17 +118,176 @@ const style = `
115
118
  `;
116
119
 
117
120
  /**
118
- * This component provides an isolated environment for arbitrary HTML via iframes.
121
+ * Builds the full HTML document string for the sandbox iframe content.
122
+ */
123
+ function buildSandBoxDocument( {
124
+ html,
125
+ title,
126
+ type,
127
+ styles,
128
+ scripts,
129
+ }: {
130
+ html: string;
131
+ title: string;
132
+ type?: string;
133
+ styles: string[];
134
+ scripts: string[];
135
+ } ): string {
136
+ const htmlDoc = (
137
+ <html lang={ document.documentElement.lang } className={ type }>
138
+ <head>
139
+ <title>{ title }</title>
140
+ <style dangerouslySetInnerHTML={ { __html: style } } />
141
+ { styles.map( ( rules, i ) => (
142
+ <style
143
+ key={ i }
144
+ dangerouslySetInnerHTML={ { __html: rules } }
145
+ />
146
+ ) ) }
147
+ </head>
148
+ <body
149
+ data-resizable-iframe-connected="data-resizable-iframe-connected"
150
+ className={ type }
151
+ >
152
+ <div dangerouslySetInnerHTML={ { __html: html } } />
153
+ <script
154
+ type="text/javascript"
155
+ dangerouslySetInnerHTML={ {
156
+ __html: `(${ observeAndResizeJS.toString() })();`,
157
+ } }
158
+ />
159
+ { scripts.map( ( src ) => (
160
+ <script key={ src } src={ src } />
161
+ ) ) }
162
+ </body>
163
+ </html>
164
+ );
165
+
166
+ return '<!DOCTYPE html>' + renderToString( htmlDoc );
167
+ }
168
+
169
+ /**
170
+ * Isolated sandbox that uses the `srcdoc` attribute to render content
171
+ * without `allow-same-origin`. This is the default for user-controlled
172
+ * content (e.g., the HTML block) where same-origin access would be a
173
+ * security risk.
119
174
  *
120
- * ```jsx
121
- * import { SandBox } from '@wordpress/components';
175
+ * Because `srcdoc` is a declarative attribute, the browser automatically
176
+ * re-renders the content when the iframe is moved in the DOM (e.g.,
177
+ * block reordering), so no `load` event listener is needed.
178
+ * The `message` listener is re-synced on every `load` so
179
+ * it follows the iframe if it's reparented into a different document.
180
+ */
181
+ function IsolatedSandBox( {
182
+ html = '',
183
+ title = '',
184
+ type,
185
+ styles = [],
186
+ scripts = [],
187
+ onFocus,
188
+ tabIndex,
189
+ }: SandBoxContentProps ) {
190
+ const ref = useRef< HTMLIFrameElement >( null );
191
+ const [ width, setWidth ] = useState( 0 );
192
+ const [ height, setHeight ] = useState( 0 );
193
+
194
+ const srcDoc = useMemo(
195
+ () => buildSandBoxDocument( { html, title, type, styles, scripts } ),
196
+ [ html, title, type, styles, scripts ]
197
+ );
198
+
199
+ useEffect( () => {
200
+ const iframe = ref.current;
201
+ if ( ! iframe ) {
202
+ return;
203
+ }
204
+
205
+ function checkMessageForResize( event: MessageEvent ) {
206
+ // Verify that the mounted element is the source of the message.
207
+ // iframe.contentWindow is accessible cross-origin as a
208
+ // WindowProxy reference, so this check still works without
209
+ // allow-same-origin.
210
+ if ( ! iframe || iframe.contentWindow !== event.source ) {
211
+ return;
212
+ }
213
+
214
+ // Attempt to parse the message data as JSON if passed as string.
215
+ let data = event.data || {};
216
+
217
+ if ( 'string' === typeof data ) {
218
+ try {
219
+ data = JSON.parse( data );
220
+ } catch {}
221
+ }
222
+
223
+ // Update the state only if the message is formatted as we expect,
224
+ // i.e. as an object with a 'resize' action.
225
+ if ( 'resize' !== data.action ) {
226
+ return;
227
+ }
228
+
229
+ setWidth( data.width );
230
+ setHeight( data.height );
231
+ }
232
+
233
+ let currentView: Window | null = null;
234
+ function syncListener() {
235
+ const view = iframe?.ownerDocument?.defaultView ?? null;
236
+ if ( view === currentView ) {
237
+ return;
238
+ }
239
+
240
+ currentView?.removeEventListener(
241
+ 'message',
242
+ checkMessageForResize
243
+ );
244
+
245
+ currentView = view;
246
+ currentView?.addEventListener( 'message', checkMessageForResize );
247
+ }
248
+
249
+ syncListener();
250
+ iframe.addEventListener( 'load', syncListener );
251
+
252
+ return () => {
253
+ iframe.removeEventListener( 'load', syncListener );
254
+ currentView?.removeEventListener(
255
+ 'message',
256
+ checkMessageForResize
257
+ );
258
+ };
259
+ }, [] );
260
+
261
+ return (
262
+ <iframe
263
+ ref={ useMergeRefs( [ ref, useFocusableIframe() ] ) }
264
+ title={ title }
265
+ tabIndex={ tabIndex }
266
+ className="components-sandbox"
267
+ sandbox="allow-scripts allow-presentation"
268
+ srcDoc={ srcDoc }
269
+ onFocus={ onFocus }
270
+ width={ Math.ceil( width ) }
271
+ height={ Math.ceil( height ) }
272
+ />
273
+ );
274
+ }
275
+
276
+ /**
277
+ * Same-origin sandbox that writes to `contentDocument` directly. This
278
+ * preserves the parent page's URL as the iframe's document URL, which
279
+ * provides a valid Referer header for nested iframes (required by
280
+ * providers like YouTube).
122
281
  *
123
- * const MySandBox = () => (
124
- * <SandBox html="<p>Content</p>" title="SandBox" type="embed" />
125
- * );
126
- * ```
282
+ * Only used when `allowSameOrigin` is true — i.e., for server-fetched
283
+ * oEmbed previews that are not directly user-controlled.
284
+ *
285
+ * This implementation is intentionally kept close to the original
286
+ * pre-refactor code to preserve past bugfixes:
287
+ * - load listener for iframe re-initialization after DOM moves (#21916)
288
+ * - forceRerender guard to avoid unnecessary full rewrites (#20176)
127
289
  */
128
- function SandBox( {
290
+ function SameOriginSandBox( {
129
291
  html = '',
130
292
  title = '',
131
293
  type,
@@ -133,7 +295,7 @@ function SandBox( {
133
295
  scripts = [],
134
296
  onFocus,
135
297
  tabIndex,
136
- }: SandBoxProps ) {
298
+ }: SandBoxContentProps ) {
137
299
  const ref = useRef< HTMLIFrameElement >( null );
138
300
  const [ width, setWidth ] = useState( 0 );
139
301
  const [ height, setHeight ] = useState( 0 );
@@ -292,4 +454,22 @@ function SandBox( {
292
454
  );
293
455
  }
294
456
 
457
+ /**
458
+ * This component provides an isolated environment for arbitrary HTML via iframes.
459
+ *
460
+ * ```jsx
461
+ * import { SandBox } from '@wordpress/components';
462
+ *
463
+ * const MySandBox = () => (
464
+ * <SandBox html="<p>Content</p>" title="SandBox" type="embed" />
465
+ * );
466
+ * ```
467
+ */
468
+ function SandBox( { allowSameOrigin = false, ...contentProps }: SandBoxProps ) {
469
+ if ( allowSameOrigin ) {
470
+ return <SameOriginSandBox { ...contentProps } />;
471
+ }
472
+ return <IsolatedSandBox { ...contentProps } />;
473
+ }
474
+
295
475
  export default SandBox;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { fireEvent, render, screen, within } from '@testing-library/react';
4
+ import { fireEvent, render, screen } from '@testing-library/react';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -16,10 +16,7 @@ import SandBox from '..';
16
16
  describe( 'SandBox', () => {
17
17
  const TestWrapper = () => {
18
18
  const [ html, setHtml ] = useState(
19
- // MutationObserver implementation from JSDom does not work as intended
20
- // with iframes so we need to ignore it for the time being.
21
- '<script type="text/javascript">window.MutationObserver = null;</script>' +
22
- '<iframe title="Mock Iframe" src="https://super.embed"></iframe>'
19
+ '<iframe title="Mock Iframe" src="https://super.embed"></iframe>'
23
20
  );
24
21
 
25
22
  const updateHtml = () => {
@@ -38,34 +35,78 @@ describe( 'SandBox', () => {
38
35
  );
39
36
  };
40
37
 
41
- it( 'should rerender with new emdeded content if html prop changes', () => {
38
+ it( 'should not include allow-same-origin by default', () => {
39
+ render( <SandBox html="<p>Hello</p>" title="Test" /> );
40
+
41
+ const iframe = screen.getByTitle< HTMLIFrameElement >( 'Test' );
42
+
43
+ expect( iframe ).toHaveAttribute(
44
+ 'sandbox',
45
+ 'allow-scripts allow-presentation'
46
+ );
47
+ expect( iframe.getAttribute( 'sandbox' ) ).not.toContain(
48
+ 'allow-same-origin'
49
+ );
50
+ } );
51
+
52
+ it( 'should set srcdoc with the provided html content', () => {
53
+ render( <SandBox html="<p>Hello</p>" title="Test Title" /> );
54
+
55
+ const iframe = screen.getByTitle< HTMLIFrameElement >( 'Test Title' );
56
+ const srcDoc = iframe.getAttribute( 'srcdoc' ) ?? '';
57
+
58
+ expect( srcDoc ).toContain( '<p>Hello</p>' );
59
+ expect( srcDoc ).toContain( '<title>Test Title</title>' );
60
+ } );
61
+
62
+ it( 'should include custom styles in srcdoc', () => {
63
+ render(
64
+ <SandBox
65
+ html="<p>Styled</p>"
66
+ title="Styled Test"
67
+ styles={ [ '.custom { color: red; }' ] }
68
+ />
69
+ );
70
+
71
+ const iframe = screen.getByTitle< HTMLIFrameElement >( 'Styled Test' );
72
+ const srcDoc = iframe.getAttribute( 'srcdoc' ) ?? '';
73
+
74
+ expect( srcDoc ).toContain( '.custom { color: red; }' );
75
+ } );
76
+
77
+ it( 'should include script tags in srcdoc', () => {
78
+ render(
79
+ <SandBox
80
+ html="<p>Script</p>"
81
+ title="Script Test"
82
+ scripts={ [ 'https://example.com/embed.js' ] }
83
+ />
84
+ );
85
+
86
+ const iframe = screen.getByTitle< HTMLIFrameElement >( 'Script Test' );
87
+ const srcDoc = iframe.getAttribute( 'srcdoc' ) ?? '';
88
+
89
+ expect( srcDoc ).toContain(
90
+ '<script src="https://example.com/embed.js">'
91
+ );
92
+ } );
93
+
94
+ it( 'should update srcdoc when html prop changes', () => {
42
95
  render( <TestWrapper /> );
43
96
 
44
97
  const iframe =
45
98
  screen.getByTitle< HTMLIFrameElement >( 'SandBox Title' );
46
99
 
47
- if ( ! iframe.contentWindow ) {
48
- throw new Error();
49
- }
50
-
51
- let sandboxedIframe = within(
52
- iframe.contentWindow.document.body
53
- ).getByTitle( 'Mock Iframe' );
54
-
55
- expect( sandboxedIframe ).toHaveAttribute(
56
- 'src',
57
- 'https://super.embed'
100
+ expect( iframe ).toHaveAttribute(
101
+ 'srcdoc',
102
+ expect.stringContaining( 'https://super.embed' )
58
103
  );
59
104
 
60
105
  fireEvent.click( screen.getByRole( 'button' ) );
61
106
 
62
- sandboxedIframe = within(
63
- iframe.contentWindow.document.body
64
- ).getByTitle( 'Mock Iframe' );
65
-
66
- expect( sandboxedIframe ).toHaveAttribute(
67
- 'src',
68
- 'https://another.super.embed'
107
+ expect( iframe ).toHaveAttribute(
108
+ 'srcdoc',
109
+ expect.stringContaining( 'https://another.super.embed' )
69
110
  );
70
111
  } );
71
112
  } );
@@ -1,4 +1,15 @@
1
1
  export type SandBoxProps = {
2
+ /**
3
+ * Whether to include `allow-same-origin` in the iframe's sandbox
4
+ * attribute. When true, nested iframes (such as third-party embeds)
5
+ * can access their own origin's cookies and storage.
6
+ *
7
+ * Only enable this for content that is NOT directly user-controlled,
8
+ * such as server-fetched oEmbed previews.
9
+ *
10
+ * @default false
11
+ */
12
+ allowSameOrigin?: boolean;
2
13
  /**
3
14
  * The HTML to render in the body of the iframe document.
4
15
  *
@@ -162,6 +162,7 @@ export const Select = styled.select< SelectProps >`
162
162
  cursor: inherit;
163
163
  display: block;
164
164
  font-family: inherit;
165
+ line-height: 1.3; // Override forms.css styles, large enough value to prevent descender clipping without affecting height
165
166
  margin: 0;
166
167
  width: 100%;
167
168
  max-width: none;
@@ -86,7 +86,12 @@ export function SnackbarList( {
86
86
 
87
87
  return (
88
88
  <motion.div
89
- layout={ ! isReducedMotion } // See https://www.framer.com/docs/animation/#layout-animations
89
+ layout={ isReducedMotion ? false : 'position' } // See https://www.framer.com/docs/animation/#layout-animations
90
+ // Ensures a stable full-width bounding box so that
91
+ // `layout="position"` only ever detects vertical
92
+ // shifts, preventing horizontal animation when
93
+ // notice text changes in place.
94
+ style={ { width: '100%' } }
90
95
  initial="init"
91
96
  animate="open"
92
97
  exit="exit"
package/src/style.scss CHANGED
@@ -1,8 +1,6 @@
1
1
  @use "@wordpress/base-styles/mixins" as *;
2
2
  @use "./animate/style.scss" as *;
3
3
  @use "./autocomplete/style.scss" as *;
4
- @use "./avatar/styles.scss" as *;
5
- @use "./avatar-group/styles.scss" as *;
6
4
  @use "./badge/styles.scss" as *;
7
5
  @use "./button-group/style.scss" as *;
8
6
  @use "./button/style.scss" as *;
@@ -137,7 +137,6 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
137
137
  user-select: none;
138
138
  width: 100%;
139
139
  z-index: 2;
140
- color: var(--wp-components-color-foreground, #1e1e1e);
141
140
  height: 38px;
142
141
  aspect-ratio: 1;
143
142
  padding-left: 0;
@@ -157,12 +156,13 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
157
156
  border: 0;
158
157
  }
159
158
 
160
- .emotion-12[disabled] {
159
+ .emotion-12[disabled],
160
+ .emotion-12[aria-disabled='true'] {
161
161
  opacity: 0.4;
162
162
  cursor: default;
163
163
  }
164
164
 
165
- .emotion-12:hover {
165
+ .emotion-12:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
166
166
  color: var(--wp-components-color-foreground, #1e1e1e);
167
167
  }
168
168
 
@@ -211,7 +211,6 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
211
211
  user-select: none;
212
212
  width: 100%;
213
213
  z-index: 2;
214
- color: var(--wp-components-color-foreground, #1e1e1e);
215
214
  height: 38px;
216
215
  aspect-ratio: 1;
217
216
  padding-left: 0;
@@ -229,12 +228,13 @@ exports[`ToggleGroupControl controlled should render correctly with icons 1`] =
229
228
  border: 0;
230
229
  }
231
230
 
232
- .emotion-17[disabled] {
231
+ .emotion-17[disabled],
232
+ .emotion-17[aria-disabled='true'] {
233
233
  opacity: 0.4;
234
234
  cursor: default;
235
235
  }
236
236
 
237
- .emotion-17:hover {
237
+ .emotion-17:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
238
238
  color: var(--wp-components-color-foreground, #1e1e1e);
239
239
  }
240
240
 
@@ -491,12 +491,13 @@ exports[`ToggleGroupControl controlled should render correctly with text options
491
491
  border: 0;
492
492
  }
493
493
 
494
- .emotion-12[disabled] {
494
+ .emotion-12[disabled],
495
+ .emotion-12[aria-disabled='true'] {
495
496
  opacity: 0.4;
496
497
  cursor: default;
497
498
  }
498
499
 
499
- .emotion-12:hover {
500
+ .emotion-12:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
500
501
  color: var(--wp-components-color-foreground, #1e1e1e);
501
502
  }
502
503
 
@@ -726,7 +727,6 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
726
727
  user-select: none;
727
728
  width: 100%;
728
729
  z-index: 2;
729
- color: var(--wp-components-color-foreground, #1e1e1e);
730
730
  height: 38px;
731
731
  aspect-ratio: 1;
732
732
  padding-left: 0;
@@ -746,12 +746,13 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
746
746
  border: 0;
747
747
  }
748
748
 
749
- .emotion-12[disabled] {
749
+ .emotion-12[disabled],
750
+ .emotion-12[aria-disabled='true'] {
750
751
  opacity: 0.4;
751
752
  cursor: default;
752
753
  }
753
754
 
754
- .emotion-12:hover {
755
+ .emotion-12:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
755
756
  color: var(--wp-components-color-foreground, #1e1e1e);
756
757
  }
757
758
 
@@ -800,7 +801,6 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
800
801
  user-select: none;
801
802
  width: 100%;
802
803
  z-index: 2;
803
- color: var(--wp-components-color-foreground, #1e1e1e);
804
804
  height: 38px;
805
805
  aspect-ratio: 1;
806
806
  padding-left: 0;
@@ -818,12 +818,13 @@ exports[`ToggleGroupControl uncontrolled should render correctly with icons 1`]
818
818
  border: 0;
819
819
  }
820
820
 
821
- .emotion-17[disabled] {
821
+ .emotion-17[disabled],
822
+ .emotion-17[aria-disabled='true'] {
822
823
  opacity: 0.4;
823
824
  cursor: default;
824
825
  }
825
826
 
826
- .emotion-17:hover {
827
+ .emotion-17:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
827
828
  color: var(--wp-components-color-foreground, #1e1e1e);
828
829
  }
829
830
 
@@ -1074,12 +1075,13 @@ exports[`ToggleGroupControl uncontrolled should render correctly with text optio
1074
1075
  border: 0;
1075
1076
  }
1076
1077
 
1077
- .emotion-12[disabled] {
1078
+ .emotion-12[disabled],
1079
+ .emotion-12[aria-disabled='true'] {
1078
1080
  opacity: 0.4;
1079
1081
  cursor: default;
1080
1082
  }
1081
1083
 
1082
- .emotion-12:hover {
1084
+ .emotion-12:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
1083
1085
  color: var(--wp-components-color-foreground, #1e1e1e);
1084
1086
  }
1085
1087
 
@@ -63,13 +63,14 @@ export const buttonView = ( {
63
63
  border: 0;
64
64
  }
65
65
 
66
- &[disabled] {
66
+ &[disabled],
67
+ &[aria-disabled='true'] {
67
68
  opacity: 0.4;
68
69
  cursor: default;
69
70
  }
70
71
 
71
- &:hover {
72
- color: ${ COLORS.theme.gray[ 900 ] };
72
+ &:hover:not( [disabled] ):not( [aria-disabled='true'] ) {
73
+ color: ${ COLORS.theme.foreground };
73
74
  }
74
75
 
75
76
  ${ isDeselectable && deselectable }
@@ -83,8 +84,6 @@ const pressed = css`
83
84
  `;
84
85
 
85
86
  const deselectable = css`
86
- color: ${ COLORS.theme.foreground };
87
-
88
87
  &:focus {
89
88
  outline: ${ CONFIG.borderWidthFocus } solid ${ COLORS.ui.borderFocus };
90
89
  outline-offset: 2px;
@@ -112,7 +111,6 @@ const isIconStyles = ( {
112
111
  };
113
112
 
114
113
  return css`
115
- color: ${ COLORS.theme.foreground };
116
114
  height: ${ iconButtonSizes[ size ] };
117
115
  aspect-ratio: 1;
118
116
  padding-left: 0;
@@ -6,6 +6,7 @@ import {
6
6
  cloneElement,
7
7
  forwardRef,
8
8
  useEffect,
9
+ useId,
9
10
  useState,
10
11
  } from '@wordpress/element';
11
12
 
@@ -238,22 +239,61 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
238
239
  }
239
240
  };
240
241
 
241
- const message = () => {
242
+ const messageId = useId();
243
+
244
+ const message = ( () => {
242
245
  if ( errorMessage ) {
243
246
  return (
244
- <ValidityIndicator type="invalid" message={ errorMessage } />
247
+ <ValidityIndicator
248
+ id={ messageId }
249
+ type="invalid"
250
+ message={ errorMessage }
251
+ />
245
252
  );
246
253
  }
247
254
  if ( statusMessage?.type ) {
248
255
  return (
249
256
  <ValidityIndicator
257
+ id={ messageId }
250
258
  type={ statusMessage.type }
251
259
  message={ statusMessage.message }
252
260
  />
253
261
  );
254
262
  }
255
263
  return null;
256
- };
264
+ } )();
265
+
266
+ const visibleMessage = showMessage ? message : null;
267
+
268
+ // Imperatively manage `aria-describedby` on the validity target so we
269
+ // merge with any value the child control sets internally (e.g. from a
270
+ // `help` prop), rather than competing with it at the props level.
271
+ useEffect( () => {
272
+ const target = getValidityTarget();
273
+ if ( ! target ) {
274
+ return;
275
+ }
276
+
277
+ function setDescribedBy( el: Element, shouldAdd: boolean ) {
278
+ const ids = ( el.getAttribute( 'aria-describedby' ) ?? '' )
279
+ .split( ' ' )
280
+ .filter( ( id ) => id && id !== messageId );
281
+
282
+ if ( shouldAdd ) {
283
+ ids.push( messageId );
284
+ }
285
+
286
+ if ( ids.length ) {
287
+ el.setAttribute( 'aria-describedby', ids.join( ' ' ) );
288
+ } else {
289
+ el.removeAttribute( 'aria-describedby' );
290
+ }
291
+ }
292
+
293
+ setDescribedBy( target, !! visibleMessage );
294
+
295
+ return () => setDescribedBy( target, false );
296
+ }, [ visibleMessage, messageId, getValidityTarget ] );
257
297
 
258
298
  return (
259
299
  <div className={ className } ref={ forwardedRef } onBlur={ onBlur }>
@@ -265,7 +305,7 @@ function UnforwardedControlWithError< C extends React.ReactElement >(
265
305
  ),
266
306
  required,
267
307
  } ) }
268
- <div aria-live="polite">{ showMessage && message() }</div>
308
+ <div aria-live="polite">{ visibleMessage }</div>
269
309
  </div>
270
310
  );
271
311
  }
@@ -0,0 +1,49 @@
1
+ import { render, screen, waitFor } from '@testing-library/react';
2
+ import userEvent from '@testing-library/user-event';
3
+ import { ValidatedCheckboxControl } from '../components';
4
+
5
+ describe( 'ValidatedCheckboxControl', () => {
6
+ it( 'should preserve the help description', () => {
7
+ render(
8
+ <ValidatedCheckboxControl
9
+ label="Agree"
10
+ help="You must agree to continue."
11
+ onChange={ () => {} }
12
+ />
13
+ );
14
+
15
+ expect(
16
+ screen.getByRole( 'checkbox', { name: 'Agree' } )
17
+ ).toHaveAccessibleDescription( 'You must agree to continue.' );
18
+ } );
19
+
20
+ it( 'should append the validation error alongside the help description', async () => {
21
+ const user = userEvent.setup();
22
+ render(
23
+ <form>
24
+ <ValidatedCheckboxControl
25
+ label="Agree"
26
+ help="You must agree to continue."
27
+ onChange={ () => {} }
28
+ required
29
+ />
30
+ <button type="submit">Submit</button>
31
+ </form>
32
+ );
33
+
34
+ const checkbox = screen.getByRole( 'checkbox', {
35
+ name: /^Agree/,
36
+ } );
37
+
38
+ await user.click( screen.getByRole( 'button', { name: 'Submit' } ) );
39
+
40
+ await waitFor( () => {
41
+ expect( checkbox ).toHaveAccessibleDescription(
42
+ expect.stringContaining( 'Constraints not satisfied' )
43
+ );
44
+ } );
45
+ expect( checkbox ).toHaveAccessibleDescription(
46
+ expect.stringContaining( 'You must agree to continue.' )
47
+ );
48
+ } );
49
+ } );