@wordpress/dataviews 4.2.0 → 4.3.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 +47 -7
- package/build/components/dataviews/index.js +3 -5
- package/build/components/dataviews/index.js.map +1 -1
- package/build/components/dataviews-bulk-actions/index.js +145 -141
- package/build/components/dataviews-bulk-actions/index.js.map +1 -1
- package/build/components/dataviews-filters/add-filter.js +4 -6
- package/build/components/dataviews-filters/add-filter.js.map +1 -1
- package/build/components/dataviews-filters/search-widget.js +28 -18
- package/build/components/dataviews-filters/search-widget.js.map +1 -1
- package/build/components/dataviews-footer/index.js +45 -0
- package/build/components/dataviews-footer/index.js.map +1 -0
- package/build/components/dataviews-item-actions/index.js +5 -8
- package/build/components/dataviews-item-actions/index.js.map +1 -1
- package/build/components/dataviews-pagination/index.js +4 -4
- package/build/components/dataviews-pagination/index.js.map +1 -1
- package/build/components/dataviews-view-config/index.js +171 -32
- package/build/components/dataviews-view-config/index.js.map +1 -1
- package/build/dataforms-layouts/panel/index.js +4 -1
- package/build/dataforms-layouts/panel/index.js.map +1 -1
- package/build/dataviews-layouts/index.js +48 -2
- package/build/dataviews-layouts/index.js.map +1 -1
- package/build/dataviews-layouts/list/index.js +124 -84
- package/build/dataviews-layouts/list/index.js.map +1 -1
- package/build/dataviews-layouts/table/column-header-menu.js +52 -54
- package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
- package/build/dataviews-layouts/table/index.js +7 -35
- package/build/dataviews-layouts/table/index.js.map +1 -1
- package/build/normalize-fields.js +4 -2
- package/build/normalize-fields.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build-module/components/dataviews/index.js +3 -5
- package/build-module/components/dataviews/index.js.map +1 -1
- package/build-module/components/dataviews-bulk-actions/index.js +145 -143
- package/build-module/components/dataviews-bulk-actions/index.js.map +1 -1
- package/build-module/components/dataviews-filters/add-filter.js +4 -6
- package/build-module/components/dataviews-filters/add-filter.js.map +1 -1
- package/build-module/components/dataviews-filters/search-widget.js +28 -18
- package/build-module/components/dataviews-filters/search-widget.js.map +1 -1
- package/build-module/components/dataviews-footer/index.js +38 -0
- package/build-module/components/dataviews-footer/index.js.map +1 -0
- package/build-module/components/dataviews-item-actions/index.js +5 -8
- package/build-module/components/dataviews-item-actions/index.js.map +1 -1
- package/build-module/components/dataviews-pagination/index.js +5 -5
- package/build-module/components/dataviews-pagination/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/index.js +177 -38
- package/build-module/components/dataviews-view-config/index.js.map +1 -1
- package/build-module/dataforms-layouts/panel/index.js +4 -1
- package/build-module/dataforms-layouts/panel/index.js.map +1 -1
- package/build-module/dataviews-layouts/index.js +45 -1
- package/build-module/dataviews-layouts/index.js.map +1 -1
- package/build-module/dataviews-layouts/list/index.js +125 -83
- package/build-module/dataviews-layouts/list/index.js.map +1 -1
- package/build-module/dataviews-layouts/table/column-header-menu.js +52 -54
- package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
- package/build-module/dataviews-layouts/table/index.js +9 -37
- package/build-module/dataviews-layouts/table/index.js.map +1 -1
- package/build-module/normalize-fields.js +4 -2
- package/build-module/normalize-fields.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-style/style-rtl.css +79 -63
- package/build-style/style.css +79 -63
- package/build-types/components/dataviews/index.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/fixtures.d.ts +27 -131
- package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/index.story.d.ts +12 -53
- package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews-bulk-actions/index.d.ts +11 -1
- package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/add-filter.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/search-widget.d.ts.map +1 -1
- package/build-types/components/dataviews-footer/index.d.ts +2 -0
- package/build-types/components/dataviews-footer/index.d.ts.map +1 -0
- package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/index.d.ts +4 -2
- package/build-types/dataviews-layouts/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
- package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
- package/build-types/normalize-fields.d.ts.map +1 -1
- package/build-types/types.d.ts +2 -0
- package/build-types/types.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/components/dataviews/index.tsx +2 -6
- package/src/components/dataviews/stories/fixtures.tsx +690 -0
- package/src/components/dataviews/stories/index.story.tsx +164 -0
- package/src/components/dataviews/style.scss +2 -0
- package/src/components/dataviews-bulk-actions/index.tsx +264 -213
- package/src/components/dataviews-bulk-actions/style.scss +9 -4
- package/src/components/dataviews-filters/add-filter.tsx +7 -11
- package/src/components/dataviews-filters/search-widget.tsx +45 -17
- package/src/components/dataviews-filters/style.scss +12 -2
- package/src/components/dataviews-footer/index.tsx +50 -0
- package/src/components/dataviews-footer/style.scss +40 -0
- package/src/components/dataviews-item-actions/index.tsx +8 -14
- package/src/components/dataviews-pagination/index.tsx +5 -5
- package/src/components/dataviews-pagination/style.scss +0 -19
- package/src/components/dataviews-view-config/index.tsx +252 -53
- package/src/components/dataviews-view-config/style.scss +25 -0
- package/src/dataforms-layouts/panel/index.tsx +2 -0
- package/src/dataviews-layouts/grid/style.scss +1 -1
- package/src/dataviews-layouts/index.ts +63 -2
- package/src/dataviews-layouts/list/index.tsx +199 -127
- package/src/dataviews-layouts/list/style.scss +10 -4
- package/src/dataviews-layouts/table/column-header-menu.tsx +85 -87
- package/src/dataviews-layouts/table/index.tsx +8 -65
- package/src/dataviews-layouts/table/style.scss +0 -5
- package/src/normalize-fields.ts +2 -0
- package/src/style.scss +1 -1
- package/src/types.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/build/components/dataviews-bulk-actions-toolbar/index.js +0 -207
- package/build/components/dataviews-bulk-actions-toolbar/index.js.map +0 -1
- package/build-module/components/dataviews-bulk-actions-toolbar/index.js +0 -201
- package/build-module/components/dataviews-bulk-actions-toolbar/index.js.map +0 -1
- package/build-types/components/dataviews-bulk-actions-toolbar/index.d.ts +0 -2
- package/build-types/components/dataviews-bulk-actions-toolbar/index.d.ts.map +0 -1
- package/src/components/dataviews/stories/fixtures.js +0 -250
- package/src/components/dataviews/stories/index.story.js +0 -71
- package/src/components/dataviews-bulk-actions-toolbar/index.tsx +0 -288
- package/src/components/dataviews-bulk-actions-toolbar/style.scss +0 -45
|
@@ -2,17 +2,11 @@
|
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
4
|
import clsx from 'clsx';
|
|
5
|
-
// TODO: use the @wordpress/components one once public
|
|
6
|
-
// eslint-disable-next-line no-restricted-imports
|
|
7
|
-
import { useStoreState } from '@ariakit/react';
|
|
8
|
-
// Import CompositeStore type, which is not exported from @wordpress/components.
|
|
9
|
-
// eslint-disable-next-line no-restricted-imports
|
|
10
|
-
import type { CompositeStore } from '@ariakit/react';
|
|
11
5
|
|
|
12
6
|
/**
|
|
13
7
|
* WordPress dependencies
|
|
14
8
|
*/
|
|
15
|
-
import { useInstanceId } from '@wordpress/compose';
|
|
9
|
+
import { useInstanceId, usePrevious } from '@wordpress/compose';
|
|
16
10
|
import {
|
|
17
11
|
__experimentalHStack as HStack,
|
|
18
12
|
__experimentalVStack as VStack,
|
|
@@ -44,39 +38,115 @@ import type { Action, NormalizedField, ViewListProps } from '../../types';
|
|
|
44
38
|
|
|
45
39
|
interface ListViewItemProps< Item > {
|
|
46
40
|
actions: Action< Item >[];
|
|
47
|
-
|
|
41
|
+
idPrefix: string;
|
|
48
42
|
isSelected: boolean;
|
|
49
43
|
item: Item;
|
|
50
44
|
mediaField?: NormalizedField< Item >;
|
|
51
45
|
onSelect: ( item: Item ) => void;
|
|
52
46
|
primaryField?: NormalizedField< Item >;
|
|
53
|
-
store: CompositeStore;
|
|
54
47
|
visibleFields: NormalizedField< Item >[];
|
|
48
|
+
onDropdownTriggerKeyDown: React.KeyboardEventHandler< HTMLButtonElement >;
|
|
55
49
|
}
|
|
56
50
|
|
|
57
51
|
const {
|
|
58
|
-
useCompositeStoreV2: useCompositeStore,
|
|
59
52
|
CompositeV2: Composite,
|
|
60
53
|
CompositeItemV2: CompositeItem,
|
|
61
54
|
CompositeRowV2: CompositeRow,
|
|
62
55
|
DropdownMenuV2: DropdownMenu,
|
|
63
56
|
} = unlock( componentsPrivateApis );
|
|
64
57
|
|
|
58
|
+
function generateItemWrapperCompositeId( idPrefix: string ) {
|
|
59
|
+
return `${ idPrefix }-item-wrapper`;
|
|
60
|
+
}
|
|
61
|
+
function generatePrimaryActionCompositeId(
|
|
62
|
+
idPrefix: string,
|
|
63
|
+
primaryActionId: string
|
|
64
|
+
) {
|
|
65
|
+
return `${ idPrefix }-primary-action-${ primaryActionId }`;
|
|
66
|
+
}
|
|
67
|
+
function generateDropdownTriggerCompositeId( idPrefix: string ) {
|
|
68
|
+
return `${ idPrefix }-dropdown`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function PrimaryActionGridCell< Item >( {
|
|
72
|
+
idPrefix,
|
|
73
|
+
primaryAction,
|
|
74
|
+
item,
|
|
75
|
+
}: {
|
|
76
|
+
idPrefix: string;
|
|
77
|
+
primaryAction: Action< Item >;
|
|
78
|
+
item: Item;
|
|
79
|
+
} ) {
|
|
80
|
+
const registry = useRegistry();
|
|
81
|
+
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
|
82
|
+
|
|
83
|
+
const compositeItemId = generatePrimaryActionCompositeId(
|
|
84
|
+
idPrefix,
|
|
85
|
+
primaryAction.id
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const label =
|
|
89
|
+
typeof primaryAction.label === 'string'
|
|
90
|
+
? primaryAction.label
|
|
91
|
+
: primaryAction.label( [ item ] );
|
|
92
|
+
|
|
93
|
+
return 'RenderModal' in primaryAction ? (
|
|
94
|
+
<div role="gridcell" key={ primaryAction.id }>
|
|
95
|
+
<CompositeItem
|
|
96
|
+
id={ compositeItemId }
|
|
97
|
+
render={
|
|
98
|
+
<Button
|
|
99
|
+
label={ label }
|
|
100
|
+
icon={ primaryAction.icon }
|
|
101
|
+
isDestructive={ primaryAction.isDestructive }
|
|
102
|
+
size="small"
|
|
103
|
+
onClick={ () => setIsModalOpen( true ) }
|
|
104
|
+
/>
|
|
105
|
+
}
|
|
106
|
+
>
|
|
107
|
+
{ isModalOpen && (
|
|
108
|
+
<ActionModal< Item >
|
|
109
|
+
action={ primaryAction }
|
|
110
|
+
items={ [ item ] }
|
|
111
|
+
closeModal={ () => setIsModalOpen( false ) }
|
|
112
|
+
/>
|
|
113
|
+
) }
|
|
114
|
+
</CompositeItem>
|
|
115
|
+
</div>
|
|
116
|
+
) : (
|
|
117
|
+
<div role="gridcell" key={ primaryAction.id }>
|
|
118
|
+
<CompositeItem
|
|
119
|
+
id={ compositeItemId }
|
|
120
|
+
render={
|
|
121
|
+
<Button
|
|
122
|
+
label={ label }
|
|
123
|
+
icon={ primaryAction.icon }
|
|
124
|
+
isDestructive={ primaryAction.isDestructive }
|
|
125
|
+
size="small"
|
|
126
|
+
onClick={ () => {
|
|
127
|
+
primaryAction.callback( [ item ], { registry } );
|
|
128
|
+
} }
|
|
129
|
+
/>
|
|
130
|
+
}
|
|
131
|
+
/>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
65
136
|
function ListItem< Item >( {
|
|
66
137
|
actions,
|
|
67
|
-
|
|
138
|
+
idPrefix,
|
|
68
139
|
isSelected,
|
|
69
140
|
item,
|
|
70
141
|
mediaField,
|
|
71
142
|
onSelect,
|
|
72
143
|
primaryField,
|
|
73
|
-
store,
|
|
74
144
|
visibleFields,
|
|
145
|
+
onDropdownTriggerKeyDown,
|
|
75
146
|
}: ListViewItemProps< Item > ) {
|
|
76
|
-
const registry = useRegistry();
|
|
77
147
|
const itemRef = useRef< HTMLElement >( null );
|
|
78
|
-
const labelId = `${
|
|
79
|
-
const descriptionId = `${
|
|
148
|
+
const labelId = `${ idPrefix }-label`;
|
|
149
|
+
const descriptionId = `${ idPrefix }-description`;
|
|
80
150
|
|
|
81
151
|
const [ isHovered, setIsHovered ] = useState( false );
|
|
82
152
|
const handleMouseEnter = () => {
|
|
@@ -111,13 +181,6 @@ function ListItem< Item >( {
|
|
|
111
181
|
};
|
|
112
182
|
}, [ actions, item ] );
|
|
113
183
|
|
|
114
|
-
const [ isModalOpen, setIsModalOpen ] = useState( false );
|
|
115
|
-
const primaryActionLabel =
|
|
116
|
-
primaryAction &&
|
|
117
|
-
( typeof primaryAction.label === 'string'
|
|
118
|
-
? primaryAction.label
|
|
119
|
-
: primaryAction.label( [ item ] ) );
|
|
120
|
-
|
|
121
184
|
const renderedMediaField = mediaField?.render ? (
|
|
122
185
|
<mediaField.render item={ item } />
|
|
123
186
|
) : (
|
|
@@ -147,10 +210,9 @@ function ListItem< Item >( {
|
|
|
147
210
|
>
|
|
148
211
|
<div role="gridcell">
|
|
149
212
|
<CompositeItem
|
|
150
|
-
store={ store }
|
|
151
213
|
render={ <div /> }
|
|
152
214
|
role="button"
|
|
153
|
-
id={
|
|
215
|
+
id={ generateItemWrapperCompositeId( idPrefix ) }
|
|
154
216
|
aria-pressed={ isSelected }
|
|
155
217
|
aria-labelledby={ labelId }
|
|
156
218
|
aria-describedby={ descriptionId }
|
|
@@ -210,65 +272,20 @@ function ListItem< Item >( {
|
|
|
210
272
|
width: 'auto',
|
|
211
273
|
} }
|
|
212
274
|
>
|
|
213
|
-
{ primaryAction &&
|
|
214
|
-
<
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
label={ primaryActionLabel }
|
|
220
|
-
icon={ primaryAction.icon }
|
|
221
|
-
isDestructive={
|
|
222
|
-
primaryAction.isDestructive
|
|
223
|
-
}
|
|
224
|
-
size="small"
|
|
225
|
-
onClick={ () =>
|
|
226
|
-
setIsModalOpen( true )
|
|
227
|
-
}
|
|
228
|
-
/>
|
|
229
|
-
}
|
|
230
|
-
>
|
|
231
|
-
{ isModalOpen && (
|
|
232
|
-
<ActionModal< Item >
|
|
233
|
-
action={ primaryAction }
|
|
234
|
-
items={ [ item ] }
|
|
235
|
-
closeModal={ () =>
|
|
236
|
-
setIsModalOpen( false )
|
|
237
|
-
}
|
|
238
|
-
/>
|
|
239
|
-
) }
|
|
240
|
-
</CompositeItem>
|
|
241
|
-
</div>
|
|
275
|
+
{ primaryAction && (
|
|
276
|
+
<PrimaryActionGridCell
|
|
277
|
+
idPrefix={ idPrefix }
|
|
278
|
+
primaryAction={ primaryAction }
|
|
279
|
+
item={ item }
|
|
280
|
+
/>
|
|
242
281
|
) }
|
|
243
|
-
{ primaryAction &&
|
|
244
|
-
! ( 'RenderModal' in primaryAction ) && (
|
|
245
|
-
<div role="gridcell" key={ primaryAction.id }>
|
|
246
|
-
<CompositeItem
|
|
247
|
-
store={ store }
|
|
248
|
-
render={
|
|
249
|
-
<Button
|
|
250
|
-
label={ primaryActionLabel }
|
|
251
|
-
icon={ primaryAction.icon }
|
|
252
|
-
isDestructive={
|
|
253
|
-
primaryAction.isDestructive
|
|
254
|
-
}
|
|
255
|
-
size="small"
|
|
256
|
-
onClick={ () => {
|
|
257
|
-
primaryAction.callback(
|
|
258
|
-
[ item ],
|
|
259
|
-
{ registry }
|
|
260
|
-
);
|
|
261
|
-
} }
|
|
262
|
-
/>
|
|
263
|
-
}
|
|
264
|
-
/>
|
|
265
|
-
</div>
|
|
266
|
-
) }
|
|
267
282
|
<div role="gridcell">
|
|
268
283
|
<DropdownMenu
|
|
269
284
|
trigger={
|
|
270
285
|
<CompositeItem
|
|
271
|
-
|
|
286
|
+
id={ generateDropdownTriggerCompositeId(
|
|
287
|
+
idPrefix
|
|
288
|
+
) }
|
|
272
289
|
render={
|
|
273
290
|
<Button
|
|
274
291
|
size="small"
|
|
@@ -276,30 +293,9 @@ function ListItem< Item >( {
|
|
|
276
293
|
label={ __( 'Actions' ) }
|
|
277
294
|
accessibleWhenDisabled
|
|
278
295
|
disabled={ ! actions.length }
|
|
279
|
-
onKeyDown={
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
} ) => {
|
|
283
|
-
if (
|
|
284
|
-
event.key ===
|
|
285
|
-
'ArrowDown'
|
|
286
|
-
) {
|
|
287
|
-
// Prevent the default behaviour (open dropdown menu) and go down.
|
|
288
|
-
event.preventDefault();
|
|
289
|
-
store.move(
|
|
290
|
-
store.down()
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
if (
|
|
294
|
-
event.key === 'ArrowUp'
|
|
295
|
-
) {
|
|
296
|
-
// Prevent the default behavior (open dropdown menu) and go up.
|
|
297
|
-
event.preventDefault();
|
|
298
|
-
store.move(
|
|
299
|
-
store.up()
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
} }
|
|
296
|
+
onKeyDown={
|
|
297
|
+
onDropdownTriggerKeyDown
|
|
298
|
+
}
|
|
303
299
|
/>
|
|
304
300
|
}
|
|
305
301
|
/>
|
|
@@ -331,6 +327,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
331
327
|
view,
|
|
332
328
|
} = props;
|
|
333
329
|
const baseId = useInstanceId( ViewList, 'view-list' );
|
|
330
|
+
|
|
334
331
|
const selectedItem = data?.findLast( ( item ) =>
|
|
335
332
|
selection.includes( getItemId( item ) )
|
|
336
333
|
);
|
|
@@ -353,34 +350,108 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
353
350
|
const onSelect = ( item: Item ) =>
|
|
354
351
|
onChangeSelection( [ getItemId( item ) ] );
|
|
355
352
|
|
|
356
|
-
const
|
|
357
|
-
( item
|
|
358
|
-
item ? `${ baseId }-${ getItemId( item ) }` : undefined,
|
|
353
|
+
const generateCompositeItemIdPrefix = useCallback(
|
|
354
|
+
( item: Item ) => `${ baseId }-${ getItemId( item ) }`,
|
|
359
355
|
[ baseId, getItemId ]
|
|
360
356
|
);
|
|
361
357
|
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
358
|
+
const isActiveCompositeItem = useCallback(
|
|
359
|
+
( item: Item, idToCheck: string ) => {
|
|
360
|
+
// All composite items use the same prefix in their IDs.
|
|
361
|
+
return idToCheck.startsWith(
|
|
362
|
+
generateCompositeItemIdPrefix( item )
|
|
363
|
+
);
|
|
364
|
+
},
|
|
365
|
+
[ generateCompositeItemIdPrefix ]
|
|
366
|
+
);
|
|
365
367
|
|
|
366
|
-
//
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
368
|
+
// Controlled state for the active composite item.
|
|
369
|
+
const [ activeCompositeId, setActiveCompositeId ] = useState<
|
|
370
|
+
string | null | undefined
|
|
371
|
+
>( undefined );
|
|
372
|
+
|
|
373
|
+
// Update the active composite item when the selected item changes.
|
|
374
|
+
useEffect( () => {
|
|
375
|
+
if ( selectedItem ) {
|
|
376
|
+
setActiveCompositeId(
|
|
377
|
+
generateItemWrapperCompositeId(
|
|
378
|
+
generateCompositeItemIdPrefix( selectedItem )
|
|
379
|
+
)
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}, [ selectedItem, generateCompositeItemIdPrefix ] );
|
|
383
|
+
|
|
384
|
+
const activeItemIndex = data.findIndex( ( item ) =>
|
|
385
|
+
isActiveCompositeItem( item, activeCompositeId ?? '' )
|
|
373
386
|
);
|
|
387
|
+
const previousActiveItemIndex = usePrevious( activeItemIndex );
|
|
388
|
+
const isActiveIdInList = activeItemIndex !== -1;
|
|
389
|
+
|
|
390
|
+
const selectCompositeItem = useCallback(
|
|
391
|
+
(
|
|
392
|
+
targetIndex: number,
|
|
393
|
+
// Allows invokers to specify a custom function to generate the
|
|
394
|
+
// target composite item ID
|
|
395
|
+
generateCompositeId: ( idPrefix: string ) => string
|
|
396
|
+
) => {
|
|
397
|
+
// Clamping between 0 and data.length - 1 to avoid out of bounds.
|
|
398
|
+
const clampedIndex = Math.min(
|
|
399
|
+
data.length - 1,
|
|
400
|
+
Math.max( 0, targetIndex )
|
|
401
|
+
);
|
|
402
|
+
const itemIdPrefix = generateCompositeItemIdPrefix(
|
|
403
|
+
data[ clampedIndex ]
|
|
404
|
+
);
|
|
405
|
+
const targetCompositeItemId = generateCompositeId( itemIdPrefix );
|
|
406
|
+
|
|
407
|
+
setActiveCompositeId( targetCompositeItemId );
|
|
408
|
+
document.getElementById( targetCompositeItemId )?.focus();
|
|
409
|
+
},
|
|
410
|
+
[ data, generateCompositeItemIdPrefix ]
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
// Select a new active composite item when the current active item
|
|
414
|
+
// is removed from the list.
|
|
374
415
|
useEffect( () => {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
416
|
+
const wasActiveIdInList =
|
|
417
|
+
previousActiveItemIndex !== undefined &&
|
|
418
|
+
previousActiveItemIndex !== -1;
|
|
419
|
+
if ( ! isActiveIdInList && wasActiveIdInList ) {
|
|
420
|
+
// By picking `previousActiveItemIndex` as the next item index, we are
|
|
421
|
+
// basically picking the item that would have been after the deleted one.
|
|
422
|
+
// If the previously active (and removed) item was the last of the list,
|
|
423
|
+
// we will select the item before it — which is the new last item.
|
|
424
|
+
selectCompositeItem(
|
|
425
|
+
previousActiveItemIndex,
|
|
426
|
+
generateItemWrapperCompositeId
|
|
427
|
+
);
|
|
382
428
|
}
|
|
383
|
-
}, [ isActiveIdInList ] );
|
|
429
|
+
}, [ isActiveIdInList, selectCompositeItem, previousActiveItemIndex ] );
|
|
430
|
+
|
|
431
|
+
// Prevent the default behavior (open dropdown menu) and instead select the
|
|
432
|
+
// dropdown menu trigger on the previous/next row.
|
|
433
|
+
// https://github.com/ariakit/ariakit/issues/3768
|
|
434
|
+
const onDropdownTriggerKeyDown = useCallback(
|
|
435
|
+
( event: React.KeyboardEvent< HTMLButtonElement > ) => {
|
|
436
|
+
if ( event.key === 'ArrowDown' ) {
|
|
437
|
+
// Select the dropdown menu trigger item in the next row.
|
|
438
|
+
event.preventDefault();
|
|
439
|
+
selectCompositeItem(
|
|
440
|
+
activeItemIndex + 1,
|
|
441
|
+
generateDropdownTriggerCompositeId
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
if ( event.key === 'ArrowUp' ) {
|
|
445
|
+
// Select the dropdown menu trigger item in the previous row.
|
|
446
|
+
event.preventDefault();
|
|
447
|
+
selectCompositeItem(
|
|
448
|
+
activeItemIndex - 1,
|
|
449
|
+
generateDropdownTriggerCompositeId
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
[ selectCompositeItem, activeItemIndex ]
|
|
454
|
+
);
|
|
384
455
|
|
|
385
456
|
const hasData = data?.length;
|
|
386
457
|
if ( ! hasData ) {
|
|
@@ -404,22 +475,23 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
404
475
|
render={ <ul /> }
|
|
405
476
|
className="dataviews-view-list"
|
|
406
477
|
role="grid"
|
|
407
|
-
|
|
478
|
+
activeId={ activeCompositeId }
|
|
479
|
+
setActiveId={ setActiveCompositeId }
|
|
408
480
|
>
|
|
409
481
|
{ data.map( ( item ) => {
|
|
410
|
-
const id =
|
|
482
|
+
const id = generateCompositeItemIdPrefix( item );
|
|
411
483
|
return (
|
|
412
484
|
<ListItem
|
|
413
485
|
key={ id }
|
|
414
|
-
|
|
486
|
+
idPrefix={ id }
|
|
415
487
|
actions={ actions }
|
|
416
488
|
item={ item }
|
|
417
489
|
isSelected={ item === selectedItem }
|
|
418
490
|
onSelect={ onSelect }
|
|
419
491
|
mediaField={ mediaField }
|
|
420
492
|
primaryField={ primaryField }
|
|
421
|
-
store={ store }
|
|
422
493
|
visibleFields={ visibleFields }
|
|
494
|
+
onDropdownTriggerKeyDown={ onDropdownTriggerKeyDown }
|
|
423
495
|
/>
|
|
424
496
|
);
|
|
425
497
|
} ) }
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
ul.dataviews-view-list {
|
|
2
|
+
list-style-type: none;
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
.dataviews-view-list {
|
|
2
6
|
margin: 0 0 auto;
|
|
3
7
|
|
|
@@ -73,6 +77,7 @@
|
|
|
73
77
|
color: $gray-900;
|
|
74
78
|
}
|
|
75
79
|
&:hover,
|
|
80
|
+
&.is-hovered,
|
|
76
81
|
&:focus-within {
|
|
77
82
|
color: var(--wp-admin-theme-color);
|
|
78
83
|
background-color: #f8f8f8;
|
|
@@ -100,6 +105,7 @@
|
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
.dataviews-view-list__item {
|
|
108
|
+
box-sizing: border-box;
|
|
103
109
|
padding: $grid-unit-20 $grid-unit-30;
|
|
104
110
|
width: 100%;
|
|
105
111
|
scroll-margin: $grid-unit-10 0;
|
|
@@ -108,12 +114,12 @@
|
|
|
108
114
|
&::before {
|
|
109
115
|
position: absolute;
|
|
110
116
|
content: "";
|
|
111
|
-
top:
|
|
117
|
+
top: var(--wp-admin-border-width-focus);
|
|
112
118
|
right: var(--wp-admin-border-width-focus);
|
|
113
119
|
bottom: var(--wp-admin-border-width-focus);
|
|
114
120
|
left: var(--wp-admin-border-width-focus);
|
|
115
121
|
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
|
|
116
|
-
border-radius: $radius-
|
|
122
|
+
border-radius: $radius-small;
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
125
|
.dataviews-view-list__primary-field {
|
|
@@ -151,8 +157,8 @@
|
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
.dataviews-view-list__media-placeholder {
|
|
154
|
-
|
|
155
|
-
height: $grid-unit-
|
|
160
|
+
width: $grid-unit-05 * 13;
|
|
161
|
+
height: $grid-unit-05 * 13;
|
|
156
162
|
background-color: $gray-200;
|
|
157
163
|
}
|
|
158
164
|
|