diff --git a/protocol-designer/package.json b/protocol-designer/package.json index 6730a8da47d..c06cc700b2f 100755 --- a/protocol-designer/package.json +++ b/protocol-designer/package.json @@ -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-mouse-backend": "1.0.0-rc.2", "react-dom": "18.2.0", "react-hook-form": "7.49.3", "react-i18next": "14.0.0", diff --git a/protocol-designer/src/components/DeckSetup/LabwareOverlays/AdapterControls.tsx b/protocol-designer/src/components/DeckSetup/LabwareOverlays/AdapterControls.tsx index e01e1b7dcd5..a2b68652f47 100644 --- a/protocol-designer/src/components/DeckSetup/LabwareOverlays/AdapterControls.tsx +++ b/protocol-designer/src/components/DeckSetup/LabwareOverlays/AdapterControls.tsx @@ -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' @@ -15,27 +15,16 @@ import { moveDeckItem, openAddLabwareModal, } from '../../../labware-ingred/actions' -import { - LabwareDefByDefURI, - selectors as labwareDefSelectors, -} from '../../../labware-defs' +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 @@ -43,38 +32,72 @@ interface OP { allLabware: LabwareOnDeck[] onDeck: boolean selectedTerminalItemId?: TerminalItemId | null - handleDragHover?: () => unknown -} -interface DP { - addLabware: (e: React.MouseEvent) => 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 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) => { + if (item.labwareOnDeck) { + dispatch(moveDeckItem(item.labwareOnDeck.slot, labwareId)) + } + }, + hover: () => { + if (handleDragHover) { + handleDragHover() + } + }, + collect: (monitor: DropTargetMonitor) => ({ + itemType: monitor.getItemType(), + isOver: !!monitor.isOver(), + draggedItem: monitor.getItem() as DroppedItem, + }), + })) + if ( selectedTerminalItemId !== START_TERMINAL_ITEM_ID || (itemType !== DND_TYPES.LABWARE && itemType !== null) @@ -101,8 +124,8 @@ export const AdapterControlsComponents = ( slotBlocked = 'Labware incompatible with this adapter' } - return connectDropTarget( - + return ( + {slotBlocked ? ( - + dispatch(openAddLabwareModal({ slot: labwareId }))} + > {!isOver && } {isOver ? 'Place Here' : 'Add Labware'} - + { + window.confirm( + `"Are you sure you want to remove this ${adapterName}?` + ) && dispatch(deleteContainer({ labwareId: labwareId })) + }} + > {!isOver && } {'Delete'} @@ -137,80 +170,3 @@ export const AdapterControlsComponents = ( ) } - -const mapStateToProps = (state: BaseState): SP => { - return { - customLabwareDefs: labwareDefSelectors.getCustomLabwareDefsByURI(state), - } -} - -const mapDispatchToProps = (dispatch: ThunkDispatch, 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) -) diff --git a/protocol-designer/src/components/DeckSetup/LabwareOverlays/DragPreview.tsx b/protocol-designer/src/components/DeckSetup/LabwareOverlays/DragPreview.tsx index 700b683c946..6d1dc0c85b7 100644 --- a/protocol-designer/src/components/DeckSetup/LabwareOverlays/DragPreview.tsx +++ b/protocol-designer/src/components/DeckSetup/LabwareOverlays/DragPreview.tsx @@ -1,32 +1,31 @@ import * as React from 'react' -import { DragLayer } from 'react-dnd' +import { useDragLayer, XYCoord } from 'react-dnd' import { LabwareOnDeck } from '../LabwareOnDeck' import { DND_TYPES } from '../../../constants' -import { LabwareOnDeck as LabwareOnDeckType } from '../../../step-forms' import { RobotWorkSpaceRenderProps } from '@opentrons/components' import styles from './DragPreview.css' interface DragPreviewProps { - isDragging: boolean - currentOffset?: { x: number; y: number } - item: { labwareOnDeck: LabwareOnDeckType } - itemType: string getRobotCoordsFromDOMCoords: RobotWorkSpaceRenderProps['getRobotCoordsFromDOMCoords'] } -const LabwareDragPreview = (props: DragPreviewProps): JSX.Element | null => { - const { - item, - itemType, - isDragging, - currentOffset, - getRobotCoordsFromDOMCoords, - } = props - if (itemType !== DND_TYPES.LABWARE || !isDragging || !currentOffset) +export const DragPreview = (props: DragPreviewProps): JSX.Element | null => { + const { getRobotCoordsFromDOMCoords } = props + const { item, itemType, isDragging, currentOffset } = useDragLayer( + monitor => ({ + item: monitor.getItem(), + itemType: monitor.getItemType(), + isDragging: monitor.isDragging(), + currentOffset: monitor.getSourceClientOffset(), + }) + ) + + if (!isDragging || !currentOffset || itemType !== DND_TYPES.LABWARE) { return null - const { x, y } = currentOffset + } - const cursor = getRobotCoordsFromDOMCoords(x, y) + const { x, y } = currentOffset + const cursor: XYCoord = getRobotCoordsFromDOMCoords(x, y) return ( { /> ) } - -export const DragPreview = DragLayer< - Omit ->(monitor => ({ - currentOffset: monitor.getSourceClientOffset(), - isDragging: monitor.isDragging(), - itemType: monitor.getItemType(), - item: monitor.getItem(), -}))(LabwareDragPreview) diff --git a/protocol-designer/src/components/DeckSetup/LabwareOverlays/EditLabware.tsx b/protocol-designer/src/components/DeckSetup/LabwareOverlays/EditLabware.tsx index e4f267114b0..530032c2306 100644 --- a/protocol-designer/src/components/DeckSetup/LabwareOverlays/EditLabware.tsx +++ b/protocol-designer/src/components/DeckSetup/LabwareOverlays/EditLabware.tsx @@ -1,18 +1,10 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' -import { connect } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import cx from 'classnames' import { Icon } from '@opentrons/components' import { getLabwareDisplayName } from '@opentrons/shared-data' -import { - DragSource, - DragSourceConnector, - DragSourceMonitor, - DropTarget, - DropTargetConnector, - DropTargetMonitor, - DropTargetSpec, -} from 'react-dnd' +import { DropTargetMonitor, useDrag, useDrop } from 'react-dnd' import { NameThisLabware } from './NameThisLabware' import { DND_TYPES } from '../../../constants' import { @@ -22,50 +14,78 @@ import { openIngredientSelector, } from '../../../labware-ingred/actions' import { selectors as labwareIngredSelectors } from '../../../labware-ingred/selectors' -import { BaseState, DeckSlot, ThunkDispatch } from '../../../types' +import { ThunkDispatch } from '../../../types' import { LabwareOnDeck } from '../../../step-forms' import styles from './LabwareOverlays.css' -interface OP { +interface Props { labwareOnDeck: LabwareOnDeck setHoveredLabware: (val?: LabwareOnDeck | null) => unknown setDraggedLabware: (val?: LabwareOnDeck | null) => unknown swapBlocked: boolean } -interface SP { - isYetUnnamed: boolean -} -interface DP { - editLiquids: () => unknown - duplicateLabware: () => unknown - deleteLabware: () => unknown - moveDeckItem: (item1: DeckSlot, item2: DeckSlot) => unknown -} -interface DNDP { - draggedLabware?: LabwareOnDeck | null - isOver: boolean - connectDragSource: (val: JSX.Element) => JSX.Element - connectDropTarget: (val: JSX.Element) => JSX.Element -} - -type Props = OP & SP & DP & DNDP - -const EditLabwareComponent = (props: Props): JSX.Element => { +export const EditLabware = (props: Props): JSX.Element | null => { const { labwareOnDeck, - isYetUnnamed, - editLiquids, - deleteLabware, - duplicateLabware, - draggedLabware, - isOver, - connectDragSource, - connectDropTarget, swapBlocked, + setDraggedLabware, + setHoveredLabware, } = props + const savedLabware = useSelector(labwareIngredSelectors.getSavedLabware) + const dispatch = useDispatch>() const { t } = useTranslation('deck') + const { isTiprack } = labwareOnDeck.def.parameters + const hasName = savedLabware[labwareOnDeck.id] + const isYetUnnamed = !labwareOnDeck.def.parameters.isTiprack && !hasName + + const editLiquids = (): void => { + dispatch(openIngredientSelector(labwareOnDeck.id)) + } + + const [, drag] = useDrag(() => ({ + type: DND_TYPES.LABWARE, + item: { labwareOnDeck }, + beginDrag: () => { + setDraggedLabware(labwareOnDeck) + return { labwareOnDeck } + }, + endDrag: () => { + setHoveredLabware(null) + setDraggedLabware(null) + }, + })) + + const [{ draggedLabware, isOver }, drop] = useDrop(() => ({ + accept: DND_TYPES.LABWARE, + canDrop: (monitor: DropTargetMonitor) => { + const draggedItem: any = monitor.getItem() + const draggedLabware = draggedItem?.labwareOnDeck + const isDifferentSlot = + draggedLabware && draggedLabware.slot !== props.labwareOnDeck.slot + return isDifferentSlot && !props.swapBlocked + }, + drop: (monitor: DropTargetMonitor) => { + const draggedItem: any = monitor.getItem() + if (draggedItem) { + dispatch( + moveDeckItem(draggedItem.labwareOnDeck.slot, props.labwareOnDeck.slot) + ) + } + }, + + hover: (monitor: DropTargetMonitor) => { + if (monitor.canDrop()) { + props.setHoveredLabware(labwareOnDeck) + } + }, + collect: (monitor: DropTargetMonitor) => ({ + isOver: monitor.isOver(), + draggedLabware: monitor.getItem() as any, + }), + })) + if (isYetUnnamed && !isTiprack) { return ( { ) : (
)} - + dispatch(duplicateLabware(labwareOnDeck.id))} + > {t('overlay.edit.duplicate')} - + { + window.confirm( + `Are you sure you want to permanently delete this ${getLabwareDisplayName( + labwareOnDeck.def + )}?` + ) && dispatch(deleteContainer({ labwareId: labwareOnDeck.id })) + }} + > {t('overlay.edit.delete')} @@ -115,8 +147,8 @@ const EditLabwareComponent = (props: Props): JSX.Element => { ) } - return connectDragSource( - connectDropTarget( + const dragResult = drag( +
{ > {contents}
- ) +
) - } -} - -const labwareSource = { - beginDrag: (props: Props, monitor: DragSourceMonitor, component: any) => { - const { labwareOnDeck } = props - props.setDraggedLabware(labwareOnDeck) - return { labwareOnDeck } - }, - endDrag: (props: Props, monitor: DragSourceMonitor, component: any) => { - props.setHoveredLabware(null) - props.setDraggedLabware(null) - }, -} -const collectLabwareSource = ( - connect: DragSourceConnector, - monitor: DragSourceMonitor -): React.ReactNode => ({ - // @ts-expect-error(BC, 12-13-2023): react dnd needs to be updated or removed to include proper type - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), - draggedItem: monitor.getItem(), -}) -const DragEditLabware = DragSource( - DND_TYPES.LABWARE, - labwareSource, - collectLabwareSource -)(EditLabwareComponent) - -const labwareDropTarget = { - canDrop: (props: Props, monitor: DropTargetMonitor) => { - const draggedItem = monitor.getItem() - const draggedLabware = draggedItem?.labwareOnDeck - const isDifferentSlot = - draggedLabware && draggedLabware.slot !== props.labwareOnDeck.slot - return isDifferentSlot && !props.swapBlocked - }, - hover: (props: Props, monitor: DropTargetSpec, component: any) => { - if (monitor.canDrop) { - props.setHoveredLabware(component.props.labwareOnDeck) - } - }, - drop: (props: Props, monitor: DropTargetMonitor) => { - const draggedItem = monitor.getItem() - if (draggedItem) { - props.moveDeckItem( - draggedItem.labwareOnDeck.slot, - props.labwareOnDeck.slot - ) - } - }, -} -const collectLabwareDropTarget = ( - 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(), - draggedLabware: monitor.getItem()?.labwareOnDeck || null, -}) -const DragDropEditLabware = DropTarget( - DND_TYPES.LABWARE, - labwareDropTarget, - collectLabwareDropTarget -)(DragEditLabware) -const mapStateToProps = (state: BaseState, ownProps: OP): SP => { - const { id } = ownProps.labwareOnDeck - const hasName = labwareIngredSelectors.getSavedLabware(state)[id] - return { - isYetUnnamed: !ownProps.labwareOnDeck.def.parameters.isTiprack && !hasName, + return dragResult !== null ? dragResult : null } } - -const mapDispatchToProps = ( - dispatch: ThunkDispatch, - ownProps: OP -): DP => ({ - editLiquids: () => - dispatch(openIngredientSelector(ownProps.labwareOnDeck.id)), - duplicateLabware: () => dispatch(duplicateLabware(ownProps.labwareOnDeck.id)), - deleteLabware: () => { - window.confirm( - `Are you sure you want to permanently delete this ${getLabwareDisplayName( - ownProps.labwareOnDeck.def - )}?` - ) && dispatch(deleteContainer({ labwareId: ownProps.labwareOnDeck.id })) - }, - moveDeckItem: (sourceSlot, destSlot) => - dispatch(moveDeckItem(sourceSlot, destSlot)), -}) - -export const EditLabware = connect( - mapStateToProps, - mapDispatchToProps -)(DragDropEditLabware) diff --git a/protocol-designer/src/components/DeckSetup/LabwareOverlays/LabwareControls.tsx b/protocol-designer/src/components/DeckSetup/LabwareOverlays/LabwareControls.tsx index 66d84a87ab3..fc7c011811c 100644 --- a/protocol-designer/src/components/DeckSetup/LabwareOverlays/LabwareControls.tsx +++ b/protocol-designer/src/components/DeckSetup/LabwareOverlays/LabwareControls.tsx @@ -16,8 +16,8 @@ import type { CoordinateTuple } from '@opentrons/shared-data' interface LabwareControlsProps { labwareOnDeck: LabwareOnDeck slotPosition: CoordinateTuple - setHoveredLabware: (labware?: LabwareOnDeck | null) => unknown - setDraggedLabware: (labware?: LabwareOnDeck | null) => unknown + setHoveredLabware: (labware?: LabwareOnDeck | null) => void + setDraggedLabware: (labware?: LabwareOnDeck | null) => void swapBlocked: boolean selectedTerminalItemId?: TerminalItemId | null } @@ -48,7 +48,6 @@ export const LabwareControls = (props: LabwareControlsProps): JSX.Element => { > {canEdit ? ( - // @ts-expect-error(sa, 2021-6-21): react dnd type mismatch JSX.Element - draggedItem: { labwareOnDeck: LabwareOnDeck } | null - itemType: string -} - -interface OP { +interface SlotControlsProps { slotPosition: CoordinateTuple | null slotBoundingBox: Dimensions // NOTE: slotId can be either AddressableAreaName or moduleId @@ -49,33 +37,59 @@ interface OP { handleDragHover?: () => unknown } -interface DP { - addLabware: (e: React.MouseEvent) => unknown - moveDeckItem: (item1: DeckSlot, item2: DeckSlot) => unknown -} - -interface SP { - customLabwareDefs: LabwareDefByDefURI +interface DroppedItem { + labwareOnDeck: LabwareOnDeck } -export type SlotControlsProps = OP & DP & DNDP & SP - -export const SlotControlsComponent = ( - props: SlotControlsProps -): JSX.Element | null => { +export const SlotControls = (props: SlotControlsProps): JSX.Element | null => { const { slotBoundingBox, slotPosition, - addLabware, + slotId, selectedTerminalItemId, - isOver, - connectDropTarget, moduleType, - draggedItem, - itemType, - customLabwareDefs, + handleDragHover, } = props + const customLabwareDefs = useSelector( + labwareDefSelectors.getCustomLabwareDefsByURI + ) + const dispatch = useDispatch() const { t } = useTranslation('deck') + + 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 (moduleType != null && draggedDef != null) { + // this is a module slot, prevent drop if the dragged labware is not compatible + const isCustomLabware = getLabwareIsCustom( + customLabwareDefs, + item.labwareOnDeck + ) + + return getLabwareIsCompatible(draggedDef, moduleType) || isCustomLabware + } + return true + }, + drop: (item: DroppedItem) => { + if (item.labwareOnDeck) { + dispatch(moveDeckItem(item.labwareOnDeck.slot, slotId)) + } + }, + hover: () => { + if (handleDragHover) { + handleDragHover() + } + }, + collect: (monitor: DropTargetMonitor) => ({ + itemType: monitor.getItemType(), + isOver: !!monitor.isOver(), + draggedItem: monitor.getItem() as DroppedItem, + }), + })) + if ( selectedTerminalItemId !== START_TERMINAL_ITEM_ID || (itemType !== DND_TYPES.LABWARE && itemType !== null) || @@ -84,6 +98,7 @@ export const SlotControlsComponent = ( return null const draggedDef = draggedItem?.labwareOnDeck?.def + const isCustomLabware = draggedItem ? getLabwareIsCustom(customLabwareDefs, draggedItem.labwareOnDeck) : false @@ -111,8 +126,12 @@ export const SlotControlsComponent = ( overlayText = 'add_labware' } - return connectDropTarget( - + const addLabware = (): void => { + dispatch(openAddLabwareModal({ slot: slotId })) + } + + return ( + {slotBlocked ? ( ) } - -const mapStateToProps = (state: BaseState): SP => { - return { - customLabwareDefs: labwareDefSelectors.getCustomLabwareDefsByURI(state), - } -} - -const mapDispatchToProps = ( - dispatch: ThunkDispatch, - ownProps: OP -): DP => ({ - addLabware: () => dispatch(openAddLabwareModal({ slot: ownProps.slotId })), - moveDeckItem: (sourceSlot, destSlot) => - dispatch(moveDeckItem(sourceSlot, destSlot)), -}) - -const slotTarget = { - drop: (props: SlotControlsProps, monitor: DropTargetMonitor) => { - const draggedItem = monitor.getItem() - if (draggedItem) { - props.moveDeckItem(draggedItem.labwareOnDeck.slot, props.slotId) - } - }, - hover: (props: SlotControlsProps) => { - if (props.handleDragHover) { - props.handleDragHover() - } - }, - canDrop: (props: SlotControlsProps, monitor: DropTargetMonitor) => { - const draggedItem = monitor.getItem() - const draggedDef = draggedItem?.labwareOnDeck?.def - const moduleType = props.moduleType - assert(draggedDef, 'no labware def of dragged item, expected it on drop') - - if (moduleType != null && draggedDef != null) { - // this is a module slot, prevent drop if the dragged labware is not compatible - const isCustomLabware = getLabwareIsCustom( - props.customLabwareDefs, - draggedItem.labwareOnDeck - ) - - return getLabwareIsCompatible(draggedDef, moduleType) || 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 SlotControls = connect( - mapStateToProps, - mapDispatchToProps -)( - DropTarget( - DND_TYPES.LABWARE, - slotTarget, - collectSlotTarget - )(SlotControlsComponent) -) diff --git a/protocol-designer/src/components/DeckSetup/index.tsx b/protocol-designer/src/components/DeckSetup/index.tsx index 8044c838050..895f46e1954 100644 --- a/protocol-designer/src/components/DeckSetup/index.tsx +++ b/protocol-designer/src/components/DeckSetup/index.tsx @@ -265,7 +265,6 @@ export const DeckSetupContents = (props: ContentsProps): JSX.Element => { labwareOnDeck={labwareLoadedOnModule} /> {isAdapter ? ( - // @ts-expect-error { {labwareLoadedOnModule == null && !shouldHideChildren && !isAdapter ? ( - // @ts-expect-error { }) .map(addressableArea => { return ( - // @ts-expect-error { /> {labwareIsAdapter ? ( - // @ts-expect-error ( + + + ) diff --git a/protocol-designer/src/components/steplist/DraggableStepItems.tsx b/protocol-designer/src/components/steplist/DraggableStepItems.tsx index 62a757cb82a..9532a40bc1f 100644 --- a/protocol-designer/src/components/steplist/DraggableStepItems.tsx +++ b/protocol-designer/src/components/steplist/DraggableStepItems.tsx @@ -1,129 +1,109 @@ import * as React from 'react' -import { connect } from 'react-redux' +import { useSelector } from 'react-redux' import { - DragSource, - DropTarget, - DragLayer, DragLayerMonitor, - DragSourceConnector, - DragSourceMonitor, - DropTargetConnector, DropTargetMonitor, - DragElementWrapper, - DragSourceOptions, - ConnectDropTarget, + useDrop, + useDrag, } from 'react-dnd' import isEqual from 'lodash/isEqual' import { DND_TYPES } from '../../constants' -import { ConnectedStepItem } from '../../containers/ConnectedStepItem' -import { PDTitledList } from '../lists' -import { stepIconsByType, StepIdType, StepType } from '../../form-types' import { selectors as stepFormSelectors } from '../../step-forms' -import { BaseState } from '../../types' +import { stepIconsByType, StepIdType } from '../../form-types' +import { + ConnectedStepItem, + ConnectedStepItemProps, +} from '../../containers/ConnectedStepItem' +import { PDTitledList } from '../lists' import { ContextMenu } from './ContextMenu' + import styles from './StepItem.css' -type DragDropStepItemProps = React.ComponentProps & { - connectDragSource: (val: unknown) => React.ReactElement - connectDropTarget: (val: unknown) => React.ReactElement +interface DragDropStepItemProps extends ConnectedStepItemProps { stepId: StepIdType stepNumber: number - isDragging: boolean findStepIndex: (stepIdType: StepIdType) => number onDrag: () => void moveStep: (stepId: StepIdType, value: number) => void } -const DragSourceStepItem = (props: DragDropStepItemProps): any => - props.connectDragSource( - props.connectDropTarget( -
- +const DragDropStepItem = (props: DragDropStepItemProps): JSX.Element => { + const { onDrag, stepId, findStepIndex, moveStep } = props + console.log('stepId', stepId) + const [{ isDragging }, drag] = useDrag(() => ({ + type: DND_TYPES.STEP_ITEM, + beginDrag: () => { + onDrag() + return { stepId: stepId } + }, + collect: (monitor: DragLayerMonitor) => ({ + isDragging: monitor.isDragging(), + }), + })) + + const [, drop] = useDrop(() => ({ + accept: DND_TYPES.STEP_ITEM, + canDrop: () => { + return false + }, + hover: (item: any) => { + console.log('item', item) + const draggedId = item.stepId + + if (draggedId !== stepId) { + const overIndex = findStepIndex(stepId) + moveStep(draggedId, overIndex) + } + }, + })) + + return ( +
+
+
- ) +
) - -const stepItemSource = { - beginDrag: (props: DragDropStepItemProps) => { - props.onDrag() - return { stepId: props.stepId } - }, } -const collectStepSource = ( - connect: DragSourceConnector, - monitor: DragSourceMonitor -): { - connectDragSource: DragElementWrapper - isDragging: boolean -} => ({ - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), -}) -const DraggableStepItem = DragSource( - DND_TYPES.STEP_ITEM, - stepItemSource, - collectStepSource -)(DragSourceStepItem) - -const stepItemTarget = { - canDrop: () => { - return false - }, - hover: (props: DragDropStepItemProps, monitor: DropTargetMonitor) => { - const { stepId: draggedId } = monitor.getItem() - const { stepId: overId } = props - - if (draggedId !== overId) { - const overIndex = props.findStepIndex(overId) - props.moveStep(draggedId, overIndex) - } - }, -} -const collectStepTarget = ( - connect: DropTargetConnector -): { connectDropTarget: ReturnType } => ({ - connectDropTarget: connect.dropTarget(), -}) -const DragDropStepItem = DropTarget( - DND_TYPES.STEP_ITEM, - stepItemTarget, - collectStepTarget -)(DraggableStepItem) interface StepItemsProps { orderedStepIds: StepIdType[] - reorderSteps: (steps: StepIdType[]) => unknown - isOver: boolean - connectDropTarget: (val: unknown) => React.ReactElement -} -interface StepItemsState { - stepIds: StepIdType[] + reorderSteps: (steps: StepIdType[]) => void } -class StepItems extends React.Component { - constructor(props: StepItemsProps) { - super(props) - this.state = { stepIds: this.props.orderedStepIds } - } +export const DraggableStepItems = (props: StepItemsProps): JSX.Element => { + const { orderedStepIds, reorderSteps } = props + const [stepIds, setStepIds] = React.useState(orderedStepIds) - onDrag = (): void => { - this.setState({ stepIds: this.props.orderedStepIds }) + const onDrag = (): void => { + setStepIds(orderedStepIds) } - submitReordering = (): void => { + const submitReordering = (): void => { if ( confirm( 'Are you sure you want to reorder these steps, it may cause errors?' ) ) { - this.props.reorderSteps(this.state.stepIds) + reorderSteps(stepIds) } } + const [{ isOver }, drop] = useDrop(() => ({ + accept: DND_TYPES.STEP_ITEM, + drop: () => { + if (!isEqual(orderedStepIds, stepIds)) { + submitReordering() + } + }, + collect: (monitor: DropTargetMonitor) => ({ + isOver: !!monitor.isOver(), + }), + })) + // TODO: BC 2018-11-27 make util function for reordering and use it in hotkey implementation too - moveStep = (stepId: StepIdType, targetIndex: number): void => { - const { stepIds } = this.state - const currentIndex = this.findStepIndex(stepId) + const moveStep = (stepId: StepIdType, targetIndex: number): void => { + const currentIndex = findStepIndex(stepId) const currentRemoved = [ ...stepIds.slice(0, currentIndex), ...stepIds.slice(currentIndex + 1, stepIds.length), @@ -133,62 +113,54 @@ class StepItems extends React.Component { stepId, ...currentRemoved.slice(targetIndex, currentRemoved.length), ] - this.setState({ stepIds: currentReinserted }) + setStepIds(currentReinserted) } - findStepIndex = (stepId: StepIdType): number => - this.state.stepIds.findIndex(id => stepId === id) + const findStepIndex = (stepId: StepIdType): number => + stepIds.findIndex(id => stepId === id) - render(): React.ReactNode { - const currentIds = this.props.isOver - ? this.state.stepIds - : this.props.orderedStepIds - return this.props.connectDropTarget( -
- - {({ makeStepOnContextMenu }) => - currentIds.map((stepId: StepIdType, index: number) => ( - - )) - } - - -
- ) - } + const currentIds = isOver ? stepIds : orderedStepIds + console.log('stepIds', stepIds) + console.log('currentStepIds', currentIds) + return ( +
+ + {({ makeStepOnContextMenu }) => + currentIds.map((stepId: StepIdType, index: number) => ( + makeStepOnContextMenu(stepId)} + findStepIndex={findStepIndex} + onDrag={onDrag} + moveStep={moveStep} + /> + )) + } + + +
+ ) } const NAV_OFFSET = 64 -interface StepDragPreviewSP { - stepType: StepType | null | undefined - stepName: string | null | undefined -} - -interface StepDragPreviewOP { - currentOffset?: { y: number; x: number } - itemType: string - isDragging: boolean - item: { stepId: StepIdType } -} - -type StepDragPreviewProps = StepDragPreviewOP & StepDragPreviewSP -type DraggableStepItemProps = Omit< - StepItemsProps, - 'isOver' | 'connectDropTarget' -> +const StepDragPreview = (): JSX.Element | null => { + const [{ isDragging, itemType, item, currentOffset }] = useDrag(() => ({ + type: DND_TYPES.STEP_ITEM, + collect: (monitor: DragLayerMonitor) => ({ + currentOffset: monitor.getSourceClientOffset(), + isDragging: monitor.isDragging(), + itemType: monitor.getItemType(), + item: monitor.getItem() as { stepId: StepIdType }, + }), + })) + + const savedStepForms = useSelector(stepFormSelectors.getSavedStepForms) + const savedForm = item && savedStepForms[item.stepId] + const { stepType, stepName } = savedForm || {} -const StepDragPreview = (props: StepDragPreviewProps): JSX.Element | null => { - const { itemType, isDragging, currentOffset, stepType, stepName } = props if ( itemType !== DND_TYPES.STEP_ITEM || !isDragging || @@ -210,47 +182,3 @@ const StepDragPreview = (props: StepDragPreviewProps): JSX.Element | null => {
) } - -const mapSTPForPreview = ( - state: BaseState, - ownProps: StepDragPreviewProps -): StepDragPreviewSP => { - const savedForm = - ownProps.item && - stepFormSelectors.getSavedStepForms(state)[ownProps.item.stepId] - const { stepType, stepName } = savedForm || {} - return { stepType, stepName } -} - -export const StepDragPreviewLayer = DragLayer((monitor: DragLayerMonitor) => ({ - currentOffset: monitor.getSourceClientOffset(), - isDragging: monitor.isDragging(), - itemType: monitor.getItemType(), - item: monitor.getItem(), -}))(connect(mapSTPForPreview)(StepDragPreview)) - -const listTarget = { - drop: ( - props: DraggableStepItemProps, - monitor: DragLayerMonitor, - component: StepItems - ) => { - if (!isEqual(props.orderedStepIds, component.state.stepIds)) { - component.submitReordering() - } - }, -} -const collectListTarget = ( - connect: DropTargetConnector, - monitor: DropTargetMonitor -): { isOver: boolean; connectDropTarget: ConnectDropTarget } => ({ - isOver: monitor.isOver(), - connectDropTarget: connect.dropTarget(), -}) - -export const DraggableStepItems = DropTarget( - DND_TYPES.STEP_ITEM, - // @ts-expect-error(sa, 2021-6-21): fix when updating react dnd to hooks api - listTarget, - collectListTarget -)(StepItems) diff --git a/protocol-designer/src/containers/ConnectedStepItem.tsx b/protocol-designer/src/containers/ConnectedStepItem.tsx index b871e77c5cc..27ea034b099 100644 --- a/protocol-designer/src/containers/ConnectedStepItem.tsx +++ b/protocol-designer/src/containers/ConnectedStepItem.tsx @@ -45,7 +45,7 @@ import { BaseState, ThunkAction } from '../types' import { getAdditionalEquipmentEntities } from '../step-forms/selectors' import { ThunkDispatch } from 'redux-thunk' -interface Props { +export interface ConnectedStepItemProps { stepId: StepIdType stepNumber: number onStepContextMenu?: () => void @@ -66,7 +66,9 @@ const getMouseClickKeyInfo = ( return { isShiftKeyPressed, isMetaKeyPressed } } -export const ConnectedStepItem = (props: Props): JSX.Element => { +export const ConnectedStepItem = ( + props: ConnectedStepItemProps +): JSX.Element => { const { stepId, stepNumber } = props const step = useSelector(stepFormSelectors.getSavedStepForms)[stepId] diff --git a/yarn.lock b/yarn.lock index b218f7b6a12..d5148bc255a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1726,6 +1726,11 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@hookform/resolvers@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.1.1.tgz#b374d33e356428fff9c6ef3c933441fe15e40784" + integrity sha512-tS16bAUkqjITNSvbJuO1x7MXbn7Oe8ZziDTJdA9mMvsoYthnOOiznOTGBYwbdlYBgU+tgpI/BtTU3paRbCuSlg== + "@humanwhocodes/config-array@^0.11.13": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -1744,10 +1749,6 @@ version "2.0.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== -"@hookform/resolvers@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-3.1.1.tgz#b374d33e356428fff9c6ef3c933441fe15e40784" - integrity sha512-tS16bAUkqjITNSvbJuO1x7MXbn7Oe8ZziDTJdA9mMvsoYthnOOiznOTGBYwbdlYBgU+tgpI/BtTU3paRbCuSlg== "@hutson/parse-repository-url@^3.0.0": version "3.0.2" @@ -2371,6 +2372,21 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.1.1.tgz#12c572ab88ef7345b43f21883fca26631c223085" integrity sha512-sLqWxCzC5/QHLhziXSCAksBxHfOnQlhPRVgPK0egEw+ktWvG75T2k+aYWVjVh9+WKeT3tlG3ZNbZQvZLmfuOIw== +"@react-dnd/asap@^5.0.1": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-5.0.2.tgz#1f81f124c1cd6f39511c11a881cfb0f715343488" + integrity sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A== + +"@react-dnd/invariant@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-4.0.2.tgz#b92edffca10a26466643349fac7cdfb8799769df" + integrity sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw== + +"@react-dnd/shallowequal@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz#d1b4befa423f692fa4abf1c79209702e7d8ae4b4" + integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA== + "@react-spring/animated@~9.6.1": version "9.6.1" resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.6.1.tgz#ccc626d847cbe346f5f8815d0928183c647eb425" @@ -5215,7 +5231,7 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.6, asap@~2.0.3: +asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -6500,11 +6516,6 @@ chalk@^4.0.2, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" -change-emitter@^0.1.2: - version "0.1.6" - resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515" - integrity sha1-6LL+PX8at9aaMhma/5HqaTFAlRU= - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -8492,15 +8503,14 @@ dmg-license@^1.0.11: smart-buffer "^4.0.2" verror "^1.10.0" -dnd-core@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-6.0.0.tgz#d347266ebd72f0a2de6ecf5e26e4ef006ebde84b" - integrity sha512-WnnFSbnC3grP/XJ+xfxgM8DyIsts3Q/rfgE6WGRWs6tCQcwILputNNm/Kw+WPS2N1e46hRy5iPl2pYwkP9kK9Q== +dnd-core@^16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-16.0.1.tgz#a1c213ed08961f6bd1959a28bb76f1a868360d19" + integrity sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng== dependencies: - asap "^2.0.6" - invariant "^2.2.4" - lodash "^4.17.11" - redux "^4.0.1" + "@react-dnd/asap" "^5.0.1" + "@react-dnd/invariant" "^4.0.1" + redux "^4.2.0" dns-equal@^1.0.0: version "1.0.0" @@ -10011,7 +10021,7 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -fbjs@^0.8.0, fbjs@^0.8.1: +fbjs@^0.8.0: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90= @@ -11592,11 +11602,6 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^2.3.1: - version "2.5.5" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" - integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== - hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -12199,7 +12204,7 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.1.0, invariant@^2.2.1, invariant@^2.2.4: +invariant@^2.2.1, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -15139,13 +15144,6 @@ node-abi@^3.45.0: dependencies: semver "^7.3.5" -node-abi@^3.45.0: - version "3.54.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.54.0.tgz#f6386f7548817acac6434c6cba02999c9aebcc69" - integrity sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA== - dependencies: - semver "^7.3.5" - node-addon-api@^1.6.3: version "1.7.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d" @@ -17518,22 +17516,21 @@ react-color@2.19.3: reactcss "^1.2.0" tinycolor2 "^1.4.1" -react-dnd-mouse-backend@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/react-dnd-mouse-backend/-/react-dnd-mouse-backend-0.1.2.tgz#bf79e5cc20715fb1bc03f3ba20389cc5b062f5da" - integrity sha512-A1kgknzYKysVgqwHnB7aFzNmV0/CBK5rJdsCSAIxZxJYaNqymfFgtDD5KneR4dVEva2nFvJXH5th1uYGH4DZGQ== +react-dnd-mouse-backend@1.0.0-rc.2: + version "1.0.0-rc.2" + resolved "https://registry.yarnpkg.com/react-dnd-mouse-backend/-/react-dnd-mouse-backend-1.0.0-rc.2.tgz#bc114d2e91ee6d079adc6920c22167a9780185af" + integrity sha512-mmbyXvg6YGKxdi7gx+ICFD0pFEMMiG1x7FBSu8ZYXBCqxVPkm8pkhrHfzd8AY89YmcWoUeqL3/DSU0u9lkwbsQ== -react-dnd@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-6.0.0.tgz#0780eafaa47293bf12dc8f79cf1e48ede8ba72f1" - integrity sha512-XI14rxF5eeGk8045xh/6KbjfLSzgkfNdQCqwkR5qAvBf0QYvkGAUz1AQfLrQudFs/DVw7WiCoCohRzJR1Kyn9Q== +react-dnd@16.0.1: + version "16.0.1" + resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-16.0.1.tgz#2442a3ec67892c60d40a1559eef45498ba26fa37" + integrity sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q== dependencies: - dnd-core "^6.0.0" - hoist-non-react-statics "^3.1.0" - invariant "^2.1.0" - lodash "^4.17.11" - recompose "^0.30.0" - shallowequal "^1.1.0" + "@react-dnd/invariant" "^4.0.1" + "@react-dnd/shallowequal" "^4.0.1" + dnd-core "^16.0.1" + fast-deep-equal "^3.1.3" + hoist-non-react-statics "^3.3.2" react-docgen-typescript@^1.21.0: version "1.22.0" @@ -17640,11 +17637,6 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-lifecycles-compat@^3.0.2: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - react-popper@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.0.0.tgz#b99452144e8fe4acc77fa3d959a8c79e07a65084" @@ -17938,18 +17930,6 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -recompose@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" - integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== - dependencies: - "@babel/runtime" "^7.0.0" - change-emitter "^0.1.2" - fbjs "^0.8.1" - hoist-non-react-statics "^2.3.1" - react-lifecycles-compat "^3.0.2" - symbol-observable "^1.0.4" - redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -18014,13 +17994,20 @@ redux@4.0.5: loose-envify "^1.4.0" symbol-observable "^1.2.0" -redux@^4.0.0, redux@^4.0.1, redux@^4.0.5: +redux@^4.0.0, redux@^4.0.5: version "4.1.0" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4" integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g== dependencies: "@babel/runtime" "^7.9.2" +redux@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" @@ -20267,7 +20254,7 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" -symbol-observable@^1.0.4, symbol-observable@^1.1.0, symbol-observable@^1.2.0: +symbol-observable@^1.1.0, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==