@wordpress/block-editor 10.0.5 → 10.0.7

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 (45) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +40 -0
  3. package/build/components/block-inspector/index.js +3 -2
  4. package/build/components/block-inspector/index.js.map +1 -1
  5. package/build/components/font-sizes/fluid-utils.js +208 -0
  6. package/build/components/font-sizes/fluid-utils.js.map +1 -0
  7. package/build/components/font-sizes/index.js +8 -0
  8. package/build/components/font-sizes/index.js.map +1 -1
  9. package/build/components/inner-blocks/use-inner-block-template-sync.js +3 -2
  10. package/build/components/inner-blocks/use-inner-block-template-sync.js.map +1 -1
  11. package/build/components/spacing-sizes-control/spacing-input-control.js +4 -2
  12. package/build/components/spacing-sizes-control/spacing-input-control.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/use-typography-props.js +17 -3
  16. package/build/hooks/use-typography-props.js.map +1 -1
  17. package/build-module/components/block-inspector/index.js +3 -2
  18. package/build-module/components/block-inspector/index.js.map +1 -1
  19. package/build-module/components/font-sizes/fluid-utils.js +197 -0
  20. package/build-module/components/font-sizes/fluid-utils.js.map +1 -0
  21. package/build-module/components/font-sizes/index.js +1 -0
  22. package/build-module/components/font-sizes/index.js.map +1 -1
  23. package/build-module/components/inner-blocks/use-inner-block-template-sync.js +3 -2
  24. package/build-module/components/inner-blocks/use-inner-block-template-sync.js.map +1 -1
  25. package/build-module/components/spacing-sizes-control/spacing-input-control.js +4 -2
  26. package/build-module/components/spacing-sizes-control/spacing-input-control.js.map +1 -1
  27. package/build-module/hooks/font-size.js +59 -1
  28. package/build-module/hooks/font-size.js.map +1 -1
  29. package/build-module/hooks/use-typography-props.js +17 -4
  30. package/build-module/hooks/use-typography-props.js.map +1 -1
  31. package/build-style/style-rtl.css +27 -21
  32. package/build-style/style.css +27 -21
  33. package/package.json +3 -3
  34. package/src/components/block-inspector/index.js +6 -3
  35. package/src/components/block-patterns-list/style.scss +5 -0
  36. package/src/components/button-block-appender/style.scss +3 -2
  37. package/src/components/font-sizes/fluid-utils.js +221 -0
  38. package/src/components/font-sizes/index.js +1 -0
  39. package/src/components/font-sizes/test/fluid-utils.js +168 -0
  40. package/src/components/inner-blocks/use-inner-block-template-sync.js +3 -2
  41. package/src/components/spacing-sizes-control/spacing-input-control.js +2 -0
  42. package/src/components/spacing-sizes-control/style.scss +26 -19
  43. package/src/hooks/font-size.js +75 -0
  44. package/src/hooks/test/use-typography-props.js +22 -0
  45. package/src/hooks/use-typography-props.js +18 -3
@@ -1068,6 +1068,7 @@
1068
1068
  .block-editor-block-patterns-list__list-item {
1069
1069
  cursor: pointer;
1070
1070
  margin-bottom: 24px;
1071
+ position: relative;
1071
1072
  }
1072
1073
  .block-editor-block-patterns-list__list-item.is-placeholder {
1073
1074
  min-height: 100px;
@@ -1712,10 +1713,10 @@
1712
1713
  color: #000;
1713
1714
  }
1714
1715
 
1715
- .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child, .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > .block-list-appender:only-child, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > .block-list-appender:only-child {
1716
+ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child, .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > .block-list-appender:only-child, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > .block-list-appender:only-child {
1716
1717
  pointer-events: none;
1717
1718
  }
1718
- .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child::after, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child::after, .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > .block-list-appender:only-child::after, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > .block-list-appender:only-child::after {
1719
+ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child::after, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child::after, .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > .block-list-appender:only-child::after, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > .block-list-appender:only-child::after {
1719
1720
  content: "";
1720
1721
  position: absolute;
1721
1722
  top: 0;
@@ -1726,7 +1727,7 @@
1726
1727
  border: 1px dashed currentColor;
1727
1728
  border-radius: 2px;
1728
1729
  }
1729
- .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child .block-editor-inserter, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child .block-editor-inserter, .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > .block-list-appender:only-child .block-editor-inserter, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > .block-list-appender:only-child .block-editor-inserter {
1730
+ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child .block-editor-inserter, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-list-appender:only-child .block-editor-inserter, .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > .block-list-appender:only-child .block-editor-inserter, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > .block-list-appender:only-child .block-editor-inserter {
1730
1731
  visibility: hidden;
1731
1732
  }
1732
1733
 
@@ -4273,7 +4274,7 @@ figcaption.block-editor-rich-text__editable [data-rich-text-placeholder]::before
4273
4274
  display: grid;
4274
4275
  grid-template-columns: auto 1fr auto;
4275
4276
  align-items: center;
4276
- grid-template-rows: 25px auto;
4277
+ grid-template-rows: 16px auto;
4277
4278
  }
4278
4279
 
4279
4280
  .component-spacing-sizes-control {
@@ -4296,15 +4297,16 @@ figcaption.block-editor-rich-text__editable [data-rich-text-placeholder]::before
4296
4297
  grid-column: 1/1;
4297
4298
  justify-content: left;
4298
4299
  height: 16px;
4299
- margin-top: 12px;
4300
+ margin-top: 16px;
4300
4301
  }
4301
4302
  .component-spacing-sizes-control .components-spacing-sizes-control__side-label {
4302
4303
  grid-column: 1/1;
4303
4304
  justify-self: left;
4304
4305
  margin-bottom: 0;
4305
4306
  }
4306
- .component-spacing-sizes-control.is-unlinked .components-range-control.components-spacing-sizes-control__range-control {
4307
- margin-top: 12px;
4307
+ .component-spacing-sizes-control.is-unlinked .components-range-control.components-spacing-sizes-control__range-control,
4308
+ .component-spacing-sizes-control.is-unlinked .components-spacing-sizes-control__custom-value-input {
4309
+ margin-top: 8px;
4308
4310
  }
4309
4311
  .component-spacing-sizes-control .components-spacing-sizes-control__hint-single,
4310
4312
  .component-spacing-sizes-control .components-spacing-sizes-control__hint-all {
@@ -4322,12 +4324,7 @@ figcaption.block-editor-rich-text__editable [data-rich-text-placeholder]::before
4322
4324
  grid-column: 2/2;
4323
4325
  grid-row: 1/1;
4324
4326
  justify-self: end;
4325
- padding: 0;
4326
- }
4327
- .component-spacing-sizes-control .components-spacing-sizes-control__custom-toggle-all.is-small.has-icon {
4328
- padding: 0;
4329
- min-width: 24px;
4330
- height: 16px;
4327
+ margin-top: -4px;
4331
4328
  }
4332
4329
  .component-spacing-sizes-control .component-spacing-sizes-control__linked-button ~ .components-spacing-sizes-control__custom-toggle-all {
4333
4330
  margin-right: 4px;
@@ -4335,29 +4332,37 @@ figcaption.block-editor-rich-text__editable [data-rich-text-placeholder]::before
4335
4332
  .component-spacing-sizes-control .components-spacing-sizes-control__custom-toggle-single {
4336
4333
  grid-column: 3/3;
4337
4334
  justify-self: end;
4338
- }
4339
- .component-spacing-sizes-control .components-spacing-sizes-control__custom-toggle-single.is-small.has-icon {
4340
- padding: 0;
4341
- min-width: 24px;
4342
- height: 16px;
4343
4335
  margin-top: 12px;
4344
4336
  }
4345
4337
  .component-spacing-sizes-control .component-spacing-sizes-control__linked-button {
4346
4338
  grid-column: 3/3;
4347
4339
  grid-row: 1/1;
4348
4340
  justify-self: end;
4341
+ line-height: 0;
4342
+ margin-top: -4px;
4349
4343
  }
4350
4344
  .component-spacing-sizes-control .components-spacing-sizes-control__custom-value-range {
4351
4345
  grid-column: span 2;
4352
- margin-left: 8px;
4353
- height: 30px;
4346
+ margin-left: 16px;
4347
+ margin-top: 8px;
4354
4348
  }
4355
4349
  .component-spacing-sizes-control .components-spacing-sizes-control__custom-value-input {
4356
4350
  width: 124px;
4351
+ margin-top: 8px;
4352
+ }
4353
+ .component-spacing-sizes-control .components-range-control {
4354
+ height: 40px;
4355
+ /* Vertically center the RangeControl until it has true 40px height. */
4356
+ display: flex;
4357
+ align-items: center;
4358
+ }
4359
+ .component-spacing-sizes-control .components-range-control > .components-base-control__field {
4360
+ /* Fixes RangeControl contents when the outer wrapper is flex */
4361
+ flex: 1;
4357
4362
  }
4358
4363
  .component-spacing-sizes-control .components-spacing-sizes-control__range-control {
4359
4364
  grid-column: span 3;
4360
- height: 40px;
4365
+ margin-top: 8px;
4361
4366
  }
4362
4367
  .component-spacing-sizes-control .components-range-control__mark {
4363
4368
  height: 4px;
@@ -4376,6 +4381,7 @@ figcaption.block-editor-rich-text__editable [data-rich-text-placeholder]::before
4376
4381
  }
4377
4382
  .component-spacing-sizes-control .components-spacing-sizes-control__custom-select-control {
4378
4383
  grid-column: span 3;
4384
+ margin-top: 8px;
4379
4385
  }
4380
4386
 
4381
4387
  body.admin-color-light {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "10.0.5",
3
+ "version": "10.0.7",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -37,7 +37,7 @@
37
37
  "@wordpress/api-fetch": "^6.14.1",
38
38
  "@wordpress/blob": "^3.17.1",
39
39
  "@wordpress/blocks": "^11.16.4",
40
- "@wordpress/components": "^21.0.4",
40
+ "@wordpress/components": "^21.0.6",
41
41
  "@wordpress/compose": "^5.15.2",
42
42
  "@wordpress/data": "^7.1.3",
43
43
  "@wordpress/date": "^4.17.1",
@@ -78,5 +78,5 @@
78
78
  "publishConfig": {
79
79
  "access": "public"
80
80
  },
81
- "gitHead": "06334a7bd943f2345f15b8d2f427721d6878e6c1"
81
+ "gitHead": "84269cffad0bab2b10e6b6da8e275716fcc8c57b"
82
82
  }
@@ -144,6 +144,7 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
144
144
  getSelectedBlockCount,
145
145
  getBlockName,
146
146
  __unstableGetContentLockingParent,
147
+ getTemplateLock,
147
148
  } = select( blockEditorStore );
148
149
 
149
150
  const _selectedBlockClientId = getSelectedBlockClientId();
@@ -157,9 +158,11 @@ const BlockInspector = ( { showNoBlockSelectedMessage = true } ) => {
157
158
  selectedBlockClientId: _selectedBlockClientId,
158
159
  selectedBlockName: _selectedBlockName,
159
160
  blockType: _blockType,
160
- topLevelLockedBlock: __unstableGetContentLockingParent(
161
- _selectedBlockClientId
162
- ),
161
+ topLevelLockedBlock:
162
+ __unstableGetContentLockingParent( _selectedBlockClientId ) ||
163
+ ( getTemplateLock( _selectedBlockClientId ) === 'contentOnly'
164
+ ? _selectedBlockClientId
165
+ : undefined ),
163
166
  };
164
167
  }, [] );
165
168
 
@@ -2,6 +2,11 @@
2
2
  cursor: pointer;
3
3
  margin-bottom: $grid-unit-30;
4
4
 
5
+ // The list item contains absolutely positioned visually hidden text,
6
+ // so make this container relative. This prevents the bug experienced in
7
+ // https://github.com/WordPress/gutenberg/issues/44842.
8
+ position: relative;
9
+
5
10
  &.is-placeholder {
6
11
  min-height: 100px;
7
12
  }
@@ -36,8 +36,9 @@
36
36
  .block-list-appender:only-child {
37
37
  .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > &,
38
38
  .is-layout-flow.block-editor-block-list__block:not(.is-selected) > &,
39
- .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > &,
40
- .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .block-editor-block-list__layout > & {
39
+ // Legacy groups have an inner container so need to be targeted separately
40
+ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > &,
41
+ .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > & {
41
42
  pointer-events: none;
42
43
 
43
44
  &::after {
@@ -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
+ } );
@@ -40,7 +40,7 @@ export default function useInnerBlockTemplateSync(
40
40
  templateLock,
41
41
  templateInsertUpdatesSelection
42
42
  ) {
43
- const { getSelectedBlocksInitialCaretPosition } =
43
+ const { getSelectedBlocksInitialCaretPosition, isBlockSelected } =
44
44
  useSelect( blockEditorStore );
45
45
  const { replaceInnerBlocks } = useDispatch( blockEditorStore );
46
46
  const innerBlocks = useSelect(
@@ -86,7 +86,8 @@ export default function useInnerBlockTemplateSync(
86
86
  nextBlocks,
87
87
  currentInnerBlocks.length === 0 &&
88
88
  templateInsertUpdatesSelection &&
89
- nextBlocks.length !== 0,
89
+ nextBlocks.length !== 0 &&
90
+ isBlockSelected( clientId ),
90
91
  // This ensures the "initialPosition" doesn't change when applying the template
91
92
  // If we're supposed to focus the block, we'll focus the first inner block
92
93
  // otherwise, we won't apply any auto-focus.
@@ -221,6 +221,7 @@ export default function SpacingInputControl( {
221
221
  hideLabelFromVision={ true }
222
222
  className="components-spacing-sizes-control__custom-value-input"
223
223
  style={ { gridColumn: '1' } }
224
+ size={ '__unstable-large' }
224
225
  />
225
226
 
226
227
  <RangeControl
@@ -279,6 +280,7 @@ export default function SpacingInputControl( {
279
280
  label={ ariaLabel }
280
281
  hideLabelFromVision={ true }
281
282
  __nextUnconstrainedWidth={ true }
283
+ size={ '__unstable-large' }
282
284
  />
283
285
  ) }
284
286
  </>