diff --git a/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx b/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx index f2f1287457c..9eee7a7806d 100644 --- a/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx +++ b/app/src/organisms/QuickTransferFlow/SelectSourceWells.tsx @@ -60,19 +60,12 @@ export function SelectSourceWells(props: SelectSourceWellsProps): JSX.Element { > {state.source != null ? ( { setSelectedWells(prevWells => ({ ...prevWells, ...wellGroup })) }} - deselectWells={wellGroup => { - setSelectedWells(wellGroup) - }} - updateHighlightedWells={wellGroup => { - console.log(wellGroup) - }} nozzleType={null} - wellContents={{}} /> ) : null} diff --git a/app/src/organisms/WellSelection/SelectionRect.tsx b/app/src/organisms/WellSelection/SelectionRect.tsx index 3ca6b5c5b93..2a8dc1f59d0 100644 --- a/app/src/organisms/WellSelection/SelectionRect.tsx +++ b/app/src/organisms/WellSelection/SelectionRect.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import type { DragRect, GenericRect } from './types' interface SelectionRectProps { - onSelectionMove?: (e: MouseEvent, arg: GenericRect) => void - onSelectionDone?: (e: MouseEvent, arg: GenericRect) => void + onSelectionMove?: (rect: GenericRect) => void + onSelectionDone?: (rect: GenericRect) => void children?: React.ReactNode } @@ -33,7 +33,7 @@ export function SelectionRect(props: SelectionRectProps): JSX.Element { yDynamic: e.clientY, } const rect = getRect(nextRect) - onSelectionMove && onSelectionMove(e, rect) + onSelectionMove && onSelectionMove(rect) return nextRect } @@ -50,7 +50,7 @@ export function SelectionRect(props: SelectionRectProps): JSX.Element { return prevPositions === positions ? null : prevPositions }) // call onSelectionDone callback with {x0, x1, y0, y1} of final selection rectangle - onSelectionDone && finalRect && onSelectionDone(e, finalRect) + onSelectionDone && finalRect && onSelectionDone(finalRect) } const handleMouseDown: React.MouseEventHandler = e => { diff --git a/app/src/organisms/WellSelection/index.tsx b/app/src/organisms/WellSelection/index.tsx index ec093a2fa34..fd7013d0725 100644 --- a/app/src/organisms/WellSelection/index.tsx +++ b/app/src/organisms/WellSelection/index.tsx @@ -15,21 +15,16 @@ import { } from './utils' import { SelectionRect } from './SelectionRect' -import type { WellMouseEvent, WellFill, WellGroup } from '@opentrons/components' -import type { ContentsByWell, GenericRect, NozzleType } from './types' +import type { WellFill, WellGroup, WellStroke } from '@opentrons/components' +import type { LabwareDefinition2 } from '@opentrons/shared-data' +import type { GenericRect, NozzleType } from './types' interface WellSelectionProps { - labwareProps: Omit< - React.ComponentProps, - 'selectedWells' - > + definition: LabwareDefinition2 /** array of primary wells. Overrides labwareProps.selectedWells */ selectedPrimaryWells: WellGroup selectWells: (wellGroup: WellGroup) => unknown - deselectWells: (wellGroup: WellGroup) => unknown - updateHighlightedWells: (wellGroup: WellGroup) => unknown nozzleType: NozzleType | null - wellContents: ContentsByWell } type ChannelType = 8 | 96 @@ -43,16 +38,9 @@ const getChannelsFromNozzleType = (nozzleType: NozzleType): ChannelType => { } export function WellSelection(props: WellSelectionProps): JSX.Element { - const { - labwareProps, - selectedPrimaryWells, - selectWells, - deselectWells, - updateHighlightedWells, - nozzleType, - wellContents, - } = props - const labwareDef = labwareProps.definition + const { definition, selectedPrimaryWells, selectWells, nozzleType } = props + + const [highlightedWells, setHighlightedWells] = React.useState({}) const _wellsFromSelected: ( selectedWells: WellGroup @@ -66,7 +54,7 @@ export function WellSelection(props: WellSelectionProps): JSX.Element { selectedWells, (acc: WellGroup, _, wellName: string): WellGroup => { const wellSet = getWellSetForMultichannel( - labwareDef, + definition, wellName, channels ) @@ -87,61 +75,36 @@ export function WellSelection(props: WellSelectionProps): JSX.Element { return _wellsFromSelected(selectedWells) } - const handleSelectionMove: (e: MouseEvent, rect: GenericRect) => void = ( - e, - rect - ) => { - if (!e.shiftKey) { - if (nozzleType != null) { - const channels = getChannelsFromNozzleType(nozzleType) - const selectedWells = _getWellsFromRect(rect) - const allWellsForMulti: WellGroup = reduce( - selectedWells, - (acc: WellGroup, _, wellName: string): WellGroup => { - const wellSetForMulti = - getWellSetForMultichannel(labwareDef, wellName, channels) || [] - const channelWells = arrayToWellGroup(wellSetForMulti) - return { - ...acc, - ...channelWells, - } - }, - {} - ) - updateHighlightedWells(allWellsForMulti) - } else { - updateHighlightedWells(_getWellsFromRect(rect)) - } - } - } - - const handleSelectionDone: (e: MouseEvent, rect: GenericRect) => void = ( - e, - rect - ) => { - const wells = _wellsFromSelected(_getWellsFromRect(rect)) - if (e.shiftKey) { - deselectWells(wells) - } else { - selectWells(wells) - } - } - - const handleMouseEnterWell: (args: WellMouseEvent) => void = args => { + const handleSelectionMove: (rect: GenericRect) => void = rect => { if (nozzleType != null) { const channels = getChannelsFromNozzleType(nozzleType) - const wellSet = getWellSetForMultichannel( - labwareDef, - args.wellName, - channels + const selectedWells = _getWellsFromRect(rect) + const allWellsForMulti: WellGroup = reduce( + selectedWells, + (acc: WellGroup, _, wellName: string): WellGroup => { + const wellSetForMulti = + getWellSetForMultichannel(definition, wellName, channels) || [] + const channelWells = arrayToWellGroup(wellSetForMulti) + return { + ...acc, + ...channelWells, + } + }, + {} ) - const nextHighlightedWells = arrayToWellGroup(wellSet || []) - nextHighlightedWells && updateHighlightedWells(nextHighlightedWells) + setHighlightedWells(allWellsForMulti) } else { - updateHighlightedWells({ [args.wellName]: null }) + setHighlightedWells(_getWellsFromRect(rect)) } } + const handleSelectionDone: (rect: GenericRect) => void = rect => { + const wells = _wellsFromSelected(_getWellsFromRect(rect)) + + selectWells(wells) + setHighlightedWells({}) + } + // For rendering, show all wells not just primary wells const allSelectedWells = nozzleType != null @@ -150,7 +113,7 @@ export function WellSelection(props: WellSelectionProps): JSX.Element { (acc, _, wellName): WellGroup => { const channels = getChannelsFromNozzleType(nozzleType) const wellSet = getWellSetForMultichannel( - labwareDef, + definition, wellName, channels ) @@ -162,12 +125,17 @@ export function WellSelection(props: WellSelectionProps): JSX.Element { : selectedPrimaryWells const wellFill: WellFill = {} - Object.keys(labwareProps.definition.wells).forEach(wellName => { + const wellStroke: WellStroke = {} + Object.keys(definition.wells).forEach(wellName => { wellFill[wellName] = COLORS.blue35 + wellStroke[wellName] = COLORS.transparent }) Object.keys(allSelectedWells).forEach(wellName => { wellFill[wellName] = COLORS.blue50 }) + Object.keys(highlightedWells).forEach(wellName => { + wellFill[wellName] = COLORS.blue50 + }) return ( { - updateHighlightedWells({}) - }} - onMouseEnterWell={({ wellName, event }) => { - if (wellContents !== null) { - handleMouseEnterWell({ wellName, event }) - } - }} hideOutline + isInteractive wellLabelOption={WELL_LABEL_OPTIONS.SHOW_LABEL_INSIDE} wellFill={wellFill} + wellStroke={wellStroke} /> diff --git a/components/src/hardware-sim/Labware/LabwareRender.tsx b/components/src/hardware-sim/Labware/LabwareRender.tsx index 853beeab858..b281aa8583f 100644 --- a/components/src/hardware-sim/Labware/LabwareRender.tsx +++ b/components/src/hardware-sim/Labware/LabwareRender.tsx @@ -60,10 +60,12 @@ export interface LabwareRenderProps { onLabwareClick?: () => void /** Hide labware outline */ hideOutline?: boolean + /** Provides well data attribute */ + isInteractive?: boolean } export const LabwareRender = (props: LabwareRenderProps): JSX.Element => { - const { gRef, definition, hideOutline } = props + const { gRef, definition, hideOutline, isInteractive } = props const cornerOffsetFromSlot = definition.cornerOffsetFromSlot const labwareLoadName = definition.parameters.loadName @@ -97,6 +99,7 @@ export const LabwareRender = (props: LabwareRenderProps): JSX.Element => { transform={`translate(${cornerOffsetFromSlot.x}, ${cornerOffsetFromSlot.y})`} ref={gRef} > + {/* TODO(bh, 2024-05-13): refactor rendering of wells - multiple layers of styled wells, DOM ordering determines which are visible */} { onLabwareClick={props.onLabwareClick} highlight={props.highlight} hideOutline={hideOutline} + isInteractive={isInteractive} /> {props.wellStroke != null ? ( unknown /** Optional callback to be executed when mouse leaves a well element */ onMouseLeaveWell?: (e: WellMouseEvent) => unknown + /** Provides well data attribute */ + isInteractive?: boolean } const TipDecoration = React.memo(function TipDecoration(props: { @@ -55,6 +57,7 @@ export function StaticLabwareComponent(props: StaticLabwareProps): JSX.Element { definition, hideOutline = false, highlight, + isInteractive, onLabwareClick, onMouseEnterWell, onMouseLeaveWell, @@ -80,6 +83,7 @@ export function StaticLabwareComponent(props: StaticLabwareProps): JSX.Element { well={definition.wells[wellName]} onMouseEnterWell={onMouseEnterWell} onMouseLeaveWell={onMouseLeaveWell} + isInteractive={isInteractive} {...(isTiprack ? STYLE_BY_WELL_CONTENTS.tipPresent : STYLE_BY_WELL_CONTENTS.defaultWell)} diff --git a/components/src/hardware-sim/Labware/labwareInternals/Well.tsx b/components/src/hardware-sim/Labware/labwareInternals/Well.tsx index 53d3dcdf688..5a7d8760646 100644 --- a/components/src/hardware-sim/Labware/labwareInternals/Well.tsx +++ b/components/src/hardware-sim/Labware/labwareInternals/Well.tsx @@ -16,6 +16,8 @@ export interface WellProps extends StyleProps { /** Optional callback, called with WellMouseEvent args onMouseOver */ onMouseEnterWell?: (e: WellMouseEvent) => unknown onMouseLeaveWell?: (e: WellMouseEvent) => unknown + /** Provides well data attribute */ + isInteractive?: boolean } export function WellComponent(props: WellProps): JSX.Element { @@ -27,10 +29,10 @@ export function WellComponent(props: WellProps): JSX.Element { fill = COLORS.white, onMouseEnterWell, onMouseLeaveWell, + isInteractive = onMouseEnterWell != null || onMouseLeaveWell != null, } = props const { x, y } = well - const isInteractive = onMouseEnterWell != null || onMouseLeaveWell != null const pointerEvents: React.CSSProperties['pointerEvents'] = isInteractive ? 'auto' : 'none'