Skip to content

Commit

Permalink
DataViews: Add density option to table layout
Browse files Browse the repository at this point in the history
  • Loading branch information
ntsekouras committed Nov 20, 2024
1 parent 944e6b8 commit fe0ada1
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 60 deletions.
2 changes: 0 additions & 2 deletions packages/dataviews/src/components/dataviews-context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 > >( {
Expand All @@ -47,7 +46,6 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
getItemId: ( item ) => item.id,
onClickItem: () => {},
isItemClickable: () => false,
density: 0,
} );

export default DataViewsContext;
2 changes: 0 additions & 2 deletions packages/dataviews/src/components/dataviews-layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export default function DataViewsLayout() {
selection,
onChangeSelection,
setOpenedFilter,
density,
onClickItem,
isItemClickable,
} = useContext( DataViewsContext );
Expand All @@ -49,7 +48,6 @@ export default function DataViewsLayout() {
onClickItem={ onClickItem }
isItemClickable={ isItemClickable }
view={ view }
density={ density }
/>
);
}
30 changes: 7 additions & 23 deletions packages/dataviews/src/components/dataviews-view-config/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import { useInstanceId } from '@wordpress/compose';
*/
import {
SORTING_DIRECTIONS,
LAYOUT_GRID,
LAYOUT_TABLE,
sortIcons,
sortLabels,
Expand All @@ -49,7 +48,6 @@ import {
import type { 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 );

Expand Down Expand Up @@ -512,19 +510,15 @@ function SettingsSection( {
);
}

function DataviewsViewConfigDropdown( {
density,
setDensity,
}: {
density: number;
setDensity: React.Dispatch< React.SetStateAction< number > >;
} ) {
function DataviewsViewConfigDropdown() {
const { view } = useContext( DataViewsContext );
const popoverId = useInstanceId(
_DataViewsViewConfig,
'dataviews-view-config-dropdown'
);

const usedLayout = VIEW_LAYOUTS.find(
( layout ) => layout.type === view.type
);
return (
<Dropdown
popoverProps={ {
Expand All @@ -551,11 +545,8 @@ function DataviewsViewConfigDropdown( {
<SortFieldControl />
<SortDirectionControl />
</HStack>
{ view.type === LAYOUT_GRID && (
<DensityPicker
density={ density }
setDensity={ setDensity }
/>
{ !! usedLayout?.viewConfigOptions && (
<usedLayout.viewConfigOptions />
) }
<ItemsPerPageControl />
</SettingsSection>
Expand All @@ -570,21 +561,14 @@ function DataviewsViewConfigDropdown( {
}

function _DataViewsViewConfig( {
density,
setDensity,
defaultLayouts = { list: {}, grid: {}, table: {} },
}: {
density: number;
setDensity: React.Dispatch< React.SetStateAction< number > >;
defaultLayouts?: SupportedLayouts;
} ) {
return (
<>
<ViewTypeMenu defaultLayouts={ defaultLayouts } />
<DataviewsViewConfigDropdown
density={ density }
setDensity={ setDensity }
/>
<DataviewsViewConfigDropdown />
</>
);
}
Expand Down
4 changes: 0 additions & 4 deletions packages/dataviews/src/components/dataviews/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -119,7 +118,6 @@ export default function DataViews< Item >( {
getItemId,
isItemClickable,
onClickItem,
density,
} }
>
<div className="dataviews-wrapper">
Expand Down Expand Up @@ -151,8 +149,6 @@ export default function DataViews< Item >( {
>
<DataViewsViewConfig
defaultLayouts={ defaultLayouts }
density={ density }
setDensity={ setDensity }
/>
{ header }
</HStack>
Expand Down
9 changes: 6 additions & 3 deletions packages/dataviews/src/dataviews-layouts/grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 { useChangeGridColumnsOnViewportChange } from './preview-size-picker';

interface GridItemProps< Item > {
selection: string[];
Expand Down Expand Up @@ -192,8 +193,8 @@ export default function ViewGrid< Item >( {
isItemClickable,
selection,
view,
density,
}: ViewGridProps< Item > ) {
useChangeGridColumnsOnViewportChange();
const mediaField = fields.find(
( field ) => field.id === view.layout?.mediaField
);
Expand Down Expand Up @@ -223,8 +224,10 @@ export default function ViewGrid< Item >( {
{ visibleFields: [], badgeFields: [] }
);
const hasData = !! data?.length;
const gridStyle = density
? { gridTemplateColumns: `repeat(${ density }, minmax(0, 1fr))` }
const gridStyle = view.layout?.gridColumns
? {
gridTemplateColumns: `repeat(${ view.layout.gridColumns }, minmax(0, 1fr))`,
}
: {};
return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
import { RangeControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useViewportMatch } from '@wordpress/compose';
import { useEffect, useMemo } from '@wordpress/element';
import { useEffect, useMemo, useContext } from '@wordpress/element';

/**
* Internal dependencies
*/
import DataViewsContext from '../../components/dataviews-context';
import type { ViewGrid } from '../../types';

const viewportBreaks = {
xhuge: { min: 3, max: 6, default: 5 },
Expand Down Expand Up @@ -39,31 +45,41 @@ function useViewPortBreakpoint() {
return null;
}

export default function DensityPicker( {
density,
setDensity,
}: {
density: number;
setDensity: React.Dispatch< React.SetStateAction< number > >;
} ) {
export function useChangeGridColumnsOnViewportChange() {
const viewport = useViewPortBreakpoint();
const context = useContext( DataViewsContext );
const view = context.view as ViewGrid;
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 gridColumns = view.layout?.gridColumns;
let newGridColumns;
if ( ! viewport || ! gridColumns ) {
return;
}
const breakValues = viewportBreaks[ viewport ];
if ( gridColumns < breakValues.min ) {
newGridColumns = breakValues.min;
}
if ( gridColumns > breakValues.max ) {
newGridColumns = breakValues.max;
}
if ( newGridColumns ) {
context.onChangeView( {
...view,
layout: {
...view.layout,
gridColumns: newGridColumns,
},
} );
}
}, [ viewport, view, context ] );
}

export default function DensityPicker() {
const viewport = useViewPortBreakpoint();
const context = useContext( DataViewsContext );
const view = context.view as ViewGrid;
const breakValues = viewportBreaks[ viewport || 'mobile' ];
const densityToUse = density || breakValues.default;
const densityToUse = view.layout?.gridColumns || breakValues.default;

const marks = useMemo(
() =>
Expand Down Expand Up @@ -94,7 +110,13 @@ export default function DensityPicker( {
max={ breakValues.max }
withInputField={ false }
onChange={ ( value = 0 ) => {
setDensity( breakValues.max + breakValues.min - value );
context.onChangeView( {
...view,
layout: {
...view.layout,
gridColumns: breakValues.max + breakValues.min - value,
},
} );
} }
step={ 1 }
/>
Expand Down
4 changes: 4 additions & 0 deletions packages/dataviews/src/dataviews-layouts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,23 @@ import ViewGrid from './grid';
import ViewList from './list';
import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../constants';
import type { View, Field } from '../types';
import PreviewSizePicker from './grid/preview-size-picker';
import DensityPicker from './table/density-picker';

export const VIEW_LAYOUTS = [
{
type: LAYOUT_TABLE,
label: __( 'Table' ),
component: ViewTable,
icon: blockTable,
viewConfigOptions: DensityPicker,
},
{
type: LAYOUT_GRID,
label: __( 'Grid' ),
component: ViewGrid,
icon: category,
viewConfigOptions: PreviewSizePicker,
},
{
type: LAYOUT_LIST,
Expand Down
57 changes: 57 additions & 0 deletions packages/dataviews/src/dataviews-layouts/table/density-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* WordPress dependencies
*/
import {
__experimentalToggleGroupControl as ToggleGroupControl,
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
} from '@wordpress/components';
import { __, _x } from '@wordpress/i18n';
import { useContext } from '@wordpress/element';

/**
* Internal dependencies
*/
import DataViewsContext from '../../components/dataviews-context';
import type { ViewTable, Density } from '../../types';

export default function DensityPicker() {
const context = useContext( DataViewsContext );
const view = context.view as ViewTable;
return (
<ToggleGroupControl
__nextHasNoMarginBottom
size="__unstable-large"
label={ __( 'Density' ) }
value={ view.layout?.density || 'balanced' }
onChange={ ( value ) => {
context.onChangeView( {
...view,
layout: {
...view.layout,
density: value as Density,
},
} );
} }
isBlock
>
<ToggleGroupControlOption
key="comfortable"
value="comfortable"
label={ _x(
'Comfortable',
'Density option for DataView layout'
) }
/>
<ToggleGroupControlOption
key="balanced"
value="balanced"
label={ _x( 'Balanced', 'Density option for DataView layout' ) }
/>
<ToggleGroupControlOption
key="compact"
value="compact"
label={ _x( 'Compact', 'Density option for DataView layout' ) }
/>
</ToggleGroupControl>
);
}
8 changes: 7 additions & 1 deletion packages/dataviews/src/dataviews-layouts/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,13 @@ function ViewTable< Item >( {
return (
<>
<table
className="dataviews-view-table"
className={ clsx( 'dataviews-view-table', {
[ `has-${ view.layout?.density }-density` ]:
view.layout?.density &&
[ 'compact', 'comfortable' ].includes(
view.layout.density
),
} ) }
aria-busy={ isLoading }
aria-describedby={ tableNoticeId }
>
Expand Down
15 changes: 15 additions & 0 deletions packages/dataviews/src/dataviews-layouts/table/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,21 @@
opacity: 1;
}
}

// Density style overrides.
&.has-compact-density {
td,
th {
padding: $grid-unit-05;
}
}

&.has-comfortable-density {
td,
th {
padding: $grid-unit-20;
}
}
}

/* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
Expand Down
Loading

0 comments on commit fe0ada1

Please sign in to comment.