From 010cf1afa2f55d4e82b7b3a77d41a39522abfe01 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Mon, 25 Nov 2024 14:43:23 +0200 Subject: [PATCH] DataViews: Add density option to `table` layout (#67170) Unlinked contributors: annchichi. Co-authored-by: ntsekouras Co-authored-by: jameskoster Co-authored-by: rogermattic Co-authored-by: oandregal Co-authored-by: youknowriad Co-authored-by: mtias Co-authored-by: mcsf --- .../src/components/dataviews-context/index.ts | 2 - .../src/components/dataviews-layout/index.tsx | 2 - .../dataviews-view-config/index.tsx | 30 ++------- .../src/components/dataviews/index.tsx | 4 -- .../src/dataviews-layouts/grid/index.tsx | 10 ++- ...ity-picker.tsx => preview-size-picker.tsx} | 65 +++++++++++-------- .../dataviews/src/dataviews-layouts/index.ts | 4 ++ .../table/density-picker.tsx | 57 ++++++++++++++++ .../src/dataviews-layouts/table/index.tsx | 8 ++- .../src/dataviews-layouts/table/style.scss | 32 +++++++++ packages/dataviews/src/types.ts | 13 +++- .../src/components/page-templates/style.scss | 1 + .../src/fields/featured-image/style.scss | 7 +- 13 files changed, 168 insertions(+), 67 deletions(-) rename packages/dataviews/src/dataviews-layouts/grid/{density-picker.tsx => preview-size-picker.tsx} (56%) create mode 100644 packages/dataviews/src/dataviews-layouts/table/density-picker.tsx diff --git a/packages/dataviews/src/components/dataviews-context/index.ts b/packages/dataviews/src/components/dataviews-context/index.ts index 87acade73bc819..19f6b4178b7b55 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 4ef0125b1f64b5..ebc251eae36a7a 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 c8b26c51275891..f13670f27cdab7 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, @@ -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 ); @@ -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 activeLayout = VIEW_LAYOUTS.find( + ( layout ) => layout.type === view.type + ); return ( - { view.type === LAYOUT_GRID && ( - + { !! activeLayout?.viewConfigOptions && ( + ) } @@ -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 ( <> - + ); } diff --git a/packages/dataviews/src/components/dataviews/index.tsx b/packages/dataviews/src/components/dataviews/index.tsx index 3e8224e61bc5d5..ee6073f40bf3d8 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/index.tsx b/packages/dataviews/src/dataviews-layouts/grid/index.tsx index e218172b7900aa..2a09fb68efab82 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 { useUpdatedPreviewSizeOnViewportChange } from './preview-size-picker'; 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,8 +223,12 @@ export default function ViewGrid< Item >( { { visibleFields: [], badgeFields: [] } ); const hasData = !! data?.length; - const gridStyle = density - ? { gridTemplateColumns: `repeat(${ density }, minmax(0, 1fr))` } + const updatedPreviewSize = useUpdatedPreviewSizeOnViewportChange(); + const usedPreviewSize = updatedPreviewSize || view.layout?.previewSize; + const gridStyle = usedPreviewSize + ? { + gridTemplateColumns: `repeat(${ usedPreviewSize }, minmax(0, 1fr))`, + } : {}; return ( <> diff --git a/packages/dataviews/src/dataviews-layouts/grid/density-picker.tsx b/packages/dataviews/src/dataviews-layouts/grid/preview-size-picker.tsx similarity index 56% rename from packages/dataviews/src/dataviews-layouts/grid/density-picker.tsx rename to packages/dataviews/src/dataviews-layouts/grid/preview-size-picker.tsx index 34ddf6c3fe52f3..b48c6422bd6b37 100644 --- a/packages/dataviews/src/dataviews-layouts/grid/density-picker.tsx +++ b/packages/dataviews/src/dataviews-layouts/grid/preview-size-picker.tsx @@ -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 { 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 }, @@ -39,31 +45,32 @@ function useViewPortBreakpoint() { return null; } -export default function DensityPicker( { - density, - setDensity, -}: { - density: number; - setDensity: React.Dispatch< React.SetStateAction< number > >; -} ) { +export function useUpdatedPreviewSizeOnViewportChange() { + const viewport = useViewPortBreakpoint(); + const view = useContext( DataViewsContext ).view as ViewGrid; + return useMemo( () => { + const previewSize = view.layout?.previewSize; + let newPreviewSize; + if ( ! viewport || ! previewSize ) { + return; + } + const breakValues = viewportBreaks[ viewport ]; + if ( previewSize < breakValues.min ) { + newPreviewSize = breakValues.min; + } + if ( previewSize > breakValues.max ) { + newPreviewSize = breakValues.max; + } + return newPreviewSize; + }, [ viewport, view ] ); +} + +export default function PreviewSizePicker() { 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 context = useContext( DataViewsContext ); + const view = context.view as ViewGrid; const breakValues = viewportBreaks[ viewport || 'mobile' ]; - const densityToUse = density || breakValues.default; + const previewSizeToUse = view.layout?.previewSize || breakValues.default; const marks = useMemo( () => @@ -88,13 +95,19 @@ export default function DensityPicker( { __next40pxDefaultSize showTooltip={ false } label={ __( 'Preview size' ) } - value={ breakValues.max + breakValues.min - densityToUse } + value={ breakValues.max + breakValues.min - previewSizeToUse } marks={ marks } min={ breakValues.min } max={ breakValues.max } withInputField={ false } onChange={ ( value = 0 ) => { - setDensity( breakValues.max + breakValues.min - value ); + context.onChangeView( { + ...view, + layout: { + ...view.layout, + previewSize: breakValues.max + breakValues.min - value, + }, + } ); } } step={ 1 } /> diff --git a/packages/dataviews/src/dataviews-layouts/index.ts b/packages/dataviews/src/dataviews-layouts/index.ts index eece17d0f4f10c..7abdd1eb459328 100644 --- a/packages/dataviews/src/dataviews-layouts/index.ts +++ b/packages/dataviews/src/dataviews-layouts/index.ts @@ -17,6 +17,8 @@ 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 = [ { @@ -24,12 +26,14 @@ export const VIEW_LAYOUTS = [ label: __( 'Table' ), component: ViewTable, icon: blockTable, + viewConfigOptions: DensityPicker, }, { type: LAYOUT_GRID, label: __( 'Grid' ), component: ViewGrid, icon: category, + viewConfigOptions: PreviewSizePicker, }, { type: LAYOUT_LIST, diff --git a/packages/dataviews/src/dataviews-layouts/table/density-picker.tsx b/packages/dataviews/src/dataviews-layouts/table/density-picker.tsx new file mode 100644 index 00000000000000..6d3d31aeb7345e --- /dev/null +++ b/packages/dataviews/src/dataviews-layouts/table/density-picker.tsx @@ -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 ( + { + context.onChangeView( { + ...view, + layout: { + ...view.layout, + density: value as Density, + }, + } ); + } } + isBlock + > + + + + + ); +} diff --git a/packages/dataviews/src/dataviews-layouts/table/index.tsx b/packages/dataviews/src/dataviews-layouts/table/index.tsx index db76d24b53bfa3..7f93a4c14a7ddc 100644 --- a/packages/dataviews/src/dataviews-layouts/table/index.tsx +++ b/packages/dataviews/src/dataviews-layouts/table/index.tsx @@ -332,7 +332,13 @@ function ViewTable< Item >( { return ( <> diff --git a/packages/dataviews/src/dataviews-layouts/table/style.scss b/packages/dataviews/src/dataviews-layouts/table/style.scss index ea2c614e4339df..3bbb045c73a9d9 100644 --- a/packages/dataviews/src/dataviews-layouts/table/style.scss +++ b/packages/dataviews/src/dataviews-layouts/table/style.scss @@ -169,6 +169,38 @@ opacity: 1; } } + + // Density style overrides. + &.has-compact-density { + thead { + th { + &:has(.dataviews-view-table-header-button):not(:first-child) { + padding-left: 0; + } + } + } + td, + th { + padding: $grid-unit-05 $grid-unit-10; + } + } + + &.has-comfortable-density { + td, + th { + padding: $grid-unit-20 $grid-unit-15; + } + } + + &.has-compact-density, + &.has-comfortable-density { + td, + th { + &.dataviews-view-table__checkbox-column { + padding-right: 0; + } + } + } } /* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */ diff --git a/packages/dataviews/src/types.ts b/packages/dataviews/src/types.ts index 8c4276f2541ecc..861dc53404f914 100644 --- a/packages/dataviews/src/types.ts +++ b/packages/dataviews/src/types.ts @@ -329,6 +329,8 @@ export interface ColumnStyle { minWidth?: string | number; } +export type Density = 'compact' | 'balanced' | 'comfortable'; + export interface ViewTable extends ViewBase { type: 'table'; @@ -347,6 +349,11 @@ export interface ViewTable extends ViewBase { * The styles for the columns. */ styles?: Record< string, ColumnStyle >; + + /** + * The density of the view. + */ + density?: Density; }; } @@ -389,6 +396,11 @@ export interface ViewGrid extends ViewBase { * The fields to use as badge fields. */ badgeFields?: string[]; + + /** + * The preview size of the grid. + */ + previewSize?: number; }; } @@ -501,7 +513,6 @@ export interface ViewBaseProps< Item > { onClickItem: ( item: Item ) => void; isItemClickable: ( item: Item ) => boolean; view: View; - density: number; } export interface ViewTableProps< Item > extends ViewBaseProps< Item > { diff --git a/packages/edit-site/src/components/page-templates/style.scss b/packages/edit-site/src/components/page-templates/style.scss index 6a753921f6f40a..4432cf6bec4923 100644 --- a/packages/edit-site/src/components/page-templates/style.scss +++ b/packages/edit-site/src/components/page-templates/style.scss @@ -60,6 +60,7 @@ .dataviews-view-table & { margin-bottom: $grid-unit-10; + display: block; } } diff --git a/packages/fields/src/fields/featured-image/style.scss b/packages/fields/src/fields/featured-image/style.scss index 46d37960199ead..918f69172f3023 100644 --- a/packages/fields/src/fields/featured-image/style.scss +++ b/packages/fields/src/fields/featured-image/style.scss @@ -83,13 +83,10 @@ fieldset.fields-controls__featured-image { } .dataviews-view-table__cell-content-wrapper { - .fields-controls__featured-image-image { - width: 32px; - height: 32px; - } - + .fields-controls__featured-image-image, .fields-controls__featured-image-placeholder { width: 32px; height: 32px; + display: block; } }