@wordpress/dataviews 1.1.0 → 1.2.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 (124) hide show
  1. package/CHANGELOG.md +11 -5
  2. package/build/bulk-actions-toolbar.js +182 -0
  3. package/build/bulk-actions-toolbar.js.map +1 -0
  4. package/build/bulk-actions.js +8 -8
  5. package/build/bulk-actions.js.map +1 -1
  6. package/build/dataviews.js +11 -4
  7. package/build/dataviews.js.map +1 -1
  8. package/build/filter-and-sort-data-view.js +2 -2
  9. package/build/filter-and-sort-data-view.js.map +1 -1
  10. package/build/filter-summary.js +3 -3
  11. package/build/filter-summary.js.map +1 -1
  12. package/build/item-actions.js +41 -22
  13. package/build/item-actions.js.map +1 -1
  14. package/build/lock-unlock.js.map +1 -1
  15. package/build/normalize-fields.js.map +1 -1
  16. package/build/pagination.js +13 -7
  17. package/build/pagination.js.map +1 -1
  18. package/build/single-selection-checkbox.js +4 -0
  19. package/build/single-selection-checkbox.js.map +1 -1
  20. package/build/types.js.map +1 -1
  21. package/build/view-grid.js +9 -10
  22. package/build/view-grid.js.map +1 -1
  23. package/build/view-list.js +134 -21
  24. package/build/view-list.js.map +1 -1
  25. package/build/view-table.js +9 -9
  26. package/build/view-table.js.map +1 -1
  27. package/build-module/bulk-actions-toolbar.js +175 -0
  28. package/build-module/bulk-actions-toolbar.js.map +1 -0
  29. package/build-module/bulk-actions.js +8 -8
  30. package/build-module/bulk-actions.js.map +1 -1
  31. package/build-module/dataviews.js +11 -4
  32. package/build-module/dataviews.js.map +1 -1
  33. package/build-module/filter-and-sort-data-view.js +2 -2
  34. package/build-module/filter-and-sort-data-view.js.map +1 -1
  35. package/build-module/filter-summary.js +3 -3
  36. package/build-module/filter-summary.js.map +1 -1
  37. package/build-module/item-actions.js +40 -24
  38. package/build-module/item-actions.js.map +1 -1
  39. package/build-module/lock-unlock.js.map +1 -1
  40. package/build-module/normalize-fields.js.map +1 -1
  41. package/build-module/pagination.js +14 -7
  42. package/build-module/pagination.js.map +1 -1
  43. package/build-module/single-selection-checkbox.js +5 -0
  44. package/build-module/single-selection-checkbox.js.map +1 -1
  45. package/build-module/types.js.map +1 -1
  46. package/build-module/view-grid.js +9 -10
  47. package/build-module/view-grid.js.map +1 -1
  48. package/build-module/view-list.js +135 -23
  49. package/build-module/view-list.js.map +1 -1
  50. package/build-module/view-table.js +9 -9
  51. package/build-module/view-table.js.map +1 -1
  52. package/build-style/style-rtl.css +62 -27
  53. package/build-style/style.css +62 -27
  54. package/build-types/add-filter.d.ts +8 -0
  55. package/build-types/add-filter.d.ts.map +1 -0
  56. package/build-types/bulk-actions-toolbar.d.ts +8 -0
  57. package/build-types/bulk-actions-toolbar.d.ts.map +1 -0
  58. package/build-types/bulk-actions.d.ts +14 -0
  59. package/build-types/bulk-actions.d.ts.map +1 -0
  60. package/build-types/dataviews.d.ts +15 -0
  61. package/build-types/dataviews.d.ts.map +1 -0
  62. package/build-types/dropdown-menu-helper.d.ts +6 -0
  63. package/build-types/dropdown-menu-helper.d.ts.map +1 -0
  64. package/build-types/filter-and-sort-data-view.d.ts +3 -3
  65. package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
  66. package/build-types/filter-summary.d.ts +6 -0
  67. package/build-types/filter-summary.d.ts.map +1 -0
  68. package/build-types/filters.d.ts +3 -0
  69. package/build-types/filters.d.ts.map +1 -0
  70. package/build-types/index.d.ts +4 -0
  71. package/build-types/index.d.ts.map +1 -0
  72. package/build-types/item-actions.d.ts +37 -0
  73. package/build-types/item-actions.d.ts.map +1 -0
  74. package/build-types/layouts.d.ts +20 -0
  75. package/build-types/layouts.d.ts.map +1 -0
  76. package/build-types/lock-unlock.d.ts +2 -0
  77. package/build-types/lock-unlock.d.ts.map +1 -0
  78. package/build-types/normalize-fields.d.ts +2 -2
  79. package/build-types/normalize-fields.d.ts.map +1 -1
  80. package/build-types/pagination.d.ts +16 -0
  81. package/build-types/pagination.d.ts.map +1 -0
  82. package/build-types/reset-filters.d.ts +6 -0
  83. package/build-types/reset-filters.d.ts.map +1 -0
  84. package/build-types/search-widget.d.ts +2 -0
  85. package/build-types/search-widget.d.ts.map +1 -0
  86. package/build-types/search.d.ts +3 -0
  87. package/build-types/search.d.ts.map +1 -0
  88. package/build-types/single-selection-checkbox.d.ts +17 -0
  89. package/build-types/single-selection-checkbox.d.ts.map +1 -0
  90. package/build-types/stories/fixtures.d.ts +114 -0
  91. package/build-types/stories/fixtures.d.ts.map +1 -0
  92. package/build-types/stories/index.story.d.ts +15 -0
  93. package/build-types/stories/index.story.d.ts.map +1 -0
  94. package/build-types/types.d.ts +152 -20
  95. package/build-types/types.d.ts.map +1 -1
  96. package/build-types/utils.d.ts +2 -0
  97. package/build-types/utils.d.ts.map +1 -0
  98. package/build-types/view-actions.d.ts +3 -0
  99. package/build-types/view-actions.d.ts.map +1 -0
  100. package/build-types/view-grid.d.ts +15 -0
  101. package/build-types/view-grid.d.ts.map +1 -0
  102. package/build-types/view-list.d.ts +16 -0
  103. package/build-types/view-list.d.ts.map +1 -0
  104. package/build-types/view-table.d.ts +14 -0
  105. package/build-types/view-table.d.ts.map +1 -0
  106. package/package.json +12 -12
  107. package/src/bulk-actions-toolbar.js +244 -0
  108. package/src/{bulk-actions.js → bulk-actions.tsx} +73 -17
  109. package/src/dataviews.js +14 -3
  110. package/src/filter-and-sort-data-view.ts +13 -8
  111. package/src/filter-summary.js +3 -3
  112. package/src/{item-actions.js → item-actions.tsx} +112 -28
  113. package/src/normalize-fields.ts +4 -2
  114. package/src/{pagination.js → pagination.tsx} +28 -7
  115. package/src/{single-selection-checkbox.js → single-selection-checkbox.tsx} +17 -2
  116. package/src/style.scss +77 -28
  117. package/src/types.ts +190 -20
  118. package/src/{view-grid.js → view-grid.tsx} +45 -16
  119. package/src/view-list.tsx +421 -0
  120. package/src/view-table.js +8 -8
  121. package/tsconfig.json +4 -2
  122. package/tsconfig.tsbuildinfo +1 -1
  123. package/src/view-list.js +0 -207
  124. /package/src/{lock-unlock.js → lock-unlock.ts} +0 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ ToolbarButton,
6
+ Toolbar,
7
+ ToolbarGroup,
8
+ __unstableMotion as motion,
9
+ __unstableAnimatePresence as AnimatePresence,
10
+ } from '@wordpress/components';
11
+ import { useMemo, useState, useRef } from '@wordpress/element';
12
+ import { _n, sprintf, __ } from '@wordpress/i18n';
13
+ import { closeSmall } from '@wordpress/icons';
14
+ import { useReducedMotion } from '@wordpress/compose';
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import { ActionWithModal } from './item-actions';
20
+
21
+ const SNACKBAR_VARIANTS = {
22
+ init: {
23
+ bottom: -48,
24
+ },
25
+ open: {
26
+ bottom: 24,
27
+ transition: {
28
+ bottom: { type: 'tween', duration: 0.2, ease: [ 0, 0, 0.2, 1 ] },
29
+ },
30
+ },
31
+ exit: {
32
+ opacity: 0,
33
+ bottom: 24,
34
+ transition: {
35
+ opacity: { type: 'tween', duration: 0.2, ease: [ 0, 0, 0.2, 1 ] },
36
+ },
37
+ },
38
+ };
39
+
40
+ function ActionTrigger( { action, onClick, isBusy } ) {
41
+ return (
42
+ <ToolbarButton
43
+ disabled={ isBusy }
44
+ label={ action.label }
45
+ icon={ action.icon }
46
+ isDestructive={ action.isDestructive }
47
+ size="compact"
48
+ onClick={ onClick }
49
+ isBusy={ isBusy }
50
+ __experimentalIsFocusable
51
+ tooltipPosition="top"
52
+ />
53
+ );
54
+ }
55
+
56
+ const EMPTY_ARRAY = [];
57
+
58
+ function ActionButton( {
59
+ action,
60
+ selectedItems,
61
+ actionInProgress,
62
+ setActionInProgress,
63
+ } ) {
64
+ const selectedEligibleItems = useMemo( () => {
65
+ return selectedItems.filter( ( item ) => {
66
+ return action.isEligible( item );
67
+ } );
68
+ }, [ action, selectedItems ] );
69
+ if ( !! action.RenderModal ) {
70
+ return (
71
+ <ActionWithModal
72
+ key={ action.id }
73
+ action={ action }
74
+ items={ selectedEligibleItems }
75
+ ActionTrigger={ ActionTrigger }
76
+ onActionStart={ () => {
77
+ setActionInProgress( action.id );
78
+ } }
79
+ onActionPerformed={ () => {
80
+ setActionInProgress( null );
81
+ } }
82
+ />
83
+ );
84
+ }
85
+ return (
86
+ <ActionTrigger
87
+ key={ action.id }
88
+ action={ action }
89
+ items={ selectedItems }
90
+ onClick={ () => {
91
+ setActionInProgress( action.id );
92
+ action.callback( selectedItems, () => {
93
+ setActionInProgress( action.id );
94
+ } );
95
+ } }
96
+ isBusy={ actionInProgress === action.id }
97
+ />
98
+ );
99
+ }
100
+
101
+ function renderToolbarContent(
102
+ selection,
103
+ actionsToShow,
104
+ selectedItems,
105
+ actionInProgress,
106
+ setActionInProgress,
107
+ setSelection
108
+ ) {
109
+ return (
110
+ <>
111
+ <ToolbarGroup>
112
+ <div className="dataviews-bulk-actions__selection-count">
113
+ { selection.length === 1
114
+ ? __( '1 item selected' )
115
+ : sprintf(
116
+ // translators: %s: Total number of selected items.
117
+ _n(
118
+ '%s item selected',
119
+ '%s items selected',
120
+ selection.length
121
+ ),
122
+ selection.length
123
+ ) }
124
+ </div>
125
+ </ToolbarGroup>
126
+ <ToolbarGroup>
127
+ { actionsToShow.map( ( action ) => {
128
+ return (
129
+ <ActionButton
130
+ key={ action.id }
131
+ action={ action }
132
+ selectedItems={ selectedItems }
133
+ actionInProgress={ actionInProgress }
134
+ setActionInProgress={ setActionInProgress }
135
+ />
136
+ );
137
+ } ) }
138
+ </ToolbarGroup>
139
+ <ToolbarGroup>
140
+ <ToolbarButton
141
+ icon={ closeSmall }
142
+ showTooltip
143
+ tooltipPosition="top"
144
+ label={ __( 'Cancel' ) }
145
+ disabled={ !! actionInProgress }
146
+ onClick={ () => {
147
+ setSelection( EMPTY_ARRAY );
148
+ } }
149
+ />
150
+ </ToolbarGroup>
151
+ </>
152
+ );
153
+ }
154
+
155
+ function ToolbarContent( {
156
+ selection,
157
+ actionsToShow,
158
+ selectedItems,
159
+ setSelection,
160
+ } ) {
161
+ const [ actionInProgress, setActionInProgress ] = useState( null );
162
+ const buttons = useRef( null );
163
+ if ( ! actionInProgress ) {
164
+ if ( buttons.current ) {
165
+ buttons.current = null;
166
+ }
167
+ return renderToolbarContent(
168
+ selection,
169
+ actionsToShow,
170
+ selectedItems,
171
+ actionInProgress,
172
+ setActionInProgress,
173
+ setSelection
174
+ );
175
+ } else if ( ! buttons.current ) {
176
+ buttons.current = renderToolbarContent(
177
+ selection,
178
+ actionsToShow,
179
+ selectedItems,
180
+ actionInProgress,
181
+ setActionInProgress,
182
+ setSelection
183
+ );
184
+ }
185
+ return buttons.current;
186
+ }
187
+
188
+ export default function BulkActionsToolbar( {
189
+ data,
190
+ selection,
191
+ actions = EMPTY_ARRAY,
192
+ setSelection,
193
+ getItemId,
194
+ } ) {
195
+ const isReducedMotion = useReducedMotion();
196
+ const selectedItems = useMemo( () => {
197
+ return data.filter( ( item ) =>
198
+ selection.includes( getItemId( item ) )
199
+ );
200
+ }, [ selection, data, getItemId ] );
201
+
202
+ const actionsToShow = useMemo(
203
+ () =>
204
+ actions.filter( ( action ) => {
205
+ return (
206
+ action.supportsBulk &&
207
+ action.icon &&
208
+ selectedItems.some( ( item ) => action.isEligible( item ) )
209
+ );
210
+ } ),
211
+ [ actions, selectedItems ]
212
+ );
213
+
214
+ if (
215
+ ( selection && selection.length === 0 ) ||
216
+ actionsToShow.length === 0
217
+ ) {
218
+ return null;
219
+ }
220
+
221
+ return (
222
+ <AnimatePresence>
223
+ <motion.div
224
+ layout={ ! isReducedMotion } // See https://www.framer.com/docs/animation/#layout-animations
225
+ initial={ 'init' }
226
+ animate={ 'open' }
227
+ exit={ 'exit' }
228
+ variants={ isReducedMotion ? undefined : SNACKBAR_VARIANTS }
229
+ className="dataviews-bulk-actions"
230
+ >
231
+ <Toolbar label={ __( 'Bulk actions' ) }>
232
+ <div className="dataviews-bulk-actions-toolbar-wrapper">
233
+ <ToolbarContent
234
+ selection={ selection }
235
+ actionsToShow={ actionsToShow }
236
+ selectedItems={ selectedItems }
237
+ setSelection={ setSelection }
238
+ />
239
+ </div>
240
+ </Toolbar>
241
+ </motion.div>
242
+ </AnimatePresence>
243
+ );
244
+ }
@@ -13,6 +13,7 @@ import { useMemo, useState, useCallback, useEffect } from '@wordpress/element';
13
13
  * Internal dependencies
14
14
  */
15
15
  import { unlock } from './lock-unlock';
16
+ import type { Action, ActionModal, AnyItem } from './types';
16
17
 
17
18
  const {
18
19
  DropdownMenuV2: DropdownMenu,
@@ -21,32 +22,73 @@ const {
21
22
  DropdownMenuSeparatorV2: DropdownMenuSeparator,
22
23
  } = unlock( componentsPrivateApis );
23
24
 
24
- export function useHasAPossibleBulkAction( actions, item ) {
25
+ interface ActionWithModalProps< Item extends AnyItem > {
26
+ action: ActionModal< Item >;
27
+ selectedItems: Item[];
28
+ setActionWithModal: ( action?: ActionModal< Item > ) => void;
29
+ onMenuOpenChange: ( isOpen: boolean ) => void;
30
+ }
31
+
32
+ interface BulkActionsItemProps< Item extends AnyItem > {
33
+ action: Action< Item >;
34
+ selectedItems: Item[];
35
+ setActionWithModal: ( action?: ActionModal< Item > ) => void;
36
+ }
37
+
38
+ interface ActionsMenuGroupProps< Item extends AnyItem > {
39
+ actions: Action< Item >[];
40
+ selectedItems: Item[];
41
+ setActionWithModal: ( action?: ActionModal< Item > ) => void;
42
+ }
43
+
44
+ interface BulkActionsProps< Item extends AnyItem > {
45
+ data: Item[];
46
+ actions: Action< Item >[];
47
+ selection: string[];
48
+ onSelectionChange: ( selection: Item[] ) => void;
49
+ getItemId: ( item: Item ) => string;
50
+ }
51
+
52
+ export function useHasAPossibleBulkAction< Item extends AnyItem >(
53
+ actions: Action< Item >[],
54
+ item: Item
55
+ ) {
25
56
  return useMemo( () => {
26
57
  return actions.some( ( action ) => {
27
- return action.supportsBulk && action.isEligible( item );
58
+ return (
59
+ action.supportsBulk &&
60
+ ( ! action.isEligible || action.isEligible( item ) )
61
+ );
28
62
  } );
29
63
  }, [ actions, item ] );
30
64
  }
31
65
 
32
- export function useSomeItemHasAPossibleBulkAction( actions, data ) {
66
+ export function useSomeItemHasAPossibleBulkAction< Item extends AnyItem >(
67
+ actions: Action< Item >[],
68
+ data: Item[]
69
+ ) {
33
70
  return useMemo( () => {
34
71
  return data.some( ( item ) => {
35
72
  return actions.some( ( action ) => {
36
- return action.supportsBulk && action.isEligible( item );
73
+ return (
74
+ action.supportsBulk &&
75
+ ( ! action.isEligible || action.isEligible( item ) )
76
+ );
37
77
  } );
38
78
  } );
39
79
  }, [ actions, data ] );
40
80
  }
41
81
 
42
- function ActionWithModal( {
82
+ function ActionWithModal< Item extends AnyItem >( {
43
83
  action,
44
84
  selectedItems,
45
85
  setActionWithModal,
46
86
  onMenuOpenChange,
47
- } ) {
87
+ }: ActionWithModalProps< Item > ) {
48
88
  const eligibleItems = useMemo( () => {
49
- return selectedItems.filter( ( item ) => action.isEligible( item ) );
89
+ return selectedItems.filter(
90
+ ( item ) => ! action.isEligible || action.isEligible( item )
91
+ );
50
92
  }, [ action, selectedItems ] );
51
93
  const { RenderModal, hideModalHeader } = action;
52
94
  const onCloseModal = useCallback( () => {
@@ -54,7 +96,7 @@ function ActionWithModal( {
54
96
  }, [ setActionWithModal ] );
55
97
  return (
56
98
  <Modal
57
- title={ ! hideModalHeader && action.label }
99
+ title={ ! hideModalHeader ? action.label : undefined }
58
100
  __experimentalHideHeader={ !! hideModalHeader }
59
101
  onRequestClose={ onCloseModal }
60
102
  overlayClassName="dataviews-action-modal"
@@ -62,18 +104,24 @@ function ActionWithModal( {
62
104
  <RenderModal
63
105
  items={ eligibleItems }
64
106
  closeModal={ onCloseModal }
65
- onPerform={ () => onMenuOpenChange( false ) }
107
+ onActionPerformed={ () => onMenuOpenChange( false ) }
66
108
  />
67
109
  </Modal>
68
110
  );
69
111
  }
70
112
 
71
- function BulkActionItem( { action, selectedItems, setActionWithModal } ) {
113
+ function BulkActionItem< Item extends AnyItem >( {
114
+ action,
115
+ selectedItems,
116
+ setActionWithModal,
117
+ }: BulkActionsItemProps< Item > ) {
72
118
  const eligibleItems = useMemo( () => {
73
- return selectedItems.filter( ( item ) => action.isEligible( item ) );
119
+ return selectedItems.filter(
120
+ ( item ) => ! action.isEligible || action.isEligible( item )
121
+ );
74
122
  }, [ action, selectedItems ] );
75
123
 
76
- const shouldShowModal = !! action.RenderModal;
124
+ const shouldShowModal = 'RenderModal' in action;
77
125
 
78
126
  return (
79
127
  <DropdownMenuItem
@@ -96,7 +144,11 @@ function BulkActionItem( { action, selectedItems, setActionWithModal } ) {
96
144
  );
97
145
  }
98
146
 
99
- function ActionsMenuGroup( { actions, selectedItems, setActionWithModal } ) {
147
+ function ActionsMenuGroup< Item extends AnyItem >( {
148
+ actions,
149
+ selectedItems,
150
+ setActionWithModal,
151
+ }: ActionsMenuGroupProps< Item > ) {
100
152
  return (
101
153
  <>
102
154
  <DropdownMenuGroup>
@@ -114,22 +166,26 @@ function ActionsMenuGroup( { actions, selectedItems, setActionWithModal } ) {
114
166
  );
115
167
  }
116
168
 
117
- export default function BulkActions( {
169
+ export default function BulkActions< Item extends AnyItem >( {
118
170
  data,
119
171
  actions,
120
172
  selection,
121
173
  onSelectionChange,
122
174
  getItemId,
123
- } ) {
175
+ }: BulkActionsProps< Item > ) {
124
176
  const bulkActions = useMemo(
125
177
  () => actions.filter( ( action ) => action.supportsBulk ),
126
178
  [ actions ]
127
179
  );
128
180
  const [ isMenuOpen, onMenuOpenChange ] = useState( false );
129
- const [ actionWithModal, setActionWithModal ] = useState();
181
+ const [ actionWithModal, setActionWithModal ] = useState<
182
+ ActionModal< Item > | undefined
183
+ >();
130
184
  const selectableItems = useMemo( () => {
131
185
  return data.filter( ( item ) => {
132
- return bulkActions.some( ( action ) => action.isEligible( item ) );
186
+ return bulkActions.some(
187
+ ( action ) => ! action.isEligible || action.isEligible( item )
188
+ );
133
189
  } );
134
190
  }, [ data, bulkActions ] );
135
191
 
package/src/dataviews.js CHANGED
@@ -15,6 +15,7 @@ import { LAYOUT_TABLE, LAYOUT_GRID } from './constants';
15
15
  import { VIEW_LAYOUTS } from './layouts';
16
16
  import BulkActions from './bulk-actions';
17
17
  import { normalizeFields } from './normalize-fields';
18
+ import BulkActionsToolbar from './bulk-actions-toolbar';
18
19
 
19
20
  const defaultGetItemId = ( item ) => item.id;
20
21
  const defaultOnSelectionChange = () => {};
@@ -127,22 +128,32 @@ export default function DataViews( {
127
128
  />
128
129
  </HStack>
129
130
  <ViewComponent
130
- fields={ _fields }
131
- view={ view }
132
- onChangeView={ onChangeView }
133
131
  actions={ actions }
134
132
  data={ data }
133
+ fields={ _fields }
135
134
  getItemId={ getItemId }
136
135
  isLoading={ isLoading }
136
+ onChangeView={ onChangeView }
137
137
  onSelectionChange={ onSetSelection }
138
138
  selection={ selection }
139
139
  setOpenedFilter={ setOpenedFilter }
140
+ view={ view }
140
141
  />
141
142
  <Pagination
142
143
  view={ view }
143
144
  onChangeView={ onChangeView }
144
145
  paginationInfo={ paginationInfo }
145
146
  />
147
+ { [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type ) &&
148
+ hasPossibleBulkAction && (
149
+ <BulkActionsToolbar
150
+ data={ data }
151
+ actions={ actions }
152
+ selection={ selection }
153
+ setSelection={ setSelection }
154
+ getItemId={ getItemId }
155
+ />
156
+ ) }
146
157
  </div>
147
158
  );
148
159
  }
@@ -15,13 +15,13 @@ import {
15
15
  OPERATOR_IS_NOT_ALL,
16
16
  } from './constants';
17
17
  import { normalizeFields } from './normalize-fields';
18
- import type { Data, Field, View } from './types';
18
+ import type { Field, AnyItem, View } from './types';
19
19
 
20
20
  function normalizeSearchInput( input = '' ) {
21
21
  return removeAccents( input.trim().toLowerCase() );
22
22
  }
23
23
 
24
- const EMPTY_ARRAY: Data = [];
24
+ const EMPTY_ARRAY: [] = [];
25
25
 
26
26
  /**
27
27
  * Applies the filtering, sorting and pagination to the raw data based on the view configuration.
@@ -32,11 +32,14 @@ const EMPTY_ARRAY: Data = [];
32
32
  *
33
33
  * @return Filtered, sorted and paginated data.
34
34
  */
35
- export function filterSortAndPaginate(
36
- data: Data,
35
+ export function filterSortAndPaginate< Item extends AnyItem >(
36
+ data: Item[],
37
37
  view: View,
38
- fields: Field[]
39
- ): { data: Data; paginationInfo: { totalItems: number; totalPages: number } } {
38
+ fields: Field< Item >[]
39
+ ): {
40
+ data: Item[];
41
+ paginationInfo: { totalItems: number; totalPages: number };
42
+ } {
40
43
  if ( ! data ) {
41
44
  return {
42
45
  data: EMPTY_ARRAY,
@@ -100,7 +103,9 @@ export function filterSortAndPaginate(
100
103
  ) {
101
104
  filteredData = filteredData.filter( ( item ) => {
102
105
  return filter.value.every( ( value: any ) => {
103
- return field.getValue( { item } ).includes( value );
106
+ return field
107
+ .getValue( { item } )
108
+ ?.includes( value );
104
109
  } );
105
110
  } );
106
111
  } else if (
@@ -111,7 +116,7 @@ export function filterSortAndPaginate(
111
116
  return filter.value.every( ( value: any ) => {
112
117
  return ! field
113
118
  .getValue( { item } )
114
- .includes( value );
119
+ ?.includes( value );
115
120
  } );
116
121
  } );
117
122
  } else if ( filter.operator === OPERATOR_IS ) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import classnames from 'classnames';
4
+ import clsx from 'clsx';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -220,7 +220,7 @@ export default function FilterSummary( {
220
220
  placement="top"
221
221
  >
222
222
  <div
223
- className={ classnames(
223
+ className={ clsx(
224
224
  'dataviews-filter-summary__chip',
225
225
  {
226
226
  'has-reset': canResetOrRemove,
@@ -253,7 +253,7 @@ export default function FilterSummary( {
253
253
  placement="top"
254
254
  >
255
255
  <button
256
- className={ classnames(
256
+ className={ clsx(
257
257
  'dataviews-filter-summary__chip-remove',
258
258
  { 'has-values': hasValues }
259
259
  ) }