@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.
- package/CHANGELOG.md +11 -5
- package/build/bulk-actions-toolbar.js +182 -0
- package/build/bulk-actions-toolbar.js.map +1 -0
- package/build/bulk-actions.js +8 -8
- package/build/bulk-actions.js.map +1 -1
- package/build/dataviews.js +11 -4
- package/build/dataviews.js.map +1 -1
- package/build/filter-and-sort-data-view.js +2 -2
- package/build/filter-and-sort-data-view.js.map +1 -1
- package/build/filter-summary.js +3 -3
- package/build/filter-summary.js.map +1 -1
- package/build/item-actions.js +41 -22
- package/build/item-actions.js.map +1 -1
- package/build/lock-unlock.js.map +1 -1
- package/build/normalize-fields.js.map +1 -1
- package/build/pagination.js +13 -7
- package/build/pagination.js.map +1 -1
- package/build/single-selection-checkbox.js +4 -0
- package/build/single-selection-checkbox.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build/view-grid.js +9 -10
- package/build/view-grid.js.map +1 -1
- package/build/view-list.js +134 -21
- package/build/view-list.js.map +1 -1
- package/build/view-table.js +9 -9
- package/build/view-table.js.map +1 -1
- package/build-module/bulk-actions-toolbar.js +175 -0
- package/build-module/bulk-actions-toolbar.js.map +1 -0
- package/build-module/bulk-actions.js +8 -8
- package/build-module/bulk-actions.js.map +1 -1
- package/build-module/dataviews.js +11 -4
- package/build-module/dataviews.js.map +1 -1
- package/build-module/filter-and-sort-data-view.js +2 -2
- package/build-module/filter-and-sort-data-view.js.map +1 -1
- package/build-module/filter-summary.js +3 -3
- package/build-module/filter-summary.js.map +1 -1
- package/build-module/item-actions.js +40 -24
- package/build-module/item-actions.js.map +1 -1
- package/build-module/lock-unlock.js.map +1 -1
- package/build-module/normalize-fields.js.map +1 -1
- package/build-module/pagination.js +14 -7
- package/build-module/pagination.js.map +1 -1
- package/build-module/single-selection-checkbox.js +5 -0
- package/build-module/single-selection-checkbox.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-module/view-grid.js +9 -10
- package/build-module/view-grid.js.map +1 -1
- package/build-module/view-list.js +135 -23
- package/build-module/view-list.js.map +1 -1
- package/build-module/view-table.js +9 -9
- package/build-module/view-table.js.map +1 -1
- package/build-style/style-rtl.css +62 -27
- package/build-style/style.css +62 -27
- package/build-types/add-filter.d.ts +8 -0
- package/build-types/add-filter.d.ts.map +1 -0
- package/build-types/bulk-actions-toolbar.d.ts +8 -0
- package/build-types/bulk-actions-toolbar.d.ts.map +1 -0
- package/build-types/bulk-actions.d.ts +14 -0
- package/build-types/bulk-actions.d.ts.map +1 -0
- package/build-types/dataviews.d.ts +15 -0
- package/build-types/dataviews.d.ts.map +1 -0
- package/build-types/dropdown-menu-helper.d.ts +6 -0
- package/build-types/dropdown-menu-helper.d.ts.map +1 -0
- package/build-types/filter-and-sort-data-view.d.ts +3 -3
- package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
- package/build-types/filter-summary.d.ts +6 -0
- package/build-types/filter-summary.d.ts.map +1 -0
- package/build-types/filters.d.ts +3 -0
- package/build-types/filters.d.ts.map +1 -0
- package/build-types/index.d.ts +4 -0
- package/build-types/index.d.ts.map +1 -0
- package/build-types/item-actions.d.ts +37 -0
- package/build-types/item-actions.d.ts.map +1 -0
- package/build-types/layouts.d.ts +20 -0
- package/build-types/layouts.d.ts.map +1 -0
- package/build-types/lock-unlock.d.ts +2 -0
- package/build-types/lock-unlock.d.ts.map +1 -0
- package/build-types/normalize-fields.d.ts +2 -2
- package/build-types/normalize-fields.d.ts.map +1 -1
- package/build-types/pagination.d.ts +16 -0
- package/build-types/pagination.d.ts.map +1 -0
- package/build-types/reset-filters.d.ts +6 -0
- package/build-types/reset-filters.d.ts.map +1 -0
- package/build-types/search-widget.d.ts +2 -0
- package/build-types/search-widget.d.ts.map +1 -0
- package/build-types/search.d.ts +3 -0
- package/build-types/search.d.ts.map +1 -0
- package/build-types/single-selection-checkbox.d.ts +17 -0
- package/build-types/single-selection-checkbox.d.ts.map +1 -0
- package/build-types/stories/fixtures.d.ts +114 -0
- package/build-types/stories/fixtures.d.ts.map +1 -0
- package/build-types/stories/index.story.d.ts +15 -0
- package/build-types/stories/index.story.d.ts.map +1 -0
- package/build-types/types.d.ts +152 -20
- package/build-types/types.d.ts.map +1 -1
- package/build-types/utils.d.ts +2 -0
- package/build-types/utils.d.ts.map +1 -0
- package/build-types/view-actions.d.ts +3 -0
- package/build-types/view-actions.d.ts.map +1 -0
- package/build-types/view-grid.d.ts +15 -0
- package/build-types/view-grid.d.ts.map +1 -0
- package/build-types/view-list.d.ts +16 -0
- package/build-types/view-list.d.ts.map +1 -0
- package/build-types/view-table.d.ts +14 -0
- package/build-types/view-table.d.ts.map +1 -0
- package/package.json +12 -12
- package/src/bulk-actions-toolbar.js +244 -0
- package/src/{bulk-actions.js → bulk-actions.tsx} +73 -17
- package/src/dataviews.js +14 -3
- package/src/filter-and-sort-data-view.ts +13 -8
- package/src/filter-summary.js +3 -3
- package/src/{item-actions.js → item-actions.tsx} +112 -28
- package/src/normalize-fields.ts +4 -2
- package/src/{pagination.js → pagination.tsx} +28 -7
- package/src/{single-selection-checkbox.js → single-selection-checkbox.tsx} +17 -2
- package/src/style.scss +77 -28
- package/src/types.ts +190 -20
- package/src/{view-grid.js → view-grid.tsx} +45 -16
- package/src/view-list.tsx +421 -0
- package/src/view-table.js +8 -8
- package/tsconfig.json +4 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/src/view-list.js +0 -207
- /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
|
-
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
107
|
+
onActionPerformed={ () => onMenuOpenChange( false ) }
|
|
66
108
|
/>
|
|
67
109
|
</Modal>
|
|
68
110
|
);
|
|
69
111
|
}
|
|
70
112
|
|
|
71
|
-
function BulkActionItem
|
|
113
|
+
function BulkActionItem< Item extends AnyItem >( {
|
|
114
|
+
action,
|
|
115
|
+
selectedItems,
|
|
116
|
+
setActionWithModal,
|
|
117
|
+
}: BulkActionsItemProps< Item > ) {
|
|
72
118
|
const eligibleItems = useMemo( () => {
|
|
73
|
-
return selectedItems.filter(
|
|
119
|
+
return selectedItems.filter(
|
|
120
|
+
( item ) => ! action.isEligible || action.isEligible( item )
|
|
121
|
+
);
|
|
74
122
|
}, [ action, selectedItems ] );
|
|
75
123
|
|
|
76
|
-
const shouldShowModal =
|
|
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
|
|
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(
|
|
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 {
|
|
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:
|
|
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:
|
|
35
|
+
export function filterSortAndPaginate< Item extends AnyItem >(
|
|
36
|
+
data: Item[],
|
|
37
37
|
view: View,
|
|
38
|
-
fields: Field[]
|
|
39
|
-
): {
|
|
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
|
|
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
|
-
|
|
119
|
+
?.includes( value );
|
|
115
120
|
} );
|
|
116
121
|
} );
|
|
117
122
|
} else if ( filter.operator === OPERATOR_IS ) {
|
package/src/filter-summary.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
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={
|
|
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={
|
|
256
|
+
className={ clsx(
|
|
257
257
|
'dataviews-filter-summary__chip-remove',
|
|
258
258
|
{ 'has-values': hasValues }
|
|
259
259
|
) }
|