diff --git a/packages/dataviews/src/components/dataviews-context/index.ts b/packages/dataviews/src/components/dataviews-context/index.ts index 87acade73bc81..19f6b4178b7b5 100644 --- a/packages/dataviews/src/components/dataviews-context/index.ts +++ b/packages/dataviews/src/components/dataviews-context/index.ts @@ -28,7 +28,6 @@ type DataViewsContextType< Item > = { getItemId: ( item: Item ) => string; onClickItem: ( item: Item ) => void; isItemClickable: ( item: Item ) => boolean; - density: number; }; const DataViewsContext = createContext< DataViewsContextType< any > >( { @@ -47,7 +46,6 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( { getItemId: ( item ) => item.id, onClickItem: () => {}, isItemClickable: () => false, - density: 0, } ); export default DataViewsContext; diff --git a/packages/dataviews/src/components/dataviews-layout/index.tsx b/packages/dataviews/src/components/dataviews-layout/index.tsx index 4ef0125b1f64b..ebc251eae36a7 100644 --- a/packages/dataviews/src/components/dataviews-layout/index.tsx +++ b/packages/dataviews/src/components/dataviews-layout/index.tsx @@ -27,7 +27,6 @@ export default function DataViewsLayout() { selection, onChangeSelection, setOpenedFilter, - density, onClickItem, isItemClickable, } = useContext( DataViewsContext ); @@ -49,7 +48,6 @@ export default function DataViewsLayout() { onClickItem={ onClickItem } isItemClickable={ isItemClickable } view={ view } - density={ density } /> ); } diff --git a/packages/dataviews/src/components/dataviews-view-config/index.tsx b/packages/dataviews/src/components/dataviews-view-config/index.tsx index c8b26c5127589..34bd2e2f65673 100644 --- a/packages/dataviews/src/components/dataviews-view-config/index.tsx +++ b/packages/dataviews/src/components/dataviews-view-config/index.tsx @@ -35,7 +35,6 @@ import { useInstanceId } from '@wordpress/compose'; */ import { SORTING_DIRECTIONS, - LAYOUT_GRID, LAYOUT_TABLE, sortIcons, sortLabels, @@ -46,10 +45,9 @@ import { getVisibleFieldIds, getHiddenFieldIds, } from '../../dataviews-layouts'; -import type { SupportedLayouts, View, Field } from '../../types'; +import type { Density, SupportedLayouts, View, Field } from '../../types'; import DataViewsContext from '../dataviews-context'; import { unlock } from '../../lock-unlock'; -import DensityPicker from '../../dataviews-layouts/grid/density-picker'; const { Menu } = unlock( componentsPrivateApis ); @@ -239,6 +237,50 @@ function ItemsPerPageControl() { ); } +function DensityPicker() { + const { view, onChangeView } = useContext( DataViewsContext ); + if ( + ! VIEW_LAYOUTS.find( ( layout ) => layout.type === view.type )?.supports + ?.density + ) { + return null; + } + return ( + { + onChangeView( { + ...view, + density: value as Density, + } ); + } } + isBlock + > + + + + + ); +} + interface FieldItemProps { id: any; label: string; @@ -512,19 +554,11 @@ function SettingsSection( { ); } -function DataviewsViewConfigDropdown( { - density, - setDensity, -}: { - density: number; - setDensity: React.Dispatch< React.SetStateAction< number > >; -} ) { - const { view } = useContext( DataViewsContext ); +function DataviewsViewConfigDropdown() { const popoverId = useInstanceId( _DataViewsViewConfig, 'dataviews-view-config-dropdown' ); - return ( - { view.type === LAYOUT_GRID && ( - - ) } + @@ -570,21 +599,14 @@ function DataviewsViewConfigDropdown( { } function _DataViewsViewConfig( { - density, - setDensity, defaultLayouts = { list: {}, grid: {}, table: {} }, }: { - density: number; - setDensity: React.Dispatch< React.SetStateAction< number > >; defaultLayouts?: SupportedLayouts; } ) { return ( <> - + ); } diff --git a/packages/dataviews/src/components/dataviews/index.tsx b/packages/dataviews/src/components/dataviews/index.tsx index 3e8224e61bc5d..ee6073f40bf3d 100644 --- a/packages/dataviews/src/components/dataviews/index.tsx +++ b/packages/dataviews/src/components/dataviews/index.tsx @@ -75,7 +75,6 @@ export default function DataViews< Item >( { header, }: DataViewsProps< Item > ) { const [ selectionState, setSelectionState ] = useState< string[] >( [] ); - const [ density, setDensity ] = useState< number >( 0 ); const isUncontrolled = selectionProperty === undefined || onChangeSelection === undefined; const selection = isUncontrolled ? selectionState : selectionProperty; @@ -119,7 +118,6 @@ export default function DataViews< Item >( { getItemId, isItemClickable, onClickItem, - density, } } >
@@ -151,8 +149,6 @@ export default function DataViews< Item >( { > { header } diff --git a/packages/dataviews/src/dataviews-layouts/grid/density-picker.tsx b/packages/dataviews/src/dataviews-layouts/grid/density-picker.tsx deleted file mode 100644 index 34ddf6c3fe52f..0000000000000 --- a/packages/dataviews/src/dataviews-layouts/grid/density-picker.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/** - * WordPress dependencies - */ -import { RangeControl } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { useViewportMatch } from '@wordpress/compose'; -import { useEffect, useMemo } from '@wordpress/element'; - -const viewportBreaks = { - xhuge: { min: 3, max: 6, default: 5 }, - huge: { min: 2, max: 4, default: 4 }, - xlarge: { min: 2, max: 3, default: 3 }, - large: { min: 1, max: 2, default: 2 }, - mobile: { min: 1, max: 2, default: 2 }, -}; - -function useViewPortBreakpoint() { - const isXHuge = useViewportMatch( 'xhuge', '>=' ); - const isHuge = useViewportMatch( 'huge', '>=' ); - const isXlarge = useViewportMatch( 'xlarge', '>=' ); - const isLarge = useViewportMatch( 'large', '>=' ); - const isMobile = useViewportMatch( 'mobile', '>=' ); - - if ( isXHuge ) { - return 'xhuge'; - } - if ( isHuge ) { - return 'huge'; - } - if ( isXlarge ) { - return 'xlarge'; - } - if ( isLarge ) { - return 'large'; - } - if ( isMobile ) { - return 'mobile'; - } - return null; -} - -export default function DensityPicker( { - density, - setDensity, -}: { - density: number; - setDensity: React.Dispatch< React.SetStateAction< number > >; -} ) { - const viewport = useViewPortBreakpoint(); - useEffect( () => { - setDensity( ( _density ) => { - if ( ! viewport || ! _density ) { - return 0; - } - const breakValues = viewportBreaks[ viewport ]; - if ( _density < breakValues.min ) { - return breakValues.min; - } - if ( _density > breakValues.max ) { - return breakValues.max; - } - return _density; - } ); - }, [ setDensity, viewport ] ); - const breakValues = viewportBreaks[ viewport || 'mobile' ]; - const densityToUse = density || breakValues.default; - - const marks = useMemo( - () => - Array.from( - { length: breakValues.max - breakValues.min + 1 }, - ( _, i ) => { - return { - value: breakValues.min + i, - }; - } - ), - [ breakValues ] - ); - - if ( ! viewport ) { - return null; - } - - return ( - { - setDensity( breakValues.max + breakValues.min - value ); - } } - step={ 1 } - /> - ); -} diff --git a/packages/dataviews/src/dataviews-layouts/grid/index.tsx b/packages/dataviews/src/dataviews-layouts/grid/index.tsx index e218172b7900a..b1a28694058c9 100644 --- a/packages/dataviews/src/dataviews-layouts/grid/index.tsx +++ b/packages/dataviews/src/dataviews-layouts/grid/index.tsx @@ -25,6 +25,7 @@ import { useHasAPossibleBulkAction } from '../../components/dataviews-bulk-actio import type { Action, NormalizedField, ViewGridProps } from '../../types'; import type { SetSelection } from '../../private-types'; import getClickableItemProps from '../utils/get-clickable-item-props'; +import useGridStyle from './use-grid-style'; interface GridItemProps< Item > { selection: string[]; @@ -192,7 +193,6 @@ export default function ViewGrid< Item >( { isItemClickable, selection, view, - density, }: ViewGridProps< Item > ) { const mediaField = fields.find( ( field ) => field.id === view.layout?.mediaField @@ -223,9 +223,7 @@ export default function ViewGrid< Item >( { { visibleFields: [], badgeFields: [] } ); const hasData = !! data?.length; - const gridStyle = density - ? { gridTemplateColumns: `repeat(${ density }, minmax(0, 1fr))` } - : {}; + const gridStyle = useGridStyle( view ); return ( <> { hasData && ( diff --git a/packages/dataviews/src/dataviews-layouts/grid/style.scss b/packages/dataviews/src/dataviews-layouts/grid/style.scss index f209accc6de15..a428f342bef6e 100644 --- a/packages/dataviews/src/dataviews-layouts/grid/style.scss +++ b/packages/dataviews/src/dataviews-layouts/grid/style.scss @@ -40,7 +40,6 @@ .dataviews-view-grid__media { width: 100%; - min-height: 200px; aspect-ratio: 1/1; background-color: $gray-100; border-radius: $grid-unit-05; diff --git a/packages/dataviews/src/dataviews-layouts/grid/use-grid-style.ts b/packages/dataviews/src/dataviews-layouts/grid/use-grid-style.ts new file mode 100644 index 0000000000000..ea2c0607543b7 --- /dev/null +++ b/packages/dataviews/src/dataviews-layouts/grid/use-grid-style.ts @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { useViewportMatch } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import type { Density, ViewGrid } from '../../types'; + +export default function useGridStyle( view: ViewGrid ) { + const isXHuge = useViewportMatch( 'xhuge' ); + const isHuge = useViewportMatch( 'huge' ); + const isXlarge = useViewportMatch( 'xlarge' ); + const isMedium = useViewportMatch( 'small' ); + // The `balanced` density (default) is handled with css. If another density is selected, + // we query the viewport to determine the number of columns to display per option. + if ( ! [ 'comfortable', 'compact' ].includes( view.density as Density ) ) { + return; + } + + let gridColumns; + if ( isXHuge ) { + gridColumns = { min: 4, max: 6 }; + } else if ( isHuge ) { + gridColumns = { min: 3, max: 5 }; + } else if ( isXlarge ) { + gridColumns = { min: 2, max: 4 }; + } else if ( isMedium ) { + gridColumns = { min: 1, max: 3 }; + } else { + // Default to mobile. + gridColumns = { min: 1, max: 2 }; + } + return { + gridTemplateColumns: `repeat(${ + view.density === 'compact' ? gridColumns.max : gridColumns.min + }, minmax(0, 1fr))`, + }; +} diff --git a/packages/dataviews/src/dataviews-layouts/index.ts b/packages/dataviews/src/dataviews-layouts/index.ts index eece17d0f4f10..4a97baacf833c 100644 --- a/packages/dataviews/src/dataviews-layouts/index.ts +++ b/packages/dataviews/src/dataviews-layouts/index.ts @@ -30,6 +30,7 @@ export const VIEW_LAYOUTS = [ label: __( 'Grid' ), component: ViewGrid, icon: category, + supports: { density: true }, }, { type: LAYOUT_LIST, diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 71990f72d4eec..efdcee9a530b1 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -247,6 +247,8 @@ export interface NormalizedFilter { isPrimary: boolean; } +export type Density = 'compact' | 'balanced' | 'comfortable'; + interface ViewBase { /** * The layout of the view. @@ -292,6 +294,11 @@ interface ViewBase { * The fields to render */ fields?: string[]; + + /** + * The density of the view. + */ + density?: Density; } export interface CombinedField { @@ -501,7 +508,6 @@ export interface ViewBaseProps< Item > { onClickItem: ( item: Item ) => void; isItemClickable: ( item: Item ) => boolean; view: View; - density: number; } export interface ViewTableProps< Item > extends ViewBaseProps< Item > {