@wordpress/dataviews 4.9.0 → 4.9.1-next.a9f418477.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 (102) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +16 -39
  3. package/build/components/dataviews/index.js +2 -3
  4. package/build/components/dataviews/index.js.map +1 -1
  5. package/build/components/dataviews-context/index.js +1 -2
  6. package/build/components/dataviews-context/index.js.map +1 -1
  7. package/build/components/dataviews-item-actions/index.js +21 -20
  8. package/build/components/dataviews-item-actions/index.js.map +1 -1
  9. package/build/components/dataviews-selection-checkbox/index.js +3 -3
  10. package/build/components/dataviews-selection-checkbox/index.js.map +1 -1
  11. package/build/components/dataviews-view-config/index.js +191 -126
  12. package/build/components/dataviews-view-config/index.js.map +1 -1
  13. package/build/dataviews-layouts/grid/index.js +88 -64
  14. package/build/dataviews-layouts/grid/index.js.map +1 -1
  15. package/build/dataviews-layouts/index.js +0 -60
  16. package/build/dataviews-layouts/index.js.map +1 -1
  17. package/build/dataviews-layouts/list/index.js +30 -13
  18. package/build/dataviews-layouts/list/index.js.map +1 -1
  19. package/build/dataviews-layouts/table/column-header-menu.js +19 -24
  20. package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
  21. package/build/dataviews-layouts/table/column-primary.js +55 -0
  22. package/build/dataviews-layouts/table/column-primary.js.map +1 -0
  23. package/build/dataviews-layouts/table/index.js +73 -83
  24. package/build/dataviews-layouts/table/index.js.map +1 -1
  25. package/build/dataviews-layouts/utils/get-clickable-item-props.js +15 -4
  26. package/build/dataviews-layouts/utils/get-clickable-item-props.js.map +1 -1
  27. package/build/types.js.map +1 -1
  28. package/build-module/components/dataviews/index.js +2 -3
  29. package/build-module/components/dataviews/index.js.map +1 -1
  30. package/build-module/components/dataviews-context/index.js +1 -2
  31. package/build-module/components/dataviews-context/index.js.map +1 -1
  32. package/build-module/components/dataviews-item-actions/index.js +21 -20
  33. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  34. package/build-module/components/dataviews-selection-checkbox/index.js +3 -3
  35. package/build-module/components/dataviews-selection-checkbox/index.js.map +1 -1
  36. package/build-module/components/dataviews-view-config/index.js +195 -130
  37. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  38. package/build-module/dataviews-layouts/grid/index.js +89 -65
  39. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  40. package/build-module/dataviews-layouts/index.js +0 -57
  41. package/build-module/dataviews-layouts/index.js.map +1 -1
  42. package/build-module/dataviews-layouts/list/index.js +30 -13
  43. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  44. package/build-module/dataviews-layouts/table/column-header-menu.js +19 -24
  45. package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
  46. package/build-module/dataviews-layouts/table/column-primary.js +48 -0
  47. package/build-module/dataviews-layouts/table/column-primary.js.map +1 -0
  48. package/build-module/dataviews-layouts/table/index.js +76 -86
  49. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  50. package/build-module/dataviews-layouts/utils/get-clickable-item-props.js +15 -4
  51. package/build-module/dataviews-layouts/utils/get-clickable-item-props.js.map +1 -1
  52. package/build-module/types.js.map +1 -1
  53. package/build-style/style-rtl.css +68 -65
  54. package/build-style/style.css +68 -65
  55. package/build-types/components/dataviews/index.d.ts.map +1 -1
  56. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  57. package/build-types/components/dataviews/stories/index.story.d.ts +0 -1
  58. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  59. package/build-types/components/dataviews-context/index.d.ts +1 -1
  60. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  61. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  62. package/build-types/components/dataviews-selection-checkbox/index.d.ts +2 -2
  63. package/build-types/components/dataviews-selection-checkbox/index.d.ts.map +1 -1
  64. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  65. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  66. package/build-types/dataviews-layouts/index.d.ts +0 -4
  67. package/build-types/dataviews-layouts/index.d.ts.map +1 -1
  68. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  69. package/build-types/dataviews-layouts/table/column-header-menu.d.ts +1 -0
  70. package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
  71. package/build-types/dataviews-layouts/table/column-primary.d.ts +14 -0
  72. package/build-types/dataviews-layouts/table/column-primary.d.ts.map +1 -0
  73. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  74. package/build-types/dataviews-layouts/utils/get-clickable-item-props.d.ts +9 -4
  75. package/build-types/dataviews-layouts/utils/get-clickable-item-props.d.ts.map +1 -1
  76. package/build-types/lock-unlock.d.ts +1 -1
  77. package/build-types/lock-unlock.d.ts.map +1 -1
  78. package/build-types/types.d.ts +21 -40
  79. package/build-types/types.d.ts.map +1 -1
  80. package/build-wp/index.js +14820 -0
  81. package/build.js +40 -0
  82. package/package.json +28 -11
  83. package/src/components/dataviews/index.tsx +2 -3
  84. package/src/components/dataviews/stories/fixtures.tsx +0 -3
  85. package/src/components/dataviews/stories/index.story.tsx +14 -106
  86. package/src/components/dataviews/style.scss +33 -33
  87. package/src/components/dataviews-context/index.ts +2 -3
  88. package/src/components/dataviews-item-actions/index.tsx +30 -25
  89. package/src/components/dataviews-selection-checkbox/index.tsx +4 -4
  90. package/src/components/dataviews-view-config/index.tsx +291 -193
  91. package/src/components/dataviews-view-config/style.scss +9 -0
  92. package/src/dataviews-layouts/grid/index.tsx +116 -99
  93. package/src/dataviews-layouts/grid/style.scss +15 -24
  94. package/src/dataviews-layouts/index.ts +0 -88
  95. package/src/dataviews-layouts/list/index.tsx +48 -30
  96. package/src/dataviews-layouts/table/column-header-menu.tsx +94 -86
  97. package/src/dataviews-layouts/table/column-primary.tsx +58 -0
  98. package/src/dataviews-layouts/table/index.tsx +89 -134
  99. package/src/dataviews-layouts/table/style.scss +4 -0
  100. package/src/dataviews-layouts/utils/get-clickable-item-props.ts +22 -9
  101. package/src/types.ts +22 -47
  102. package/tsconfig.tsbuildinfo +1 -1
@@ -27,7 +27,6 @@ import type {
27
27
  ViewTable as ViewTableType,
28
28
  Operator,
29
29
  } from '../../types';
30
- import { getVisibleFieldIds } from '../index';
31
30
 
32
31
  const { Menu } = unlock( componentsPrivateApis );
33
32
 
@@ -38,6 +37,7 @@ interface HeaderMenuProps< Item > {
38
37
  onChangeView: ( view: ViewTableType ) => void;
39
38
  onHide: ( field: NormalizedField< Item > ) => void;
40
39
  setOpenedFilter: ( fieldId: string ) => void;
40
+ canMove?: boolean;
41
41
  }
42
42
 
43
43
  function WithMenuSeparators( { children }: { children: ReactNode } ) {
@@ -59,46 +59,38 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
59
59
  onChangeView,
60
60
  onHide,
61
61
  setOpenedFilter,
62
+ canMove = true,
62
63
  }: HeaderMenuProps< Item >,
63
64
  ref: Ref< HTMLButtonElement >
64
65
  ) {
65
- const visibleFieldIds = getVisibleFieldIds( view, fields );
66
+ const visibleFieldIds = view.fields ?? [];
66
67
  const index = visibleFieldIds?.indexOf( fieldId ) as number;
67
68
  const isSorted = view.sort?.field === fieldId;
68
69
  let isHidable = false;
69
70
  let isSortable = false;
70
71
  let canAddFilter = false;
71
- let header;
72
72
  let operators: Operator[] = [];
73
-
74
- const combinedField = view.layout?.combinedFields?.find(
75
- ( f ) => f.id === fieldId
76
- );
77
73
  const field = fields.find( ( f ) => f.id === fieldId );
78
74
 
79
- if ( ! combinedField ) {
80
- if ( ! field ) {
81
- // No combined or regular field found.
82
- return null;
83
- }
75
+ if ( ! field ) {
76
+ // No combined or regular field found.
77
+ return null;
78
+ }
84
79
 
85
- isHidable = field.enableHiding !== false;
86
- isSortable = field.enableSorting !== false;
87
- header = field.header;
80
+ isHidable = field.enableHiding !== false;
81
+ isSortable = field.enableSorting !== false;
82
+ const header = field.header;
88
83
 
89
- operators = sanitizeOperators( field );
90
- // Filter can be added:
91
- // 1. If the field is not already part of a view's filters.
92
- // 2. If the field meets the type and operator requirements.
93
- // 3. If it's not primary. If it is, it should be already visible.
94
- canAddFilter =
95
- ! view.filters?.some( ( _filter ) => fieldId === _filter.field ) &&
96
- !! field.elements?.length &&
97
- !! operators.length &&
98
- ! field.filterBy?.isPrimary;
99
- } else {
100
- header = combinedField.header || combinedField.label;
101
- }
84
+ operators = sanitizeOperators( field );
85
+ // Filter can be added:
86
+ // 1. If the field is not already part of a view's filters.
87
+ // 2. If the field meets the type and operator requirements.
88
+ // 3. If it's not primary. If it is, it should be already visible.
89
+ canAddFilter =
90
+ ! view.filters?.some( ( _filter ) => fieldId === _filter.field ) &&
91
+ !! field.elements?.length &&
92
+ !! operators.length &&
93
+ ! field.filterBy?.isPrimary;
102
94
 
103
95
  return (
104
96
  <Menu
@@ -188,64 +180,80 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
188
180
  </Menu.Item>
189
181
  </Menu.Group>
190
182
  ) }
191
- <Menu.Group>
192
- <Menu.Item
193
- prefix={ <Icon icon={ arrowLeft } /> }
194
- disabled={ index < 1 }
195
- onClick={ () => {
196
- onChangeView( {
197
- ...view,
198
- fields: [
199
- ...( visibleFieldIds.slice(
200
- 0,
201
- index - 1
202
- ) ?? [] ),
203
- fieldId,
204
- visibleFieldIds[ index - 1 ],
205
- ...visibleFieldIds.slice( index + 1 ),
206
- ],
207
- } );
208
- } }
209
- >
210
- <Menu.ItemLabel>{ __( 'Move left' ) }</Menu.ItemLabel>
211
- </Menu.Item>
212
- <Menu.Item
213
- prefix={ <Icon icon={ arrowRight } /> }
214
- disabled={ index >= visibleFieldIds.length - 1 }
215
- onClick={ () => {
216
- onChangeView( {
217
- ...view,
218
- fields: [
219
- ...( visibleFieldIds.slice( 0, index ) ??
220
- [] ),
221
- visibleFieldIds[ index + 1 ],
222
- fieldId,
223
- ...visibleFieldIds.slice( index + 2 ),
224
- ],
225
- } );
226
- } }
227
- >
228
- <Menu.ItemLabel>{ __( 'Move right' ) }</Menu.ItemLabel>
229
- </Menu.Item>
230
- { isHidable && field && (
231
- <Menu.Item
232
- prefix={ <Icon icon={ unseen } /> }
233
- onClick={ () => {
234
- onHide( field );
235
- onChangeView( {
236
- ...view,
237
- fields: visibleFieldIds.filter(
238
- ( id ) => id !== fieldId
239
- ),
240
- } );
241
- } }
242
- >
243
- <Menu.ItemLabel>
244
- { __( 'Hide column' ) }
245
- </Menu.ItemLabel>
246
- </Menu.Item>
247
- ) }
248
- </Menu.Group>
183
+ { ( canMove || isHidable ) && field && (
184
+ <Menu.Group>
185
+ { canMove && (
186
+ <Menu.Item
187
+ prefix={ <Icon icon={ arrowLeft } /> }
188
+ disabled={ index < 1 }
189
+ onClick={ () => {
190
+ onChangeView( {
191
+ ...view,
192
+ fields: [
193
+ ...( visibleFieldIds.slice(
194
+ 0,
195
+ index - 1
196
+ ) ?? [] ),
197
+ fieldId,
198
+ visibleFieldIds[ index - 1 ],
199
+ ...visibleFieldIds.slice(
200
+ index + 1
201
+ ),
202
+ ],
203
+ } );
204
+ } }
205
+ >
206
+ <Menu.ItemLabel>
207
+ { __( 'Move left' ) }
208
+ </Menu.ItemLabel>
209
+ </Menu.Item>
210
+ ) }
211
+ { canMove && (
212
+ <Menu.Item
213
+ prefix={ <Icon icon={ arrowRight } /> }
214
+ disabled={ index >= visibleFieldIds.length - 1 }
215
+ onClick={ () => {
216
+ onChangeView( {
217
+ ...view,
218
+ fields: [
219
+ ...( visibleFieldIds.slice(
220
+ 0,
221
+ index
222
+ ) ?? [] ),
223
+ visibleFieldIds[ index + 1 ],
224
+ fieldId,
225
+ ...visibleFieldIds.slice(
226
+ index + 2
227
+ ),
228
+ ],
229
+ } );
230
+ } }
231
+ >
232
+ <Menu.ItemLabel>
233
+ { __( 'Move right' ) }
234
+ </Menu.ItemLabel>
235
+ </Menu.Item>
236
+ ) }
237
+ { isHidable && field && (
238
+ <Menu.Item
239
+ prefix={ <Icon icon={ unseen } /> }
240
+ onClick={ () => {
241
+ onHide( field );
242
+ onChangeView( {
243
+ ...view,
244
+ fields: visibleFieldIds.filter(
245
+ ( id ) => id !== fieldId
246
+ ),
247
+ } );
248
+ } }
249
+ >
250
+ <Menu.ItemLabel>
251
+ { __( 'Hide column' ) }
252
+ </Menu.ItemLabel>
253
+ </Menu.Item>
254
+ ) }
255
+ </Menu.Group>
256
+ ) }
249
257
  </WithMenuSeparators>
250
258
  </Menu>
251
259
  );
@@ -0,0 +1,58 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ __experimentalHStack as HStack,
6
+ __experimentalVStack as VStack,
7
+ } from '@wordpress/components';
8
+
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import type { NormalizedField } from '../../types';
13
+ import getClickableItemProps from '../utils/get-clickable-item-props';
14
+
15
+ function ColumnPrimary< Item >( {
16
+ item,
17
+ titleField,
18
+ mediaField,
19
+ descriptionField,
20
+ onClickItem,
21
+ isItemClickable,
22
+ }: {
23
+ item: Item;
24
+ titleField?: NormalizedField< Item >;
25
+ mediaField?: NormalizedField< Item >;
26
+ descriptionField?: NormalizedField< Item >;
27
+ onClickItem?: ( item: Item ) => void;
28
+ isItemClickable: ( item: Item ) => boolean;
29
+ } ) {
30
+ const clickableProps = getClickableItemProps( {
31
+ item,
32
+ isItemClickable,
33
+ onClickItem,
34
+ className:
35
+ 'dataviews-view-table__cell-content-wrapper dataviews-title-field',
36
+ } );
37
+ return (
38
+ <HStack spacing={ 3 } justify="flex-start">
39
+ { mediaField && (
40
+ <div className="dataviews-view-table__cell-content-wrapper dataviews-column-primary__media">
41
+ <mediaField.render item={ item } />
42
+ </div>
43
+ ) }
44
+ <VStack spacing={ 0 }>
45
+ { titleField && (
46
+ <div { ...clickableProps }>
47
+ <titleField.render item={ item } />
48
+ </div>
49
+ ) }
50
+ { descriptionField && (
51
+ <descriptionField.render item={ item } />
52
+ ) }
53
+ </VStack>
54
+ </HStack>
55
+ );
56
+ }
57
+
58
+ export default ColumnPrimary;
@@ -7,17 +7,13 @@ import clsx from 'clsx';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { __ } from '@wordpress/i18n';
10
- import {
11
- Spinner,
12
- __experimentalHStack as HStack,
13
- __experimentalVStack as VStack,
14
- } from '@wordpress/components';
10
+ import { Spinner } from '@wordpress/components';
15
11
  import { useEffect, useId, useRef, useState } from '@wordpress/element';
16
12
 
17
13
  /**
18
14
  * Internal dependencies
19
15
  */
20
- import SingleSelectionCheckbox from '../../components/dataviews-selection-checkbox';
16
+ import DataViewsSelectionCheckbox from '../../components/dataviews-selection-checkbox';
21
17
  import ItemActions from '../../components/dataviews-item-actions';
22
18
  import { sortValues } from '../../constants';
23
19
  import {
@@ -30,39 +26,15 @@ import type {
30
26
  NormalizedField,
31
27
  ViewTable as ViewTableType,
32
28
  ViewTableProps,
33
- CombinedField,
34
29
  } from '../../types';
35
30
  import type { SetSelection } from '../../private-types';
36
31
  import ColumnHeaderMenu from './column-header-menu';
37
- import { getVisibleFieldIds } from '../index';
38
- import getClickableItemProps from '../utils/get-clickable-item-props';
32
+ import ColumnPrimary from './column-primary';
39
33
 
40
34
  interface TableColumnFieldProps< Item > {
41
- primaryField?: NormalizedField< Item >;
42
- field: NormalizedField< Item >;
43
- item: Item;
44
- isItemClickable: ( item: Item ) => boolean;
45
- onClickItem: ( item: Item ) => void;
46
- }
47
-
48
- interface TableColumnCombinedProps< Item > {
49
- primaryField?: NormalizedField< Item >;
50
- fields: NormalizedField< Item >[];
51
- field: CombinedField;
52
- item: Item;
53
- view: ViewTableType;
54
- isItemClickable: ( item: Item ) => boolean;
55
- onClickItem: ( item: Item ) => void;
56
- }
57
-
58
- interface TableColumnProps< Item > {
59
- primaryField?: NormalizedField< Item >;
60
35
  fields: NormalizedField< Item >[];
61
- item: Item;
62
36
  column: string;
63
- view: ViewTableType;
64
- isItemClickable: ( item: Item ) => boolean;
65
- onClickItem: ( item: Item ) => void;
37
+ item: Item;
66
38
  }
67
39
 
68
40
  interface TableRowProps< Item > {
@@ -72,90 +44,34 @@ interface TableRowProps< Item > {
72
44
  fields: NormalizedField< Item >[];
73
45
  id: string;
74
46
  view: ViewTableType;
75
- primaryField?: NormalizedField< Item >;
47
+ titleField?: NormalizedField< Item >;
48
+ mediaField?: NormalizedField< Item >;
49
+ descriptionField?: NormalizedField< Item >;
76
50
  selection: string[];
77
51
  getItemId: ( item: Item ) => string;
78
52
  onChangeSelection: SetSelection;
79
53
  isItemClickable: ( item: Item ) => boolean;
80
- onClickItem: ( item: Item ) => void;
81
- }
82
-
83
- function TableColumn< Item >( {
84
- column,
85
- fields,
86
- view,
87
- ...props
88
- }: TableColumnProps< Item > ) {
89
- const field = fields.find( ( f ) => f.id === column );
90
- if ( !! field ) {
91
- return <TableColumnField { ...props } field={ field } />;
92
- }
93
- const combinedField = view.layout?.combinedFields?.find(
94
- ( f ) => f.id === column
95
- );
96
- if ( !! combinedField ) {
97
- return (
98
- <TableColumnCombined
99
- { ...props }
100
- fields={ fields }
101
- view={ view }
102
- field={ combinedField }
103
- />
104
- );
105
- }
106
-
107
- return null;
54
+ onClickItem?: ( item: Item ) => void;
108
55
  }
109
56
 
110
57
  function TableColumnField< Item >( {
111
- primaryField,
112
58
  item,
113
- field,
114
- isItemClickable,
115
- onClickItem,
59
+ fields,
60
+ column,
116
61
  }: TableColumnFieldProps< Item > ) {
117
- const isPrimaryField = primaryField?.id === field.id;
118
- const isItemClickableField = ( i: Item ) =>
119
- isItemClickable( i ) && isPrimaryField;
62
+ const field = fields.find( ( f ) => f.id === column );
120
63
 
121
- const clickableProps = getClickableItemProps(
122
- item,
123
- isItemClickableField,
124
- onClickItem,
125
- 'dataviews-view-table__cell-content'
126
- );
64
+ if ( ! field ) {
65
+ return null;
66
+ }
127
67
 
128
68
  return (
129
- <div
130
- className={ clsx( 'dataviews-view-table__cell-content-wrapper', {
131
- 'dataviews-view-table__primary-field': isPrimaryField,
132
- } ) }
133
- >
134
- <div { ...clickableProps }>
135
- <field.render { ...{ item } } />
136
- </div>
69
+ <div className="dataviews-view-table__cell-content-wrapper">
70
+ <field.render { ...{ item } } />
137
71
  </div>
138
72
  );
139
73
  }
140
74
 
141
- function TableColumnCombined< Item >( {
142
- field,
143
- ...props
144
- }: TableColumnCombinedProps< Item > ) {
145
- const children = field.children.map( ( child ) => (
146
- <TableColumn key={ child } { ...props } column={ child } />
147
- ) );
148
-
149
- if ( field.direction === 'horizontal' ) {
150
- return (
151
- <HStack spacing={ 3 } justify="flex-start">
152
- { children }
153
- </HStack>
154
- );
155
- }
156
- return <VStack spacing={ 0 }>{ children }</VStack>;
157
- }
158
-
159
75
  function TableRow< Item >( {
160
76
  hasBulkActions,
161
77
  item,
@@ -163,7 +79,9 @@ function TableRow< Item >( {
163
79
  fields,
164
80
  id,
165
81
  view,
166
- primaryField,
82
+ titleField,
83
+ mediaField,
84
+ descriptionField,
167
85
  selection,
168
86
  getItemId,
169
87
  isItemClickable,
@@ -173,7 +91,7 @@ function TableRow< Item >( {
173
91
  const hasPossibleBulkAction = useHasAPossibleBulkAction( actions, item );
174
92
  const isSelected = hasPossibleBulkAction && selection.includes( id );
175
93
  const [ isHovered, setIsHovered ] = useState( false );
176
-
94
+ const { showTitle = true, showMedia = true, showDescription = true } = view;
177
95
  const handleMouseEnter = () => {
178
96
  setIsHovered( true );
179
97
  };
@@ -185,7 +103,11 @@ function TableRow< Item >( {
185
103
  // `onClick` and can be used to exclude touchscreen devices from certain
186
104
  // behaviours.
187
105
  const isTouchDeviceRef = useRef( false );
188
- const columns = getVisibleFieldIds( view, fields );
106
+ const columns = view.fields ?? [];
107
+ const hasPrimaryColumn =
108
+ ( titleField && showTitle ) ||
109
+ ( mediaField && showMedia ) ||
110
+ ( descriptionField && showDescription );
189
111
 
190
112
  return (
191
113
  <tr
@@ -223,17 +145,31 @@ function TableRow< Item >( {
223
145
  } }
224
146
  >
225
147
  <div className="dataviews-view-table__cell-content-wrapper">
226
- <SingleSelectionCheckbox
148
+ <DataViewsSelectionCheckbox
227
149
  item={ item }
228
150
  selection={ selection }
229
151
  onChangeSelection={ onChangeSelection }
230
152
  getItemId={ getItemId }
231
- primaryField={ primaryField }
153
+ titleField={ titleField }
232
154
  disabled={ ! hasPossibleBulkAction }
233
155
  />
234
156
  </div>
235
157
  </td>
236
158
  ) }
159
+ { hasPrimaryColumn && (
160
+ <td>
161
+ <ColumnPrimary
162
+ item={ item }
163
+ titleField={ showTitle ? titleField : undefined }
164
+ mediaField={ showMedia ? mediaField : undefined }
165
+ descriptionField={
166
+ showDescription ? descriptionField : undefined
167
+ }
168
+ isItemClickable={ isItemClickable }
169
+ onClickItem={ onClickItem }
170
+ />
171
+ </td>
172
+ ) }
237
173
  { columns.map( ( column: string ) => {
238
174
  // Explicits picks the supported styles.
239
175
  const { width, maxWidth, minWidth } =
@@ -241,14 +177,10 @@ function TableRow< Item >( {
241
177
 
242
178
  return (
243
179
  <td key={ column } style={ { width, maxWidth, minWidth } }>
244
- <TableColumn
245
- primaryField={ primaryField }
246
- isItemClickable={ isItemClickable }
247
- onClickItem={ onClickItem }
180
+ <TableColumnField
248
181
  fields={ fields }
249
182
  item={ item }
250
183
  column={ column }
251
- view={ view }
252
184
  />
253
185
  </td>
254
186
  );
@@ -322,12 +254,30 @@ function ViewTable< Item >( {
322
254
  setNextHeaderMenuToFocus( fallback?.node );
323
255
  };
324
256
 
325
- const columns = getVisibleFieldIds( view, fields );
326
257
  const hasData = !! data?.length;
327
258
 
328
- const primaryField = fields.find(
329
- ( field ) => field.id === view.layout?.primaryField
259
+ const titleField = fields.find( ( field ) => field.id === view.titleField );
260
+ const mediaField = fields.find( ( field ) => field.id === view.mediaField );
261
+ const descriptionField = fields.find(
262
+ ( field ) => field.id === view.descriptionField
330
263
  );
264
+ const { showTitle = true, showMedia = true, showDescription = true } = view;
265
+ const hasPrimaryColumn =
266
+ ( titleField && showTitle ) ||
267
+ ( mediaField && showMedia ) ||
268
+ ( descriptionField && showDescription );
269
+ const columns = view.fields ?? [];
270
+ const headerMenuRef =
271
+ ( column: string, index: number ) => ( node: HTMLButtonElement ) => {
272
+ if ( node ) {
273
+ headerMenuRefs.current.set( column, {
274
+ node,
275
+ fallback: columns[ index > 0 ? index - 1 : 1 ],
276
+ } );
277
+ } else {
278
+ headerMenuRefs.current.delete( column );
279
+ }
280
+ };
331
281
 
332
282
  return (
333
283
  <>
@@ -361,6 +311,27 @@ function ViewTable< Item >( {
361
311
  />
362
312
  </th>
363
313
  ) }
314
+ { hasPrimaryColumn && (
315
+ <th scope="col">
316
+ <span className="dataviews-view-table-header">
317
+ { titleField && (
318
+ <ColumnHeaderMenu
319
+ ref={ headerMenuRef(
320
+ titleField.id,
321
+ 0
322
+ ) }
323
+ fieldId={ titleField.id }
324
+ view={ view }
325
+ fields={ fields }
326
+ onChangeView={ onChangeView }
327
+ onHide={ onHide }
328
+ setOpenedFilter={ setOpenedFilter }
329
+ canMove={ false }
330
+ />
331
+ ) }
332
+ </span>
333
+ </th>
334
+ ) }
364
335
  { columns.map( ( column, index ) => {
365
336
  // Explicits picks the supported styles.
366
337
  const { width, maxWidth, minWidth } =
@@ -370,6 +341,7 @@ function ViewTable< Item >( {
370
341
  key={ column }
371
342
  style={ { width, maxWidth, minWidth } }
372
343
  aria-sort={
344
+ view.sort?.direction &&
373
345
  view.sort?.field === column
374
346
  ? sortValues[ view.sort.direction ]
375
347
  : undefined
@@ -377,26 +349,7 @@ function ViewTable< Item >( {
377
349
  scope="col"
378
350
  >
379
351
  <ColumnHeaderMenu
380
- ref={ ( node ) => {
381
- if ( node ) {
382
- headerMenuRefs.current.set(
383
- column,
384
- {
385
- node,
386
- fallback:
387
- columns[
388
- index > 0
389
- ? index - 1
390
- : 1
391
- ],
392
- }
393
- );
394
- } else {
395
- headerMenuRefs.current.delete(
396
- column
397
- );
398
- }
399
- } }
352
+ ref={ headerMenuRef( column, index ) }
400
353
  fieldId={ column }
401
354
  view={ view }
402
355
  fields={ fields }
@@ -427,7 +380,9 @@ function ViewTable< Item >( {
427
380
  fields={ fields }
428
381
  id={ getItemId( item ) || index.toString() }
429
382
  view={ view }
430
- primaryField={ primaryField }
383
+ titleField={ titleField }
384
+ mediaField={ mediaField }
385
+ descriptionField={ descriptionField }
431
386
  selection={ selection }
432
387
  getItemId={ getItemId }
433
388
  onChangeSelection={ onChangeSelection }
@@ -222,3 +222,7 @@
222
222
  --checkbox-input-size: 16px;
223
223
  }
224
224
  }
225
+
226
+ .dataviews-column-primary__media {
227
+ max-width: 60px;
228
+ }
@@ -1,20 +1,33 @@
1
- export default function getClickableItemProps< Item >(
2
- item: Item,
3
- isItemClickable: ( item: Item ) => boolean,
4
- onClickItem: ( item: Item ) => void,
5
- className: string
6
- ) {
7
- if ( ! isItemClickable( item ) ) {
1
+ export default function getClickableItemProps< Item >( {
2
+ item,
3
+ isItemClickable,
4
+ onClickItem,
5
+ className,
6
+ }: {
7
+ item: Item;
8
+ isItemClickable: ( item: Item ) => boolean;
9
+ onClickItem?: ( item: Item ) => void;
10
+ className?: string;
11
+ } ) {
12
+ if ( ! isItemClickable( item ) || ! onClickItem ) {
8
13
  return { className };
9
14
  }
10
15
 
11
16
  return {
12
- className: `${ className } ${ className }--clickable`,
17
+ className: className
18
+ ? `${ className } ${ className }--clickable`
19
+ : undefined,
13
20
  role: 'button',
14
21
  tabIndex: 0,
15
- onClick: () => onClickItem( item ),
22
+ onClick: ( event: React.MouseEvent ) => {
23
+ // Prevents onChangeSelection from triggering.
24
+ event.stopPropagation();
25
+ onClickItem( item );
26
+ },
16
27
  onKeyDown: ( event: React.KeyboardEvent ) => {
17
28
  if ( event.key === 'Enter' || event.key === '' ) {
29
+ // Prevents onChangeSelection from triggering.
30
+ event.stopPropagation();
18
31
  onClickItem( item );
19
32
  }
20
33
  },