Skip to content

Commit

Permalink
Dataviews: Add: Bulk actions toolbar.
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Apr 9, 2024
1 parent e1384bb commit 5939c3d
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 4 deletions.
157 changes: 157 additions & 0 deletions packages/dataviews/src/bulk-actions-toolbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/**
* WordPress dependencies
*/
import {
ToolbarButton,
Toolbar,
ToolbarGroup,
__unstableMotion as motion,
__unstableAnimatePresence as AnimatePresence,
} from '@wordpress/components';
import { useMemo } from '@wordpress/element';
import { _n, sprintf, __ } from '@wordpress/i18n';
import { closeSmall } from '@wordpress/icons';
import { useReducedMotion } from '@wordpress/compose';

/**
* Internal dependencies
*/
import { ActionWithModal } from './item-actions';

const SNACKBAR_VARIANTS = {
init: {
bottom: -48,
},
open: {
bottom: 24,
transition: {
bottom: { type: 'tween', duration: 0.2, ease: [ 0, 0, 0.2, 1 ] },
},
},
exit: {
opacity: 0,
bottom: 24,
transition: {
opacity: { type: 'tween', duration: 0.2, ease: [ 0, 0, 0.2, 1 ] },
},
},
};

function PrimaryActionTrigger( { action, onClick, items } ) {
const isDisabled = useMemo( () => {
return items.some( ( item ) => ! action.isEligible( item ) );
}, [ action, items ] );
return (
<ToolbarButton
disabled={ isDisabled }
label={ action.label }
icon={ action.icon }
isDestructive={ action.isDestructive }
size="compact"
onClick={ onClick }
/>
);
}

const EMPTY_ARRAY = [];

export default function BulkActionsToolbar( {
data,
selection,
actions = EMPTY_ARRAY,
setSelection,
getItemId,
} ) {
const isReducedMotion = useReducedMotion();
const selectedItems = useMemo( () => {
return data.filter( ( item ) =>
selection.includes( getItemId( item ) )
);
}, [ selection, data, getItemId ] );

const primaryActionsToShow = useMemo(
() =>
actions.filter( ( action ) => {
return (
action.supportsBulk &&
action.isPrimary &&
selectedItems.some( ( item ) => action.isEligible( item ) )
);
} ),
[ actions, selectedItems ]
);

if (
( selection && selection.length === 0 ) ||
primaryActionsToShow.length === 0
) {
return null;
}

return (
<AnimatePresence>
<motion.div
layout={ ! isReducedMotion } // See https://www.framer.com/docs/animation/#layout-animations
initial={ 'init' }
animate={ 'open' }
exit={ 'exit' }
variants={ isReducedMotion ? undefined : SNACKBAR_VARIANTS }
className="dataviews-bulk-actions"
>
<Toolbar label={ __( 'Bulk actions' ) }>
<div className="dataviews-bulk-actions-toolbar-wrapper">
<ToolbarGroup>
<div className="dataviews-bulk-actions__selection-count">
{
// translators: %s: Total number of selected items.
sprintf(
// translators: %s: Total number of selected items.
_n(
'%s selected',
selection.length
),
selection.length
)
}
</div>
{ primaryActionsToShow.map( ( action ) => {
if ( !! action.RenderModal ) {
return (
<ActionWithModal
key={ action.id }
action={ action }
items={ selectedItems }
ActionTrigger={
PrimaryActionTrigger
}
/>
);
}
return (
<PrimaryActionTrigger
key={ action.id }
action={ action }
items={ selectedItems }
onClick={ () =>
action.callback( selectedItems )
}
/>
);
} ) }
</ToolbarGroup>
<ToolbarGroup>
<ToolbarButton
icon={ closeSmall }
showTooltip
label={ __( 'Cancel' ) }
onClick={ () => {
setSelection( EMPTY_ARRAY );
} }
/>
</ToolbarGroup>
</div>
</Toolbar>
</motion.div>
</AnimatePresence>
);
}
11 changes: 11 additions & 0 deletions packages/dataviews/src/dataviews.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Search from './search';
import { VIEW_LAYOUTS, LAYOUT_TABLE, LAYOUT_GRID } from './constants';
import BulkActions from './bulk-actions';
import { normalizeFields } from './normalize-fields';
import BulkActionsToolbar from './bulk-actions-toolbar';

const defaultGetItemId = ( item ) => item.id;
const defaultOnSelectionChange = () => {};
Expand Down Expand Up @@ -142,6 +143,16 @@ export default function DataViews( {
onChangeView={ onChangeView }
paginationInfo={ paginationInfo }
/>
{ [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type ) &&
hasPossibleBulkAction && (
<BulkActionsToolbar
data={ data }
actions={ actions }
selection={ selection }
setSelection={ setSelection }
getItemId={ getItemId }
/>
) }
</div>
);
}
9 changes: 5 additions & 4 deletions packages/dataviews/src/item-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ function DropdownMenuItemTrigger( { action, onClick } ) {
);
}

function ActionWithModal( { action, item, ActionTrigger } ) {
export function ActionWithModal( { action, items, ActionTrigger } ) {
const [ isModalOpen, setIsModalOpen ] = useState( false );
const actionTriggerProps = {
action,
onClick: () => setIsModalOpen( true ),
items,
};
const { RenderModal, hideModalHeader } = action;
return (
Expand All @@ -69,7 +70,7 @@ function ActionWithModal( { action, item, ActionTrigger } ) {
) }` }
>
<RenderModal
items={ [ item ] }
items={ items }
closeModal={ () => setIsModalOpen( false ) }
/>
</Modal>
Expand All @@ -87,7 +88,7 @@ function ActionsDropdownMenuGroup( { actions, item } ) {
<ActionWithModal
key={ action.id }
action={ action }
item={ item }
items={ [ item ] }
ActionTrigger={ DropdownMenuItemTrigger }
/>
);
Expand Down Expand Up @@ -139,7 +140,7 @@ export default function ItemActions( { item, actions, isCompact } ) {
<ActionWithModal
key={ action.id }
action={ action }
item={ item }
items={ [ item ] }
ActionTrigger={ ButtonTrigger }
/>
);
Expand Down
37 changes: 37 additions & 0 deletions packages/dataviews/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -785,3 +785,40 @@
}
}
}


.dataviews-bulk-actions-toolbar-wrapper {
display: flex;
flex-grow: 1;
width: 100%;
}

.dataviews-bulk-actions {
position: absolute;
display: flex;
flex-direction: column;
align-content: center;
flex-wrap: wrap;
width: 100%;
bottom: $grid-unit-30;

.components-accessible-toolbar {
border-color: $gray-300;
box-shadow: $shadow-popover;

.components-toolbar-group {
border-color: $gray-200;

&:last-child {
border: 0;
}
}
}

.dataviews-bulk-actions__selection-count {
display: flex;
align-items: center;
margin: 0 $grid-unit-10 0 $grid-unit-15;
color: $gray-700;
}
}

0 comments on commit 5939c3d

Please sign in to comment.