Skip to content

Commit

Permalink
Update: Grid layout: Allow users to adjust grid density (#63367)
Browse files Browse the repository at this point in the history
Co-authored-by: jorgefilipecosta <[email protected]>
Co-authored-by: jameskoster <[email protected]>
Co-authored-by: stokesman <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: colorful-tones <[email protected]>
  • Loading branch information
6 people authored Jul 22, 2024
1 parent 8df860e commit e78e4e3
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 13 deletions.
4 changes: 3 additions & 1 deletion packages/compose/src/hooks/use-viewport-match/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { createContext, useContext } from '@wordpress/element';
import useMediaQuery from '../use-media-query';

/**
* @typedef {"huge" | "wide" | "large" | "medium" | "small" | "mobile"} WPBreakpoint
* @typedef {"xhuge" | "huge" | "wide" | "xlarge" | "large" | "medium" | "small" | "mobile"} WPBreakpoint
*/

/**
Expand All @@ -20,8 +20,10 @@ import useMediaQuery from '../use-media-query';
* @type {Record<WPBreakpoint, number>}
*/
const BREAKPOINTS = {
xhuge: 1920,
huge: 1440,
wide: 1280,
xlarge: 1080,
large: 960,
medium: 782,
small: 600,
Expand Down
2 changes: 2 additions & 0 deletions packages/dataviews/src/components/dataviews-context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type DataViewsContextType< Item > = {
openedFilter: string | null;
setOpenedFilter: ( openedFilter: string | null ) => void;
getItemId: ( item: Item ) => string;
density: number;
};

const DataViewsContext = createContext< DataViewsContextType< any > >( {
Expand All @@ -42,6 +43,7 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
setOpenedFilter: () => {},
openedFilter: null,
getItemId: ( item ) => item.id,
density: 0,
} );

export default DataViewsContext;
2 changes: 2 additions & 0 deletions packages/dataviews/src/components/dataviews-layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default function DataViewsLayout() {
selection,
onChangeSelection,
setOpenedFilter,
density,
} = useContext( DataViewsContext );

const ViewComponent = VIEW_LAYOUTS.find( ( v ) => v.type === view.type )
Expand All @@ -44,6 +45,7 @@ export default function DataViewsLayout() {
selection={ selection }
setOpenedFilter={ setOpenedFilter }
view={ view }
density={ density }
/>
);
}
10 changes: 10 additions & 0 deletions packages/dataviews/src/components/dataviews/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import DataViewsViewConfig from '../dataviews-view-config';
import { normalizeFields } from '../../normalize-fields';
import type { Action, Field, View, SupportedLayouts } from '../../types';
import type { SelectionOrUpdater } from '../../private-types';
import DensityPicker from '../../layouts/grid/density-picker';
import { LAYOUT_GRID } from '../../constants';

type ItemWithId = { id: string };

Expand Down Expand Up @@ -59,6 +61,7 @@ export default function DataViews< Item >( {
onChangeSelection,
}: DataViewsProps< Item > ) {
const [ selectionState, setSelectionState ] = useState< string[] >( [] );
const [ density, setDensity ] = useState< number >( 0 );
const isUncontrolled =
selectionProperty === undefined || onChangeSelection === undefined;
const selection = isUncontrolled ? selectionState : selectionProperty;
Expand Down Expand Up @@ -95,6 +98,7 @@ export default function DataViews< Item >( {
openedFilter,
setOpenedFilter,
getItemId,
density,
} }
>
<div className="dataviews-wrapper">
Expand All @@ -111,6 +115,12 @@ export default function DataViews< Item >( {
{ search && <DataViewsSearch label={ searchLabel } /> }
<DataViewsFilters />
</HStack>
{ view.type === LAYOUT_GRID && (
<DensityPicker
density={ density }
setDensity={ setDensity }
/>
) }
<DataViewsBulkActions />
<DataViewsViewConfig defaultLayouts={ defaultLayouts } />
</HStack>
Expand Down
136 changes: 136 additions & 0 deletions packages/dataviews/src/layouts/grid/density-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* WordPress dependencies
*/
import { RangeControl, Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useViewportMatch } from '@wordpress/compose';
import { plus, lineSolid } from '@wordpress/icons';
import { useEffect } 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;
}

// Value is number from 0 to 100 representing how big an item is in the grid
// 100 being the biggest and 0 being the smallest.
// The size is relative to the viewport size, if one a given viewport the
// number of allowed items in a grid is 3 to 6 a 0 ( the smallest ) will mean that the grid will
// have 6 items in a row, a 100 ( the biggest ) will mean that the grid will have 3 items in a row.
// A value of 75 will mean that the grid will have 4 items in a row.
function getRangeValue(
density: number,
breakValues: { min: number; max: number; default: number }
) {
const inverseDensity = breakValues.max - density;
const max = breakValues.max - breakValues.min;
return Math.round( ( inverseDensity * 100 ) / max );
}

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 ] );
if ( ! viewport ) {
return null;
}
const breakValues = viewportBreaks[ viewport ];
const densityToUse = density || breakValues.default;
const rangeValue = getRangeValue( densityToUse, breakValues );

const step = 100 / ( breakValues.max - breakValues.min + 1 );
return (
<>
<Button
size="compact"
icon={ lineSolid }
disabled={ rangeValue <= 0 }
accessibleWhenDisabled
label={ __( 'Decrease size' ) }
onClick={ () => {
setDensity( densityToUse + 1 );
} }
/>
<RangeControl
__nextHasNoMarginBottom
showTooltip={ false }
className="dataviews-density-picker__range-control"
label={ __( 'Item size' ) }
hideLabelFromVision
value={ rangeValue }
min={ 0 }
max={ 100 }
withInputField={ false }
onChange={ ( value = 0 ) => {
const inverseValue = 100 - value;
setDensity(
Math.round(
( inverseValue *
( breakValues.max - breakValues.min ) ) /
100 +
breakValues.min
)
);
} }
step={ step }
/>
<Button
size="compact"
icon={ plus }
disabled={ rangeValue >= 100 }
accessibleWhenDisabled
label={ __( 'Increase size' ) }
onClick={ () => {
setDensity( densityToUse - 1 );
} }
/>
</>
);
}
5 changes: 5 additions & 0 deletions packages/dataviews/src/layouts/grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ export default function ViewGrid< Item >( {
onChangeSelection,
selection,
view,
density,
}: ViewGridProps< Item > ) {
const mediaField = fields.find(
( field ) => field.id === view.layout?.mediaField
Expand Down Expand Up @@ -202,6 +203,9 @@ export default function ViewGrid< Item >( {
{ visibleFields: [], badgeFields: [] }
);
const hasData = !! data?.length;
const gridStyle = density
? { gridTemplateColumns: `repeat(${ density }, minmax(0, 1fr))` }
: {};
return (
<>
{ hasData && (
Expand All @@ -210,6 +214,7 @@ export default function ViewGrid< Item >( {
columns={ 2 }
alignment="top"
className="dataviews-view-grid"
style={ gridStyle }
aria-busy={ isLoading }
>
{ data.map( ( item ) => {
Expand Down
36 changes: 24 additions & 12 deletions packages/dataviews/src/layouts/grid/style.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
.dataviews-view-grid {
margin-bottom: auto;
grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
grid-template-rows: max-content;
padding: 0 $grid-unit-60 $grid-unit-30;
transition: padding ease-out 0.1s;
@include reduce-motion("transition");

@include break-mobile() {
grid-template-columns: repeat(2, minmax(0, 1fr)) !important; // Todo: eliminate !important dependency
}

@include break-xlarge() {
grid-template-columns: repeat(3, minmax(0, 1fr)) !important; // Todo: eliminate !important dependency
}

@include break-huge() {
grid-template-columns: repeat(4, minmax(0, 1fr)) !important; // Todo: eliminate !important dependency
}

.dataviews-view-grid__card {
height: 100%;
Expand Down Expand Up @@ -122,6 +110,30 @@
}
}

.dataviews-view-grid.dataviews-view-grid {
grid-template-columns: repeat(1, minmax(0, 1fr));

@include break-mobile() {
grid-template-columns: repeat(2, minmax(0, 1fr));
}

@include break-xlarge() {
grid-template-columns: repeat(3, minmax(0, 1fr));
}

@include break-huge() {
grid-template-columns: repeat(4, minmax(0, 1fr));
}

@include break-xhuge() {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}

.dataviews-density-picker__range-control {
width: 200px;
}

.dataviews-view-grid__field-value:empty,
.dataviews-view-grid__field:empty {
display: none;
Expand Down
1 change: 1 addition & 0 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ export interface ViewBaseProps< Item > {
selection: string[];
setOpenedFilter: ( fieldId: string ) => void;
view: View;
density: number;
}

export interface ViewTableProps< Item > extends ViewBaseProps< Item > {
Expand Down

0 comments on commit e78e4e3

Please sign in to comment.