import { cloneElement, forwardRef, Fragment, useState } from 'react'; import { Dropdown, DropdownItem, DropdownList } from '@patternfly/react-core/dist/esm/components/Dropdown'; import { Button } from '@patternfly/react-core/dist/esm/components/Button'; import { Divider } from '@patternfly/react-core/dist/esm/components/Divider'; import { MenuToggle } from '@patternfly/react-core/dist/esm/components/MenuToggle'; import { IAction, IExtraData, IRowData } from './TableTypes'; import RhUiEllipsisVerticalFillIcon from '@patternfly/react-icons/dist/esm/icons/rh-ui-ellipsis-vertical-fill-icon'; import { Tooltip } from '@patternfly/react-core/dist/esm/components/Tooltip'; export interface CustomActionsToggleProps { onToggle: (event: React.MouseEvent | React.KeyboardEvent) => void; isOpen: boolean; isDisabled: boolean; toggleRef: React.Ref; } export interface ActionsColumnProps extends Omit, 'label'> { /** Actions to be rendered within or without the action dropdown */ items: IAction[]; /** Indicates whether the actions dropdown is disabled */ isDisabled?: boolean; /** Data of the row the action dropdown is located */ rowData?: IRowData; /** Extra data of a row */ extraData?: IExtraData; /** Custom actions toggle for the actions dropdown */ actionsToggle?: (props: CustomActionsToggleProps) => React.ReactNode; /** Additional properties for the actions dropdown popper */ popperProps?: any; /** @hide Forwarded ref */ innerRef?: React.Ref; /** Ref to forward to the first item in the popup menu */ firstActionItemRef?: React.Ref; /** Flag indicating that the dropdown's onOpenChange callback should not be called. */ isOnOpenChangeDisabled?: boolean; } const ActionsColumnBase: React.FunctionComponent = ({ items, isDisabled, rowData, extraData, actionsToggle, popperProps = { position: 'end', direction: 'down' }, innerRef, firstActionItemRef, isOnOpenChangeDisabled = false, ...props }: ActionsColumnProps) => { const [isOpen, setIsOpen] = useState(false); const onToggle = () => { setIsOpen(!isOpen); }; const onActionClick = ( event: React.MouseEvent | React.KeyboardEvent | MouseEvent, onClick: | ((event: React.MouseEvent, rowIndex: number | undefined, rowData: IRowData, extraData: IExtraData) => void) | undefined ): void => { // Only prevent default if onClick is provided. This allows href support. if (onClick) { event.preventDefault(); // tslint:disable-next-line:no-unused-expression onClick(event as React.MouseEvent, extraData && extraData.rowIndex, rowData, extraData); } }; return ( {items .filter((item) => item.isOutsideDropdown) // eslint-disable-next-line @typescript-eslint/no-unused-vars .map(({ title, itemKey, onClick, isOutsideDropdown, ...props }, key) => typeof title === 'string' ? ( ) : ( cloneElement(title as React.ReactElement, { onClick, isDisabled, ...props }) ) )} setIsOpen(isOpen) : undefined} toggle={(toggleRef: any) => actionsToggle ? ( actionsToggle({ onToggle, isOpen, isDisabled, toggleRef }) ) : ( } /> ) } {...(rowData && rowData.actionProps)} ref={innerRef} {...props} popperProps={popperProps} > {items .filter((item) => !item.isOutsideDropdown) .map( ({ title, itemKey, onClick, tooltipProps, isSeparator, shouldCloseOnClick = true, ...props }, index) => { if (isSeparator) { return ; } const item = ( { onActionClick(event, onClick); shouldCloseOnClick && onToggle(); }} {...props} key={itemKey || index} data-key={itemKey || index} ref={index === 0 ? firstActionItemRef : undefined} > {title} ); if (tooltipProps?.content) { return ( {item} ); } else { return item; } } )} ); }; export const ActionsColumn = forwardRef((props: ActionsColumnProps, ref: React.Ref) => ( )); ActionsColumn.displayName = 'ActionsColumn';