11import * as React from 'react' ;
22
3+ import { Plate } from '../Plate' ;
34import { PALETTE } from '../theme' ;
45
56import { EmptyLabware } from './EmptyLabware' ;
@@ -13,16 +14,17 @@ import {
1314 LABWARE_METADATA ,
1415} from './labwareMetadata' ;
1516import {
17+ Labware ,
1618 LabwareConfig ,
1719 LabwareKey ,
1820 LabwareWithStyle ,
1921 TecanLabwares ,
2022} from './types' ;
2123
22- // Scaling constants for fit-to-width behavior
2324const GRID_PADDING = 8 ;
2425const GRID_GAP = 8 ;
2526const COLUMN_COUNT = 5 ;
27+ const ROW_COUNT = 3 ;
2628const GRID_OVERHEAD = GRID_PADDING * 2 + GRID_GAP * ( COLUMN_COUNT - 1 ) ;
2729const COLUMN_OVERHEAD = 60 ;
2830const BASE_CONTENT_WIDTH = 1400 ;
@@ -51,7 +53,6 @@ const LABWARE_ITEM_BASE_STYLE = {
5153 justifySelf : 'center' ,
5254} as const ;
5355
54- // Shared style for columns that span all 3 grid rows
5556const SPANNING_COLUMN_BASE_STYLE = {
5657 display : 'grid' ,
5758 alignSelf : 'center' ,
@@ -68,41 +69,20 @@ const RIGHT_COLUMN_STYLE = {
6869 gridArea : 'rightColumn' ,
6970} as const ;
7071
71- // Helper functions for dynamic grid sizing
72-
73- /**
74- * Calculates dynamic grid-template-columns based on which columns have content.
75- * Empty columns get minimal width (40-60px), filled columns get proportional sizes
76- * matching physical Tecan deck dimensions (column 1: 0.5fr, columns 2-3: 1fr).
77- */
7872function calculateGridTemplateColumns ( labwares : TecanLabwares ) : string {
7973 const filledByColumn = getFilledLabwaresByColumn ( labwares ) ;
8074
81- const columnSizes = [
82- ( filledByColumn [ 0 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Column 0
83- ( filledByColumn [ 1 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Column 1
84- ( filledByColumn [ 2 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Column 2
85- ( filledByColumn [ 3 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Column 3
86- ( filledByColumn [ 4 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Column 4
87- ] ;
88-
89- return columnSizes . join ( ' ' ) ;
75+ return Array . from ( { length : COLUMN_COUNT } , ( _ , i ) =>
76+ ( filledByColumn [ i ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' ,
77+ ) . join ( ' ' ) ;
9078}
9179
92- /**
93- * Calculates dynamic grid-template-rows based on which rows have content.
94- * Empty rows get minimal height (40-60px), filled rows get auto.
95- */
9680function calculateGridTemplateRows ( labwares : TecanLabwares ) : string {
9781 const filledByRow = getFilledLabwaresByRow ( labwares ) ;
9882
99- const rowSizes = [
100- ( filledByRow [ 0 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Row 0
101- ( filledByRow [ 1 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Row 1
102- ( filledByRow [ 2 ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' , // Row 2
103- ] ;
104-
105- return rowSizes . join ( ' ' ) ;
83+ return Array . from ( { length : ROW_COUNT } , ( _ , i ) =>
84+ ( filledByRow [ i ] ?. length ?? 0 ) > 0 ? 'auto' : 'minmax(40px, 60px)' ,
85+ ) . join ( ' ' ) ;
10686}
10787
10888export function TecanDeckView ( { labwares } : { labwares : TecanLabwares } ) {
@@ -164,7 +144,7 @@ export function TecanDeckView({ labwares }: { labwares: TecanLabwares }) {
164144 const labware : LabwareWithStyle = {
165145 key,
166146 ...metadata ,
167- content : labwares [ key ] ?. content ,
147+ labware : labwares [ key ] ,
168148 style : {
169149 ...LABWARE_ITEM_BASE_STYLE ,
170150 gridArea : key ,
@@ -190,15 +170,36 @@ export function TecanDeckView({ labwares }: { labwares: TecanLabwares }) {
190170 ) ;
191171 } , [ labwares ] ) ;
192172
193- const renderLabware = ( labware : LabwareConfig ) =>
194- labware . content ? (
173+ const renderLabwareContent = (
174+ labware : Labware ,
175+ coordinateSystem : LabwareConfig [ 'coordinateSystem' ] ,
176+ ) => {
177+ if ( labware . type === 'custom' ) {
178+ return labware . content ;
179+ }
180+
181+ return (
182+ < Plate
183+ coordinateSystem = { coordinateSystem }
184+ data = { labware . data }
185+ loading = { labware . loading }
186+ wellSizing = { labware . wellSizing ?? 'compact' }
187+ />
188+ ) ;
189+ } ;
190+
191+ const renderLabware = ( labwareConfig : LabwareConfig ) =>
192+ labwareConfig . labware ? (
195193 < LabwareDetailItem
196- shortLabel = { labware . shortLabel }
197- content = { labware . content }
198- backgroundColor = { labware . color }
194+ shortLabel = { labwareConfig . shortLabel }
195+ content = { renderLabwareContent (
196+ labwareConfig . labware ,
197+ labwareConfig . coordinateSystem ,
198+ ) }
199+ backgroundColor = { labwareConfig . color }
199200 />
200201 ) : (
201- < EmptyLabware shortLabel = { labware . shortLabel } />
202+ < EmptyLabware shortLabel = { labwareConfig . shortLabel } />
202203 ) ;
203204
204205 return (
0 commit comments