@wordpress/dataviews 0.4.0 → 0.5.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 +2 -0
- package/README.md +1 -0
- package/build/add-filter.js +25 -108
- package/build/add-filter.js.map +1 -1
- package/build/constants.js +9 -18
- package/build/constants.js.map +1 -1
- package/build/dataviews.js +22 -16
- package/build/dataviews.js.map +1 -1
- package/build/dropdown-menu-helper.js +1 -2
- package/build/dropdown-menu-helper.js.map +1 -1
- package/build/filter-summary.js +180 -77
- package/build/filter-summary.js.map +1 -1
- package/build/filters.js +32 -18
- package/build/filters.js.map +1 -1
- package/build/pagination.js +1 -2
- package/build/pagination.js.map +1 -1
- package/build/reset-filters.js +4 -1
- package/build/reset-filters.js.map +1 -1
- package/build/search-widget.js +111 -0
- package/build/search-widget.js.map +1 -0
- package/build/search.js +2 -3
- package/build/search.js.map +1 -1
- package/build/single-selection-checkbox.js +54 -0
- package/build/single-selection-checkbox.js.map +1 -0
- package/build/utils.js +14 -1
- package/build/utils.js.map +1 -1
- package/build/view-actions.js +2 -3
- package/build/view-actions.js.map +1 -1
- package/build/view-grid.js +92 -22
- package/build/view-grid.js.map +1 -1
- package/build/view-list.js +2 -1
- package/build/view-list.js.map +1 -1
- package/build/view-table.js +45 -134
- package/build/view-table.js.map +1 -1
- package/build-module/add-filter.js +28 -111
- package/build-module/add-filter.js.map +1 -1
- package/build-module/dataviews.js +23 -17
- package/build-module/dataviews.js.map +1 -1
- package/build-module/filter-summary.js +181 -79
- package/build-module/filter-summary.js.map +1 -1
- package/build-module/filters.js +32 -17
- package/build-module/filters.js.map +1 -1
- package/build-module/reset-filters.js +4 -1
- package/build-module/reset-filters.js.map +1 -1
- package/build-module/search-widget.js +101 -0
- package/build-module/search-widget.js.map +1 -0
- package/build-module/search.js +1 -1
- package/build-module/search.js.map +1 -1
- package/build-module/single-selection-checkbox.js +47 -0
- package/build-module/single-selection-checkbox.js.map +1 -0
- package/build-module/utils.js +12 -0
- package/build-module/utils.js.map +1 -1
- package/build-module/view-actions.js +1 -1
- package/build-module/view-actions.js.map +1 -1
- package/build-module/view-grid.js +92 -22
- package/build-module/view-grid.js.map +1 -1
- package/build-module/view-list.js +2 -1
- package/build-module/view-list.js.map +1 -1
- package/build-module/view-table.js +45 -133
- package/build-module/view-table.js.map +1 -1
- package/build-style/style-rtl.css +257 -44
- package/build-style/style.css +257 -44
- package/package.json +12 -11
- package/src/add-filter.js +39 -230
- package/src/dataviews.js +31 -20
- package/src/filter-summary.js +228 -135
- package/src/filters.js +42 -29
- package/src/reset-filters.js +12 -2
- package/src/search-widget.js +128 -0
- package/src/search.js +1 -1
- package/src/single-selection-checkbox.js +59 -0
- package/src/style.scss +264 -44
- package/src/utils.js +15 -0
- package/src/view-actions.js +1 -2
- package/src/view-grid.js +127 -53
- package/src/view-list.js +5 -1
- package/src/view-table.js +61 -234
package/src/view-table.js
CHANGED
|
@@ -6,7 +6,7 @@ import classnames from 'classnames';
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
|
-
import { __
|
|
9
|
+
import { __ } from '@wordpress/i18n';
|
|
10
10
|
import { useAsyncList } from '@wordpress/compose';
|
|
11
11
|
import { unseen, funnel } from '@wordpress/icons';
|
|
12
12
|
import {
|
|
@@ -16,75 +16,66 @@ import {
|
|
|
16
16
|
CheckboxControl,
|
|
17
17
|
} from '@wordpress/components';
|
|
18
18
|
import {
|
|
19
|
-
Children,
|
|
20
|
-
Fragment,
|
|
21
19
|
forwardRef,
|
|
22
20
|
useEffect,
|
|
23
21
|
useId,
|
|
24
22
|
useRef,
|
|
25
23
|
useState,
|
|
24
|
+
Children,
|
|
25
|
+
Fragment,
|
|
26
26
|
} from '@wordpress/element';
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Internal dependencies
|
|
30
30
|
*/
|
|
31
|
+
import SingleSelectionCheckbox from './single-selection-checkbox';
|
|
31
32
|
import { unlock } from './lock-unlock';
|
|
32
33
|
import ItemActions from './item-actions';
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
34
|
+
import { sanitizeOperators } from './utils';
|
|
35
|
+
import { ENUMERATION_TYPE, SORTING_DIRECTIONS } from './constants';
|
|
35
36
|
|
|
36
37
|
const {
|
|
37
38
|
DropdownMenuV2: DropdownMenu,
|
|
38
39
|
DropdownMenuGroupV2: DropdownMenuGroup,
|
|
39
40
|
DropdownMenuItemV2: DropdownMenuItem,
|
|
40
41
|
DropdownMenuRadioItemV2: DropdownMenuRadioItem,
|
|
41
|
-
DropdownMenuSeparatorV2: DropdownMenuSeparator,
|
|
42
42
|
DropdownMenuItemLabelV2: DropdownMenuItemLabel,
|
|
43
|
-
|
|
43
|
+
DropdownMenuSeparatorV2: DropdownMenuSeparator,
|
|
44
44
|
} = unlock( componentsPrivateApis );
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
function WithSeparators( { children } ) {
|
|
47
|
+
return Children.toArray( children )
|
|
48
|
+
.filter( Boolean )
|
|
49
|
+
.map( ( child, i ) => (
|
|
50
|
+
<Fragment key={ i }>
|
|
51
|
+
{ i > 0 && <DropdownMenuSeparator /> }
|
|
52
|
+
{ child }
|
|
53
|
+
</Fragment>
|
|
54
|
+
) );
|
|
55
|
+
}
|
|
47
56
|
|
|
48
|
-
const
|
|
49
|
-
let operators = field.filterBy?.operators;
|
|
50
|
-
if ( ! operators || ! Array.isArray( operators ) ) {
|
|
51
|
-
operators = Object.keys( OPERATORS );
|
|
52
|
-
}
|
|
53
|
-
return operators.filter( ( operator ) =>
|
|
54
|
-
Object.keys( OPERATORS ).includes( operator )
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
+
const sortArrows = { asc: '↑', desc: '↓' };
|
|
57
58
|
|
|
58
59
|
const HeaderMenu = forwardRef( function HeaderMenu(
|
|
59
|
-
{ field, view, onChangeView, onHide },
|
|
60
|
+
{ field, view, onChangeView, onHide, setOpenedFilter },
|
|
60
61
|
ref
|
|
61
62
|
) {
|
|
62
63
|
const isHidable = field.enableHiding !== false;
|
|
63
|
-
|
|
64
64
|
const isSortable = field.enableSorting !== false;
|
|
65
65
|
const isSorted = view.sort?.field === field.id;
|
|
66
|
-
|
|
67
|
-
let filter, filterInView, activeElement, activeOperator, otherFilters;
|
|
68
66
|
const operators = sanitizeOperators( field );
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
activeOperator = filterInView?.operator || filter.operators[ 0 ];
|
|
81
|
-
}
|
|
82
|
-
const isFilterable = !! filter;
|
|
83
|
-
|
|
84
|
-
if ( ! isSortable && ! isHidable && ! isFilterable ) {
|
|
67
|
+
// Filter can be added:
|
|
68
|
+
// 1. If the field is not already part of a view's filters.
|
|
69
|
+
// 2. If the field meets the type and operator requirements.
|
|
70
|
+
// 3. If it's not primary. If it is, it should be already visible.
|
|
71
|
+
const canAddFilter =
|
|
72
|
+
! view.filters?.some( ( _filter ) => field.id === _filter.field ) &&
|
|
73
|
+
field.type === ENUMERATION_TYPE &&
|
|
74
|
+
!! operators.length &&
|
|
75
|
+
! field.filterBy?.isPrimary;
|
|
76
|
+
if ( ! isSortable && ! isHidable && ! canAddFilter ) {
|
|
85
77
|
return field.header;
|
|
86
78
|
}
|
|
87
|
-
|
|
88
79
|
return (
|
|
89
80
|
<DropdownMenu
|
|
90
81
|
align="start"
|
|
@@ -146,6 +137,32 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
146
137
|
) }
|
|
147
138
|
</DropdownMenuGroup>
|
|
148
139
|
) }
|
|
140
|
+
{ canAddFilter && (
|
|
141
|
+
<DropdownMenuGroup>
|
|
142
|
+
<DropdownMenuItem
|
|
143
|
+
prefix={ <Icon icon={ funnel } /> }
|
|
144
|
+
onClick={ () => {
|
|
145
|
+
setOpenedFilter( field.id );
|
|
146
|
+
onChangeView( {
|
|
147
|
+
...view,
|
|
148
|
+
page: 1,
|
|
149
|
+
filters: [
|
|
150
|
+
...( view.filters || [] ),
|
|
151
|
+
{
|
|
152
|
+
field: field.id,
|
|
153
|
+
value: undefined,
|
|
154
|
+
operator: operators[ 0 ],
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
} );
|
|
158
|
+
} }
|
|
159
|
+
>
|
|
160
|
+
<DropdownMenuItemLabel>
|
|
161
|
+
{ __( 'Add filter' ) }
|
|
162
|
+
</DropdownMenuItemLabel>
|
|
163
|
+
</DropdownMenuItem>
|
|
164
|
+
</DropdownMenuGroup>
|
|
165
|
+
) }
|
|
149
166
|
{ isHidable && (
|
|
150
167
|
<DropdownMenuItem
|
|
151
168
|
prefix={ <Icon icon={ unseen } /> }
|
|
@@ -164,149 +181,11 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
164
181
|
</DropdownMenuItemLabel>
|
|
165
182
|
</DropdownMenuItem>
|
|
166
183
|
) }
|
|
167
|
-
{ isFilterable && (
|
|
168
|
-
<DropdownMenuGroup>
|
|
169
|
-
<DropdownMenu
|
|
170
|
-
key={ filter.field }
|
|
171
|
-
trigger={
|
|
172
|
-
<DropdownMenuItem
|
|
173
|
-
prefix={ <Icon icon={ funnel } /> }
|
|
174
|
-
suffix={
|
|
175
|
-
activeElement && (
|
|
176
|
-
<span aria-hidden="true">
|
|
177
|
-
{ activeOperator in OPERATORS &&
|
|
178
|
-
`${ OPERATORS[ activeOperator ].label } ` }
|
|
179
|
-
{ activeElement?.label }
|
|
180
|
-
</span>
|
|
181
|
-
)
|
|
182
|
-
}
|
|
183
|
-
>
|
|
184
|
-
<DropdownMenuItemLabel>
|
|
185
|
-
{ __( 'Filter by' ) }
|
|
186
|
-
</DropdownMenuItemLabel>
|
|
187
|
-
</DropdownMenuItem>
|
|
188
|
-
}
|
|
189
|
-
>
|
|
190
|
-
<WithSeparators>
|
|
191
|
-
<DropdownMenuGroup>
|
|
192
|
-
{ filter.elements.map( ( element ) => {
|
|
193
|
-
const isActive =
|
|
194
|
-
activeElement?.value ===
|
|
195
|
-
element.value;
|
|
196
|
-
return (
|
|
197
|
-
<DropdownMenuRadioItemCustom
|
|
198
|
-
key={ element.value }
|
|
199
|
-
name={ `view-table-${ filter.field }` }
|
|
200
|
-
value={ element.value }
|
|
201
|
-
checked={ isActive }
|
|
202
|
-
onClick={ () => {
|
|
203
|
-
onChangeView( {
|
|
204
|
-
...view,
|
|
205
|
-
page: 1,
|
|
206
|
-
filters: [
|
|
207
|
-
...otherFilters,
|
|
208
|
-
{
|
|
209
|
-
field: filter.field,
|
|
210
|
-
operator:
|
|
211
|
-
activeOperator,
|
|
212
|
-
value: isActive
|
|
213
|
-
? undefined
|
|
214
|
-
: element.value,
|
|
215
|
-
},
|
|
216
|
-
],
|
|
217
|
-
} );
|
|
218
|
-
} }
|
|
219
|
-
>
|
|
220
|
-
<DropdownMenuItemLabel>
|
|
221
|
-
{ element.label }
|
|
222
|
-
</DropdownMenuItemLabel>
|
|
223
|
-
{ !! element.description && (
|
|
224
|
-
<DropdownMenuItemHelpText>
|
|
225
|
-
{ element.description }
|
|
226
|
-
</DropdownMenuItemHelpText>
|
|
227
|
-
) }
|
|
228
|
-
</DropdownMenuRadioItemCustom>
|
|
229
|
-
);
|
|
230
|
-
} ) }
|
|
231
|
-
</DropdownMenuGroup>
|
|
232
|
-
{ filter.operators.length > 1 && (
|
|
233
|
-
<DropdownMenu
|
|
234
|
-
trigger={
|
|
235
|
-
<DropdownMenuItem
|
|
236
|
-
suffix={
|
|
237
|
-
<span aria-hidden="true">
|
|
238
|
-
{
|
|
239
|
-
OPERATORS[
|
|
240
|
-
activeOperator
|
|
241
|
-
]?.label
|
|
242
|
-
}
|
|
243
|
-
</span>
|
|
244
|
-
}
|
|
245
|
-
>
|
|
246
|
-
<DropdownMenuItemLabel>
|
|
247
|
-
{ __( 'Conditions' ) }
|
|
248
|
-
</DropdownMenuItemLabel>
|
|
249
|
-
</DropdownMenuItem>
|
|
250
|
-
}
|
|
251
|
-
>
|
|
252
|
-
{ Object.entries( OPERATORS ).map(
|
|
253
|
-
( [
|
|
254
|
-
operator,
|
|
255
|
-
{ label, key },
|
|
256
|
-
] ) => (
|
|
257
|
-
<DropdownMenuRadioItem
|
|
258
|
-
key={ key }
|
|
259
|
-
name={ `view-table-${ filter.field }-conditions` }
|
|
260
|
-
value={ operator }
|
|
261
|
-
checked={
|
|
262
|
-
activeOperator ===
|
|
263
|
-
operator
|
|
264
|
-
}
|
|
265
|
-
onChange={ ( e ) =>
|
|
266
|
-
onChangeView( {
|
|
267
|
-
...view,
|
|
268
|
-
page: 1,
|
|
269
|
-
filters: [
|
|
270
|
-
...otherFilters,
|
|
271
|
-
{
|
|
272
|
-
field: filter.field,
|
|
273
|
-
operator:
|
|
274
|
-
e.target
|
|
275
|
-
.value,
|
|
276
|
-
value: filterInView?.value,
|
|
277
|
-
},
|
|
278
|
-
],
|
|
279
|
-
} )
|
|
280
|
-
}
|
|
281
|
-
>
|
|
282
|
-
<DropdownMenuItemLabel>
|
|
283
|
-
{ label }
|
|
284
|
-
</DropdownMenuItemLabel>
|
|
285
|
-
</DropdownMenuRadioItem>
|
|
286
|
-
)
|
|
287
|
-
) }
|
|
288
|
-
</DropdownMenu>
|
|
289
|
-
) }
|
|
290
|
-
</WithSeparators>
|
|
291
|
-
</DropdownMenu>
|
|
292
|
-
</DropdownMenuGroup>
|
|
293
|
-
) }
|
|
294
184
|
</WithSeparators>
|
|
295
185
|
</DropdownMenu>
|
|
296
186
|
);
|
|
297
187
|
} );
|
|
298
188
|
|
|
299
|
-
function WithSeparators( { children } ) {
|
|
300
|
-
return Children.toArray( children )
|
|
301
|
-
.filter( Boolean )
|
|
302
|
-
.map( ( child, i ) => (
|
|
303
|
-
<Fragment key={ i }>
|
|
304
|
-
{ i > 0 && <DropdownMenuSeparator /> }
|
|
305
|
-
{ child }
|
|
306
|
-
</Fragment>
|
|
307
|
-
) );
|
|
308
|
-
}
|
|
309
|
-
|
|
310
189
|
function BulkSelectionCheckbox( { selection, onSelectionChange, data } ) {
|
|
311
190
|
const areAllSelected = selection.length === data.length;
|
|
312
191
|
return (
|
|
@@ -327,60 +206,6 @@ function BulkSelectionCheckbox( { selection, onSelectionChange, data } ) {
|
|
|
327
206
|
);
|
|
328
207
|
}
|
|
329
208
|
|
|
330
|
-
function SingleSelectionCheckbox( {
|
|
331
|
-
selection,
|
|
332
|
-
onSelectionChange,
|
|
333
|
-
item,
|
|
334
|
-
data,
|
|
335
|
-
getItemId,
|
|
336
|
-
primaryField,
|
|
337
|
-
} ) {
|
|
338
|
-
const id = getItemId( item );
|
|
339
|
-
const isSelected = selection.includes( id );
|
|
340
|
-
let selectionLabel;
|
|
341
|
-
if ( primaryField?.getValue && item ) {
|
|
342
|
-
// eslint-disable-next-line @wordpress/valid-sprintf
|
|
343
|
-
selectionLabel = sprintf(
|
|
344
|
-
/* translators: %s: item title. */
|
|
345
|
-
isSelected ? __( 'Deselect item: %s' ) : __( 'Select item: %s' ),
|
|
346
|
-
primaryField.getValue( { item } )
|
|
347
|
-
);
|
|
348
|
-
} else {
|
|
349
|
-
selectionLabel = isSelected
|
|
350
|
-
? __( 'Select a new item' )
|
|
351
|
-
: __( 'Deselect item' );
|
|
352
|
-
}
|
|
353
|
-
return (
|
|
354
|
-
<CheckboxControl
|
|
355
|
-
className="dataviews-view-table-selection-checkbox"
|
|
356
|
-
__nextHasNoMarginBottom
|
|
357
|
-
checked={ isSelected }
|
|
358
|
-
label={ selectionLabel }
|
|
359
|
-
onChange={ () => {
|
|
360
|
-
if ( ! isSelected ) {
|
|
361
|
-
onSelectionChange(
|
|
362
|
-
data.filter( ( _item ) => {
|
|
363
|
-
const itemId = getItemId?.( _item );
|
|
364
|
-
return (
|
|
365
|
-
itemId === id || selection.includes( itemId )
|
|
366
|
-
);
|
|
367
|
-
} )
|
|
368
|
-
);
|
|
369
|
-
} else {
|
|
370
|
-
onSelectionChange(
|
|
371
|
-
data.filter( ( _item ) => {
|
|
372
|
-
const itemId = getItemId?.( _item );
|
|
373
|
-
return (
|
|
374
|
-
itemId !== id && selection.includes( itemId )
|
|
375
|
-
);
|
|
376
|
-
} )
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
} }
|
|
380
|
-
/>
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
209
|
function ViewTable( {
|
|
385
210
|
view,
|
|
386
211
|
onChangeView,
|
|
@@ -392,6 +217,7 @@ function ViewTable( {
|
|
|
392
217
|
deferredRendering,
|
|
393
218
|
selection,
|
|
394
219
|
onSelectionChange,
|
|
220
|
+
setOpenedFilter,
|
|
395
221
|
} ) {
|
|
396
222
|
const hasBulkActions = actions?.some( ( action ) => action.supportsBulk );
|
|
397
223
|
const headerMenuRefs = useRef( new Map() );
|
|
@@ -502,6 +328,7 @@ function ViewTable( {
|
|
|
502
328
|
view={ view }
|
|
503
329
|
onChangeView={ onChangeView }
|
|
504
330
|
onHide={ onHide }
|
|
331
|
+
setOpenedFilter={ setOpenedFilter }
|
|
505
332
|
/>
|
|
506
333
|
</th>
|
|
507
334
|
) ) }
|
|
@@ -539,7 +366,7 @@ function ViewTable( {
|
|
|
539
366
|
minWidth: 20,
|
|
540
367
|
} }
|
|
541
368
|
>
|
|
542
|
-
<
|
|
369
|
+
<div className="dataviews-view-table__cell-content-wrapper">
|
|
543
370
|
<SingleSelectionCheckbox
|
|
544
371
|
id={
|
|
545
372
|
getItemId( item ) || index
|
|
@@ -553,7 +380,7 @@ function ViewTable( {
|
|
|
553
380
|
data={ data }
|
|
554
381
|
primaryField={ primaryField }
|
|
555
382
|
/>
|
|
556
|
-
</
|
|
383
|
+
</div>
|
|
557
384
|
</td>
|
|
558
385
|
) }
|
|
559
386
|
{ visibleFields.map( ( field ) => (
|
|
@@ -567,7 +394,7 @@ function ViewTable( {
|
|
|
567
394
|
field.maxWidth || undefined,
|
|
568
395
|
} }
|
|
569
396
|
>
|
|
570
|
-
<
|
|
397
|
+
<div
|
|
571
398
|
className={ classnames(
|
|
572
399
|
'dataviews-view-table__cell-content-wrapper',
|
|
573
400
|
{
|
|
@@ -580,7 +407,7 @@ function ViewTable( {
|
|
|
580
407
|
{ field.render( {
|
|
581
408
|
item,
|
|
582
409
|
} ) }
|
|
583
|
-
</
|
|
410
|
+
</div>
|
|
584
411
|
</td>
|
|
585
412
|
) ) }
|
|
586
413
|
{ !! actions?.length && (
|