import type { PlateMapEditorState, Rack, Well, WellLegendItem, } from '../types' import { SAMPLE_COLOR_SCALE, SLOT_ORDER } from '../utils/color' export function activePlateFromState(state: PlateMapEditorState) { return state.plates.find(plate => plate.id === state.activePlateId) ?? state.plates[0] } export function sampleColorsFromPlateState(state: PlateMapEditorState): Record { return Object.fromEntries( state.samples .filter(sample => sample.color) .map(sample => [sample.id, sample.color as string]) ) } export function legendItemsFromPlateState(state: PlateMapEditorState): WellLegendItem[] { return state.samples.map((sample, index) => ({ type: sample.id, label: sample.name, color: sample.color ?? colorForIndex(index), })) } export function colorForIndex(index: number): string { // The gray tail of the scale is reserved for "other"; component plates cycle the eight hues. const colors = SAMPLE_COLOR_SCALE.slice(0, 8) return colors[index % colors.length] } /** * Plates as PlateEditor racks: slots assigned in order, a well's sample id moved to its group (the stored * plate map keeps it in `sampleType`). Plate maps carry no injection volume. * @deprecated Scheduled for removal from the core SDK in MINT 1.4; the biology templates move to a dedicated package or the owning plugins. */ export function racksFromPlateState(state: PlateMapEditorState): Rack[] { const sampleIds = new Set(state.samples.map(sample => sample.id)) const asRackWell = (well: Well): Partial => well.sampleType && sampleIds.has(well.sampleType) ? { ...well, sampleType: 'sample', group: well.sampleType } : well return state.plates.map((plate, index) => ({ id: plate.id, name: plate.name, format: plate.format, slot: SLOT_ORDER[index % SLOT_ORDER.length], injectionVolume: 0, wells: Object.fromEntries(Object.entries(plate.wells).map(([id, well]) => [id, asRackWell(well)])), })) }