From f2d37b1a0362ee9b7e3650ba35757a365f426b45 Mon Sep 17 00:00:00 2001 From: Nick Diehl <47604184+ncdiehl11@users.noreply.github.com> Date: Fri, 1 Nov 2024 10:58:07 -0400 Subject: [PATCH] feat(protocol-designer): add step dragging indicator (#16660) Adds logic to display a divider under a target step when a step is being dragged (for reordering) over that target step. Closes AUTH-1013 --- .../Timeline/ConnectedStepInfo.tsx | 4 +++- .../ProtocolSteps/Timeline/DraggableSteps.tsx | 13 ++++++++---- .../ProtocolSteps/Timeline/StepContainer.tsx | 20 ++++++++++++++++--- .../Timeline/__tests__/StepContainer.test.tsx | 4 ++++ 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx index 1e533b2bfd3..778159b6d31 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/ConnectedStepInfo.tsx @@ -46,10 +46,11 @@ import type { DeleteModalType } from '../../../../components/modals/ConfirmDelet export interface ConnectedStepInfoProps { stepId: StepIdType stepNumber: number + dragHovered?: boolean } export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { - const { stepId, stepNumber } = props + const { stepId, stepNumber, dragHovered = false } = props const { t } = useTranslation('application') const dispatch = useDispatch>() const stepIds = useSelector(getOrderedStepIds) @@ -215,6 +216,7 @@ export function ConnectedStepInfo(props: ConnectedStepInfoProps): JSX.Element { title={`${stepNumber}. ${ step.stepName || t(`stepType.${step.stepType}`) }`} + dragHovered={dragHovered} /> ) diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/DraggableSteps.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/DraggableSteps.tsx index bf92c681796..d48ada0665b 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/DraggableSteps.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/DraggableSteps.tsx @@ -14,7 +14,7 @@ import { selectors as stepFormSelectors } from '../../../../step-forms' import { stepIconsByType } from '../../../../form-types' import { StepContainer } from './StepContainer' import { ConnectedStepInfo } from './ConnectedStepInfo' -import type { DragLayerMonitor, DropTargetOptions } from 'react-dnd' +import type { DragLayerMonitor, DropTargetMonitor } from 'react-dnd' import type { StepIdType } from '../../../../form-types' import type { ConnectedStepItemProps } from '../../../../containers/ConnectedStepItem' @@ -44,7 +44,7 @@ function DragDropStep(props: DragDropStepProps): JSX.Element { [orderedStepIds] ) - const [{ handlerId }, drop] = useDrop( + const [{ handlerId, hovered }, drop] = useDrop( () => ({ accept: DND_TYPES.STEP_ITEM, canDrop: () => { @@ -57,8 +57,9 @@ function DragDropStep(props: DragDropStepProps): JSX.Element { moveStep(draggedId, overIndex) } }, - collect: (monitor: DropTargetOptions) => ({ + collect: (monitor: DropTargetMonitor) => ({ handlerId: monitor.getHandlerId(), + hovered: monitor.isOver(), }), }), [orderedStepIds] @@ -71,7 +72,11 @@ function DragDropStep(props: DragDropStepProps): JSX.Element { style={{ opacity: isDragging ? 0.3 : 1 }} data-handler-id={handlerId} > - + ) } diff --git a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx index d6f5b532e79..0abd86d73c1 100644 --- a/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx +++ b/protocol-designer/src/pages/Designer/ProtocolSteps/Timeline/StepContainer.tsx @@ -4,11 +4,12 @@ import { useDispatch, useSelector } from 'react-redux' import { ALIGN_CENTER, BORDERS, - Box, Btn, COLORS, CURSOR_DEFAULT, CURSOR_POINTER, + DIRECTION_COLUMN, + Divider, Flex, Icon, JUSTIFY_SPACE_BETWEEN, @@ -55,6 +56,7 @@ export interface StepContainerProps { hovered?: boolean hasError?: boolean isStepAfterError?: boolean + dragHovered?: boolean } export function StepContainer(props: StepContainerProps): JSX.Element { @@ -71,6 +73,7 @@ export function StepContainer(props: StepContainerProps): JSX.Element { title, hasError = false, isStepAfterError = false, + dragHovered = false, } = props const [top, setTop] = React.useState(0) const menuRootRef = React.useRef(null) @@ -188,12 +191,14 @@ export function StepContainer(props: StepContainerProps): JSX.Element { onCancelClick={cancelMultiDelete} /> )} - - + {dragHovered ? ( + + ) : null} + {stepOverflowMenu && stepId != null ? createPortal( { render(props) screen.getByText('Final deck state') }) + it('renders the divider if hover targets that step', () => { + render({ ...props, dragHovered: true }) + screen.getByTestId('divider') + }) })