@wordpress/dataviews 0.8.0 → 1.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 +3 -13
- package/build/add-filter.js.map +1 -1
- package/build/bulk-actions.js.map +1 -1
- package/build/constants.js +1 -4
- package/build/constants.js.map +1 -1
- package/build/dataviews.js +3 -17
- package/build/dataviews.js.map +1 -1
- package/build/dropdown-menu-helper.js.map +1 -1
- package/build/filter-and-sort-data-view.js +147 -0
- package/build/filter-and-sort-data-view.js.map +1 -0
- package/build/filter-summary.js +4 -2
- package/build/filter-summary.js.map +1 -1
- package/build/filters.js +11 -17
- package/build/filters.js.map +1 -1
- package/build/index.js +3 -9
- package/build/index.js.map +1 -1
- package/build/item-actions.js.map +1 -1
- package/build/lock-unlock.js.map +1 -1
- package/build/normalize-fields.js +25 -0
- package/build/normalize-fields.js.map +1 -0
- package/build/pagination.js.map +1 -1
- package/build/reset-filters.js.map +1 -1
- package/build/search-widget.js +5 -4
- package/build/search-widget.js.map +1 -1
- package/build/search.js.map +1 -1
- package/build/single-selection-checkbox.js +1 -1
- package/build/single-selection-checkbox.js.map +1 -1
- package/build/utils.js +1 -65
- package/build/utils.js.map +1 -1
- package/build/view-actions.js.map +1 -1
- package/build/view-grid.js +57 -19
- package/build/view-grid.js.map +1 -1
- package/build/view-list.js +112 -66
- package/build/view-list.js.map +1 -1
- package/build/view-table.js +32 -24
- package/build/view-table.js.map +1 -1
- package/build-module/add-filter.js.map +1 -1
- package/build-module/bulk-actions.js.map +1 -1
- package/build-module/constants.js +0 -3
- package/build-module/constants.js.map +1 -1
- package/build-module/dataviews.js +3 -17
- package/build-module/dataviews.js.map +1 -1
- package/build-module/dropdown-menu-helper.js.map +1 -1
- package/build-module/filter-and-sort-data-view.js +139 -0
- package/build-module/filter-and-sort-data-view.js.map +1 -0
- package/build-module/filter-summary.js +3 -2
- package/build-module/filter-summary.js.map +1 -1
- package/build-module/filters.js +12 -18
- package/build-module/filters.js.map +1 -1
- package/build-module/index.js +1 -1
- package/build-module/index.js.map +1 -1
- package/build-module/item-actions.js.map +1 -1
- package/build-module/lock-unlock.js.map +1 -1
- package/build-module/normalize-fields.js +19 -0
- package/build-module/normalize-fields.js.map +1 -0
- package/build-module/pagination.js.map +1 -1
- package/build-module/reset-filters.js.map +1 -1
- package/build-module/search-widget.js +4 -3
- package/build-module/search-widget.js.map +1 -1
- package/build-module/search.js.map +1 -1
- package/build-module/single-selection-checkbox.js +1 -1
- package/build-module/single-selection-checkbox.js.map +1 -1
- package/build-module/utils.js +0 -63
- package/build-module/utils.js.map +1 -1
- package/build-module/view-actions.js.map +1 -1
- package/build-module/view-grid.js +58 -20
- package/build-module/view-grid.js.map +1 -1
- package/build-module/view-list.js +114 -68
- package/build-module/view-list.js.map +1 -1
- package/build-module/view-table.js +33 -25
- package/build-module/view-table.js.map +1 -1
- package/build-style/style-rtl.css +75 -39
- package/build-style/style.css +75 -39
- package/package.json +11 -11
- package/src/constants.js +0 -3
- package/src/dataviews.js +2 -16
- package/src/filter-and-sort-data-view.js +154 -0
- package/src/filter-summary.js +4 -4
- package/src/filters.js +20 -32
- package/src/index.js +1 -1
- package/src/normalize-fields.js +17 -0
- package/src/search-widget.js +4 -3
- package/src/single-selection-checkbox.js +1 -1
- package/src/stories/fixtures.js +75 -1
- package/src/stories/index.story.js +5 -113
- package/src/style.scss +89 -49
- package/src/test/filter-and-sort-data-view.js +276 -0
- package/src/utils.js +0 -52
- package/src/view-grid.js +97 -36
- package/src/view-list.js +147 -77
- package/src/view-table.js +36 -24
package/src/view-grid.js
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
__experimentalGrid as Grid,
|
|
11
11
|
__experimentalHStack as HStack,
|
|
12
12
|
__experimentalVStack as VStack,
|
|
13
|
-
Tooltip,
|
|
14
13
|
Spinner,
|
|
14
|
+
Flex,
|
|
15
|
+
FlexItem,
|
|
15
16
|
} from '@wordpress/components';
|
|
16
17
|
import { __ } from '@wordpress/i18n';
|
|
17
|
-
import { useAsyncList } from '@wordpress/compose';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Internal dependencies
|
|
@@ -34,6 +34,8 @@ function GridItem( {
|
|
|
34
34
|
mediaField,
|
|
35
35
|
primaryField,
|
|
36
36
|
visibleFields,
|
|
37
|
+
badgeFields,
|
|
38
|
+
columnFields,
|
|
37
39
|
} ) {
|
|
38
40
|
const hasBulkAction = useHasAPossibleBulkAction( actions, item );
|
|
39
41
|
const id = getItemId( item );
|
|
@@ -98,29 +100,76 @@ function GridItem( {
|
|
|
98
100
|
</HStack>
|
|
99
101
|
<ItemActions item={ item } actions={ actions } isCompact />
|
|
100
102
|
</HStack>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
103
|
+
{ !! badgeFields?.length && (
|
|
104
|
+
<HStack
|
|
105
|
+
className="dataviews-view-grid__badge-fields"
|
|
106
|
+
spacing={ 2 }
|
|
107
|
+
wrap
|
|
108
|
+
align="top"
|
|
109
|
+
justify="flex-start"
|
|
110
|
+
>
|
|
111
|
+
{ badgeFields.map( ( field ) => {
|
|
112
|
+
const renderedValue = field.render( {
|
|
113
|
+
item,
|
|
114
|
+
} );
|
|
115
|
+
if ( ! renderedValue ) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return (
|
|
119
|
+
<FlexItem
|
|
120
|
+
key={ field.id }
|
|
121
|
+
className={ 'dataviews-view-grid__field-value' }
|
|
122
|
+
>
|
|
123
|
+
{ renderedValue }
|
|
124
|
+
</FlexItem>
|
|
125
|
+
);
|
|
126
|
+
} ) }
|
|
127
|
+
</HStack>
|
|
128
|
+
) }
|
|
129
|
+
{ !! visibleFields?.length && (
|
|
130
|
+
<VStack className="dataviews-view-grid__fields" spacing={ 3 }>
|
|
131
|
+
{ visibleFields.map( ( field ) => {
|
|
132
|
+
const renderedValue = field.render( {
|
|
133
|
+
item,
|
|
134
|
+
} );
|
|
135
|
+
if ( ! renderedValue ) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return (
|
|
139
|
+
<Flex
|
|
140
|
+
className={ classnames(
|
|
141
|
+
'dataviews-view-grid__field',
|
|
142
|
+
columnFields?.includes( field.id )
|
|
143
|
+
? 'is-column'
|
|
144
|
+
: 'is-row'
|
|
145
|
+
) }
|
|
146
|
+
key={ field.id }
|
|
147
|
+
gap={ 1 }
|
|
148
|
+
justify="flex-start"
|
|
149
|
+
expanded
|
|
150
|
+
style={ { height: 'auto' } }
|
|
151
|
+
direction={
|
|
152
|
+
columnFields?.includes( field.id )
|
|
153
|
+
? 'column'
|
|
154
|
+
: 'row'
|
|
155
|
+
}
|
|
156
|
+
>
|
|
157
|
+
<>
|
|
158
|
+
<FlexItem className="dataviews-view-grid__field-name">
|
|
159
|
+
{ field.header }
|
|
160
|
+
</FlexItem>
|
|
161
|
+
<FlexItem
|
|
162
|
+
className="dataviews-view-grid__field-value"
|
|
163
|
+
style={ { maxHeight: 'none' } }
|
|
164
|
+
>
|
|
165
|
+
{ renderedValue }
|
|
166
|
+
</FlexItem>
|
|
167
|
+
</>
|
|
168
|
+
</Flex>
|
|
169
|
+
);
|
|
170
|
+
} ) }
|
|
171
|
+
</VStack>
|
|
172
|
+
) }
|
|
124
173
|
</VStack>
|
|
125
174
|
);
|
|
126
175
|
}
|
|
@@ -132,7 +181,6 @@ export default function ViewGrid( {
|
|
|
132
181
|
actions,
|
|
133
182
|
isLoading,
|
|
134
183
|
getItemId,
|
|
135
|
-
deferredRendering,
|
|
136
184
|
selection,
|
|
137
185
|
onSelectionChange,
|
|
138
186
|
} ) {
|
|
@@ -142,16 +190,27 @@ export default function ViewGrid( {
|
|
|
142
190
|
const primaryField = fields.find(
|
|
143
191
|
( field ) => field.id === view.layout.primaryField
|
|
144
192
|
);
|
|
145
|
-
const visibleFields = fields.
|
|
146
|
-
( field ) =>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
193
|
+
const { visibleFields, badgeFields } = fields.reduce(
|
|
194
|
+
( accumulator, field ) => {
|
|
195
|
+
if (
|
|
196
|
+
view.hiddenFields.includes( field.id ) ||
|
|
197
|
+
[ view.layout.mediaField, view.layout.primaryField ].includes(
|
|
198
|
+
field.id
|
|
199
|
+
)
|
|
200
|
+
) {
|
|
201
|
+
return accumulator;
|
|
202
|
+
}
|
|
203
|
+
// If the field is a badge field, add it to the badgeFields array
|
|
204
|
+
// otherwise add it to the rest visibleFields array.
|
|
205
|
+
const key = view.layout.badgeFields?.includes( field.id )
|
|
206
|
+
? 'badgeFields'
|
|
207
|
+
: 'visibleFields';
|
|
208
|
+
accumulator[ key ].push( field );
|
|
209
|
+
return accumulator;
|
|
210
|
+
},
|
|
211
|
+
{ visibleFields: [], badgeFields: [] }
|
|
151
212
|
);
|
|
152
|
-
const
|
|
153
|
-
const usedData = deferredRendering ? shownData : data;
|
|
154
|
-
const hasData = !! usedData?.length;
|
|
213
|
+
const hasData = !! data?.length;
|
|
155
214
|
return (
|
|
156
215
|
<>
|
|
157
216
|
{ hasData && (
|
|
@@ -162,7 +221,7 @@ export default function ViewGrid( {
|
|
|
162
221
|
className="dataviews-view-grid"
|
|
163
222
|
aria-busy={ isLoading }
|
|
164
223
|
>
|
|
165
|
-
{
|
|
224
|
+
{ data.map( ( item ) => {
|
|
166
225
|
return (
|
|
167
226
|
<GridItem
|
|
168
227
|
key={ getItemId( item ) }
|
|
@@ -175,6 +234,8 @@ export default function ViewGrid( {
|
|
|
175
234
|
mediaField={ mediaField }
|
|
176
235
|
primaryField={ primaryField }
|
|
177
236
|
visibleFields={ visibleFields }
|
|
237
|
+
badgeFields={ badgeFields }
|
|
238
|
+
columnFields={ view.layout.columnFields }
|
|
178
239
|
/>
|
|
179
240
|
);
|
|
180
241
|
} ) }
|
package/src/view-list.js
CHANGED
|
@@ -6,17 +6,120 @@ import classNames from 'classnames';
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
10
10
|
import {
|
|
11
11
|
__experimentalHStack as HStack,
|
|
12
12
|
__experimentalVStack as VStack,
|
|
13
|
-
|
|
13
|
+
privateApis as componentsPrivateApis,
|
|
14
14
|
Spinner,
|
|
15
|
+
VisuallyHidden,
|
|
15
16
|
} from '@wordpress/components';
|
|
16
|
-
import {
|
|
17
|
-
import { info } from '@wordpress/icons';
|
|
17
|
+
import { useCallback, useEffect, useRef } from '@wordpress/element';
|
|
18
18
|
import { __ } from '@wordpress/i18n';
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Internal dependencies
|
|
22
|
+
*/
|
|
23
|
+
import { unlock } from './lock-unlock';
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
useCompositeStoreV2: useCompositeStore,
|
|
27
|
+
CompositeV2: Composite,
|
|
28
|
+
CompositeItemV2: CompositeItem,
|
|
29
|
+
CompositeRowV2: CompositeRow,
|
|
30
|
+
} = unlock( componentsPrivateApis );
|
|
31
|
+
|
|
32
|
+
function ListItem( {
|
|
33
|
+
id,
|
|
34
|
+
item,
|
|
35
|
+
isSelected,
|
|
36
|
+
onSelect,
|
|
37
|
+
mediaField,
|
|
38
|
+
primaryField,
|
|
39
|
+
visibleFields,
|
|
40
|
+
} ) {
|
|
41
|
+
const itemRef = useRef( null );
|
|
42
|
+
const labelId = `${ id }-label`;
|
|
43
|
+
const descriptionId = `${ id }-description`;
|
|
44
|
+
|
|
45
|
+
useEffect( () => {
|
|
46
|
+
if ( isSelected ) {
|
|
47
|
+
itemRef.current?.scrollIntoView( {
|
|
48
|
+
behavior: 'auto',
|
|
49
|
+
block: 'nearest',
|
|
50
|
+
inline: 'nearest',
|
|
51
|
+
} );
|
|
52
|
+
}
|
|
53
|
+
}, [ isSelected ] );
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<CompositeRow
|
|
57
|
+
ref={ itemRef }
|
|
58
|
+
render={ <li /> }
|
|
59
|
+
role="row"
|
|
60
|
+
className={ classNames( {
|
|
61
|
+
'is-selected': isSelected,
|
|
62
|
+
} ) }
|
|
63
|
+
>
|
|
64
|
+
<HStack className="dataviews-view-list__item-wrapper">
|
|
65
|
+
<div role="gridcell">
|
|
66
|
+
<CompositeItem
|
|
67
|
+
render={ <div /> }
|
|
68
|
+
role="button"
|
|
69
|
+
id={ id }
|
|
70
|
+
aria-pressed={ isSelected }
|
|
71
|
+
aria-labelledby={ labelId }
|
|
72
|
+
aria-describedby={ descriptionId }
|
|
73
|
+
className="dataviews-view-list__item"
|
|
74
|
+
onClick={ () => onSelect( item ) }
|
|
75
|
+
>
|
|
76
|
+
<HStack
|
|
77
|
+
spacing={ 3 }
|
|
78
|
+
justify="start"
|
|
79
|
+
alignment="flex-start"
|
|
80
|
+
>
|
|
81
|
+
<div className="dataviews-view-list__media-wrapper">
|
|
82
|
+
{ mediaField?.render( { item } ) || (
|
|
83
|
+
<div className="dataviews-view-list__media-placeholder"></div>
|
|
84
|
+
) }
|
|
85
|
+
</div>
|
|
86
|
+
<VStack spacing={ 1 }>
|
|
87
|
+
<span
|
|
88
|
+
className="dataviews-view-list__primary-field"
|
|
89
|
+
id={ labelId }
|
|
90
|
+
>
|
|
91
|
+
{ primaryField?.render( { item } ) }
|
|
92
|
+
</span>
|
|
93
|
+
<div
|
|
94
|
+
className="dataviews-view-list__fields"
|
|
95
|
+
id={ descriptionId }
|
|
96
|
+
>
|
|
97
|
+
{ visibleFields.map( ( field ) => (
|
|
98
|
+
<div
|
|
99
|
+
key={ field.id }
|
|
100
|
+
className="dataviews-view-list__field"
|
|
101
|
+
>
|
|
102
|
+
<VisuallyHidden
|
|
103
|
+
as="span"
|
|
104
|
+
className="dataviews-view-list__field-label"
|
|
105
|
+
>
|
|
106
|
+
{ field.header }
|
|
107
|
+
</VisuallyHidden>
|
|
108
|
+
<span className="dataviews-view-list__field-value">
|
|
109
|
+
{ field.render( { item } ) }
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
) ) }
|
|
113
|
+
</div>
|
|
114
|
+
</VStack>
|
|
115
|
+
</HStack>
|
|
116
|
+
</CompositeItem>
|
|
117
|
+
</div>
|
|
118
|
+
</HStack>
|
|
119
|
+
</CompositeRow>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
20
123
|
export default function ViewList( {
|
|
21
124
|
view,
|
|
22
125
|
fields,
|
|
@@ -24,12 +127,14 @@ export default function ViewList( {
|
|
|
24
127
|
isLoading,
|
|
25
128
|
getItemId,
|
|
26
129
|
onSelectionChange,
|
|
27
|
-
onDetailsChange,
|
|
28
130
|
selection,
|
|
29
|
-
|
|
131
|
+
id: preferredId,
|
|
30
132
|
} ) {
|
|
31
|
-
const
|
|
32
|
-
const
|
|
133
|
+
const baseId = useInstanceId( ViewList, 'view-list', preferredId );
|
|
134
|
+
const selectedItem = data?.findLast( ( item ) =>
|
|
135
|
+
selection.includes( item.id )
|
|
136
|
+
);
|
|
137
|
+
|
|
33
138
|
const mediaField = fields.find(
|
|
34
139
|
( field ) => field.id === view.layout.mediaField
|
|
35
140
|
);
|
|
@@ -44,14 +149,21 @@ export default function ViewList( {
|
|
|
44
149
|
)
|
|
45
150
|
);
|
|
46
151
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
};
|
|
152
|
+
const onSelect = useCallback(
|
|
153
|
+
( item ) => onSelectionChange( [ item ] ),
|
|
154
|
+
[ onSelectionChange ]
|
|
155
|
+
);
|
|
53
156
|
|
|
54
|
-
const
|
|
157
|
+
const getItemDomId = useCallback(
|
|
158
|
+
( item ) => ( item ? `${ baseId }-${ getItemId( item ) }` : undefined ),
|
|
159
|
+
[ baseId, getItemId ]
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const store = useCompositeStore( {
|
|
163
|
+
defaultActiveId: getItemDomId( selectedItem ),
|
|
164
|
+
} );
|
|
165
|
+
|
|
166
|
+
const hasData = data?.length;
|
|
55
167
|
if ( ! hasData ) {
|
|
56
168
|
return (
|
|
57
169
|
<div
|
|
@@ -68,70 +180,28 @@ export default function ViewList( {
|
|
|
68
180
|
}
|
|
69
181
|
|
|
70
182
|
return (
|
|
71
|
-
<
|
|
72
|
-
{
|
|
183
|
+
<Composite
|
|
184
|
+
id={ baseId }
|
|
185
|
+
render={ <ul /> }
|
|
186
|
+
className="dataviews-view-list"
|
|
187
|
+
role="grid"
|
|
188
|
+
store={ store }
|
|
189
|
+
>
|
|
190
|
+
{ data.map( ( item ) => {
|
|
191
|
+
const id = getItemDomId( item );
|
|
73
192
|
return (
|
|
74
|
-
<
|
|
75
|
-
key={
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
aria-pressed={ selection.includes( item.id ) }
|
|
85
|
-
onKeyDown={ onEnter( item ) }
|
|
86
|
-
className="dataviews-view-list__item"
|
|
87
|
-
onClick={ () => onSelectionChange( [ item ] ) }
|
|
88
|
-
>
|
|
89
|
-
<HStack
|
|
90
|
-
spacing={ 3 }
|
|
91
|
-
justify="start"
|
|
92
|
-
alignment="flex-start"
|
|
93
|
-
>
|
|
94
|
-
<div className="dataviews-view-list__media-wrapper">
|
|
95
|
-
{ mediaField?.render( { item } ) || (
|
|
96
|
-
<div className="dataviews-view-list__media-placeholder"></div>
|
|
97
|
-
) }
|
|
98
|
-
</div>
|
|
99
|
-
<VStack spacing={ 1 }>
|
|
100
|
-
<span className="dataviews-view-list__primary-field">
|
|
101
|
-
{ primaryField?.render( { item } ) }
|
|
102
|
-
</span>
|
|
103
|
-
<div className="dataviews-view-list__fields">
|
|
104
|
-
{ visibleFields.map( ( field ) => {
|
|
105
|
-
return (
|
|
106
|
-
<span
|
|
107
|
-
key={ field.id }
|
|
108
|
-
className="dataviews-view-list__field"
|
|
109
|
-
>
|
|
110
|
-
{ field.render( {
|
|
111
|
-
item,
|
|
112
|
-
} ) }
|
|
113
|
-
</span>
|
|
114
|
-
);
|
|
115
|
-
} ) }
|
|
116
|
-
</div>
|
|
117
|
-
</VStack>
|
|
118
|
-
</HStack>
|
|
119
|
-
</div>
|
|
120
|
-
{ onDetailsChange && (
|
|
121
|
-
<Button
|
|
122
|
-
className="dataviews-view-list__details-button"
|
|
123
|
-
onClick={ () =>
|
|
124
|
-
onDetailsChange( [ item ] )
|
|
125
|
-
}
|
|
126
|
-
icon={ info }
|
|
127
|
-
label={ __( 'View details' ) }
|
|
128
|
-
size="compact"
|
|
129
|
-
/>
|
|
130
|
-
) }
|
|
131
|
-
</HStack>
|
|
132
|
-
</li>
|
|
193
|
+
<ListItem
|
|
194
|
+
key={ id }
|
|
195
|
+
id={ id }
|
|
196
|
+
item={ item }
|
|
197
|
+
isSelected={ item === selectedItem }
|
|
198
|
+
onSelect={ onSelect }
|
|
199
|
+
mediaField={ mediaField }
|
|
200
|
+
primaryField={ primaryField }
|
|
201
|
+
visibleFields={ visibleFields }
|
|
202
|
+
/>
|
|
133
203
|
);
|
|
134
204
|
} ) }
|
|
135
|
-
</
|
|
205
|
+
</Composite>
|
|
136
206
|
);
|
|
137
207
|
}
|
package/src/view-table.js
CHANGED
|
@@ -7,7 +7,6 @@ import classnames from 'classnames';
|
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
9
|
import { __ } from '@wordpress/i18n';
|
|
10
|
-
import { useAsyncList } from '@wordpress/compose';
|
|
11
10
|
import { unseen, funnel } from '@wordpress/icons';
|
|
12
11
|
import {
|
|
13
12
|
Button,
|
|
@@ -34,7 +33,7 @@ import SingleSelectionCheckbox from './single-selection-checkbox';
|
|
|
34
33
|
import { unlock } from './lock-unlock';
|
|
35
34
|
import ItemActions from './item-actions';
|
|
36
35
|
import { sanitizeOperators } from './utils';
|
|
37
|
-
import {
|
|
36
|
+
import { SORTING_DIRECTIONS } from './constants';
|
|
38
37
|
import {
|
|
39
38
|
useSomeItemHasAPossibleBulkAction,
|
|
40
39
|
useHasAPossibleBulkAction,
|
|
@@ -76,7 +75,7 @@ const HeaderMenu = forwardRef( function HeaderMenu(
|
|
|
76
75
|
// 3. If it's not primary. If it is, it should be already visible.
|
|
77
76
|
const canAddFilter =
|
|
78
77
|
! view.filters?.some( ( _filter ) => field.id === _filter.field ) &&
|
|
79
|
-
field.
|
|
78
|
+
!! field.elements?.length &&
|
|
80
79
|
!! operators.length &&
|
|
81
80
|
! field.filterBy?.isPrimary;
|
|
82
81
|
if ( ! isSortable && ! isHidable && ! canAddFilter ) {
|
|
@@ -219,7 +218,9 @@ function BulkSelectionCheckbox( {
|
|
|
219
218
|
onSelectionChange( selectableItems );
|
|
220
219
|
}
|
|
221
220
|
} }
|
|
222
|
-
label={
|
|
221
|
+
aria-label={
|
|
222
|
+
areAllSelected ? __( 'Deselect all' ) : __( 'Select all' )
|
|
223
|
+
}
|
|
223
224
|
/>
|
|
224
225
|
);
|
|
225
226
|
}
|
|
@@ -237,7 +238,6 @@ function TableRow( {
|
|
|
237
238
|
data,
|
|
238
239
|
} ) {
|
|
239
240
|
const hasPossibleBulkAction = useHasAPossibleBulkAction( actions, item );
|
|
240
|
-
|
|
241
241
|
const isSelected = selection.includes( id );
|
|
242
242
|
|
|
243
243
|
const [ isHovered, setIsHovered ] = useState( false );
|
|
@@ -250,22 +250,28 @@ function TableRow( {
|
|
|
250
250
|
setIsHovered( false );
|
|
251
251
|
};
|
|
252
252
|
|
|
253
|
+
// Will be set to true if `onTouchStart` fires. This happens before
|
|
254
|
+
// `onClick` and can be used to exclude touchscreen devices from certain
|
|
255
|
+
// behaviours.
|
|
256
|
+
const isTouchDevice = useRef( false );
|
|
257
|
+
|
|
253
258
|
return (
|
|
254
259
|
<tr
|
|
255
260
|
className={ classnames( 'dataviews-view-table__row', {
|
|
256
|
-
'is-selected':
|
|
257
|
-
hasPossibleBulkAction && selection.includes( id ),
|
|
261
|
+
'is-selected': hasPossibleBulkAction && isSelected,
|
|
258
262
|
'is-hovered': isHovered,
|
|
263
|
+
'has-bulk-actions': hasPossibleBulkAction,
|
|
259
264
|
} ) }
|
|
260
265
|
onMouseEnter={ handleMouseEnter }
|
|
261
266
|
onMouseLeave={ handleMouseLeave }
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
onTouchStart={ () => {
|
|
268
|
+
isTouchDevice.current = true;
|
|
269
|
+
} }
|
|
270
|
+
onClick={ () => {
|
|
271
|
+
if (
|
|
272
|
+
! isTouchDevice.current &&
|
|
273
|
+
document.getSelection().type !== 'Range'
|
|
274
|
+
) {
|
|
269
275
|
if ( ! isSelected ) {
|
|
270
276
|
onSelectionChange(
|
|
271
277
|
data.filter( ( _item ) => {
|
|
@@ -294,8 +300,7 @@ function TableRow( {
|
|
|
294
300
|
<td
|
|
295
301
|
className="dataviews-view-table__checkbox-column"
|
|
296
302
|
style={ {
|
|
297
|
-
width:
|
|
298
|
-
minWidth: 20,
|
|
303
|
+
width: '1%',
|
|
299
304
|
} }
|
|
300
305
|
>
|
|
301
306
|
<div className="dataviews-view-table__cell-content-wrapper">
|
|
@@ -337,9 +342,20 @@ function TableRow( {
|
|
|
337
342
|
</td>
|
|
338
343
|
) ) }
|
|
339
344
|
{ !! actions?.length && (
|
|
340
|
-
|
|
345
|
+
// Disable reason: we are not making the element interactive,
|
|
346
|
+
// but preventing any click events from bubbling up to the
|
|
347
|
+
// table row. This allows us to add a click handler to the row
|
|
348
|
+
// itself (to toggle row selection) without erroneously
|
|
349
|
+
// intercepting click events from ItemActions.
|
|
350
|
+
|
|
351
|
+
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */
|
|
352
|
+
<td
|
|
353
|
+
className="dataviews-view-table__actions-column"
|
|
354
|
+
onClick={ ( e ) => e.stopPropagation() }
|
|
355
|
+
>
|
|
341
356
|
<ItemActions item={ item } actions={ actions } />
|
|
342
357
|
</td>
|
|
358
|
+
/* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */
|
|
343
359
|
) }
|
|
344
360
|
</tr>
|
|
345
361
|
);
|
|
@@ -353,7 +369,6 @@ function ViewTable( {
|
|
|
353
369
|
data,
|
|
354
370
|
getItemId,
|
|
355
371
|
isLoading = false,
|
|
356
|
-
deferredRendering,
|
|
357
372
|
selection,
|
|
358
373
|
onSelectionChange,
|
|
359
374
|
setOpenedFilter,
|
|
@@ -370,7 +385,6 @@ function ViewTable( {
|
|
|
370
385
|
}
|
|
371
386
|
} );
|
|
372
387
|
|
|
373
|
-
const asyncData = useAsyncList( data );
|
|
374
388
|
const tableNoticeId = useId();
|
|
375
389
|
|
|
376
390
|
if ( nextHeaderMenuToFocus ) {
|
|
@@ -393,8 +407,7 @@ function ViewTable( {
|
|
|
393
407
|
! view.hiddenFields.includes( field.id ) &&
|
|
394
408
|
! [ view.layout.mediaField ].includes( field.id )
|
|
395
409
|
);
|
|
396
|
-
const
|
|
397
|
-
const hasData = !! usedData?.length;
|
|
410
|
+
const hasData = !! data?.length;
|
|
398
411
|
const sortValues = { asc: 'ascending', desc: 'descending' };
|
|
399
412
|
|
|
400
413
|
const primaryField = fields.find(
|
|
@@ -414,8 +427,7 @@ function ViewTable( {
|
|
|
414
427
|
<th
|
|
415
428
|
className="dataviews-view-table__checkbox-column"
|
|
416
429
|
style={ {
|
|
417
|
-
width:
|
|
418
|
-
minWidth: 20,
|
|
430
|
+
width: '1%',
|
|
419
431
|
} }
|
|
420
432
|
data-field-id="selection"
|
|
421
433
|
scope="col"
|
|
@@ -486,7 +498,7 @@ function ViewTable( {
|
|
|
486
498
|
</thead>
|
|
487
499
|
<tbody>
|
|
488
500
|
{ hasData &&
|
|
489
|
-
|
|
501
|
+
data.map( ( item, index ) => (
|
|
490
502
|
<TableRow
|
|
491
503
|
key={ getItemId( item ) }
|
|
492
504
|
item={ item }
|