Skip to content

Commit

Permalink
DataViews: simplify selection setting (#62846)
Browse files Browse the repository at this point in the history
Co-authored-by: ellatrix <ellatrix@git.wordpress.org>
Co-authored-by: youknowriad <youknowriad@git.wordpress.org>
Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org>
Co-authored-by: sirreal <jonsurrell@git.wordpress.org>
Co-authored-by: jsnajdr <jsnajdr@git.wordpress.org>
Co-authored-by: luisherranz <luisherranz@git.wordpress.org>
Co-authored-by: oandregal <oandregal@git.wordpress.org>
  • Loading branch information
8 people authored Jun 27, 2024
1 parent 0e05f99 commit fe67010
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 113 deletions.
7 changes: 4 additions & 3 deletions packages/dataviews/src/bulk-actions-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { useRegistry } from '@wordpress/data';
import { ActionWithModal } from './item-actions';
import type { Action } from './types';
import type { ActionTriggerProps } from './item-actions';
import type { SetSelection } from './private-types';

interface ActionButtonProps< Item > {
action: Action< Item >;
Expand All @@ -32,14 +33,14 @@ interface ToolbarContentProps< Item > {
selection: string[];
actionsToShow: Action< Item >[];
selectedItems: Item[];
onSelectionChange: ( selection: Item[] ) => void;
onSelectionChange: SetSelection;
}

interface BulkActionsToolbarProps< Item > {
data: Item[];
selection: string[];
actions: Action< Item >[];
onSelectionChange: ( selection: Item[] ) => void;
onSelectionChange: SetSelection;
getItemId: ( item: Item ) => string;
}

Expand Down Expand Up @@ -131,7 +132,7 @@ function renderToolbarContent< Item >(
selectedItems: Item[],
actionInProgress: string | null,
setActionInProgress: ( actionId: string | null ) => void,
onSelectionChange: ( selection: Item[] ) => void
onSelectionChange: SetSelection
) {
return (
<>
Expand Down
9 changes: 7 additions & 2 deletions packages/dataviews/src/bulk-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useRegistry } from '@wordpress/data';
*/
import { unlock } from './lock-unlock';
import type { Action, ActionModal } from './types';
import type { SetSelection } from './private-types';

const {
DropdownMenuV2: DropdownMenu,
Expand Down Expand Up @@ -46,7 +47,7 @@ interface BulkActionsProps< Item > {
data: Item[];
actions: Action< Item >[];
selection: string[];
onSelectionChange: ( selection: Item[] ) => void;
onSelectionChange: SetSelection;
getItemId: ( item: Item ) => string;
}

Expand Down Expand Up @@ -248,7 +249,11 @@ export default function BulkActions< Item >( {
disabled={ areAllSelected }
hideOnClick={ false }
onClick={ () => {
onSelectionChange( selectableItems );
onSelectionChange(
selectableItems.map( ( item ) =>
getItemId( item )
)
);
} }
suffix={ numberSelectableItems }
>
Expand Down
43 changes: 20 additions & 23 deletions packages/dataviews/src/dataviews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { ComponentType } from 'react';
* WordPress dependencies
*/
import { __experimentalHStack as HStack } from '@wordpress/components';
import { useMemo, useState, useCallback } from '@wordpress/element';
import { useMemo, useState } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -22,6 +22,7 @@ import BulkActions from './bulk-actions';
import { normalizeFields } from './normalize-fields';
import BulkActionsToolbar from './bulk-actions-toolbar';
import type { Action, Field, View, ViewBaseProps } from './types';
import type { SetSelection, SelectionOrUpdater } from './private-types';

type ItemWithId = { id: string };

Expand All @@ -40,7 +41,7 @@ type DataViewsProps< Item > = {
};
supportedLayouts: string[];
selection?: string[];
setSelection?: ( selection: string[] ) => void;
setSelection?: SetSelection;
onSelectionChange?: ( items: Item[] ) => void;
} & ( Item extends ItemWithId
? { getItemId?: ( item: Item ) => string }
Expand Down Expand Up @@ -83,26 +84,22 @@ export default function DataViews< Item >( {
onSelectionChange = defaultOnSelectionChange,
}: DataViewsProps< Item > ) {
const [ selectionState, setSelectionState ] = useState< string[] >( [] );
let selection, setSelection;
if (
selectionProperty !== undefined &&
setSelectionProperty !== undefined
) {
selection = selectionProperty;
setSelection = setSelectionProperty;
} else {
selection = selectionState;
setSelection = setSelectionState;
}
const isUncontrolled =
selectionProperty === undefined || setSelectionProperty === undefined;
const selection = isUncontrolled ? selectionState : selectionProperty;
const setSelection = isUncontrolled
? setSelectionState
: setSelectionProperty;
const [ openedFilter, setOpenedFilter ] = useState< string | null >( null );

const onSetSelection = useCallback(
( items: Item[] ) => {
setSelection( items.map( ( item ) => getItemId( item ) ) );
onSelectionChange( items );
},
[ setSelection, getItemId, onSelectionChange ]
);
function setSelectionWithChange( value: SelectionOrUpdater ) {
const newValue =
typeof value === 'function' ? value( selection ) : value;
onSelectionChange(
data.filter( ( item ) => newValue.includes( getItemId( item ) ) )
);
return setSelection( value );
}

const ViewComponent = VIEW_LAYOUTS.find( ( v ) => v.type === view.type )
?.component as ComponentType< ViewBaseProps< Item > >;
Expand Down Expand Up @@ -149,7 +146,7 @@ export default function DataViews< Item >( {
<BulkActions
actions={ actions }
data={ data }
onSelectionChange={ onSetSelection }
onSelectionChange={ setSelectionWithChange }
selection={ _selection }
getItemId={ getItemId }
/>
Expand All @@ -168,7 +165,7 @@ export default function DataViews< Item >( {
getItemId={ getItemId }
isLoading={ isLoading }
onChangeView={ onChangeView }
onSelectionChange={ onSetSelection }
onSelectionChange={ setSelectionWithChange }
selection={ _selection }
setOpenedFilter={ setOpenedFilter }
view={ view }
Expand All @@ -184,7 +181,7 @@ export default function DataViews< Item >( {
data={ data }
actions={ actions }
selection={ _selection }
onSelectionChange={ onSetSelection }
onSelectionChange={ setSelectionWithChange }
getItemId={ getItemId }
/>
) }
Expand Down
2 changes: 2 additions & 0 deletions packages/dataviews/src/private-types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type SelectionOrUpdater = string[] | ( ( prev: string[] ) => string[] );
export type SetSelection = ( selection: SelectionOrUpdater ) => void;
37 changes: 11 additions & 26 deletions packages/dataviews/src/single-selection-checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { CheckboxControl } from '@wordpress/components';
* Internal dependencies
*/
import type { Field } from './types';
import type { SetSelection } from './private-types';

interface SingleSelectionCheckboxProps< Item > {
selection: string[];
onSelectionChange: ( selection: Item[] ) => void;
onSelectionChange: SetSelection;
item: Item;
data: Item[];
getItemId: ( item: Item ) => string;
primaryField?: Field< Item >;
disabled: boolean;
Expand All @@ -23,23 +23,22 @@ export default function SingleSelectionCheckbox< Item >( {
selection,
onSelectionChange,
item,
data,
getItemId,
primaryField,
disabled,
}: SingleSelectionCheckboxProps< Item > ) {
const id = getItemId( item );
const isSelected = ! disabled && selection.includes( id );
const checked = ! disabled && selection.includes( id );
let selectionLabel;
if ( primaryField?.getValue && item ) {
// eslint-disable-next-line @wordpress/valid-sprintf
selectionLabel = sprintf(
/* translators: %s: item title. */
isSelected ? __( 'Deselect item: %s' ) : __( 'Select item: %s' ),
checked ? __( 'Deselect item: %s' ) : __( 'Select item: %s' ),
primaryField.getValue( { item } )
);
} else {
selectionLabel = isSelected
selectionLabel = checked
? __( 'Select a new item' )
: __( 'Deselect item' );
}
Expand All @@ -49,31 +48,17 @@ export default function SingleSelectionCheckbox< Item >( {
__nextHasNoMarginBottom
aria-label={ selectionLabel }
aria-disabled={ disabled }
checked={ isSelected }
checked={ checked }
onChange={ () => {
if ( disabled ) {
return;
}

if ( ! isSelected ) {
onSelectionChange(
data.filter( ( _item ) => {
const itemId = getItemId?.( _item );
return (
itemId === id || selection.includes( itemId )
);
} )
);
} else {
onSelectionChange(
data.filter( ( _item ) => {
const itemId = getItemId?.( _item );
return (
itemId !== id && selection.includes( itemId )
);
} )
);
}
onSelectionChange(
selection.includes( id )
? selection.filter( ( itemId ) => id !== itemId )
: [ ...selection, id ]
);
} }
/>
);
Expand Down
7 changes: 6 additions & 1 deletion packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
*/
import type { ReactElement, ReactNode } from 'react';

/**
* Internal dependencies
*/
import type { SetSelection } from './private-types';

export type SortDirection = 'asc' | 'desc';

/**
Expand Down Expand Up @@ -383,7 +388,7 @@ export interface ViewBaseProps< Item > {
getItemId: ( item: Item ) => string;
isLoading?: boolean;
onChangeView( view: View ): void;
onSelectionChange: ( items: Item[] ) => void;
onSelectionChange: SetSelection;
selection: string[];
setOpenedFilter: ( fieldId: string ) => void;
view: View;
Expand Down
33 changes: 7 additions & 26 deletions packages/dataviews/src/view-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import ItemActions from './item-actions';
import SingleSelectionCheckbox from './single-selection-checkbox';
import { useHasAPossibleBulkAction } from './bulk-actions';
import type { Action, NormalizedField, ViewGridProps } from './types';
import type { SetSelection } from './private-types';

interface GridItemProps< Item > {
selection: string[];
data: Item[];
onSelectionChange: ( items: Item[] ) => void;
onSelectionChange: SetSelection;
getItemId: ( item: Item ) => string;
item: Item;
actions: Action< Item >[];
Expand All @@ -40,7 +40,6 @@ interface GridItemProps< Item > {

function GridItem< Item >( {
selection,
data,
onSelectionChange,
getItemId,
item,
Expand Down Expand Up @@ -68,27 +67,11 @@ function GridItem< Item >( {
if ( ! hasBulkAction ) {
return;
}
if ( ! isSelected ) {
onSelectionChange(
data.filter( ( _item ) => {
const itemId = getItemId?.( _item );
return (
itemId === id ||
selection.includes( itemId )
);
} )
);
} else {
onSelectionChange(
data.filter( ( _item ) => {
const itemId = getItemId?.( _item );
return (
itemId !== id &&
selection.includes( itemId )
);
} )
);
}
onSelectionChange(
selection.includes( id )
? selection.filter( ( itemId ) => id !== itemId )
: [ ...selection, id ]
);
}
} }
>
Expand All @@ -104,7 +87,6 @@ function GridItem< Item >( {
selection={ selection }
onSelectionChange={ onSelectionChange }
getItemId={ getItemId }
data={ data }
primaryField={ primaryField }
disabled={ ! hasBulkAction }
/>
Expand Down Expand Up @@ -239,7 +221,6 @@ export default function ViewGrid< Item >( {
<GridItem
key={ getItemId( item ) }
selection={ selection }
data={ data }
onSelectionChange={ onSelectionChange }
getItemId={ getItemId }
item={ item }
Expand Down
6 changes: 2 additions & 4 deletions packages/dataviews/src/view-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,8 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
)
);

const onSelect = useCallback(
( item: Item ) => onSelectionChange( [ item ] ),
[ onSelectionChange ]
);
const onSelect = ( item: Item ) =>
onSelectionChange( [ getItemId( item ) ] );

const getItemDomId = useCallback(
( item?: Item ) =>
Expand Down
Loading

0 comments on commit fe67010

Please sign in to comment.