@wordpress/block-editor 10.0.4 → 10.0.6

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 (50) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +40 -0
  3. package/build/components/block-inspector/index.js +3 -4
  4. package/build/components/block-inspector/index.js.map +1 -1
  5. package/build/components/block-list/block.js +72 -14
  6. package/build/components/block-list/block.js.map +1 -1
  7. package/build/components/font-sizes/fluid-utils.js +208 -0
  8. package/build/components/font-sizes/fluid-utils.js.map +1 -0
  9. package/build/components/font-sizes/index.js +8 -0
  10. package/build/components/font-sizes/index.js.map +1 -1
  11. package/build/components/inserter/search-items.js +2 -17
  12. package/build/components/inserter/search-items.js.map +1 -1
  13. package/build/hooks/font-size.js +60 -0
  14. package/build/hooks/font-size.js.map +1 -1
  15. package/build/hooks/margin.js +4 -4
  16. package/build/hooks/margin.js.map +1 -1
  17. package/build/hooks/use-typography-props.js +17 -3
  18. package/build/hooks/use-typography-props.js.map +1 -1
  19. package/build-module/components/block-inspector/index.js +3 -4
  20. package/build-module/components/block-inspector/index.js.map +1 -1
  21. package/build-module/components/block-list/block.js +72 -14
  22. package/build-module/components/block-list/block.js.map +1 -1
  23. package/build-module/components/font-sizes/fluid-utils.js +197 -0
  24. package/build-module/components/font-sizes/fluid-utils.js.map +1 -0
  25. package/build-module/components/font-sizes/index.js +1 -0
  26. package/build-module/components/font-sizes/index.js.map +1 -1
  27. package/build-module/components/inserter/search-items.js +3 -17
  28. package/build-module/components/inserter/search-items.js.map +1 -1
  29. package/build-module/hooks/font-size.js +59 -1
  30. package/build-module/hooks/font-size.js.map +1 -1
  31. package/build-module/hooks/margin.js +4 -4
  32. package/build-module/hooks/margin.js.map +1 -1
  33. package/build-module/hooks/use-typography-props.js +17 -4
  34. package/build-module/hooks/use-typography-props.js.map +1 -1
  35. package/build-style/style-rtl.css +61 -106
  36. package/build-style/style.css +61 -106
  37. package/package.json +3 -4
  38. package/src/components/block-inspector/index.js +4 -7
  39. package/src/components/block-list/block.js +111 -7
  40. package/src/components/block-list/style.scss +85 -133
  41. package/src/components/button-block-appender/style.scss +3 -1
  42. package/src/components/font-sizes/fluid-utils.js +221 -0
  43. package/src/components/font-sizes/index.js +1 -0
  44. package/src/components/font-sizes/test/fluid-utils.js +168 -0
  45. package/src/components/inserter/search-items.js +3 -15
  46. package/src/components/inserter/test/search-items.js +4 -0
  47. package/src/hooks/font-size.js +75 -0
  48. package/src/hooks/margin.js +4 -4
  49. package/src/hooks/test/use-typography-props.js +22 -0
  50. package/src/hooks/use-typography-props.js +18 -3
@@ -0,0 +1,221 @@
1
+ /**
2
+ * The fluid utilities must match the backend equivalent.
3
+ * See: gutenberg_get_typography_font_size_value() in lib/block-supports/typography.php
4
+ * ---------------------------------------------------------------
5
+ */
6
+
7
+ // Defaults.
8
+ const DEFAULT_MAXIMUM_VIEWPORT_WIDTH = '1600px';
9
+ const DEFAULT_MINIMUM_VIEWPORT_WIDTH = '768px';
10
+ const DEFAULT_SCALE_FACTOR = 1;
11
+ const DEFAULT_MINIMUM_FONT_SIZE_FACTOR = 0.75;
12
+ const DEFAULT_MAXIMUM_FONT_SIZE_FACTOR = 1.5;
13
+
14
+ /**
15
+ * Computes a fluid font-size value that uses clamp(). A minimum and maxinmum
16
+ * font size OR a single font size can be specified.
17
+ *
18
+ * If a single font size is specified, it is scaled up and down by
19
+ * minimumFontSizeFactor and maximumFontSizeFactor to arrive at the minimum and
20
+ * maximum sizes.
21
+ *
22
+ * @example
23
+ * ```js
24
+ * // Calculate fluid font-size value from a minimum and maximum value.
25
+ * const fontSize = getComputedFluidTypographyValue( {
26
+ * minimumFontSize: '20px',
27
+ * maximumFontSize: '45px'
28
+ * } );
29
+ * // Calculate fluid font-size value from a single font size.
30
+ * const fontSize = getComputedFluidTypographyValue( {
31
+ * fontSize: '30px',
32
+ * } );
33
+ * ```
34
+ *
35
+ * @param {Object} args
36
+ * @param {?string} args.minimumViewPortWidth Minimum viewport size from which type will have fluidity. Optional if fontSize is specified.
37
+ * @param {?string} args.maximumViewPortWidth Maximum size up to which type will have fluidity. Optional if fontSize is specified.
38
+ * @param {string|number} [args.fontSize] Size to derive maximumFontSize and minimumFontSize from, if necessary. Optional if minimumFontSize and maximumFontSize are specified.
39
+ * @param {?string} args.maximumFontSize Maximum font size for any clamp() calculation. Optional.
40
+ * @param {?string} args.minimumFontSize Minimum font size for any clamp() calculation. Optional.
41
+ * @param {?number} args.scaleFactor A scale factor to determine how fast a font scales within boundaries. Optional.
42
+ * @param {?number} args.minimumFontSizeFactor How much to scale defaultFontSize by to derive minimumFontSize. Optional.
43
+ * @param {?number} args.maximumFontSizeFactor How much to scale defaultFontSize by to derive maximumFontSize. Optional.
44
+ *
45
+ * @return {string|null} A font-size value using clamp().
46
+ */
47
+ export function getComputedFluidTypographyValue( {
48
+ minimumFontSize,
49
+ maximumFontSize,
50
+ fontSize,
51
+ minimumViewPortWidth = DEFAULT_MINIMUM_VIEWPORT_WIDTH,
52
+ maximumViewPortWidth = DEFAULT_MAXIMUM_VIEWPORT_WIDTH,
53
+ scaleFactor = DEFAULT_SCALE_FACTOR,
54
+ minimumFontSizeFactor = DEFAULT_MINIMUM_FONT_SIZE_FACTOR,
55
+ maximumFontSizeFactor = DEFAULT_MAXIMUM_FONT_SIZE_FACTOR,
56
+ } ) {
57
+ // Calculate missing minimumFontSize and maximumFontSize from
58
+ // defaultFontSize if provided.
59
+ if ( fontSize && ( ! minimumFontSize || ! maximumFontSize ) ) {
60
+ // Parse default font size.
61
+ const fontSizeParsed = getTypographyValueAndUnit( fontSize );
62
+
63
+ // Protect against invalid units.
64
+ if ( ! fontSizeParsed?.unit ) {
65
+ return null;
66
+ }
67
+
68
+ // If no minimumFontSize is provided, derive using min scale factor.
69
+ if ( ! minimumFontSize ) {
70
+ minimumFontSize =
71
+ fontSizeParsed.value * minimumFontSizeFactor +
72
+ fontSizeParsed.unit;
73
+ }
74
+
75
+ // If no maximumFontSize is provided, derive using max scale factor.
76
+ if ( ! maximumFontSize ) {
77
+ maximumFontSize =
78
+ fontSizeParsed.value * maximumFontSizeFactor +
79
+ fontSizeParsed.unit;
80
+ }
81
+ }
82
+
83
+ // Return early if one of the provided inputs is not provided.
84
+ if ( ! minimumFontSize || ! maximumFontSize ) {
85
+ return null;
86
+ }
87
+
88
+ // Grab the minimum font size and normalize it in order to use the value for calculations.
89
+ const minimumFontSizeParsed = getTypographyValueAndUnit( minimumFontSize );
90
+
91
+ // We get a 'preferred' unit to keep units consistent when calculating,
92
+ // otherwise the result will not be accurate.
93
+ const fontSizeUnit = minimumFontSizeParsed?.unit || 'rem';
94
+
95
+ // Grab the maximum font size and normalize it in order to use the value for calculations.
96
+ const maximumFontSizeParsed = getTypographyValueAndUnit( maximumFontSize, {
97
+ coerceTo: fontSizeUnit,
98
+ } );
99
+
100
+ // Protect against unsupported units.
101
+ if ( ! minimumFontSizeParsed || ! maximumFontSizeParsed ) {
102
+ return null;
103
+ }
104
+
105
+ // Use rem for accessible fluid target font scaling.
106
+ const minimumFontSizeRem = getTypographyValueAndUnit( minimumFontSize, {
107
+ coerceTo: 'rem',
108
+ } );
109
+
110
+ // Viewport widths defined for fluid typography. Normalize units
111
+ const maximumViewPortWidthParsed = getTypographyValueAndUnit(
112
+ maximumViewPortWidth,
113
+ { coerceTo: fontSizeUnit }
114
+ );
115
+ const minumumViewPortWidthParsed = getTypographyValueAndUnit(
116
+ minimumViewPortWidth,
117
+ { coerceTo: fontSizeUnit }
118
+ );
119
+
120
+ // Protect against unsupported units.
121
+ if (
122
+ ! maximumViewPortWidthParsed ||
123
+ ! minumumViewPortWidthParsed ||
124
+ ! minimumFontSizeRem
125
+ ) {
126
+ return null;
127
+ }
128
+
129
+ // Build CSS rule.
130
+ // Borrowed from https://websemantics.uk/tools/responsive-font-calculator/.
131
+ const minViewPortWidthOffsetValue = roundToPrecision(
132
+ minumumViewPortWidthParsed.value / 100,
133
+ 3
134
+ );
135
+
136
+ const viewPortWidthOffset = minViewPortWidthOffsetValue + fontSizeUnit;
137
+ let linearFactor =
138
+ 100 *
139
+ ( ( maximumFontSizeParsed.value - minimumFontSizeParsed.value ) /
140
+ ( maximumViewPortWidthParsed.value -
141
+ minumumViewPortWidthParsed.value ) );
142
+ linearFactor = roundToPrecision( linearFactor, 3 ) || 1;
143
+ const linearFactorScaled = linearFactor * scaleFactor;
144
+ const fluidTargetFontSize = `${ minimumFontSizeRem.value }${ minimumFontSizeRem.unit } + ((1vw - ${ viewPortWidthOffset }) * ${ linearFactorScaled })`;
145
+
146
+ return `clamp(${ minimumFontSize }, ${ fluidTargetFontSize }, ${ maximumFontSize })`;
147
+ }
148
+
149
+ /**
150
+ * Internal method that checks a string for a unit and value and returns an array consisting of `'value'` and `'unit'`, e.g., [ '42', 'rem' ].
151
+ * A raw font size of `value + unit` is expected. If the value is an integer, it will convert to `value + 'px'`.
152
+ *
153
+ * @param {string|number} rawValue Raw size value from theme.json.
154
+ * @param {Object|undefined} options Calculation options.
155
+ *
156
+ * @return {{ unit: string, value: number }|null} An object consisting of `'value'` and `'unit'` properties.
157
+ */
158
+ export function getTypographyValueAndUnit( rawValue, options = {} ) {
159
+ if ( typeof rawValue !== 'string' && typeof rawValue !== 'number' ) {
160
+ return null;
161
+ }
162
+
163
+ // Converts numeric values to pixel values by default.
164
+ if ( isFinite( rawValue ) ) {
165
+ rawValue = `${ rawValue }px`;
166
+ }
167
+
168
+ const { coerceTo, rootSizeValue, acceptableUnits } = {
169
+ coerceTo: '',
170
+ // Default browser font size. Later we could inject some JS to compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`.
171
+ rootSizeValue: 16,
172
+ acceptableUnits: [ 'rem', 'px', 'em' ],
173
+ ...options,
174
+ };
175
+
176
+ const acceptableUnitsGroup = acceptableUnits?.join( '|' );
177
+ const regexUnits = new RegExp(
178
+ `^(\\d*\\.?\\d+)(${ acceptableUnitsGroup }){1,1}$`
179
+ );
180
+
181
+ const matches = rawValue.match( regexUnits );
182
+
183
+ // We need a number value and a unit.
184
+ if ( ! matches || matches.length < 3 ) {
185
+ return null;
186
+ }
187
+
188
+ let [ , value, unit ] = matches;
189
+
190
+ let returnValue = parseFloat( value );
191
+
192
+ if ( 'px' === coerceTo && ( 'em' === unit || 'rem' === unit ) ) {
193
+ returnValue = returnValue * rootSizeValue;
194
+ unit = coerceTo;
195
+ }
196
+
197
+ if ( 'px' === unit && ( 'em' === coerceTo || 'rem' === coerceTo ) ) {
198
+ returnValue = returnValue / rootSizeValue;
199
+ unit = coerceTo;
200
+ }
201
+
202
+ return {
203
+ value: returnValue,
204
+ unit,
205
+ };
206
+ }
207
+
208
+ /**
209
+ * Returns a value rounded to defined precision.
210
+ * Returns `undefined` if the value is not a valid finite number.
211
+ *
212
+ * @param {number} value Raw value.
213
+ * @param {number} digits The number of digits to appear after the decimal point
214
+ *
215
+ * @return {number|undefined} Value rounded to standard precision.
216
+ */
217
+ export function roundToPrecision( value, digits = 3 ) {
218
+ return Number.isFinite( value )
219
+ ? parseFloat( value.toFixed( digits ) )
220
+ : undefined;
221
+ }
@@ -3,5 +3,6 @@ export {
3
3
  getFontSizeClass,
4
4
  getFontSizeObjectByValue,
5
5
  } from './utils';
6
+ export { getComputedFluidTypographyValue } from './fluid-utils';
6
7
  export { default as FontSizePicker } from './font-size-picker';
7
8
  export { default as withFontSizes } from './with-font-sizes';
@@ -0,0 +1,168 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { logged } from '@wordpress/deprecated';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import {
10
+ getComputedFluidTypographyValue,
11
+ getTypographyValueAndUnit,
12
+ } from '../fluid-utils';
13
+
14
+ describe( 'getComputedFluidTypographyValue()', () => {
15
+ afterEach( () => {
16
+ for ( const key in logged ) {
17
+ delete logged[ key ];
18
+ }
19
+ } );
20
+
21
+ it( 'should return a fluid font size when given a min and max font size', () => {
22
+ const fluidTypographyValues = getComputedFluidTypographyValue( {
23
+ minimumFontSize: '20px',
24
+ maximumFontSize: '45px',
25
+ } );
26
+ expect( fluidTypographyValues ).toBe(
27
+ 'clamp(20px, 1.25rem + ((1vw - 7.68px) * 3.005), 45px)'
28
+ );
29
+ } );
30
+
31
+ it( 'should return a fluid font size when given a font size', () => {
32
+ const fluidTypographyValues = getComputedFluidTypographyValue( {
33
+ fontSize: '30px',
34
+ } );
35
+ expect( fluidTypographyValues ).toBe(
36
+ 'clamp(22.5px, 1.40625rem + ((1vw - 7.68px) * 2.704), 45px)'
37
+ );
38
+ } );
39
+
40
+ it( 'should return a fluid font size based on px when given a numerical font size', () => {
41
+ const fluidTypographyValues = getComputedFluidTypographyValue( {
42
+ fontSize: '30px',
43
+ } );
44
+ expect( fluidTypographyValues ).toBe(
45
+ 'clamp(22.5px, 1.40625rem + ((1vw - 7.68px) * 2.704), 45px)'
46
+ );
47
+ } );
48
+
49
+ it( 'should return a fluid font size when given a min and max viewport width', () => {
50
+ const fluidTypographyValues = getComputedFluidTypographyValue( {
51
+ fontSize: '30px',
52
+ minimumViewPortWidth: '500px',
53
+ maximumViewPortWidth: '1000px',
54
+ } );
55
+ expect( fluidTypographyValues ).toBe(
56
+ 'clamp(22.5px, 1.40625rem + ((1vw - 5px) * 4.5), 45px)'
57
+ );
58
+ } );
59
+
60
+ it( 'should return a fluid font size when given a scale factor', () => {
61
+ const fluidTypographyValues = getComputedFluidTypographyValue( {
62
+ fontSize: '30px',
63
+ scaleFactor: '2',
64
+ } );
65
+ expect( fluidTypographyValues ).toBe(
66
+ 'clamp(22.5px, 1.40625rem + ((1vw - 7.68px) * 5.408), 45px)'
67
+ );
68
+ } );
69
+
70
+ it( 'should return a fluid font size when given a min and max font size factor', () => {
71
+ const fluidTypographyValues = getComputedFluidTypographyValue( {
72
+ fontSize: '30px',
73
+ minimumFontSizeFactor: '0.5',
74
+ maximumFontSizeFactor: '2',
75
+ } );
76
+ expect( fluidTypographyValues ).toBe(
77
+ 'clamp(15px, 0.9375rem + ((1vw - 7.68px) * 5.409), 60px)'
78
+ );
79
+ } );
80
+
81
+ describe( 'getTypographyValueAndUnit', () => {
82
+ it( 'should return the expected return values', () => {
83
+ [
84
+ {
85
+ value: null,
86
+ expected: null,
87
+ },
88
+ {
89
+ value: false,
90
+ expected: null,
91
+ },
92
+ {
93
+ value: true,
94
+ expected: null,
95
+ },
96
+ {
97
+ value: [ '10' ],
98
+ expected: null,
99
+ },
100
+ {
101
+ value: '10vh',
102
+ expected: null,
103
+ },
104
+ {
105
+ value: 'calc(2 * 10px)',
106
+ expected: null,
107
+ },
108
+ {
109
+ value: 'clamp(15px, 0.9375rem + ((1vw - 7.68px) * 5.409), 60px)',
110
+ expected: null,
111
+ },
112
+ {
113
+ value: '10',
114
+ expected: {
115
+ value: 10,
116
+ unit: 'px',
117
+ },
118
+ },
119
+ {
120
+ value: 11,
121
+ expected: {
122
+ value: 11,
123
+ unit: 'px',
124
+ },
125
+ },
126
+ {
127
+ value: 11.234,
128
+ expected: {
129
+ value: 11.234,
130
+ unit: 'px',
131
+ },
132
+ },
133
+ {
134
+ value: '12rem',
135
+ expected: {
136
+ value: 12,
137
+ unit: 'rem',
138
+ },
139
+ },
140
+ {
141
+ value: '12px',
142
+ expected: {
143
+ value: 12,
144
+ unit: 'px',
145
+ },
146
+ },
147
+ {
148
+ value: '12em',
149
+ expected: {
150
+ value: 12,
151
+ unit: 'em',
152
+ },
153
+ },
154
+ {
155
+ value: '12.74em',
156
+ expected: {
157
+ value: 12.74,
158
+ unit: 'em',
159
+ },
160
+ },
161
+ ].forEach( ( { value, expected } ) => {
162
+ expect( getTypographyValueAndUnit( value ) ).toEqual(
163
+ expected
164
+ );
165
+ } );
166
+ } );
167
+ } );
168
+ } );
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { noCase } from 'change-case';
5
4
  import removeAccents from 'remove-accents';
6
- import { find } from 'lodash';
5
+ import { find, words } from 'lodash';
7
6
 
8
7
  // Default search helpers.
9
8
  const defaultGetName = ( item ) => item.name || '';
@@ -36,17 +35,6 @@ function normalizeSearchInput( input = '' ) {
36
35
  return input;
37
36
  }
38
37
 
39
- /**
40
- * Extracts words from an input string.
41
- *
42
- * @param {string} input The input string.
43
- *
44
- * @return {Array} Words, extracted from the input string.
45
- */
46
- function extractWords( input = '' ) {
47
- return noCase( input ).split( ' ' ).filter( Boolean );
48
- }
49
-
50
38
  /**
51
39
  * Converts the search term into a list of normalized terms.
52
40
  *
@@ -55,7 +43,7 @@ function extractWords( input = '' ) {
55
43
  * @return {string[]} The normalized list of search terms.
56
44
  */
57
45
  export const getNormalizedSearchTerms = ( input = '' ) => {
58
- return extractWords( normalizeSearchInput( input ) );
46
+ return words( normalizeSearchInput( input ) );
59
47
  };
60
48
 
61
49
  const removeMatchingTerms = ( unmatchedTerms, unprocessedTerms ) => {
@@ -162,7 +150,7 @@ export function getItemSearchRank( item, searchTerm, config = {} ) {
162
150
  category,
163
151
  collection,
164
152
  ].join( ' ' );
165
- const normalizedSearchTerms = extractWords( normalizedSearchInput );
153
+ const normalizedSearchTerms = words( normalizedSearchInput );
166
154
  const unmatchedTerms = removeMatchingTerms(
167
155
  normalizedSearchTerms,
168
156
  terms
@@ -42,6 +42,10 @@ describe( 'getNormalizedSearchTerms', () => {
42
42
  getNormalizedSearchTerms( ' Média & Text Tag-Cloud > 123' )
43
43
  ).toEqual( [ 'media', 'text', 'tag', 'cloud', '123' ] );
44
44
  } );
45
+
46
+ it( 'should support non-latin letters', () => {
47
+ expect( getNormalizedSearchTerms( 'მედია' ) ).toEqual( [ 'მედია' ] );
48
+ } );
45
49
  } );
46
50
 
47
51
  describe( 'getItemSearchRank', () => {
@@ -5,6 +5,7 @@ import { addFilter } from '@wordpress/hooks';
5
5
  import { hasBlockSupport } from '@wordpress/blocks';
6
6
  import TokenList from '@wordpress/token-list';
7
7
  import { createHigherOrderComponent } from '@wordpress/compose';
8
+ import { select } from '@wordpress/data';
8
9
 
9
10
  /**
10
11
  * Internal dependencies
@@ -14,6 +15,7 @@ import {
14
15
  getFontSizeClass,
15
16
  getFontSizeObjectByValue,
16
17
  FontSizePicker,
18
+ getComputedFluidTypographyValue,
17
19
  } from '../components/font-sizes';
18
20
  import { TYPOGRAPHY_SUPPORT_KEY } from './typography';
19
21
  import {
@@ -22,6 +24,7 @@ import {
22
24
  shouldSkipSerialization,
23
25
  } from './utils';
24
26
  import useSetting from '../components/use-setting';
27
+ import { store as blockEditorStore } from '../store';
25
28
 
26
29
  export const FONT_SIZE_SUPPORT_KEY = 'typography.fontSize';
27
30
 
@@ -282,6 +285,69 @@ export function addTransforms( result, source, index, results ) {
282
285
  );
283
286
  }
284
287
 
288
+ /**
289
+ * Allow custom font sizes to appear fluid when fluid typography is enabled at
290
+ * the theme level.
291
+ *
292
+ * Adds a custom getEditWrapperProps() callback to all block types that support
293
+ * font sizes. Then, if fluid typography is enabled, this callback will swap any
294
+ * custom font size in style.fontSize with a fluid font size (i.e. one that uses
295
+ * clamp()).
296
+ *
297
+ * It's important that this hook runs after 'core/style/addEditProps' sets
298
+ * style.fontSize as otherwise fontSize will be overwritten.
299
+ *
300
+ * @param {Object} blockType Block settings object.
301
+ */
302
+ function addEditPropsForFluidCustomFontSizes( blockType ) {
303
+ if (
304
+ ! hasBlockSupport( blockType, FONT_SIZE_SUPPORT_KEY ) ||
305
+ shouldSkipSerialization( blockType, TYPOGRAPHY_SUPPORT_KEY, 'fontSize' )
306
+ ) {
307
+ return blockType;
308
+ }
309
+
310
+ const existingGetEditWrapperProps = blockType.getEditWrapperProps;
311
+
312
+ blockType.getEditWrapperProps = ( attributes ) => {
313
+ const wrapperProps = existingGetEditWrapperProps
314
+ ? existingGetEditWrapperProps( attributes )
315
+ : {};
316
+
317
+ const fontSize = wrapperProps?.style?.fontSize;
318
+
319
+ // TODO: This sucks! We should be using useSetting( 'typography.fluid' )
320
+ // or even useSelect( blockEditorStore ). We can't do either here
321
+ // because getEditWrapperProps is a plain JavaScript function called by
322
+ // BlockListBlock and not a React component rendered within
323
+ // BlockListContext.Provider. If we set fontSize using editor.
324
+ // BlockListBlock instead of using getEditWrapperProps then the value is
325
+ // clobbered when the core/style/addEditProps filter runs.
326
+ const isFluidTypographyEnabled =
327
+ !! select( blockEditorStore ).getSettings().__experimentalFeatures
328
+ ?.typography?.fluid;
329
+
330
+ const newFontSize =
331
+ fontSize && isFluidTypographyEnabled
332
+ ? getComputedFluidTypographyValue( { fontSize } )
333
+ : null;
334
+
335
+ if ( newFontSize === null ) {
336
+ return wrapperProps;
337
+ }
338
+
339
+ return {
340
+ ...wrapperProps,
341
+ style: {
342
+ ...wrapperProps?.style,
343
+ fontSize: newFontSize,
344
+ },
345
+ };
346
+ };
347
+
348
+ return blockType;
349
+ }
350
+
285
351
  addFilter(
286
352
  'blocks.registerBlockType',
287
353
  'core/font/addAttribute',
@@ -307,3 +373,12 @@ addFilter(
307
373
  'core/font-size/addTransforms',
308
374
  addTransforms
309
375
  );
376
+
377
+ addFilter(
378
+ 'blocks.registerBlockType',
379
+ 'core/font-size/addEditPropsForFluidCustomFontSizes',
380
+ addEditPropsForFluidCustomFontSizes,
381
+ // Run after 'core/style/addEditProps' so that the style object has already
382
+ // been translated into inline CSS.
383
+ 11
384
+ );
@@ -190,10 +190,10 @@ export function MarginVisualizer( { clientId, attributes } ) {
190
190
  borderRightWidth: marginRight,
191
191
  borderBottomWidth: marginBottom,
192
192
  borderLeftWidth: marginLeft,
193
- top: marginTop !== 0 ? `-${ marginTop }` : 0,
194
- right: marginRight !== 0 ? `-${ marginRight }` : 0,
195
- bottom: marginBottom !== 0 ? `-${ marginBottom }` : 0,
196
- left: marginLeft !== 0 ? `-${ marginLeft }` : 0,
193
+ top: marginTop !== 0 ? `calc(${ marginTop } * -1)` : 0,
194
+ right: marginRight !== 0 ? `calc(${ marginRight } * -1)` : 0,
195
+ bottom: marginBottom !== 0 ? `calc(${ marginBottom } * -1)` : 0,
196
+ left: marginLeft !== 0 ? `calc(${ marginLeft } * -1)` : 0,
197
197
  };
198
198
  }, [ margin ] );
199
199
 
@@ -25,4 +25,26 @@ describe( 'getTypographyClassesAndStyles', () => {
25
25
  },
26
26
  } );
27
27
  } );
28
+
29
+ it( 'should return fluid font size styles', () => {
30
+ const attributes = {
31
+ fontFamily: 'tofu',
32
+ style: {
33
+ typography: {
34
+ letterSpacing: '22px',
35
+ fontSize: '2rem',
36
+ textTransform: 'uppercase',
37
+ },
38
+ },
39
+ };
40
+ expect( getTypographyClassesAndStyles( attributes, true ) ).toEqual( {
41
+ className: 'has-tofu-font-family',
42
+ style: {
43
+ letterSpacing: '22px',
44
+ fontSize:
45
+ 'clamp(1.5rem, 1.5rem + ((1vw - 0.48rem) * 2.885), 3rem)',
46
+ textTransform: 'uppercase',
47
+ },
48
+ } );
49
+ } );
28
50
  } );
@@ -9,6 +9,7 @@ import classnames from 'classnames';
9
9
  */
10
10
  import { getInlineStyles } from './style';
11
11
  import { getFontSizeClass } from '../components/font-sizes';
12
+ import { getComputedFluidTypographyValue } from '../components/font-sizes/fluid-utils';
12
13
 
13
14
  // This utility is intended to assist where the serialization of the typography
14
15
  // block support is being skipped for a block but the typography related CSS
@@ -18,12 +19,26 @@ import { getFontSizeClass } from '../components/font-sizes';
18
19
  * Provides the CSS class names and inline styles for a block's typography support
19
20
  * attributes.
20
21
  *
21
- * @param {Object} attributes Block attributes.
22
+ * @param {Object} attributes Block attributes.
23
+ * @param {boolean} isFluidFontSizeActive Whether the function should try to convert font sizes to fluid values.
22
24
  *
23
25
  * @return {Object} Typography block support derived CSS classes & styles.
24
26
  */
25
- export function getTypographyClassesAndStyles( attributes ) {
26
- const typographyStyles = attributes?.style?.typography || {};
27
+ export function getTypographyClassesAndStyles(
28
+ attributes,
29
+ isFluidFontSizeActive
30
+ ) {
31
+ let typographyStyles = attributes?.style?.typography || {};
32
+
33
+ if ( isFluidFontSizeActive ) {
34
+ typographyStyles = {
35
+ ...typographyStyles,
36
+ fontSize: getComputedFluidTypographyValue( {
37
+ fontSize: attributes?.style?.typography?.fontSize,
38
+ } ),
39
+ };
40
+ }
41
+
27
42
  const style = getInlineStyles( { typography: typographyStyles } );
28
43
  const fontFamilyClassName = !! attributes?.fontFamily
29
44
  ? `has-${ kebabCase( attributes.fontFamily ) }-font-family`