diff --git a/packages/dataviews/src/stories/fixtures.js b/packages/dataviews/src/stories/fixtures.js new file mode 100644 index 0000000000000..6b9073e2cc78d --- /dev/null +++ b/packages/dataviews/src/stories/fixtures.js @@ -0,0 +1,126 @@ +/** + * WordPress dependencies + */ +import { trash } from '@wordpress/icons'; +import { + Button, + __experimentalText as Text, + __experimentalHStack as HStack, + __experimentalVStack as VStack, +} from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { LAYOUT_TABLE } from '../constants'; + +export const data = [ + { + id: 1, + title: 'Apollo', + description: 'Apollo description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 2, + title: 'Space', + description: 'Space description', + image: 'https://live.staticflickr.com/5678/21911065441_92e2d44708_b.jpg', + }, + { + id: 3, + title: 'NASA', + description: 'NASA photo', + image: 'https://live.staticflickr.com/742/21712365770_8f70a2c91e_b.jpg', + }, + { + id: 4, + title: 'Neptune', + description: 'Neptune description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 5, + title: 'Mercury', + description: 'Mercury description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 6, + title: 'Venus', + description: 'Venus description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 7, + title: 'Earth', + description: 'Earth description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 8, + title: 'Mars', + description: 'Mars description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 9, + title: 'Jupiter', + description: 'Jupiter description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 10, + title: 'Saturn', + description: 'Saturn description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, + { + id: 11, + title: 'Uranus', + description: 'Uranus description', + image: 'https://live.staticflickr.com/5725/21726228300_51333bd62c_b.jpg', + }, +]; + +export const DEFAULT_VIEW = { + type: LAYOUT_TABLE, + search: '', + page: 1, + perPage: 10, + hiddenFields: [ 'image' ], + layout: {}, + filters: [], +}; + +export const actions = [ + { + id: 'delete', + label: 'Delete item', + isPrimary: true, + icon: trash, + hideModalHeader: true, + RenderModal: ( { item, closeModal } ) => { + return ( + + + { `Are you sure you want to delete "${ item.title }"?` } + + + + + + + ); + }, + }, + { + id: 'secondary', + label: 'Secondary action', + callback() {}, + }, +]; diff --git a/packages/dataviews/src/stories/index.story.js b/packages/dataviews/src/stories/index.story.js new file mode 100644 index 0000000000000..e0bea0c92c2b2 --- /dev/null +++ b/packages/dataviews/src/stories/index.story.js @@ -0,0 +1,137 @@ +/** + * WordPress dependencies + */ +import { useState, useMemo, useCallback } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { DataViews, LAYOUT_GRID, LAYOUT_TABLE } from '../index'; + +import { DEFAULT_VIEW, actions, data } from './fixtures'; + +const meta = { + title: 'DataViews (Experimental)/DataViews', + component: DataViews, +}; +export default meta; + +const defaultConfigPerViewType = { + [ LAYOUT_TABLE ]: {}, + [ LAYOUT_GRID ]: { + mediaField: 'image', + primaryField: 'title', + }, +}; + +function normalizeSearchInput( input = '' ) { + return input.trim().toLowerCase(); +} + +const fields = [ + { + header: 'Image', + id: 'image', + render: ( { item } ) => { + return ( + + ); + }, + width: 50, + enableSorting: false, + }, + { + header: 'Title', + id: 'title', + getValue: ( { item } ) => item.title, + maxWidth: 400, + enableHiding: false, + }, + { + header: 'Description', + id: 'description', + getValue: ( { item } ) => item.description, + maxWidth: 200, + enableSorting: false, + }, +]; + +export const Default = ( props ) => { + const [ view, setView ] = useState( DEFAULT_VIEW ); + const { shownData, paginationInfo } = useMemo( () => { + let filteredData = [ ...data ]; + // Handle global search. + if ( view.search ) { + const normalizedSearch = normalizeSearchInput( view.search ); + filteredData = filteredData.filter( ( item ) => { + return [ + normalizeSearchInput( item.title ), + normalizeSearchInput( item.description ), + ].some( ( field ) => field.includes( normalizedSearch ) ); + } ); + } + // Handle sorting. + if ( view.sort ) { + const stringSortingFields = [ 'title' ]; + const fieldId = view.sort.field; + if ( stringSortingFields.includes( fieldId ) ) { + const fieldToSort = fields.find( ( field ) => { + return field.id === fieldId; + } ); + filteredData.sort( ( a, b ) => { + const valueA = fieldToSort.getValue( { item: a } ) ?? ''; + const valueB = fieldToSort.getValue( { item: b } ) ?? ''; + return view.sort.direction === 'asc' + ? valueA.localeCompare( valueB ) + : valueB.localeCompare( valueA ); + } ); + } + } + // Handle pagination. + const start = ( view.page - 1 ) * view.perPage; + const totalItems = filteredData?.length || 0; + filteredData = filteredData?.slice( start, start + view.perPage ); + return { + shownData: filteredData, + paginationInfo: { + totalItems, + totalPages: Math.ceil( totalItems / view.perPage ), + }, + }; + }, [ view ] ); + const onChangeView = useCallback( + ( viewUpdater ) => { + let updatedView = + typeof viewUpdater === 'function' + ? viewUpdater( view ) + : viewUpdater; + if ( updatedView.type !== view.type ) { + updatedView = { + ...updatedView, + layout: { + ...defaultConfigPerViewType[ updatedView.type ], + }, + }; + } + + setView( updatedView ); + }, + [ view, setView ] + ); + return ( + + ); +}; +Default.args = { + actions, + getItemId: ( item ) => item.id, + isLoading: false, + supportedLayouts: [ LAYOUT_TABLE, LAYOUT_GRID ], +}; diff --git a/packages/dataviews/src/style.scss b/packages/dataviews/src/style.scss index b18ddb4075c72..5dd89f4c27970 100644 --- a/packages/dataviews/src/style.scss +++ b/packages/dataviews/src/style.scss @@ -3,6 +3,7 @@ height: calc(100% - #{$grid-unit-40} * 2); overflow: auto; padding: $grid-unit-40 $grid-unit-40 0; + box-sizing: border-box; > div { min-height: 100%; @@ -100,7 +101,7 @@ } } - .dataviews-view-grid__title { + .dataviews-view-grid__primary-field { min-height: $grid-unit-30; a { diff --git a/packages/dataviews/src/view-grid.js b/packages/dataviews/src/view-grid.js index 8a39bdd8353d1..89dd7d393430d 100644 --- a/packages/dataviews/src/view-grid.js +++ b/packages/dataviews/src/view-grid.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { + FlexBlock, __experimentalGrid as Grid, __experimentalHStack as HStack, __experimentalVStack as VStack, @@ -45,10 +46,12 @@ export default function ViewGrid( { data, fields, view, actions, getItemId } ) { { mediaField?.render( { item, view } ) } - { primaryField?.render( { item, view } ) } + + { primaryField?.render( { item, view } ) } +