Skip to content

Commit

Permalink
DataViews: iterate on list view (#56746)
Browse files Browse the repository at this point in the history
Co-authored-by: James Koster <james@jameskoster.co.uk>
  • Loading branch information
oandregal and jameskoster authored Dec 7, 2023
1 parent a66cf2a commit 40c233f
Show file tree
Hide file tree
Showing 11 changed files with 245 additions and 64 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions packages/dataviews/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ npm install @wordpress/dataviews --save
fields={ fields }
actions={ [ trashPostAction ] }
paginationInfo={ { totalItems, totalPages } }
onSelectionChange={ ( items ) => { /* ... */ } }
/>
```

Expand Down Expand Up @@ -75,8 +76,8 @@ Example:
- `value`: the actual value selected by the user.
- `hiddenFields`: the `id` of the fields that are hidden in the UI.
- `layout`: config that is specific to a particular layout type.
- `mediaField`: used by the `grid` layout. The `id` of the field to be used for rendering each card's media.
- `primaryField`: used by the `grid` layout. The `id` of the field to be used for rendering each card's title.
- `mediaField`: used by the `grid` and `list` layouts. The `id` of the field to be used for rendering each card's media.
- `primaryField`: used by the `grid` and `list` layouts. The `id` of the field to be highlighted in each card/list item.

### View <=> data

Expand Down
1 change: 1 addition & 0 deletions packages/dataviews/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@wordpress/element": "file:../element",
"@wordpress/i18n": "file:../i18n",
"@wordpress/icons": "file:../icons",
"@wordpress/keycodes": "file:../keycodes",
"@wordpress/private-apis": "file:../private-apis",
"classnames": "^2.3.1",
"remove-accents": "^0.5.0"
Expand Down
20 changes: 8 additions & 12 deletions packages/dataviews/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { blockTable, category, drawerLeft } from '@wordpress/icons';
import { __, isRTL } from '@wordpress/i18n';
import {
blockTable,
category,
formatListBullets,
formatListBulletsRTL,
} from '@wordpress/icons';

/**
* Internal dependencies
Expand All @@ -29,26 +34,17 @@ export const VIEW_LAYOUTS = [
label: __( 'Table' ),
component: ViewTable,
icon: blockTable,
supports: {
preview: false,
},
},
{
type: LAYOUT_GRID,
label: __( 'Grid' ),
component: ViewGrid,
icon: category,
supports: {
preview: false,
},
},
{
type: LAYOUT_LIST,
label: __( 'List' ),
component: ViewList,
icon: drawerLeft,
supports: {
preview: true,
},
icon: isRTL() ? formatListBulletsRTL : formatListBullets,
},
];
12 changes: 11 additions & 1 deletion packages/dataviews/src/dataviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
__experimentalVStack as VStack,
__experimentalHStack as HStack,
} from '@wordpress/components';
import { useMemo } from '@wordpress/element';
import { useMemo, useState } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -28,7 +28,15 @@ export default function DataViews( {
isLoading = false,
paginationInfo,
supportedLayouts,
onSelectionChange,
} ) {
const [ selection, setSelection ] = useState( [] );

const onSetSelection = ( items ) => {
setSelection( items.map( ( item ) => item.id ) );
onSelectionChange( items );
};

const ViewComponent = VIEW_LAYOUTS.find(
( v ) => v.type === view.type
).component;
Expand Down Expand Up @@ -72,6 +80,8 @@ export default function DataViews( {
data={ data }
getItemId={ getItemId }
isLoading={ isLoading }
onSelectionChange={ onSetSelection }
selection={ selection }
/>
<Pagination
view={ view }
Expand Down
80 changes: 80 additions & 0 deletions packages/dataviews/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,86 @@
}
}

.dataviews-list-view {
li {
border-bottom: $border-width solid $gray-100;
margin: 0;
&:last-child {
border-bottom: 0;
}
}

.dataviews-list-view__item {
padding: $grid-unit-15 $grid-unit-40;
cursor: default;
&:focus,
&:hover {
background-color: lighten($gray-100, 3%);
}
&:focus {
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}
h3 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}

.dataviews-list-view__item-selected,
.dataviews-list-view__item-selected:hover {
background-color: $gray-100;

&:focus {
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}
}

.dataviews-list-view__media-wrapper {
min-width: $grid-unit-40;
height: $grid-unit-40;
border-radius: $grid-unit-05;
overflow: hidden;
position: relative;

&::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: inset 0 0 0 $border-width rgba(0, 0, 0, 0.1);
border-radius: $grid-unit-05;
}
}

.edit-site-page-pages__featured-image,
.dataviews-list-view__media-placeholder {
min-width: $grid-unit-40;
height: $grid-unit-40;
}

.dataviews-list-view__media-placeholder {
background-color: $gray-200;
}

.dataviews-list-view__fields {
color: $gray-700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

.dataviews-list-view__field {
margin-right: $grid-unit-15;

&:last-child {
margin-right: 0;
}
}
}
}

.dataviews-action-modal {
z-index: z-index(".dataviews-action-modal");
}
7 changes: 3 additions & 4 deletions packages/dataviews/src/view-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ export default function ViewGrid( { data, fields, view, actions, getItemId } ) {
className="dataviews-view-grid__card"
>
<div className="dataviews-view-grid__media">
{ mediaField?.render( { item, view } ) }
{ mediaField?.render( { item } ) }
</div>
<HStack
className="dataviews-view-grid__primary-field"
justify="space-between"
>
<FlexBlock>
{ primaryField?.render( { item, view } ) }
{ primaryField?.render( { item } ) }
</FlexBlock>
<ItemActions
item={ item }
Expand All @@ -65,7 +65,6 @@ export default function ViewGrid( { data, fields, view, actions, getItemId } ) {
{ visibleFields.map( ( field ) => {
const renderedValue = field.render( {
item,
view,
} );
if ( ! renderedValue ) {
return null;
Expand All @@ -80,7 +79,7 @@ export default function ViewGrid( { data, fields, view, actions, getItemId } ) {
{ field.header }
</div>
<div className="dataviews-view-grid__field-value">
{ field.render( { item, view } ) }
{ field.render( { item } ) }
</div>
</VStack>
);
Expand Down
98 changes: 93 additions & 5 deletions packages/dataviews/src/view-list.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,97 @@
/**
* Internal dependencies
* External dependencies
*/
import ViewTable from './view-table';
import classNames from 'classnames';

export default function ViewList( props ) {
// To do: change to email-like preview list.
return <ViewTable { ...props } />;
/**
* WordPress dependencies
*/
import { useAsyncList } from '@wordpress/compose';
import {
__experimentalHStack as HStack,
__experimentalVStack as VStack,
} from '@wordpress/components';
import { ENTER, SPACE } from '@wordpress/keycodes';

export default function ViewList( {
view,
fields,
data,
getItemId,
onSelectionChange,
selection,
} ) {
const shownData = useAsyncList( data, { step: 3 } );
const mediaField = fields.find(
( field ) => field.id === view.layout.mediaField
);
const primaryField = fields.find(
( field ) => field.id === view.layout.primaryField
);
const visibleFields = fields.filter(
( field ) =>
! view.hiddenFields.includes( field.id ) &&
! [ view.layout.primaryField, view.layout.mediaField ].includes(
field.id
)
);

const onEnter = ( item ) => ( event ) => {
const { keyCode } = event;
if ( [ ENTER, SPACE ].includes( keyCode ) ) {
onSelectionChange( [ item ] );
}
};

return (
<ul className="dataviews-list-view">
{ shownData.map( ( item, index ) => {
return (
<li key={ getItemId?.( item ) || index }>
<div
role="button"
tabIndex={ 0 }
aria-pressed={ selection.includes( item.id ) }
onKeyDown={ onEnter( item ) }
className={ classNames(
'dataviews-list-view__item',
{
'dataviews-list-view__item-selected':
selection.includes( item.id ),
}
) }
onClick={ () => onSelectionChange( [ item ] ) }
>
<HStack spacing={ 3 }>
<div className="dataviews-list-view__media-wrapper">
{ mediaField?.render( { item } ) || (
<div className="dataviews-list-view__media-placeholder"></div>
) }
</div>
<HStack>
<VStack spacing={ 1 }>
{ primaryField?.render( { item } ) }
<div className="dataviews-list-view__fields">
{ visibleFields.map( ( field ) => {
return (
<span
key={ field.id }
className="dataviews-list-view__field"
>
{ field.render( {
item,
} ) }
</span>
);
} ) }
</div>
</VStack>
</HStack>
</HStack>
</div>
</li>
);
} ) }
</ul>
);
}
3 changes: 1 addition & 2 deletions packages/dataviews/src/view-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,7 @@ function ViewTable( {
const columns = useMemo( () => {
const _columns = fields.map( ( field ) => {
const { render, getValue, ...column } = field;
column.cell = ( props ) =>
render( { item: props.row.original, view } );
column.cell = ( props ) => render( { item: props.row.original } );
if ( getValue ) {
column.accessorFn = ( item ) => getValue( { item } );
}
Expand Down
Loading

1 comment on commit 40c233f

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 40c233f.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7126053932
📝 Reported issues:

Please sign in to comment.