From 3ef9ad614364673f899293cb7d45b64ab42a985c Mon Sep 17 00:00:00 2001 From: Brent Hagen Date: Fri, 2 Aug 2024 14:36:23 -0400 Subject: [PATCH] feat(components): migrate LocationIcon to DeckInfoLabel (#15846) updates and renames the location icon component to reflect helix/ODD styles closes PLAT-370, PLAT-408, RQA-2827 --- .../InterventionContent/InterventionInfo.tsx | 18 ++-- .../Devices/HistoricalProtocolRunDrawer.tsx | 4 +- .../SetupLabware/LabwareListItem.tsx | 8 +- .../__tests__/LabwareListItem.test.tsx | 4 +- .../shared/LeftColumnLabwareInfo.tsx | 2 +- .../__tests__/LeftColumnLabwareInfo.test.tsx | 4 +- .../MoveLabwareInterventionContent.tsx | 8 +- .../LabwarePositionCheck/ResultsSummary.tsx | 6 +- .../organisms/ProtocolSetupLabware/index.tsx | 30 +++--- .../ProtocolSetupLiquids/LiquidDetails.tsx | 4 +- .../FixtureTable.tsx | 4 +- .../ModuleTable.tsx | 6 +- app/src/pages/ProtocolDetails/Hardware.tsx | 8 +- .../pages/QuickTransferDetails/Hardware.tsx | 8 +- .../src/atoms/StyledText/StyledText.tsx | 19 +++- .../src/hardware-sim/Deck/SlotLabels.tsx | 38 ++------ .../helix-design-system/product/typography.ts | 7 ++ components/src/icons/ModuleIcon.tsx | 13 ++- .../DeckInfoLabel.stories.tsx} | 52 +++++----- .../__tests__/DeckInfoLabel.test.tsx | 49 ++++++++++ .../src/molecules/DeckInfoLabel/index.tsx | 94 +++++++++++++++++++ .../__tests__/LocationIcon.test.tsx | 52 ---------- .../src/molecules/LocationIcon/index.tsx | 89 ------------------ components/src/molecules/index.ts | 2 +- .../src/ui-style-constants/typography.ts | 1 - .../src/components/DeckSetup/SlotLabels.tsx | 18 ++-- 26 files changed, 276 insertions(+), 272 deletions(-) rename components/src/molecules/{LocationIcon/LocationIcon.stories.tsx => DeckInfoLabel/DeckInfoLabel.stories.tsx} (57%) create mode 100644 components/src/molecules/DeckInfoLabel/__tests__/DeckInfoLabel.test.tsx create mode 100644 components/src/molecules/DeckInfoLabel/index.tsx delete mode 100644 components/src/molecules/LocationIcon/__tests__/LocationIcon.test.tsx delete mode 100644 components/src/molecules/LocationIcon/index.tsx diff --git a/app/src/molecules/InterventionModal/InterventionContent/InterventionInfo.tsx b/app/src/molecules/InterventionModal/InterventionContent/InterventionInfo.tsx index aa6ad81c97e..1031519602a 100644 --- a/app/src/molecules/InterventionModal/InterventionContent/InterventionInfo.tsx +++ b/app/src/molecules/InterventionModal/InterventionContent/InterventionInfo.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { css } from 'styled-components' import { - LocationIcon, + DeckInfoLabel, Flex, Icon, COLORS, @@ -15,14 +15,14 @@ import { } from '@opentrons/components' import { Divider } from '../../../atoms/structure/Divider' -import type { LocationIconProps } from '@opentrons/components' +import type { DeckInfoLabelProps } from '@opentrons/components' export interface InterventionInfoProps { type: 'location-arrow-location' | 'location-colon-location' | 'location' labwareName: string labwareNickname?: string - currentLocationProps: LocationIconProps - newLocationProps?: LocationIconProps + currentLocationProps: DeckInfoLabelProps + newLocationProps?: DeckInfoLabelProps } export function InterventionInfo(props: InterventionInfoProps): JSX.Element { @@ -96,9 +96,9 @@ const buildLocArrowLoc = (props: InterventionInfoProps): JSX.Element => { } `} > - + - + ) } else { @@ -111,7 +111,7 @@ const buildLoc = ({ }: InterventionInfoProps): JSX.Element => { return ( - + ) } @@ -130,9 +130,9 @@ const buildLocColonLoc = (props: InterventionInfoProps): JSX.Element => { } `} > - + - + ) } else { diff --git a/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx b/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx index a2d897ca283..6171e7d6e01 100644 --- a/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx +++ b/app/src/organisms/Devices/HistoricalProtocolRunDrawer.tsx @@ -9,12 +9,12 @@ import { BORDERS, Box, COLORS, + DeckInfoLabel, DIRECTION_COLUMN, Flex, InfoScreen, JUSTIFY_FLEX_START, LegacyStyledText, - LocationIcon, OVERFLOW_HIDDEN, SPACING, TYPOGRAPHY, @@ -254,7 +254,7 @@ export function HistoricalProtocolRunDrawer( gridGap={SPACING.spacing4} alignItems={ALIGN_CENTER} > - + {offset.location.moduleModel != null ? getModuleDisplayName(offset.location.moduleModel) diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx index 32c3d434c35..651657d4597 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/LabwareListItem.tsx @@ -6,8 +6,8 @@ import { ALIGN_CENTER, BORDERS, Btn, - LocationIcon, COLORS, + DeckInfoLabel, DIRECTION_COLUMN, DIRECTION_ROW, DISPLAY_FLEX, @@ -270,7 +270,7 @@ export function LabwareListItem( {slotInfo != null && isFlex ? ( - + ) : ( )} {nestedLabwareInfo != null || moduleDisplayName != null ? ( - + ) : null} {moduleType != null ? ( - ) : null} diff --git a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx index 108439c1262..0a83231dee5 100644 --- a/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx +++ b/app/src/organisms/Devices/ProtocolRun/SetupLabware/__tests__/LabwareListItem.test.tsx @@ -172,7 +172,7 @@ describe('LabwareListItem', () => { }) screen.getByText('Mock Labware Definition') screen.getByTestId('slot_info_7') - screen.getByTestId('LocationIcon_stacked') + screen.getByTestId('DeckInfoLabel_stacked') screen.getByText('Magnetic Module GEN1') const button = screen.getByText('Secure labware instructions') fireEvent.click(button) @@ -207,7 +207,7 @@ describe('LabwareListItem', () => { }) screen.getByText('Mock Labware Definition') screen.getByTestId('slot_info_7') - screen.getByTestId('LocationIcon_stacked') + screen.getByTestId('DeckInfoLabel_stacked') screen.getByText('Temperature Module GEN1') screen.getByText('nickName') }) diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/LeftColumnLabwareInfo.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/LeftColumnLabwareInfo.tsx index 2c38ec645c6..9363bdf7e50 100644 --- a/app/src/organisms/ErrorRecoveryFlows/shared/LeftColumnLabwareInfo.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/shared/LeftColumnLabwareInfo.tsx @@ -44,7 +44,7 @@ export function LeftColumnLabwareInfo({ type, labwareName: failedLabwareName ?? '', labwareNickname: failedLabwareNickname ?? '', - currentLocationProps: { slotName: buildLabwareLocationSlotName() }, + currentLocationProps: { deckLabel: buildLabwareLocationSlotName() }, }} notificationProps={ bannerText ? { type: 'alert', heading: bannerText } : undefined diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/LeftColumnLabwareInfo.test.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/LeftColumnLabwareInfo.test.tsx index 0edf9b95236..30aae62a9ca 100644 --- a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/LeftColumnLabwareInfo.test.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/LeftColumnLabwareInfo.test.tsx @@ -52,7 +52,7 @@ describe('LeftColumnLabwareInfo', () => { expect.objectContaining({ type: 'location', labwareName: 'MOCK_LW_NAME', - currentLocationProps: { slotName: 'A1' }, + currentLocationProps: { deckLabel: 'A1' }, }), {} ) @@ -82,7 +82,7 @@ describe('LeftColumnLabwareInfo', () => { expect(vi.mocked(InterventionInfo)).toHaveBeenCalledWith( expect.objectContaining({ - currentLocationProps: { slotName: '' }, + currentLocationProps: { deckLabel: '' }, }), {} ) diff --git a/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx b/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx index 469e5e9f2d7..f8692794081 100644 --- a/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx +++ b/app/src/organisms/InterventionModal/MoveLabwareInterventionContent.tsx @@ -7,12 +7,12 @@ import { BORDERS, Box, COLORS, + DeckInfoLabel, DIRECTION_COLUMN, DISPLAY_NONE, Flex, Icon, LabwareRender, - LocationIcon, Module, MoveLabwareOnDeck, RESPONSIVENESS, @@ -256,11 +256,11 @@ function LabwareDisplayLocation( let displayLocation: React.ReactNode = '' if (location === 'offDeck') { // TODO(BC, 08/28/23): remove this string cast after update i18next to >23 (see https://www.i18next.com/overview/typescript#argument-of-type-defaulttfuncreturn-is-not-assignable-to-parameter-of-type-xyz) - displayLocation = + displayLocation = } else if ('slotName' in location) { - displayLocation = + displayLocation = } else if ('addressableAreaName' in location) { - displayLocation = + displayLocation = } else if ('moduleId' in location) { const moduleModel = getModuleModelFromRunData( protocolData, diff --git a/app/src/organisms/LabwarePositionCheck/ResultsSummary.tsx b/app/src/organisms/LabwarePositionCheck/ResultsSummary.tsx index 65320d3cc36..3459b095f61 100644 --- a/app/src/organisms/LabwarePositionCheck/ResultsSummary.tsx +++ b/app/src/organisms/LabwarePositionCheck/ResultsSummary.tsx @@ -17,11 +17,11 @@ import { ALIGN_FLEX_END, BORDERS, COLORS, + DeckInfoLabel, DIRECTION_COLUMN, Flex, Icon, JUSTIFY_SPACE_BETWEEN, - LocationIcon, MODULE_ICON_NAME_BY_TYPE, OVERFLOW_AUTO, PrimaryButton, @@ -373,9 +373,9 @@ export const TerseOffsetTable = (props: OffsetTableProps): JSX.Element => { return ( - + {location.moduleModel != null ? ( - + location = } else if ( selectedLabware != null && typeof selectedLabware.location === 'object' && 'addressableAreaName' in selectedLabware?.location ) { location = ( - + ) } else if ( selectedLabware != null && @@ -169,7 +171,7 @@ export function ProtocolSetupLabware({ module.moduleId === selectedLabware.location.moduleId ) if (matchedModule != null) { - location = + location = } } else if ( selectedLabware != null && @@ -184,13 +186,13 @@ export function ProtocolSetupLabware({ )?.params.location if (adapterLocation != null && adapterLocation !== 'offDeck') { if ('slotName' in adapterLocation) { - location = + location = } else if ('moduleId' in adapterLocation) { const moduleUnderAdapter = attachedProtocolModuleMatches.find( module => module.moduleId === adapterLocation.moduleId ) if (moduleUnderAdapter != null) { - location = + location = } } } @@ -492,19 +494,19 @@ function RowLabware({ let location: JSX.Element | string | null = null if (initialLocation === 'offDeck') { location = ( - + ) } else if ('slotName' in initialLocation) { slotName = initialLocation.slotName - location = + location = } else if ('addressableAreaName' in initialLocation) { slotName = initialLocation.addressableAreaName - location = + location = } else if (matchedModuleType != null && matchedModule?.slotName != null) { slotName = matchedModule.slotName location = ( <> - + ) } else if ('labwareId' in initialLocation) { @@ -518,14 +520,14 @@ function RowLabware({ if (adapterLocation != null && adapterLocation !== 'offDeck') { if ('slotName' in adapterLocation) { slotName = adapterLocation.slotName - location = + location = } else if ('moduleId' in adapterLocation) { const moduleUnderAdapter = attachedProtocolModules.find( module => module.moduleId === adapterLocation.moduleId ) if (moduleUnderAdapter != null) { slotName = moduleUnderAdapter.slotName - location = + location = } } } @@ -541,7 +543,7 @@ function RowLabware({ {location} {nestedLabwareInfo != null || matchedModule != null ? ( - + ) : null} - - + diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx index 5576c7d049c..b8885dd60a1 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/FixtureTable.tsx @@ -5,10 +5,10 @@ import { BORDERS, COLORS, Chip, + DeckInfoLabel, DIRECTION_ROW, Flex, JUSTIFY_SPACE_BETWEEN, - LocationIcon, SPACING, LegacyStyledText, TYPOGRAPHY, @@ -219,7 +219,7 @@ function FixtureTableItem({ - + - ) if (hardware.hardwareType === 'module') { - location = + location = } else if (hardware.hardwareType === 'fixture') { location = ( - + ) } const isMagneticBlockFixture = diff --git a/app/src/pages/QuickTransferDetails/Hardware.tsx b/app/src/pages/QuickTransferDetails/Hardware.tsx index 11e6e3319c8..399f9764f97 100644 --- a/app/src/pages/QuickTransferDetails/Hardware.tsx +++ b/app/src/pages/QuickTransferDetails/Hardware.tsx @@ -5,8 +5,8 @@ import { ALIGN_CENTER, BORDERS, COLORS, + DeckInfoLabel, Flex, - LocationIcon, ModuleIcon, SPACING, LegacyStyledText, @@ -114,10 +114,12 @@ function HardwareItem({ ) if (hardware.hardwareType === 'module') { - location = + location = } else if (hardware.hardwareType === 'fixture') { location = ( - + ) } const isMagneticBlockFixture = diff --git a/components/src/atoms/StyledText/StyledText.tsx b/components/src/atoms/StyledText/StyledText.tsx index 3bb124a3def..fc33536da9a 100644 --- a/components/src/atoms/StyledText/StyledText.tsx +++ b/components/src/atoms/StyledText/StyledText.tsx @@ -111,6 +111,14 @@ const helixProductStyleMap = { } `, }, + captionBold: { + as: 'label', + style: css` + @media not (${RESPONSIVENESS.touchscreenMediaQuerySpecs}) { + font: ${HELIX_TYPOGRAPHY.fontStyleCaptionBold}; + } + `, + }, captionRegular: { as: 'label', style: css` @@ -300,12 +308,13 @@ function styleForODDName(name?: ODDStyles): FlattenSimpleInterpolation { return name ? ODDStyleMap[name].style : css`` } -// this is some artifact of the way styled-text forwards arguments. -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -const DesktopStyledText: (props: Props) => JSX.Element = styled(Text)` - ${props => styleForDesktopName(props.desktopStyle)} +const DesktopStyledText: (props: Props) => JSX.Element = styled( + Text +).withConfig({ + shouldForwardProp: p => p !== 'oddStyle' && p !== 'desktopStyle', +})` + ${(props: Props) => styleForDesktopName(props.desktopStyle)} ` -/* eslint-enable @typescript-eslint/no-unsafe-argument */ export const StyledText: (props: Props) => JSX.Element = styled( DesktopStyledText diff --git a/components/src/hardware-sim/Deck/SlotLabels.tsx b/components/src/hardware-sim/Deck/SlotLabels.tsx index 31648cda9c0..ffa69db790d 100644 --- a/components/src/hardware-sim/Deck/SlotLabels.tsx +++ b/components/src/hardware-sim/Deck/SlotLabels.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' -import { LocationIcon } from '../../molecules' +import { DeckInfoLabel } from '../../molecules' import { Flex } from '../../primitives' import { ALIGN_CENTER, DIRECTION_COLUMN, JUSTIFY_CENTER } from '../../styles' import { RobotCoordsForeignObject } from './RobotCoordsForeignObject' @@ -41,36 +41,16 @@ export const SlotLabels = ({ width="2.5rem" > - + - + - + - + @@ -99,14 +79,14 @@ export const SlotLabels = ({ justifyContent={JUSTIFY_CENTER} width={`${widthLargeRem}rem`} > - + - + - + {show4thColumn ? ( - + ) : null} diff --git a/components/src/helix-design-system/product/typography.ts b/components/src/helix-design-system/product/typography.ts index 2d80ffc99f1..f2f83996a15 100644 --- a/components/src/helix-design-system/product/typography.ts +++ b/components/src/helix-design-system/product/typography.ts @@ -117,6 +117,13 @@ const fontSizeCaption = '0.8125rem' // 13px const lineHeightCaption = '1rem' // 16px const fontFamilyCaption = fontFamily +// Caption-Bold +export const fontSizeCaptionBold = fontSizeCaption +export const lineHeightCaptionBold = lineHeightCaption +export const fontFamilyCaptionBold = fontFamilyCaption +export const fontWeightCaptionBold = fontWeightBold +export const fontStyleCaptionBold = `${fontWeightCaptionBold} ${fontSizeCaptionBold}/${lineHeightCaptionBold} ${fontFamilyCaptionBold}` + // Caption-Medium export const fontSizeCaptionSemiBold = fontSizeCaption export const lineHeightCaptionSemiBold = lineHeightCaption diff --git a/components/src/icons/ModuleIcon.tsx b/components/src/icons/ModuleIcon.tsx index 616c6c1408d..d5ba6b78b70 100644 --- a/components/src/icons/ModuleIcon.tsx +++ b/components/src/icons/ModuleIcon.tsx @@ -11,9 +11,18 @@ import { import type { ModuleType } from '@opentrons/shared-data' import type { StyleProps } from '../primitives/types' -import type { IconName } from './Icon' -export const MODULE_ICON_NAME_BY_TYPE: { [type in ModuleType]: IconName } = { +export type ModuleIconName = + | 'ot-magnet-v2' + | 'ot-heater-shaker' + | 'ot-temperature-v2' + | 'ot-magnet-v2' + | 'ot-thermocycler' + | 'ot-absorbance' + +export const MODULE_ICON_NAME_BY_TYPE: { + [type in ModuleType]: ModuleIconName +} = { [MAGNETIC_BLOCK_TYPE]: 'ot-magnet-v2', [HEATERSHAKER_MODULE_TYPE]: 'ot-heater-shaker', [TEMPERATURE_MODULE_TYPE]: 'ot-temperature-v2', diff --git a/components/src/molecules/LocationIcon/LocationIcon.stories.tsx b/components/src/molecules/DeckInfoLabel/DeckInfoLabel.stories.tsx similarity index 57% rename from components/src/molecules/LocationIcon/LocationIcon.stories.tsx rename to components/src/molecules/DeckInfoLabel/DeckInfoLabel.stories.tsx index 64f150640c2..ee604d56453 100644 --- a/components/src/molecules/LocationIcon/LocationIcon.stories.tsx +++ b/components/src/molecules/DeckInfoLabel/DeckInfoLabel.stories.tsx @@ -2,48 +2,37 @@ import * as React from 'react' import { customViewports } from '../../../../.storybook/preview' import { Flex } from '../../primitives' import { SPACING } from '../../ui-style-constants' -import { ICON_DATA_BY_NAME } from '../../icons' -import { LocationIcon } from '.' +import { DeckInfoLabel } from '.' import type { Meta, StoryObj } from '@storybook/react' -const slots = [ - 'A1', - 'A2', - 'A3', - 'A4', - 'B1', - 'B2', - 'B3', - 'B4', - 'C1', - 'C2', - 'C3', - 'C4', - 'D1', - 'D2', - 'D3', - 'D4', -] - -const meta: Meta = { - title: 'Library/Molecules/LocationIcon', +const meta: Meta = { + title: 'Library/Molecules/DeckInfoLabel', argTypes: { iconName: { control: { type: 'select', }, - options: Object.keys(ICON_DATA_BY_NAME), + options: [ + 'ot-magnet-v2', + 'ot-heater-shaker', + 'ot-temperature-v2', + 'ot-magnet-v2', + 'ot-thermocycler', + 'ot-absorbance', + 'stacked', + ], }, - slotName: { + deckLabel: { control: { - type: 'select', + type: 'text', }, - options: slots, + defaultValue: 'A1', }, }, - component: LocationIcon, + component: DeckInfoLabel, parameters: { + controls: { include: ['highlight', 'iconName', 'deckLabel'] }, viewport: { viewports: customViewports, defaultViewport: 'onDeviceDisplay', @@ -58,17 +47,20 @@ const meta: Meta = { ], } export default meta -type Story = StoryObj +type Story = StoryObj export const DisplaySlot: Story = { args: { - slotName: 'A1', + deckLabel: 'A1', iconName: undefined, + highlight: false, }, } export const DisplayIcon: Story = { args: { + deckLabel: undefined, iconName: 'ot-temperature-v2', + highlight: false, }, } diff --git a/components/src/molecules/DeckInfoLabel/__tests__/DeckInfoLabel.test.tsx b/components/src/molecules/DeckInfoLabel/__tests__/DeckInfoLabel.test.tsx new file mode 100644 index 00000000000..0784374d363 --- /dev/null +++ b/components/src/molecules/DeckInfoLabel/__tests__/DeckInfoLabel.test.tsx @@ -0,0 +1,49 @@ +import * as React from 'react' +import { describe, it, beforeEach, expect } from 'vitest' +import { renderWithProviders } from '../../../testing/utils' +import { screen } from '@testing-library/react' +import { SPACING } from '../../../ui-style-constants' +import { BORDERS, COLORS } from '../../../helix-design-system' + +import { DeckInfoLabel } from '..' + +const render = (props: React.ComponentProps) => { + return renderWithProviders() +} + +describe('DeckInfoLabel', () => { + let props: React.ComponentProps + + beforeEach(() => { + props = { + deckLabel: 'A1', + } + }) + + it('should render the proper styles - web style', () => { + render(props) + const deckInfoLabel = screen.getByTestId('DeckInfoLabel_A1') + expect(deckInfoLabel).toHaveStyle( + `padding: ${SPACING.spacing2} ${SPACING.spacing4}` + ) + expect(deckInfoLabel).toHaveStyle(`height: ${SPACING.spacing20}`) + expect(deckInfoLabel).toHaveStyle('width: max-content') + expect(deckInfoLabel).toHaveStyle(`border: 2px solid ${COLORS.black90}`) + expect(deckInfoLabel).toHaveStyle(`border-radius: ${BORDERS.borderRadius8}`) + }) + + it.todo('should render the proper styles - odd style') + + it('should render deck label', () => { + render(props) + screen.getByText('A1') + }) + + it('should render an icon', () => { + props = { + iconName: 'ot-temperature-v2', + } + render(props) + screen.getByLabelText(props.iconName) + }) +}) diff --git a/components/src/molecules/DeckInfoLabel/index.tsx b/components/src/molecules/DeckInfoLabel/index.tsx new file mode 100644 index 00000000000..86666c3263f --- /dev/null +++ b/components/src/molecules/DeckInfoLabel/index.tsx @@ -0,0 +1,94 @@ +import * as React from 'react' +import styled from 'styled-components' + +import { StyledText } from '../../atoms' +import { BORDERS, COLORS } from '../../helix-design-system' +import { Icon } from '../../icons' +import { Flex } from '../../primitives' +import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../styles' +import { RESPONSIVENESS, SPACING } from '../../ui-style-constants' + +import type { ModuleIconName } from '../../icons' +import type { StyleProps } from '../../primitives' + +interface DeckLabelProps extends StyleProps { + /** deck label to display */ + deckLabel: string + iconName?: undefined +} + +interface HardwareIconProps extends StyleProps { + /** hardware icon name */ + iconName: ModuleIconName | 'stacked' + deckLabel?: undefined +} + +// type union requires one of deckLabel or iconName, but not both +export type DeckInfoLabelProps = (DeckLabelProps | HardwareIconProps) & { + highlight?: boolean +} + +export const DeckInfoLabel = styled(DeckInfoLabelComponent)` + align-items: ${ALIGN_CENTER}; + background-color: ${props => + props.highlight ?? false ? COLORS.blue50 : 'inherit'}; + border: 2px solid + ${props => (props.highlight ?? false ? 'transparent' : COLORS.black90)}; + width: ${props => props.width ?? 'max-content'}; + padding: ${SPACING.spacing2} ${SPACING.spacing4}; + border-radius: ${BORDERS.borderRadius8}; + justify-content: ${JUSTIFY_CENTER}; + height: ${props => + props.height ?? SPACING.spacing20}; // prevents the icon from being squished + + > svg { + height: 0.875rem; + width: 0.875rem; + } + + @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { + border-radius: ${BORDERS.borderRadius12}; + height: ${props => props.height ?? SPACING.spacing32}; + padding: ${SPACING.spacing4} + ${props => + props.deckLabel != null ? SPACING.spacing8 : SPACING.spacing6}; + > svg { + height: 1.25rem; + width: 1.25rem; + } + } +` + +function DeckInfoLabelComponent({ + deckLabel, + iconName, + highlight = false, + ...styleProps +}: DeckInfoLabelProps): JSX.Element { + return ( + + {iconName != null ? ( + + ) : ( + + {deckLabel} + + )} + + ) +} diff --git a/components/src/molecules/LocationIcon/__tests__/LocationIcon.test.tsx b/components/src/molecules/LocationIcon/__tests__/LocationIcon.test.tsx deleted file mode 100644 index 1750d594d1d..00000000000 --- a/components/src/molecules/LocationIcon/__tests__/LocationIcon.test.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as React from 'react' -import { describe, it, beforeEach, expect } from 'vitest' -import { renderWithProviders } from '../../../testing/utils' -import { screen } from '@testing-library/react' -import { SPACING, TYPOGRAPHY } from '../../../ui-style-constants' -import { BORDERS, COLORS } from '../../../helix-design-system' - -import { LocationIcon } from '..' - -const render = (props: React.ComponentProps) => { - return renderWithProviders() -} - -describe('LocationIcon', () => { - let props: React.ComponentProps - - beforeEach(() => { - props = { - slotName: 'A1', - } - }) - - it('should render the proper styles - web style', () => { - render(props) - const locationIcon = screen.getByTestId('LocationIcon_A1') - expect(locationIcon).toHaveStyle( - `padding: ${SPACING.spacing2} ${SPACING.spacing4}` - ) - expect(locationIcon).toHaveStyle('height: max-content') - expect(locationIcon).toHaveStyle('width: max-content') - expect(locationIcon).toHaveStyle(`border: 1px solid ${COLORS.black90}`) - expect(locationIcon).toHaveStyle(`border-radius: ${BORDERS.borderRadius4}`) - }) - - it.todo('should render the proper styles - odd style') - - it('should render slot name', () => { - render(props) - const text = screen.getByText('A1') - expect(text).toHaveStyle(`font-size: ${TYPOGRAPHY.fontSizeCaption}`) - expect(text).toHaveStyle('line-height: normal') - expect(text).toHaveStyle(` font-weight: ${TYPOGRAPHY.fontWeightBold}`) - }) - - it('should render an icon', () => { - props = { - iconName: 'ot-temperature-v2', - } - render(props) - screen.getByLabelText(props.iconName as string) - }) -}) diff --git a/components/src/molecules/LocationIcon/index.tsx b/components/src/molecules/LocationIcon/index.tsx deleted file mode 100644 index 6a922f155c0..00000000000 --- a/components/src/molecules/LocationIcon/index.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import * as React from 'react' -import { css } from 'styled-components' - -import { Icon } from '../../icons' -import { Flex, Text } from '../../primitives' -import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../styles' -import { RESPONSIVENESS, SPACING, TYPOGRAPHY } from '../../ui-style-constants' -import { BORDERS, COLORS } from '../../helix-design-system' - -import type { IconName } from '../../icons' -import type { StyleProps } from '../../primitives' - -interface SlotLocationProps extends StyleProps { - /** name constant of the slot to display */ - slotName: string - iconName?: undefined -} - -interface HardwareIconProps extends StyleProps { - /** hardware icon name */ - iconName: IconName - slotName?: undefined -} - -// type union requires one of slotName or iconName, but not both -export type LocationIconProps = SlotLocationProps | HardwareIconProps - -const LOCATION_ICON_STYLE = css<{ - slotName?: string - color?: string - height?: string - width?: string -}>` - align-items: ${ALIGN_CENTER}; - border: 1px solid ${props => props.color ?? COLORS.black90}; - width: ${props => props.width ?? 'max-content'}; - padding: ${SPACING.spacing2} ${SPACING.spacing4}; - border-radius: ${BORDERS.borderRadius4}; - justify-content: ${JUSTIFY_CENTER}; - height: max-content; // prevents the icon from being squished - - @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { - border: 2px solid ${props => props.color ?? COLORS.black90}; - border-radius: ${BORDERS.borderRadius12}; - height: ${props => props.height ?? SPACING.spacing32}; - padding: ${SPACING.spacing4} - ${props => (props.slotName != null ? SPACING.spacing8 : SPACING.spacing6)}; - } -` - -const SLOT_NAME_TEXT_STYLE = css` - font-size: ${TYPOGRAPHY.fontSizeCaption}; - line-height: normal; - font-weight: ${TYPOGRAPHY.fontWeightBold}; - - @media ${RESPONSIVENESS.touchscreenMediaQuerySpecs} { - ${TYPOGRAPHY.smallBodyTextBold} - } -` - -export function LocationIcon({ - slotName, - iconName, - color, - ...styleProps -}: LocationIconProps): JSX.Element { - return ( - - {iconName != null ? ( - - ) : ( - {slotName} - )} - - ) -} diff --git a/components/src/molecules/index.ts b/components/src/molecules/index.ts index e188f8070d3..e4b70216f31 100644 --- a/components/src/molecules/index.ts +++ b/components/src/molecules/index.ts @@ -1,5 +1,5 @@ +export * from './DeckInfoLabel' export * from './LiquidIcon' -export * from './LocationIcon' export * from './Tabs' export * from './ParametersTable' export * from './ParametersTable/InfoScreen' diff --git a/components/src/ui-style-constants/typography.ts b/components/src/ui-style-constants/typography.ts index 83134e5cedf..b596d7376f5 100644 --- a/components/src/ui-style-constants/typography.ts +++ b/components/src/ui-style-constants/typography.ts @@ -15,7 +15,6 @@ export const fontSizeH4 = '0.813rem' // 13px export const fontSizeH6 = '0.563rem' // 9px export const fontSizeP = '0.8125rem' // 13px export const fontSizeLabel = '0.6875rem' // 11px -// this is redundant but we need this for captions and it makes more sense to call it caption rather than re-using fsh6 export const fontSizeCaption = '0.625rem' // 10px // Font Weights diff --git a/protocol-designer/src/components/DeckSetup/SlotLabels.tsx b/protocol-designer/src/components/DeckSetup/SlotLabels.tsx index 5b736cf760e..ffbbb73fde0 100644 --- a/protocol-designer/src/components/DeckSetup/SlotLabels.tsx +++ b/protocol-designer/src/components/DeckSetup/SlotLabels.tsx @@ -2,9 +2,9 @@ import * as React from 'react' import { FLEX_ROBOT_TYPE } from '@opentrons/shared-data' import { + DeckInfoLabel, Flex, JUSTIFY_CENTER, - LocationIcon, RobotCoordsForeignObject, ALIGN_CENTER, DIRECTION_COLUMN, @@ -44,16 +44,16 @@ export const SlotLabels = ({ width="2.5rem" > - + - + - + - + @@ -74,21 +74,21 @@ export const SlotLabels = ({ justifyContent={JUSTIFY_CENTER} flex="1" > - + - + - + {hasStagingAreas ? ( - + ) : null}