Skip to content

Commit

Permalink
feat(protocol-designer): update React DnD from version 6.0.0 to 16.0.1 (
Browse files Browse the repository at this point in the history
  • Loading branch information
jerader authored and Carlos-fernandez committed May 20, 2024
1 parent 939bd72 commit 279b9c9
Show file tree
Hide file tree
Showing 20 changed files with 503 additions and 762 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,23 @@ import * as React from 'react'
import { Svg } from '../../primitives'
import type { DeckDefinition, DeckSlot } from '@opentrons/shared-data'

export interface RobotCoordinateSpaceWithDOMCoordsRenderProps {
export interface RobotCoordinateSpaceWithRefRenderProps {
deckSlotsById: { [slotId: string]: DeckSlot }
getRobotCoordsFromDOMCoords: (
domX: number,
domY: number
) => { x: number; y: number }
}

interface RobotCoordinateSpaceWithDOMCoordsProps
interface RobotCoordinateSpaceWithRefProps
extends React.ComponentProps<typeof Svg> {
viewBox?: string | null
deckDef?: DeckDefinition
children?: (
props: RobotCoordinateSpaceWithDOMCoordsRenderProps
) => React.ReactNode
children?: (props: RobotCoordinateSpaceWithRefRenderProps) => React.ReactNode
}

type GetRobotCoordsFromDOMCoords = RobotCoordinateSpaceWithDOMCoordsRenderProps['getRobotCoordsFromDOMCoords']

export function RobotCoordinateSpaceWithDOMCoords(
props: RobotCoordinateSpaceWithDOMCoordsProps
export function RobotCoordinateSpaceWithRef(
props: RobotCoordinateSpaceWithRefProps
): JSX.Element | null {
const { children, deckDef, viewBox, ...restProps } = props
const wrapperRef = React.useRef<SVGSVGElement>(null)
const getRobotCoordsFromDOMCoords: GetRobotCoordsFromDOMCoords = (x, y) => {
if (wrapperRef.current == null) return { x: 0, y: 0 }

const cursorPoint = wrapperRef.current.createSVGPoint()

cursorPoint.x = x
cursorPoint.y = y

return cursorPoint.matrixTransform(
wrapperRef.current.getScreenCTM()?.inverse()
)
}
if (deckDef == null && viewBox == null) return null

let wholeDeckViewBox
Expand All @@ -59,7 +40,7 @@ export function RobotCoordinateSpaceWithDOMCoords(
transform="scale(1, -1)"
{...restProps}
>
{children?.({ deckSlotsById, getRobotCoordsFromDOMCoords })}
{children?.({ deckSlotsById })}
</Svg>
)
}
2 changes: 1 addition & 1 deletion components/src/hardware-sim/RobotCoordinateSpace/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './RobotCoordinateSpaceWithDOMCoords'
export * from './RobotCoordinateSpaceWithRef'
export * from './RobotCoordinateSpace'
4 changes: 2 additions & 2 deletions protocol-designer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
"query-string": "6.2.0",
"react": "18.2.0",
"react-color": "2.19.3",
"react-dnd": "6.0.0",
"react-dnd-mouse-backend": "0.1.2",
"react-dnd": "16.0.1",
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0",
"react-hook-form": "7.49.3",
"react-i18next": "14.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export function LabwareOnDeck(props: LabwareOnDeckProps): JSX.Element {
const missingTips = missingTipsByLabwareId
? missingTipsByLabwareId[labwareOnDeck.id]
: null

return (
<g transform={`translate(${x}, ${y})`} className={className}>
<LabwareRender
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import assert from 'assert'
import * as React from 'react'
import { DropTarget, DropTargetConnector, DropTargetMonitor } from 'react-dnd'
import { useDispatch, useSelector } from 'react-redux'
import { DropTargetMonitor, useDrop } from 'react-dnd'
import cx from 'classnames'
import { connect } from 'react-redux'
import noop from 'lodash/noop'
import { Icon, RobotCoordsForeignDiv } from '@opentrons/components'
import { DND_TYPES } from '../../../constants'
Expand All @@ -15,66 +15,108 @@ import {
moveDeckItem,
openAddLabwareModal,
} from '../../../labware-ingred/actions'
import {
LabwareDefByDefURI,
selectors as labwareDefSelectors,
} from '../../../labware-defs'
import { getDeckSetupForActiveItem } from '../../../top-selectors/labware-locations'
import { selectors as labwareDefSelectors } from '../../../labware-defs'
import { START_TERMINAL_ITEM_ID, TerminalItemId } from '../../../steplist'
import { BlockedSlot } from './BlockedSlot'

import type { CoordinateTuple, Dimensions } from '@opentrons/shared-data'
import type { BaseState, DeckSlot, ThunkDispatch } from '../../../types'
import type { LabwareOnDeck } from '../../../step-forms'

import styles from './LabwareOverlays.css'

interface DNDP {
isOver: boolean
connectDropTarget: (val: React.ReactNode) => JSX.Element
draggedItem: { labwareOnDeck: LabwareOnDeck } | null
itemType: string
}

interface OP {
interface AdapterControlsProps {
slotPosition: CoordinateTuple
slotBoundingBox: Dimensions
// labwareId is the adapter's labwareId
labwareId: string
allLabware: LabwareOnDeck[]
onDeck: boolean
selectedTerminalItemId?: TerminalItemId | null
handleDragHover?: () => unknown
}
interface DP {
addLabware: (e: React.MouseEvent<any>) => unknown
moveDeckItem: (item1: DeckSlot, item2: DeckSlot) => unknown
deleteLabware: () => void
handleDragHover?: () => void
}

interface SP {
customLabwareDefs: LabwareDefByDefURI
interface DroppedItem {
labwareOnDeck: LabwareOnDeck
}

export type SlotControlsProps = OP & DP & DNDP & SP

export const AdapterControlsComponents = (
props: SlotControlsProps
export const AdapterControls = (
props: AdapterControlsProps
): JSX.Element | null => {
const {
slotPosition,
slotBoundingBox,
addLabware,
selectedTerminalItemId,
isOver,
connectDropTarget,
draggedItem,
itemType,
deleteLabware,
labwareId,
customLabwareDefs,
onDeck,
handleDragHover,
allLabware,
} = props
const customLabwareDefs = useSelector(
labwareDefSelectors.getCustomLabwareDefsByURI
)
const activeDeckSetup = useSelector(getDeckSetupForActiveItem)
const labware = activeDeckSetup.labware
const ref = React.useRef(null)
const [newSlot, setSlot] = React.useState<string | null>(null)
const dispatch = useDispatch()

const adapterName =
allLabware.find(labware => labware.id === labwareId)?.def.metadata
.displayName ?? ''

const [{ itemType, draggedItem, isOver }, drop] = useDrop({
accept: DND_TYPES.LABWARE,
canDrop: (item: DroppedItem) => {
const draggedDef = item.labwareOnDeck?.def
assert(draggedDef, 'no labware def of dragged item, expected it on drop')

if (draggedDef != null) {
const isCustomLabware = getLabwareIsCustom(
customLabwareDefs,
item.labwareOnDeck
)
return (
getAdapterLabwareIsAMatch(
labwareId,
allLabware,
draggedDef.parameters.loadName
) || isCustomLabware
)
}
return true
},
drop: (item: DroppedItem) => {
const droppedLabware = item
if (newSlot != null) {
dispatch(moveDeckItem(newSlot, labwareId))
} else if (droppedLabware.labwareOnDeck != null) {
const droppedSlot = droppedLabware.labwareOnDeck.slot
dispatch(moveDeckItem(droppedSlot, labwareId))
}
},
hover: () => {
if (handleDragHover != null) {
handleDragHover()
}
},
collect: (monitor: DropTargetMonitor) => ({
itemType: monitor.getItemType(),
isOver: !!monitor.isOver(),
draggedItem: monitor.getItem() as DroppedItem,
}),
})

const draggedLabware = Object.values(labware).find(
l => l.id === draggedItem?.labwareOnDeck?.id
)

React.useEffect(() => {
if (draggedLabware != null) {
setSlot(draggedLabware.slot)
}
})

if (
selectedTerminalItemId !== START_TERMINAL_ITEM_ID ||
(itemType !== DND_TYPES.LABWARE && itemType !== null)
Expand All @@ -101,8 +143,10 @@ export const AdapterControlsComponents = (
slotBlocked = 'Labware incompatible with this adapter'
}

return connectDropTarget(
<g>
drop(ref)

return (
<g ref={ref}>
{slotBlocked ? (
<BlockedSlot
x={slotPosition[0]}
Expand All @@ -124,11 +168,21 @@ export const AdapterControlsComponents = (
onClick: isOver ? noop : undefined,
}}
>
<a className={styles.overlay_button} onClick={addLabware}>
<a
className={styles.overlay_button}
onClick={() => dispatch(openAddLabwareModal({ slot: labwareId }))}
>
{!isOver && <Icon className={styles.overlay_icon} name="plus" />}
{isOver ? 'Place Here' : 'Add Labware'}
</a>
<a className={styles.overlay_button} onClick={deleteLabware}>
<a
className={styles.overlay_button}
onClick={() => {
window.confirm(
`"Are you sure you want to remove this ${adapterName}?`
) && dispatch(deleteContainer({ labwareId: labwareId }))
}}
>
{!isOver && <Icon className={styles.overlay_icon} name="close" />}
{'Delete'}
</a>
Expand All @@ -137,80 +191,3 @@ export const AdapterControlsComponents = (
</g>
)
}

const mapStateToProps = (state: BaseState): SP => {
return {
customLabwareDefs: labwareDefSelectors.getCustomLabwareDefsByURI(state),
}
}

const mapDispatchToProps = (dispatch: ThunkDispatch<any>, ownProps: OP): DP => {
const adapterName =
ownProps.allLabware.find(labware => labware.id === ownProps.labwareId)?.def
.metadata.displayName ?? ''
return {
addLabware: () =>
dispatch(openAddLabwareModal({ slot: ownProps.labwareId })),
moveDeckItem: (sourceSlot, destSlot) =>
dispatch(moveDeckItem(sourceSlot, destSlot)),
deleteLabware: () => {
window.confirm(`"Are you sure you want to remove this ${adapterName}?`) &&
dispatch(deleteContainer({ labwareId: ownProps.labwareId }))
},
}
}

const slotTarget = {
drop: (props: SlotControlsProps, monitor: DropTargetMonitor) => {
const draggedItem = monitor.getItem()
if (draggedItem) {
props.moveDeckItem(draggedItem.labwareOnDeck.slot, props.labwareId)
}
},
hover: (props: SlotControlsProps) => {
if (props.handleDragHover) {
props.handleDragHover()
}
},
canDrop: (props: SlotControlsProps, monitor: DropTargetMonitor) => {
const draggedItem = monitor.getItem()
const draggedDef = draggedItem?.labwareOnDeck?.def
assert(draggedDef, 'no labware def of dragged item, expected it on drop')

if (draggedDef != null) {
const isCustomLabware = getLabwareIsCustom(
props.customLabwareDefs,
draggedItem.labwareOnDeck
)
return (
getAdapterLabwareIsAMatch(
props.labwareId,
props.allLabware,
draggedDef.parameters.loadName
) || isCustomLabware
)
}
return true
},
}
const collectSlotTarget = (
connect: DropTargetConnector,
monitor: DropTargetMonitor
): React.ReactNode => ({
// @ts-expect-error(BC, 12-13-2023): react dnd needs to be updated or removed to include proper type
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
draggedItem: monitor.getItem(),
itemType: monitor.getItemType(),
})

export const AdapterControls = connect(
mapStateToProps,
mapDispatchToProps
)(
DropTarget(
DND_TYPES.LABWARE,
slotTarget,
collectSlotTarget
)(AdapterControlsComponents)
)

This file was deleted.

Loading

0 comments on commit 279b9c9

Please sign in to comment.