import type { HeatmapConfig, Well, WellPlateSelectionMode, WellShape } from '../types' import { DEFAULT_SAMPLE_TYPE_COLORS, getHeatmapColor, } from './WellPlate.colors' export interface WellClassState { wellShape: WellShape selectionMode: WellPlateSelectionMode selected: boolean dragOver: boolean hovered: boolean disabled: boolean readonly: boolean dragSource: boolean dragTarget: boolean } export interface WellStyleState { heatmap: HeatmapConfig sampleColors: Record } export function wellClasses(well: Well, state: WellClassState): string[] { const classes = [ 'mint-well-plate__well', state.wellShape === 'circle' ? 'mint-well-plate__well--circle' : 'mint-well-plate__well--rounded', ] if (state.selectionMode === 'drag' && well.sampleType) { classes.push('mint-well-plate__well--draggable') } if (state.dragSource) classes.push('mint-well-plate__well--drag-source') else if (state.dragTarget) classes.push('mint-well-plate__well--drag-target') else if (state.selected) classes.push('mint-well-plate__well--selected') else if (state.dragOver) classes.push('mint-well-plate__well--drag-over') else if (state.hovered && !state.readonly) classes.push('mint-well-plate__well--hovered') if (state.disabled) classes.push('mint-well-plate__well--disabled') if (well.state === 'filled') classes.push('mint-well-plate__well--filled') return classes } export function wellStyle(well: Well, state: WellStyleState): Record { const heatmapColor = getHeatmapColor(state.heatmap, well.value) if (heatmapColor) { return { backgroundColor: heatmapColor, border: '1px solid transparent' } } const groupColor = well.sampleType && ((well.group ? state.sampleColors[well.group] : undefined) ?? state.sampleColors[well.sampleType] ?? DEFAULT_SAMPLE_TYPE_COLORS[well.sampleType]) if (!groupColor) return {} // empty / filled wells are styled by well-plate.css return sampleTint(groupColor) } /** 15% fill and 40% outline of a sample color; color-mix accepts hex and `var()` tokens alike. */ export function sampleTint(color: string): { backgroundColor: string; border: string } { return { backgroundColor: `color-mix(in srgb, ${color} 15%, transparent)`, border: `1px solid color-mix(in srgb, ${color} 40%, transparent)`, } } let sampleTypeIndicatorWarned = false /** One dev-only warning per page for the no-op `showSampleTypeIndicator` prop. */ export function warnSampleTypeIndicatorDeprecated(): void { if (sampleTypeIndicatorWarned) return if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return sampleTypeIndicatorWarned = true console.warn( '[WellPlate] showSampleTypeIndicator is deprecated and renders nothing; it is removed in MINT 1.4. ' + 'The sample-type marker already shows shape per type and Q / i glyphs for QC / iQC.', ) } export function wellLabel(well: Well, showWellLabels: boolean): string | undefined { if (!showWellLabels) return undefined return well.metadata?.label as string | undefined } export function wellBadge( well: Well, showBadges: boolean, ): { text: string; color: string } | null { if (!showBadges || !well.metadata) return null const count = well.metadata.injectionCount as number | undefined if (count && count > 1) { return { text: String(count), color: '#6366f1' } } if (well.metadata.customMethod) { return { text: '+', color: '#ec4899' } } return null }