@wordpress/dataviews 1.2.0 → 2.0.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 +16 -0
- package/README.md +33 -30
- package/build/add-filter.js +30 -22
- package/build/add-filter.js.map +1 -1
- package/build/bulk-actions-toolbar.js +74 -69
- package/build/bulk-actions-toolbar.js.map +1 -1
- package/build/bulk-actions.js +69 -56
- package/build/bulk-actions.js.map +1 -1
- package/build/constants.js +17 -10
- package/build/constants.js.map +1 -1
- package/build/dataviews.js +63 -56
- package/build/dataviews.js.map +1 -1
- package/build/filter-summary.js +105 -95
- package/build/filter-summary.js.map +1 -1
- package/build/filters.js +18 -17
- package/build/filters.js.map +1 -1
- package/build/index.js.map +1 -1
- package/build/item-actions.js +78 -65
- package/build/item-actions.js.map +1 -1
- package/build/layouts.js.map +1 -1
- package/build/pagination.js +60 -57
- package/build/pagination.js.map +1 -1
- package/build/reset-filters.js +9 -4
- package/build/reset-filters.js.map +1 -1
- package/build/search-widget.js +108 -89
- package/build/search-widget.js.map +1 -1
- package/build/search.js +13 -6
- package/build/search.js.map +1 -1
- package/build/single-selection-checkbox.js +2 -2
- package/build/single-selection-checkbox.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build/utils.js +3 -15
- package/build/utils.js.map +1 -1
- package/build/view-actions.js +168 -120
- package/build/view-actions.js.map +1 -1
- package/build/view-grid.js +113 -99
- package/build/view-grid.js.map +1 -1
- package/build/view-list.js +153 -132
- package/build/view-list.js.map +1 -1
- package/build/view-table.js +220 -192
- package/build/view-table.js.map +1 -1
- package/build-module/add-filter.js +30 -22
- package/build-module/add-filter.js.map +1 -1
- package/build-module/bulk-actions-toolbar.js +76 -69
- package/build-module/bulk-actions-toolbar.js.map +1 -1
- package/build-module/bulk-actions.js +71 -56
- package/build-module/bulk-actions.js.map +1 -1
- package/build-module/constants.js +16 -9
- package/build-module/constants.js.map +1 -1
- package/build-module/dataviews.js +64 -56
- package/build-module/dataviews.js.map +1 -1
- package/build-module/filter-summary.js +106 -96
- package/build-module/filter-summary.js.map +1 -1
- package/build-module/filters.js +18 -17
- package/build-module/filters.js.map +1 -1
- package/build-module/index.js.map +1 -1
- package/build-module/item-actions.js +80 -65
- package/build-module/item-actions.js.map +1 -1
- package/build-module/layouts.js.map +1 -1
- package/build-module/pagination.js +61 -58
- package/build-module/pagination.js.map +1 -1
- package/build-module/reset-filters.js +9 -4
- package/build-module/reset-filters.js.map +1 -1
- package/build-module/search-widget.js +109 -89
- package/build-module/search-widget.js.map +1 -1
- package/build-module/search.js +13 -6
- package/build-module/search.js.map +1 -1
- package/build-module/single-selection-checkbox.js +2 -3
- package/build-module/single-selection-checkbox.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-module/utils.js +2 -13
- package/build-module/utils.js.map +1 -1
- package/build-module/view-actions.js +170 -121
- package/build-module/view-actions.js.map +1 -1
- package/build-module/view-grid.js +115 -99
- package/build-module/view-grid.js.map +1 -1
- package/build-module/view-list.js +154 -132
- package/build-module/view-list.js.map +1 -1
- package/build-module/view-table.js +223 -194
- package/build-module/view-table.js.map +1 -1
- package/build-style/style-rtl.css +109 -20
- package/build-style/style.css +109 -20
- package/build-types/add-filter.d.ts +9 -6
- package/build-types/add-filter.d.ts.map +1 -1
- package/build-types/bulk-actions-toolbar.d.ts +11 -7
- package/build-types/bulk-actions-toolbar.d.ts.map +1 -1
- package/build-types/bulk-actions.d.ts.map +1 -1
- package/build-types/constants.d.ts +19 -32
- package/build-types/constants.d.ts.map +1 -1
- package/build-types/dataviews.d.ts +21 -14
- package/build-types/dataviews.d.ts.map +1 -1
- package/build-types/filter-summary.d.ts +13 -5
- package/build-types/filter-summary.d.ts.map +1 -1
- package/build-types/filters.d.ts +11 -1
- package/build-types/filters.d.ts.map +1 -1
- package/build-types/index.d.ts +3 -3
- package/build-types/index.d.ts.map +1 -1
- package/build-types/item-actions.d.ts +5 -7
- package/build-types/item-actions.d.ts.map +1 -1
- package/build-types/layouts.d.ts +8 -4
- package/build-types/layouts.d.ts.map +1 -1
- package/build-types/reset-filters.d.ts +12 -5
- package/build-types/reset-filters.d.ts.map +1 -1
- package/build-types/search-widget.d.ts +9 -1
- package/build-types/search-widget.d.ts.map +1 -1
- package/build-types/search.d.ts +11 -1
- package/build-types/search.d.ts.map +1 -1
- package/build-types/types.d.ts +78 -10
- package/build-types/types.d.ts.map +1 -1
- package/build-types/utils.d.ts +2 -1
- package/build-types/utils.d.ts.map +1 -1
- package/build-types/view-actions.d.ts +10 -1
- package/build-types/view-actions.d.ts.map +1 -1
- package/build-types/view-grid.d.ts +1 -12
- package/build-types/view-grid.d.ts.map +1 -1
- package/build-types/view-list.d.ts +2 -14
- package/build-types/view-list.d.ts.map +1 -1
- package/build-types/view-table.d.ts +3 -12
- package/build-types/view-table.d.ts.map +1 -1
- package/package.json +11 -12
- package/src/{add-filter.js → add-filter.tsx} +17 -1
- package/src/{bulk-actions-toolbar.js → bulk-actions-toolbar.tsx} +68 -40
- package/src/bulk-actions.tsx +5 -1
- package/src/constants.ts +12 -5
- package/src/{dataviews.js → dataviews.tsx} +41 -12
- package/src/{filter-summary.js → filter-summary.tsx} +35 -6
- package/src/{filters.js → filters.tsx} +18 -6
- package/src/item-actions.tsx +20 -15
- package/src/pagination.tsx +1 -1
- package/src/{reset-filters.js → reset-filters.tsx} +17 -2
- package/src/{search-widget.js → search-widget.tsx} +27 -7
- package/src/{search.js → search.tsx} +22 -5
- package/src/style.scss +97 -23
- package/src/types.ts +105 -10
- package/src/{utils.js → utils.ts} +5 -13
- package/src/{view-actions.js → view-actions.tsx} +105 -49
- package/src/view-grid.tsx +4 -20
- package/src/view-list.tsx +12 -23
- package/src/{view-table.js → view-table.tsx} +91 -32
- package/tsconfig.json +0 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/build/dropdown-menu-helper.js +0 -71
- package/build/dropdown-menu-helper.js.map +0 -1
- package/build-module/dropdown-menu-helper.js +0 -64
- package/build-module/dropdown-menu-helper.js.map +0 -1
- package/build-types/dropdown-menu-helper.d.ts +0 -6
- package/build-types/dropdown-menu-helper.d.ts.map +0 -1
- package/src/dropdown-menu-helper.js +0 -61
- /package/src/{index.js → index.ts} +0 -0
- /package/src/{layouts.js → layouts.ts} +0 -0
|
@@ -8,8 +8,11 @@ import {
|
|
|
8
8
|
OPERATOR_IS_ANY,
|
|
9
9
|
OPERATOR_IS_NONE,
|
|
10
10
|
} from './constants';
|
|
11
|
+
import type { AnyItem, NormalizedField } from './types';
|
|
11
12
|
|
|
12
|
-
export
|
|
13
|
+
export function sanitizeOperators< Item extends AnyItem >(
|
|
14
|
+
field: NormalizedField< Item >
|
|
15
|
+
) {
|
|
13
16
|
let operators = field.filterBy?.operators;
|
|
14
17
|
|
|
15
18
|
// Assign default values.
|
|
@@ -17,17 +20,6 @@ export const sanitizeOperators = ( field ) => {
|
|
|
17
20
|
operators = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
// Transform legacy in, notIn operators to is, isNot.
|
|
21
|
-
// To be removed in the future.
|
|
22
|
-
if ( operators.includes( 'in' ) ) {
|
|
23
|
-
operators = operators.filter( ( operator ) => operator !== 'is' );
|
|
24
|
-
operators.push( 'is' );
|
|
25
|
-
}
|
|
26
|
-
if ( operators.includes( 'notIn' ) ) {
|
|
27
|
-
operators = operators.filter( ( operator ) => operator !== 'notIn' );
|
|
28
|
-
operators.push( 'isNot' );
|
|
29
|
-
}
|
|
30
|
-
|
|
31
23
|
// Make sure only valid operators are used.
|
|
32
24
|
operators = operators.filter( ( operator ) =>
|
|
33
25
|
ALL_OPERATORS.includes( operator )
|
|
@@ -45,4 +37,4 @@ export const sanitizeOperators = ( field ) => {
|
|
|
45
37
|
}
|
|
46
38
|
|
|
47
39
|
return operators;
|
|
48
|
-
}
|
|
40
|
+
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import type { ChangeEvent } from 'react';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* WordPress dependencies
|
|
3
8
|
*/
|
|
@@ -13,8 +18,9 @@ import { settings } from '@wordpress/icons';
|
|
|
13
18
|
* Internal dependencies
|
|
14
19
|
*/
|
|
15
20
|
import { unlock } from './lock-unlock';
|
|
16
|
-
import { SORTING_DIRECTIONS } from './constants';
|
|
21
|
+
import { SORTING_DIRECTIONS, sortLabels } from './constants';
|
|
17
22
|
import { VIEW_LAYOUTS } from './layouts';
|
|
23
|
+
import type { AnyItem, NormalizedField, View } from './types';
|
|
18
24
|
|
|
19
25
|
const {
|
|
20
26
|
DropdownMenuV2: DropdownMenu,
|
|
@@ -25,7 +31,41 @@ const {
|
|
|
25
31
|
DropdownMenuItemLabelV2: DropdownMenuItemLabel,
|
|
26
32
|
} = unlock( componentsPrivateApis );
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
interface ViewTypeMenuProps {
|
|
35
|
+
view: View;
|
|
36
|
+
onChangeView: ( view: View ) => void;
|
|
37
|
+
supportedLayouts?: string[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface PageSizeMenuProps {
|
|
41
|
+
view: View;
|
|
42
|
+
onChangeView: ( view: View ) => void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface FieldsVisibilityMenuProps< Item extends AnyItem > {
|
|
46
|
+
view: View;
|
|
47
|
+
onChangeView: ( view: View ) => void;
|
|
48
|
+
fields: NormalizedField< Item >[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface SortMenuProps< Item extends AnyItem > {
|
|
52
|
+
fields: NormalizedField< Item >[];
|
|
53
|
+
view: View;
|
|
54
|
+
onChangeView: ( view: View ) => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface ViewActionsProps< Item extends AnyItem > {
|
|
58
|
+
fields: NormalizedField< Item >[];
|
|
59
|
+
view: View;
|
|
60
|
+
onChangeView: ( view: View ) => void;
|
|
61
|
+
supportedLayouts?: string[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function ViewTypeMenu( {
|
|
65
|
+
view,
|
|
66
|
+
onChangeView,
|
|
67
|
+
supportedLayouts,
|
|
68
|
+
}: ViewTypeMenuProps ) {
|
|
29
69
|
let _availableViews = VIEW_LAYOUTS;
|
|
30
70
|
if ( supportedLayouts ) {
|
|
31
71
|
_availableViews = _availableViews.filter( ( _view ) =>
|
|
@@ -41,7 +81,7 @@ function ViewTypeMenu( { view, onChangeView, supportedLayouts } ) {
|
|
|
41
81
|
trigger={
|
|
42
82
|
<DropdownMenuItem
|
|
43
83
|
suffix={
|
|
44
|
-
<span aria-hidden="true">{ activeView
|
|
84
|
+
<span aria-hidden="true">{ activeView?.label }</span>
|
|
45
85
|
}
|
|
46
86
|
>
|
|
47
87
|
<DropdownMenuItemLabel>
|
|
@@ -58,11 +98,18 @@ function ViewTypeMenu( { view, onChangeView, supportedLayouts } ) {
|
|
|
58
98
|
name="view-actions-available-view"
|
|
59
99
|
checked={ availableView.type === view.type }
|
|
60
100
|
hideOnClick
|
|
61
|
-
onChange={ ( e ) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
101
|
+
onChange={ ( e: ChangeEvent< HTMLInputElement > ) => {
|
|
102
|
+
switch ( e.target.value ) {
|
|
103
|
+
case 'list':
|
|
104
|
+
case 'grid':
|
|
105
|
+
case 'table':
|
|
106
|
+
return onChangeView( {
|
|
107
|
+
...view,
|
|
108
|
+
type: e.target.value,
|
|
109
|
+
layout: {},
|
|
110
|
+
} );
|
|
111
|
+
}
|
|
112
|
+
throw new Error( 'Invalid dataview' );
|
|
66
113
|
} }
|
|
67
114
|
>
|
|
68
115
|
<DropdownMenuItemLabel>
|
|
@@ -76,7 +123,7 @@ function ViewTypeMenu( { view, onChangeView, supportedLayouts } ) {
|
|
|
76
123
|
}
|
|
77
124
|
|
|
78
125
|
const PAGE_SIZE_VALUES = [ 10, 20, 50, 100 ];
|
|
79
|
-
function PageSizeMenu( { view, onChangeView } ) {
|
|
126
|
+
function PageSizeMenu( { view, onChangeView }: PageSizeMenuProps ) {
|
|
80
127
|
return (
|
|
81
128
|
<DropdownMenu
|
|
82
129
|
trigger={
|
|
@@ -114,7 +161,11 @@ function PageSizeMenu( { view, onChangeView } ) {
|
|
|
114
161
|
);
|
|
115
162
|
}
|
|
116
163
|
|
|
117
|
-
function FieldsVisibilityMenu
|
|
164
|
+
function FieldsVisibilityMenu< Item extends AnyItem >( {
|
|
165
|
+
view,
|
|
166
|
+
onChangeView,
|
|
167
|
+
fields,
|
|
168
|
+
}: FieldsVisibilityMenuProps< Item > ) {
|
|
118
169
|
const hidableFields = fields.filter(
|
|
119
170
|
( field ) =>
|
|
120
171
|
field.enableHiding !== false && field.id !== view.layout.mediaField
|
|
@@ -164,7 +215,11 @@ function FieldsVisibilityMenu( { view, onChangeView, fields } ) {
|
|
|
164
215
|
);
|
|
165
216
|
}
|
|
166
217
|
|
|
167
|
-
function SortMenu
|
|
218
|
+
function SortMenu< Item extends AnyItem >( {
|
|
219
|
+
fields,
|
|
220
|
+
view,
|
|
221
|
+
onChangeView,
|
|
222
|
+
}: SortMenuProps< Item > ) {
|
|
168
223
|
const sortableFields = fields.filter(
|
|
169
224
|
( field ) => field.enableSorting !== false
|
|
170
225
|
);
|
|
@@ -206,43 +261,41 @@ function SortMenu( { fields, view, onChangeView } ) {
|
|
|
206
261
|
minWidth: '220px',
|
|
207
262
|
} }
|
|
208
263
|
>
|
|
209
|
-
{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
field.id === currentSortedField.id;
|
|
264
|
+
{ SORTING_DIRECTIONS.map( ( direction ) => {
|
|
265
|
+
const isChecked =
|
|
266
|
+
currentSortedField !== undefined &&
|
|
267
|
+
sortedDirection === direction &&
|
|
268
|
+
field.id === currentSortedField.id;
|
|
215
269
|
|
|
216
|
-
|
|
270
|
+
const value = `${ field.id }-${ direction }`;
|
|
217
271
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
) }
|
|
272
|
+
return (
|
|
273
|
+
<DropdownMenuRadioItem
|
|
274
|
+
key={ value }
|
|
275
|
+
// All sorting radio items share the same name, so that
|
|
276
|
+
// selecting a sorting option automatically deselects the
|
|
277
|
+
// previously selected one, even if it is displayed in
|
|
278
|
+
// another submenu. The field and direction are passed via
|
|
279
|
+
// the `value` prop.
|
|
280
|
+
name="view-actions-sorting"
|
|
281
|
+
value={ value }
|
|
282
|
+
checked={ isChecked }
|
|
283
|
+
onChange={ () => {
|
|
284
|
+
onChangeView( {
|
|
285
|
+
...view,
|
|
286
|
+
sort: {
|
|
287
|
+
field: field.id,
|
|
288
|
+
direction,
|
|
289
|
+
},
|
|
290
|
+
} );
|
|
291
|
+
} }
|
|
292
|
+
>
|
|
293
|
+
<DropdownMenuItemLabel>
|
|
294
|
+
{ sortLabels[ direction ] }
|
|
295
|
+
</DropdownMenuItemLabel>
|
|
296
|
+
</DropdownMenuRadioItem>
|
|
297
|
+
);
|
|
298
|
+
} ) }
|
|
246
299
|
</DropdownMenu>
|
|
247
300
|
);
|
|
248
301
|
} ) }
|
|
@@ -250,12 +303,12 @@ function SortMenu( { fields, view, onChangeView } ) {
|
|
|
250
303
|
);
|
|
251
304
|
}
|
|
252
305
|
|
|
253
|
-
|
|
306
|
+
function _ViewActions< Item extends AnyItem >( {
|
|
254
307
|
fields,
|
|
255
308
|
view,
|
|
256
309
|
onChangeView,
|
|
257
310
|
supportedLayouts,
|
|
258
|
-
} ) {
|
|
311
|
+
}: ViewActionsProps< Item > ) {
|
|
259
312
|
return (
|
|
260
313
|
<DropdownMenu
|
|
261
314
|
trigger={
|
|
@@ -286,6 +339,9 @@ const ViewActions = memo( function ViewActions( {
|
|
|
286
339
|
</DropdownMenuGroup>
|
|
287
340
|
</DropdownMenu>
|
|
288
341
|
);
|
|
289
|
-
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// A type assertion is used here to keep the type argument.
|
|
345
|
+
const ViewActions = memo( _ViewActions ) as typeof _ViewActions;
|
|
290
346
|
|
|
291
347
|
export default ViewActions;
|
package/src/view-grid.tsx
CHANGED
|
@@ -22,12 +22,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
22
22
|
import ItemActions from './item-actions';
|
|
23
23
|
import SingleSelectionCheckbox from './single-selection-checkbox';
|
|
24
24
|
import { useHasAPossibleBulkAction } from './bulk-actions';
|
|
25
|
-
import type {
|
|
26
|
-
Action,
|
|
27
|
-
AnyItem,
|
|
28
|
-
NormalizedField,
|
|
29
|
-
ViewGrid as ViewGridType,
|
|
30
|
-
} from './types';
|
|
25
|
+
import type { Action, AnyItem, NormalizedField, ViewGridProps } from './types';
|
|
31
26
|
|
|
32
27
|
interface GridItemProps< Item extends AnyItem > {
|
|
33
28
|
selection: string[];
|
|
@@ -40,18 +35,7 @@ interface GridItemProps< Item extends AnyItem > {
|
|
|
40
35
|
primaryField?: NormalizedField< Item >;
|
|
41
36
|
visibleFields: NormalizedField< Item >[];
|
|
42
37
|
badgeFields: NormalizedField< Item >[];
|
|
43
|
-
columnFields
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
interface ViewGridProps< Item extends AnyItem > {
|
|
47
|
-
actions: Action< Item >[];
|
|
48
|
-
data: Item[];
|
|
49
|
-
fields: NormalizedField< Item >[];
|
|
50
|
-
getItemId: ( item: Item ) => string;
|
|
51
|
-
isLoading: boolean;
|
|
52
|
-
onSelectionChange: ( items: Item[] ) => void;
|
|
53
|
-
selection: string[];
|
|
54
|
-
view: ViewGridType;
|
|
38
|
+
columnFields?: string[];
|
|
55
39
|
}
|
|
56
40
|
|
|
57
41
|
function GridItem< Item extends AnyItem >( {
|
|
@@ -147,7 +131,7 @@ function GridItem< Item extends AnyItem >( {
|
|
|
147
131
|
return (
|
|
148
132
|
<FlexItem
|
|
149
133
|
key={ field.id }
|
|
150
|
-
className=
|
|
134
|
+
className="dataviews-view-grid__field-value"
|
|
151
135
|
>
|
|
152
136
|
{ renderedValue }
|
|
153
137
|
</FlexItem>
|
|
@@ -244,7 +228,7 @@ export default function ViewGrid< Item extends AnyItem >( {
|
|
|
244
228
|
<>
|
|
245
229
|
{ hasData && (
|
|
246
230
|
<Grid
|
|
247
|
-
gap={
|
|
231
|
+
gap={ 8 }
|
|
248
232
|
columns={ 2 }
|
|
249
233
|
alignment="top"
|
|
250
234
|
className="dataviews-view-grid"
|
package/src/view-list.tsx
CHANGED
|
@@ -32,27 +32,10 @@ import { moreVertical } from '@wordpress/icons';
|
|
|
32
32
|
* Internal dependencies
|
|
33
33
|
*/
|
|
34
34
|
import { unlock } from './lock-unlock';
|
|
35
|
-
import type {
|
|
36
|
-
Action,
|
|
37
|
-
AnyItem,
|
|
38
|
-
NormalizedField,
|
|
39
|
-
ViewList as ViewListType,
|
|
40
|
-
} from './types';
|
|
35
|
+
import type { Action, AnyItem, NormalizedField, ViewListProps } from './types';
|
|
41
36
|
|
|
42
37
|
import { ActionsDropdownMenuGroup, ActionModal } from './item-actions';
|
|
43
38
|
|
|
44
|
-
interface ListViewProps< Item extends AnyItem > {
|
|
45
|
-
actions: Action< Item >[];
|
|
46
|
-
data: Item[];
|
|
47
|
-
fields: NormalizedField< Item >[];
|
|
48
|
-
getItemId: ( item: Item ) => string;
|
|
49
|
-
id: string;
|
|
50
|
-
isLoading: boolean;
|
|
51
|
-
onSelectionChange: ( selection: Item[] ) => void;
|
|
52
|
-
selection: string[];
|
|
53
|
-
view: ViewListType;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
39
|
interface ListViewItemProps< Item extends AnyItem > {
|
|
57
40
|
actions: Action< Item >[];
|
|
58
41
|
id?: string;
|
|
@@ -122,6 +105,11 @@ function ListItem< Item extends AnyItem >( {
|
|
|
122
105
|
}, [ actions, item ] );
|
|
123
106
|
|
|
124
107
|
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
|
108
|
+
const primaryActionLabel =
|
|
109
|
+
primaryAction &&
|
|
110
|
+
( typeof primaryAction.label === 'string'
|
|
111
|
+
? primaryAction.label
|
|
112
|
+
: primaryAction.label( [ item ] ) );
|
|
125
113
|
|
|
126
114
|
return (
|
|
127
115
|
<CompositeRow
|
|
@@ -137,7 +125,8 @@ function ListItem< Item extends AnyItem >( {
|
|
|
137
125
|
>
|
|
138
126
|
<HStack
|
|
139
127
|
className="dataviews-view-list__item-wrapper"
|
|
140
|
-
alignment="
|
|
128
|
+
alignment="center"
|
|
129
|
+
spacing={ 0 }
|
|
141
130
|
>
|
|
142
131
|
<div role="gridcell">
|
|
143
132
|
<CompositeItem
|
|
@@ -161,7 +150,7 @@ function ListItem< Item extends AnyItem >( {
|
|
|
161
150
|
<div className="dataviews-view-list__media-placeholder"></div>
|
|
162
151
|
) }
|
|
163
152
|
</div>
|
|
164
|
-
<VStack spacing={
|
|
153
|
+
<VStack spacing={ 0 }>
|
|
165
154
|
<span
|
|
166
155
|
className="dataviews-view-list__primary-field"
|
|
167
156
|
id={ labelId }
|
|
@@ -209,7 +198,7 @@ function ListItem< Item extends AnyItem >( {
|
|
|
209
198
|
store={ store }
|
|
210
199
|
render={
|
|
211
200
|
<Button
|
|
212
|
-
label={
|
|
201
|
+
label={ primaryActionLabel }
|
|
213
202
|
icon={ primaryAction.icon }
|
|
214
203
|
isDestructive={
|
|
215
204
|
primaryAction.isDestructive
|
|
@@ -240,7 +229,7 @@ function ListItem< Item extends AnyItem >( {
|
|
|
240
229
|
store={ store }
|
|
241
230
|
render={
|
|
242
231
|
<Button
|
|
243
|
-
label={
|
|
232
|
+
label={ primaryActionLabel }
|
|
244
233
|
icon={ primaryAction.icon }
|
|
245
234
|
isDestructive={
|
|
246
235
|
primaryAction.isDestructive
|
|
@@ -311,7 +300,7 @@ function ListItem< Item extends AnyItem >( {
|
|
|
311
300
|
}
|
|
312
301
|
|
|
313
302
|
export default function ViewList< Item extends AnyItem >(
|
|
314
|
-
props:
|
|
303
|
+
props: ViewListProps< Item >
|
|
315
304
|
) {
|
|
316
305
|
const {
|
|
317
306
|
actions,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
+
import type { ReactNode, Ref, PropsWithoutRef, RefAttributes } from 'react';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* WordPress dependencies
|
|
@@ -33,11 +34,24 @@ import SingleSelectionCheckbox from './single-selection-checkbox';
|
|
|
33
34
|
import { unlock } from './lock-unlock';
|
|
34
35
|
import ItemActions from './item-actions';
|
|
35
36
|
import { sanitizeOperators } from './utils';
|
|
36
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
SORTING_DIRECTIONS,
|
|
39
|
+
sortArrows,
|
|
40
|
+
sortLabels,
|
|
41
|
+
sortValues,
|
|
42
|
+
} from './constants';
|
|
37
43
|
import {
|
|
38
44
|
useSomeItemHasAPossibleBulkAction,
|
|
39
45
|
useHasAPossibleBulkAction,
|
|
40
46
|
} from './bulk-actions';
|
|
47
|
+
import type {
|
|
48
|
+
Action,
|
|
49
|
+
AnyItem,
|
|
50
|
+
NormalizedField,
|
|
51
|
+
SortDirection,
|
|
52
|
+
ViewTable as ViewTableType,
|
|
53
|
+
ViewTableProps,
|
|
54
|
+
} from './types';
|
|
41
55
|
|
|
42
56
|
const {
|
|
43
57
|
DropdownMenuV2: DropdownMenu,
|
|
@@ -48,7 +62,35 @@ const {
|
|
|
48
62
|
DropdownMenuSeparatorV2: DropdownMenuSeparator,
|
|
49
63
|
} = unlock( componentsPrivateApis );
|
|
50
64
|
|
|
51
|
-
|
|
65
|
+
interface HeaderMenuProps< Item extends AnyItem > {
|
|
66
|
+
field: NormalizedField< Item >;
|
|
67
|
+
view: ViewTableType;
|
|
68
|
+
onChangeView: ( view: ViewTableType ) => void;
|
|
69
|
+
onHide: ( field: NormalizedField< Item > ) => void;
|
|
70
|
+
setOpenedFilter: ( fieldId: string ) => void;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface BulkSelectionCheckboxProps< Item extends AnyItem > {
|
|
74
|
+
selection: string[];
|
|
75
|
+
onSelectionChange: ( items: Item[] ) => void;
|
|
76
|
+
data: Item[];
|
|
77
|
+
actions: Action< Item >[];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface TableRowProps< Item extends AnyItem > {
|
|
81
|
+
hasBulkActions: boolean;
|
|
82
|
+
item: Item;
|
|
83
|
+
actions: Action< Item >[];
|
|
84
|
+
id: string;
|
|
85
|
+
visibleFields: NormalizedField< Item >[];
|
|
86
|
+
primaryField?: NormalizedField< Item >;
|
|
87
|
+
selection: string[];
|
|
88
|
+
getItemId: ( item: Item ) => string;
|
|
89
|
+
onSelectionChange: ( items: Item[] ) => void;
|
|
90
|
+
data: Item[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function WithDropDownMenuSeparators( { children }: { children: ReactNode } ) {
|
|
52
94
|
return Children.toArray( children )
|
|
53
95
|
.filter( Boolean )
|
|
54
96
|
.map( ( child, i ) => (
|
|
@@ -59,11 +101,15 @@ function WithDropDownMenuSeparators( { children } ) {
|
|
|
59
101
|
) );
|
|
60
102
|
}
|
|
61
103
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
104
|
+
const _HeaderMenu = forwardRef( function HeaderMenu< Item extends AnyItem >(
|
|
105
|
+
{
|
|
106
|
+
field,
|
|
107
|
+
view,
|
|
108
|
+
onChangeView,
|
|
109
|
+
onHide,
|
|
110
|
+
setOpenedFilter,
|
|
111
|
+
}: HeaderMenuProps< Item >,
|
|
112
|
+
ref: Ref< HTMLButtonElement >
|
|
67
113
|
) {
|
|
68
114
|
const isHidable = field.enableHiding !== false;
|
|
69
115
|
const isSortable = field.enableSorting !== false;
|
|
@@ -92,9 +138,9 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
92
138
|
variant="tertiary"
|
|
93
139
|
>
|
|
94
140
|
{ field.header }
|
|
95
|
-
{ isSorted && (
|
|
141
|
+
{ view.sort && isSorted && (
|
|
96
142
|
<span aria-hidden="true">
|
|
97
|
-
{
|
|
143
|
+
{ sortArrows[ view.sort.direction ] }
|
|
98
144
|
</span>
|
|
99
145
|
) }
|
|
100
146
|
</Button>
|
|
@@ -104,9 +150,10 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
104
150
|
<WithDropDownMenuSeparators>
|
|
105
151
|
{ isSortable && (
|
|
106
152
|
<DropdownMenuGroup>
|
|
107
|
-
{
|
|
108
|
-
(
|
|
153
|
+
{ SORTING_DIRECTIONS.map(
|
|
154
|
+
( direction: SortDirection ) => {
|
|
109
155
|
const isChecked =
|
|
156
|
+
view.sort &&
|
|
110
157
|
isSorted &&
|
|
111
158
|
view.sort.direction === direction;
|
|
112
159
|
|
|
@@ -134,7 +181,7 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
134
181
|
} }
|
|
135
182
|
>
|
|
136
183
|
<DropdownMenuItemLabel>
|
|
137
|
-
{
|
|
184
|
+
{ sortLabels[ direction ] }
|
|
138
185
|
</DropdownMenuItemLabel>
|
|
139
186
|
</DropdownMenuRadioItem>
|
|
140
187
|
);
|
|
@@ -191,16 +238,24 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
191
238
|
);
|
|
192
239
|
} );
|
|
193
240
|
|
|
194
|
-
|
|
241
|
+
// @ts-expect-error Lift the `Item` type argument through the forwardRef.
|
|
242
|
+
const HeaderMenu: < Item extends AnyItem >(
|
|
243
|
+
props: PropsWithoutRef< HeaderMenuProps< Item > > &
|
|
244
|
+
RefAttributes< HTMLButtonElement >
|
|
245
|
+
) => ReturnType< typeof _HeaderMenu > = _HeaderMenu;
|
|
246
|
+
|
|
247
|
+
function BulkSelectionCheckbox< Item extends AnyItem >( {
|
|
195
248
|
selection,
|
|
196
249
|
onSelectionChange,
|
|
197
250
|
data,
|
|
198
251
|
actions,
|
|
199
|
-
} ) {
|
|
252
|
+
}: BulkSelectionCheckboxProps< Item > ) {
|
|
200
253
|
const selectableItems = useMemo( () => {
|
|
201
254
|
return data.filter( ( item ) => {
|
|
202
255
|
return actions.some(
|
|
203
|
-
( action ) =>
|
|
256
|
+
( action ) =>
|
|
257
|
+
action.supportsBulk &&
|
|
258
|
+
( ! action.isEligible || action.isEligible( item ) )
|
|
204
259
|
);
|
|
205
260
|
} );
|
|
206
261
|
}, [ data, actions ] );
|
|
@@ -210,7 +265,7 @@ function BulkSelectionCheckbox( {
|
|
|
210
265
|
className="dataviews-view-table-selection-checkbox"
|
|
211
266
|
__nextHasNoMarginBottom
|
|
212
267
|
checked={ areAllSelected }
|
|
213
|
-
indeterminate={ ! areAllSelected && selection.length }
|
|
268
|
+
indeterminate={ ! areAllSelected && !! selection.length }
|
|
214
269
|
onChange={ () => {
|
|
215
270
|
if ( areAllSelected ) {
|
|
216
271
|
onSelectionChange( [] );
|
|
@@ -225,7 +280,7 @@ function BulkSelectionCheckbox( {
|
|
|
225
280
|
);
|
|
226
281
|
}
|
|
227
282
|
|
|
228
|
-
function TableRow( {
|
|
283
|
+
function TableRow< Item extends AnyItem >( {
|
|
229
284
|
hasBulkActions,
|
|
230
285
|
item,
|
|
231
286
|
actions,
|
|
@@ -236,7 +291,7 @@ function TableRow( {
|
|
|
236
291
|
getItemId,
|
|
237
292
|
onSelectionChange,
|
|
238
293
|
data,
|
|
239
|
-
} ) {
|
|
294
|
+
}: TableRowProps< Item > ) {
|
|
240
295
|
const hasPossibleBulkAction = useHasAPossibleBulkAction( actions, item );
|
|
241
296
|
const isSelected = selection.includes( id );
|
|
242
297
|
|
|
@@ -270,7 +325,7 @@ function TableRow( {
|
|
|
270
325
|
onClick={ () => {
|
|
271
326
|
if (
|
|
272
327
|
! isTouchDevice.current &&
|
|
273
|
-
document.getSelection()
|
|
328
|
+
document.getSelection()?.type !== 'Range'
|
|
274
329
|
) {
|
|
275
330
|
if ( ! isSelected ) {
|
|
276
331
|
onSelectionChange(
|
|
@@ -305,7 +360,6 @@ function TableRow( {
|
|
|
305
360
|
>
|
|
306
361
|
<div className="dataviews-view-table__cell-content-wrapper">
|
|
307
362
|
<SingleSelectionCheckbox
|
|
308
|
-
id={ id }
|
|
309
363
|
item={ item }
|
|
310
364
|
selection={ selection }
|
|
311
365
|
onSelectionChange={ onSelectionChange }
|
|
@@ -361,7 +415,7 @@ function TableRow( {
|
|
|
361
415
|
);
|
|
362
416
|
}
|
|
363
417
|
|
|
364
|
-
function ViewTable( {
|
|
418
|
+
function ViewTable< Item extends AnyItem >( {
|
|
365
419
|
actions,
|
|
366
420
|
data,
|
|
367
421
|
fields,
|
|
@@ -372,10 +426,13 @@ function ViewTable( {
|
|
|
372
426
|
selection,
|
|
373
427
|
setOpenedFilter,
|
|
374
428
|
view,
|
|
375
|
-
} ) {
|
|
376
|
-
const headerMenuRefs = useRef
|
|
377
|
-
|
|
378
|
-
|
|
429
|
+
}: ViewTableProps< Item > ) {
|
|
430
|
+
const headerMenuRefs = useRef<
|
|
431
|
+
Map< string, { node: HTMLButtonElement; fallback: string } >
|
|
432
|
+
>( new Map() );
|
|
433
|
+
const headerMenuToFocusRef = useRef< HTMLButtonElement >();
|
|
434
|
+
const [ nextHeaderMenuToFocus, setNextHeaderMenuToFocus ] =
|
|
435
|
+
useState< HTMLButtonElement >();
|
|
379
436
|
const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
|
|
380
437
|
|
|
381
438
|
useEffect( () => {
|
|
@@ -393,13 +450,15 @@ function ViewTable( {
|
|
|
393
450
|
// Clearing out the focus directive is necessary to make sure
|
|
394
451
|
// future renders don't cause unexpected focus jumps.
|
|
395
452
|
headerMenuToFocusRef.current = nextHeaderMenuToFocus;
|
|
396
|
-
setNextHeaderMenuToFocus();
|
|
453
|
+
setNextHeaderMenuToFocus( undefined );
|
|
397
454
|
return;
|
|
398
455
|
}
|
|
399
456
|
|
|
400
|
-
const onHide = ( field ) => {
|
|
457
|
+
const onHide = ( field: NormalizedField< Item > ) => {
|
|
401
458
|
const hidden = headerMenuRefs.current.get( field.id );
|
|
402
|
-
const fallback =
|
|
459
|
+
const fallback = hidden
|
|
460
|
+
? headerMenuRefs.current.get( hidden.fallback )
|
|
461
|
+
: undefined;
|
|
403
462
|
setNextHeaderMenuToFocus( fallback?.node );
|
|
404
463
|
};
|
|
405
464
|
const visibleFields = fields.filter(
|
|
@@ -408,7 +467,6 @@ function ViewTable( {
|
|
|
408
467
|
! [ view.layout.mediaField ].includes( field.id )
|
|
409
468
|
);
|
|
410
469
|
const hasData = !! data?.length;
|
|
411
|
-
const sortValues = { asc: 'ascending', desc: 'descending' };
|
|
412
470
|
|
|
413
471
|
const primaryField = fields.find(
|
|
414
472
|
( field ) => field.id === view.layout.primaryField
|
|
@@ -450,8 +508,9 @@ function ViewTable( {
|
|
|
450
508
|
} }
|
|
451
509
|
data-field-id={ field.id }
|
|
452
510
|
aria-sort={
|
|
453
|
-
view.sort?.field === field.id
|
|
454
|
-
|
|
511
|
+
view.sort?.field === field.id
|
|
512
|
+
? sortValues[ view.sort.direction ]
|
|
513
|
+
: undefined
|
|
455
514
|
}
|
|
456
515
|
scope="col"
|
|
457
516
|
>
|
|
@@ -504,7 +563,7 @@ function ViewTable( {
|
|
|
504
563
|
item={ item }
|
|
505
564
|
hasBulkActions={ hasBulkActions }
|
|
506
565
|
actions={ actions }
|
|
507
|
-
id={ getItemId( item ) || index }
|
|
566
|
+
id={ getItemId( item ) || index.toString() }
|
|
508
567
|
visibleFields={ visibleFields }
|
|
509
568
|
primaryField={ primaryField }
|
|
510
569
|
selection={ selection }
|
package/tsconfig.json
CHANGED
|
@@ -4,17 +4,14 @@
|
|
|
4
4
|
"compilerOptions": {
|
|
5
5
|
"rootDir": "src",
|
|
6
6
|
"declarationDir": "build-types",
|
|
7
|
-
"skipLibCheck": true,
|
|
8
7
|
"checkJs": false
|
|
9
8
|
},
|
|
10
9
|
"references": [
|
|
11
|
-
{ "path": "../a11y" },
|
|
12
10
|
{ "path": "../components" },
|
|
13
11
|
{ "path": "../compose" },
|
|
14
12
|
{ "path": "../element" },
|
|
15
13
|
{ "path": "../i18n" },
|
|
16
14
|
{ "path": "../icons" },
|
|
17
|
-
{ "path": "../keycodes" },
|
|
18
15
|
{ "path": "../primitives" },
|
|
19
16
|
{ "path": "../private-apis" }
|
|
20
17
|
],
|