diff --git a/packages/dataviews/src/components/dataviews-bulk-actions/index.tsx b/packages/dataviews/src/components/dataviews-bulk-actions/index.tsx
index 92a3fe85f67e74..86f0bb6db0ba84 100644
--- a/packages/dataviews/src/components/dataviews-bulk-actions/index.tsx
+++ b/packages/dataviews/src/components/dataviews-bulk-actions/index.tsx
@@ -1,3 +1,8 @@
+/**
+ * External dependencies
+ */
+import type { ReactElement } from 'react';
+
/**
* WordPress dependencies
*/
@@ -15,11 +20,46 @@ import { closeSmall } from '@wordpress/icons';
* Internal dependencies
*/
import DataViewsContext from '../dataviews-context';
-import { ActionWithModal } from '../dataviews-item-actions';
-import type { Action } from '../../types';
+import { ActionModal } from '../dataviews-item-actions';
+import type { Action, ActionModal as ActionModalType } from '../../types';
import type { SetSelection } from '../../private-types';
import type { ActionTriggerProps } from '../dataviews-item-actions';
+interface ActionWithModalProps< Item > {
+ action: ActionModalType< Item >;
+ items: Item[];
+ ActionTriggerComponent: (
+ props: ActionTriggerProps< Item >
+ ) => ReactElement;
+}
+
+function ActionWithModal< Item >( {
+ action,
+ items,
+ ActionTriggerComponent,
+}: ActionWithModalProps< Item > ) {
+ const [ isModalOpen, setIsModalOpen ] = useState( false );
+ const actionTriggerProps = {
+ action,
+ onClick: () => {
+ setIsModalOpen( true );
+ },
+ items,
+ };
+ return (
+ <>
+
+ { isModalOpen && (
+ setIsModalOpen( false ) }
+ />
+ ) }
+ >
+ );
+}
+
export function useHasAPossibleBulkAction< Item >(
actions: Action< Item >[],
item: Item
@@ -160,7 +200,7 @@ function ActionButton< Item >( {
key={ action.id }
action={ action }
items={ selectedEligibleItems }
- ActionTrigger={ ActionTrigger }
+ ActionTriggerComponent={ ActionTrigger }
/>
);
}
diff --git a/packages/dataviews/src/components/dataviews-item-actions/index.tsx b/packages/dataviews/src/components/dataviews-item-actions/index.tsx
index c5e1cb09adf15f..abe63e27a15b3b 100644
--- a/packages/dataviews/src/components/dataviews-item-actions/index.tsx
+++ b/packages/dataviews/src/components/dataviews-item-actions/index.tsx
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import type { MouseEventHandler, ReactElement } from 'react';
+import type { MouseEventHandler } from 'react';
/**
* WordPress dependencies
@@ -32,20 +32,17 @@ export interface ActionTriggerProps< Item > {
items: Item[];
}
-interface ActionModalProps< Item > {
+export interface ActionModalProps< Item > {
action: ActionModalType< Item >;
items: Item[];
- closeModal?: () => void;
-}
-
-interface ActionWithModalProps< Item > extends ActionModalProps< Item > {
- ActionTrigger: ( props: ActionTriggerProps< Item > ) => ReactElement;
- isBusy?: boolean;
+ closeModal: () => void;
}
interface ActionsMenuGroupProps< Item > {
actions: Action< Item >[];
item: Item;
+ registry: ReturnType< typeof useRegistry >;
+ setActiveModalAction: ( action: ActionModalType< Item > | null ) => void;
}
interface ItemActionsProps< Item > {
@@ -58,6 +55,7 @@ interface CompactItemActionsProps< Item > {
item: Item;
actions: Action< Item >[];
isSmall?: boolean;
+ registry: ReturnType< typeof useRegistry >;
}
interface PrimaryActionsProps< Item > {
@@ -65,12 +63,6 @@ interface PrimaryActionsProps< Item > {
actions: Action< Item >[];
registry: ReturnType< typeof useRegistry >;
}
-interface ActionsListProps< Item > {
- item: Item;
- actions: Action< Item >[];
- registry: ReturnType< typeof useRegistry >;
- ActionTrigger: ( props: ActionTriggerProps< Item > ) => ReactElement;
-}
function ButtonTrigger< Item >( {
action,
@@ -98,10 +90,7 @@ function MenuItemTrigger< Item >( {
const label =
typeof action.label === 'string' ? action.label : action.label( items );
return (
-
+
{ label }
);
@@ -118,7 +107,7 @@ export function ActionModal< Item >( {
{} ) }
+ onRequestClose={ closeModal }
focusOnMount="firstContentElement"
size="medium"
overlayClassName={ `dataviews-action-modal dataviews-action-modal__${ kebabCase(
@@ -130,48 +119,28 @@ export function ActionModal< Item >( {
);
}
-export function ActionWithModal< Item >( {
- action,
- items,
- ActionTrigger,
- isBusy,
-}: ActionWithModalProps< Item > ) {
- const [ isModalOpen, setIsModalOpen ] = useState( false );
- const actionTriggerProps = {
- action,
- onClick: () => {
- setIsModalOpen( true );
- },
- items,
- isBusy,
- };
- return (
- <>
-
- { isModalOpen && (
- setIsModalOpen( false ) }
- />
- ) }
- >
- );
-}
-
export function ActionsMenuGroup< Item >( {
actions,
item,
+ registry,
+ setActiveModalAction,
}: ActionsMenuGroupProps< Item > ) {
- const registry = useRegistry();
return (
-
+ { actions.map( ( action ) => (
+ {
+ if ( 'RenderModal' in action ) {
+ setActiveModalAction( action );
+ return;
+ }
+ action.callback( [ item ], { registry } );
+ } }
+ items={ [ item ] }
+ />
+ ) ) }
);
}
@@ -210,6 +179,7 @@ export default function ItemActions< Item >( {
item={ item }
actions={ eligibleActions }
isSmall
+ registry={ registry }
/>
);
}
@@ -239,7 +209,11 @@ export default function ItemActions< Item >( {
actions={ primaryActions }
registry={ registry }
/>
-
+
);
}
@@ -248,23 +222,41 @@ function CompactItemActions< Item >( {
item,
actions,
isSmall,
+ registry,
}: CompactItemActionsProps< Item > ) {
+ const [ activeModalAction, setActiveModalAction ] = useState(
+ null as ActionModalType< Item > | null
+ );
return (
-
+
+ { !! activeModalAction && (
+ setActiveModalAction( null ) }
+ />
+ ) }
+ >
);
}
@@ -273,45 +265,33 @@ function PrimaryActions< Item >( {
actions,
registry,
}: PrimaryActionsProps< Item > ) {
+ const [ activeModalAction, setActiveModalAction ] = useState( null as any );
if ( ! Array.isArray( actions ) || actions.length === 0 ) {
return null;
}
return (
-
- );
-}
-
-function ActionsList< Item >( {
- item,
- actions,
- registry,
- ActionTrigger,
-}: ActionsListProps< Item > ) {
- return actions.map( ( action ) => {
- if ( 'RenderModal' in action ) {
- return (
-
+ { actions.map( ( action ) => (
+ {
+ if ( 'RenderModal' in action ) {
+ setActiveModalAction( action );
+ return;
+ }
+ action.callback( [ item ], { registry } );
+ } }
items={ [ item ] }
- ActionTrigger={ ActionTrigger }
/>
- );
- }
- return (
- {
- action.callback( [ item ], { registry } );
- } }
- items={ [ item ] }
- />
- );
- } );
+ ) ) }
+ { !! activeModalAction && (
+ setActiveModalAction( null ) }
+ />
+ ) }
+ >
+ );
}
diff --git a/packages/dataviews/src/dataviews-layouts/list/index.tsx b/packages/dataviews/src/dataviews-layouts/list/index.tsx
index d400cc62741699..62d813c1485af8 100644
--- a/packages/dataviews/src/dataviews-layouts/list/index.tsx
+++ b/packages/dataviews/src/dataviews-layouts/list/index.tsx
@@ -40,6 +40,7 @@ import type {
NormalizedField,
ViewList as ViewListType,
ViewListProps,
+ ActionModal as ActionModalType,
} from '../../types';
interface ListViewItemProps< Item > {
@@ -154,7 +155,11 @@ function ListItem< Item >( {
const labelId = `${ idPrefix }-label`;
const descriptionId = `${ idPrefix }-description`;
+ const registry = useRegistry();
const [ isHovered, setIsHovered ] = useState( false );
+ const [ activeModalAction, setActiveModalAction ] = useState(
+ null as ActionModalType< Item > | null
+ );
const handleHover: React.MouseEventHandler = ( { type } ) => {
const isHover = type === 'mouseenter';
setIsHovered( isHover );
@@ -233,8 +238,17 @@ function ListItem< Item >( {
+ { !! activeModalAction && (
+ setActiveModalAction( null ) }
+ />
+ ) }
) }
diff --git a/packages/editor/src/components/post-actions/index.js b/packages/editor/src/components/post-actions/index.js
index ab11b5e318b5a6..bfdddb4a5a062d 100644
--- a/packages/editor/src/components/post-actions/index.js
+++ b/packages/editor/src/components/post-actions/index.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { useSelect } from '@wordpress/data';
+import { useRegistry, useSelect } from '@wordpress/data';
import { useState, useMemo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import {
@@ -21,7 +21,7 @@ import { usePostActions } from './actions';
const { Menu, kebabCase } = unlock( componentsPrivateApis );
export default function PostActions( { postType, postId, onActionPerformed } ) {
- const [ isActionsMenuOpen, setIsActionsMenuOpen ] = useState( false );
+ const [ activeModalAction, setActiveModalAction ] = useState( null );
const { item, permissions } = useSelect(
( select ) => {
const { getEditedEntityRecord, getEntityRecordPermissions } =
@@ -54,32 +54,34 @@ export default function PostActions( { postType, postId, onActionPerformed } ) {
}, [ allActions, itemWithPermissions ] );
return (
-
- setIsActionsMenuOpen( ! isActionsMenuOpen )
- }
+ <>
+
+ }
+ placement="bottom-end"
+ >
+
- }
- onOpenChange={ setIsActionsMenuOpen }
- placement="bottom-end"
- >
- {
- setIsActionsMenuOpen( false );
- } }
- />
-
+
+ { !! activeModalAction && (
+ setActiveModalAction( null ) }
+ />
+ ) }
+ >
);
}
@@ -88,78 +90,51 @@ export default function PostActions( { postType, postId, onActionPerformed } ) {
// and the dataviews package should not be using the editor packages directly,
// so duplicating the code here seems like the least bad option.
-// Copied as is from packages/dataviews/src/item-actions.js
function DropdownMenuItemTrigger( { action, onClick, items } ) {
const label =
typeof action.label === 'string' ? action.label : action.label( items );
return (
-
+
{ label }
);
}
-// Copied as is from packages/dataviews/src/item-actions.js
-// With an added onClose prop.
-function ActionWithModal( { action, item, ActionTrigger, onClose } ) {
- const [ isModalOpen, setIsModalOpen ] = useState( false );
- const actionTriggerProps = {
- action,
- onClick: () => setIsModalOpen( true ),
- items: [ item ],
- };
- const { RenderModal, hideModalHeader } = action;
+export function ActionModal( { action, items, closeModal } ) {
+ const label =
+ typeof action.label === 'string' ? action.label : action.label( items );
return (
- <>
-
- { isModalOpen && (
- {
- setIsModalOpen( false );
- } }
- overlayClassName={ `editor-action-modal editor-action-modal__${ kebabCase(
- action.id
- ) }` }
- focusOnMount="firstContentElement"
- size="medium"
- >
- {
- setIsModalOpen( false );
- onClose();
- } }
- />
-
- ) }
- >
+ {} ) }
+ focusOnMount="firstContentElement"
+ size="medium"
+ overlayClassName={ `editor-action-modal editor-action-modal__${ kebabCase(
+ action.id
+ ) }` }
+ >
+
+
);
}
-// Copied as is from packages/dataviews/src/item-actions.js
-// With an added onClose prop.
-function ActionsDropdownMenuGroup( { actions, item, onClose } ) {
+function ActionsDropdownMenuGroup( { actions, item, setActiveModalAction } ) {
+ const registry = useRegistry();
return (
{ actions.map( ( action ) => {
- if ( action.RenderModal ) {
- return (
-
- );
- }
return (
action.callback( [ item ] ) }
+ onClick={ () => {
+ if ( 'RenderModal' in action ) {
+ setActiveModalAction( action );
+ return;
+ }
+ action.callback( [ item ], { registry } );
+ } }
items={ [ item ] }
/>
);