@wordpress/dataviews 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/bulk-actions.js +143 -0
  3. package/build/bulk-actions.js.map +1 -0
  4. package/build/dataviews.js +15 -1
  5. package/build/dataviews.js.map +1 -1
  6. package/build/item-actions.js +4 -4
  7. package/build/item-actions.js.map +1 -1
  8. package/build/pagination.js +2 -2
  9. package/build/pagination.js.map +1 -1
  10. package/build/view-actions.js +3 -2
  11. package/build/view-actions.js.map +1 -1
  12. package/build/view-grid.js +11 -8
  13. package/build/view-grid.js.map +1 -1
  14. package/build/view-list.js +13 -1
  15. package/build/view-list.js.map +1 -1
  16. package/build/view-table.js +116 -9
  17. package/build/view-table.js.map +1 -1
  18. package/build-module/bulk-actions.js +136 -0
  19. package/build-module/bulk-actions.js.map +1 -0
  20. package/build-module/dataviews.js +17 -3
  21. package/build-module/dataviews.js.map +1 -1
  22. package/build-module/item-actions.js +4 -4
  23. package/build-module/item-actions.js.map +1 -1
  24. package/build-module/pagination.js +2 -2
  25. package/build-module/pagination.js.map +1 -1
  26. package/build-module/view-actions.js +4 -3
  27. package/build-module/view-actions.js.map +1 -1
  28. package/build-module/view-grid.js +12 -9
  29. package/build-module/view-grid.js.map +1 -1
  30. package/build-module/view-list.js +13 -1
  31. package/build-module/view-list.js.map +1 -1
  32. package/build-module/view-table.js +120 -13
  33. package/build-module/view-table.js.map +1 -1
  34. package/build-style/style-rtl.css +143 -26
  35. package/build-style/style.css +143 -26
  36. package/package.json +11 -11
  37. package/src/bulk-actions.js +187 -0
  38. package/src/dataviews.js +29 -2
  39. package/src/item-actions.js +4 -7
  40. package/src/pagination.js +2 -6
  41. package/src/style.scss +152 -29
  42. package/src/view-actions.js +8 -14
  43. package/src/view-grid.js +14 -12
  44. package/src/view-list.js +20 -1
  45. package/src/view-table.js +161 -15
package/src/style.scss CHANGED
@@ -18,6 +18,10 @@
18
18
  }
19
19
  }
20
20
 
21
+ .dataviews-filters__view-actions.components-h-stack {
22
+ align-items: center;
23
+ }
24
+
21
25
  .dataviews-filters-button {
22
26
  position: relative;
23
27
  }
@@ -55,6 +59,10 @@
55
59
  margin: $grid-unit-40 0 $grid-unit-20;
56
60
  }
57
61
 
62
+ .dataviews-view-table-wrapper {
63
+ overflow-x: auto;
64
+ }
65
+
58
66
  .dataviews-view-table {
59
67
  width: 100%;
60
68
  text-indent: 0;
@@ -77,10 +85,23 @@
77
85
  td,
78
86
  th {
79
87
  padding: $grid-unit-15;
80
- min-width: 160px;
88
+ white-space: nowrap;
89
+
90
+ @include break-huge() {
91
+ min-width: 200px;
92
+ }
93
+
81
94
  &[data-field-id="actions"] {
82
95
  text-align: right;
83
96
  }
97
+
98
+ &.dataviews-view-table__checkbox-column {
99
+ padding-right: 0;
100
+ }
101
+
102
+ .components-checkbox-control__input-container {
103
+ margin: $grid-unit-05;
104
+ }
84
105
  }
85
106
  tr {
86
107
  border-bottom: 1px solid $gray-100;
@@ -109,8 +130,32 @@
109
130
  }
110
131
 
111
132
  &:hover {
112
- td {
113
- background-color: #f8f8f8;
133
+ background-color: #f8f8f8;
134
+ }
135
+
136
+ .components-checkbox-control__input {
137
+ opacity: 0;
138
+
139
+ &:checked,
140
+ &:indeterminate,
141
+ &:focus {
142
+ opacity: 1;
143
+ }
144
+ }
145
+
146
+ &:focus-within,
147
+ &:hover {
148
+ .components-checkbox-control__input {
149
+ opacity: 1;
150
+ }
151
+ }
152
+
153
+ &.is-selected {
154
+ background-color: rgba(var(--wp-admin-theme-color--rgb), 0.04);
155
+ color: $gray-700;
156
+
157
+ &:hover {
158
+ background-color: rgba(var(--wp-admin-theme-color--rgb), 0.08);
114
159
  }
115
160
  }
116
161
  }
@@ -132,7 +177,16 @@
132
177
  padding-left: $grid-unit-05;
133
178
  }
134
179
  }
135
-
180
+ tbody {
181
+ td {
182
+ vertical-align: top;
183
+ }
184
+ .dataviews-view-table__cell-content-wrapper {
185
+ min-height: $grid-unit-40;
186
+ display: flex;
187
+ align-items: center;
188
+ }
189
+ }
136
190
  .dataviews-view-table-header-button {
137
191
  padding: $grid-unit-05 $grid-unit-10;
138
192
  font-size: 11px;
@@ -155,6 +209,48 @@
155
209
  .dataviews-view-table-header {
156
210
  padding-left: $grid-unit-05;
157
211
  }
212
+
213
+ .dataviews-view-table__actions-column {
214
+ width: 1%;
215
+ }
216
+ }
217
+
218
+ .dataviews-view-list__primary-field,
219
+ .dataviews-view-grid__primary-field,
220
+ .dataviews-view-table__primary-field {
221
+ font-size: $default-font-size;
222
+ font-weight: 500;
223
+ color: $gray-900;
224
+ text-overflow: ellipsis;
225
+ white-space: nowrap;
226
+ overflow: hidden;
227
+ display: block;
228
+ width: 100%;
229
+
230
+ a {
231
+ text-decoration: none;
232
+ color: inherit;
233
+ text-overflow: ellipsis;
234
+ white-space: nowrap;
235
+ overflow: hidden;
236
+ display: block;
237
+ width: 100%;
238
+
239
+ &:hover {
240
+ color: $gray-900;
241
+ }
242
+ }
243
+
244
+ button.components-button.is-link {
245
+ text-decoration: none;
246
+ color: inherit;
247
+ font-weight: inherit;
248
+ text-overflow: ellipsis;
249
+ white-space: nowrap;
250
+ overflow: hidden;
251
+ display: block;
252
+ width: 100%;
253
+ }
158
254
  }
159
255
 
160
256
  .dataviews-view-grid {
@@ -171,22 +267,17 @@
171
267
  }
172
268
 
173
269
  .dataviews-view-grid__card {
174
- .dataviews-view-grid__primary-field {
175
- .dataviews-view-grid__title-field {
176
- white-space: nowrap;
177
- overflow: hidden;
178
- text-overflow: ellipsis;
179
- display: block;
180
- font-size: $default-font-size;
181
- width: 100%;
182
- }
270
+ border-radius: $radius-block-ui * 2;
271
+ border: 1px solid $gray-200;
272
+ height: 100%;
273
+ justify-content: flex-start;
183
274
 
184
- .dataviews-view-grid__title-field a,
185
- button.dataviews-view-grid__title-field {
186
- font-weight: 500;
187
- color: $gray-900;
188
- text-decoration: none;
189
- }
275
+ .dataviews-view-grid__title-actions {
276
+ padding: 0 $grid-unit-05;
277
+ }
278
+
279
+ .dataviews-view-grid__primary-field {
280
+ min-height: $grid-unit-50;
190
281
  }
191
282
  }
192
283
 
@@ -194,11 +285,11 @@
194
285
  width: 100%;
195
286
  min-height: 200px;
196
287
  aspect-ratio: 1/1;
197
- box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
198
- border-radius: $radius-block-ui * 2;
199
- overflow: hidden;
288
+ border-bottom: 1px solid $gray-200;
289
+ background-color: $gray-100;
290
+ border-radius: 3px 3px 0 0;
200
291
 
201
- > * {
292
+ img {
202
293
  object-fit: cover;
203
294
  width: 100%;
204
295
  height: 100%;
@@ -206,7 +297,7 @@
206
297
  }
207
298
 
208
299
  .dataviews-view-grid__primary-field {
209
- min-height: $grid-unit-30;
300
+ padding: $grid-unit-10;
210
301
  }
211
302
 
212
303
  .dataviews-view-grid__fields {
@@ -214,12 +305,14 @@
214
305
  font-size: 12px;
215
306
  line-height: 16px;
216
307
 
308
+ &:not(:empty) {
309
+ padding: $grid-unit-15;
310
+ padding-top: 0;
311
+ }
312
+
217
313
  .dataviews-view-grid__field {
218
- .dataviews-view-grid__field-header {
219
- color: $gray-700;
220
- }
221
314
  .dataviews-view-grid__field-value {
222
- color: $gray-900;
315
+ color: $gray-700;
223
316
  }
224
317
  }
225
318
  }
@@ -251,6 +344,7 @@
251
344
  &:not(.is-selected):hover {
252
345
  color: var(--wp-admin-theme-color);
253
346
 
347
+ .dataviews-view-list__primary-field,
254
348
  .dataviews-view-list__fields {
255
349
  color: var(--wp-admin-theme-color);
256
350
  }
@@ -263,6 +357,7 @@
263
357
  background-color: var(--wp-admin-theme-color);
264
358
  color: $white;
265
359
 
360
+ .dataviews-view-list__primary-field,
266
361
  .dataviews-view-list__fields,
267
362
  .components-button {
268
363
  color: $white;
@@ -299,11 +394,19 @@
299
394
  }
300
395
 
301
396
  .dataviews-view-list__media-wrapper {
302
- min-width: $grid-unit-40;
397
+ width: $grid-unit-40;
303
398
  height: $grid-unit-40;
304
399
  border-radius: $grid-unit-05;
305
400
  overflow: hidden;
306
401
  position: relative;
402
+ flex-shrink: 0;
403
+ background-color: $gray-100;
404
+
405
+ img {
406
+ width: 100%;
407
+ height: 100%;
408
+ object-fit: cover;
409
+ }
307
410
 
308
411
  &::after {
309
412
  content: "";
@@ -335,6 +438,10 @@
335
438
  &:last-child {
336
439
  margin-right: 0;
337
440
  }
441
+
442
+ &:empty {
443
+ display: none;
444
+ }
338
445
  }
339
446
  }
340
447
 
@@ -373,7 +480,23 @@
373
480
  padding: 0 $grid-unit-40;
374
481
  }
375
482
 
483
+ .dataviews-view-table-selection-checkbox label {
484
+ position: absolute;
485
+ width: 1px;
486
+ height: 1px;
487
+ padding: 0;
488
+ margin: -1px;
489
+ overflow: hidden;
490
+ clip: rect(0, 0, 0, 0);
491
+ white-space: nowrap;
492
+ border: 0;
493
+ }
494
+
376
495
  .dataviews-filters__custom-menu-radio-item-prefix {
377
496
  display: block;
378
497
  width: 24px;
379
498
  }
499
+
500
+ .dataviews-bulk-edit-button.components-button {
501
+ flex-shrink: 0;
502
+ }
@@ -7,12 +7,13 @@ import {
7
7
  } from '@wordpress/components';
8
8
  import { __ } from '@wordpress/i18n';
9
9
  import { memo } from '@wordpress/element';
10
+ import { settings } from '@wordpress/icons';
10
11
 
11
12
  /**
12
13
  * Internal dependencies
13
14
  */
14
15
  import { unlock } from './lock-unlock';
15
- import { VIEW_LAYOUTS, LAYOUT_TABLE, SORTING_DIRECTIONS } from './constants';
16
+ import { VIEW_LAYOUTS, SORTING_DIRECTIONS } from './constants';
16
17
 
17
18
  const {
18
19
  DropdownMenuV2: DropdownMenu,
@@ -260,24 +261,17 @@ const ViewActions = memo( function ViewActions( {
260
261
  trigger={
261
262
  <Button
262
263
  size="compact"
263
- icon={
264
- VIEW_LAYOUTS.find( ( v ) => v.type === view.type )
265
- ?.icon ||
266
- VIEW_LAYOUTS.find( ( v ) => v.type === LAYOUT_TABLE )
267
- .icon
268
- }
264
+ icon={ settings }
269
265
  label={ __( 'View options' ) }
270
266
  />
271
267
  }
272
268
  >
273
269
  <DropdownMenuGroup>
274
- { window?.__experimentalAdminViews && (
275
- <ViewTypeMenu
276
- view={ view }
277
- onChangeView={ onChangeView }
278
- supportedLayouts={ supportedLayouts }
279
- />
280
- ) }
270
+ <ViewTypeMenu
271
+ view={ view }
272
+ onChangeView={ onChangeView }
273
+ supportedLayouts={ supportedLayouts }
274
+ />
281
275
  <SortMenu
282
276
  fields={ fields }
283
277
  view={ view }
package/src/view-grid.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import {
5
- FlexBlock,
6
5
  __experimentalGrid as Grid,
7
6
  __experimentalHStack as HStack,
8
7
  __experimentalVStack as VStack,
8
+ Tooltip,
9
9
  } from '@wordpress/components';
10
10
  import { useAsyncList } from '@wordpress/compose';
11
11
 
@@ -39,14 +39,14 @@ export default function ViewGrid( {
39
39
  const usedData = deferredRendering ? shownData : data;
40
40
  return (
41
41
  <Grid
42
- gap={ 8 }
42
+ gap={ 6 }
43
43
  columns={ 2 }
44
44
  alignment="top"
45
45
  className="dataviews-view-grid"
46
46
  >
47
47
  { usedData.map( ( item ) => (
48
48
  <VStack
49
- spacing={ 3 }
49
+ spacing={ 0 }
50
50
  key={ getItemId( item ) }
51
51
  className="dataviews-view-grid__card"
52
52
  >
@@ -54,12 +54,12 @@ export default function ViewGrid( {
54
54
  { mediaField?.render( { item } ) }
55
55
  </div>
56
56
  <HStack
57
- className="dataviews-view-grid__primary-field"
58
57
  justify="space-between"
58
+ className="dataviews-view-grid__title-actions"
59
59
  >
60
- <FlexBlock>
60
+ <HStack className="dataviews-view-grid__primary-field">
61
61
  { primaryField?.render( { item } ) }
62
- </FlexBlock>
62
+ </HStack>
63
63
  <ItemActions
64
64
  item={ item }
65
65
  actions={ actions }
@@ -83,12 +83,14 @@ export default function ViewGrid( {
83
83
  key={ field.id }
84
84
  spacing={ 1 }
85
85
  >
86
- <div className="dataviews-view-grid__field-header">
87
- { field.header }
88
- </div>
89
- <div className="dataviews-view-grid__field-value">
90
- { renderedValue }
91
- </div>
86
+ <Tooltip
87
+ text={ field.header }
88
+ placement="left"
89
+ >
90
+ <div className="dataviews-view-grid__field-value">
91
+ { renderedValue }
92
+ </div>
93
+ </Tooltip>
92
94
  </VStack>
93
95
  );
94
96
  } ) }
package/src/view-list.js CHANGED
@@ -20,6 +20,7 @@ export default function ViewList( {
20
20
  view,
21
21
  fields,
22
22
  data,
23
+ isLoading,
23
24
  getItemId,
24
25
  onSelectionChange,
25
26
  onDetailsChange,
@@ -49,6 +50,22 @@ export default function ViewList( {
49
50
  }
50
51
  };
51
52
 
53
+ const hasData = usedData?.length;
54
+ if ( ! hasData ) {
55
+ return (
56
+ <div
57
+ className={ classNames( {
58
+ 'dataviews-loading': isLoading,
59
+ 'dataviews-no-results': ! hasData && ! isLoading,
60
+ } ) }
61
+ >
62
+ { ! hasData && (
63
+ <p>{ isLoading ? __( 'Loading…' ) : __( 'No results' ) }</p>
64
+ ) }
65
+ </div>
66
+ );
67
+ }
68
+
52
69
  return (
53
70
  <ul className="dataviews-view-list">
54
71
  { usedData.map( ( item ) => {
@@ -75,7 +92,9 @@ export default function ViewList( {
75
92
  ) }
76
93
  </div>
77
94
  <VStack spacing={ 1 }>
78
- { primaryField?.render( { item } ) }
95
+ <span className="dataviews-view-list__primary-field">
96
+ { primaryField?.render( { item } ) }
97
+ </span>
79
98
  <div className="dataviews-view-list__fields">
80
99
  { visibleFields.map( ( field ) => {
81
100
  return (
package/src/view-table.js CHANGED
@@ -1,18 +1,19 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import classNames from 'classnames';
4
+ import classnames from 'classnames';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { __ } from '@wordpress/i18n';
9
+ import { __, sprintf } from '@wordpress/i18n';
10
10
  import { useAsyncList } from '@wordpress/compose';
11
11
  import { unseen, funnel } from '@wordpress/icons';
12
12
  import {
13
13
  Button,
14
14
  Icon,
15
15
  privateApis as componentsPrivateApis,
16
+ CheckboxControl,
16
17
  } from '@wordpress/components';
17
18
  import {
18
19
  Children,
@@ -306,6 +307,80 @@ function WithSeparators( { children } ) {
306
307
  ) );
307
308
  }
308
309
 
310
+ function BulkSelectionCheckbox( { selection, onSelectionChange, data } ) {
311
+ const areAllSelected = selection.length === data.length;
312
+ return (
313
+ <CheckboxControl
314
+ className="dataviews-view-table-selection-checkbox"
315
+ __nextHasNoMarginBottom
316
+ checked={ areAllSelected }
317
+ indeterminate={ ! areAllSelected && selection.length }
318
+ onChange={ () => {
319
+ if ( areAllSelected ) {
320
+ onSelectionChange( [] );
321
+ } else {
322
+ onSelectionChange( data );
323
+ }
324
+ } }
325
+ label={ areAllSelected ? __( 'Deselect all' ) : __( 'Select all' ) }
326
+ />
327
+ );
328
+ }
329
+
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
+
309
384
  function ViewTable( {
310
385
  view,
311
386
  onChangeView,
@@ -315,7 +390,10 @@ function ViewTable( {
315
390
  getItemId,
316
391
  isLoading = false,
317
392
  deferredRendering,
393
+ selection,
394
+ onSelectionChange,
318
395
  } ) {
396
+ const hasBulkActions = actions?.some( ( action ) => action.supportsBulk );
319
397
  const headerMenuRefs = useRef( new Map() );
320
398
  const headerMenuToFocusRef = useRef();
321
399
  const [ nextHeaderMenuToFocus, setNextHeaderMenuToFocus ] = useState();
@@ -348,23 +426,42 @@ function ViewTable( {
348
426
  const visibleFields = fields.filter(
349
427
  ( field ) =>
350
428
  ! view.hiddenFields.includes( field.id ) &&
351
- ! [ view.layout.mediaField, view.layout.primaryField ].includes(
352
- field.id
353
- )
429
+ ! [ view.layout.mediaField ].includes( field.id )
354
430
  );
355
431
  const usedData = deferredRendering ? asyncData : data;
356
432
  const hasData = !! usedData?.length;
357
433
  const sortValues = { asc: 'ascending', desc: 'descending' };
358
434
 
435
+ const primaryField = fields.find(
436
+ ( field ) => field.id === view.layout.primaryField
437
+ );
438
+
359
439
  return (
360
- <div>
440
+ <div className="dataviews-view-table-wrapper">
361
441
  <table
362
442
  className="dataviews-view-table"
363
443
  aria-busy={ isLoading }
364
444
  aria-describedby={ tableNoticeId }
365
445
  >
366
446
  <thead>
367
- <tr>
447
+ <tr className="dataviews-view-table__row">
448
+ { hasBulkActions && (
449
+ <th
450
+ className="dataviews-view-table__checkbox-column"
451
+ style={ {
452
+ width: 20,
453
+ minWidth: 20,
454
+ } }
455
+ data-field-id="selection"
456
+ scope="col"
457
+ >
458
+ <BulkSelectionCheckbox
459
+ selection={ selection }
460
+ onSelectionChange={ onSelectionChange }
461
+ data={ data }
462
+ />
463
+ </th>
464
+ ) }
368
465
  { visibleFields.map( ( field, index ) => (
369
466
  <th
370
467
  key={ field.id }
@@ -409,7 +506,10 @@ function ViewTable( {
409
506
  </th>
410
507
  ) ) }
411
508
  { !! actions?.length && (
412
- <th data-field-id="actions">
509
+ <th
510
+ data-field-id="actions"
511
+ className="dataviews-view-table__actions-column"
512
+ >
413
513
  <span className="dataviews-view-table-header">
414
514
  { __( 'Actions' ) }
415
515
  </span>
@@ -419,8 +519,43 @@ function ViewTable( {
419
519
  </thead>
420
520
  <tbody>
421
521
  { hasData &&
422
- usedData.map( ( item ) => (
423
- <tr key={ getItemId( item ) }>
522
+ usedData.map( ( item, index ) => (
523
+ <tr
524
+ key={ getItemId( item ) }
525
+ className={ classnames(
526
+ 'dataviews-view-table__row',
527
+ {
528
+ 'is-selected': selection.includes(
529
+ getItemId( item ) || index
530
+ ),
531
+ }
532
+ ) }
533
+ >
534
+ { hasBulkActions && (
535
+ <td
536
+ className="dataviews-view-table__checkbox-column"
537
+ style={ {
538
+ width: 20,
539
+ minWidth: 20,
540
+ } }
541
+ >
542
+ <span className="dataviews-view-table__cell-content-wrapper">
543
+ <SingleSelectionCheckbox
544
+ id={
545
+ getItemId( item ) || index
546
+ }
547
+ item={ item }
548
+ selection={ selection }
549
+ onSelectionChange={
550
+ onSelectionChange
551
+ }
552
+ getItemId={ getItemId }
553
+ data={ data }
554
+ primaryField={ primaryField }
555
+ />
556
+ </span>
557
+ </td>
558
+ ) }
424
559
  { visibleFields.map( ( field ) => (
425
560
  <td
426
561
  key={ field.id }
@@ -432,13 +567,24 @@ function ViewTable( {
432
567
  field.maxWidth || undefined,
433
568
  } }
434
569
  >
435
- { field.render( {
436
- item,
437
- } ) }
570
+ <span
571
+ className={ classnames(
572
+ 'dataviews-view-table__cell-content-wrapper',
573
+ {
574
+ 'dataviews-view-table__primary-field':
575
+ primaryField?.id ===
576
+ field.id,
577
+ }
578
+ ) }
579
+ >
580
+ { field.render( {
581
+ item,
582
+ } ) }
583
+ </span>
438
584
  </td>
439
585
  ) ) }
440
586
  { !! actions?.length && (
441
- <td>
587
+ <td className="dataviews-view-table__actions-column">
442
588
  <ItemActions
443
589
  item={ item }
444
590
  actions={ actions }
@@ -450,7 +596,7 @@ function ViewTable( {
450
596
  </tbody>
451
597
  </table>
452
598
  <div
453
- className={ classNames( {
599
+ className={ classnames( {
454
600
  'dataviews-loading': isLoading,
455
601
  'dataviews-no-results': ! hasData && ! isLoading,
456
602
  } ) }