@wordpress/block-editor 11.8.0 → 12.0.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 (216) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +15 -3
  3. package/build/components/block-info-slot-fill/index.js +47 -0
  4. package/build/components/block-info-slot-fill/index.js.map +1 -0
  5. package/build/components/block-inspector/index.js +4 -2
  6. package/build/components/block-inspector/index.js.map +1 -1
  7. package/build/components/block-list/block.native.js +3 -4
  8. package/build/components/block-list/block.native.js.map +1 -1
  9. package/build/components/block-toolbar/index.js +2 -1
  10. package/build/components/block-toolbar/index.js.map +1 -1
  11. package/build/components/block-tools/block-contextual-toolbar.js +83 -9
  12. package/build/components/block-tools/block-contextual-toolbar.js.map +1 -1
  13. package/build/components/block-tools/selected-block-popover.js +11 -28
  14. package/build/components/block-tools/selected-block-popover.js.map +1 -1
  15. package/build/components/editor-styles/index.js +4 -3
  16. package/build/components/editor-styles/index.js.map +1 -1
  17. package/build/components/font-sizes/fluid-utils.js +21 -14
  18. package/build/components/font-sizes/fluid-utils.js.map +1 -1
  19. package/build/components/global-styles/border-panel.js +2 -32
  20. package/build/components/global-styles/border-panel.js.map +1 -1
  21. package/build/components/global-styles/color-panel.js +12 -12
  22. package/build/components/global-styles/color-panel.js.map +1 -1
  23. package/build/components/global-styles/color-panel.native.js +174 -0
  24. package/build/components/global-styles/color-panel.native.js.map +1 -0
  25. package/build/components/global-styles/dimensions-panel.js +6 -6
  26. package/build/components/global-styles/dimensions-panel.js.map +1 -1
  27. package/build/components/global-styles/effects-panel.js +1 -1
  28. package/build/components/global-styles/effects-panel.js.map +1 -1
  29. package/build/components/global-styles/filters-panel.js +78 -14
  30. package/build/components/global-styles/filters-panel.js.map +1 -1
  31. package/build/components/global-styles/typography-panel.js +9 -9
  32. package/build/components/global-styles/typography-panel.js.map +1 -1
  33. package/build/components/global-styles/use-global-styles-output.js +87 -77
  34. package/build/components/global-styles/use-global-styles-output.js.map +1 -1
  35. package/build/components/index.js +7 -0
  36. package/build/components/index.js.map +1 -1
  37. package/build/components/inserter/block-types-tab.js +12 -7
  38. package/build/components/inserter/block-types-tab.js.map +1 -1
  39. package/build/components/inserter/index.js +2 -1
  40. package/build/components/inserter/index.js.map +1 -1
  41. package/build/components/inspector-controls/groups.js +2 -0
  42. package/build/components/inspector-controls/groups.js.map +1 -1
  43. package/build/components/inspector-controls-tabs/styles-tab.js +2 -0
  44. package/build/components/inspector-controls-tabs/styles-tab.js.map +1 -1
  45. package/build/components/list-view/block-select-button.js +7 -2
  46. package/build/components/list-view/block-select-button.js.map +1 -1
  47. package/build/components/list-view/block.js +12 -21
  48. package/build/components/list-view/block.js.map +1 -1
  49. package/build/components/list-view/drop-indicator.js +37 -10
  50. package/build/components/list-view/drop-indicator.js.map +1 -1
  51. package/build/components/list-view/index.js +10 -4
  52. package/build/components/list-view/index.js.map +1 -1
  53. package/build/components/list-view/leaf.js +2 -1
  54. package/build/components/list-view/leaf.js.map +1 -1
  55. package/build/components/list-view/use-block-selection.js +1 -1
  56. package/build/components/list-view/use-block-selection.js.map +1 -1
  57. package/build/components/media-replace-flow/index.js +5 -5
  58. package/build/components/media-replace-flow/index.js.map +1 -1
  59. package/build/components/navigable-toolbar/index.js +12 -4
  60. package/build/components/navigable-toolbar/index.js.map +1 -1
  61. package/build/components/off-canvas-editor/appender.js +2 -7
  62. package/build/components/off-canvas-editor/appender.js.map +1 -1
  63. package/build/hooks/duotone.js +29 -4
  64. package/build/hooks/duotone.js.map +1 -1
  65. package/build/hooks/utils.js +15 -3
  66. package/build/hooks/utils.js.map +1 -1
  67. package/build/private-apis.js +10 -1
  68. package/build/private-apis.js.map +1 -1
  69. package/build/store/actions.js +7 -0
  70. package/build/store/actions.js.map +1 -1
  71. package/build/utils/object.js +5 -5
  72. package/build/utils/object.js.map +1 -1
  73. package/build/utils/transform-styles/index.js +2 -2
  74. package/build/utils/transform-styles/index.js.map +1 -1
  75. package/build/utils/use-should-contextual-toolbar-show.js +68 -0
  76. package/build/utils/use-should-contextual-toolbar-show.js.map +1 -0
  77. package/build-module/components/block-info-slot-fill/index.js +34 -0
  78. package/build-module/components/block-info-slot-fill/index.js.map +1 -0
  79. package/build-module/components/block-inspector/index.js +3 -2
  80. package/build-module/components/block-inspector/index.js.map +1 -1
  81. package/build-module/components/block-list/block.native.js +3 -4
  82. package/build-module/components/block-list/block.native.js.map +1 -1
  83. package/build-module/components/block-toolbar/index.js +2 -1
  84. package/build-module/components/block-toolbar/index.js.map +1 -1
  85. package/build-module/components/block-tools/block-contextual-toolbar.js +79 -9
  86. package/build-module/components/block-tools/block-contextual-toolbar.js.map +1 -1
  87. package/build-module/components/block-tools/selected-block-popover.js +10 -27
  88. package/build-module/components/block-tools/selected-block-popover.js.map +1 -1
  89. package/build-module/components/editor-styles/index.js +4 -3
  90. package/build-module/components/editor-styles/index.js.map +1 -1
  91. package/build-module/components/font-sizes/fluid-utils.js +21 -14
  92. package/build-module/components/font-sizes/fluid-utils.js.map +1 -1
  93. package/build-module/components/global-styles/border-panel.js +2 -32
  94. package/build-module/components/global-styles/border-panel.js.map +1 -1
  95. package/build-module/components/global-styles/color-panel.js +13 -13
  96. package/build-module/components/global-styles/color-panel.js.map +1 -1
  97. package/build-module/components/global-styles/color-panel.native.js +150 -0
  98. package/build-module/components/global-styles/color-panel.native.js.map +1 -0
  99. package/build-module/components/global-styles/dimensions-panel.js +7 -7
  100. package/build-module/components/global-styles/dimensions-panel.js.map +1 -1
  101. package/build-module/components/global-styles/effects-panel.js +2 -2
  102. package/build-module/components/global-styles/effects-panel.js.map +1 -1
  103. package/build-module/components/global-styles/filters-panel.js +78 -16
  104. package/build-module/components/global-styles/filters-panel.js.map +1 -1
  105. package/build-module/components/global-styles/typography-panel.js +10 -10
  106. package/build-module/components/global-styles/typography-panel.js.map +1 -1
  107. package/build-module/components/global-styles/use-global-styles-output.js +87 -77
  108. package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
  109. package/build-module/components/index.js +1 -1
  110. package/build-module/components/index.js.map +1 -1
  111. package/build-module/components/inserter/block-types-tab.js +12 -6
  112. package/build-module/components/inserter/block-types-tab.js.map +1 -1
  113. package/build-module/components/inserter/index.js +2 -1
  114. package/build-module/components/inserter/index.js.map +1 -1
  115. package/build-module/components/inspector-controls/groups.js +2 -0
  116. package/build-module/components/inspector-controls/groups.js.map +1 -1
  117. package/build-module/components/inspector-controls-tabs/styles-tab.js +2 -0
  118. package/build-module/components/inspector-controls-tabs/styles-tab.js.map +1 -1
  119. package/build-module/components/list-view/block-select-button.js +7 -2
  120. package/build-module/components/list-view/block-select-button.js.map +1 -1
  121. package/build-module/components/list-view/block.js +14 -22
  122. package/build-module/components/list-view/block.js.map +1 -1
  123. package/build-module/components/list-view/drop-indicator.js +36 -10
  124. package/build-module/components/list-view/drop-indicator.js.map +1 -1
  125. package/build-module/components/list-view/index.js +11 -5
  126. package/build-module/components/list-view/index.js.map +1 -1
  127. package/build-module/components/list-view/leaf.js +2 -1
  128. package/build-module/components/list-view/leaf.js.map +1 -1
  129. package/build-module/components/list-view/use-block-selection.js +1 -1
  130. package/build-module/components/list-view/use-block-selection.js.map +1 -1
  131. package/build-module/components/media-replace-flow/index.js +5 -5
  132. package/build-module/components/media-replace-flow/index.js.map +1 -1
  133. package/build-module/components/navigable-toolbar/index.js +12 -4
  134. package/build-module/components/navigable-toolbar/index.js.map +1 -1
  135. package/build-module/components/off-canvas-editor/appender.js +1 -5
  136. package/build-module/components/off-canvas-editor/appender.js.map +1 -1
  137. package/build-module/hooks/duotone.js +28 -5
  138. package/build-module/hooks/duotone.js.map +1 -1
  139. package/build-module/hooks/utils.js +16 -4
  140. package/build-module/hooks/utils.js.map +1 -1
  141. package/build-module/private-apis.js +7 -1
  142. package/build-module/private-apis.js.map +1 -1
  143. package/build-module/store/actions.js +7 -0
  144. package/build-module/store/actions.js.map +1 -1
  145. package/build-module/utils/object.js +4 -4
  146. package/build-module/utils/object.js.map +1 -1
  147. package/build-module/utils/transform-styles/index.js +2 -2
  148. package/build-module/utils/transform-styles/index.js.map +1 -1
  149. package/build-module/utils/use-should-contextual-toolbar-show.js +56 -0
  150. package/build-module/utils/use-should-contextual-toolbar-show.js.map +1 -0
  151. package/build-style/content-rtl.css +9 -6
  152. package/build-style/content.css +9 -6
  153. package/build-style/style-rtl.css +223 -46
  154. package/build-style/style.css +223 -46
  155. package/package.json +32 -32
  156. package/src/components/block-info-slot-fill/index.js +24 -0
  157. package/src/components/block-inspector/index.js +3 -0
  158. package/src/components/block-list/block.native.js +2 -3
  159. package/src/components/block-list/content.scss +16 -15
  160. package/src/components/block-mobile-toolbar/test/block-actions-menu.native.js +9 -9
  161. package/src/components/block-mover/style.scss +10 -4
  162. package/src/components/block-mover/test/index.native.js +4 -4
  163. package/src/components/block-toolbar/index.js +4 -3
  164. package/src/components/block-toolbar/style.scss +56 -33
  165. package/src/components/block-tools/block-contextual-toolbar.js +94 -11
  166. package/src/components/block-tools/selected-block-popover.js +11 -44
  167. package/src/components/block-tools/style.scss +157 -3
  168. package/src/components/editor-styles/index.js +9 -5
  169. package/src/components/font-sizes/fluid-utils.js +31 -14
  170. package/src/components/font-sizes/test/fluid-utils.js +5 -16
  171. package/src/components/global-styles/border-panel.js +1 -30
  172. package/src/components/global-styles/color-panel.js +13 -13
  173. package/src/components/global-styles/color-panel.native.js +207 -0
  174. package/src/components/global-styles/dimensions-panel.js +17 -7
  175. package/src/components/global-styles/effects-panel.js +2 -2
  176. package/src/components/global-styles/filters-panel.js +90 -17
  177. package/src/components/global-styles/style.scss +2 -1
  178. package/src/components/global-styles/test/typography-utils.js +63 -22
  179. package/src/components/global-styles/test/use-global-styles-output.js +126 -4
  180. package/src/components/global-styles/typography-panel.js +37 -11
  181. package/src/components/global-styles/use-global-styles-output.js +64 -64
  182. package/src/components/index.js +1 -0
  183. package/src/components/inserter/block-types-tab.js +9 -6
  184. package/src/components/inserter/index.js +1 -1
  185. package/src/components/inspector-controls/groups.js +2 -0
  186. package/src/components/inspector-controls-tabs/styles-tab.js +1 -0
  187. package/src/components/list-view/block-select-button.js +6 -1
  188. package/src/components/list-view/block.js +23 -31
  189. package/src/components/list-view/drop-indicator.js +67 -22
  190. package/src/components/list-view/index.js +8 -1
  191. package/src/components/list-view/leaf.js +1 -0
  192. package/src/components/list-view/style.scss +15 -3
  193. package/src/components/list-view/use-block-selection.js +1 -1
  194. package/src/components/media-replace-flow/README.md +3 -2
  195. package/src/components/media-replace-flow/index.js +4 -5
  196. package/src/components/navigable-toolbar/index.js +12 -3
  197. package/src/components/off-canvas-editor/appender.js +1 -4
  198. package/src/components/url-popover/test/__snapshots__/index.js.snap +3 -3
  199. package/src/hooks/duotone.js +46 -25
  200. package/src/hooks/test/anchor.js +113 -0
  201. package/src/hooks/test/color.js +0 -9
  202. package/src/hooks/test/use-typography-props.js +2 -2
  203. package/src/hooks/test/utils.js +20 -101
  204. package/src/hooks/utils.js +20 -3
  205. package/src/private-apis.js +6 -0
  206. package/src/store/actions.js +7 -0
  207. package/src/utils/object.js +4 -4
  208. package/src/utils/test/object.js +21 -21
  209. package/src/utils/transform-styles/index.js +2 -2
  210. package/src/utils/use-should-contextual-toolbar-show.js +75 -0
  211. package/tsconfig.json +1 -0
  212. package/build/hooks/color-panel.native.js +0 -77
  213. package/build/hooks/color-panel.native.js.map +0 -1
  214. package/build-module/hooks/color-panel.native.js +0 -62
  215. package/build-module/hooks/color-panel.native.js.map +0 -1
  216. package/src/hooks/color-panel.native.js +0 -63
@@ -0,0 +1,207 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useSelect } from '@wordpress/data';
5
+ import { useEffect, useState, useMemo, useCallback } from '@wordpress/element';
6
+ import { __ } from '@wordpress/i18n';
7
+ import { useGlobalStyles } from '@wordpress/components';
8
+ import { store as blockEditorStore } from '@wordpress/block-editor';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import PanelColorGradientSettings from '../colors-gradients/panel-color-gradient-settings';
14
+ import { useColorsPerOrigin, useGradientsPerOrigin } from './hooks';
15
+ import { getValueFromVariable } from './utils';
16
+ import { setImmutably } from '../../utils/object';
17
+ import ContrastChecker from '../contrast-checker';
18
+ import InspectorControls from '../inspector-controls';
19
+ import {
20
+ useHasColorPanel,
21
+ useHasTextPanel,
22
+ useHasBackgroundPanel,
23
+ } from './color-panel.js';
24
+
25
+ const ColorPanel = ( {
26
+ value,
27
+ inheritedValue = value,
28
+ onChange,
29
+ settings,
30
+ } ) => {
31
+ const colors = useColorsPerOrigin( settings );
32
+ const gradients = useGradientsPerOrigin( settings );
33
+ const globalStyles = useGlobalStyles();
34
+
35
+ const [ detectedBackgroundColor, setDetectedBackgroundColor ] = useState();
36
+ const [ detectedTextColor, setDetectedTextColor ] = useState();
37
+
38
+ const { baseGlobalStyles } = useSelect( ( select ) => {
39
+ const { getSettings } = select( blockEditorStore );
40
+ return {
41
+ baseGlobalStyles:
42
+ getSettings()?.__experimentalGlobalStylesBaseStyles?.color,
43
+ };
44
+ } );
45
+
46
+ const decodeValue = ( rawValue ) =>
47
+ getValueFromVariable( { settings }, '', rawValue );
48
+ const encodeColorValue = useCallback(
49
+ ( colorValue ) => {
50
+ const allColors = colors.flatMap(
51
+ ( { colors: originColors } ) => originColors
52
+ );
53
+ const colorObject = allColors.find(
54
+ ( { color } ) => color === colorValue
55
+ );
56
+ return colorObject
57
+ ? 'var:preset|color|' + colorObject.slug
58
+ : colorValue;
59
+ },
60
+ [ colors ]
61
+ );
62
+ const encodeGradientValue = useCallback(
63
+ ( gradientValue ) => {
64
+ const allGradients = gradients.flatMap(
65
+ ( { gradients: originGradients } ) => originGradients
66
+ );
67
+ const gradientObject = allGradients.find(
68
+ ( { gradient } ) => gradient === gradientValue
69
+ );
70
+ return gradientObject
71
+ ? 'var:preset|gradient|' + gradientObject.slug
72
+ : gradientValue;
73
+ },
74
+ [ gradients ]
75
+ );
76
+
77
+ // Text Color
78
+ const showTextPanel = useHasTextPanel( settings );
79
+ const textColor = decodeValue( inheritedValue?.color?.text );
80
+ const setTextColor = useCallback(
81
+ ( newColor ) => {
82
+ onChange(
83
+ setImmutably(
84
+ value,
85
+ [ 'color', 'text' ],
86
+ encodeColorValue( newColor )
87
+ )
88
+ );
89
+ },
90
+ [ encodeColorValue, onChange, value ]
91
+ );
92
+ const resetTextColor = useCallback(
93
+ () => setTextColor( undefined ),
94
+ [ setTextColor ]
95
+ );
96
+
97
+ // BackgroundColor
98
+ const showBackgroundPanel = useHasBackgroundPanel( settings );
99
+ const backgroundColor = decodeValue( inheritedValue?.color?.background );
100
+ const gradient = decodeValue( inheritedValue?.color?.gradient );
101
+ const setBackgroundColor = useCallback(
102
+ ( newColor ) => {
103
+ const newValue = setImmutably(
104
+ value,
105
+ [ 'color', 'background' ],
106
+ encodeColorValue( newColor )
107
+ );
108
+ newValue.color.gradient = undefined;
109
+ onChange( newValue );
110
+ },
111
+ [ encodeColorValue, onChange, value ]
112
+ );
113
+ const setGradient = useCallback(
114
+ ( newGradient ) => {
115
+ const newValue = setImmutably(
116
+ value,
117
+ [ 'color', 'gradient' ],
118
+ encodeGradientValue( newGradient )
119
+ );
120
+ newValue.color.background = undefined;
121
+ onChange( newValue );
122
+ },
123
+ [ encodeGradientValue, onChange, value ]
124
+ );
125
+ const resetBackground = useCallback( () => {
126
+ const newValue = setImmutably(
127
+ value,
128
+ [ 'color', 'background' ],
129
+ undefined
130
+ );
131
+ newValue.color.gradient = undefined;
132
+ onChange( newValue );
133
+ }, [ onChange, value ] );
134
+ const currentGradients = settings?.color?.gradients;
135
+ const withoutGradientsSupport =
136
+ Array.isArray( currentGradients ) && currentGradients.length === 0;
137
+
138
+ const items = useMemo(
139
+ () =>
140
+ [
141
+ showTextPanel && {
142
+ label: __( 'Text' ),
143
+ colorValue: textColor,
144
+ onColorChange: setTextColor,
145
+ onColorCleared: resetTextColor,
146
+ },
147
+ showBackgroundPanel && {
148
+ label: __( 'Background' ),
149
+ colorValue: backgroundColor,
150
+ onColorChange: setBackgroundColor,
151
+ onColorCleared: resetBackground,
152
+ onGradientChange: ! withoutGradientsSupport
153
+ ? setGradient
154
+ : undefined,
155
+ gradientValue: gradient,
156
+ },
157
+ ].filter( Boolean ),
158
+ [
159
+ backgroundColor,
160
+ gradient,
161
+ resetBackground,
162
+ resetTextColor,
163
+ setBackgroundColor,
164
+ setGradient,
165
+ setTextColor,
166
+ showBackgroundPanel,
167
+ showTextPanel,
168
+ textColor,
169
+ withoutGradientsSupport,
170
+ ]
171
+ );
172
+
173
+ useEffect( () => {
174
+ // The following logic is used to determine current text/background colors:
175
+ // 1. The globalStyles object is queried to determine whether a color has been
176
+ // set via a block's settings.
177
+ // 2. If a block-based theme is in use and no globalStyles exist, the theme's
178
+ // default/base colors are used.
179
+ // 3. If no globalStyles exist and a theme isn't block-based, there is no way
180
+ // to determine the default text/background color and the checker won't run.
181
+ const currentDetectedTextColor =
182
+ globalStyles?.color || baseGlobalStyles?.text;
183
+ const currentDetectedBackgroundColor =
184
+ globalStyles?.backgroundColor || baseGlobalStyles?.background;
185
+
186
+ setDetectedTextColor( currentDetectedTextColor );
187
+ setDetectedBackgroundColor( currentDetectedBackgroundColor );
188
+ }, [ globalStyles, baseGlobalStyles ] );
189
+
190
+ return (
191
+ <InspectorControls>
192
+ <PanelColorGradientSettings
193
+ title={ __( 'Color' ) }
194
+ initialOpen={ false }
195
+ settings={ items }
196
+ >
197
+ <ContrastChecker
198
+ backgroundColor={ detectedBackgroundColor }
199
+ textColor={ detectedTextColor }
200
+ />
201
+ </PanelColorGradientSettings>
202
+ </InspectorControls>
203
+ );
204
+ };
205
+
206
+ export { useHasColorPanel };
207
+ export default ColorPanel;
@@ -28,7 +28,7 @@ import SpacingSizesControl from '../spacing-sizes-control';
28
28
  import HeightControl from '../height-control';
29
29
  import ChildLayoutControl from '../child-layout-control';
30
30
  import { cleanEmptyObject } from '../../hooks/utils';
31
- import { immutableSet } from '../../utils/object';
31
+ import { setImmutably } from '../../utils/object';
32
32
 
33
33
  const AXIAL_SIDES = [ 'horizontal', 'vertical' ];
34
34
 
@@ -226,7 +226,11 @@ export default function DimensionsPanel( {
226
226
  const contentSizeValue = decodeValue( inheritedValue?.layout?.contentSize );
227
227
  const setContentSizeValue = ( newValue ) => {
228
228
  onChange(
229
- immutableSet( value, [ 'layout', 'contentSize' ], newValue )
229
+ setImmutably(
230
+ value,
231
+ [ 'layout', 'contentSize' ],
232
+ newValue || undefined
233
+ )
230
234
  );
231
235
  };
232
236
  const hasUserSetContentSizeValue = () => !! value?.layout?.contentSize;
@@ -237,7 +241,13 @@ export default function DimensionsPanel( {
237
241
  useHasWideSize( settings ) && includeLayoutControls;
238
242
  const wideSizeValue = decodeValue( inheritedValue?.layout?.wideSize );
239
243
  const setWideSizeValue = ( newValue ) => {
240
- onChange( immutableSet( value, [ 'layout', 'wideSize' ], newValue ) );
244
+ onChange(
245
+ setImmutably(
246
+ value,
247
+ [ 'layout', 'wideSize' ],
248
+ newValue || undefined
249
+ )
250
+ );
241
251
  };
242
252
  const hasUserSetWideSizeValue = () => !! value?.layout?.wideSize;
243
253
  const resetWideSizeValue = () => setWideSizeValue( undefined );
@@ -254,7 +264,7 @@ export default function DimensionsPanel( {
254
264
  paddingSides.some( ( side ) => AXIAL_SIDES.includes( side ) );
255
265
  const setPaddingValues = ( newPaddingValues ) => {
256
266
  const padding = filterValuesBySides( newPaddingValues, paddingSides );
257
- onChange( immutableSet( value, [ 'spacing', 'padding' ], padding ) );
267
+ onChange( setImmutably( value, [ 'spacing', 'padding' ], padding ) );
258
268
  };
259
269
  const hasPaddingValue = () =>
260
270
  !! value?.spacing?.padding &&
@@ -274,7 +284,7 @@ export default function DimensionsPanel( {
274
284
  marginSides.some( ( side ) => AXIAL_SIDES.includes( side ) );
275
285
  const setMarginValues = ( newMarginValues ) => {
276
286
  const margin = filterValuesBySides( newMarginValues, marginSides );
277
- onChange( immutableSet( value, [ 'spacing', 'margin' ], margin ) );
287
+ onChange( setImmutably( value, [ 'spacing', 'margin' ], margin ) );
278
288
  };
279
289
  const hasMarginValue = () =>
280
290
  !! value?.spacing?.margin &&
@@ -293,7 +303,7 @@ export default function DimensionsPanel( {
293
303
  gapSides && gapSides.some( ( side ) => AXIAL_SIDES.includes( side ) );
294
304
  const setGapValue = ( newGapValue ) => {
295
305
  onChange(
296
- immutableSet( value, [ 'spacing', 'blockGap' ], newGapValue )
306
+ setImmutably( value, [ 'spacing', 'blockGap' ], newGapValue )
297
307
  );
298
308
  };
299
309
  const setGapValues = ( nextBoxGapValue ) => {
@@ -318,7 +328,7 @@ export default function DimensionsPanel( {
318
328
  const minHeightValue = decodeValue( inheritedValue?.dimensions?.minHeight );
319
329
  const setMinHeightValue = ( newValue ) => {
320
330
  onChange(
321
- immutableSet( value, [ 'dimensions', 'minHeight' ], newValue )
331
+ setImmutably( value, [ 'dimensions', 'minHeight' ], newValue )
322
332
  );
323
333
  };
324
334
  const resetMinHeightValue = () => {
@@ -27,7 +27,7 @@ import { shadow as shadowIcon, Icon, check } from '@wordpress/icons';
27
27
  * Internal dependencies
28
28
  */
29
29
  import { getValueFromVariable } from './utils';
30
- import { immutableSet } from '../../utils/object';
30
+ import { setImmutably } from '../../utils/object';
31
31
 
32
32
  export function useHasEffectsPanel( settings ) {
33
33
  const hasShadowControl = useHasShadowControl( settings );
@@ -81,7 +81,7 @@ export default function EffectsPanel( {
81
81
  const hasShadowEnabled = useHasShadowControl( settings );
82
82
  const shadow = decodeValue( inheritedValue?.shadow );
83
83
  const setShadow = ( newValue ) => {
84
- onChange( immutableSet( value, [ 'shadow' ], newValue ) );
84
+ onChange( setImmutably( value, [ 'shadow' ], newValue ) );
85
85
  };
86
86
  const hasShadow = () => !! value?.shadow;
87
87
  const resetShadow = () => setShadow( undefined );
@@ -1,11 +1,26 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
4
9
  import {
5
10
  __experimentalToolsPanel as ToolsPanel,
6
11
  __experimentalToolsPanelItem as ToolsPanelItem,
12
+ __experimentalItemGroup as ItemGroup,
13
+ __experimentalHStack as HStack,
14
+ __experimentalZStack as ZStack,
7
15
  __experimentalVStack as VStack,
16
+ __experimentalDropdownContentWrapper as DropdownContentWrapper,
17
+ Button,
18
+ ColorIndicator,
8
19
  DuotonePicker,
20
+ DuotoneSwatch,
21
+ Dropdown,
22
+ Flex,
23
+ FlexItem,
9
24
  } from '@wordpress/components';
10
25
  import { __ } from '@wordpress/i18n';
11
26
  import { useCallback, useMemo } from '@wordpress/element';
@@ -14,7 +29,7 @@ import { useCallback, useMemo } from '@wordpress/element';
14
29
  * Internal dependencies
15
30
  */
16
31
  import { getValueFromVariable } from './utils';
17
- import { immutableSet } from '../../utils/object';
32
+ import { setImmutably } from '../../utils/object';
18
33
 
19
34
  const EMPTY_ARRAY = [];
20
35
  function useMultiOriginColorPresets(
@@ -75,6 +90,29 @@ const DEFAULT_CONTROLS = {
75
90
  duotone: true,
76
91
  };
77
92
 
93
+ const popoverProps = {
94
+ placement: 'left-start',
95
+ offset: 36,
96
+ shift: true,
97
+ className: 'block-editor-duotone-control__popover',
98
+ headerTitle: __( 'Duotone' ),
99
+ };
100
+
101
+ const LabeledColorIndicator = ( { indicator, label } ) => (
102
+ <HStack justify="flex-start">
103
+ <ZStack isLayered={ false } offset={ -8 }>
104
+ <Flex expanded={ false }>
105
+ { indicator === 'unset' || ! indicator ? (
106
+ <ColorIndicator className="block-editor-duotone-control__unset-indicator" />
107
+ ) : (
108
+ <DuotoneSwatch values={ indicator } />
109
+ ) }
110
+ </Flex>
111
+ </ZStack>
112
+ <FlexItem title={ label }>{ label }</FlexItem>
113
+ </HStack>
114
+ );
115
+
78
116
  export default function FiltersPanel( {
79
117
  as: Wrapper = FiltersToolsPanel,
80
118
  value,
@@ -105,11 +143,16 @@ export default function FiltersPanel( {
105
143
  const settedValue = duotonePreset
106
144
  ? `var:preset|duotone|${ duotonePreset.slug }`
107
145
  : newValue;
108
- onChange( immutableSet( value, [ 'filter', 'duotone' ], settedValue ) );
146
+ onChange( setImmutably( value, [ 'filter', 'duotone' ], settedValue ) );
109
147
  };
110
148
  const hasDuotone = () => !! value?.filter?.duotone;
111
149
  const resetDuotone = () => setDuotone( undefined );
112
150
 
151
+ const disableCustomColors = ! settings?.color?.custom;
152
+ const disableCustomDuotone =
153
+ ! settings?.color?.customDuotone ||
154
+ ( colorPalette?.length === 0 && disableCustomColors );
155
+
113
156
  const resetAllFilter = useCallback( ( previousValue ) => {
114
157
  return {
115
158
  ...previousValue,
@@ -135,21 +178,51 @@ export default function FiltersPanel( {
135
178
  isShownByDefault={ defaultControls.duotone }
136
179
  panelId={ panelId }
137
180
  >
138
- <VStack>
139
- <p>
140
- { __(
141
- 'Create a two-tone color effect without losing your original image.'
142
- ) }
143
- </p>
144
- <DuotonePicker
145
- colorPalette={ colorPalette }
146
- duotonePalette={ duotonePalette }
147
- disableCustomColors={ true }
148
- disableCustomDuotone={ true }
149
- value={ duotone }
150
- onChange={ setDuotone }
151
- />
152
- </VStack>
181
+ <Dropdown
182
+ popoverProps={ popoverProps }
183
+ className="block-editor-global-styles-filters-panel__dropdown"
184
+ renderToggle={ ( { onToggle, isOpen } ) => {
185
+ const toggleProps = {
186
+ onClick: onToggle,
187
+ className: classnames( { 'is-open': isOpen } ),
188
+ 'aria-expanded': isOpen,
189
+ };
190
+
191
+ return (
192
+ <ItemGroup isBordered isSeparated>
193
+ <Button { ...toggleProps }>
194
+ <LabeledColorIndicator
195
+ indicator={ duotone }
196
+ label={ __( 'Duotone' ) }
197
+ />
198
+ </Button>
199
+ </ItemGroup>
200
+ );
201
+ } }
202
+ renderContent={ () => (
203
+ <DropdownContentWrapper paddingSize="medium">
204
+ <VStack>
205
+ <p>
206
+ { __(
207
+ 'Create a two-tone color effect without losing your original image.'
208
+ ) }
209
+ </p>
210
+ <DuotonePicker
211
+ colorPalette={ colorPalette }
212
+ duotonePalette={ duotonePalette }
213
+ disableCustomColors={
214
+ disableCustomColors
215
+ }
216
+ disableCustomDuotone={
217
+ disableCustomDuotone
218
+ }
219
+ value={ duotone }
220
+ onChange={ setDuotone }
221
+ />
222
+ </VStack>
223
+ </DropdownContentWrapper>
224
+ ) }
225
+ />
153
226
  </ToolsPanelItem>
154
227
  ) }
155
228
  </Wrapper>
@@ -6,11 +6,12 @@
6
6
  width: 230px;
7
7
  }
8
8
 
9
+ .block-editor-global-styles-filters-panel__dropdown,
9
10
  .block-editor-global-styles-effects-panel__shadow-dropdown {
10
11
  display: block;
11
12
  padding: 0;
12
13
 
13
- > button {
14
+ button {
14
15
  width: 100%;
15
16
  padding: $grid-unit-10;
16
17
 
@@ -89,11 +89,11 @@ describe( 'typography utils', () => {
89
89
  fluid: true,
90
90
  },
91
91
  expected:
92
- 'clamp(1.313rem, 1.313rem + ((1vw - 0.48rem) * 0.84), 1.75rem)',
92
+ 'clamp(1.119rem, 1.119rem + ((1vw - 0.2rem) * 0.789), 1.75rem)',
93
93
  },
94
94
 
95
95
  {
96
- message: 'should return clamp value with eem min and max units',
96
+ message: 'should return clamp value with em min and max units',
97
97
  preset: {
98
98
  size: '1.75em',
99
99
  },
@@ -101,19 +101,19 @@ describe( 'typography utils', () => {
101
101
  fluid: true,
102
102
  },
103
103
  expected:
104
- 'clamp(1.313em, 1.313rem + ((1vw - 0.48em) * 0.84), 1.75em)',
104
+ 'clamp(1.119em, 1.119rem + ((1vw - 0.2em) * 0.789), 1.75em)',
105
105
  },
106
106
 
107
107
  {
108
108
  message: 'should return clamp value for floats',
109
109
  preset: {
110
- size: '100.175px',
110
+ size: '70.175px',
111
111
  },
112
112
  typographySettings: {
113
113
  fluid: true,
114
114
  },
115
115
  expected:
116
- 'clamp(75.131px, 4.696rem + ((1vw - 7.68px) * 3.01), 100.175px)',
116
+ 'clamp(37.897px, 2.369rem + ((1vw - 3.2px) * 2.522), 70.175px)',
117
117
  },
118
118
 
119
119
  {
@@ -127,20 +127,20 @@ describe( 'typography utils', () => {
127
127
  fluid: true,
128
128
  },
129
129
  expected:
130
- 'clamp(24.75px, 1.547rem + ((1vw - 7.68px) * 0.992), 33px)',
130
+ 'clamp(20.515px, 1.282rem + ((1vw - 3.2px) * 0.975), 33px)',
131
131
  },
132
132
 
133
133
  {
134
134
  message: 'should coerce float to `px` and returns clamp value',
135
135
  preset: {
136
- size: 100.23,
136
+ size: 70.175,
137
137
  fluid: true,
138
138
  },
139
139
  typographySettings: {
140
140
  fluid: true,
141
141
  },
142
142
  expected:
143
- 'clamp(75.173px, 4.698rem + ((1vw - 7.68px) * 3.012), 100.23px)',
143
+ 'clamp(37.897px, 2.369rem + ((1vw - 3.2px) * 2.522), 70.175px)',
144
144
  },
145
145
 
146
146
  {
@@ -154,7 +154,7 @@ describe( 'typography utils', () => {
154
154
  fluid: true,
155
155
  },
156
156
  expected:
157
- 'clamp(21px, 1.313rem + ((1vw - 7.68px) * 0.841), 28px)',
157
+ 'clamp(17.905px, 1.119rem + ((1vw - 3.2px) * 0.789), 28px)',
158
158
  },
159
159
 
160
160
  {
@@ -167,7 +167,7 @@ describe( 'typography utils', () => {
167
167
  fluid: true,
168
168
  },
169
169
  expected:
170
- 'clamp(21px, 1.313rem + ((1vw - 7.68px) * 0.841), 28px)',
170
+ 'clamp(17.905px, 1.119rem + ((1vw - 3.2px) * 0.789), 28px)',
171
171
  },
172
172
 
173
173
  {
@@ -183,8 +183,7 @@ describe( 'typography utils', () => {
183
183
  typographySettings: {
184
184
  fluid: true,
185
185
  },
186
- expected:
187
- 'clamp(5rem, 5rem + ((1vw - 0.48rem) * -5.769), 32px)',
186
+ expected: 'clamp(5rem, 5rem + ((1vw - 0.2rem) * -3.75), 32px)',
188
187
  },
189
188
 
190
189
  {
@@ -240,14 +239,14 @@ describe( 'typography utils', () => {
240
239
  fluid: true,
241
240
  },
242
241
  expected:
243
- 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 93.75), 50rem)',
242
+ 'clamp(20px, 1.25rem + ((1vw - 3.2px) * 60.938), 50rem)',
244
243
  },
245
244
 
246
245
  {
247
246
  message:
248
247
  'should return clamp value where no fluid max size is set',
249
248
  preset: {
250
- size: '28px',
249
+ size: '50px',
251
250
  fluid: {
252
251
  min: '2.6rem',
253
252
  },
@@ -256,7 +255,7 @@ describe( 'typography utils', () => {
256
255
  fluid: true,
257
256
  },
258
257
  expected:
259
- 'clamp(2.6rem, 2.6rem + ((1vw - 0.48rem) * -1.635), 28px)',
258
+ 'clamp(2.6rem, 2.6rem + ((1vw - 0.2rem) * 0.656), 50px)',
260
259
  },
261
260
 
262
261
  {
@@ -272,7 +271,7 @@ describe( 'typography utils', () => {
272
271
  fluid: true,
273
272
  },
274
273
  expected:
275
- 'clamp(21px, 1.313rem + ((1vw - 7.68px) * 7.091), 80px)',
274
+ 'clamp(17.905px, 1.119rem + ((1vw - 3.2px) * 4.851), 80px)',
276
275
  },
277
276
 
278
277
  {
@@ -289,7 +288,7 @@ describe( 'typography utils', () => {
289
288
  fluid: true,
290
289
  },
291
290
  expected:
292
- 'clamp(0.5rem, 0.5rem + ((1vw - 0.48rem) * 8.654), 5rem)',
291
+ 'clamp(0.5rem, 0.5rem + ((1vw - 0.2rem) * 5.625), 5rem)',
293
292
  },
294
293
 
295
294
  {
@@ -305,7 +304,7 @@ describe( 'typography utils', () => {
305
304
  fluid: true,
306
305
  },
307
306
  expected:
308
- 'clamp(12px, 0.75rem + ((1vw - 7.68px) * 0.962), 20px)',
307
+ 'clamp(12px, 0.75rem + ((1vw - 3.2px) * 0.625), 20px)',
309
308
  },
310
309
 
311
310
  {
@@ -321,7 +320,7 @@ describe( 'typography utils', () => {
321
320
  fluid: true,
322
321
  },
323
322
  expected:
324
- 'clamp(0.875rem, 0.875rem + ((1vw - 0.48rem) * 36.779), 20rem)',
323
+ 'clamp(0.875rem, 0.875rem + ((1vw - 0.2rem) * 23.906), 20rem)',
325
324
  },
326
325
 
327
326
  {
@@ -337,7 +336,7 @@ describe( 'typography utils', () => {
337
336
  typographySettings: {
338
337
  fluid: true,
339
338
  },
340
- expected: 'clamp(30px, 1.875rem + ((1vw - 7.68px) * 1), 30px)',
339
+ expected: 'clamp(30px, 1.875rem + ((1vw - 3.2px) * 1), 30px)',
341
340
  },
342
341
 
343
342
  {
@@ -352,7 +351,7 @@ describe( 'typography utils', () => {
352
351
  },
353
352
  },
354
353
  expected:
355
- 'clamp(14px, 0.875rem + ((1vw - 7.68px) * 0.12), 15px)',
354
+ 'clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.078), 15px)',
356
355
  },
357
356
 
358
357
  // Equivalent custom config PHP unit tests in `test_should_covert_font_sizes_to_fluid_values()`.
@@ -366,7 +365,7 @@ describe( 'typography utils', () => {
366
365
  minFontSize: '16px',
367
366
  },
368
367
  },
369
- expected: 'clamp(16px, 1rem + ((1vw - 7.68px) * 0.12), 17px)',
368
+ expected: 'clamp(16px, 1rem + ((1vw - 3.2px) * 0.078), 17px)',
370
369
  },
371
370
 
372
371
  {
@@ -382,6 +381,48 @@ describe( 'typography utils', () => {
382
381
  },
383
382
  expected: '15px',
384
383
  },
384
+
385
+ {
386
+ message:
387
+ 'should apply scaled min font size for em values when custom min font size is not set',
388
+ preset: {
389
+ size: '12rem',
390
+ },
391
+ typographySettings: {
392
+ fluid: true,
393
+ },
394
+ expected:
395
+ 'clamp(5.174rem, 5.174rem + ((1vw - 0.2rem) * 8.533), 12rem)',
396
+ },
397
+
398
+ {
399
+ message:
400
+ 'should apply scaled min font size for px values when custom min font size is not set',
401
+ preset: {
402
+ size: '200px',
403
+ },
404
+ typographySettings: {
405
+ fluid: true,
406
+ },
407
+ expected:
408
+ 'clamp(85.342px, 5.334rem + ((1vw - 3.2px) * 8.958), 200px)',
409
+ },
410
+
411
+ {
412
+ message:
413
+ 'should not apply scaled min font size for minimum font size when custom min font size is set',
414
+ preset: {
415
+ size: '200px',
416
+ fluid: {
417
+ min: '100px',
418
+ },
419
+ },
420
+ typographySettings: {
421
+ fluid: true,
422
+ },
423
+ expected:
424
+ 'clamp(100px, 6.25rem + ((1vw - 3.2px) * 7.813), 200px)',
425
+ },
385
426
  ].forEach( ( { message, preset, typographySettings, expected } ) => {
386
427
  it( `${ message }`, () => {
387
428
  expect(