@wordpress/components 25.9.1 → 25.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/build/alignment-matrix-control/cell.js +8 -5
  3. package/build/alignment-matrix-control/cell.js.map +1 -1
  4. package/build/alignment-matrix-control/index.js +27 -43
  5. package/build/alignment-matrix-control/index.js.map +1 -1
  6. package/build/alignment-matrix-control/utils.js +29 -9
  7. package/build/alignment-matrix-control/utils.js.map +1 -1
  8. package/build/circular-option-picker/circular-option-picker-option.js +20 -39
  9. package/build/circular-option-picker/circular-option-picker-option.js.map +1 -1
  10. package/build/circular-option-picker/circular-option-picker.js +11 -32
  11. package/build/circular-option-picker/circular-option-picker.js.map +1 -1
  12. package/build/circular-option-picker/types.js.map +1 -1
  13. package/build/color-palette/index.js +7 -2
  14. package/build/color-palette/index.js.map +1 -1
  15. package/build/color-picker/component.js +12 -2
  16. package/build/color-picker/component.js.map +1 -1
  17. package/build/color-picker/picker.js +77 -1
  18. package/build/color-picker/picker.js.map +1 -1
  19. package/build/color-picker/styles.js +8 -8
  20. package/build/color-picker/styles.js.map +1 -1
  21. package/build/color-picker/types.js.map +1 -1
  22. package/build/composite/v2.js +43 -0
  23. package/build/composite/v2.js.map +1 -0
  24. package/build/confirm-dialog/component.js +74 -8
  25. package/build/confirm-dialog/component.js.map +1 -1
  26. package/build/confirm-dialog/types.js.map +1 -1
  27. package/build/custom-gradient-picker/gradient-bar/control-points.js +13 -4
  28. package/build/custom-gradient-picker/gradient-bar/control-points.js.map +1 -1
  29. package/build/font-size-picker/utils.js +1 -1
  30. package/build/font-size-picker/utils.js.map +1 -1
  31. package/build/modal/index.js +45 -16
  32. package/build/modal/index.js.map +1 -1
  33. package/build/palette-edit/index.js +4 -0
  34. package/build/palette-edit/index.js.map +1 -1
  35. package/build/popover/index.js +34 -6
  36. package/build/popover/index.js.map +1 -1
  37. package/build/private-apis.js +9 -1
  38. package/build/private-apis.js.map +1 -1
  39. package/build/progress-bar/styles.js +5 -5
  40. package/build/progress-bar/styles.js.map +1 -1
  41. package/build/sandbox/index.js +1 -1
  42. package/build/sandbox/index.js.map +1 -1
  43. package/build/sandbox/index.native.js +1 -1
  44. package/build/sandbox/index.native.js.map +1 -1
  45. package/build/tabs/context.js +16 -0
  46. package/build/tabs/context.js.map +1 -0
  47. package/build/tabs/index.js +147 -0
  48. package/build/tabs/index.js.map +1 -0
  49. package/build/tabs/styles.js +38 -0
  50. package/build/tabs/styles.js.map +1 -0
  51. package/build/tabs/tab.js +46 -0
  52. package/build/tabs/tab.js.map +1 -0
  53. package/build/tabs/tablist.js +47 -0
  54. package/build/tabs/tablist.js.map +1 -0
  55. package/build/tabs/tabpanel.js +48 -0
  56. package/build/tabs/tabpanel.js.map +1 -0
  57. package/build/tabs/types.js +6 -0
  58. package/build/tabs/types.js.map +1 -0
  59. package/build/text/component.js +7 -6
  60. package/build/text/component.js.map +1 -1
  61. package/build/text/hook.js +6 -15
  62. package/build/text/hook.js.map +1 -1
  63. package/build/text/index.js.map +1 -1
  64. package/build/text/styles.js +7 -7
  65. package/build/text/styles.js.map +1 -1
  66. package/build/text/types.js.map +1 -1
  67. package/build/text/utils.js +17 -33
  68. package/build/text/utils.js.map +1 -1
  69. package/build/toggle-group-control/toggle-group-control-option-base/component.js +1 -0
  70. package/build/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
  71. package/build/toolbar/toolbar/index.js +17 -10
  72. package/build/toolbar/toolbar/index.js.map +1 -1
  73. package/build/toolbar/toolbar/types.js.map +1 -1
  74. package/build/tools-panel/tools-panel-item/hook.js +2 -2
  75. package/build/tools-panel/tools-panel-item/hook.js.map +1 -1
  76. package/build/tools-panel/types.js.map +1 -1
  77. package/build/unit-control/utils.js +108 -0
  78. package/build/unit-control/utils.js.map +1 -1
  79. package/build/utils/unit-values.js +1 -1
  80. package/build/utils/unit-values.js.map +1 -1
  81. package/build-module/alignment-matrix-control/cell.js +7 -4
  82. package/build-module/alignment-matrix-control/cell.js.map +1 -1
  83. package/build-module/alignment-matrix-control/index.js +27 -43
  84. package/build-module/alignment-matrix-control/index.js.map +1 -1
  85. package/build-module/alignment-matrix-control/utils.js +29 -8
  86. package/build-module/alignment-matrix-control/utils.js.map +1 -1
  87. package/build-module/circular-option-picker/circular-option-picker-option.js +20 -39
  88. package/build-module/circular-option-picker/circular-option-picker-option.js.map +1 -1
  89. package/build-module/circular-option-picker/circular-option-picker.js +10 -31
  90. package/build-module/circular-option-picker/circular-option-picker.js.map +1 -1
  91. package/build-module/circular-option-picker/types.js.map +1 -1
  92. package/build-module/color-palette/index.js +7 -2
  93. package/build-module/color-palette/index.js.map +1 -1
  94. package/build-module/color-picker/component.js +13 -3
  95. package/build-module/color-picker/component.js.map +1 -1
  96. package/build-module/color-picker/picker.js +78 -2
  97. package/build-module/color-picker/picker.js.map +1 -1
  98. package/build-module/color-picker/styles.js +8 -8
  99. package/build-module/color-picker/styles.js.map +1 -1
  100. package/build-module/color-picker/types.js.map +1 -1
  101. package/build-module/composite/v2.js +15 -0
  102. package/build-module/composite/v2.js.map +1 -0
  103. package/build-module/confirm-dialog/component.js +72 -7
  104. package/build-module/confirm-dialog/component.js.map +1 -1
  105. package/build-module/confirm-dialog/types.js.map +1 -1
  106. package/build-module/custom-gradient-picker/gradient-bar/control-points.js +13 -4
  107. package/build-module/custom-gradient-picker/gradient-bar/control-points.js.map +1 -1
  108. package/build-module/font-size-picker/utils.js +1 -1
  109. package/build-module/font-size-picker/utils.js.map +1 -1
  110. package/build-module/modal/index.js +47 -18
  111. package/build-module/modal/index.js.map +1 -1
  112. package/build-module/palette-edit/index.js +4 -0
  113. package/build-module/palette-edit/index.js.map +1 -1
  114. package/build-module/popover/index.js +34 -6
  115. package/build-module/popover/index.js.map +1 -1
  116. package/build-module/private-apis.js +9 -1
  117. package/build-module/private-apis.js.map +1 -1
  118. package/build-module/progress-bar/styles.js +5 -5
  119. package/build-module/progress-bar/styles.js.map +1 -1
  120. package/build-module/sandbox/index.js +1 -1
  121. package/build-module/sandbox/index.js.map +1 -1
  122. package/build-module/sandbox/index.native.js +1 -1
  123. package/build-module/sandbox/index.native.js.map +1 -1
  124. package/build-module/tabs/context.js +12 -0
  125. package/build-module/tabs/context.js.map +1 -0
  126. package/build-module/tabs/index.js +142 -0
  127. package/build-module/tabs/index.js.map +1 -0
  128. package/build-module/tabs/styles.js +36 -0
  129. package/build-module/tabs/styles.js.map +1 -0
  130. package/build-module/tabs/tab.js +43 -0
  131. package/build-module/tabs/tab.js.map +1 -0
  132. package/build-module/tabs/tablist.js +41 -0
  133. package/build-module/tabs/tablist.js.map +1 -0
  134. package/build-module/tabs/tabpanel.js +43 -0
  135. package/build-module/tabs/tabpanel.js.map +1 -0
  136. package/build-module/tabs/types.js +2 -0
  137. package/build-module/tabs/types.js.map +1 -0
  138. package/build-module/text/component.js +6 -6
  139. package/build-module/text/component.js.map +1 -1
  140. package/build-module/text/hook.js +11 -19
  141. package/build-module/text/hook.js.map +1 -1
  142. package/build-module/text/index.js.map +1 -1
  143. package/build-module/text/styles.js +7 -7
  144. package/build-module/text/styles.js.map +1 -1
  145. package/build-module/text/types.js.map +1 -1
  146. package/build-module/text/utils.js +17 -10
  147. package/build-module/text/utils.js.map +1 -1
  148. package/build-module/toggle-group-control/toggle-group-control-option-base/component.js +1 -0
  149. package/build-module/toggle-group-control/toggle-group-control-option-base/component.js.map +1 -1
  150. package/build-module/toolbar/toolbar/index.js +18 -11
  151. package/build-module/toolbar/toolbar/index.js.map +1 -1
  152. package/build-module/toolbar/toolbar/types.js.map +1 -1
  153. package/build-module/tools-panel/tools-panel-item/hook.js +2 -2
  154. package/build-module/tools-panel/tools-panel-item/hook.js.map +1 -1
  155. package/build-module/tools-panel/types.js.map +1 -1
  156. package/build-module/unit-control/utils.js +108 -0
  157. package/build-module/unit-control/utils.js.map +1 -1
  158. package/build-module/utils/unit-values.js +1 -1
  159. package/build-module/utils/unit-values.js.map +1 -1
  160. package/build-style/style-rtl.css +16 -4
  161. package/build-style/style.css +16 -4
  162. package/build-types/alignment-matrix-control/cell.d.ts +1 -1
  163. package/build-types/alignment-matrix-control/cell.d.ts.map +1 -1
  164. package/build-types/alignment-matrix-control/index.d.ts.map +1 -1
  165. package/build-types/alignment-matrix-control/stories/index.story.d.ts.map +1 -1
  166. package/build-types/alignment-matrix-control/utils.d.ts +9 -9
  167. package/build-types/alignment-matrix-control/utils.d.ts.map +1 -1
  168. package/build-types/circular-option-picker/circular-option-picker-option.d.ts.map +1 -1
  169. package/build-types/circular-option-picker/circular-option-picker.d.ts.map +1 -1
  170. package/build-types/circular-option-picker/types.d.ts +4 -6
  171. package/build-types/circular-option-picker/types.d.ts.map +1 -1
  172. package/build-types/color-palette/index.d.ts.map +1 -1
  173. package/build-types/color-picker/component.d.ts.map +1 -1
  174. package/build-types/color-picker/picker.d.ts +1 -1
  175. package/build-types/color-picker/picker.d.ts.map +1 -1
  176. package/build-types/color-picker/styles.d.ts.map +1 -1
  177. package/build-types/color-picker/types.d.ts +3 -0
  178. package/build-types/color-picker/types.d.ts.map +1 -1
  179. package/build-types/composite/v2.d.ts +12 -0
  180. package/build-types/composite/v2.d.ts.map +1 -0
  181. package/build-types/confirm-dialog/component.d.ts +70 -29
  182. package/build-types/confirm-dialog/component.d.ts.map +1 -1
  183. package/build-types/confirm-dialog/stories/index.story.d.ts +11 -0
  184. package/build-types/confirm-dialog/stories/index.story.d.ts.map +1 -0
  185. package/build-types/confirm-dialog/test/index.d.ts +2 -0
  186. package/build-types/confirm-dialog/test/index.d.ts.map +1 -0
  187. package/build-types/confirm-dialog/types.d.ts +32 -10
  188. package/build-types/confirm-dialog/types.d.ts.map +1 -1
  189. package/build-types/custom-gradient-picker/gradient-bar/control-points.d.ts.map +1 -1
  190. package/build-types/font-size-picker/utils.d.ts.map +1 -1
  191. package/build-types/heading/stories/index.story.d.ts.map +1 -1
  192. package/build-types/modal/index.d.ts.map +1 -1
  193. package/build-types/palette-edit/index.d.ts.map +1 -1
  194. package/build-types/popover/index.d.ts +1 -1
  195. package/build-types/popover/index.d.ts.map +1 -1
  196. package/build-types/popover/stories/e2e/index.story.d.ts +1 -1
  197. package/build-types/private-apis.d.ts.map +1 -1
  198. package/build-types/progress-bar/styles.d.ts.map +1 -1
  199. package/build-types/sandbox/index.d.ts.map +1 -1
  200. package/build-types/tabs/context.d.ts +8 -0
  201. package/build-types/tabs/context.d.ts.map +1 -0
  202. package/build-types/tabs/index.d.ts +13 -0
  203. package/build-types/tabs/index.d.ts.map +1 -0
  204. package/build-types/tabs/stories/index.story.d.ts +20 -0
  205. package/build-types/tabs/stories/index.story.d.ts.map +1 -0
  206. package/build-types/tabs/styles.d.ts +17 -0
  207. package/build-types/tabs/styles.d.ts.map +1 -0
  208. package/build-types/tabs/tab.d.ts +10 -0
  209. package/build-types/tabs/tab.d.ts.map +1 -0
  210. package/build-types/tabs/tablist.d.ts +7 -0
  211. package/build-types/tabs/tablist.d.ts.map +1 -0
  212. package/build-types/tabs/tabpanel.d.ts +7 -0
  213. package/build-types/tabs/tabpanel.d.ts.map +1 -0
  214. package/build-types/tabs/test/index.d.ts +2 -0
  215. package/build-types/tabs/test/index.d.ts.map +1 -0
  216. package/build-types/tabs/types.d.ts +134 -0
  217. package/build-types/tabs/types.d.ts.map +1 -0
  218. package/build-types/text/component.d.ts +4 -2
  219. package/build-types/text/component.d.ts.map +1 -1
  220. package/build-types/text/hook.d.ts +171 -165
  221. package/build-types/text/hook.d.ts.map +1 -1
  222. package/build-types/text/index.d.ts +2 -2
  223. package/build-types/text/index.d.ts.map +1 -1
  224. package/build-types/text/stories/index.story.d.ts +21 -0
  225. package/build-types/text/stories/index.story.d.ts.map +1 -0
  226. package/build-types/text/styles.d.ts +7 -7
  227. package/build-types/text/styles.d.ts.map +1 -1
  228. package/build-types/text/types.d.ts +1 -1
  229. package/build-types/text/types.d.ts.map +1 -1
  230. package/build-types/text/utils.d.ts +56 -61
  231. package/build-types/text/utils.d.ts.map +1 -1
  232. package/build-types/toggle-group-control/toggle-group-control-option-base/component.d.ts.map +1 -1
  233. package/build-types/toolbar/stories/index.story.d.ts +5 -0
  234. package/build-types/toolbar/stories/index.story.d.ts.map +1 -1
  235. package/build-types/toolbar/toolbar/index.d.ts.map +1 -1
  236. package/build-types/toolbar/toolbar/types.d.ts +10 -0
  237. package/build-types/toolbar/toolbar/types.d.ts.map +1 -1
  238. package/build-types/tools-panel/tools-panel-item/hook.d.ts.map +1 -1
  239. package/build-types/tools-panel/types.d.ts +2 -0
  240. package/build-types/tools-panel/types.d.ts.map +1 -1
  241. package/build-types/unit-control/utils.d.ts.map +1 -1
  242. package/package.json +19 -19
  243. package/src/alignment-matrix-control/cell.tsx +6 -2
  244. package/src/alignment-matrix-control/index.tsx +31 -54
  245. package/src/alignment-matrix-control/stories/index.story.tsx +3 -7
  246. package/src/alignment-matrix-control/test/index.tsx +117 -18
  247. package/src/alignment-matrix-control/utils.tsx +33 -9
  248. package/src/button/style.scss +1 -2
  249. package/src/circular-option-picker/circular-option-picker-option.tsx +24 -38
  250. package/src/circular-option-picker/circular-option-picker.tsx +11 -28
  251. package/src/circular-option-picker/types.ts +6 -5
  252. package/src/color-palette/index.tsx +6 -1
  253. package/src/color-picker/component.tsx +25 -3
  254. package/src/color-picker/picker.tsx +96 -2
  255. package/src/color-picker/styles.ts +0 -1
  256. package/src/color-picker/types.ts +3 -0
  257. package/src/composite/v2.ts +22 -0
  258. package/src/confirm-dialog/README.md +1 -1
  259. package/src/confirm-dialog/component.tsx +79 -13
  260. package/src/confirm-dialog/stories/{index.story.js → index.story.tsx} +26 -24
  261. package/src/confirm-dialog/test/{index.js → index.tsx} +3 -3
  262. package/src/confirm-dialog/types.ts +32 -12
  263. package/src/custom-gradient-picker/gradient-bar/control-points.tsx +32 -25
  264. package/src/font-size-picker/utils.ts +2 -1
  265. package/src/heading/stories/index.story.tsx +2 -4
  266. package/src/modal/index.tsx +58 -22
  267. package/src/modal/test/index.tsx +29 -0
  268. package/src/notice/style.scss +0 -1
  269. package/src/palette-edit/index.tsx +4 -0
  270. package/src/popover/index.tsx +99 -57
  271. package/src/popover/style.scss +9 -0
  272. package/src/private-apis.ts +15 -1
  273. package/src/progress-bar/styles.ts +19 -4
  274. package/src/sandbox/index.native.js +1 -1
  275. package/src/sandbox/index.tsx +3 -1
  276. package/src/tabs/README.md +242 -0
  277. package/src/tabs/context.ts +13 -0
  278. package/src/tabs/index.tsx +167 -0
  279. package/src/tabs/stories/index.story.tsx +352 -0
  280. package/src/tabs/styles.ts +103 -0
  281. package/src/tabs/tab.tsx +39 -0
  282. package/src/tabs/tablist.tsx +40 -0
  283. package/src/tabs/tabpanel.tsx +42 -0
  284. package/src/tabs/test/index.tsx +1124 -0
  285. package/src/tabs/types.ts +142 -0
  286. package/src/text/README.md +2 -2
  287. package/src/text/{component.js → component.tsx} +10 -6
  288. package/src/text/{hook.js → hook.ts} +12 -15
  289. package/src/text/stories/index.story.tsx +80 -0
  290. package/src/text/types.ts +1 -6
  291. package/src/text/{utils.js → utils.ts} +40 -14
  292. package/src/toggle-group-control/test/__snapshots__/index.tsx.snap +8 -0
  293. package/src/toggle-group-control/toggle-group-control-option-base/component.tsx +1 -0
  294. package/src/toolbar/stories/index.story.tsx +15 -0
  295. package/src/toolbar/test/index.tsx +8 -0
  296. package/src/toolbar/toolbar/README.md +9 -0
  297. package/src/toolbar/toolbar/index.tsx +21 -12
  298. package/src/toolbar/toolbar/style.scss +9 -0
  299. package/src/toolbar/toolbar/types.ts +10 -0
  300. package/src/tools-panel/tools-panel/README.md +3 -0
  301. package/src/tools-panel/tools-panel-item/hook.ts +4 -6
  302. package/src/tools-panel/types.ts +2 -0
  303. package/src/unit-control/utils.ts +124 -0
  304. package/src/utils/unit-values.ts +1 -1
  305. package/tsconfig.tsbuildinfo +1 -1
  306. package/src/text/stories/index.story.js +0 -53
  307. /package/src/text/{index.js → index.ts} +0 -0
  308. /package/src/text/{styles.js → styles.ts} +0 -0
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { Meta, StoryFn } from '@storybook/react';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -7,47 +12,41 @@ import { useState } from '@wordpress/element';
7
12
  * Internal dependencies
8
13
  */
9
14
  import Button from '../../button';
10
- import { ConfirmDialog } from '..';
15
+ import { ConfirmDialog } from '../component';
11
16
 
12
- const meta = {
17
+ const meta: Meta< typeof ConfirmDialog > = {
13
18
  component: ConfirmDialog,
14
19
  title: 'Components (Experimental)/ConfirmDialog',
15
20
  argTypes: {
16
- children: {
17
- control: { type: 'text' },
18
- },
19
- confirmButtonText: {
20
- control: { type: 'text' },
21
- },
22
- cancelButtonText: {
23
- control: { type: 'text' },
24
- },
25
21
  isOpen: {
26
22
  control: { type: null },
27
23
  },
28
- onConfirm: { action: 'onConfirm' },
29
- onCancel: { action: 'onCancel' },
30
- },
31
- args: {
32
- children: 'Would you like to privately publish the post now?',
33
24
  },
34
25
  parameters: {
26
+ actions: { argTypesRegex: '^on.*' },
27
+ controls: {
28
+ expanded: true,
29
+ },
35
30
  docs: { canvas: { sourceState: 'shown' } },
36
31
  },
37
32
  };
38
33
 
39
34
  export default meta;
40
35
 
41
- const Template = ( { onConfirm, onCancel, ...args } ) => {
36
+ const Template: StoryFn< typeof ConfirmDialog > = ( {
37
+ onConfirm,
38
+ onCancel,
39
+ ...args
40
+ } ) => {
42
41
  const [ isOpen, setIsOpen ] = useState( false );
43
42
 
44
- const handleConfirm = ( ...confirmArgs ) => {
45
- onConfirm( ...confirmArgs );
43
+ const handleConfirm: typeof onConfirm = ( confirmArgs ) => {
44
+ onConfirm( confirmArgs );
46
45
  setIsOpen( false );
47
46
  };
48
47
 
49
- const handleCancel = ( ...cancelArgs ) => {
50
- onCancel( ...cancelArgs );
48
+ const handleCancel: typeof onCancel = ( cancelArgs ) => {
49
+ onCancel?.( cancelArgs );
51
50
  setIsOpen( false );
52
51
  };
53
52
 
@@ -70,7 +69,7 @@ const Template = ( { onConfirm, onCancel, ...args } ) => {
70
69
  };
71
70
 
72
71
  // Simplest usage: just declare the component with the required `onConfirm` prop. Note: the `onCancel` prop is optional here, unless you'd like to render the component in Controlled mode (see below)
73
- export const _default = Template.bind( {} );
72
+ export const Default = Template.bind( {} );
74
73
  const _defaultSnippet = `() => {
75
74
  const [ isOpen, setIsOpen ] = useState( false );
76
75
  const [ confirmVal, setConfirmVal ] = useState('');
@@ -103,8 +102,10 @@ const _defaultSnippet = `() => {
103
102
  </>
104
103
  );
105
104
  };`;
106
- _default.args = {};
107
- _default.parameters = {
105
+ Default.args = {
106
+ children: 'Would you like to privately publish the post now?',
107
+ };
108
+ Default.parameters = {
108
109
  docs: {
109
110
  source: {
110
111
  code: _defaultSnippet,
@@ -117,6 +118,7 @@ _default.parameters = {
117
118
  // To customize button text, pass the `cancelButtonText` and/or `confirmButtonText` props.
118
119
  export const WithCustomButtonLabels = Template.bind( {} );
119
120
  WithCustomButtonLabels.args = {
121
+ ...Default.args,
120
122
  cancelButtonText: 'No thanks',
121
123
  confirmButtonText: 'Yes please!',
122
124
  };
@@ -113,7 +113,7 @@ describe( 'Confirm', () => {
113
113
  expect( onCancel ).toHaveBeenCalled();
114
114
  } );
115
115
 
116
- it( 'should be dismissable even if an `onCancel` callback is not provided', async () => {
116
+ it( 'should be dismissible even if an `onCancel` callback is not provided', async () => {
117
117
  const user = userEvent.setup();
118
118
 
119
119
  render(
@@ -144,7 +144,7 @@ describe( 'Confirm', () => {
144
144
 
145
145
  // Disable reason: Semantic queries can’t reach the overlay.
146
146
  // eslint-disable-next-line testing-library/no-node-access
147
- await user.click( confirmDialog.parentElement );
147
+ await user.click( confirmDialog.parentElement! );
148
148
 
149
149
  expect( confirmDialog ).not.toBeInTheDocument();
150
150
  expect( onCancel ).toHaveBeenCalled();
@@ -325,7 +325,7 @@ describe( 'Confirm', () => {
325
325
 
326
326
  // Disable reason: Semantic queries can’t reach the overlay.
327
327
  // eslint-disable-next-line testing-library/no-node-access
328
- await user.click( confirmDialog.parentElement );
328
+ await user.click( confirmDialog.parentElement! );
329
329
 
330
330
  expect( onCancel ).toHaveBeenCalled();
331
331
  } );
@@ -13,21 +13,41 @@ export type DialogInputEvent =
13
13
  | KeyboardEvent< HTMLDivElement >
14
14
  | MouseEvent< HTMLButtonElement >;
15
15
 
16
- type BaseProps = {
16
+ export type ConfirmDialogProps = {
17
+ /**
18
+ * The actual message for the dialog. It's passed as children and any valid `ReactNode` is accepted.
19
+ */
17
20
  children: ReactNode;
21
+ /**
22
+ * The callback that's called when the user confirms.
23
+ * A confirmation can happen when the `OK` button is clicked or when `Enter` is pressed.
24
+ */
18
25
  onConfirm: ( event: DialogInputEvent ) => void;
26
+ /**
27
+ * The optional custom text to display as the confirmation button's label.
28
+ */
19
29
  confirmButtonText?: string;
30
+ /**
31
+ * The optional custom text to display as the cancellation button's label.
32
+ */
20
33
  cancelButtonText?: string;
21
- };
22
-
23
- type ControlledProps = BaseProps & {
24
- onCancel: ( event: DialogInputEvent ) => void;
25
- isOpen: boolean;
26
- };
27
-
28
- type UncontrolledProps = BaseProps & {
34
+ /**
35
+ * The callback that's called when the user cancels. A cancellation can happen
36
+ * when the `Cancel` button is clicked, when the `ESC` key is pressed, or when
37
+ * a click outside of the dialog focus is detected (i.e. in the overlay).
38
+ *
39
+ * It's not required if `isOpen` is not set (uncontrolled mode), as the component
40
+ * will take care of closing itself, but you can still pass a callback if something
41
+ * must be done upon cancelling (the component will still close itself in this case).
42
+ *
43
+ * If `isOpen` is set (controlled mode), then it's required, and you need to set
44
+ * the state that defines `isOpen` to `false` as part of this callback if you want the
45
+ * dialog to close when the user cancels.
46
+ */
29
47
  onCancel?: ( event: DialogInputEvent ) => void;
30
- isOpen?: never;
48
+ /**
49
+ * Defines if the dialog is open (displayed) or closed (not rendered/displayed).
50
+ * It also implicitly toggles the controlled mode if set or the uncontrolled mode if it's not set.
51
+ */
52
+ isOpen?: boolean;
31
53
  };
32
-
33
- export type OwnProps = ControlledProps | UncontrolledProps;
@@ -42,6 +42,7 @@ import type {
42
42
  InsertPointProps,
43
43
  } from '../types';
44
44
  import type { CustomColorPickerDropdownProps } from '../../color-palette/types';
45
+ import DropdownContentWrapper from '../../dropdown/dropdown-content-wrapper';
45
46
 
46
47
  function ControlPointButton( {
47
48
  isOpen,
@@ -93,6 +94,10 @@ function GradientColorPickerDropdown( {
93
94
  ( {
94
95
  placement: 'bottom',
95
96
  offset: 8,
97
+ // Disabling resize as it would otherwise cause the popover to show
98
+ // scrollbars while dragging the color picker's handle close to the
99
+ // popover edge.
100
+ resize: false,
96
101
  } ) as const,
97
102
  []
98
103
  );
@@ -271,7 +276,7 @@ function ControlPoints( {
271
276
  />
272
277
  ) }
273
278
  renderContent={ ( { onClose } ) => (
274
- <>
279
+ <DropdownContentWrapper paddingSize="none">
275
280
  <ColorPicker
276
281
  enableAlpha={ ! disableAlpha }
277
282
  color={ point.color }
@@ -311,7 +316,7 @@ function ControlPoints( {
311
316
  </Button>
312
317
  </HStack>
313
318
  ) }
314
- </>
319
+ </DropdownContentWrapper>
315
320
  ) }
316
321
  style={ {
317
322
  left: `${ point.position }%`,
@@ -360,29 +365,31 @@ function InsertPoint( {
360
365
  />
361
366
  ) }
362
367
  renderContent={ () => (
363
- <ColorPicker
364
- enableAlpha={ ! disableAlpha }
365
- onChange={ ( color ) => {
366
- if ( ! alreadyInsertedPoint ) {
367
- onChange(
368
- addControlPoint(
369
- controlPoints,
370
- insertPosition,
371
- colord( color ).toRgbString()
372
- )
373
- );
374
- setAlreadyInsertedPoint( true );
375
- } else {
376
- onChange(
377
- updateControlPointColorByPosition(
378
- controlPoints,
379
- insertPosition,
380
- colord( color ).toRgbString()
381
- )
382
- );
383
- }
384
- } }
385
- />
368
+ <DropdownContentWrapper paddingSize="none">
369
+ <ColorPicker
370
+ enableAlpha={ ! disableAlpha }
371
+ onChange={ ( color ) => {
372
+ if ( ! alreadyInsertedPoint ) {
373
+ onChange(
374
+ addControlPoint(
375
+ controlPoints,
376
+ insertPosition,
377
+ colord( color ).toRgbString()
378
+ )
379
+ );
380
+ setAlreadyInsertedPoint( true );
381
+ } else {
382
+ onChange(
383
+ updateControlPointColorByPosition(
384
+ controlPoints,
385
+ insertPosition,
386
+ colord( color ).toRgbString()
387
+ )
388
+ );
389
+ }
390
+ } }
391
+ />
392
+ </DropdownContentWrapper>
386
393
  ) }
387
394
  style={
388
395
  insertPosition !== null
@@ -19,7 +19,8 @@ import { parseQuantityAndUnitFromRawValue } from '../unit-control';
19
19
  export function isSimpleCssValue(
20
20
  value: NonNullable< FontSizePickerProps[ 'value' ] >
21
21
  ) {
22
- const sizeRegex = /^[\d\.]+(px|em|rem|vw|vh|%)?$/i;
22
+ const sizeRegex =
23
+ /^[\d\.]+(px|em|rem|vw|vh|%|svw|lvw|dvw|svh|lvh|dvh|vi|svi|lvi|dvi|vb|svb|lvb|dvb|vmin|svmin|lvmin|dvmin|vmax|svmax|lvmax|dvmax)?$/i;
23
24
  return sizeRegex.test( String( value ) );
24
25
  }
25
26
 
@@ -12,7 +12,6 @@ const meta: Meta< typeof Heading > = {
12
12
  component: Heading,
13
13
  title: 'Components (Experimental)/Heading',
14
14
  argTypes: {
15
- adjustLineHeightForInnerControls: { control: { type: 'text' } },
16
15
  as: { control: { type: 'text' } },
17
16
  color: { control: { type: 'color' } },
18
17
  display: { control: { type: 'text' } },
@@ -20,9 +19,8 @@ const meta: Meta< typeof Heading > = {
20
19
  lineHeight: { control: { type: 'text' } },
21
20
  optimizeReadabilityFor: { control: { type: 'color' } },
22
21
  variant: {
23
- control: { type: 'radio' },
24
- options: [ 'undefined', 'muted' ],
25
- mapping: { undefined, muted: 'muted' },
22
+ control: { type: 'select' },
23
+ options: [ undefined, 'muted' ],
26
24
  },
27
25
  weight: { control: { type: 'text' } },
28
26
  },
@@ -2,7 +2,12 @@
2
2
  * External dependencies
3
3
  */
4
4
  import classnames from 'classnames';
5
- import type { ForwardedRef, KeyboardEvent, UIEvent } from 'react';
5
+ import type {
6
+ ForwardedRef,
7
+ KeyboardEvent,
8
+ MutableRefObject,
9
+ UIEvent,
10
+ } from 'react';
6
11
 
7
12
  /**
8
13
  * WordPress dependencies
@@ -15,12 +20,13 @@ import {
15
20
  useState,
16
21
  forwardRef,
17
22
  useLayoutEffect,
23
+ createContext,
24
+ useContext,
18
25
  } from '@wordpress/element';
19
26
  import {
20
27
  useInstanceId,
21
28
  useFocusReturn,
22
29
  useFocusOnMount,
23
- __experimentalUseFocusOutside as useFocusOutside,
24
30
  useConstrainedTabbing,
25
31
  useMergeRefs,
26
32
  } from '@wordpress/compose';
@@ -36,8 +42,13 @@ import Button from '../button';
36
42
  import StyleProvider from '../style-provider';
37
43
  import type { ModalProps } from './types';
38
44
 
39
- // Used to count the number of open modals.
40
- let openModalCount = 0;
45
+ // Used to track and dismiss the prior modal when another opens unless nested.
46
+ const level0Dismissers: MutableRefObject<
47
+ ModalProps[ 'onRequestClose' ] | undefined
48
+ >[] = [];
49
+ const ModalContext = createContext( level0Dismissers );
50
+
51
+ let isBodyOpenClassActive = false;
41
52
 
42
53
  function UnforwardedModal(
43
54
  props: ModalProps,
@@ -91,7 +102,6 @@ function UnforwardedModal(
91
102
  );
92
103
  const constrainedTabbingRef = useConstrainedTabbing();
93
104
  const focusReturnRef = useFocusReturn();
94
- const focusOutsideProps = useFocusOutside( onRequestClose );
95
105
  const contentRef = useRef< HTMLDivElement >( null );
96
106
  const childrenContainerRef = useRef< HTMLDivElement >( null );
97
107
 
@@ -120,26 +130,52 @@ function UnforwardedModal(
120
130
  }
121
131
  }, [ contentRef ] );
122
132
 
133
+ // Accessibly isolates/unisolates the modal.
123
134
  useEffect( () => {
124
135
  ariaHelper.modalize( ref.current );
125
136
  return () => ariaHelper.unmodalize();
126
137
  }, [] );
127
138
 
139
+ // Keeps a fresh ref for the subsequent effect.
140
+ const refOnRequestClose = useRef< ModalProps[ 'onRequestClose' ] >();
128
141
  useEffect( () => {
129
- openModalCount++;
142
+ refOnRequestClose.current = onRequestClose;
143
+ }, [ onRequestClose ] );
130
144
 
131
- if ( openModalCount === 1 ) {
132
- document.body.classList.add( bodyOpenClassName );
133
- }
145
+ // The list of `onRequestClose` callbacks of open (non-nested) Modals. Only
146
+ // one should remain open at a time and the list enables closing prior ones.
147
+ const dismissers = useContext( ModalContext );
148
+ // Used for the tracking and dismissing any nested modals.
149
+ const nestedDismissers = useRef< typeof level0Dismissers >( [] );
134
150
 
151
+ // Updates the stack tracking open modals at this level and calls
152
+ // onRequestClose for any prior and/or nested modals as applicable.
153
+ useEffect( () => {
154
+ dismissers.push( refOnRequestClose );
155
+ const [ first, second ] = dismissers;
156
+ if ( second ) first?.current?.();
157
+
158
+ const nested = nestedDismissers.current;
135
159
  return () => {
136
- openModalCount--;
160
+ nested[ 0 ]?.current?.();
161
+ dismissers.shift();
162
+ };
163
+ }, [ dismissers ] );
137
164
 
138
- if ( openModalCount === 0 ) {
165
+ const isLevel0 = dismissers === level0Dismissers;
166
+ // Adds/removes the value of bodyOpenClassName to body element.
167
+ useEffect( () => {
168
+ if ( ! isBodyOpenClassActive ) {
169
+ isBodyOpenClassActive = true;
170
+ document.body.classList.add( bodyOpenClassName );
171
+ }
172
+ return () => {
173
+ if ( isLevel0 && dismissers.length === 0 ) {
139
174
  document.body.classList.remove( bodyOpenClassName );
175
+ isBodyOpenClassActive = false;
140
176
  }
141
177
  };
142
- }, [ bodyOpenClassName ] );
178
+ }, [ bodyOpenClassName, dismissers, isLevel0 ] );
143
179
 
144
180
  // Calls the isContentScrollable callback when the Modal children container resizes.
145
181
  useLayoutEffect( () => {
@@ -200,12 +236,9 @@ function UnforwardedModal(
200
236
  onPointerUp: React.PointerEventHandler< HTMLDivElement >;
201
237
  } = {
202
238
  onPointerDown: ( event ) => {
203
- if ( event.isPrimary && event.target === event.currentTarget ) {
239
+ if ( event.target === event.currentTarget ) {
204
240
  pressTarget = event.target;
205
- // Avoids loss of focus yet also leaves `useFocusOutside`
206
- // practically useless with its only potential trigger being
207
- // programmatic focus movement. TODO opt for either removing
208
- // the hook or enhancing it such that this isn't needed.
241
+ // Avoids focus changing so that focus return works as expected.
209
242
  event.preventDefault();
210
243
  }
211
244
  },
@@ -222,7 +255,7 @@ function UnforwardedModal(
222
255
  },
223
256
  };
224
257
 
225
- return createPortal(
258
+ const modal = (
226
259
  // eslint-disable-next-line jsx-a11y/no-static-element-interactions
227
260
  <div
228
261
  ref={ useMergeRefs( [ ref, forwardedRef ] ) }
@@ -253,9 +286,6 @@ function UnforwardedModal(
253
286
  aria-labelledby={ contentLabel ? undefined : headingId }
254
287
  aria-describedby={ aria.describedby }
255
288
  tabIndex={ -1 }
256
- { ...( shouldCloseOnClickOutside
257
- ? focusOutsideProps
258
- : {} ) }
259
289
  onKeyDown={ onKeyDown }
260
290
  >
261
291
  <div
@@ -320,7 +350,13 @@ function UnforwardedModal(
320
350
  </div>
321
351
  </div>
322
352
  </StyleProvider>
323
- </div>,
353
+ </div>
354
+ );
355
+
356
+ return createPortal(
357
+ <ModalContext.Provider value={ nestedDismissers.current }>
358
+ { modal }
359
+ </ModalContext.Provider>,
324
360
  document.body
325
361
  );
326
362
  }
@@ -167,6 +167,35 @@ describe( 'Modal', () => {
167
167
  expect( onRequestClose ).not.toHaveBeenCalled();
168
168
  } );
169
169
 
170
+ it( 'should request closing of nested modal when outer modal unmounts', async () => {
171
+ const user = userEvent.setup();
172
+ const onRequestClose = jest.fn();
173
+
174
+ const RequestCloseOfNested = () => {
175
+ const [ isShown, setIsShown ] = useState( true );
176
+ return (
177
+ <>
178
+ { isShown && (
179
+ <Modal
180
+ onKeyDown={ ( { key } ) => {
181
+ if ( key === 'o' ) setIsShown( false );
182
+ } }
183
+ onRequestClose={ noop }
184
+ >
185
+ <Modal onRequestClose={ onRequestClose }>
186
+ <p>Nested modal content</p>
187
+ </Modal>
188
+ </Modal>
189
+ ) }
190
+ </>
191
+ );
192
+ };
193
+ render( <RequestCloseOfNested /> );
194
+
195
+ await user.keyboard( 'o' );
196
+ expect( onRequestClose ).toHaveBeenCalled();
197
+ } );
198
+
170
199
  it( 'should accessibly hide and show siblings including outer modals', async () => {
171
200
  const user = userEvent.setup();
172
201
 
@@ -4,7 +4,6 @@
4
4
  font-size: $default-font-size;
5
5
  background-color: $white;
6
6
  border-left: 4px solid $components-color-accent;
7
- margin: 5px 15px 2px;
8
7
  padding: 8px 12px;
9
8
  align-items: center;
10
9
 
@@ -121,6 +121,10 @@ function ColorPickerPopover< T extends Color | Gradient >( {
121
121
  () => ( {
122
122
  shift: true,
123
123
  offset: 20,
124
+ // Disabling resize as it would otherwise cause the popover to show
125
+ // scrollbars while dragging the color picker's handle close to the
126
+ // popover edge.
127
+ resize: false,
124
128
  placement: 'left-start',
125
129
  ...receivedPopoverProps,
126
130
  className: classnames(