@wordpress/components 29.5.1 → 29.7.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 (100) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/build/angle-picker-control/index.js +1 -1
  3. package/build/angle-picker-control/index.js.map +1 -1
  4. package/build/autocomplete/index.js +5 -30
  5. package/build/autocomplete/index.js.map +1 -1
  6. package/build/custom-select-control-v2/styles.js +9 -9
  7. package/build/custom-select-control-v2/styles.js.map +1 -1
  8. package/build/font-size-picker/font-size-picker-select.js +1 -8
  9. package/build/font-size-picker/font-size-picker-select.js.map +1 -1
  10. package/build/font-size-picker/index.js +12 -34
  11. package/build/font-size-picker/index.js.map +1 -1
  12. package/build/font-size-picker/styles.js +12 -19
  13. package/build/font-size-picker/styles.js.map +1 -1
  14. package/build/font-size-picker/utils.js +0 -22
  15. package/build/font-size-picker/utils.js.map +1 -1
  16. package/build/number-control/index.js +6 -4
  17. package/build/number-control/index.js.map +1 -1
  18. package/build/range-control/index.js +6 -5
  19. package/build/range-control/index.js.map +1 -1
  20. package/build/toolbar/toolbar-dropdown-menu/index.js +4 -3
  21. package/build/toolbar/toolbar-dropdown-menu/index.js.map +1 -1
  22. package/build/toolbar/toolbar-item/index.js +4 -3
  23. package/build/toolbar/toolbar-item/index.js.map +1 -1
  24. package/build/utils/get-node-text.js +30 -0
  25. package/build/utils/get-node-text.js.map +1 -0
  26. package/build/utils/math.js +18 -15
  27. package/build/utils/math.js.map +1 -1
  28. package/build-module/angle-picker-control/index.js +1 -1
  29. package/build-module/angle-picker-control/index.js.map +1 -1
  30. package/build-module/autocomplete/index.js +3 -28
  31. package/build-module/autocomplete/index.js.map +1 -1
  32. package/build-module/custom-select-control-v2/styles.js +9 -9
  33. package/build-module/custom-select-control-v2/styles.js.map +1 -1
  34. package/build-module/font-size-picker/font-size-picker-select.js +2 -9
  35. package/build-module/font-size-picker/font-size-picker-select.js.map +1 -1
  36. package/build-module/font-size-picker/index.js +14 -36
  37. package/build-module/font-size-picker/index.js.map +1 -1
  38. package/build-module/font-size-picker/styles.js +11 -18
  39. package/build-module/font-size-picker/styles.js.map +1 -1
  40. package/build-module/font-size-picker/utils.js +0 -22
  41. package/build-module/font-size-picker/utils.js.map +1 -1
  42. package/build-module/number-control/index.js +7 -5
  43. package/build-module/number-control/index.js.map +1 -1
  44. package/build-module/range-control/index.js +6 -5
  45. package/build-module/range-control/index.js.map +1 -1
  46. package/build-module/toolbar/toolbar-dropdown-menu/index.js +3 -2
  47. package/build-module/toolbar/toolbar-dropdown-menu/index.js.map +1 -1
  48. package/build-module/toolbar/toolbar-item/index.js +3 -2
  49. package/build-module/toolbar/toolbar-item/index.js.map +1 -1
  50. package/build-module/utils/get-node-text.js +24 -0
  51. package/build-module/utils/get-node-text.js.map +1 -0
  52. package/build-module/utils/math.js +17 -14
  53. package/build-module/utils/math.js.map +1 -1
  54. package/build-style/style-rtl.css +1 -3
  55. package/build-style/style.css +1 -3
  56. package/build-types/angle-picker-control/index.d.ts +1 -1
  57. package/build-types/autocomplete/index.d.ts +2 -2
  58. package/build-types/autocomplete/index.d.ts.map +1 -1
  59. package/build-types/custom-select-control-v2/styles.d.ts.map +1 -1
  60. package/build-types/font-size-picker/font-size-picker-select.d.ts.map +1 -1
  61. package/build-types/font-size-picker/index.d.ts.map +1 -1
  62. package/build-types/font-size-picker/styles.d.ts +0 -4
  63. package/build-types/font-size-picker/styles.d.ts.map +1 -1
  64. package/build-types/font-size-picker/utils.d.ts +1 -9
  65. package/build-types/font-size-picker/utils.d.ts.map +1 -1
  66. package/build-types/number-control/index.d.ts.map +1 -1
  67. package/build-types/range-control/index.d.ts +6 -5
  68. package/build-types/range-control/index.d.ts.map +1 -1
  69. package/build-types/toolbar/toolbar-dropdown-menu/index.d.ts +2 -2
  70. package/build-types/toolbar/toolbar-dropdown-menu/index.d.ts.map +1 -1
  71. package/build-types/toolbar/toolbar-item/index.d.ts +2 -2
  72. package/build-types/toolbar/toolbar-item/index.d.ts.map +1 -1
  73. package/build-types/utils/get-node-text.d.ts +3 -0
  74. package/build-types/utils/get-node-text.d.ts.map +1 -0
  75. package/build-types/utils/math.d.ts +10 -11
  76. package/build-types/utils/math.d.ts.map +1 -1
  77. package/package.json +19 -19
  78. package/src/angle-picker-control/README.md +1 -1
  79. package/src/angle-picker-control/index.tsx +1 -1
  80. package/src/autocomplete/index.tsx +3 -30
  81. package/src/button/style.scss +0 -2
  82. package/src/custom-select-control-v2/styles.ts +1 -0
  83. package/src/font-size-picker/font-size-picker-select.tsx +2 -12
  84. package/src/font-size-picker/index.tsx +18 -47
  85. package/src/font-size-picker/styles.ts +0 -5
  86. package/src/font-size-picker/test/index.tsx +36 -80
  87. package/src/font-size-picker/test/utils.ts +1 -37
  88. package/src/font-size-picker/utils.ts +1 -24
  89. package/src/form-token-field/style.scss +1 -1
  90. package/src/number-control/index.tsx +8 -7
  91. package/src/number-control/test/index.tsx +15 -2
  92. package/src/range-control/index.tsx +6 -5
  93. package/src/toolbar/toolbar-dropdown-menu/index.tsx +3 -2
  94. package/src/toolbar/toolbar-item/index.tsx +3 -2
  95. package/src/utils/get-node-text.ts +24 -0
  96. package/src/utils/math.js +17 -22
  97. package/src/utils/test/get-node-text.js +37 -0
  98. package/src/utils/test/math.js +28 -32
  99. package/src/utils/theme-variables.scss +0 -4
  100. package/tsconfig.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/components",
3
- "version": "29.5.1",
3
+ "version": "29.7.0",
4
4
  "description": "UI components for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -44,23 +44,23 @@
44
44
  "@types/gradient-parser": "0.1.3",
45
45
  "@types/highlight-words-core": "1.2.1",
46
46
  "@use-gesture/react": "^10.3.1",
47
- "@wordpress/a11y": "^4.19.1",
48
- "@wordpress/compose": "^7.19.1",
49
- "@wordpress/date": "^5.19.1",
50
- "@wordpress/deprecated": "^4.19.1",
51
- "@wordpress/dom": "^4.19.1",
52
- "@wordpress/element": "^6.19.1",
53
- "@wordpress/escape-html": "^3.19.1",
54
- "@wordpress/hooks": "^4.19.1",
55
- "@wordpress/html-entities": "^4.19.1",
56
- "@wordpress/i18n": "^5.19.1",
57
- "@wordpress/icons": "^10.19.1",
58
- "@wordpress/is-shallow-equal": "^5.19.1",
59
- "@wordpress/keycodes": "^4.19.1",
60
- "@wordpress/primitives": "^4.19.1",
61
- "@wordpress/private-apis": "^1.19.1",
62
- "@wordpress/rich-text": "^7.19.1",
63
- "@wordpress/warning": "^3.19.1",
47
+ "@wordpress/a11y": "^4.21.0",
48
+ "@wordpress/compose": "^7.21.0",
49
+ "@wordpress/date": "^5.21.0",
50
+ "@wordpress/deprecated": "^4.21.0",
51
+ "@wordpress/dom": "^4.21.0",
52
+ "@wordpress/element": "^6.21.0",
53
+ "@wordpress/escape-html": "^3.21.0",
54
+ "@wordpress/hooks": "^4.21.0",
55
+ "@wordpress/html-entities": "^4.21.0",
56
+ "@wordpress/i18n": "^5.21.0",
57
+ "@wordpress/icons": "^10.21.0",
58
+ "@wordpress/is-shallow-equal": "^5.21.0",
59
+ "@wordpress/keycodes": "^4.21.0",
60
+ "@wordpress/primitives": "^4.21.0",
61
+ "@wordpress/private-apis": "^1.21.0",
62
+ "@wordpress/rich-text": "^7.21.0",
63
+ "@wordpress/warning": "^3.21.0",
64
64
  "change-case": "^4.1.2",
65
65
  "clsx": "^2.1.1",
66
66
  "colord": "^2.7.0",
@@ -85,5 +85,5 @@
85
85
  "publishConfig": {
86
86
  "access": "public"
87
87
  },
88
- "gitHead": "6f49fee89f840761f7fedf662713cbd4a71723e9"
88
+ "gitHead": "104af00f9abcd7a4d36b87e648f148c72cc4ea5f"
89
89
  }
@@ -19,7 +19,7 @@ function Example() {
19
19
  <AnglePickerControl
20
20
  value={ angle }
21
21
  onChange={ setAngle }
22
- </>
22
+ />
23
23
  );
24
24
  }
25
25
  ```
@@ -97,7 +97,7 @@ function UnforwardedAnglePickerControl(
97
97
  * <AnglePickerControl
98
98
  * value={ angle }
99
99
  * onChange={ setAngle }
100
- * </>
100
+ * />
101
101
  * );
102
102
  * }
103
103
  * ```
@@ -40,35 +40,7 @@ import type {
40
40
  UseAutocompleteProps,
41
41
  WPCompleter,
42
42
  } from './types';
43
-
44
- const getNodeText = ( node: React.ReactNode ): string => {
45
- if ( node === null ) {
46
- return '';
47
- }
48
-
49
- switch ( typeof node ) {
50
- case 'string':
51
- case 'number':
52
- return node.toString();
53
- break;
54
- case 'boolean':
55
- return '';
56
- break;
57
- case 'object': {
58
- if ( node instanceof Array ) {
59
- return node.map( getNodeText ).join( '' );
60
- }
61
- if ( 'props' in node ) {
62
- return getNodeText( node.props.children );
63
- }
64
- break;
65
- }
66
- default:
67
- return '';
68
- }
69
-
70
- return '';
71
- };
43
+ import getNodeText from '../utils/get-node-text';
72
44
 
73
45
  const EMPTY_FILTERED_OPTIONS: KeyedOption[] = [];
74
46
 
@@ -394,12 +366,13 @@ export function useAutocomplete( {
394
366
  ? `components-autocomplete-item-${ instanceId }-${ selectedKey }`
395
367
  : null;
396
368
  const hasSelection = record.start !== undefined;
369
+ const showPopover = !! textContent && hasSelection && !! AutocompleterUI;
397
370
 
398
371
  return {
399
372
  listBoxId,
400
373
  activeId,
401
374
  onKeyDown: withIgnoreIMEEvents( handleKeyDown ),
402
- popover: hasSelection && AutocompleterUI && (
375
+ popover: showPopover && (
403
376
  <AutocompleterUI
404
377
  className={ className }
405
378
  filterValue={ filterValue }
@@ -302,7 +302,6 @@
302
302
 
303
303
  &.has-icon:not(.has-text) {
304
304
  padding: 0;
305
- width: $button-size-compact;
306
305
  min-width: $button-size-compact;
307
306
  }
308
307
  }
@@ -315,7 +314,6 @@
315
314
 
316
315
  &.has-icon:not(.has-text) {
317
316
  padding: 0;
318
- width: $button-size-small;
319
317
  min-width: $button-size-small;
320
318
  }
321
319
  }
@@ -213,6 +213,7 @@ export const SelectedItemCheck = styled( Ariakit.SelectItemCheck )`
213
213
  display: flex;
214
214
  align-items: center;
215
215
  margin-inline-start: ${ space( 2 ) };
216
+ fill: currentColor;
216
217
 
217
218
  // Keep the checkmark vertically aligned at the top. Since the item text has a
218
219
  // 28px line height and the checkmark is 24px tall, a (28-24)/2 = 2px margin
@@ -7,12 +7,11 @@ import { __, sprintf } from '@wordpress/i18n';
7
7
  * Internal dependencies
8
8
  */
9
9
  import CustomSelectControl from '../custom-select-control';
10
- import { parseQuantityAndUnitFromRawValue } from '../unit-control';
11
10
  import type {
12
11
  FontSizePickerSelectProps,
13
12
  FontSizePickerSelectOption,
14
13
  } from './types';
15
- import { getCommonSizeUnit, isSimpleCssValue } from './utils';
14
+ import { isSimpleCssValue } from './utils';
16
15
 
17
16
  const DEFAULT_OPTION: FontSizePickerSelectOption = {
18
17
  key: 'default',
@@ -23,20 +22,11 @@ const DEFAULT_OPTION: FontSizePickerSelectOption = {
23
22
  const FontSizePickerSelect = ( props: FontSizePickerSelectProps ) => {
24
23
  const { __next40pxDefaultSize, fontSizes, value, size, onChange } = props;
25
24
 
26
- const areAllSizesSameUnit = !! getCommonSizeUnit( fontSizes );
27
-
28
25
  const options: FontSizePickerSelectOption[] = [
29
26
  DEFAULT_OPTION,
30
27
  ...fontSizes.map( ( fontSize ) => {
31
28
  let hint;
32
- if ( areAllSizesSameUnit ) {
33
- const [ quantity ] = parseQuantityAndUnitFromRawValue(
34
- fontSize.size
35
- );
36
- if ( quantity !== undefined ) {
37
- hint = String( quantity );
38
- }
39
- } else if ( isSimpleCssValue( fontSize.size ) ) {
29
+ if ( isSimpleCssValue( fontSize.size ) ) {
40
30
  hint = String( fontSize.size );
41
31
  }
42
32
  return {
@@ -8,7 +8,8 @@ import type { ForwardedRef } from 'react';
8
8
  */
9
9
  import { __ } from '@wordpress/i18n';
10
10
  import { settings } from '@wordpress/icons';
11
- import { useState, useMemo, forwardRef } from '@wordpress/element';
11
+ import { useState, forwardRef } from '@wordpress/element';
12
+ import { useInstanceId } from '@wordpress/compose';
12
13
 
13
14
  /**
14
15
  * Internal dependencies
@@ -21,20 +22,11 @@ import {
21
22
  parseQuantityAndUnitFromRawValue,
22
23
  useCustomUnits,
23
24
  } from '../unit-control';
24
- import { VisuallyHidden } from '../visually-hidden';
25
- import { getCommonSizeUnit } from './utils';
26
25
  import type { FontSizePickerProps } from './types';
27
- import {
28
- Container,
29
- Header,
30
- HeaderHint,
31
- HeaderLabel,
32
- HeaderToggle,
33
- } from './styles';
26
+ import { Container, Header, HeaderLabel, HeaderToggle } from './styles';
34
27
  import { Spacer } from '../spacer';
35
28
  import FontSizePickerSelect from './font-size-picker-select';
36
29
  import FontSizePickerToggleGroup from './font-size-picker-toggle-group';
37
- import { T_SHIRT_NAMES } from './constants';
38
30
  import { maybeWarnDeprecated36pxSize } from '../utils/deprecated-36px-size';
39
31
 
40
32
  const DEFAULT_UNITS = [ 'px', 'em', 'rem', 'vw', 'vh' ];
@@ -58,6 +50,11 @@ const UnforwardedFontSizePicker = (
58
50
  withReset = true,
59
51
  } = props;
60
52
 
53
+ const labelId = useInstanceId(
54
+ UnforwardedFontSizePicker,
55
+ 'font-size-picker-label'
56
+ );
57
+
61
58
  const units = useCustomUnits( {
62
59
  availableUnits: unitsProp,
63
60
  } );
@@ -83,29 +80,6 @@ const UnforwardedFontSizePicker = (
83
80
  : ( 'togglegroup' as const );
84
81
  }
85
82
 
86
- const headerHint = useMemo( () => {
87
- switch ( currentPickerType ) {
88
- case 'custom':
89
- return __( 'Custom' );
90
- case 'togglegroup':
91
- if ( selectedFontSize ) {
92
- return (
93
- selectedFontSize.name ||
94
- T_SHIRT_NAMES[ fontSizes.indexOf( selectedFontSize ) ]
95
- );
96
- }
97
- break;
98
- case 'select':
99
- const commonUnit = getCommonSizeUnit( fontSizes );
100
- if ( commonUnit ) {
101
- return `(${ commonUnit })`;
102
- }
103
- break;
104
- }
105
-
106
- return '';
107
- }, [ currentPickerType, selectedFontSize, fontSizes ] );
108
-
109
83
  if ( fontSizes.length === 0 && disableCustomFontSizes ) {
110
84
  return null;
111
85
  }
@@ -131,19 +105,16 @@ const UnforwardedFontSizePicker = (
131
105
  } );
132
106
 
133
107
  return (
134
- <Container ref={ ref } className="components-font-size-picker">
135
- <VisuallyHidden as="legend">{ __( 'Font size' ) }</VisuallyHidden>
108
+ <Container
109
+ ref={ ref }
110
+ className="components-font-size-picker"
111
+ // This Container component renders a fieldset element that needs to be labeled.
112
+ aria-labelledby={ labelId }
113
+ >
136
114
  <Spacer>
137
115
  <Header className="components-font-size-picker__header">
138
- <HeaderLabel
139
- aria-label={ `${ __( 'Size' ) } ${ headerHint || '' }` }
140
- >
141
- { __( 'Size' ) }
142
- { headerHint && (
143
- <HeaderHint className="components-font-size-picker__header__hint">
144
- { headerHint }
145
- </HeaderHint>
146
- ) }
116
+ <HeaderLabel id={ labelId }>
117
+ { __( 'Font size' ) }
147
118
  </HeaderLabel>
148
119
  { ! disableCustomFontSizes && (
149
120
  <HeaderToggle
@@ -213,7 +184,7 @@ const UnforwardedFontSizePicker = (
213
184
  <UnitControl
214
185
  __next40pxDefaultSize={ __next40pxDefaultSize }
215
186
  __shouldNotWarnDeprecated36pxSize
216
- label={ __( 'Custom' ) }
187
+ label={ __( 'Font size' ) }
217
188
  labelPosition="top"
218
189
  hideLabelFromVision
219
190
  value={ value }
@@ -245,7 +216,7 @@ const UnforwardedFontSizePicker = (
245
216
  }
246
217
  __shouldNotWarnDeprecated36pxSize
247
218
  className="components-font-size-picker__custom-input"
248
- label={ __( 'Custom Size' ) }
219
+ label={ __( 'Font size' ) }
249
220
  hideLabelFromVision
250
221
  value={ valueQuantity }
251
222
  initialPosition={ fallbackFontSize }
@@ -10,7 +10,6 @@ import BaseControl from '../base-control';
10
10
  import Button from '../button';
11
11
  import { HStack } from '../h-stack';
12
12
  import { space } from '../utils/space';
13
- import { COLORS } from '../utils';
14
13
 
15
14
  export const Container = styled.fieldset`
16
15
  border: 0;
@@ -33,7 +32,3 @@ export const HeaderLabel = styled( BaseControl.VisualLabel )`
33
32
  justify-content: flex-start;
34
33
  margin-bottom: 0;
35
34
  `;
36
-
37
- export const HeaderHint = styled.span`
38
- color: ${ COLORS.gray[ 700 ] };
39
- `;
@@ -52,7 +52,9 @@ describe( 'FontSizePicker', () => {
52
52
  await render(
53
53
  <FontSizePicker value={ value } onChange={ onChange } />
54
54
  );
55
- const input = screen.getByLabelText( 'Custom' );
55
+ const input = screen.getByRole( 'spinbutton', {
56
+ name: 'Font size',
57
+ } );
56
58
  await user.clear( input );
57
59
  await user.type( input, '80' );
58
60
  expect( onChange ).toHaveBeenCalledTimes( 3 ); // Once for the clear, then once per keystroke.
@@ -79,7 +81,9 @@ describe( 'FontSizePicker', () => {
79
81
  await user.click(
80
82
  screen.getByRole( 'button', { name: 'Set custom size' } )
81
83
  );
82
- const input = screen.getByLabelText( 'Custom' );
84
+ const input = screen.getByRole( 'spinbutton', {
85
+ name: 'Font size',
86
+ } );
83
87
  await user.type( input, '80' );
84
88
  expect( onChange ).toHaveBeenCalledTimes( 2 ); // Once per keystroke.
85
89
  expect( onChange ).toHaveBeenCalledWith( expectedValue );
@@ -129,28 +133,14 @@ describe( 'FontSizePicker', () => {
129
133
  const options = screen.getAllByRole( 'option' );
130
134
  expect( options ).toHaveLength( 7 );
131
135
  expect( options[ 0 ] ).toHaveAccessibleName( 'Default' );
132
- expect( options[ 1 ] ).toHaveAccessibleName( 'Tiny 8' );
133
- expect( options[ 2 ] ).toHaveAccessibleName( 'Small 12' );
134
- expect( options[ 3 ] ).toHaveAccessibleName( 'Medium 16' );
135
- expect( options[ 4 ] ).toHaveAccessibleName( 'Large 20' );
136
- expect( options[ 5 ] ).toHaveAccessibleName( 'Extra Large 30' );
137
- expect( options[ 6 ] ).toHaveAccessibleName( 'xx-large 40' );
136
+ expect( options[ 1 ] ).toHaveAccessibleName( 'Tiny 8px' );
137
+ expect( options[ 2 ] ).toHaveAccessibleName( 'Small 12px' );
138
+ expect( options[ 3 ] ).toHaveAccessibleName( 'Medium 16px' );
139
+ expect( options[ 4 ] ).toHaveAccessibleName( 'Large 20px' );
140
+ expect( options[ 5 ] ).toHaveAccessibleName( 'Extra Large 30px' );
141
+ expect( options[ 6 ] ).toHaveAccessibleName( 'xx-large 40px' );
138
142
  } );
139
143
 
140
- test.each( [
141
- { value: undefined, expectedLabel: 'Size (px)' },
142
- { value: '8px', expectedLabel: 'Size (px)' },
143
- { value: '3px', expectedLabel: 'Size Custom' },
144
- ] )(
145
- 'displays $expectedLabel as label when value is $value',
146
- async ( { value, expectedLabel } ) => {
147
- await render(
148
- <FontSizePicker fontSizes={ fontSizes } value={ value } />
149
- );
150
- expect( screen.getByLabelText( expectedLabel ) ).toBeVisible();
151
- }
152
- );
153
-
154
144
  test.each( [
155
145
  {
156
146
  option: 'Default',
@@ -158,7 +148,7 @@ describe( 'FontSizePicker', () => {
158
148
  expectedArguments: [ undefined ],
159
149
  },
160
150
  {
161
- option: 'Tiny 8',
151
+ option: 'Tiny 8px',
162
152
  value: undefined,
163
153
  expectedArguments: [ '8px', fontSizes[ 0 ] ],
164
154
  },
@@ -255,23 +245,6 @@ describe( 'FontSizePicker', () => {
255
245
  }
256
246
  );
257
247
 
258
- test.each( [
259
- { value: undefined, expectedLabel: 'Size' },
260
- { value: '8px', expectedLabel: 'Size' },
261
- { value: '1em', expectedLabel: 'Size' },
262
- { value: '2rem', expectedLabel: 'Size' },
263
- { value: 'clamp(1.75rem, 3vw, 2.25rem)', expectedLabel: 'Size' },
264
- { value: '3px', expectedLabel: 'Size Custom' },
265
- ] )(
266
- 'displays $expectedLabel as label when value is $value',
267
- async ( { value, expectedLabel } ) => {
268
- await render(
269
- <FontSizePicker fontSizes={ fontSizes } value={ value } />
270
- );
271
- expect( screen.getByLabelText( expectedLabel ) ).toBeVisible();
272
- }
273
- );
274
-
275
248
  test.each( [
276
249
  {
277
250
  option: 'Default',
@@ -372,20 +345,6 @@ describe( 'FontSizePicker', () => {
372
345
  expect( options[ 4 ] ).toHaveAccessibleName( 'Gigantosaurus' );
373
346
  } );
374
347
 
375
- test.each( [
376
- { value: undefined, expectedLabel: 'Size' },
377
- { value: '12px', expectedLabel: 'Size Small' },
378
- { value: '40px', expectedLabel: 'Size Gigantosaurus' },
379
- ] )(
380
- 'displays $expectedLabel as label when value is $value',
381
- async ( { value, expectedLabel } ) => {
382
- await render(
383
- <FontSizePicker fontSizes={ fontSizes } value={ value } />
384
- );
385
- expect( screen.getByLabelText( expectedLabel ) ).toBeVisible();
386
- }
387
- );
388
-
389
348
  it( 'calls onChange when a font size is selected', async () => {
390
349
  const user = userEvent.setup();
391
350
  const onChange = jest.fn();
@@ -439,25 +398,6 @@ describe( 'FontSizePicker', () => {
439
398
  expect( options[ 3 ] ).toHaveAccessibleName( 'Extra Large' );
440
399
  } );
441
400
 
442
- test.each( [
443
- { value: undefined, expectedLabel: 'Size' },
444
- { value: '12px', expectedLabel: 'Size Small' },
445
- { value: '1em', expectedLabel: 'Size Medium' },
446
- { value: '2rem', expectedLabel: 'Size Large' },
447
- {
448
- value: 'clamp(1.75rem, 3vw, 2.25rem)',
449
- expectedLabel: 'Size Extra Large',
450
- },
451
- ] )(
452
- 'displays $expectedLabel as label when value is $value',
453
- async ( { value, expectedLabel } ) => {
454
- await render(
455
- <FontSizePicker fontSizes={ fontSizes } value={ value } />
456
- );
457
- expect( screen.getByLabelText( expectedLabel ) ).toBeVisible();
458
- }
459
- );
460
-
461
401
  test.each( [
462
402
  { radio: 'Small', expectedArguments: [ '12px', fontSizes[ 0 ] ] },
463
403
  { radio: 'Medium', expectedArguments: [ '1em', fontSizes[ 1 ] ] },
@@ -524,14 +464,18 @@ describe( 'FontSizePicker', () => {
524
464
  await render(
525
465
  <FontSizePicker fontSizes={ fontSizes } value="3px" />
526
466
  );
527
- expect( screen.getByLabelText( 'Custom' ) ).toBeVisible();
467
+ expect(
468
+ screen.getByRole( 'spinbutton', { name: 'Font size' } )
469
+ ).toBeVisible();
528
470
  } );
529
471
 
530
472
  it( 'hides custom input when disableCustomFontSizes is set to `true` with a custom font size', async () => {
531
473
  const { rerender } = await render(
532
474
  <FontSizePicker fontSizes={ fontSizes } value="3px" />
533
475
  );
534
- expect( screen.getByLabelText( 'Custom' ) ).toBeVisible();
476
+ expect(
477
+ screen.getByRole( 'spinbutton', { name: 'Font size' } )
478
+ ).toBeVisible();
535
479
 
536
480
  rerender(
537
481
  <FontSizePicker
@@ -549,7 +493,9 @@ describe( 'FontSizePicker', () => {
549
493
  const { rerender } = await render(
550
494
  <FontSizePicker fontSizes={ fontSizes } value="3px" />
551
495
  );
552
- expect( screen.getByLabelText( 'Custom' ) ).toBeVisible();
496
+ expect(
497
+ screen.getByRole( 'spinbutton', { name: 'Font size' } )
498
+ ).toBeVisible();
553
499
 
554
500
  rerender(
555
501
  <FontSizePicker
@@ -557,7 +503,9 @@ describe( 'FontSizePicker', () => {
557
503
  value={ fontSizes[ 0 ].size }
558
504
  />
559
505
  );
560
- expect( screen.getByLabelText( 'Custom' ) ).toBeVisible();
506
+ expect(
507
+ screen.getByRole( 'spinbutton', { name: 'Font size' } )
508
+ ).toBeVisible();
561
509
  } );
562
510
 
563
511
  it( 'allows custom values by default', async () => {
@@ -569,7 +517,10 @@ describe( 'FontSizePicker', () => {
569
517
  await user.click(
570
518
  screen.getByRole( 'button', { name: 'Set custom size' } )
571
519
  );
572
- await user.type( screen.getByLabelText( 'Custom' ), '80' );
520
+ await user.type(
521
+ screen.getByRole( 'spinbutton', { name: 'Font size' } ),
522
+ '80'
523
+ );
573
524
  expect( onChange ).toHaveBeenCalledTimes( 2 ); // Once per keystroke.
574
525
  expect( onChange ).toHaveBeenCalledWith( '80px' );
575
526
  } );
@@ -585,7 +536,10 @@ describe( 'FontSizePicker', () => {
585
536
  screen.getByRole( 'button', { name: 'Set custom size' } )
586
537
  );
587
538
 
588
- await user.type( screen.getByLabelText( 'Custom' ), '80' );
539
+ await user.type(
540
+ screen.getByRole( 'spinbutton', { name: 'Font size' } ),
541
+ '80'
542
+ );
589
543
 
590
544
  await user.click(
591
545
  screen.getByRole( 'button', { name: 'Use size preset' } )
@@ -632,7 +586,9 @@ describe( 'FontSizePicker', () => {
632
586
  await user.click(
633
587
  screen.getByRole( 'button', { name: 'Set custom size' } )
634
588
  );
635
- const sliderInput = screen.getByLabelText( 'Custom Size' );
589
+ const sliderInput = screen.getByRole( 'slider', {
590
+ name: 'Font size',
591
+ } );
636
592
  fireEvent.change( sliderInput, {
637
593
  target: { value: 80 },
638
594
  } );
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { isSimpleCssValue, getCommonSizeUnit } from '../utils';
4
+ import { isSimpleCssValue } from '../utils';
5
5
 
6
6
  describe( 'isSimpleCssValue', () => {
7
7
  test.each( [
@@ -31,39 +31,3 @@ describe( 'isSimpleCssValue', () => {
31
31
  expect( isSimpleCssValue( cssValue ) ).toBe( result );
32
32
  } );
33
33
  } );
34
-
35
- describe( 'getCommonSizeUnit', () => {
36
- it( 'returns null when fontSizes is empty', () => {
37
- expect( getCommonSizeUnit( [] ) ).toBe( null );
38
- } );
39
-
40
- it( 'returns px when all sizes are px', () => {
41
- expect(
42
- getCommonSizeUnit( [
43
- { slug: 'small', size: '10px' },
44
- { slug: 'medium', size: '20px' },
45
- { slug: 'large', size: '30px' },
46
- ] )
47
- ).toBe( 'px' );
48
- } );
49
-
50
- it( 'returns em when all sizes are em', () => {
51
- expect(
52
- getCommonSizeUnit( [
53
- { slug: 'small', size: '1em' },
54
- { slug: 'medium', size: '2em' },
55
- { slug: 'large', size: '3em' },
56
- ] )
57
- ).toBe( 'em' );
58
- } );
59
-
60
- it( 'returns null when sizes are heterogeneous', () => {
61
- expect(
62
- getCommonSizeUnit( [
63
- { slug: 'small', size: '10px' },
64
- { slug: 'medium', size: '2em' },
65
- { slug: 'large', size: '3rem' },
66
- ] )
67
- ).toBe( null );
68
- } );
69
- } );
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import type { FontSizePickerProps, FontSize } from './types';
5
- import { parseQuantityAndUnitFromRawValue } from '../unit-control';
4
+ import type { FontSizePickerProps } from './types';
6
5
 
7
6
  /**
8
7
  * Some themes use css vars for their font sizes, so until we
@@ -18,25 +17,3 @@ export function isSimpleCssValue(
18
17
  /^[\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;
19
18
  return sizeRegex.test( String( value ) );
20
19
  }
21
-
22
- /**
23
- * If all of the given font sizes have the same unit (e.g. 'px'), return that
24
- * unit. Otherwise return null.
25
- *
26
- * @param fontSizes List of font sizes.
27
- * @return The common unit, or null.
28
- */
29
- export function getCommonSizeUnit( fontSizes: FontSize[] ) {
30
- const [ firstFontSize, ...otherFontSizes ] = fontSizes;
31
- if ( ! firstFontSize ) {
32
- return null;
33
- }
34
- const [ , firstUnit ] = parseQuantityAndUnitFromRawValue(
35
- firstFontSize.size
36
- );
37
- const areAllSizesSameUnit = otherFontSizes.every( ( fontSize ) => {
38
- const [ , unit ] = parseQuantityAndUnitFromRawValue( fontSize.size );
39
- return unit === firstUnit;
40
- } );
41
- return areAllSizesSameUnit ? firstUnit : null;
42
- }
@@ -186,7 +186,7 @@
186
186
  color: $gray-600;
187
187
 
188
188
  &.is-selected {
189
- background-color: $components-color-accent-transparent-40;
189
+ background: color-mix(in srgb, $components-color-accent 4%, transparent);
190
190
  }
191
191
  }
192
192
 
@@ -18,7 +18,7 @@ import deprecated from '@wordpress/deprecated';
18
18
  */
19
19
  import { Input, SpinButton, styles } from './styles/number-control-styles';
20
20
  import * as inputControlActionTypes from '../input-control/reducer/actions';
21
- import { add, subtract, roundClamp } from '../utils/math';
21
+ import { add, subtract, clamp, ensureValidStep } from '../utils/math';
22
22
  import { ensureNumber, isValueEmpty } from '../utils/values';
23
23
  import type { WordPressComponentProps } from '../context/wordpress-component';
24
24
  import type { NumberControlProps } from './types';
@@ -78,17 +78,18 @@ function UnforwardedNumberControl(
78
78
  const isStepAny = step === 'any';
79
79
  const baseStep = isStepAny ? 1 : ensureNumber( step );
80
80
  const baseSpin = ensureNumber( spinFactor ) * baseStep;
81
- const baseValue = roundClamp( 0, min, max, baseStep );
82
81
  const constrainValue = (
83
82
  value: number | string,
84
83
  stepOverride?: number
85
84
  ) => {
86
- // When step is "any" clamp the value, otherwise round and clamp it.
87
- // Use '' + to convert to string for use in input value attribute.
88
- return isStepAny
89
- ? '' + Math.min( max, Math.max( min, ensureNumber( value ) ) )
90
- : '' + roundClamp( value, min, max, stepOverride ?? baseStep );
85
+ // When step is not "any" the value must be a valid step.
86
+ if ( ! isStepAny ) {
87
+ value = ensureValidStep( value, min, stepOverride ?? baseStep );
88
+ }
89
+
90
+ return `${ clamp( value, min, max ) }`;
91
91
  };
92
+ const baseValue = constrainValue( 0 );
92
93
 
93
94
  const autoComplete = typeProp === 'number' ? 'off' : undefined;
94
95
  const classes = clsx( 'components-number-control', className );