@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
@@ -8,11 +8,12 @@ import styled from '@emotion/styled';
8
8
  * Internal dependencies
9
9
  */
10
10
  import { COLORS, rtl } from '../../utils';
11
- import type { Size } from '../types';
11
+ import type { SelectControlProps } from '../types';
12
12
 
13
- interface SelectProps {
14
- disabled?: boolean;
15
- selectSize?: Size;
13
+ interface SelectProps extends Pick< SelectControlProps, 'disabled' > {
14
+ // Using `selectSize` instead of `size` to avoid a type conflict with the
15
+ // `size` HTML attribute of the `select` element.
16
+ selectSize?: SelectControlProps[ 'size' ];
16
17
  }
17
18
 
18
19
  const disabledStyles = ( { disabled }: SelectProps ) => {
@@ -23,14 +24,14 @@ const disabledStyles = ( { disabled }: SelectProps ) => {
23
24
  } );
24
25
  };
25
26
 
26
- const fontSizeStyles = ( { selectSize }: SelectProps ) => {
27
+ const fontSizeStyles = ( { selectSize = 'default' }: SelectProps ) => {
27
28
  const sizes = {
28
29
  default: '13px',
29
30
  small: '11px',
30
31
  '__unstable-large': '13px',
31
32
  };
32
33
 
33
- const fontSize = sizes[ selectSize as Size ];
34
+ const fontSize = sizes[ selectSize ];
34
35
  const fontSizeMobile = '16px';
35
36
 
36
37
  if ( ! fontSize ) return '';
@@ -44,7 +45,7 @@ const fontSizeStyles = ( { selectSize }: SelectProps ) => {
44
45
  `;
45
46
  };
46
47
 
47
- const sizeStyles = ( { selectSize }: SelectProps ) => {
48
+ const sizeStyles = ( { selectSize = 'default' }: SelectProps ) => {
48
49
  const sizes = {
49
50
  default: {
50
51
  height: 30,
@@ -63,7 +64,7 @@ const sizeStyles = ( { selectSize }: SelectProps ) => {
63
64
  },
64
65
  };
65
66
 
66
- const style = sizes[ selectSize as Size ] || sizes.default;
67
+ const style = sizes[ selectSize ];
67
68
 
68
69
  return css( style );
69
70
  };
@@ -32,7 +32,7 @@ describe( 'SelectControl', () => {
32
32
 
33
33
  expect( screen.getByText( 'Option 1' ) ).toBeInTheDocument();
34
34
 
35
- const selectElement = screen.queryByLabelText( 'Select' );
35
+ const selectElement = screen.getByLabelText( 'Select' );
36
36
 
37
37
  fireEvent.change( selectElement, {
38
38
  target: { value: 'option-group-option-1' },
@@ -68,7 +68,7 @@ describe( 'SelectControl', () => {
68
68
 
69
69
  expect( screen.getByText( 'Option 1' ) ).toBeInTheDocument();
70
70
 
71
- const selectElement = screen.queryByLabelText( 'Select' );
71
+ const selectElement = screen.getByLabelText( 'Select' );
72
72
 
73
73
  fireEvent.change( selectElement, {
74
74
  target: { value: 'option-2' },
@@ -1 +1,66 @@
1
- export type Size = 'default' | 'small' | '__unstable-large';
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ChangeEvent, FocusEvent, ReactNode } from 'react';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type { InputBaseProps } from '../input-control/types';
10
+ import type { BaseControlProps } from '../base-control/types';
11
+
12
+ export interface SelectControlProps
13
+ extends Pick<
14
+ InputBaseProps,
15
+ | 'disabled'
16
+ | 'hideLabelFromVision'
17
+ | 'label'
18
+ | 'labelPosition'
19
+ | 'prefix'
20
+ | 'size'
21
+ | 'suffix'
22
+ >,
23
+ Pick< BaseControlProps, 'help' > {
24
+ /**
25
+ * If this property is added, multiple values can be selected. The value passed should be an array.
26
+ *
27
+ * @default false
28
+ */
29
+ multiple?: boolean;
30
+ onBlur?: ( event: FocusEvent< HTMLSelectElement > ) => void;
31
+ onFocus?: ( event: FocusEvent< HTMLSelectElement > ) => void;
32
+ /**
33
+ * A function that receives the value of the new option that is being selected as input.
34
+ *
35
+ * If `multiple` is `true`, the value received is an array of the selected value.
36
+ * Otherwise, the value received is a single value with the new selected value.
37
+ */
38
+ onChange?: (
39
+ value: string | string[],
40
+ extra?: { event?: ChangeEvent< HTMLSelectElement > }
41
+ ) => void;
42
+ options?: {
43
+ /**
44
+ * The label to be shown to the user.
45
+ */
46
+ label: string;
47
+ /**
48
+ * The internal value used to choose the selected value.
49
+ * This is also the value passed to `onChange` when the option is selected.
50
+ */
51
+ value: string;
52
+ id?: string;
53
+ /**
54
+ * Whether or not the option should have the disabled attribute.
55
+ *
56
+ * @default false
57
+ */
58
+ disabled?: boolean;
59
+ }[];
60
+ value?: string | string[];
61
+ /**
62
+ * As an alternative to the `options` prop, `optgroup`s and `options` can be
63
+ * passed in as `children` for more customizability.
64
+ */
65
+ children?: ReactNode;
66
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ChangeEvent, ForwardedRef } from 'react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useInstanceId } from '@wordpress/compose';
10
+ import { forwardRef } from '@wordpress/element';
11
+
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import BaseControl from '../base-control';
16
+ import type { WordPressComponentProps } from '../ui/context';
17
+ import type { TextControlProps } from './types';
18
+
19
+ function UnforwardedTextControl(
20
+ props: WordPressComponentProps< TextControlProps, 'input', false >,
21
+ ref: ForwardedRef< HTMLInputElement >
22
+ ) {
23
+ const {
24
+ label,
25
+ hideLabelFromVision,
26
+ value,
27
+ help,
28
+ className,
29
+ onChange,
30
+ type = 'text',
31
+ ...additionalProps
32
+ } = props;
33
+ const instanceId = useInstanceId( TextControl );
34
+ const id = `inspector-text-control-${ instanceId }`;
35
+ const onChangeValue = ( event: ChangeEvent< HTMLInputElement > ) =>
36
+ onChange( event.target.value );
37
+
38
+ return (
39
+ <BaseControl
40
+ label={ label }
41
+ hideLabelFromVision={ hideLabelFromVision }
42
+ id={ id }
43
+ help={ help }
44
+ className={ className }
45
+ >
46
+ <input
47
+ className="components-text-control__input"
48
+ type={ type }
49
+ id={ id }
50
+ value={ value }
51
+ onChange={ onChangeValue }
52
+ aria-describedby={ !! help ? id + '__help' : undefined }
53
+ ref={ ref }
54
+ { ...additionalProps }
55
+ />
56
+ </BaseControl>
57
+ );
58
+ }
59
+
60
+ /**
61
+ * TextControl components let users enter and edit text.
62
+ *
63
+ *
64
+ * @example
65
+ * ```jsx
66
+ * import { TextControl } from '@wordpress/components';
67
+ * import { useState } from '@wordpress/element';
68
+ *
69
+ * const MyTextControl = () => {
70
+ * const [ className, setClassName ] = useState( '' );
71
+ *
72
+ * return (
73
+ * <TextControl
74
+ * label="Additional CSS Class"
75
+ * value={ className }
76
+ * onChange={ ( value ) => setClassName( value ) }
77
+ * />
78
+ * );
79
+ * };
80
+ * ```
81
+ */
82
+ export const TextControl = forwardRef( UnforwardedTextControl );
83
+
84
+ export default TextControl;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ComponentMeta, ComponentStory } from '@storybook/react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useState } from '@wordpress/element';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import TextControl from '..';
15
+
16
+ const meta: ComponentMeta< typeof TextControl > = {
17
+ component: TextControl,
18
+ title: 'Components/TextControl',
19
+ argTypes: {
20
+ onChange: {
21
+ action: 'onChange',
22
+ },
23
+ value: {
24
+ control: { type: null },
25
+ },
26
+ },
27
+ parameters: {
28
+ controls: {
29
+ expanded: true,
30
+ },
31
+ docs: { source: { state: 'open' } },
32
+ },
33
+ };
34
+ export default meta;
35
+
36
+ const DefaultTemplate: ComponentStory< typeof TextControl > = ( {
37
+ onChange,
38
+ ...args
39
+ } ) => {
40
+ const [ value, setValue ] = useState( '' );
41
+
42
+ return (
43
+ <TextControl
44
+ { ...args }
45
+ value={ value }
46
+ onChange={ ( v ) => {
47
+ setValue( v );
48
+ onChange( v );
49
+ } }
50
+ />
51
+ );
52
+ };
53
+
54
+ export const Default: ComponentStory<
55
+ typeof TextControl
56
+ > = DefaultTemplate.bind( {} );
57
+ Default.args = {};
58
+
59
+ export const WithLabelAndHelpText: ComponentStory<
60
+ typeof TextControl
61
+ > = DefaultTemplate.bind( {} );
62
+ WithLabelAndHelpText.args = {
63
+ ...Default.args,
64
+ label: 'Label Text',
65
+ help: 'Help text to explain the input.',
66
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { HTMLInputTypeAttribute } from 'react';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type { BaseControlProps } from '../base-control/types';
10
+
11
+ export type TextControlProps = Pick<
12
+ BaseControlProps,
13
+ 'className' | 'hideLabelFromVision' | 'help' | 'label'
14
+ > & {
15
+ /**
16
+ * A function that receives the value of the input.
17
+ */
18
+ onChange: ( value: string ) => void;
19
+ /**
20
+ * The current value of the input.
21
+ */
22
+ value: string | number;
23
+ /**
24
+ * Type of the input element to render. Defaults to "text".
25
+ *
26
+ * @default 'text'
27
+ */
28
+ type?: HTMLInputTypeAttribute;
29
+ };
@@ -1,14 +1,10 @@
1
- /**
2
- * WordPress dependencies
3
- */
4
- import { Icon } from '@wordpress/icons';
5
-
6
1
  /**
7
2
  * Internal dependencies
8
3
  */
9
4
  import type { WordPressComponentProps } from '../../ui/context';
10
5
  import type { ToggleGroupControlOptionIconProps } from '../types';
11
6
  import { ToggleGroupControlOptionBase } from '../toggle-group-control-option-base';
7
+ import Icon from '../../icon';
12
8
 
13
9
  export default function ToggleGroupControlOptionIcon(
14
10
  props: WordPressComponentProps<
@@ -167,7 +167,7 @@ exports[`ToolsPanel first and last panel items should apply first/last classes t
167
167
  <button
168
168
  aria-expanded="false"
169
169
  aria-haspopup="true"
170
- aria-label="View options"
170
+ aria-label="Panel header options"
171
171
  class="components-button components-dropdown-menu__toggle is-small has-icon"
172
172
  type="button"
173
173
  >
@@ -161,7 +161,7 @@ const renderPanel = () => {
161
161
  */
162
162
  const getMenuButton = () => {
163
163
  return screen.getByRole( 'button', {
164
- name: /view([\w\s]+)options/i,
164
+ name: /Panel([\w\s]+)header([\w\s]+)options/i,
165
165
  } );
166
166
  };
167
167
 
@@ -178,7 +178,6 @@ const openDropdownMenu = () => {
178
178
 
179
179
  // Opens dropdown then selects the menu item by label before simulating a click.
180
180
  const selectMenuItem = async ( label ) => {
181
- openDropdownMenu();
182
181
  const menuItem = await screen.findByText( label );
183
182
  fireEvent.click( menuItem );
184
183
  };
@@ -289,18 +288,30 @@ describe( 'ToolsPanel', () => {
289
288
 
290
289
  it( 'should render panel item when corresponding menu item is selected', async () => {
291
290
  renderPanel();
291
+ await openDropdownMenu();
292
292
  await selectMenuItem( altControlProps.label );
293
293
  const control = await screen.findByText( 'Alt control' );
294
294
 
295
295
  expect( control ).toBeInTheDocument();
296
+
297
+ // Test the aria live announcement.
298
+ const announcement = await screen.getByText( 'Alt is now visible' );
299
+ expect( announcement ).toHaveAttribute( 'aria-live', 'assertive' );
296
300
  } );
297
301
 
298
302
  it( 'should prevent optional panel item rendering when toggled off via menu item', async () => {
299
303
  renderPanel();
304
+ await openDropdownMenu();
300
305
  await selectMenuItem( controlProps.label );
301
306
  const control = screen.queryByText( 'Example control' );
302
307
 
303
308
  expect( control ).not.toBeInTheDocument();
309
+
310
+ // Test the aria live announcement.
311
+ const announcement = await screen.getByText(
312
+ 'Example hidden and reset to default'
313
+ );
314
+ expect( announcement ).toHaveAttribute( 'aria-live', 'assertive' );
304
315
  } );
305
316
 
306
317
  it( 'should continue to render shown by default item after it is toggled off via menu item', async () => {
@@ -319,10 +330,17 @@ describe( 'ToolsPanel', () => {
319
330
 
320
331
  expect( control ).toBeInTheDocument();
321
332
 
333
+ await openDropdownMenu();
322
334
  await selectMenuItem( controlProps.label );
323
335
  const resetControl = screen.getByText( 'Default control' );
324
336
 
325
337
  expect( resetControl ).toBeInTheDocument();
338
+
339
+ // Test the aria live announcement.
340
+ const announcement = await screen.getByText(
341
+ 'Example reset to default'
342
+ );
343
+ expect( announcement ).toHaveAttribute( 'aria-live', 'assertive' );
326
344
  } );
327
345
 
328
346
  it( 'should render appropriate menu groups', async () => {
@@ -657,6 +675,8 @@ describe( 'ToolsPanel', () => {
657
675
 
658
676
  it( 'should call onDeselect callback when menu item is toggled off', async () => {
659
677
  renderPanel();
678
+
679
+ await openDropdownMenu();
660
680
  await selectMenuItem( controlProps.label );
661
681
 
662
682
  expect( controlProps.onSelect ).not.toHaveBeenCalled();
@@ -665,6 +685,8 @@ describe( 'ToolsPanel', () => {
665
685
 
666
686
  it( 'should call onSelect callback when menu item is toggled on', async () => {
667
687
  renderPanel();
688
+
689
+ await openDropdownMenu();
668
690
  await selectMenuItem( altControlProps.label );
669
691
 
670
692
  expect( altControlProps.onSelect ).toHaveBeenCalledTimes( 1 );
@@ -673,6 +695,8 @@ describe( 'ToolsPanel', () => {
673
695
 
674
696
  it( 'should call resetAll callback when its menu item is selected', async () => {
675
697
  renderPanel();
698
+
699
+ await openDropdownMenu();
676
700
  await selectMenuItem( 'Reset all' );
677
701
 
678
702
  expect( resetAll ).toHaveBeenCalledTimes( 1 );
@@ -688,6 +712,7 @@ describe( 'ToolsPanel', () => {
688
712
  it( 'should call onDeselect after previous reset all', async () => {
689
713
  renderPanel();
690
714
 
715
+ await openDropdownMenu();
691
716
  await selectMenuItem( 'Reset all' ); // Initial control is displayed by default.
692
717
  await selectMenuItem( controlProps.label ); // Re-display control.
693
718
 
@@ -715,9 +740,8 @@ describe( 'ToolsPanel', () => {
715
740
  openDropdownMenu();
716
741
 
717
742
  const defaultItem = screen.getByText( 'Nested Control 1' );
718
- const defaultMenuItem = screen.getByRole( 'menuitemcheckbox', {
743
+ const defaultMenuItem = screen.getByRole( 'menuitem', {
719
744
  name: 'Reset Nested Control 1',
720
- checked: true,
721
745
  } );
722
746
 
723
747
  const altItem = screen.getByText( 'Nested Control 2' );
@@ -754,9 +778,8 @@ describe( 'ToolsPanel', () => {
754
778
  openDropdownMenu();
755
779
 
756
780
  const defaultItem = screen.getByText( 'Nested Control 1' );
757
- const defaultMenuItem = screen.getByRole( 'menuitemcheckbox', {
781
+ const defaultMenuItem = screen.getByRole( 'menuitem', {
758
782
  name: 'Reset Nested Control 1',
759
- checked: true,
760
783
  } );
761
784
 
762
785
  const altItem = screen.getByText( 'Nested Control 2' );
@@ -807,6 +830,7 @@ describe( 'ToolsPanel', () => {
807
830
  expect( secondItem ).toBeInTheDocument();
808
831
 
809
832
  // Toggle on the first item.
833
+ await openDropdownMenu();
810
834
  await selectMenuItem( altControlProps.label );
811
835
 
812
836
  // The order of items should be as per their original source order.
@@ -964,7 +988,7 @@ describe( 'ToolsPanel', () => {
964
988
  isShownByDefault: false,
965
989
  };
966
990
 
967
- it( 'should render appropriate icon for the dropdown menu where there are default controls', async () => {
991
+ it( 'should render appropriate labels and descriptions for the dropdown menu where there are default controls', async () => {
968
992
  render(
969
993
  <ToolsPanel { ...defaultProps }>
970
994
  <ToolsPanelItem { ...defaultControls }>
@@ -977,13 +1001,18 @@ describe( 'ToolsPanel', () => {
977
1001
  );
978
1002
 
979
1003
  const optionsDisplayedIcon = screen.getByRole( 'button', {
980
- name: 'View options',
1004
+ name: 'Panel header options',
981
1005
  } );
982
1006
 
983
1007
  expect( optionsDisplayedIcon ).toBeInTheDocument();
1008
+
1009
+ // The dropdown toggle doesn't have a description when an option is displayed.
1010
+ // In this case the default control is displayed.
1011
+ expect( optionsDisplayedIcon ).not.toHaveAccessibleDescription();
984
1012
  } );
985
1013
 
986
- it( 'should render appropriate icons for the dropdown menu where there are no default controls', async () => {
1014
+ it( 'should render appropriate labels and descriptions for the dropdown menu where there are no default controls', async () => {
1015
+ // All options are inactive.
987
1016
  render(
988
1017
  <ToolsPanel { ...defaultProps }>
989
1018
  <ToolsPanelItem { ...optionalControls }>
@@ -992,25 +1021,49 @@ describe( 'ToolsPanel', () => {
992
1021
  </ToolsPanel>
993
1022
  );
994
1023
 
995
- // There are unactivated, optional menu items in the Tools Panel dropdown.
996
1024
  const optionsHiddenIcon = screen.getByRole( 'button', {
997
- name: 'View and add options',
1025
+ name: 'Panel header options',
998
1026
  } );
999
1027
 
1028
+ // The dropdown toggle has a description indicating that all options are hidden.
1000
1029
  expect( optionsHiddenIcon ).toBeInTheDocument();
1030
+ expect( optionsHiddenIcon ).toHaveAccessibleDescription(
1031
+ 'All options are currently hidden'
1032
+ );
1001
1033
 
1034
+ // Activate one of the options.
1035
+ await openDropdownMenu();
1002
1036
  await selectMenuItem( optionalControls.label );
1003
1037
 
1004
- // There are now NO unactivated, optional menu items in the Tools Panel dropdown.
1005
- expect(
1006
- screen.queryByRole( 'button', { name: 'View and add options' } )
1007
- ).not.toBeInTheDocument();
1008
-
1009
1038
  const optionsDisplayedIcon = screen.getByRole( 'button', {
1010
- name: 'View options',
1039
+ name: 'Panel header options',
1011
1040
  } );
1012
1041
 
1013
- expect( optionsDisplayedIcon ).toBeInTheDocument();
1042
+ // The dropdown toggle no longer has a description.
1043
+ expect( optionsDisplayedIcon ).not.toHaveAccessibleDescription();
1044
+ } );
1045
+ } );
1046
+
1047
+ describe( 'reset all button', () => {
1048
+ it( "should disable the reset all button when there's nothing to reset", async () => {
1049
+ await renderPanel();
1050
+ await openDropdownMenu();
1051
+
1052
+ const resetAllItem = await screen.findByRole( 'menuitem', {
1053
+ disabled: false,
1054
+ } );
1055
+ expect( resetAllItem ).toBeInTheDocument();
1056
+
1057
+ await selectMenuItem( 'Reset all' );
1058
+
1059
+ // Test the aria live announcement.
1060
+ const announcement = await screen.getByText( 'All options reset' );
1061
+ expect( announcement ).toHaveAttribute( 'aria-live', 'assertive' );
1062
+
1063
+ const disabledResetAllItem = await screen.findByRole( 'menuitem', {
1064
+ disabled: true,
1065
+ } );
1066
+ expect( disabledResetAllItem ).toBeInTheDocument();
1014
1067
  } );
1015
1068
  } );
1016
1069