@wordpress/dataviews 1.2.0 → 2.0.1

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 (150) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +33 -30
  3. package/build/add-filter.js +30 -22
  4. package/build/add-filter.js.map +1 -1
  5. package/build/bulk-actions-toolbar.js +74 -69
  6. package/build/bulk-actions-toolbar.js.map +1 -1
  7. package/build/bulk-actions.js +69 -56
  8. package/build/bulk-actions.js.map +1 -1
  9. package/build/constants.js +17 -10
  10. package/build/constants.js.map +1 -1
  11. package/build/dataviews.js +63 -56
  12. package/build/dataviews.js.map +1 -1
  13. package/build/filter-summary.js +105 -95
  14. package/build/filter-summary.js.map +1 -1
  15. package/build/filters.js +18 -17
  16. package/build/filters.js.map +1 -1
  17. package/build/index.js.map +1 -1
  18. package/build/item-actions.js +79 -65
  19. package/build/item-actions.js.map +1 -1
  20. package/build/layouts.js.map +1 -1
  21. package/build/pagination.js +60 -57
  22. package/build/pagination.js.map +1 -1
  23. package/build/reset-filters.js +9 -4
  24. package/build/reset-filters.js.map +1 -1
  25. package/build/search-widget.js +108 -89
  26. package/build/search-widget.js.map +1 -1
  27. package/build/search.js +13 -6
  28. package/build/search.js.map +1 -1
  29. package/build/single-selection-checkbox.js +2 -2
  30. package/build/single-selection-checkbox.js.map +1 -1
  31. package/build/types.js.map +1 -1
  32. package/build/utils.js +3 -15
  33. package/build/utils.js.map +1 -1
  34. package/build/view-actions.js +168 -120
  35. package/build/view-actions.js.map +1 -1
  36. package/build/view-grid.js +113 -99
  37. package/build/view-grid.js.map +1 -1
  38. package/build/view-list.js +154 -132
  39. package/build/view-list.js.map +1 -1
  40. package/build/view-table.js +220 -192
  41. package/build/view-table.js.map +1 -1
  42. package/build-module/add-filter.js +30 -22
  43. package/build-module/add-filter.js.map +1 -1
  44. package/build-module/bulk-actions-toolbar.js +76 -69
  45. package/build-module/bulk-actions-toolbar.js.map +1 -1
  46. package/build-module/bulk-actions.js +71 -56
  47. package/build-module/bulk-actions.js.map +1 -1
  48. package/build-module/constants.js +16 -9
  49. package/build-module/constants.js.map +1 -1
  50. package/build-module/dataviews.js +64 -56
  51. package/build-module/dataviews.js.map +1 -1
  52. package/build-module/filter-summary.js +106 -96
  53. package/build-module/filter-summary.js.map +1 -1
  54. package/build-module/filters.js +18 -17
  55. package/build-module/filters.js.map +1 -1
  56. package/build-module/index.js.map +1 -1
  57. package/build-module/item-actions.js +81 -65
  58. package/build-module/item-actions.js.map +1 -1
  59. package/build-module/layouts.js.map +1 -1
  60. package/build-module/pagination.js +61 -58
  61. package/build-module/pagination.js.map +1 -1
  62. package/build-module/reset-filters.js +9 -4
  63. package/build-module/reset-filters.js.map +1 -1
  64. package/build-module/search-widget.js +109 -89
  65. package/build-module/search-widget.js.map +1 -1
  66. package/build-module/search.js +13 -6
  67. package/build-module/search.js.map +1 -1
  68. package/build-module/single-selection-checkbox.js +2 -3
  69. package/build-module/single-selection-checkbox.js.map +1 -1
  70. package/build-module/types.js.map +1 -1
  71. package/build-module/utils.js +2 -13
  72. package/build-module/utils.js.map +1 -1
  73. package/build-module/view-actions.js +170 -121
  74. package/build-module/view-actions.js.map +1 -1
  75. package/build-module/view-grid.js +115 -99
  76. package/build-module/view-grid.js.map +1 -1
  77. package/build-module/view-list.js +155 -132
  78. package/build-module/view-list.js.map +1 -1
  79. package/build-module/view-table.js +223 -194
  80. package/build-module/view-table.js.map +1 -1
  81. package/build-style/style-rtl.css +115 -22
  82. package/build-style/style.css +115 -22
  83. package/build-types/add-filter.d.ts +9 -6
  84. package/build-types/add-filter.d.ts.map +1 -1
  85. package/build-types/bulk-actions-toolbar.d.ts +11 -7
  86. package/build-types/bulk-actions-toolbar.d.ts.map +1 -1
  87. package/build-types/bulk-actions.d.ts.map +1 -1
  88. package/build-types/constants.d.ts +19 -32
  89. package/build-types/constants.d.ts.map +1 -1
  90. package/build-types/dataviews.d.ts +21 -14
  91. package/build-types/dataviews.d.ts.map +1 -1
  92. package/build-types/filter-summary.d.ts +13 -5
  93. package/build-types/filter-summary.d.ts.map +1 -1
  94. package/build-types/filters.d.ts +11 -1
  95. package/build-types/filters.d.ts.map +1 -1
  96. package/build-types/index.d.ts +3 -3
  97. package/build-types/index.d.ts.map +1 -1
  98. package/build-types/item-actions.d.ts +5 -7
  99. package/build-types/item-actions.d.ts.map +1 -1
  100. package/build-types/layouts.d.ts +8 -4
  101. package/build-types/layouts.d.ts.map +1 -1
  102. package/build-types/reset-filters.d.ts +12 -5
  103. package/build-types/reset-filters.d.ts.map +1 -1
  104. package/build-types/search-widget.d.ts +9 -1
  105. package/build-types/search-widget.d.ts.map +1 -1
  106. package/build-types/search.d.ts +11 -1
  107. package/build-types/search.d.ts.map +1 -1
  108. package/build-types/types.d.ts +78 -10
  109. package/build-types/types.d.ts.map +1 -1
  110. package/build-types/utils.d.ts +2 -1
  111. package/build-types/utils.d.ts.map +1 -1
  112. package/build-types/view-actions.d.ts +10 -1
  113. package/build-types/view-actions.d.ts.map +1 -1
  114. package/build-types/view-grid.d.ts +1 -12
  115. package/build-types/view-grid.d.ts.map +1 -1
  116. package/build-types/view-list.d.ts +2 -14
  117. package/build-types/view-list.d.ts.map +1 -1
  118. package/build-types/view-table.d.ts +3 -12
  119. package/build-types/view-table.d.ts.map +1 -1
  120. package/package.json +11 -12
  121. package/src/{add-filter.js → add-filter.tsx} +17 -1
  122. package/src/{bulk-actions-toolbar.js → bulk-actions-toolbar.tsx} +68 -40
  123. package/src/bulk-actions.tsx +5 -1
  124. package/src/constants.ts +12 -5
  125. package/src/{dataviews.js → dataviews.tsx} +41 -12
  126. package/src/{filter-summary.js → filter-summary.tsx} +35 -6
  127. package/src/{filters.js → filters.tsx} +18 -6
  128. package/src/item-actions.tsx +21 -15
  129. package/src/pagination.tsx +1 -1
  130. package/src/{reset-filters.js → reset-filters.tsx} +17 -2
  131. package/src/{search-widget.js → search-widget.tsx} +27 -7
  132. package/src/{search.js → search.tsx} +22 -5
  133. package/src/style.scss +102 -25
  134. package/src/types.ts +105 -10
  135. package/src/{utils.js → utils.ts} +5 -13
  136. package/src/{view-actions.js → view-actions.tsx} +105 -49
  137. package/src/view-grid.tsx +4 -20
  138. package/src/view-list.tsx +13 -23
  139. package/src/{view-table.js → view-table.tsx} +91 -32
  140. package/tsconfig.json +0 -3
  141. package/tsconfig.tsbuildinfo +1 -1
  142. package/build/dropdown-menu-helper.js +0 -71
  143. package/build/dropdown-menu-helper.js.map +0 -1
  144. package/build-module/dropdown-menu-helper.js +0 -64
  145. package/build-module/dropdown-menu-helper.js.map +0 -1
  146. package/build-types/dropdown-menu-helper.d.ts +0 -6
  147. package/build-types/dropdown-menu-helper.d.ts.map +0 -1
  148. package/src/dropdown-menu-helper.js +0 -61
  149. /package/src/{index.js → index.ts} +0 -0
  150. /package/src/{layouts.js → layouts.ts} +0 -0
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ComponentType } from 'react';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -16,21 +21,46 @@ import { VIEW_LAYOUTS } from './layouts';
16
21
  import BulkActions from './bulk-actions';
17
22
  import { normalizeFields } from './normalize-fields';
18
23
  import BulkActionsToolbar from './bulk-actions-toolbar';
24
+ import type { Action, AnyItem, Field, View, ViewBaseProps } from './types';
25
+
26
+ interface DataViewsProps< Item extends AnyItem > {
27
+ view: View;
28
+ onChangeView: ( view: View ) => void;
29
+ fields: Field< Item >[];
30
+ search?: boolean;
31
+ searchLabel?: string;
32
+ actions?: Action< Item >[];
33
+ data: Item[];
34
+ getItemId?: ( item: Item ) => string;
35
+ isLoading?: boolean;
36
+ paginationInfo: {
37
+ totalItems: number;
38
+ totalPages: number;
39
+ };
40
+ supportedLayouts: string[];
41
+ onSelectionChange?: ( items: Item[] ) => void;
42
+ }
19
43
 
20
- const defaultGetItemId = ( item ) => item.id;
44
+ const defaultGetItemId = ( item: AnyItem ) => item.id;
21
45
  const defaultOnSelectionChange = () => {};
22
46
 
23
- function useSomeItemHasAPossibleBulkAction( actions, data ) {
47
+ function useSomeItemHasAPossibleBulkAction< Item extends AnyItem >(
48
+ actions: Action< Item >[],
49
+ data: Item[]
50
+ ) {
24
51
  return useMemo( () => {
25
52
  return data.some( ( item ) => {
26
53
  return actions.some( ( action ) => {
27
- return action.supportsBulk && action.isEligible( item );
54
+ return (
55
+ action.supportsBulk &&
56
+ ( ! action.isEligible || action.isEligible( item ) )
57
+ );
28
58
  } );
29
59
  } );
30
60
  }, [ actions, data ] );
31
61
  }
32
62
 
33
- export default function DataViews( {
63
+ export default function DataViews< Item extends AnyItem >( {
34
64
  view,
35
65
  onChangeView,
36
66
  fields,
@@ -43,9 +73,9 @@ export default function DataViews( {
43
73
  paginationInfo,
44
74
  supportedLayouts,
45
75
  onSelectionChange = defaultOnSelectionChange,
46
- } ) {
47
- const [ selection, setSelection ] = useState( [] );
48
- const [ openedFilter, setOpenedFilter ] = useState( null );
76
+ }: DataViewsProps< Item > ) {
77
+ const [ selection, setSelection ] = useState< string[] >( [] );
78
+ const [ openedFilter, setOpenedFilter ] = useState< string | null >( null );
49
79
 
50
80
  useEffect( () => {
51
81
  if (
@@ -67,16 +97,15 @@ export default function DataViews( {
67
97
  }, [ selection, data, getItemId, onSelectionChange ] );
68
98
 
69
99
  const onSetSelection = useCallback(
70
- ( items ) => {
100
+ ( items: Item[] ) => {
71
101
  setSelection( items.map( ( item ) => getItemId( item ) ) );
72
102
  onSelectionChange( items );
73
103
  },
74
104
  [ setSelection, getItemId, onSelectionChange ]
75
105
  );
76
106
 
77
- const ViewComponent = VIEW_LAYOUTS.find(
78
- ( v ) => v.type === view.type
79
- ).component;
107
+ const ViewComponent = VIEW_LAYOUTS.find( ( v ) => v.type === view.type )
108
+ ?.component as ComponentType< ViewBaseProps< Item > >;
80
109
  const _fields = useMemo( () => normalizeFields( fields ), [ fields ] );
81
110
 
82
111
  const hasPossibleBulkAction = useSomeItemHasAPossibleBulkAction(
@@ -150,7 +179,7 @@ export default function DataViews( {
150
179
  data={ data }
151
180
  actions={ actions }
152
181
  selection={ selection }
153
- setSelection={ setSelection }
182
+ onSelectionChange={ onSetSelection }
154
183
  getItemId={ getItemId }
155
184
  />
156
185
  ) }
@@ -2,6 +2,7 @@
2
2
  * External dependencies
3
3
  */
4
4
  import clsx from 'clsx';
5
+ import type { RefObject } from 'react';
5
6
 
6
7
  /**
7
8
  * WordPress dependencies
@@ -35,8 +36,30 @@ import {
35
36
  OPERATOR_IS_ALL,
36
37
  OPERATOR_IS_NOT_ALL,
37
38
  } from './constants';
39
+ import type { Filter, NormalizedFilter, Operator, Option, View } from './types';
38
40
 
39
- const FilterText = ( { activeElements, filterInView, filter } ) => {
41
+ interface FilterTextProps {
42
+ activeElements: Option[];
43
+ filterInView?: Filter;
44
+ filter: NormalizedFilter;
45
+ }
46
+
47
+ interface OperatorSelectorProps {
48
+ filter: NormalizedFilter;
49
+ view: View;
50
+ onChangeView: ( view: View ) => void;
51
+ }
52
+
53
+ interface FilterSummaryProps extends OperatorSelectorProps {
54
+ addFilterRef: RefObject< HTMLButtonElement >;
55
+ openedFilter: string | null;
56
+ }
57
+
58
+ const FilterText = ( {
59
+ activeElements,
60
+ filterInView,
61
+ filter,
62
+ }: FilterTextProps ) => {
40
63
  if ( activeElements === undefined || activeElements.length === 0 ) {
41
64
  return filter.name;
42
65
  }
@@ -125,7 +148,11 @@ const FilterText = ( { activeElements, filterInView, filter } ) => {
125
148
  );
126
149
  };
127
150
 
128
- function OperatorSelector( { filter, view, onChangeView } ) {
151
+ function OperatorSelector( {
152
+ filter,
153
+ view,
154
+ onChangeView,
155
+ }: OperatorSelectorProps ) {
129
156
  const operatorOptions = filter.operators?.map( ( operator ) => ( {
130
157
  value: operator,
131
158
  label: OPERATORS[ operator ]?.label,
@@ -150,13 +177,14 @@ function OperatorSelector( { filter, view, onChangeView } ) {
150
177
  value={ value }
151
178
  options={ operatorOptions }
152
179
  onChange={ ( newValue ) => {
180
+ const operator = newValue as Operator;
153
181
  const newFilters = currentFilter
154
182
  ? [
155
183
  ...view.filters.map( ( _filter ) => {
156
184
  if ( _filter.field === filter.field ) {
157
185
  return {
158
186
  ..._filter,
159
- operator: newValue,
187
+ operator,
160
188
  };
161
189
  }
162
190
  return _filter;
@@ -166,7 +194,8 @@ function OperatorSelector( { filter, view, onChangeView } ) {
166
194
  ...view.filters,
167
195
  {
168
196
  field: filter.field,
169
- operator: newValue,
197
+ operator,
198
+ value: undefined,
170
199
  },
171
200
  ];
172
201
  onChangeView( {
@@ -188,8 +217,8 @@ export default function FilterSummary( {
188
217
  addFilterRef,
189
218
  openedFilter,
190
219
  ...commonProps
191
- } ) {
192
- const toggleRef = useRef();
220
+ }: FilterSummaryProps ) {
221
+ const toggleRef = useRef< HTMLDivElement >( null );
193
222
  const { filter, view, onChangeView } = commonProps;
194
223
  const filterInView = view.filters.find( ( f ) => f.field === filter.field );
195
224
  const activeElements = filter.elements.filter( ( element ) => {
@@ -2,6 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { memo, useRef } from '@wordpress/element';
5
+ import { __experimentalHStack as HStack } from '@wordpress/components';
5
6
 
6
7
  /**
7
8
  * Internal dependencies
@@ -11,17 +12,25 @@ import AddFilter from './add-filter';
11
12
  import ResetFilters from './reset-filters';
12
13
  import { sanitizeOperators } from './utils';
13
14
  import { ALL_OPERATORS, OPERATOR_IS, OPERATOR_IS_NOT } from './constants';
14
- import { __experimentalHStack as HStack } from '@wordpress/components';
15
+ import type { AnyItem, NormalizedField, NormalizedFilter, View } from './types';
15
16
 
16
- const Filters = memo( function Filters( {
17
+ interface FiltersProps< Item extends AnyItem > {
18
+ fields: NormalizedField< Item >[];
19
+ view: View;
20
+ onChangeView: ( view: View ) => void;
21
+ openedFilter: string | null;
22
+ setOpenedFilter: ( openedFilter: string | null ) => void;
23
+ }
24
+
25
+ function _Filters< Item extends AnyItem >( {
17
26
  fields,
18
27
  view,
19
28
  onChangeView,
20
29
  openedFilter,
21
30
  setOpenedFilter,
22
- } ) {
23
- const addFilterRef = useRef();
24
- const filters = [];
31
+ }: FiltersProps< Item > ) {
32
+ const addFilterRef = useRef< HTMLButtonElement >( null );
33
+ const filters: NormalizedFilter[] = [];
25
34
  fields.forEach( ( field ) => {
26
35
  if ( ! field.elements?.length ) {
27
36
  return;
@@ -108,6 +117,9 @@ const Filters = memo( function Filters( {
108
117
  { filterComponents }
109
118
  </HStack>
110
119
  );
111
- } );
120
+ }
121
+
122
+ // A type assertion is used here to keep the type argument.
123
+ const Filters = memo( _Filters ) as typeof _Filters;
112
124
 
113
125
  export default Filters;
@@ -30,14 +30,11 @@ const {
30
30
  kebabCase,
31
31
  } = unlock( componentsPrivateApis );
32
32
 
33
- interface ButtonTriggerProps< Item extends AnyItem > {
34
- action: Action< Item >;
35
- onClick: MouseEventHandler;
36
- }
37
-
38
- interface DropdownMenuItemTriggerProps< Item extends AnyItem > {
33
+ export interface ActionTriggerProps< Item extends AnyItem > {
39
34
  action: Action< Item >;
40
35
  onClick: MouseEventHandler;
36
+ isBusy?: boolean;
37
+ items: Item[];
41
38
  }
42
39
 
43
40
  interface ActionModalProps< Item extends AnyItem > {
@@ -48,9 +45,7 @@ interface ActionModalProps< Item extends AnyItem > {
48
45
 
49
46
  interface ActionWithModalProps< Item extends AnyItem >
50
47
  extends ActionModalProps< Item > {
51
- ActionTrigger: (
52
- props: ButtonTriggerProps< Item > | DropdownMenuItemTriggerProps< Item >
53
- ) => ReactElement;
48
+ ActionTrigger: ( props: ActionTriggerProps< Item > ) => ReactElement;
54
49
  isBusy?: boolean;
55
50
  }
56
51
 
@@ -62,7 +57,7 @@ interface ActionsDropdownMenuGroupProps< Item extends AnyItem > {
62
57
  interface ItemActionsProps< Item extends AnyItem > {
63
58
  item: Item;
64
59
  actions: Action< Item >[];
65
- isCompact: boolean;
60
+ isCompact?: boolean;
66
61
  }
67
62
 
68
63
  interface CompactItemActionsProps< Item extends AnyItem > {
@@ -73,10 +68,13 @@ interface CompactItemActionsProps< Item extends AnyItem > {
73
68
  function ButtonTrigger< Item extends AnyItem >( {
74
69
  action,
75
70
  onClick,
76
- }: ButtonTriggerProps< Item > ) {
71
+ items,
72
+ }: ActionTriggerProps< Item > ) {
73
+ const label =
74
+ typeof action.label === 'string' ? action.label : action.label( items );
77
75
  return (
78
76
  <Button
79
- label={ action.label }
77
+ label={ label }
80
78
  icon={ action.icon }
81
79
  isDestructive={ action.isDestructive }
82
80
  size="compact"
@@ -88,13 +86,16 @@ function ButtonTrigger< Item extends AnyItem >( {
88
86
  function DropdownMenuItemTrigger< Item extends AnyItem >( {
89
87
  action,
90
88
  onClick,
91
- }: DropdownMenuItemTriggerProps< Item > ) {
89
+ items,
90
+ }: ActionTriggerProps< Item > ) {
91
+ const label =
92
+ typeof action.label === 'string' ? action.label : action.label( items );
92
93
  return (
93
94
  <DropdownMenuItem
94
95
  onClick={ onClick }
95
96
  hideOnClick={ ! ( 'RenderModal' in action ) }
96
97
  >
97
- <DropdownMenuItemLabel>{ action.label }</DropdownMenuItemLabel>
98
+ <DropdownMenuItemLabel>{ label }</DropdownMenuItemLabel>
98
99
  </DropdownMenuItem>
99
100
  );
100
101
  }
@@ -104,9 +105,11 @@ export function ActionModal< Item extends AnyItem >( {
104
105
  items,
105
106
  closeModal,
106
107
  }: ActionModalProps< Item > ) {
108
+ const label =
109
+ typeof action.label === 'string' ? action.label : action.label( items );
107
110
  return (
108
111
  <Modal
109
- title={ action.modalHeader || action.label }
112
+ title={ action.modalHeader || label }
110
113
  __experimentalHideHeader={ !! action.hideModalHeader }
111
114
  onRequestClose={ closeModal ?? ( () => {} ) }
112
115
  overlayClassName={ `dataviews-action-modal dataviews-action-modal__${ kebabCase(
@@ -174,6 +177,7 @@ export function ActionsDropdownMenuGroup< Item extends AnyItem >( {
174
177
  key={ action.id }
175
178
  action={ action }
176
179
  onClick={ () => action.callback( [ item ] ) }
180
+ items={ [ item ] }
177
181
  />
178
182
  );
179
183
  } ) }
@@ -230,6 +234,7 @@ export default function ItemActions< Item extends AnyItem >( {
230
234
  key={ action.id }
231
235
  action={ action }
232
236
  onClick={ () => action.callback( [ item ] ) }
237
+ items={ [ item ] }
233
238
  />
234
239
  );
235
240
  } ) }
@@ -249,6 +254,7 @@ function CompactItemActions< Item extends AnyItem >( {
249
254
  size="compact"
250
255
  icon={ moreVertical }
251
256
  label={ __( 'Actions' ) }
257
+ __experimentalIsFocusable
252
258
  disabled={ ! actions.length }
253
259
  className="dataviews-all-actions-button"
254
260
  />
@@ -74,7 +74,7 @@ const Pagination = memo( function Pagination( {
74
74
  page: +newValue,
75
75
  } );
76
76
  } }
77
- size={ 'compact' }
77
+ size="compact"
78
78
  __nextHasNoMarginBottom
79
79
  />
80
80
  ),
@@ -4,8 +4,23 @@
4
4
  import { Button } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- export default function ResetFilter( { filters, view, onChangeView } ) {
8
- const isPrimary = ( field ) =>
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { NormalizedFilter, View } from './types';
11
+
12
+ interface ResetFilterProps {
13
+ filters: NormalizedFilter[];
14
+ view: View;
15
+ onChangeView: ( view: View ) => void;
16
+ }
17
+
18
+ export default function ResetFilter( {
19
+ filters,
20
+ view,
21
+ onChangeView,
22
+ }: ResetFilterProps ) {
23
+ const isPrimary = ( field: string ) =>
9
24
  filters.some(
10
25
  ( _filter ) => _filter.field === field && _filter.isPrimary
11
26
  );
@@ -22,6 +22,7 @@ import { SVG, Circle } from '@wordpress/primitives';
22
22
  * Internal dependencies
23
23
  */
24
24
  import { unlock } from './lock-unlock';
25
+ import type { Filter, NormalizedFilter, View } from './types';
25
26
 
26
27
  const {
27
28
  CompositeV2: Composite,
@@ -29,6 +30,12 @@ const {
29
30
  useCompositeStoreV2: useCompositeStore,
30
31
  } = unlock( componentsPrivateApis );
31
32
 
33
+ interface SearchWidgetProps {
34
+ view: View;
35
+ filter: NormalizedFilter;
36
+ onChangeView: ( view: View ) => void;
37
+ }
38
+
32
39
  const radioCheck = (
33
40
  <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
34
41
  <Circle cx={ 12 } cy={ 12 } r={ 3 }></Circle>
@@ -39,8 +46,11 @@ function normalizeSearchInput( input = '' ) {
39
46
  return removeAccents( input.trim().toLowerCase() );
40
47
  }
41
48
 
42
- const EMPTY_ARRAY = [];
43
- const getCurrentValue = ( filterDefinition, currentFilter ) => {
49
+ const EMPTY_ARRAY: [] = [];
50
+ const getCurrentValue = (
51
+ filterDefinition: NormalizedFilter,
52
+ currentFilter?: Filter
53
+ ) => {
44
54
  if ( filterDefinition.singleSelection ) {
45
55
  return currentFilter?.value;
46
56
  }
@@ -56,7 +66,11 @@ const getCurrentValue = ( filterDefinition, currentFilter ) => {
56
66
  return EMPTY_ARRAY;
57
67
  };
58
68
 
59
- const getNewValue = ( filterDefinition, currentFilter, value ) => {
69
+ const getNewValue = (
70
+ filterDefinition: NormalizedFilter,
71
+ currentFilter: Filter | undefined,
72
+ value: any
73
+ ) => {
60
74
  if ( filterDefinition.singleSelection ) {
61
75
  return value;
62
76
  }
@@ -70,7 +84,7 @@ const getNewValue = ( filterDefinition, currentFilter, value ) => {
70
84
  return [ value ];
71
85
  };
72
86
 
73
- function ListBox( { view, filter, onChangeView } ) {
87
+ function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
74
88
  const compositeStore = useCompositeStore( {
75
89
  virtualFocus: true,
76
90
  focusLoop: true,
@@ -184,7 +198,7 @@ function ListBox( { view, filter, onChangeView } ) {
184
198
  );
185
199
  }
186
200
 
187
- function ComboboxList( { view, filter, onChangeView } ) {
201
+ function ComboboxList( { view, filter, onChangeView }: SearchWidgetProps ) {
188
202
  const [ searchValue, setSearchValue ] = useState( '' );
189
203
  const deferredSearchValue = useDeferredValue( searchValue );
190
204
  const currentFilter = view.filters.find(
@@ -234,7 +248,13 @@ function ComboboxList( { view, filter, onChangeView } ) {
234
248
  setValue={ setSearchValue }
235
249
  >
236
250
  <div className="dataviews-search-widget-filter-combobox__wrapper">
237
- <Ariakit.ComboboxLabel render={ <VisuallyHidden /> }>
251
+ <Ariakit.ComboboxLabel
252
+ render={
253
+ <VisuallyHidden>
254
+ { __( 'Search items' ) }
255
+ </VisuallyHidden>
256
+ }
257
+ >
238
258
  { __( 'Search items' ) }
239
259
  </Ariakit.ComboboxLabel>
240
260
  <Ariakit.Combobox
@@ -290,7 +310,7 @@ function ComboboxList( { view, filter, onChangeView } ) {
290
310
  );
291
311
  }
292
312
 
293
- export default function SearchWidget( props ) {
313
+ export default function SearchWidget( props: SearchWidgetProps ) {
294
314
  const Widget = props.filter.elements.length > 10 ? ComboboxList : ListBox;
295
315
  return <Widget { ...props } />;
296
316
  }
@@ -6,20 +6,37 @@ import { useEffect, useRef, memo } from '@wordpress/element';
6
6
  import { SearchControl } from '@wordpress/components';
7
7
  import { useDebouncedInput } from '@wordpress/compose';
8
8
 
9
- const Search = memo( function Search( { label, view, onChangeView } ) {
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import type { View } from './types';
13
+
14
+ interface SearchProps {
15
+ label?: string;
16
+ view: View;
17
+ onChangeView: ( view: View ) => void;
18
+ }
19
+
20
+ const Search = memo( function Search( {
21
+ label,
22
+ view,
23
+ onChangeView,
24
+ }: SearchProps ) {
10
25
  const [ search, setSearch, debouncedSearch ] = useDebouncedInput(
11
26
  view.search
12
27
  );
13
28
  useEffect( () => {
14
- setSearch( view.search );
15
- }, [ view ] );
29
+ setSearch( view.search ?? '' );
30
+ }, [ view.search, setSearch ] );
16
31
  const onChangeViewRef = useRef( onChangeView );
32
+ const viewRef = useRef( view );
17
33
  useEffect( () => {
18
34
  onChangeViewRef.current = onChangeView;
19
- }, [ onChangeView ] );
35
+ viewRef.current = view;
36
+ }, [ onChangeView, view ] );
20
37
  useEffect( () => {
21
38
  onChangeViewRef.current( {
22
- ...view,
39
+ ...viewRef.current,
23
40
  page: 1,
24
41
  search: debouncedSearch,
25
42
  } );