@wordpress/components 25.2.0 → 25.3.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 (144) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/button/index.js +13 -4
  3. package/build/button/index.js.map +1 -1
  4. package/build/confirm-dialog/component.js +9 -1
  5. package/build/confirm-dialog/component.js.map +1 -1
  6. package/build/font-size-picker/index.js +5 -3
  7. package/build/font-size-picker/index.js.map +1 -1
  8. package/build/font-size-picker/styles.js +19 -26
  9. package/build/font-size-picker/styles.js.map +1 -1
  10. package/build/guide/icons.js +2 -5
  11. package/build/guide/icons.js.map +1 -1
  12. package/build/guide/index.js +14 -11
  13. package/build/guide/index.js.map +1 -1
  14. package/build/guide/page-control.js +1 -3
  15. package/build/guide/page-control.js.map +1 -1
  16. package/build/item-group/styles.js +10 -10
  17. package/build/item-group/styles.js.map +1 -1
  18. package/build/mobile/bottom-sheet/cell.native.js +2 -1
  19. package/build/mobile/bottom-sheet/cell.native.js.map +1 -1
  20. package/build/number-control/index.js +8 -4
  21. package/build/number-control/index.js.map +1 -1
  22. package/build/number-control/styles/number-control-styles.js +9 -15
  23. package/build/number-control/styles/number-control-styles.js.map +1 -1
  24. package/build/range-control/index.js +7 -1
  25. package/build/range-control/index.js.map +1 -1
  26. package/build/range-control/input-range.js.map +1 -1
  27. package/build/range-control/styles/range-control-styles.js +35 -36
  28. package/build/range-control/styles/range-control-styles.js.map +1 -1
  29. package/build/select-control/index.js +2 -1
  30. package/build/select-control/index.js.map +1 -1
  31. package/build/unit-control/index.js +4 -2
  32. package/build/unit-control/index.js.map +1 -1
  33. package/build/z-stack/component.js +5 -3
  34. package/build/z-stack/component.js.map +1 -1
  35. package/build/z-stack/styles.js +23 -42
  36. package/build/z-stack/styles.js.map +1 -1
  37. package/build-module/button/index.js +13 -4
  38. package/build-module/button/index.js.map +1 -1
  39. package/build-module/confirm-dialog/component.js +10 -2
  40. package/build-module/confirm-dialog/component.js.map +1 -1
  41. package/build-module/font-size-picker/index.js +5 -4
  42. package/build-module/font-size-picker/index.js.map +1 -1
  43. package/build-module/font-size-picker/styles.js +17 -23
  44. package/build-module/font-size-picker/styles.js.map +1 -1
  45. package/build-module/guide/icons.js +2 -5
  46. package/build-module/guide/icons.js.map +1 -1
  47. package/build-module/guide/index.js +14 -10
  48. package/build-module/guide/index.js.map +1 -1
  49. package/build-module/guide/page-control.js +1 -3
  50. package/build-module/guide/page-control.js.map +1 -1
  51. package/build-module/item-group/styles.js +10 -10
  52. package/build-module/item-group/styles.js.map +1 -1
  53. package/build-module/mobile/bottom-sheet/cell.native.js +2 -1
  54. package/build-module/mobile/bottom-sheet/cell.native.js.map +1 -1
  55. package/build-module/number-control/index.js +8 -5
  56. package/build-module/number-control/index.js.map +1 -1
  57. package/build-module/number-control/styles/number-control-styles.js +7 -14
  58. package/build-module/number-control/styles/number-control-styles.js.map +1 -1
  59. package/build-module/range-control/index.js +6 -1
  60. package/build-module/range-control/index.js.map +1 -1
  61. package/build-module/range-control/input-range.js.map +1 -1
  62. package/build-module/range-control/styles/range-control-styles.js +35 -36
  63. package/build-module/range-control/styles/range-control-styles.js.map +1 -1
  64. package/build-module/select-control/index.js +2 -1
  65. package/build-module/select-control/index.js.map +1 -1
  66. package/build-module/unit-control/index.js +3 -2
  67. package/build-module/unit-control/index.js.map +1 -1
  68. package/build-module/z-stack/component.js +5 -3
  69. package/build-module/z-stack/component.js.map +1 -1
  70. package/build-module/z-stack/styles.js +22 -44
  71. package/build-module/z-stack/styles.js.map +1 -1
  72. package/build-style/style-rtl.css +19 -35
  73. package/build-style/style.css +19 -35
  74. package/build-types/button/deprecated.d.ts +6 -6
  75. package/build-types/button/index.d.ts.map +1 -1
  76. package/build-types/button/types.d.ts +16 -9
  77. package/build-types/button/types.d.ts.map +1 -1
  78. package/build-types/color-picker/styles.d.ts +2 -1
  79. package/build-types/color-picker/styles.d.ts.map +1 -1
  80. package/build-types/confirm-dialog/component.d.ts.map +1 -1
  81. package/build-types/font-size-picker/index.d.ts.map +1 -1
  82. package/build-types/font-size-picker/styles.d.ts +0 -6
  83. package/build-types/font-size-picker/styles.d.ts.map +1 -1
  84. package/build-types/guide/icons.d.ts +1 -3
  85. package/build-types/guide/icons.d.ts.map +1 -1
  86. package/build-types/guide/index.d.ts.map +1 -1
  87. package/build-types/guide/page-control.d.ts.map +1 -1
  88. package/build-types/navigator/navigator-back-button/component.d.ts +1 -1
  89. package/build-types/navigator/navigator-back-button/hook.d.ts +1 -1
  90. package/build-types/navigator/navigator-button/component.d.ts +1 -1
  91. package/build-types/navigator/navigator-button/hook.d.ts +1 -1
  92. package/build-types/navigator/navigator-to-parent-button/component.d.ts +1 -1
  93. package/build-types/number-control/index.d.ts.map +1 -1
  94. package/build-types/number-control/styles/number-control-styles.d.ts +5 -3
  95. package/build-types/number-control/styles/number-control-styles.d.ts.map +1 -1
  96. package/build-types/range-control/index.d.ts +15 -2
  97. package/build-types/range-control/index.d.ts.map +1 -1
  98. package/build-types/range-control/input-range.d.ts.map +1 -1
  99. package/build-types/range-control/styles/range-control-styles.d.ts +4 -2
  100. package/build-types/range-control/styles/range-control-styles.d.ts.map +1 -1
  101. package/build-types/range-control/types.d.ts +6 -0
  102. package/build-types/range-control/types.d.ts.map +1 -1
  103. package/build-types/select-control/index.d.ts.map +1 -1
  104. package/build-types/select-control/types.d.ts +6 -0
  105. package/build-types/select-control/types.d.ts.map +1 -1
  106. package/build-types/toolbar/toolbar-button/index.d.ts +6 -6
  107. package/build-types/unit-control/index.d.ts.map +1 -1
  108. package/build-types/z-stack/component.d.ts.map +1 -1
  109. package/build-types/z-stack/stories/index.d.ts.map +1 -1
  110. package/build-types/z-stack/styles.d.ts +5 -4
  111. package/build-types/z-stack/styles.d.ts.map +1 -1
  112. package/package.json +20 -20
  113. package/src/button/README.md +15 -0
  114. package/src/button/index.tsx +11 -4
  115. package/src/button/style.scss +13 -12
  116. package/src/button/test/index.tsx +13 -0
  117. package/src/button/types.ts +17 -9
  118. package/src/confirm-dialog/component.tsx +12 -2
  119. package/src/confirm-dialog/stories/index.js +8 -15
  120. package/src/confirm-dialog/test/index.js +42 -0
  121. package/src/dropdown-menu/style.scss +9 -13
  122. package/src/font-size-picker/index.tsx +9 -5
  123. package/src/font-size-picker/styles.ts +0 -10
  124. package/src/guide/icons.tsx +2 -7
  125. package/src/guide/index.tsx +14 -13
  126. package/src/guide/page-control.tsx +1 -5
  127. package/src/guide/style.scss +8 -24
  128. package/src/item-group/styles.ts +1 -1
  129. package/src/mobile/bottom-sheet/cell.native.js +1 -0
  130. package/src/modal/style.scss +3 -2
  131. package/src/number-control/index.tsx +6 -4
  132. package/src/number-control/styles/number-control-styles.ts +8 -16
  133. package/src/range-control/index.tsx +14 -2
  134. package/src/range-control/input-range.tsx +0 -1
  135. package/src/range-control/styles/range-control-styles.ts +12 -3
  136. package/src/range-control/types.ts +6 -0
  137. package/src/select-control/index.tsx +1 -0
  138. package/src/select-control/types.ts +6 -0
  139. package/src/unit-control/index.tsx +3 -2
  140. package/src/unit-control/test/index.tsx +5 -2
  141. package/src/z-stack/component.tsx +4 -2
  142. package/src/z-stack/stories/index.tsx +6 -13
  143. package/src/z-stack/styles.ts +23 -24
  144. package/tsconfig.tsbuildinfo +1 -1
@@ -194,6 +194,48 @@ describe( 'Confirm', () => {
194
194
  expect( confirmDialog ).not.toBeInTheDocument();
195
195
  expect( onConfirm ).toHaveBeenCalled();
196
196
  } );
197
+
198
+ it( 'calls only the `onCancel` callback and not the `onConfirm` callback when the cancel button is submitted using the keyboard', async () => {
199
+ const user = userEvent.setup();
200
+
201
+ const onConfirm = jest.fn().mockName( 'onConfirm()' );
202
+ const onCancel = jest.fn().mockName( 'onCancel()' );
203
+
204
+ render(
205
+ <ConfirmDialog
206
+ onConfirm={ onConfirm }
207
+ onCancel={ onCancel }
208
+ >
209
+ Are you sure?
210
+ </ConfirmDialog>
211
+ );
212
+
213
+ await user.keyboard( '[Tab][Enter]' );
214
+
215
+ expect( onConfirm ).not.toHaveBeenCalled();
216
+ expect( onCancel ).toHaveBeenCalledTimes( 1 );
217
+ } );
218
+
219
+ it( 'calls only the `onConfirm` callback when the confirm button is submitted using the keyboard', async () => {
220
+ const user = userEvent.setup();
221
+
222
+ const onConfirm = jest.fn().mockName( 'onConfirm()' );
223
+ const onCancel = jest.fn().mockName( 'onCancel()' );
224
+
225
+ render(
226
+ <ConfirmDialog
227
+ onConfirm={ onConfirm }
228
+ onCancel={ onCancel }
229
+ >
230
+ Are you sure?
231
+ </ConfirmDialog>
232
+ );
233
+
234
+ await user.keyboard( '[Tab][Tab][Enter]' );
235
+
236
+ expect( onConfirm ).toHaveBeenCalledTimes( 1 );
237
+ expect( onCancel ).not.toHaveBeenCalled();
238
+ } );
197
239
  } );
198
240
  } );
199
241
 
@@ -30,19 +30,15 @@
30
30
  height: 1px;
31
31
  }
32
32
 
33
- &.is-active svg {
34
- // Block UI appearance.
35
- color: $white;
36
- background: $gray-900;
37
- box-shadow: 0 0 0 $border-width $gray-900;
38
- border-radius: $border-width;
39
- }
40
-
41
- // Formatting buttons
42
- > svg {
43
- border-radius: $radius-block-ui;
44
- width: $button-size-small;
45
- height: $button-size-small;
33
+ &.is-active {
34
+ svg,
35
+ .dashicon {
36
+ // Block UI appearance.
37
+ color: $white;
38
+ background: $gray-900;
39
+ box-shadow: 0 0 0 $border-width $gray-900;
40
+ border-radius: $border-width;
41
+ }
46
42
  }
47
43
 
48
44
  // If menu items are icon-only, make them stretch only to the icon size.
@@ -14,6 +14,7 @@ import { useState, useMemo, forwardRef } from '@wordpress/element';
14
14
  /**
15
15
  * Internal dependencies
16
16
  */
17
+ import { Button } from '../button';
17
18
  import RangeControl from '../range-control';
18
19
  import { Flex, FlexItem } from '../flex';
19
20
  import {
@@ -31,7 +32,6 @@ import {
31
32
  HeaderLabel,
32
33
  HeaderToggle,
33
34
  Controls,
34
- ResetButton,
35
35
  } from './styles';
36
36
  import { Spacer } from '../spacer';
37
37
  import FontSizePickerSelect from './font-size-picker-select';
@@ -268,17 +268,21 @@ const UnforwardedFontSizePicker = (
268
268
  ) }
269
269
  { withReset && (
270
270
  <FlexItem>
271
- <ResetButton
271
+ <Button
272
272
  disabled={ value === undefined }
273
273
  onClick={ () => {
274
274
  onChange?.( undefined );
275
275
  } }
276
- isSmall
277
276
  variant="secondary"
278
- size={ size }
277
+ __next40pxDefaultSize
278
+ size={
279
+ size !== '__unstable-large'
280
+ ? 'small'
281
+ : 'default'
282
+ }
279
283
  >
280
284
  { __( 'Reset' ) }
281
- </ResetButton>
285
+ </Button>
282
286
  </FlexItem>
283
287
  ) }
284
288
  </Flex>
@@ -11,7 +11,6 @@ import Button from '../button';
11
11
  import { HStack } from '../h-stack';
12
12
  import { space } from '../ui/utils/space';
13
13
  import { COLORS } from '../utils';
14
- import type { FontSizePickerProps } from './types';
15
14
 
16
15
  export const Container = styled.fieldset`
17
16
  border: 0;
@@ -44,12 +43,3 @@ export const Controls = styled.div< {
44
43
  ${ ( props ) =>
45
44
  ! props.__nextHasNoMarginBottom && `margin-bottom: ${ space( 6 ) };` }
46
45
  `;
47
-
48
- export const ResetButton = styled( Button )< {
49
- size: FontSizePickerProps[ 'size' ];
50
- } >`
51
- &&& {
52
- height: ${ ( props ) =>
53
- props.size === '__unstable-large' ? '40px' : '30px' };
54
- }
55
- `;
@@ -3,13 +3,8 @@
3
3
  */
4
4
  import { SVG, Circle } from '@wordpress/primitives';
5
5
 
6
- export const PageControlIcon = ( { isSelected }: { isSelected: boolean } ) => (
6
+ export const PageControlIcon = () => (
7
7
  <SVG width="8" height="8" fill="none" xmlns="http://www.w3.org/2000/svg">
8
- <Circle
9
- cx="4"
10
- cy="4"
11
- r="4"
12
- fill={ isSelected ? '#419ECD' : '#E1E3E6' }
13
- />
8
+ <Circle cx="4" cy="4" r="4" />
14
9
  </SVG>
15
10
  );
@@ -9,7 +9,6 @@ import classnames from 'classnames';
9
9
  import { useState, useEffect, Children, useRef } from '@wordpress/element';
10
10
  import deprecated from '@wordpress/deprecated';
11
11
  import { __ } from '@wordpress/i18n';
12
- import { focus } from '@wordpress/dom';
13
12
 
14
13
  /**
15
14
  * Internal dependencies
@@ -59,9 +58,17 @@ function Guide( {
59
58
  onFinish,
60
59
  pages = [],
61
60
  }: GuideProps ) {
62
- const guideContainer = useRef< HTMLDivElement >( null );
61
+ const ref = useRef< HTMLDivElement >( null );
63
62
  const [ currentPage, setCurrentPage ] = useState( 0 );
64
63
 
64
+ useEffect( () => {
65
+ // Place focus at the top of the guide on mount and when the page changes.
66
+ const frame = ref.current?.querySelector( '.components-guide' );
67
+ if ( frame instanceof HTMLElement ) {
68
+ frame.focus();
69
+ }
70
+ }, [ currentPage ] );
71
+
65
72
  useEffect( () => {
66
73
  if ( Children.count( children ) ) {
67
74
  deprecated( 'Passing children to <Guide>', {
@@ -71,16 +78,6 @@ function Guide( {
71
78
  }
72
79
  }, [ children ] );
73
80
 
74
- useEffect( () => {
75
- // Each time we change the current page, start from the first element of the page.
76
- // This also solves any focus loss that can happen.
77
- if ( guideContainer.current ) {
78
- (
79
- focus.tabbable.find( guideContainer.current ) as HTMLElement[]
80
- )[ 0 ]?.focus();
81
- }
82
- }, [ currentPage ] );
83
-
84
81
  if ( Children.count( children ) ) {
85
82
  pages =
86
83
  Children.map( children, ( child ) => ( {
@@ -111,6 +108,7 @@ function Guide( {
111
108
  <Modal
112
109
  className={ classnames( 'components-guide', className ) }
113
110
  contentLabel={ contentLabel }
111
+ isDismissible={ pages.length > 1 }
114
112
  onRequestClose={ onFinish }
115
113
  onKeyDown={ ( event ) => {
116
114
  if ( event.code === 'ArrowLeft' ) {
@@ -123,7 +121,7 @@ function Guide( {
123
121
  event.preventDefault();
124
122
  }
125
123
  } }
126
- ref={ guideContainer }
124
+ ref={ ref }
127
125
  >
128
126
  <div className="components-guide__container">
129
127
  <div className="components-guide__page">
@@ -144,6 +142,7 @@ function Guide( {
144
142
  { canGoBack && (
145
143
  <Button
146
144
  className="components-guide__back-button"
145
+ variant="tertiary"
147
146
  onClick={ goBack }
148
147
  >
149
148
  { __( 'Previous' ) }
@@ -152,6 +151,7 @@ function Guide( {
152
151
  { canGoForward && (
153
152
  <Button
154
153
  className="components-guide__forward-button"
154
+ variant="primary"
155
155
  onClick={ goForward }
156
156
  >
157
157
  { __( 'Next' ) }
@@ -160,6 +160,7 @@ function Guide( {
160
160
  { ! canGoForward && (
161
161
  <Button
162
162
  className="components-guide__finish-button"
163
+ variant="primary"
163
164
  onClick={ onFinish }
164
165
  >
165
166
  { finishButtonText }
@@ -28,11 +28,7 @@ export default function PageControl( {
28
28
  >
29
29
  <Button
30
30
  key={ page }
31
- icon={
32
- <PageControlIcon
33
- isSelected={ page === currentPage }
34
- />
35
- }
31
+ icon={ <PageControlIcon /> }
36
32
  aria-label={ sprintf(
37
33
  /* translators: 1: current page number 2: total number of pages */
38
34
  __( 'Page %1$d of %2$d' ),
@@ -29,7 +29,7 @@
29
29
 
30
30
  &:hover {
31
31
  svg {
32
- fill: #fff;
32
+ fill: $white;
33
33
  }
34
34
  }
35
35
  }
@@ -57,7 +57,7 @@
57
57
  &__footer {
58
58
  align-content: center;
59
59
  display: flex;
60
- height: 30px;
60
+ height: $button-size;
61
61
  justify-content: center;
62
62
  margin: 0 0 $grid-unit-30 0;
63
63
  padding: 0 $grid-unit-40;
@@ -78,6 +78,11 @@
78
78
  height: 30px;
79
79
  min-width: 20px;
80
80
  margin: -6px 0;
81
+ color: $gray-200;
82
+ }
83
+
84
+ li[aria-current="step"] .components-button {
85
+ color: var(--wp-components-color-accent, var(--wp-admin-theme-color));
81
86
  }
82
87
  }
83
88
  }
@@ -85,7 +90,6 @@
85
90
  .components-modal__frame.components-guide {
86
91
  border: none;
87
92
  min-width: 312px;
88
- height: 80vh;
89
93
  max-height: 575px;
90
94
 
91
95
  @media ( max-width: $break-small ) {
@@ -98,34 +102,14 @@
98
102
  &.components-guide__back-button,
99
103
  &.components-guide__forward-button,
100
104
  &.components-guide__finish-button {
101
- height: 30px;
102
105
  position: absolute;
103
106
  }
104
107
 
105
- &.components-guide__back-button,
106
- &.components-guide__forward-button {
107
- font-size: $default-font-size;
108
- padding: 4px 2px;
109
-
110
- &.has-text svg {
111
- margin: 0;
112
- }
113
-
114
- &:hover {
115
- text-decoration: underline;
116
- }
117
- }
118
-
119
108
  &.components-guide__back-button {
120
109
  left: $grid-unit-40;
121
110
  }
122
111
 
123
- &.components-guide__forward-button {
124
- right: $grid-unit-40;
125
- color: #1386bf;
126
- font-weight: bold;
127
- }
128
-
112
+ &.components-guide__forward-button,
129
113
  &.components-guide__finish-button {
130
114
  right: $grid-unit-40;
131
115
  }
@@ -24,7 +24,7 @@ export const unstyledButton = css`
24
24
  color: ${ COLORS.ui.theme };
25
25
  }
26
26
 
27
- &:focus {
27
+ &:focus-visible {
28
28
  box-shadow: 0 0 0 var( --wp-admin-border-width-focus )
29
29
  var(
30
30
  --wp-components-color-accent,
@@ -431,6 +431,7 @@ class BottomSheetCell extends Component {
431
431
  <Icon
432
432
  icon={ check }
433
433
  fill={ platformStyles.isSelected.color }
434
+ testID="bottom-sheet-cell-selected-icon"
434
435
  />
435
436
  ) }
436
437
  { showValue && getValueComponent() }
@@ -72,7 +72,7 @@
72
72
  .components-modal__header {
73
73
  box-sizing: border-box;
74
74
  border-bottom: $border-width solid transparent;
75
- padding: $grid-unit-30 $grid-unit-40 $grid-unit-15;
75
+ padding: $grid-unit-30 $grid-unit-40 $grid-unit-10;
76
76
  display: flex;
77
77
  flex-direction: row;
78
78
  justify-content: space-between;
@@ -130,7 +130,8 @@
130
130
  .components-modal__content {
131
131
  flex: 1;
132
132
  margin-top: $header-height + $grid-unit-15;
133
- padding: 0 $grid-unit-40 $grid-unit-40;
133
+ // Small top padding required to avoid cutting off the visible outline when the first child element is focusable.
134
+ padding: $grid-unit-05 $grid-unit-40 $grid-unit-40;
134
135
  overflow: auto;
135
136
 
136
137
  &.hide-header {
@@ -16,7 +16,7 @@ import deprecated from '@wordpress/deprecated';
16
16
  /**
17
17
  * Internal dependencies
18
18
  */
19
- import { Input, SpinButton } from './styles/number-control-styles';
19
+ import { Input, SpinButton, styles } from './styles/number-control-styles';
20
20
  import * as inputControlActionTypes from '../input-control/reducer/actions';
21
21
  import { add, subtract, roundClamp } from '../utils/math';
22
22
  import { ensureNumber, isValueEmpty } from '../utils/values';
@@ -24,6 +24,7 @@ import type { WordPressComponentProps } from '../ui/context/wordpress-component'
24
24
  import type { NumberControlProps } from './types';
25
25
  import { HStack } from '../h-stack';
26
26
  import { Spacer } from '../spacer';
27
+ import { useCx } from '../utils';
27
28
 
28
29
  const noop = () => {};
29
30
 
@@ -59,7 +60,6 @@ function UnforwardedNumberControl(
59
60
  } );
60
61
  spinControls = 'none';
61
62
  }
62
-
63
63
  const inputRef = useRef< HTMLInputElement >();
64
64
  const mergedRef = useMergeRefs( [ inputRef, forwardedRef ] );
65
65
 
@@ -78,6 +78,8 @@ function UnforwardedNumberControl(
78
78
 
79
79
  const autoComplete = typeProp === 'number' ? 'off' : undefined;
80
80
  const classes = classNames( 'components-number-control', className );
81
+ const cx = useCx();
82
+ const spinButtonClasses = cx( size === 'small' && styles.smallSpinButtons );
81
83
 
82
84
  const spinValue = (
83
85
  value: string | number | undefined,
@@ -236,6 +238,7 @@ function UnforwardedNumberControl(
236
238
  <Spacer marginBottom={ 0 } marginRight={ 2 }>
237
239
  <HStack spacing={ 1 }>
238
240
  <SpinButton
241
+ className={ spinButtonClasses }
239
242
  icon={ plusIcon }
240
243
  isSmall
241
244
  aria-hidden="true"
@@ -244,9 +247,9 @@ function UnforwardedNumberControl(
244
247
  onClick={ buildSpinButtonClickHandler(
245
248
  'up'
246
249
  ) }
247
- size={ size }
248
250
  />
249
251
  <SpinButton
252
+ className={ spinButtonClasses }
250
253
  icon={ resetIcon }
251
254
  isSmall
252
255
  aria-hidden="true"
@@ -255,7 +258,6 @@ function UnforwardedNumberControl(
255
258
  onClick={ buildSpinButtonClickHandler(
256
259
  'down'
257
260
  ) }
258
- size={ size }
259
261
  />
260
262
  </HStack>
261
263
  </Spacer>
@@ -11,7 +11,6 @@ import InputControl from '../../input-control';
11
11
  import { COLORS } from '../../utils';
12
12
  import Button from '../../button';
13
13
  import { space } from '../../ui/utils/space';
14
- import type { NumberControlProps } from '../types';
15
14
 
16
15
  const htmlArrowStyles = ( { hideHTMLArrows }: { hideHTMLArrows: boolean } ) => {
17
16
  if ( ! hideHTMLArrows ) {
@@ -35,23 +34,16 @@ export const Input = styled( InputControl )`
35
34
  ${ htmlArrowStyles };
36
35
  `;
37
36
 
38
- const spinButtonSizeStyles = ( {
39
- size,
40
- }: Pick< NumberControlProps, 'size' > ) => {
41
- if ( size !== 'small' ) {
42
- return ``;
43
- }
44
-
45
- return css`
46
- width: ${ space( 5 ) };
47
- min-width: ${ space( 5 ) };
48
- height: ${ space( 5 ) };
49
- `;
50
- };
51
-
52
37
  export const SpinButton = styled( Button )`
53
38
  &&&&& {
54
39
  color: ${ COLORS.ui.theme };
55
- ${ spinButtonSizeStyles }
56
40
  }
57
41
  `;
42
+
43
+ const smallSpinButtons = css`
44
+ width: ${ space( 5 ) };
45
+ min-width: ${ space( 5 ) };
46
+ height: ${ space( 5 ) };
47
+ `;
48
+
49
+ export const styles = { smallSpinButtons };
@@ -37,6 +37,7 @@ import {
37
37
 
38
38
  import type { RangeControlProps } from './types';
39
39
  import type { WordPressComponentProps } from '../ui/context';
40
+ import { space } from '../ui/utils/space';
40
41
 
41
42
  const noop = () => {};
42
43
 
@@ -69,6 +70,7 @@ function UnforwardedRangeControl(
69
70
  railColor,
70
71
  renderTooltipContent = ( v ) => v,
71
72
  resetFallbackValue,
73
+ __next40pxDefaultSize = false,
72
74
  shiftStep = 10,
73
75
  showTooltip: showTooltipProp,
74
76
  step = 1,
@@ -208,7 +210,6 @@ function UnforwardedRangeControl(
208
210
  const offsetStyle = {
209
211
  [ isRTL() ? 'right' : 'left' ]: fillValueOffset,
210
212
  };
211
-
212
213
  return (
213
214
  <BaseControl
214
215
  __nextHasNoMarginBottom={ __nextHasNoMarginBottom }
@@ -218,7 +219,10 @@ function UnforwardedRangeControl(
218
219
  id={ `${ id }` }
219
220
  help={ help }
220
221
  >
221
- <Root className="components-range-control__root">
222
+ <Root
223
+ className="components-range-control__root"
224
+ __next40pxDefaultSize={ __next40pxDefaultSize }
225
+ >
222
226
  { beforeIcon && (
223
227
  <BeforeIconWrapper>
224
228
  <Icon icon={ beforeIcon } />
@@ -305,6 +309,14 @@ function UnforwardedRangeControl(
305
309
  onBlur={ handleOnInputNumberBlur }
306
310
  onChange={ handleOnChange }
307
311
  shiftStep={ shiftStep }
312
+ size={
313
+ __next40pxDefaultSize
314
+ ? '__unstable-large'
315
+ : 'default'
316
+ }
317
+ __unstableInputWidth={
318
+ __next40pxDefaultSize ? space( 20 ) : space( 16 )
319
+ }
308
320
  step={ step }
309
321
  // @ts-expect-error TODO: Investigate if the `null` value is necessary
310
322
  value={ inputSliderValue }
@@ -16,7 +16,6 @@ function InputRange(
16
16
  ref: React.ForwardedRef< HTMLInputElement >
17
17
  ) {
18
18
  const { describedBy, label, value, ...otherProps } = props;
19
-
20
19
  return (
21
20
  <BaseInputRange
22
21
  { ...otherProps }
@@ -18,6 +18,7 @@ import type {
18
18
  TooltipProps,
19
19
  TrackProps,
20
20
  WrapperProps,
21
+ RangeControlProps,
21
22
  } from '../types';
22
23
 
23
24
  const rangeHeightValue = 30;
@@ -26,15 +27,24 @@ const rangeHeight = () =>
26
27
  css( { height: rangeHeightValue, minHeight: rangeHeightValue } );
27
28
  const thumbSize = 12;
28
29
 
29
- export const Root = styled.div`
30
+ const deprecatedHeight = ( {
31
+ __next40pxDefaultSize,
32
+ }: Pick< RangeControlProps, '__next40pxDefaultSize' > ) =>
33
+ ! __next40pxDefaultSize && css( { minHeight: rangeHeightValue } );
34
+
35
+ type RootProps = Pick< RangeControlProps, '__next40pxDefaultSize' >;
36
+ export const Root = styled.div< RootProps >`
30
37
  -webkit-tap-highlight-color: transparent;
31
- align-items: flex-start;
38
+ align-items: center;
32
39
  display: flex;
33
40
  justify-content: flex-start;
34
41
  padding: 0;
35
42
  position: relative;
36
43
  touch-action: none;
37
44
  width: 100%;
45
+ min-height: 40px;
46
+ /* TODO: remove after removing the __next40pxDefaultSize prop */
47
+ ${ deprecatedHeight };
38
48
  `;
39
49
 
40
50
  const wrapperColor = ( { color = COLORS.ui.borderFocus }: WrapperProps ) =>
@@ -296,7 +306,6 @@ export const InputNumber = styled( NumberControl )`
296
306
  display: inline-block;
297
307
  font-size: 13px;
298
308
  margin-top: 0;
299
- width: ${ space( 16 ) } !important;
300
309
 
301
310
  input[type='number']& {
302
311
  ${ rangeHeight };
@@ -203,6 +203,12 @@ export type RangeControlProps = Pick<
203
203
  * @default 10
204
204
  */
205
205
  shiftStep?: number;
206
+ /**
207
+ * Start opting into the larger default height that will become the default size in a future version.
208
+ *
209
+ * @default false
210
+ */
211
+ __next40pxDefaultSize?: boolean;
206
212
  /**
207
213
  * Forcing the Tooltip UI to show or hide. This is overridden to `false`
208
214
  * when `step` is set to the special string value `any`.
@@ -135,6 +135,7 @@ function UnforwardedSelectControl(
135
135
  key={ key }
136
136
  value={ option.value }
137
137
  disabled={ option.disabled }
138
+ hidden={ option.hidden }
138
139
  >
139
140
  { option.label }
140
141
  </option>
@@ -40,6 +40,12 @@ type SelectControlBaseProps = Pick<
40
40
  * @default false
41
41
  */
42
42
  disabled?: boolean;
43
+ /**
44
+ * Whether or not the option should be hidden.
45
+ *
46
+ * @default false
47
+ */
48
+ hidden?: boolean;
43
49
  }[];
44
50
  /**
45
51
  * As an alternative to the `options` prop, `optgroup`s and `options` can be
@@ -24,6 +24,7 @@ import {
24
24
  getValidParsedQuantityAndUnit,
25
25
  } from './utils';
26
26
  import { useControlledState } from '../utils/hooks';
27
+ import { escapeRegExp } from '../utils/strings';
27
28
  import type { UnitControlProps, UnitControlOnChangeCallback } from './types';
28
29
 
29
30
  function UnforwardedUnitControl(
@@ -76,9 +77,9 @@ function UnforwardedUnitControl(
76
77
  );
77
78
  const [ { value: firstUnitValue = '' } = {}, ...rest ] = list;
78
79
  const firstCharacters = rest.reduce( ( carry, { value } ) => {
79
- const first = value?.substring( 0, 1 ) || '';
80
+ const first = escapeRegExp( value?.substring( 0, 1 ) || '' );
80
81
  return carry.includes( first ) ? carry : `${ carry }|${ first }`;
81
- }, firstUnitValue.substring( 0, 1 ) );
82
+ }, escapeRegExp( firstUnitValue.substring( 0, 1 ) ) );
82
83
  return [ list, new RegExp( `^(?:${ firstCharacters })$`, 'i' ) ];
83
84
  }, [ nonNullValueProp, unitProp, unitsProp ] );
84
85
  const [ parsedQuantity, parsedUnit ] = getParsedQuantityAndUnit(
@@ -373,18 +373,21 @@ describe( 'UnitControl', () => {
373
373
  const units = [
374
374
  { value: 'pt', label: 'pt', default: 0 },
375
375
  { value: 'vmax', label: 'vmax', default: 10 },
376
+ // Proves that units with regex control characters don't error.
377
+ { value: '+', label: '+', default: 10 },
376
378
  ];
377
379
 
378
380
  render( <UnitControl units={ units } /> );
379
381
 
380
382
  const options = getSelectOptions();
381
383
 
382
- expect( options.length ).toBe( 2 );
384
+ expect( options.length ).toBe( 3 );
383
385
 
384
- const [ pt, vmax ] = options;
386
+ const [ pt, vmax, plus ] = options;
385
387
 
386
388
  expect( pt.value ).toBe( 'pt' );
387
389
  expect( vmax.value ).toBe( 'vmax' );
390
+ expect( plus.value ).toBe( '+' );
388
391
  } );
389
392
 
390
393
  it( 'should reset value on unit change, if unit has default value', async () => {
@@ -35,13 +35,14 @@ function UnconnectedZStack(
35
35
 
36
36
  const clonedChildren = validChildren.map( ( child, index ) => {
37
37
  const zIndex = isReversed ? childrenLastIndex - index : index;
38
- const offsetAmount = offset * index;
38
+ // Only when the component is layered, the offset needs to be multiplied by
39
+ // the item's index, so that items can correctly stack at the right distance
40
+ const offsetAmount = isLayered ? offset * index : offset;
39
41
 
40
42
  const key = isValidElement( child ) ? child.key : index;
41
43
 
42
44
  return (
43
45
  <ZStackChildView
44
- isLayered={ isLayered }
45
46
  offsetAmount={ offsetAmount }
46
47
  zIndex={ zIndex }
47
48
  key={ key }
@@ -55,6 +56,7 @@ function UnconnectedZStack(
55
56
  <ZStackView
56
57
  { ...otherProps }
57
58
  className={ className }
59
+ isLayered={ isLayered }
58
60
  ref={ forwardedRef }
59
61
  >
60
62
  { clonedChildren }