@wordpress/components 19.9.0 → 19.10.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 (185) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/CONTRIBUTING.md +80 -7
  3. package/build/angle-picker-control/angle-circle.js +5 -7
  4. package/build/angle-picker-control/angle-circle.js.map +1 -1
  5. package/build/box-control/index.js +0 -21
  6. package/build/box-control/index.js.map +1 -1
  7. package/build/box-control/utils.js +1 -8
  8. package/build/box-control/utils.js.map +1 -1
  9. package/build/button/index.js +3 -5
  10. package/build/button/index.js.map +1 -1
  11. package/build/circular-option-picker/index.js +1 -2
  12. package/build/circular-option-picker/index.js.map +1 -1
  13. package/build/disabled/index.js +4 -76
  14. package/build/disabled/index.js.map +1 -1
  15. package/build/input-control/index.js +3 -2
  16. package/build/input-control/index.js.map +1 -1
  17. package/build/input-control/styles/input-control-styles.js +42 -30
  18. package/build/input-control/styles/input-control-styles.js.map +1 -1
  19. package/build/mobile/bottom-sheet-select-control/index.native.js +1 -0
  20. package/build/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  21. package/build/popover/index.js +6 -52
  22. package/build/popover/index.js.map +1 -1
  23. package/build/select-control/index.js +31 -4
  24. package/build/select-control/index.js.map +1 -1
  25. package/build/select-control/styles/select-control-styles.js +8 -8
  26. package/build/select-control/styles/select-control-styles.js.map +1 -1
  27. package/build/text-control/index.js +35 -28
  28. package/build/text-control/index.js.map +1 -1
  29. package/build/text-control/types.js +6 -0
  30. package/build/text-control/types.js.map +1 -0
  31. package/build/toggle-group-control/toggle-group-control-option-icon/component.js +6 -4
  32. package/build/toggle-group-control/toggle-group-control-option-icon/component.js.map +1 -1
  33. package/build/tools-panel/tools-panel-header/component.js +52 -36
  34. package/build/tools-panel/tools-panel-header/component.js.map +1 -1
  35. package/build/unit-control/index.js +3 -3
  36. package/build/unit-control/index.js.map +1 -1
  37. package/build/unit-control/styles/unit-control-styles.js +11 -20
  38. package/build/unit-control/styles/unit-control-styles.js.map +1 -1
  39. package/build/unit-control/utils.js.map +1 -1
  40. package/build-module/angle-picker-control/angle-circle.js +5 -7
  41. package/build-module/angle-picker-control/angle-circle.js.map +1 -1
  42. package/build-module/box-control/index.js +1 -20
  43. package/build-module/box-control/index.js.map +1 -1
  44. package/build-module/box-control/utils.js +0 -6
  45. package/build-module/box-control/utils.js.map +1 -1
  46. package/build-module/button/index.js +3 -4
  47. package/build-module/button/index.js.map +1 -1
  48. package/build-module/circular-option-picker/index.js +1 -2
  49. package/build-module/circular-option-picker/index.js.map +1 -1
  50. package/build-module/disabled/index.js +5 -76
  51. package/build-module/disabled/index.js.map +1 -1
  52. package/build-module/input-control/index.js +3 -2
  53. package/build-module/input-control/index.js.map +1 -1
  54. package/build-module/input-control/styles/input-control-styles.js +42 -30
  55. package/build-module/input-control/styles/input-control-styles.js.map +1 -1
  56. package/build-module/mobile/bottom-sheet-select-control/index.native.js +1 -0
  57. package/build-module/mobile/bottom-sheet-select-control/index.native.js.map +1 -1
  58. package/build-module/popover/index.js +6 -52
  59. package/build-module/popover/index.js.map +1 -1
  60. package/build-module/select-control/index.js +29 -3
  61. package/build-module/select-control/index.js.map +1 -1
  62. package/build-module/select-control/styles/select-control-styles.js +8 -8
  63. package/build-module/select-control/styles/select-control-styles.js.map +1 -1
  64. package/build-module/text-control/index.js +35 -27
  65. package/build-module/text-control/index.js.map +1 -1
  66. package/build-module/text-control/types.js +2 -0
  67. package/build-module/text-control/types.js.map +1 -0
  68. package/build-module/toggle-group-control/toggle-group-control-option-icon/component.js +1 -5
  69. package/build-module/toggle-group-control/toggle-group-control-option-icon/component.js.map +1 -1
  70. package/build-module/tools-panel/tools-panel-header/component.js +51 -36
  71. package/build-module/tools-panel/tools-panel-header/component.js.map +1 -1
  72. package/build-module/unit-control/index.js +3 -3
  73. package/build-module/unit-control/index.js.map +1 -1
  74. package/build-module/unit-control/styles/unit-control-styles.js +11 -20
  75. package/build-module/unit-control/styles/unit-control-styles.js.map +1 -1
  76. package/build-module/unit-control/utils.js.map +1 -1
  77. package/build-style/style-rtl.css +7 -0
  78. package/build-style/style.css +7 -0
  79. package/build-types/button/index.d.ts.map +1 -1
  80. package/build-types/circular-option-picker/index.d.ts.map +1 -1
  81. package/build-types/color-picker/styles.d.ts +3 -3
  82. package/build-types/disabled/index.d.ts.map +1 -1
  83. package/build-types/input-control/index.d.ts +4 -3
  84. package/build-types/input-control/index.d.ts.map +1 -1
  85. package/build-types/input-control/stories/index.d.ts +5 -5
  86. package/build-types/input-control/stories/index.d.ts.map +1 -1
  87. package/build-types/input-control/styles/input-control-styles.d.ts +1 -0
  88. package/build-types/input-control/styles/input-control-styles.d.ts.map +1 -1
  89. package/build-types/input-control/types.d.ts +6 -0
  90. package/build-types/input-control/types.d.ts.map +1 -1
  91. package/build-types/number-control/styles/number-control-styles.d.ts +1 -1
  92. package/build-types/popover/index.d.ts +0 -1
  93. package/build-types/popover/index.d.ts.map +1 -1
  94. package/build-types/select-control/index.d.ts +30 -26
  95. package/build-types/select-control/index.d.ts.map +1 -1
  96. package/build-types/select-control/stories/index.d.ts +23 -0
  97. package/build-types/select-control/stories/index.d.ts.map +1 -0
  98. package/build-types/select-control/styles/select-control-styles.d.ts +3 -4
  99. package/build-types/select-control/styles/select-control-styles.d.ts.map +1 -1
  100. package/build-types/select-control/test/select-control.d.ts +2 -0
  101. package/build-types/select-control/test/select-control.d.ts.map +1 -0
  102. package/build-types/select-control/types.d.ts +52 -1
  103. package/build-types/select-control/types.d.ts.map +1 -1
  104. package/build-types/text-control/index.d.ts +32 -0
  105. package/build-types/text-control/index.d.ts.map +1 -0
  106. package/build-types/text-control/stories/index.d.ts +13 -0
  107. package/build-types/text-control/stories/index.d.ts.map +1 -0
  108. package/build-types/text-control/types.d.ts +25 -0
  109. package/build-types/text-control/types.d.ts.map +1 -0
  110. package/build-types/toggle-group-control/toggle-group-control-option-icon/component.d.ts.map +1 -1
  111. package/build-types/tools-panel/tools-panel-header/component.d.ts.map +1 -1
  112. package/build-types/tools-panel/types.d.ts +0 -1
  113. package/build-types/tools-panel/types.d.ts.map +1 -1
  114. package/build-types/unit-control/index.d.ts +2 -2
  115. package/build-types/unit-control/index.d.ts.map +1 -1
  116. package/build-types/unit-control/styles/unit-control-styles.d.ts.map +1 -1
  117. package/build-types/unit-control/test/index.d.ts +2 -0
  118. package/build-types/unit-control/test/index.d.ts.map +1 -0
  119. package/build-types/unit-control/test/utils.d.ts +2 -0
  120. package/build-types/unit-control/test/utils.d.ts.map +1 -0
  121. package/build-types/unit-control/types.d.ts +1 -1
  122. package/build-types/unit-control/types.d.ts.map +1 -1
  123. package/build-types/unit-control/utils.d.ts +3 -3
  124. package/build-types/unit-control/utils.d.ts.map +1 -1
  125. package/package.json +17 -17
  126. package/src/angle-picker-control/angle-circle.js +3 -3
  127. package/src/box-control/README.md +0 -74
  128. package/src/box-control/index.js +0 -15
  129. package/src/box-control/stories/index.js +0 -29
  130. package/src/box-control/utils.js +0 -7
  131. package/src/button/index.js +2 -4
  132. package/src/button/test/index.js +16 -1
  133. package/src/circular-option-picker/index.js +1 -2
  134. package/src/color-palette/README.md +0 -1
  135. package/src/color-palette/test/__snapshots__/index.js.snap +2 -3
  136. package/src/confirm-dialog/stories/index.js +87 -99
  137. package/src/date-time/stories/index.js +19 -0
  138. package/src/date-time/test/date.js +107 -78
  139. package/src/dimension-control/test/__snapshots__/index.test.js.snap +4 -4
  140. package/src/disabled/index.js +5 -90
  141. package/src/form-file-upload/test/index.js +15 -12
  142. package/src/input-control/README.md +1 -1
  143. package/src/input-control/index.tsx +3 -2
  144. package/src/input-control/stories/index.tsx +1 -1
  145. package/src/input-control/styles/input-control-styles.tsx +19 -5
  146. package/src/input-control/types.ts +6 -0
  147. package/src/menu-item/style.scss +10 -0
  148. package/src/mobile/bottom-sheet/bottom-sheet-navigation/test/navigation-container.native.js +8 -1
  149. package/src/mobile/bottom-sheet-select-control/index.native.js +1 -0
  150. package/src/mobile/html-text-input/style.android.scss +1 -0
  151. package/src/mobile/html-text-input/style.ios.scss +1 -0
  152. package/src/mobile/link-settings/test/link-settings-navigation.native.js +9 -1
  153. package/src/popover/index.js +5 -51
  154. package/src/select-control/README.md +2 -2
  155. package/src/select-control/index.tsx +30 -29
  156. package/src/select-control/stories/index.tsx +90 -0
  157. package/src/select-control/styles/select-control-styles.ts +9 -8
  158. package/src/select-control/test/{select-control.js → select-control.tsx} +2 -2
  159. package/src/select-control/types.ts +66 -1
  160. package/src/text-control/index.tsx +84 -0
  161. package/src/text-control/stories/index.tsx +66 -0
  162. package/src/text-control/types.ts +29 -0
  163. package/src/toggle-group-control/toggle-group-control-option-icon/component.tsx +1 -5
  164. package/src/tools-panel/test/__snapshots__/index.js.snap +1 -1
  165. package/src/tools-panel/test/index.js +71 -18
  166. package/src/tools-panel/tools-panel-header/component.tsx +75 -33
  167. package/src/tools-panel/types.ts +0 -1
  168. package/src/tooltip/test/index.js +6 -0
  169. package/src/unit-control/index.tsx +2 -5
  170. package/src/unit-control/styles/unit-control-styles.ts +3 -13
  171. package/src/unit-control/test/__snapshots__/index.tsx.snap +33 -0
  172. package/src/unit-control/test/{index.js → index.tsx} +214 -165
  173. package/src/unit-control/test/{utils.js → utils.ts} +38 -19
  174. package/src/unit-control/types.ts +4 -1
  175. package/src/unit-control/utils.ts +5 -3
  176. package/tsconfig.json +2 -1
  177. package/tsconfig.tsbuildinfo +1 -1
  178. package/build/box-control/visualizer.js +0 -165
  179. package/build/box-control/visualizer.js.map +0 -1
  180. package/build-module/box-control/visualizer.js +0 -154
  181. package/build-module/box-control/visualizer.js.map +0 -1
  182. package/src/box-control/visualizer.js +0 -116
  183. package/src/select-control/stories/index.js +0 -104
  184. package/src/text-control/index.js +0 -72
  185. package/src/text-control/stories/index.js +0 -46
@@ -1,19 +1,13 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { includes, debounce } from 'lodash';
5
4
  import classnames from 'classnames';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
9
8
  */
10
- import {
11
- createContext,
12
- useCallback,
13
- useLayoutEffect,
14
- useRef,
15
- } from '@wordpress/element';
16
- import { focus } from '@wordpress/dom';
9
+ import { __experimentalUseDisabled as useDisabled } from '@wordpress/compose';
10
+ import { createContext } from '@wordpress/element';
17
11
 
18
12
  /**
19
13
  * Internal dependencies
@@ -23,25 +17,6 @@ import { StyledWrapper } from './styles/disabled-styles';
23
17
  const Context = createContext( false );
24
18
  const { Consumer, Provider } = Context;
25
19
 
26
- /**
27
- * Names of control nodes which qualify for disabled behavior.
28
- *
29
- * See WHATWG HTML Standard: 4.10.18.5: "Enabling and disabling form controls: the disabled attribute".
30
- *
31
- * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute
32
- *
33
- * @type {string[]}
34
- */
35
- const DISABLED_ELIGIBLE_NODE_NAMES = [
36
- 'BUTTON',
37
- 'FIELDSET',
38
- 'INPUT',
39
- 'OPTGROUP',
40
- 'OPTION',
41
- 'SELECT',
42
- 'TEXTAREA',
43
- ];
44
-
45
20
  /**
46
21
  * @typedef OwnProps
47
22
  * @property {string} [className] Classname for the disabled element.
@@ -54,68 +29,8 @@ const DISABLED_ELIGIBLE_NODE_NAMES = [
54
29
  * @return {JSX.Element} Element wrapping the children to disable them when isDisabled is true.
55
30
  */
56
31
  function Disabled( { className, children, isDisabled = true, ...props } ) {
57
- /** @type {import('react').RefObject<HTMLDivElement>} */
58
- const node = useRef( null );
59
-
60
- const disable = () => {
61
- if ( ! node.current ) {
62
- return;
63
- }
64
-
65
- focus.focusable.find( node.current ).forEach( ( focusable ) => {
66
- if (
67
- includes( DISABLED_ELIGIBLE_NODE_NAMES, focusable.nodeName )
68
- ) {
69
- focusable.setAttribute( 'disabled', '' );
70
- }
71
-
72
- if ( focusable.nodeName === 'A' ) {
73
- focusable.setAttribute( 'tabindex', '-1' );
74
- }
75
-
76
- const tabIndex = focusable.getAttribute( 'tabindex' );
77
- if ( tabIndex !== null && tabIndex !== '-1' ) {
78
- focusable.removeAttribute( 'tabindex' );
79
- }
80
-
81
- if ( focusable.hasAttribute( 'contenteditable' ) ) {
82
- focusable.setAttribute( 'contenteditable', 'false' );
83
- }
84
- } );
85
- };
86
-
87
- // Debounce re-disable since disabling process itself will incur
88
- // additional mutations which should be ignored.
89
- const debouncedDisable = useCallback(
90
- debounce( disable, undefined, { leading: true } ),
91
- []
92
- );
93
-
94
- useLayoutEffect( () => {
95
- if ( ! isDisabled ) {
96
- return;
97
- }
98
-
99
- disable();
100
-
101
- /** @type {MutationObserver | undefined} */
102
- let observer;
103
- if ( node.current ) {
104
- observer = new window.MutationObserver( debouncedDisable );
105
- observer.observe( node.current, {
106
- childList: true,
107
- attributes: true,
108
- subtree: true,
109
- } );
110
- }
111
-
112
- return () => {
113
- if ( observer ) {
114
- observer.disconnect();
115
- }
116
- debouncedDisable.cancel();
117
- };
118
- }, [] );
32
+ /** @type {import('react').RefCallback<HTMLDivElement>} */
33
+ const ref = useDisabled();
119
34
 
120
35
  if ( ! isDisabled ) {
121
36
  return <Provider value={ false }>{ children }</Provider>;
@@ -124,7 +39,7 @@ function Disabled( { className, children, isDisabled = true, ...props } ) {
124
39
  return (
125
40
  <Provider value={ true }>
126
41
  <StyledWrapper
127
- ref={ node }
42
+ ref={ ref }
128
43
  className={ classnames( className, 'components-disabled' ) }
129
44
  { ...props }
130
45
  >
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render as RTLrender, screen } from '@testing-library/react';
4
+ import { render, screen } from '@testing-library/react';
5
5
  import userEvent from '@testing-library/user-event';
6
6
 
7
7
  /**
@@ -14,15 +14,9 @@ import FormFileUpload from '../';
14
14
  */
15
15
  const { File } = window;
16
16
 
17
- function render( jsx ) {
18
- return {
19
- user: userEvent.setup( {
20
- // Avoids timeout errors (https://github.com/testing-library/user-event/issues/565#issuecomment-1064579531).
21
- delay: null,
22
- } ),
23
- ...RTLrender( jsx ),
24
- };
25
- }
17
+ const user = userEvent.setup( {
18
+ advanceTimers: jest.advanceTimersByTime,
19
+ } );
26
20
 
27
21
  // @testing-library/user-event considers changing <input type="file"> to a string as a change, but it do not occur on real browsers, so the comparisons will be against this result
28
22
  const fakePath = expect.objectContaining( {
@@ -32,6 +26,15 @@ const fakePath = expect.objectContaining( {
32
26
  } );
33
27
 
34
28
  describe( 'FormFileUpload', () => {
29
+ beforeEach( () => {
30
+ jest.useFakeTimers();
31
+ } );
32
+
33
+ afterEach( () => {
34
+ jest.runOnlyPendingTimers();
35
+ jest.useRealTimers();
36
+ } );
37
+
35
38
  it( 'should show an Icon Button and a hidden input', () => {
36
39
  render( <FormFileUpload>My Upload Button</FormFileUpload> );
37
40
 
@@ -44,7 +47,7 @@ describe( 'FormFileUpload', () => {
44
47
  it( 'should not fire a change event after selecting the same file', async () => {
45
48
  const onChange = jest.fn();
46
49
 
47
- const { user } = render(
50
+ render(
48
51
  <FormFileUpload onChange={ onChange }>
49
52
  My Upload Button
50
53
  </FormFileUpload>
@@ -67,7 +70,7 @@ describe( 'FormFileUpload', () => {
67
70
  it( 'should fire a change event after selecting the same file if the value was reset in between', async () => {
68
71
  const onChange = jest.fn();
69
72
 
70
- const { user } = render(
73
+ render(
71
74
  <FormFileUpload
72
75
  onClick={ jest.fn( ( e ) => ( e.target.value = '' ) ) }
73
76
  onChange={ onChange }
@@ -18,7 +18,7 @@ const Example = () => {
18
18
  return (
19
19
  <InputControl
20
20
  value={ value }
21
- onChange={ ( nextValue ) => setValue( nextValue ) }
21
+ onChange={ ( nextValue ) => setValue( nextValue ?? '' ) }
22
22
  />
23
23
  );
24
24
  };
@@ -92,7 +92,7 @@ export function UnforwardedInputControl(
92
92
  * InputControl components let users enter and edit text. This is an experimental component
93
93
  * intended to (in time) merge with or replace `TextControl`.
94
94
  *
95
- * @example
95
+ * ```jsx
96
96
  * import { __experimentalInputControl as InputControl } from '@wordpress/components';
97
97
  * import { useState } from '@wordpress/compose';
98
98
  *
@@ -102,10 +102,11 @@ export function UnforwardedInputControl(
102
102
  * return (
103
103
  * <InputControl
104
104
  * value={ value }
105
- * onChange={ ( nextValue ) => setValue( nextValue ) }
105
+ * onChange={ ( nextValue ) => setValue( nextValue ?? '' ) }
106
106
  * />
107
107
  * );
108
108
  * };
109
+ * ```
109
110
  */
110
111
  export const InputControl = forwardRef( UnforwardedInputControl );
111
112
 
@@ -18,6 +18,7 @@ const meta: ComponentMeta< typeof InputControl > = {
18
18
  prefix: { control: { type: null } },
19
19
  suffix: { control: { type: null } },
20
20
  type: { control: { type: 'text' } },
21
+ value: { control: { disable: true } },
21
22
  },
22
23
  parameters: {
23
24
  controls: { expanded: true },
@@ -34,7 +35,6 @@ export const Default = Template.bind( {} );
34
35
  Default.args = {
35
36
  label: 'Value',
36
37
  placeholder: 'Placeholder',
37
- value: '',
38
38
  };
39
39
 
40
40
  export const WithPrefix = Template.bind( {} );
@@ -105,6 +105,7 @@ export const Container = styled.div< ContainerProps >`
105
105
  `;
106
106
 
107
107
  type InputProps = {
108
+ __next36pxDefaultSize?: boolean;
108
109
  disabled?: boolean;
109
110
  inputSize?: Size;
110
111
  isDragging?: boolean;
@@ -140,14 +141,17 @@ const fontSizeStyles = ( { inputSize: size }: InputProps ) => {
140
141
  `;
141
142
  };
142
143
 
143
- const sizeStyles = ( { inputSize: size }: InputProps ) => {
144
+ const sizeStyles = ( {
145
+ inputSize: size,
146
+ __next36pxDefaultSize,
147
+ }: InputProps ) => {
144
148
  const sizes = {
145
149
  default: {
146
- height: 30,
150
+ height: 36,
147
151
  lineHeight: 1,
148
- minHeight: 30,
149
- paddingLeft: 8,
150
- paddingRight: 8,
152
+ minHeight: 36,
153
+ paddingLeft: 16,
154
+ paddingRight: 16,
151
155
  },
152
156
  small: {
153
157
  height: 24,
@@ -165,6 +169,16 @@ const sizeStyles = ( { inputSize: size }: InputProps ) => {
165
169
  },
166
170
  };
167
171
 
172
+ if ( ! __next36pxDefaultSize ) {
173
+ sizes.default = {
174
+ height: 30,
175
+ lineHeight: 1,
176
+ minHeight: 30,
177
+ paddingLeft: 8,
178
+ paddingRight: 8,
179
+ };
180
+ }
181
+
168
182
  const style = sizes[ size as Size ] || sizes.default;
169
183
 
170
184
  return css( style );
@@ -27,6 +27,12 @@ export type DragProps = Parameters< Parameters< typeof useDrag >[ 0 ] >[ 0 ];
27
27
  export type Size = 'default' | 'small' | '__unstable-large';
28
28
 
29
29
  interface BaseProps {
30
+ /**
31
+ * Start opting into the larger default height that will become the default size in a future version.
32
+ *
33
+ * @default false
34
+ */
35
+ __next36pxDefaultSize?: boolean;
30
36
  __unstableInputWidth?: CSSProperties[ 'width' ];
31
37
  /**
32
38
  * If true, the label will only be visible to screen readers.
@@ -38,6 +38,16 @@
38
38
  margin-right: 0;
39
39
  }
40
40
  }
41
+
42
+ &:disabled,
43
+ &[aria-disabled="true"] {
44
+ // Override the button component's tertiary background and color.
45
+ &.is-tertiary {
46
+ background: none;
47
+ color: var(--wp-admin-theme-color-darker-10);
48
+ opacity: 0.3;
49
+ }
50
+ }
41
51
  }
42
52
 
43
53
  .components-menu-item__info-wrapper {
@@ -27,7 +27,14 @@ const TestScreen = ( { fullScreen, name, navigateTo } ) => {
27
27
  );
28
28
  };
29
29
 
30
- jest.useFakeTimers( 'legacy' );
30
+ beforeAll( () => {
31
+ jest.useFakeTimers( 'legacy' );
32
+ } );
33
+
34
+ afterAll( () => {
35
+ jest.runOnlyPendingTimers();
36
+ jest.useRealTimers();
37
+ } );
31
38
 
32
39
  it( 'animates height transitioning from non-full-screen to full-screen', async () => {
33
40
  const screen = render(
@@ -82,6 +82,7 @@ const BottomSheetSelectControl = ( {
82
82
  customActionButton
83
83
  separatorType="none"
84
84
  label={ item.label }
85
+ icon={ item.icon }
85
86
  onPress={ onChangeValue( item.value ) }
86
87
  leftAlign={ true }
87
88
  key={ index }
@@ -14,6 +14,7 @@
14
14
  padding-right: $padding;
15
15
  padding-top: $padding;
16
16
  padding-bottom: $padding;
17
+ margin-top: $padding * 2;
17
18
  }
18
19
 
19
20
  .scrollView {
@@ -20,4 +20,5 @@ $title-height: 32;
20
20
  padding-top: $padding;
21
21
  padding-bottom: $padding;
22
22
  height: $title-height;
23
+ margin-top: $padding * 2;
23
24
  }
@@ -9,7 +9,15 @@ import { render, fireEvent, waitFor } from 'test/helpers';
9
9
  */
10
10
  import LinkSettingsNavigation from '../link-settings-navigation';
11
11
 
12
- jest.useFakeTimers( 'legacy' );
12
+ beforeAll( () => {
13
+ jest.useFakeTimers( 'legacy' );
14
+ } );
15
+
16
+ afterAll( () => {
17
+ jest.runOnlyPendingTimers();
18
+ jest.useRealTimers();
19
+ } );
20
+
13
21
  jest.spyOn( Keyboard, 'dismiss' );
14
22
 
15
23
  const subject = (
@@ -47,7 +47,6 @@ function computeAnchorRect(
47
47
  anchorRect,
48
48
  getAnchorRect,
49
49
  anchorRef = false,
50
- shouldAnchorIncludePadding,
51
50
  container
52
51
  ) {
53
52
  if ( anchorRect ) {
@@ -98,17 +97,14 @@ function computeAnchorRect(
98
97
  container
99
98
  );
100
99
 
101
- if ( shouldAnchorIncludePadding ) {
102
- return rect;
103
- }
104
-
105
- return withoutPadding( rect, anchorRef );
100
+ return rect;
106
101
  }
107
102
 
108
103
  const { top, bottom } = anchorRef;
109
104
  const topRect = top.getBoundingClientRect();
110
105
  const bottomRect = bottom.getBoundingClientRect();
111
- const rect = offsetIframe(
106
+
107
+ return offsetIframe(
112
108
  new window.DOMRect(
113
109
  topRect.left,
114
110
  topRect.top,
@@ -118,12 +114,6 @@ function computeAnchorRect(
118
114
  top.ownerDocument,
119
115
  container
120
116
  );
121
-
122
- if ( shouldAnchorIncludePadding ) {
123
- return rect;
124
- }
125
-
126
- return withoutPadding( rect, anchorRef );
127
117
  }
128
118
 
129
119
  if ( ! anchorRefFallback.current ) {
@@ -131,45 +121,12 @@ function computeAnchorRect(
131
121
  }
132
122
 
133
123
  const { parentNode } = anchorRefFallback.current;
134
- const rect = offsetIframe(
124
+
125
+ return offsetIframe(
135
126
  parentNode.getBoundingClientRect(),
136
127
  parentNode.ownerDocument,
137
128
  container
138
129
  );
139
-
140
- if ( shouldAnchorIncludePadding ) {
141
- return rect;
142
- }
143
-
144
- return withoutPadding( rect, parentNode );
145
- }
146
-
147
- function getComputedStyle( node ) {
148
- return node.ownerDocument.defaultView.getComputedStyle( node );
149
- }
150
-
151
- function withoutPadding( rect, element ) {
152
- const {
153
- paddingTop,
154
- paddingBottom,
155
- paddingLeft,
156
- paddingRight,
157
- } = getComputedStyle( element );
158
- const top = paddingTop ? parseInt( paddingTop, 10 ) : 0;
159
- const bottom = paddingBottom ? parseInt( paddingBottom, 10 ) : 0;
160
- const left = paddingLeft ? parseInt( paddingLeft, 10 ) : 0;
161
- const right = paddingRight ? parseInt( paddingRight, 10 ) : 0;
162
-
163
- return {
164
- x: rect.left + left,
165
- y: rect.top + top,
166
- width: rect.width - left - right,
167
- height: rect.height - top - bottom,
168
- left: rect.left + left,
169
- right: rect.right - right,
170
- top: rect.top + top,
171
- bottom: rect.bottom - bottom,
172
- };
173
130
  }
174
131
 
175
132
  /**
@@ -252,7 +209,6 @@ const Popover = (
252
209
  range,
253
210
  focusOnMount = 'firstElement',
254
211
  anchorRef,
255
- shouldAnchorIncludePadding,
256
212
  anchorRect,
257
213
  getAnchorRect,
258
214
  expandOnMobile,
@@ -304,7 +260,6 @@ const Popover = (
304
260
  anchorRect,
305
261
  getAnchorRect,
306
262
  anchorRef,
307
- shouldAnchorIncludePadding,
308
263
  containerRef.current
309
264
  );
310
265
 
@@ -480,7 +435,6 @@ const Popover = (
480
435
  anchorRect,
481
436
  getAnchorRect,
482
437
  anchorRef,
483
- shouldAnchorIncludePadding,
484
438
  position,
485
439
  contentSize,
486
440
  __unstableStickyBoundaryElement,
@@ -114,7 +114,7 @@ Render a user interface to select multiple users from a list.
114
114
  this.setState( { users } );
115
115
  } }
116
116
  options={ [
117
- { value: null, label: 'Select a User', disabled: true },
117
+ { value: '', label: 'Select a User', disabled: true },
118
118
  { value: 'a', label: 'User A' },
119
119
  { value: 'b', label: 'User B' },
120
120
  { value: 'c', label: 'User c' },
@@ -194,7 +194,7 @@ If this property is added, multiple values can be selected. The value passed sho
194
194
  An array of objects containing the following properties:
195
195
 
196
196
  - `label`: (string) The label to be shown to the user.
197
- - `value`: (Object) The internal value used to choose the selected value. This is also the value passed to onChange when the option is selected.
197
+ - `value`: (string) The internal value used to choose the selected value. This is also the value passed to onChange when the option is selected.
198
198
  - `disabled`: (boolean) Whether or not the option should have the disabled attribute.
199
199
  - Type: `Array`
200
200
  - Required: No
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { isEmpty, noop } from 'lodash';
5
5
  import classNames from 'classnames';
6
- import type { ChangeEvent, FocusEvent, ReactNode, ForwardedRef } from 'react';
6
+ import type { ChangeEvent, FocusEvent, ForwardedRef } from 'react';
7
7
 
8
8
  /**
9
9
  * WordPress dependencies
@@ -17,10 +17,9 @@ import { Icon, chevronDown } from '@wordpress/icons';
17
17
  */
18
18
  import BaseControl from '../base-control';
19
19
  import InputBase from '../input-control/input-base';
20
- import type { InputBaseProps, LabelPosition } from '../input-control/types';
21
20
  import { Select, DownArrowWrapper } from './styles/select-control-styles';
22
- import type { Size } from './types';
23
21
  import type { WordPressComponentProps } from '../ui/context';
22
+ import type { SelectControlProps } from './types';
24
23
 
25
24
  function useUniqueId( idProp?: string ) {
26
25
  const instanceId = useInstanceId( SelectControl );
@@ -29,30 +28,7 @@ function useUniqueId( idProp?: string ) {
29
28
  return idProp || id;
30
29
  }
31
30
 
32
- export interface SelectControlProps
33
- extends Omit< InputBaseProps, 'children' | 'isFocused' > {
34
- help?: string;
35
- hideLabelFromVision?: boolean;
36
- multiple?: boolean;
37
- onBlur?: ( event: FocusEvent< HTMLSelectElement > ) => void;
38
- onFocus?: ( event: FocusEvent< HTMLSelectElement > ) => void;
39
- onChange?: (
40
- value: string | string[],
41
- extra?: { event?: ChangeEvent< HTMLSelectElement > }
42
- ) => void;
43
- options?: {
44
- label: string;
45
- value: string;
46
- id?: string;
47
- disabled?: boolean;
48
- }[];
49
- size?: Size;
50
- value?: string | string[];
51
- labelPosition?: LabelPosition;
52
- children?: ReactNode;
53
- }
54
-
55
- function SelectControl(
31
+ function UnforwardedSelectControl(
56
32
  {
57
33
  className,
58
34
  disabled = false,
@@ -165,6 +141,31 @@ function SelectControl(
165
141
  /* eslint-enable jsx-a11y/no-onchange */
166
142
  }
167
143
 
168
- const ForwardedComponent = forwardRef( SelectControl );
144
+ /**
145
+ * `SelectControl` allows users to select from a single or multiple option menu.
146
+ * It functions as a wrapper around the browser's native `<select>` element.
147
+ *
148
+ * @example
149
+ * import { SelectControl } from '@wordpress/components';
150
+ * import { useState } from '@wordpress/element';
151
+ *
152
+ * const MySelectControl = () => {
153
+ * const [ size, setSize ] = useState( '50%' );
154
+ *
155
+ * return (
156
+ * <SelectControl
157
+ * label="Size"
158
+ * value={ size }
159
+ * options={ [
160
+ * { label: 'Big', value: '100%' },
161
+ * { label: 'Medium', value: '50%' },
162
+ * { label: 'Small', value: '25%' },
163
+ * ] }
164
+ * onChange={ setSize }
165
+ * />
166
+ * );
167
+ * };
168
+ */
169
+ export const SelectControl = forwardRef( UnforwardedSelectControl );
169
170
 
170
- export default ForwardedComponent;
171
+ export default SelectControl;
@@ -0,0 +1,90 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ComponentMeta, ComponentStory } from '@storybook/react';
5
+ import type { ComponentProps } from 'react';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import { useState } from '@wordpress/element';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import SelectControl from '..';
16
+
17
+ const meta: ComponentMeta< typeof SelectControl > = {
18
+ title: 'Components/SelectControl',
19
+ component: SelectControl,
20
+ argTypes: {
21
+ help: { control: { type: 'text' } },
22
+ label: { control: { type: 'text' } },
23
+ prefix: { control: { type: 'text' } },
24
+ suffix: { control: { type: 'text' } },
25
+ value: { control: { type: null } },
26
+ },
27
+ parameters: {
28
+ controls: { expanded: true },
29
+ docs: { source: { state: 'open' } },
30
+ },
31
+ };
32
+ export default meta;
33
+
34
+ const SelectControlWithState: ComponentStory< typeof SelectControl > = (
35
+ args
36
+ ) => {
37
+ const [ selection, setSelection ] = useState<
38
+ ComponentProps< typeof SelectControl >[ 'value' ]
39
+ >();
40
+
41
+ return (
42
+ <SelectControl
43
+ { ...args }
44
+ value={ selection }
45
+ onChange={ setSelection }
46
+ />
47
+ );
48
+ };
49
+
50
+ export const Default = SelectControlWithState.bind( {} );
51
+ Default.args = {
52
+ options: [
53
+ { value: '', label: 'Select an Option', disabled: true },
54
+ { value: 'a', label: 'Option A' },
55
+ { value: 'b', label: 'Option B' },
56
+ { value: 'c', label: 'Option C' },
57
+ ],
58
+ };
59
+
60
+ export const WithLabelAndHelpText = SelectControlWithState.bind( {} );
61
+ WithLabelAndHelpText.args = {
62
+ ...Default.args,
63
+ help: 'Help text to explain the select control.',
64
+ label: 'Value',
65
+ };
66
+
67
+ /**
68
+ * As an alternative to the `options` prop, `optgroup`s and `options` can be
69
+ * passed in as `children` for more customizability.
70
+ */
71
+ export const WithCustomChildren: ComponentStory< typeof SelectControl > = (
72
+ args
73
+ ) => {
74
+ return (
75
+ <SelectControlWithState { ...args }>
76
+ <option value="option-1">Option 1</option>
77
+ <option value="option-2" disabled>
78
+ Option 2 - Disabled
79
+ </option>
80
+ <optgroup label="Option Group 1">
81
+ <option value="option-group-1-option-1">
82
+ Option Group 1 - Option 1
83
+ </option>
84
+ <option value="option-group-1-option-2" disabled>
85
+ Option Group 1 - Option 2 - Disabled
86
+ </option>
87
+ </optgroup>
88
+ </SelectControlWithState>
89
+ );
90
+ };