@wordpress/components 21.0.1 → 21.1.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 (103) hide show
  1. package/CHANGELOG.md +16 -7
  2. package/build/autocomplete/get-default-use-items.js +3 -3
  3. package/build/autocomplete/get-default-use-items.js.map +1 -1
  4. package/build/box-control/unit-control.js +0 -1
  5. package/build/box-control/unit-control.js.map +1 -1
  6. package/build/button/index.js +5 -1
  7. package/build/button/index.js.map +1 -1
  8. package/build/drop-zone/index.js +7 -1
  9. package/build/drop-zone/index.js.map +1 -1
  10. package/build/higher-order/with-filters/index.js +1 -1
  11. package/build/higher-order/with-filters/index.js.map +1 -1
  12. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +3 -3
  13. package/build/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js.map +1 -1
  14. package/build/mobile/link-picker/link-picker-results.native.js +3 -3
  15. package/build/mobile/link-picker/link-picker-results.native.js.map +1 -1
  16. package/build/range-control/input-range.js +1 -15
  17. package/build/range-control/input-range.js.map +1 -1
  18. package/build/range-control/tooltip.js +1 -1
  19. package/build/range-control/tooltip.js.map +1 -1
  20. package/build/range-control/utils.js +2 -58
  21. package/build/range-control/utils.js.map +1 -1
  22. package/build/tree-grid/index.js +13 -8
  23. package/build/tree-grid/index.js.map +1 -1
  24. package/build/unit-control/index.js +2 -2
  25. package/build/unit-control/index.js.map +1 -1
  26. package/build/unit-control/index.native.js +10 -2
  27. package/build/unit-control/index.native.js.map +1 -1
  28. package/build/unit-control/styles/unit-control-styles.js +21 -32
  29. package/build/unit-control/styles/unit-control-styles.js.map +1 -1
  30. package/build/utils/hooks/use-controlled-state.js +2 -3
  31. package/build/utils/hooks/use-controlled-state.js.map +1 -1
  32. package/build-module/autocomplete/get-default-use-items.js +1 -1
  33. package/build-module/autocomplete/get-default-use-items.js.map +1 -1
  34. package/build-module/box-control/unit-control.js +0 -1
  35. package/build-module/box-control/unit-control.js.map +1 -1
  36. package/build-module/button/index.js +5 -1
  37. package/build-module/button/index.js.map +1 -1
  38. package/build-module/drop-zone/index.js +7 -1
  39. package/build-module/drop-zone/index.js.map +1 -1
  40. package/build-module/higher-order/with-filters/index.js +2 -2
  41. package/build-module/higher-order/with-filters/index.js.map +1 -1
  42. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +1 -1
  43. package/build-module/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js.map +1 -1
  44. package/build-module/mobile/link-picker/link-picker-results.native.js +1 -1
  45. package/build-module/mobile/link-picker/link-picker-results.native.js.map +1 -1
  46. package/build-module/range-control/input-range.js +1 -14
  47. package/build-module/range-control/input-range.js.map +1 -1
  48. package/build-module/range-control/tooltip.js +1 -1
  49. package/build-module/range-control/tooltip.js.map +1 -1
  50. package/build-module/range-control/utils.js +2 -57
  51. package/build-module/range-control/utils.js.map +1 -1
  52. package/build-module/tree-grid/index.js +13 -8
  53. package/build-module/tree-grid/index.js.map +1 -1
  54. package/build-module/unit-control/index.js +2 -2
  55. package/build-module/unit-control/index.js.map +1 -1
  56. package/build-module/unit-control/index.native.js +10 -2
  57. package/build-module/unit-control/index.native.js.map +1 -1
  58. package/build-module/unit-control/styles/unit-control-styles.js +20 -31
  59. package/build-module/unit-control/styles/unit-control-styles.js.map +1 -1
  60. package/build-module/utils/hooks/use-controlled-state.js +3 -4
  61. package/build-module/utils/hooks/use-controlled-state.js.map +1 -1
  62. package/build-types/button/index.d.ts.map +1 -1
  63. package/build-types/drop-zone/index.d.ts.map +1 -1
  64. package/build-types/popover/stories/e2e/index.d.ts +8 -0
  65. package/build-types/popover/stories/e2e/index.d.ts.map +1 -0
  66. package/build-types/range-control/input-range.d.ts.map +1 -1
  67. package/build-types/range-control/stories/index.d.ts.map +1 -1
  68. package/build-types/range-control/types.d.ts +0 -2
  69. package/build-types/range-control/types.d.ts.map +1 -1
  70. package/build-types/range-control/utils.d.ts +1 -12
  71. package/build-types/range-control/utils.d.ts.map +1 -1
  72. package/build-types/unit-control/styles/unit-control-styles.d.ts +1 -4
  73. package/build-types/unit-control/styles/unit-control-styles.d.ts.map +1 -1
  74. package/build-types/utils/hooks/use-controlled-state.d.ts.map +1 -1
  75. package/package.json +17 -17
  76. package/src/autocomplete/get-default-use-items.js +1 -1
  77. package/src/box-control/unit-control.js +0 -1
  78. package/src/button/index.js +7 -1
  79. package/src/button/test/index.js +36 -0
  80. package/src/color-palette/test/__snapshots__/index.js.snap +169 -1106
  81. package/src/color-palette/test/index.js +107 -61
  82. package/src/drop-zone/index.tsx +4 -1
  83. package/src/font-size-picker/stories/e2e/index.js +47 -0
  84. package/src/higher-order/with-filters/index.js +2 -2
  85. package/src/mobile/bottom-sheet/bottom-sheet-navigation/navigation-screen.native.js +1 -2
  86. package/src/mobile/link-picker/link-picker-results.native.js +1 -1
  87. package/src/popover/stories/e2e/index.tsx +25 -0
  88. package/src/range-control/README.md +6 -7
  89. package/src/range-control/input-range.tsx +1 -21
  90. package/src/range-control/stories/index.tsx +2 -1
  91. package/src/range-control/tooltip.tsx +1 -1
  92. package/src/range-control/types.ts +0 -2
  93. package/src/range-control/utils.ts +3 -75
  94. package/src/tree-grid/index.js +23 -14
  95. package/src/tree-grid/test/__snapshots__/cell.js.snap +21 -17
  96. package/src/tree-grid/test/__snapshots__/index.js.snap +1 -1
  97. package/src/unit-control/index.native.js +8 -0
  98. package/src/unit-control/index.tsx +2 -2
  99. package/src/unit-control/styles/unit-control-styles.ts +0 -20
  100. package/src/unit-control/test/index.tsx +6 -3
  101. package/src/utils/hooks/use-controlled-state.js +9 -6
  102. package/tsconfig.tsbuildinfo +1 -1
  103. package/src/unit-control/test/__snapshots__/index.tsx.snap +0 -31
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { mount, shallow } from 'enzyme';
4
+ import { render, screen, within } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
5
6
 
6
7
  /**
7
8
  * Internal dependencies
@@ -17,102 +18,147 @@ describe( 'ColorPalette', () => {
17
18
  const currentColor = '#f00';
18
19
  const onChange = jest.fn();
19
20
 
20
- const wrapper = mount(
21
- <ColorPalette
22
- colors={ colors }
23
- value={ currentColor }
24
- onChange={ onChange }
25
- />
26
- );
27
- const buttons = wrapper.find( 'Option button' );
28
-
29
21
  beforeEach( () => {
30
22
  onChange.mockClear();
31
23
  } );
32
24
 
33
25
  test( 'should render a dynamic toolbar of colors', () => {
34
- expect( wrapper ).toMatchSnapshot();
26
+ const { container } = render(
27
+ <ColorPalette
28
+ colors={ colors }
29
+ value={ currentColor }
30
+ onChange={ onChange }
31
+ />
32
+ );
33
+
34
+ expect( container ).toMatchSnapshot();
35
35
  } );
36
36
 
37
37
  test( 'should render three color button options', () => {
38
- expect( buttons ).toHaveLength( 3 );
38
+ render(
39
+ <ColorPalette
40
+ colors={ colors }
41
+ value={ currentColor }
42
+ onChange={ onChange }
43
+ />
44
+ );
45
+
46
+ expect(
47
+ screen.getAllByRole( 'button', { name: /^Color:/ } )
48
+ ).toHaveLength( 3 );
39
49
  } );
40
50
 
41
- test( 'should call onClick on an active button with undefined', () => {
42
- const activeButton = buttons.findWhere( ( button ) =>
43
- button.hasClass( 'is-pressed' )
51
+ test( 'should call onClick on an active button with undefined', async () => {
52
+ const user = userEvent.setup( {
53
+ advanceTimers: jest.advanceTimersByTime,
54
+ } );
55
+
56
+ render(
57
+ <ColorPalette
58
+ colors={ colors }
59
+ value={ currentColor }
60
+ onChange={ onChange }
61
+ />
62
+ );
63
+
64
+ await user.click(
65
+ screen.getByRole( 'button', { name: /^Color:/, pressed: true } )
44
66
  );
45
- activeButton.simulate( 'click' );
46
67
 
47
68
  expect( onChange ).toHaveBeenCalledTimes( 1 );
48
69
  expect( onChange ).toHaveBeenCalledWith( undefined );
49
70
  } );
50
71
 
51
- test( 'should call onClick on an inactive button', () => {
52
- const inactiveButton = buttons
53
- .findWhere( ( button ) => ! button.hasClass( 'is-pressed' ) )
54
- .first();
55
- inactiveButton.simulate( 'click' );
72
+ test( 'should call onClick on an inactive button', async () => {
73
+ const user = userEvent.setup( {
74
+ advanceTimers: jest.advanceTimersByTime,
75
+ } );
76
+
77
+ render(
78
+ <ColorPalette
79
+ colors={ colors }
80
+ value={ currentColor }
81
+ onChange={ onChange }
82
+ />
83
+ );
84
+
85
+ await user.click(
86
+ screen.getAllByRole( 'button', {
87
+ name: /^Color:/,
88
+ pressed: false,
89
+ } )[ 0 ]
90
+ );
56
91
 
57
92
  expect( onChange ).toHaveBeenCalledTimes( 1 );
93
+ expect( onChange ).toHaveBeenCalledWith( '#fff' );
58
94
  } );
59
95
 
60
- test( 'should call onClick with undefined, when the clearButton onClick is triggered', () => {
61
- const clearButton = wrapper.find( 'ButtonAction button' );
96
+ test( 'should call onClick with undefined, when the clearButton onClick is triggered', async () => {
97
+ const user = userEvent.setup( {
98
+ advanceTimers: jest.advanceTimersByTime,
99
+ } );
62
100
 
63
- expect( clearButton ).toHaveLength( 1 );
101
+ render(
102
+ <ColorPalette
103
+ colors={ colors }
104
+ value={ currentColor }
105
+ onChange={ onChange }
106
+ />
107
+ );
64
108
 
65
- clearButton.simulate( 'click' );
109
+ await user.click( screen.getByRole( 'button', { name: 'Clear' } ) );
66
110
 
67
111
  expect( onChange ).toHaveBeenCalledTimes( 1 );
68
112
  expect( onChange ).toHaveBeenCalledWith( undefined );
69
113
  } );
70
114
 
71
115
  test( 'should allow disabling custom color picker', () => {
72
- expect(
73
- shallow(
74
- <ColorPalette
75
- colors={ colors }
76
- disableCustomColors={ true }
77
- value={ currentColor }
78
- onChange={ onChange }
79
- />
80
- )
81
- ).toMatchSnapshot();
82
- } );
116
+ const { container } = render(
117
+ <ColorPalette
118
+ colors={ colors }
119
+ disableCustomColors
120
+ value={ currentColor }
121
+ onChange={ onChange }
122
+ />
123
+ );
83
124
 
84
- describe( 'Dropdown', () => {
85
- const dropdown = wrapper.find( 'Dropdown' );
125
+ expect( container ).toMatchSnapshot();
126
+ } );
86
127
 
87
- test( 'should render it correctly', () => {
88
- expect( dropdown ).toMatchSnapshot();
128
+ test( 'should render dropdown and its content', async () => {
129
+ const user = userEvent.setup( {
130
+ advanceTimers: jest.advanceTimersByTime,
89
131
  } );
90
132
 
91
- describe( '.renderToggle', () => {
92
- const isOpen = true;
93
- const onToggle = jest.fn();
94
-
95
- const renderedToggleButton = mount(
96
- dropdown.props().renderToggle( { isOpen, onToggle } )
97
- );
98
-
99
- test( 'should render dropdown content', () => {
100
- expect( renderedToggleButton ).toMatchSnapshot();
101
- } );
133
+ render(
134
+ <ColorPalette
135
+ colors={ colors }
136
+ value={ currentColor }
137
+ onChange={ onChange }
138
+ />
139
+ );
102
140
 
103
- test( 'should call onToggle on click.', () => {
104
- renderedToggleButton.find( 'button' ).simulate( 'click' );
141
+ await user.click(
142
+ screen.getByRole( 'button', {
143
+ name: /^Custom color picker/,
144
+ expanded: false,
145
+ } )
146
+ );
105
147
 
106
- expect( onToggle ).toHaveBeenCalledTimes( 1 );
107
- } );
148
+ const dropdownButton = screen.getByRole( 'button', {
149
+ name: /^Custom color picker/,
150
+ expanded: true,
108
151
  } );
109
152
 
110
- describe( '.renderContent', () => {
111
- const renderedContent = shallow( dropdown.props().renderContent() );
153
+ expect( dropdownButton ).toBeVisible();
112
154
 
113
- test( 'should render dropdown content', () => {
114
- expect( renderedContent ).toMatchSnapshot();
115
- } );
116
- } );
155
+ expect(
156
+ within( dropdownButton ).getByText( colors[ 0 ].name )
157
+ ).toBeVisible();
158
+ expect(
159
+ within( dropdownButton ).getByText(
160
+ colors[ 0 ].color.replace( '#', '' )
161
+ )
162
+ ).toBeVisible();
117
163
  } );
118
164
  } );
@@ -119,7 +119,6 @@ export function DropZoneComponent( {
119
119
  const disableMotion = useReducedMotion();
120
120
 
121
121
  let children;
122
-
123
122
  const backdrop = {
124
123
  hidden: { scaleY: 0, opacity: 0 },
125
124
  show: {
@@ -156,6 +155,10 @@ export function DropZoneComponent( {
156
155
  animate="show"
157
156
  exit={ disableMotion ? 'show' : 'exit' }
158
157
  className="components-drop-zone__content"
158
+ // Without this, when this div is shown,
159
+ // Safari calls a onDropZoneLeave causing a loop because of this bug
160
+ // https://bugs.webkit.org/show_bug.cgi?id=66547
161
+ style={ { pointerEvents: 'none' } }
159
162
  >
160
163
  <motion.div variants={ foreground }>
161
164
  <Icon
@@ -0,0 +1,47 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import FontSizePicker from '../..';
10
+
11
+ export default {
12
+ title: 'Components/FontSizePicker',
13
+ component: FontSizePicker,
14
+ };
15
+
16
+ const FontSizePickerWithState = ( { initialValue, ...props } ) => {
17
+ const [ fontSize, setFontSize ] = useState( initialValue );
18
+ return (
19
+ <FontSizePicker
20
+ { ...props }
21
+ value={ fontSize }
22
+ onChange={ setFontSize }
23
+ />
24
+ );
25
+ };
26
+
27
+ export const Default = FontSizePickerWithState.bind( {} );
28
+ Default.args = {
29
+ fontSizes: [
30
+ {
31
+ name: 'Small',
32
+ slug: 'small',
33
+ size: 12,
34
+ },
35
+ {
36
+ name: 'Normal',
37
+ slug: 'normal',
38
+ size: 16,
39
+ },
40
+ {
41
+ name: 'Big',
42
+ slug: 'big',
43
+ size: 26,
44
+ },
45
+ ],
46
+ initialValue: 16,
47
+ };
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { debounce, without } from 'lodash';
4
+ import { without } from 'lodash';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { Component } from '@wordpress/element';
10
10
  import { addAction, applyFilters, removeAction } from '@wordpress/hooks';
11
- import { createHigherOrderComponent } from '@wordpress/compose';
11
+ import { createHigherOrderComponent, debounce } from '@wordpress/compose';
12
12
 
13
13
  const ANIMATION_FRAME_PERIOD = 16;
14
14
 
@@ -7,13 +7,12 @@ import {
7
7
  useFocusEffect,
8
8
  } from '@react-navigation/native';
9
9
  import { View, ScrollView, TouchableHighlight } from 'react-native';
10
- import { debounce } from 'lodash';
11
10
 
12
11
  /**
13
12
  * WordPress dependencies
14
13
  */
15
14
  import { BottomSheetContext } from '@wordpress/components';
16
-
15
+ import { debounce } from '@wordpress/compose';
17
16
  import { useRef, useCallback, useContext, useMemo } from '@wordpress/element';
18
17
 
19
18
  /**
@@ -2,12 +2,12 @@
2
2
  * External dependencies
3
3
  */
4
4
  import { ActivityIndicator, FlatList, View } from 'react-native';
5
- import { debounce } from 'lodash';
6
5
 
7
6
  /**
8
7
  * WordPress dependencies
9
8
  */
10
9
  import { BottomSheet, BottomSheetConsumer } from '@wordpress/components';
10
+ import { debounce } from '@wordpress/compose';
11
11
  import { useState, useEffect, useRef } from '@wordpress/element';
12
12
  import { useSelect } from '@wordpress/data';
13
13
 
@@ -0,0 +1,25 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import Popover from '../..';
10
+
11
+ export default {
12
+ title: 'Components/Popover',
13
+ component: Popover,
14
+ };
15
+
16
+ export const Default = () => {
17
+ const [ isVisible, setIsVisible ] = useState( false );
18
+
19
+ return (
20
+ <button onClick={ () => setIsVisible( ( state ) => ! state ) }>
21
+ Toggle Popover!
22
+ { isVisible && <Popover>Popover is toggled!</Popover> }
23
+ </button>
24
+ );
25
+ };
@@ -16,15 +16,14 @@ A RangeControl for volume
16
16
 
17
17
  ### Anatomy
18
18
 
19
- ![](https://make.wordpress.org/design/files/2018/12/rangecontrol-anatomy.png)
20
-
21
19
  A RangeControl can contain the following elements:
22
20
 
23
- 1. **Track**: The track shows the range available for user selection. For left-to-right (LTR) languages, the smallest value appears on the far left, and the largest value on the far right. For right-to-left (RTL) languages this orientation is reversed, with the smallest value on the far right and the largest value on the far left.
24
- 2. **Thumb**: The thumb slides along the track, displaying the selected value through its position.
25
- 3. **Value entry field**: The value entry field displays the currently selected, specific numerical value.
26
- 4. **Icon** (optional): An icon can be displayed before or after the slider.
27
- 5. **Tick mark** (optional): Tick marks represent predetermined values to which the user can move the slider.
21
+ 1. **Rail**: The rail represents the entire surface area of the slider, from the minimum value selectable by the user to the maximum value selectable by the user. For left-to-right (LTR) languages, the minimum value appears on the far left, and the maximum value on the far right. For right-to-left (RTL) languages this orientation is reversed, with the minimum value on the far right and the maximum value on the far left.
22
+ 2. **Track**: The track represents the portion of the rail from the minimum value to the currently selected value.
23
+ 3. **Thumb**: The thumb slides along the track, displaying the selected value through its position.
24
+ 4. **Value entry field**: The value entry field displays the currently selected, specific numerical value.
25
+ 5. **Icon** (optional): An icon can be displayed before or after the slider.
26
+ 6. **Tick mark** (optional): Tick marks represent predetermined values to which the user can move the slider.
28
27
 
29
28
  ### Types
30
29
 
@@ -7,39 +7,19 @@ import { forwardRef } from '@wordpress/element';
7
7
  * Internal dependencies
8
8
  */
9
9
  import { InputRange as BaseInputRange } from './styles/range-control-styles';
10
- import { useDebouncedHoverInteraction } from './utils';
11
10
 
12
11
  import type { InputRangeProps } from './types';
13
12
  import type { WordPressComponentProps } from '../ui/context';
14
13
 
15
- const noop = () => {};
16
-
17
14
  function InputRange(
18
15
  props: WordPressComponentProps< InputRangeProps, 'input' >,
19
16
  ref: React.ForwardedRef< HTMLInputElement >
20
17
  ) {
21
- const {
22
- describedBy,
23
- label,
24
- onHideTooltip = noop,
25
- onMouseLeave = noop,
26
- onMouseMove = noop,
27
- onShowTooltip = noop,
28
- value,
29
- ...otherProps
30
- } = props;
31
-
32
- const hoverInteractions = useDebouncedHoverInteraction( {
33
- onHide: onHideTooltip,
34
- onMouseLeave,
35
- onMouseMove,
36
- onShow: onShowTooltip,
37
- } );
18
+ const { describedBy, label, value, ...otherProps } = props;
38
19
 
39
20
  return (
40
21
  <BaseInputRange
41
22
  { ...otherProps }
42
- { ...hoverInteractions }
43
23
  aria-describedby={ describedBy }
44
24
  aria-label={ label }
45
25
  aria-hidden={ false }
@@ -35,7 +35,7 @@ const meta: ComponentMeta< typeof RangeControl > = {
35
35
  icon: { control: { type: null } },
36
36
  marks: { control: { type: 'object' } },
37
37
  onBlur: { control: { type: null } },
38
- onChange: { action: 'onChange' },
38
+ onChange: { control: { type: null } },
39
39
  onFocus: { control: { type: null } },
40
40
  onMouseLeave: { control: { type: null } },
41
41
  onMouseMove: { control: { type: null } },
@@ -46,6 +46,7 @@ const meta: ComponentMeta< typeof RangeControl > = {
46
46
  value: { control: { type: null } },
47
47
  },
48
48
  parameters: {
49
+ actions: { argTypesRegex: '^on.*' },
49
50
  controls: { expanded: true },
50
51
  docs: { source: { state: 'open' } },
51
52
  },
@@ -59,7 +59,7 @@ function useTooltipPosition( { inputRef, tooltipPosition }: TooltipProps ) {
59
59
  if ( inputRef && inputRef.current ) {
60
60
  setPosition( tooltipPosition );
61
61
  }
62
- }, [ tooltipPosition ] );
62
+ }, [ tooltipPosition, inputRef ] );
63
63
 
64
64
  useEffect( () => {
65
65
  setTooltipPosition();
@@ -236,10 +236,8 @@ export type RailProps = MarksProps & {
236
236
  export type InputRangeProps = {
237
237
  describedBy?: string;
238
238
  label?: string;
239
- onHideTooltip?: () => void;
240
239
  onMouseLeave?: MouseEventHandler< HTMLInputElement >;
241
240
  onMouseMove?: MouseEventHandler< HTMLInputElement >;
242
- onShowTooltip?: () => void;
243
241
  value?: number | '';
244
242
  };
245
243
 
@@ -1,12 +1,7 @@
1
- /**
2
- * External dependencies
3
- */
4
- import type { MouseEventHandler } from 'react';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
9
- import { useCallback, useRef, useEffect, useState } from '@wordpress/element';
4
+ import { useCallback } from '@wordpress/element';
10
5
 
11
6
  /**
12
7
  * Internal dependencies
@@ -14,12 +9,7 @@ import { useCallback, useRef, useEffect, useState } from '@wordpress/element';
14
9
  import { useControlledState } from '../utils/hooks';
15
10
  import { clamp } from '../utils/math';
16
11
 
17
- import type {
18
- UseControlledRangeValueArgs,
19
- UseDebouncedHoverInteractionArgs,
20
- } from './types';
21
-
22
- const noop = () => {};
12
+ import type { UseControlledRangeValueArgs } from './types';
23
13
 
24
14
  /**
25
15
  * A float supported clamp function for a specific value.
@@ -64,72 +54,10 @@ export function useControlledRangeValue(
64
54
  setInternalState( floatClamp( nextValue, min, max ) );
65
55
  }
66
56
  },
67
- [ min, max ]
57
+ [ min, max, setInternalState ]
68
58
  );
69
59
 
70
60
  // `state` can't be an empty string because we specified a fallback value of
71
61
  // `null` in `useControlledState`
72
62
  return [ state as Exclude< typeof state, '' >, setState ] as const;
73
63
  }
74
-
75
- /**
76
- * Hook to encapsulate the debouncing "hover" to better handle the showing
77
- * and hiding of the Tooltip.
78
- *
79
- * @param settings
80
- * @return Bound properties for use on a React.Node.
81
- */
82
- export function useDebouncedHoverInteraction(
83
- settings: UseDebouncedHoverInteractionArgs
84
- ) {
85
- const {
86
- onHide = noop,
87
- onMouseLeave = noop as MouseEventHandler,
88
- onMouseMove = noop as MouseEventHandler,
89
- onShow = noop,
90
- timeout = 300,
91
- } = settings;
92
-
93
- const [ show, setShow ] = useState( false );
94
- const timeoutRef = useRef< number | undefined >();
95
-
96
- const setDebouncedTimeout = useCallback(
97
- ( callback ) => {
98
- window.clearTimeout( timeoutRef.current );
99
-
100
- timeoutRef.current = window.setTimeout( callback, timeout );
101
- },
102
- [ timeout ]
103
- );
104
-
105
- const handleOnMouseMove = useCallback( ( event ) => {
106
- onMouseMove( event );
107
-
108
- setDebouncedTimeout( () => {
109
- if ( ! show ) {
110
- setShow( true );
111
- onShow();
112
- }
113
- } );
114
- }, [] );
115
-
116
- const handleOnMouseLeave = useCallback( ( event ) => {
117
- onMouseLeave( event );
118
-
119
- setDebouncedTimeout( () => {
120
- setShow( false );
121
- onHide();
122
- } );
123
- }, [] );
124
-
125
- useEffect( () => {
126
- return () => {
127
- window.clearTimeout( timeoutRef.current );
128
- };
129
- } );
130
-
131
- return {
132
- onMouseMove: handleOnMouseMove,
133
- onMouseLeave: handleOnMouseLeave,
134
- };
135
- }
@@ -36,12 +36,13 @@ function getRowFocusables( rowElement ) {
36
36
  * Renders both a table and tbody element, used to create a tree hierarchy.
37
37
  *
38
38
  * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/components/src/tree-grid/README.md
39
- * @param {Object} props Component props.
40
- * @param {WPElement} props.children Children to be rendered.
41
- * @param {Function} props.onExpandRow Callback to fire when row is expanded.
42
- * @param {Function} props.onCollapseRow Callback to fire when row is collapsed.
43
- * @param {Function} props.onFocusRow Callback to fire when moving focus to a different row.
44
- * @param {Object} ref A ref to the underlying DOM table element.
39
+ * @param {Object} props Component props.
40
+ * @param {WPElement} props.children Children to be rendered.
41
+ * @param {Function} props.onExpandRow Callback to fire when row is expanded.
42
+ * @param {Function} props.onCollapseRow Callback to fire when row is collapsed.
43
+ * @param {Function} props.onFocusRow Callback to fire when moving focus to a different row.
44
+ * @param {string} props.applicationAriaLabel Label to use for the application role.
45
+ * @param {Object} ref A ref to the underlying DOM table element.
45
46
  */
46
47
  function TreeGrid(
47
48
  {
@@ -49,6 +50,7 @@ function TreeGrid(
49
50
  onExpandRow = () => {},
50
51
  onCollapseRow = () => {},
51
52
  onFocusRow = () => {},
53
+ applicationAriaLabel,
52
54
  ...props
53
55
  },
54
56
  ref
@@ -286,14 +288,21 @@ function TreeGrid(
286
288
  /* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
287
289
  return (
288
290
  <RovingTabIndexContainer>
289
- <table
290
- { ...props }
291
- role="treegrid"
292
- onKeyDown={ onKeyDown }
293
- ref={ ref }
294
- >
295
- <tbody>{ children }</tbody>
296
- </table>
291
+ {
292
+ // Prevent browser mode from triggering in NVDA by wrapping List View
293
+ // in a role=application wrapper.
294
+ // see: https://github.com/WordPress/gutenberg/issues/43729
295
+ }
296
+ <div role="application" aria-label={ applicationAriaLabel }>
297
+ <table
298
+ { ...props }
299
+ role="treegrid"
300
+ onKeyDown={ onKeyDown }
301
+ ref={ ref }
302
+ >
303
+ <tbody>{ children }</tbody>
304
+ </table>
305
+ </div>
297
306
  </RovingTabIndexContainer>
298
307
  );
299
308
  /* eslint-enable jsx-a11y/no-noninteractive-element-to-interactive-role */
@@ -1,23 +1,27 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`TreeGridCell uses a child render function to render children 1`] = `
4
- <table
5
- onKeyDown={[Function]}
6
- role="treegrid"
4
+ <div
5
+ role="application"
7
6
  >
8
- <tbody>
9
- <tr>
10
- <td
11
- role="gridcell"
12
- >
13
- <button
14
- className="my-button"
15
- onFocus={[Function]}
7
+ <table
8
+ onKeyDown={[Function]}
9
+ role="treegrid"
10
+ >
11
+ <tbody>
12
+ <tr>
13
+ <td
14
+ role="gridcell"
16
15
  >
17
- Click Me!
18
- </button>
19
- </td>
20
- </tr>
21
- </tbody>
22
- </table>
16
+ <button
17
+ className="my-button"
18
+ onFocus={[Function]}
19
+ >
20
+ Click Me!
21
+ </button>
22
+ </td>
23
+ </tr>
24
+ </tbody>
25
+ </table>
26
+ </div>
23
27
  `;
@@ -1,3 +1,3 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`TreeGrid simple rendering renders a table, tbody and any child elements 1`] = `"<table role=\\"treegrid\\"><tbody><tr role=\\"row\\" aria-level=\\"1\\" aria-posinset=\\"1\\" aria-setsize=\\"1\\"><td role=\\"gridcell\\">Test</td></tr></tbody></table>"`;
3
+ exports[`TreeGrid simple rendering renders a table, tbody and any child elements 1`] = `"<div role=\\"application\\"><table role=\\"treegrid\\"><tbody><tr role=\\"row\\" aria-level=\\"1\\" aria-posinset=\\"1\\" aria-setsize=\\"1\\"><td role=\\"gridcell\\">Test</td></tr></tbody></table></div>"`;