@morscherlab/mld-sdk 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AuditTrail.vue.d.ts +1 -10
- package/dist/components/AuditTrail.vue.js.map +1 -1
- package/dist/components/BatchProgressList.vue.d.ts +1 -17
- package/dist/components/BatchProgressList.vue.js.map +1 -1
- package/dist/components/Breadcrumb.vue.d.ts +1 -5
- package/dist/components/Breadcrumb.vue.js.map +1 -1
- package/dist/components/DateTimePicker.vue.js +0 -1
- package/dist/components/DateTimePicker.vue.js.map +1 -1
- package/dist/components/MoleculeInput.vue.d.ts +1 -4
- package/dist/components/MoleculeInput.vue.js.map +1 -1
- package/dist/components/RackEditor.vue.js +2 -2
- package/dist/components/RackEditor.vue.js.map +1 -1
- package/dist/components/ReagentList.vue.d.ts +1 -15
- package/dist/components/ReagentList.vue.js.map +1 -1
- package/dist/components/SampleHierarchyTree.vue.d.ts +1 -12
- package/dist/components/SampleHierarchyTree.vue.js.map +1 -1
- package/dist/components/ScheduleCalendar.vue.js.map +1 -1
- package/dist/components/ScientificNumber.vue.d.ts +1 -1
- package/dist/components/ScientificNumber.vue.js.map +1 -1
- package/dist/components/SettingsModal.vue.d.ts +1 -5
- package/dist/components/SettingsModal.vue.js.map +1 -1
- package/dist/components/StepWizard.vue.d.ts +1 -8
- package/dist/components/StepWizard.vue.js.map +1 -1
- package/dist/components/UnitInput.vue.d.ts +1 -6
- package/dist/components/UnitInput.vue.js.map +1 -1
- package/dist/components/WellPlate.vue.d.ts +5 -1
- package/dist/components/WellPlate.vue.js +219 -27
- package/dist/components/WellPlate.vue.js.map +1 -1
- package/dist/styles.css +113 -88
- package/dist/types/components.d.ts +12 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/AuditTrail.vue +1 -12
- package/src/components/BatchProgressList.vue +1 -20
- package/src/components/Breadcrumb.vue +1 -5
- package/src/components/DateTimePicker.vue +1 -1
- package/src/components/MoleculeInput.story.vue +1 -1
- package/src/components/MoleculeInput.vue +1 -5
- package/src/components/RackEditor.vue +2 -2
- package/src/components/ReagentList.story.vue +1 -1
- package/src/components/ReagentList.vue +1 -26
- package/src/components/SampleHierarchyTree.story.vue +1 -1
- package/src/components/SampleHierarchyTree.vue +1 -25
- package/src/components/ScheduleCalendar.vue +1 -1
- package/src/components/ScientificNumber.story.vue +1 -2
- package/src/components/ScientificNumber.vue +1 -2
- package/src/components/SettingsModal.vue +1 -7
- package/src/components/StepWizard.vue +1 -10
- package/src/components/UnitInput.vue +1 -7
- package/src/components/WellPlate.story.vue +85 -1
- package/src/components/WellPlate.vue +194 -9
- package/src/styles/components/button.css +2 -0
- package/src/styles/components/datetime-picker.css +4 -0
- package/src/styles/components/rack-editor.css +6 -0
- package/src/styles/components/well-plate.css +50 -57
- package/src/types/components.ts +16 -0
- package/src/types/index.ts +13 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WellPlate.vue.js","sources":["../../src/components/WellPlate.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { WellPlateFormat, WellPlateSelectionMode, WellPlateSize, Well, HeatmapConfig, WellShape, WellEditField, WellEditData, WellLegendItem } from '../types'\nimport WellEditPopup from './WellEditPopup.vue'\n\ninterface Props {\n modelValue?: string[]\n format?: WellPlateFormat\n wells?: Record<string, Partial<Well>>\n selectionMode?: WellPlateSelectionMode\n showLabels?: boolean\n showWellIds?: boolean\n showSampleTypeIndicator?: boolean\n heatmap?: HeatmapConfig\n sampleColors?: Record<string, string>\n zoom?: number\n disabled?: boolean\n readonly?: boolean\n size?: WellPlateSize\n wellShape?: WellShape\n // New editing props\n showWellLabels?: boolean\n showBadges?: boolean\n editable?: boolean\n editFields?: WellEditField[]\n defaultInjectionVolume?: number\n showLegend?: boolean\n legendItems?: WellLegendItem[]\n}\n\n// Drag state for moving wells\nconst dragSourceWell = ref<string | null>(null)\nconst dragTargetWell = ref<string | null>(null)\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => [],\n format: 96,\n wells: () => ({}),\n selectionMode: 'multiple',\n showLabels: true,\n showWellIds: false,\n showSampleTypeIndicator: false,\n heatmap: () => ({ enabled: false }),\n sampleColors: () => ({}),\n zoom: 1,\n disabled: false,\n readonly: false,\n size: 'md',\n wellShape: 'rounded',\n // New props default to off for backward compatibility\n showWellLabels: false,\n showBadges: false,\n editable: false,\n editFields: () => ['label', 'sampleType', 'injectionVolume', 'injectionCount', 'customMethod'],\n defaultInjectionVolume: 5,\n showLegend: false,\n legendItems: undefined,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [wellIds: string[]]\n 'well-click': [wellId: string, event: MouseEvent]\n 'well-hover': [wellId: string | null, event?: MouseEvent]\n 'selection-change': [wellIds: string[]]\n 'context-menu': [wellId: string, event: MouseEvent]\n 'well-move': [sourceWellId: string, targetWellId: string]\n // New editing emits\n 'well-edit': [wellId: string, data: WellEditData]\n 'well-clear': [wellId: string]\n}>()\n\nconst plateRef = ref<HTMLElement | null>(null)\nconst tableRef = ref<HTMLElement | null>(null)\nconst isDragging = ref(false)\nconst dragStart = ref<{ row: number; col: number } | null>(null)\nconst dragEnd = ref<{ row: number; col: number } | null>(null)\nconst hoveredWell = ref<string | null>(null)\n\n// Edit popup state\nconst editingWellId = ref<string | null>(null)\nconst editPopupPosition = ref({ x: 0, y: 0 })\n\nconst PLATE_CONFIGS: Record<WellPlateFormat, { rows: number; cols: number }> = {\n 6: { rows: 2, cols: 3 },\n 12: { rows: 3, cols: 4 },\n 24: { rows: 4, cols: 6 },\n 48: { rows: 6, cols: 8 },\n 54: { rows: 6, cols: 9 },\n 96: { rows: 8, cols: 12 },\n 384: { rows: 16, cols: 24 },\n}\n\nconst plateConfig = computed(() => PLATE_CONFIGS[props.format])\n\nconst rowLabels = computed(() =>\n Array.from({ length: plateConfig.value.rows }, (_, i) => String.fromCharCode(65 + i))\n)\n\nconst colLabels = computed(() =>\n Array.from({ length: plateConfig.value.cols }, (_, i) => i + 1)\n)\n\nconst wellGrid = computed(() => {\n const grid: Well[][] = []\n for (let row = 0; row < plateConfig.value.rows; row++) {\n const rowWells: Well[] = []\n for (let col = 0; col < plateConfig.value.cols; col++) {\n const id = `${rowLabels.value[row]}${col + 1}`\n const wellData = props.wells[id] || {}\n rowWells.push({\n id,\n row,\n col,\n state: wellData.state || 'empty',\n sampleType: wellData.sampleType,\n value: wellData.value,\n metadata: wellData.metadata,\n })\n }\n grid.push(rowWells)\n }\n return grid\n})\n\nconst selectedWellSet = computed(() => new Set(props.modelValue))\n\nconst dragSelectedWells = computed(() => {\n if (!isDragging.value || !dragStart.value || !dragEnd.value) return new Set<string>()\n\n const minRow = Math.min(dragStart.value.row, dragEnd.value.row)\n const maxRow = Math.max(dragStart.value.row, dragEnd.value.row)\n const minCol = Math.min(dragStart.value.col, dragEnd.value.col)\n const maxCol = Math.max(dragStart.value.col, dragEnd.value.col)\n\n const wells = new Set<string>()\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const id = `${rowLabels.value[row]}${col + 1}`\n wells.add(id)\n }\n }\n return wells\n})\n\n// Size presets with pixel values for reliable sizing\nconst sizeConfig = computed(() => {\n const sizes = {\n sm: { cellWidth: '40px', cellHeight: '40px', headerWidth: '32px', headerHeight: '32px', fontSize: '0.625rem', gap: '2px' },\n md: { cellWidth: '56px', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '3px' },\n lg: { cellWidth: '80px', cellHeight: '40px', headerWidth: '40px', headerHeight: '32px', fontSize: '0.875rem', gap: '4px' },\n xl: { cellWidth: '96px', cellHeight: '48px', headerWidth: '48px', headerHeight: '40px', fontSize: '1rem', gap: '4px' },\n fill: { cellWidth: '100%', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '2px' },\n }\n return sizes[props.size]\n})\n\nconst isFillMode = computed(() => props.size === 'fill')\n\n// Default legend items\nconst defaultLegendItems: WellLegendItem[] = [\n { type: 'sample', label: 'Sample', color: '#10b981' },\n { type: 'blank', label: 'Blank', color: '#f97316' },\n { type: 'qc', label: 'QC', color: '#8b5cf6' },\n]\n\nconst activeLegendItems = computed(() => props.legendItems ?? defaultLegendItems)\n\n// Sample type colors (matching MSExpDesigner)\nconst defaultSampleTypeColors: Record<string, { bg: string; border: string }> = {\n sample: { bg: 'rgba(16, 185, 129, 0.15)', border: 'rgba(16, 185, 129, 0.4)' },\n control: { bg: 'rgba(59, 130, 246, 0.15)', border: 'rgba(59, 130, 246, 0.4)' },\n blank: { bg: 'rgba(249, 115, 22, 0.15)', border: 'rgba(249, 115, 22, 0.4)' },\n qc: { bg: 'rgba(139, 92, 246, 0.15)', border: 'rgba(139, 92, 246, 0.4)' },\n}\n\nconst heatmapColors: Record<string, string[]> = {\n viridis: ['#440154', '#482878', '#3e4989', '#31688e', '#26828e', '#1f9e89', '#35b779', '#6ece58', '#b5de2b', '#fde725'],\n plasma: ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'],\n turbo: ['#30123b', '#4145ab', '#4675ed', '#39a2fc', '#1bcfd4', '#24e79e', '#71f05f', '#c1f034', '#f1c83c', '#f99538', '#e45a31', '#ba2512', '#7a0403'],\n}\n\nfunction getHeatmapColor(value: number | undefined): string | null {\n if (!props.heatmap?.enabled || value === undefined) return null\n\n const min = props.heatmap.min ?? 0\n const max = props.heatmap.max ?? 1\n const normalized = Math.max(0, Math.min(1, (value - min) / (max - min)))\n\n const colors = props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length\n ? props.heatmap.customColors\n : heatmapColors[props.heatmap.colorScale || 'viridis']\n\n const index = Math.min(Math.floor(normalized * (colors.length - 1)), colors.length - 1)\n return colors[index]\n}\n\nfunction getWellClasses(well: Well): string[] {\n const isWellSelected = isSelected(well.id)\n const isDragOver = dragSelectedWells.value.has(well.id)\n const isHovered = hoveredWell.value === well.id\n const isDisabled = props.disabled || well.state === 'disabled'\n const isDragSource = dragSourceWell.value === well.id\n const isDragTarget = dragTargetWell.value === well.id\n\n const classes = [\n 'mld-well-plate__well',\n props.wellShape === 'circle' ? 'mld-well-plate__well--circle' : 'mld-well-plate__well--rounded',\n ]\n\n if (props.selectionMode === 'drag' && well.sampleType) {\n classes.push('mld-well-plate__well--draggable')\n }\n\n if (isDragSource) classes.push('mld-well-plate__well--drag-source')\n else if (isDragTarget) classes.push('mld-well-plate__well--drag-target')\n else if (isWellSelected) classes.push('mld-well-plate__well--selected')\n else if (isDragOver) classes.push('mld-well-plate__well--drag-over')\n else if (isHovered && !props.readonly) classes.push('mld-well-plate__well--hovered')\n\n if (isDisabled) classes.push('mld-well-plate__well--disabled')\n if (well.state === 'filled') classes.push('mld-well-plate__well--filled')\n\n return classes\n}\n\nfunction getWellStyle(well: Well): Record<string, string> {\n const heatmapColor = getHeatmapColor(well.value)\n if (heatmapColor) {\n return { backgroundColor: heatmapColor, border: '1px solid transparent' }\n }\n\n if (well.sampleType && props.sampleColors[well.sampleType]) {\n const color = props.sampleColors[well.sampleType]\n return {\n backgroundColor: `${color}26`,\n border: `1px solid ${color}66`,\n }\n }\n\n if (well.sampleType && defaultSampleTypeColors[well.sampleType]) {\n const colors = defaultSampleTypeColors[well.sampleType]\n return {\n backgroundColor: colors.bg,\n border: `1px solid ${colors.border}`,\n }\n }\n\n const borderStyle = well.state === 'filled' ? 'solid' : 'dashed'\n return {\n backgroundColor: 'var(--bg-tertiary)',\n border: `1px ${borderStyle} var(--border-color)`,\n }\n}\n\nfunction getSampleTypeIndicator(well: Well): string | null {\n if (!props.showSampleTypeIndicator || !well.sampleType) return null\n const typeMap: Record<string, string> = {\n sample: 'S',\n control: 'C',\n blank: 'B',\n qc: 'Q',\n }\n return typeMap[well.sampleType] || well.sampleType.charAt(0).toUpperCase()\n}\n\nfunction getWellLabel(well: Well): string | undefined {\n if (!props.showWellLabels) return undefined\n return well.metadata?.label as string | undefined\n}\n\nfunction getWellBadge(well: Well): { text: string; color: string } | null {\n if (!props.showBadges || !well.metadata) return null\n const count = well.metadata.injectionCount as number | undefined\n if (count && count > 1) {\n return { text: String(count), color: '#6366f1' }\n }\n if (well.metadata.customMethod) {\n return { text: '+', color: '#ec4899' }\n }\n return null\n}\n\nfunction isSelected(wellId: string): boolean {\n return selectedWellSet.value.has(wellId) || dragSelectedWells.value.has(wellId)\n}\n\nfunction handleWellClick(well: Well, event: MouseEvent) {\n if (props.disabled || props.readonly) return\n\n emit('well-click', well.id, event)\n\n // When editable, open popup instead of modifying selection\n if (props.editable) {\n openEditPopup(well.id, event)\n return\n }\n\n if (props.selectionMode === 'none') return\n\n const isCurrentlySelected = selectedWellSet.value.has(well.id)\n const isMultiSelect = event.shiftKey || event.metaKey || event.ctrlKey\n\n let newSelection: string[]\n if (props.selectionMode === 'single') {\n newSelection = isCurrentlySelected ? [] : [well.id]\n } else if (isMultiSelect) {\n newSelection = isCurrentlySelected\n ? props.modelValue.filter(id => id !== well.id)\n : [...props.modelValue, well.id]\n } else {\n newSelection = isCurrentlySelected && props.modelValue.length === 1 ? [] : [well.id]\n }\n\n emit('update:modelValue', newSelection)\n emit('selection-change', newSelection)\n}\n\nfunction openEditPopup(wellId: string, event: MouseEvent) {\n const target = event.currentTarget as HTMLElement\n const rect = target.getBoundingClientRect()\n editPopupPosition.value = {\n x: rect.right + 8,\n y: rect.top,\n }\n editingWellId.value = wellId\n}\n\nfunction handleEditSave(data: WellEditData) {\n emit('well-edit', data.wellId, data)\n editingWellId.value = null\n}\n\nfunction handleEditClear() {\n if (editingWellId.value) {\n emit('well-clear', editingWellId.value)\n }\n editingWellId.value = null\n}\n\nfunction handleEditClose() {\n editingWellId.value = null\n}\n\nfunction handleWellMouseDown(well: Well, event: MouseEvent) {\n if (props.disabled || props.readonly || props.selectionMode !== 'rectangle') return\n if (props.editable) return\n if (event.button !== 0) return\n\n isDragging.value = true\n dragStart.value = { row: well.row, col: well.col }\n dragEnd.value = { row: well.row, col: well.col }\n}\n\nfunction handleWellMouseEnter(well: Well, event: MouseEvent) {\n hoveredWell.value = well.id\n emit('well-hover', well.id, event)\n\n if (isDragging.value && props.selectionMode === 'rectangle') {\n dragEnd.value = { row: well.row, col: well.col }\n }\n}\n\nfunction handleWellMouseLeave() {\n hoveredWell.value = null\n emit('well-hover', null)\n}\n\nfunction handleMouseUp() {\n if (!isDragging.value || props.selectionMode !== 'rectangle') return\n\n const newSelection = Array.from(dragSelectedWells.value)\n isDragging.value = false\n dragStart.value = null\n dragEnd.value = null\n\n if (newSelection.length > 0) {\n emit('update:modelValue', newSelection)\n emit('selection-change', newSelection)\n }\n}\n\nfunction handleContextMenu(well: Well, event: MouseEvent) {\n event.preventDefault()\n emit('context-menu', well.id, event)\n}\n\n// Drag handlers for moving well contents\nfunction handleDragStart(well: Well, event: DragEvent) {\n if (props.disabled || props.readonly || props.selectionMode !== 'drag') return\n if (!well.sampleType) return\n\n dragSourceWell.value = well.id\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', well.id)\n }\n}\n\nfunction handleDragOver(well: Well, event: DragEvent) {\n if (props.selectionMode !== 'drag' || !dragSourceWell.value) return\n event.preventDefault()\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = 'move'\n }\n dragTargetWell.value = well.id\n}\n\nfunction handleDragLeave() {\n dragTargetWell.value = null\n}\n\nfunction handleDrop(well: Well, event: DragEvent) {\n event.preventDefault()\n if (props.selectionMode !== 'drag' || !dragSourceWell.value) return\n\n const sourceId = dragSourceWell.value\n const targetId = well.id\n\n if (sourceId !== targetId) {\n emit('well-move', sourceId, targetId)\n }\n\n dragSourceWell.value = null\n dragTargetWell.value = null\n}\n\nfunction handleDragEnd() {\n dragSourceWell.value = null\n dragTargetWell.value = null\n}\n\nfunction handleKeyDown(event: KeyboardEvent) {\n if (props.disabled || props.readonly) return\n\n if (event.key === 'Escape') {\n if (editingWellId.value) {\n editingWellId.value = null\n return\n }\n emit('update:modelValue', [])\n emit('selection-change', [])\n }\n\n if ((event.key === 'a' || event.key === 'A') && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n const allWells = wellGrid.value.flat().map(w => w.id)\n emit('update:modelValue', allWells)\n emit('selection-change', allWells)\n }\n}\n\nonMounted(() => {\n document.addEventListener('mouseup', handleMouseUp)\n document.addEventListener('keydown', handleKeyDown)\n})\n\nonUnmounted(() => {\n document.removeEventListener('mouseup', handleMouseUp)\n document.removeEventListener('keydown', handleKeyDown)\n})\n\nconst containerStyle = computed(() =>\n isFillMode.value ? {} : {\n transform: `scale(${props.zoom})`,\n transformOrigin: 'top left',\n }\n)\n\nconst tableStyle = computed(() => ({\n borderCollapse: 'separate' as const,\n borderSpacing: sizeConfig.value.gap,\n ...(isFillMode.value ? { width: '100%', tableLayout: 'fixed' as const } : {}),\n}))\n</script>\n\n<template>\n <div\n ref=\"plateRef\"\n :class=\"['mld-well-plate', isFillMode ? 'mld-well-plate--fill' : 'mld-well-plate--inline']\"\n :style=\"containerStyle\"\n >\n <div class=\"mld-well-plate__scroll\">\n <div class=\"mld-well-plate__content\">\n <table\n ref=\"tableRef\"\n class=\"mld-well-plate__table\"\n role=\"grid\"\n :aria-label=\"`${props.format}-well plate`\"\n :style=\"tableStyle\"\n >\n <!-- Column headers -->\n <thead v-if=\"props.showLabels\">\n <tr>\n <th :style=\"{ width: sizeConfig.headerWidth, height: sizeConfig.headerHeight }\"></th>\n <th\n v-for=\"col in colLabels\"\n :key=\"col\"\n class=\"mld-well-plate__col-header\"\n :style=\"{ height: sizeConfig.headerHeight, fontSize: sizeConfig.fontSize }\"\n >\n {{ col }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, rowIndex) in wellGrid\" :key=\"rowIndex\" role=\"row\">\n <!-- Row header -->\n <td\n v-if=\"props.showLabels\"\n class=\"mld-well-plate__row-header\"\n :style=\"{ width: sizeConfig.headerWidth, height: sizeConfig.cellHeight, minWidth: sizeConfig.headerWidth, minHeight: sizeConfig.cellHeight, fontSize: sizeConfig.fontSize }\"\n >\n {{ rowLabels[rowIndex] }}\n </td>\n\n <!-- Wells -->\n <td v-for=\"well in row\" :key=\"well.id\" class=\"mld-well-plate__cell\">\n <div\n role=\"gridcell\"\n tabindex=\"0\"\n :aria-label=\"`Well ${well.id}${well.sampleType ? `, Sample type: ${well.sampleType}` : ''}${well.value !== undefined ? `, Value: ${well.value}` : ''}`\"\n :aria-selected=\"isSelected(well.id)\"\n :aria-disabled=\"props.disabled || well.state === 'disabled'\"\n :draggable=\"props.selectionMode === 'drag' && !!well.sampleType\"\n :class=\"getWellClasses(well)\"\n :style=\"{\n width: isFillMode ? '100%' : sizeConfig.cellWidth,\n height: sizeConfig.cellHeight,\n minWidth: isFillMode ? '0' : sizeConfig.cellWidth,\n minHeight: sizeConfig.cellHeight,\n boxSizing: 'border-box',\n fontSize: sizeConfig.fontSize,\n ...getWellStyle(well),\n }\"\n :title=\"`${well.id}${well.sampleType ? `: ${well.sampleType}` : ''}${getWellLabel(well) ? ` - ${getWellLabel(well)}` : ''}`\"\n @click=\"handleWellClick(well, $event)\"\n @mousedown=\"handleWellMouseDown(well, $event)\"\n @mouseenter=\"handleWellMouseEnter(well, $event)\"\n @mouseleave=\"handleWellMouseLeave\"\n @contextmenu=\"handleContextMenu(well, $event)\"\n @dragstart=\"handleDragStart(well, $event)\"\n @dragover.prevent=\"handleDragOver(well, $event)\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop(well, $event)\"\n @dragend=\"handleDragEnd\"\n @keydown.enter=\"handleWellClick(well, $event as unknown as MouseEvent)\"\n @keydown.space.prevent=\"handleWellClick(well, $event as unknown as MouseEvent)\"\n >\n <!-- Well label text (from metadata.label) -->\n <span\n v-if=\"getWellLabel(well)\"\n class=\"mld-well-plate__label\"\n >\n {{ getWellLabel(well) }}\n </span>\n <!-- Sample type indicator (S/B/Q/C) -->\n <span\n v-else-if=\"getSampleTypeIndicator(well)\"\n class=\"mld-well-plate__indicator\"\n >\n {{ getSampleTypeIndicator(well) }}\n </span>\n <!-- Well ID -->\n <span\n v-else-if=\"props.showWellIds\"\n class=\"mld-well-plate__well-id\"\n >\n {{ well.id }}\n </span>\n\n <!-- Badge (injection count or custom method) -->\n <span\n v-if=\"getWellBadge(well)\"\n class=\"mld-well-plate__badge\"\n :style=\"{ backgroundColor: getWellBadge(well)!.color }\"\n :title=\"getWellBadge(well)!.text === '+' ? 'Custom method' : `${getWellBadge(well)!.text}x injections`\"\n >\n {{ getWellBadge(well)!.text }}\n </span>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n\n <!-- Heatmap legend (inside content wrapper to match table width) -->\n <div\n v-if=\"props.heatmap?.enabled && props.heatmap.showLegend\"\n class=\"mld-well-plate__legend\"\n >\n <span class=\"mld-well-plate__legend-label\">{{ props.heatmap.min ?? 0 }}</span>\n <div class=\"mld-well-plate__legend-bar\">\n <div\n v-for=\"(color, index) in (props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length ? props.heatmap.customColors : heatmapColors[props.heatmap.colorScale || 'viridis'])\"\n :key=\"index\"\n class=\"mld-well-plate__legend-segment\"\n :style=\"{ backgroundColor: color }\"\n />\n </div>\n <span class=\"mld-well-plate__legend-label\">{{ props.heatmap.max ?? 1 }}</span>\n </div>\n\n <!-- Sample type legend bar -->\n <div v-if=\"props.showLegend\" class=\"mld-well-plate__sample-legend\">\n <div\n v-for=\"item in activeLegendItems\"\n :key=\"item.type\"\n class=\"mld-well-plate__sample-legend-item\"\n >\n <span\n class=\"mld-well-plate__sample-legend-dot\"\n :style=\"{ backgroundColor: `${item.color}26`, border: `1px solid ${item.color}66` }\"\n />\n <span class=\"mld-well-plate__sample-legend-text\">{{ item.label }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Edit popup -->\n <WellEditPopup\n v-if=\"editable && editingWellId\"\n :well-id=\"editingWellId\"\n :well-data=\"wells[editingWellId]\"\n :edit-fields=\"editFields\"\n :default-injection-volume=\"defaultInjectionVolume\"\n :position=\"editPopupPosition\"\n @save=\"handleEditSave\"\n @clear=\"handleEditClear\"\n @close=\"handleEditClose\"\n />\n </div>\n</template>\n\n<style>\n@import '../styles/components/well-plate.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_Fragment","_renderList","_openBlock","_toDisplayString","_normalizeClass","_normalizeStyle","_withModifiers","_createBlock","WellEditPopup"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,UAAM,iBAAiB,IAAmB,IAAI;AAC9C,UAAM,iBAAiB,IAAmB,IAAI;AAE9C,UAAM,QAAQ;AAyBd,UAAM,OAAO;AAYb,UAAM,WAAW,IAAwB,IAAI;AAC7C,UAAM,WAAW,IAAwB,IAAI;AAC7C,UAAM,aAAa,IAAI,KAAK;AAC5B,UAAM,YAAY,IAAyC,IAAI;AAC/D,UAAM,UAAU,IAAyC,IAAI;AAC7D,UAAM,cAAc,IAAmB,IAAI;AAG3C,UAAM,gBAAgB,IAAmB,IAAI;AAC7C,UAAM,oBAAoB,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG;AAE5C,UAAM,gBAAyE;AAAA,MAC7E,GAAG,EAAE,MAAM,GAAG,MAAM,EAAA;AAAA,MACpB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAA;AAAA,MACrB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAA;AAAA,MACrB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAA;AAAA,MACrB,IAAI,EAAE,MAAM,GAAG,MAAM,EAAA;AAAA,MACrB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAA;AAAA,MACrB,KAAK,EAAE,MAAM,IAAI,MAAM,GAAA;AAAA,IAAG;AAG5B,UAAM,cAAc,SAAS,MAAM,cAAc,MAAM,MAAM,CAAC;AAE9D,UAAM,YAAY;AAAA,MAAS,MACzB,MAAM,KAAK,EAAE,QAAQ,YAAY,MAAM,KAAA,GAAQ,CAAC,GAAG,MAAM,OAAO,aAAa,KAAK,CAAC,CAAC;AAAA,IAAA;AAGtF,UAAM,YAAY;AAAA,MAAS,MACzB,MAAM,KAAK,EAAE,QAAQ,YAAY,MAAM,KAAA,GAAQ,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,IAAA;AAGhE,UAAM,WAAW,SAAS,MAAM;AAC9B,YAAM,OAAiB,CAAA;AACvB,eAAS,MAAM,GAAG,MAAM,YAAY,MAAM,MAAM,OAAO;AACrD,cAAM,WAAmB,CAAA;AACzB,iBAAS,MAAM,GAAG,MAAM,YAAY,MAAM,MAAM,OAAO;AACrD,gBAAM,KAAK,GAAG,UAAU,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC;AAC5C,gBAAM,WAAW,MAAM,MAAM,EAAE,KAAK,CAAA;AACpC,mBAAS,KAAK;AAAA,YACZ;AAAA,YACA;AAAA,YACA;AAAA,YACA,OAAO,SAAS,SAAS;AAAA,YACzB,YAAY,SAAS;AAAA,YACrB,OAAO,SAAS;AAAA,YAChB,UAAU,SAAS;AAAA,UAAA,CACpB;AAAA,QACH;AACA,aAAK,KAAK,QAAQ;AAAA,MACpB;AACA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,kBAAkB,SAAS,MAAM,IAAI,IAAI,MAAM,UAAU,CAAC;AAEhE,UAAM,oBAAoB,SAAS,MAAM;AACvC,UAAI,CAAC,WAAW,SAAS,CAAC,UAAU,SAAS,CAAC,QAAQ,MAAO,QAAO,oBAAI,IAAA;AAExE,YAAM,SAAS,KAAK,IAAI,UAAU,MAAM,KAAK,QAAQ,MAAM,GAAG;AAC9D,YAAM,SAAS,KAAK,IAAI,UAAU,MAAM,KAAK,QAAQ,MAAM,GAAG;AAC9D,YAAM,SAAS,KAAK,IAAI,UAAU,MAAM,KAAK,QAAQ,MAAM,GAAG;AAC9D,YAAM,SAAS,KAAK,IAAI,UAAU,MAAM,KAAK,QAAQ,MAAM,GAAG;AAE9D,YAAM,4BAAY,IAAA;AAClB,eAAS,MAAM,QAAQ,OAAO,QAAQ,OAAO;AAC3C,iBAAS,MAAM,QAAQ,OAAO,QAAQ,OAAO;AAC3C,gBAAM,KAAK,GAAG,UAAU,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC;AAC5C,gBAAM,IAAI,EAAE;AAAA,QACd;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AAGD,UAAM,aAAa,SAAS,MAAM;AAChC,YAAM,QAAQ;AAAA,QACZ,IAAI,EAAE,WAAW,QAAQ,YAAY,QAAQ,aAAa,QAAQ,cAAc,QAAQ,UAAU,YAAY,KAAK,MAAA;AAAA,QACnH,IAAI,EAAE,WAAW,QAAQ,YAAY,QAAQ,aAAa,QAAQ,cAAc,QAAQ,UAAU,WAAW,KAAK,MAAA;AAAA,QAClH,IAAI,EAAE,WAAW,QAAQ,YAAY,QAAQ,aAAa,QAAQ,cAAc,QAAQ,UAAU,YAAY,KAAK,MAAA;AAAA,QACnH,IAAI,EAAE,WAAW,QAAQ,YAAY,QAAQ,aAAa,QAAQ,cAAc,QAAQ,UAAU,QAAQ,KAAK,MAAA;AAAA,QAC/G,MAAM,EAAE,WAAW,QAAQ,YAAY,QAAQ,aAAa,QAAQ,cAAc,QAAQ,UAAU,WAAW,KAAK,MAAA;AAAA,MAAM;AAE5H,aAAO,MAAM,MAAM,IAAI;AAAA,IACzB,CAAC;AAED,UAAM,aAAa,SAAS,MAAM,MAAM,SAAS,MAAM;AAGvD,UAAM,qBAAuC;AAAA,MAC3C,EAAE,MAAM,UAAU,OAAO,UAAU,OAAO,UAAA;AAAA,MAC1C,EAAE,MAAM,SAAS,OAAO,SAAS,OAAO,UAAA;AAAA,MACxC,EAAE,MAAM,MAAM,OAAO,MAAM,OAAO,UAAA;AAAA,IAAU;AAG9C,UAAM,oBAAoB,SAAS,MAAM,MAAM,eAAe,kBAAkB;AAGhF,UAAM,0BAA0E;AAAA,MAC9E,QAAQ,EAAE,IAAI,4BAA4B,QAAQ,0BAAA;AAAA,MAClD,SAAS,EAAE,IAAI,4BAA4B,QAAQ,0BAAA;AAAA,MACnD,OAAO,EAAE,IAAI,4BAA4B,QAAQ,0BAAA;AAAA,MACjD,IAAI,EAAE,IAAI,4BAA4B,QAAQ,0BAAA;AAAA,IAA0B;AAG1E,UAAM,gBAA0C;AAAA,MAC9C,SAAS,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACtH,QAAQ,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,MACrH,OAAO,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,IAAA;AAGvJ,aAAS,gBAAgB,OAA0C;;AACjE,UAAI,GAAC,WAAM,YAAN,mBAAe,YAAW,UAAU,OAAW,QAAO;AAE3D,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,QAAQ,QAAQ,MAAM,IAAI,CAAC;AAEvE,YAAM,SAAS,MAAM,QAAQ,eAAe,cAAY,WAAM,QAAQ,iBAAd,mBAA4B,UAChF,MAAM,QAAQ,eACd,cAAc,MAAM,QAAQ,cAAc,SAAS;AAEvD,YAAM,QAAQ,KAAK,IAAI,KAAK,MAAM,cAAc,OAAO,SAAS,EAAE,GAAG,OAAO,SAAS,CAAC;AACtF,aAAO,OAAO,KAAK;AAAA,IACrB;AAEA,aAAS,eAAe,MAAsB;AAC5C,YAAM,iBAAiB,WAAW,KAAK,EAAE;AACzC,YAAM,aAAa,kBAAkB,MAAM,IAAI,KAAK,EAAE;AACtD,YAAM,YAAY,YAAY,UAAU,KAAK;AAC7C,YAAM,aAAa,MAAM,YAAY,KAAK,UAAU;AACpD,YAAM,eAAe,eAAe,UAAU,KAAK;AACnD,YAAM,eAAe,eAAe,UAAU,KAAK;AAEnD,YAAM,UAAU;AAAA,QACd;AAAA,QACA,MAAM,cAAc,WAAW,iCAAiC;AAAA,MAAA;AAGlE,UAAI,MAAM,kBAAkB,UAAU,KAAK,YAAY;AACrD,gBAAQ,KAAK,iCAAiC;AAAA,MAChD;AAEA,UAAI,aAAc,SAAQ,KAAK,mCAAmC;AAAA,eACzD,aAAc,SAAQ,KAAK,mCAAmC;AAAA,eAC9D,eAAgB,SAAQ,KAAK,gCAAgC;AAAA,eAC7D,WAAY,SAAQ,KAAK,iCAAiC;AAAA,eAC1D,aAAa,CAAC,MAAM,SAAU,SAAQ,KAAK,+BAA+B;AAEnF,UAAI,WAAY,SAAQ,KAAK,gCAAgC;AAC7D,UAAI,KAAK,UAAU,SAAU,SAAQ,KAAK,8BAA8B;AAExE,aAAO;AAAA,IACT;AAEA,aAAS,aAAa,MAAoC;AACxD,YAAM,eAAe,gBAAgB,KAAK,KAAK;AAC/C,UAAI,cAAc;AAChB,eAAO,EAAE,iBAAiB,cAAc,QAAQ,wBAAA;AAAA,MAClD;AAEA,UAAI,KAAK,cAAc,MAAM,aAAa,KAAK,UAAU,GAAG;AAC1D,cAAM,QAAQ,MAAM,aAAa,KAAK,UAAU;AAChD,eAAO;AAAA,UACL,iBAAiB,GAAG,KAAK;AAAA,UACzB,QAAQ,aAAa,KAAK;AAAA,QAAA;AAAA,MAE9B;AAEA,UAAI,KAAK,cAAc,wBAAwB,KAAK,UAAU,GAAG;AAC/D,cAAM,SAAS,wBAAwB,KAAK,UAAU;AACtD,eAAO;AAAA,UACL,iBAAiB,OAAO;AAAA,UACxB,QAAQ,aAAa,OAAO,MAAM;AAAA,QAAA;AAAA,MAEtC;AAEA,YAAM,cAAc,KAAK,UAAU,WAAW,UAAU;AACxD,aAAO;AAAA,QACL,iBAAiB;AAAA,QACjB,QAAQ,OAAO,WAAW;AAAA,MAAA;AAAA,IAE9B;AAEA,aAAS,uBAAuB,MAA2B;AACzD,UAAI,CAAC,MAAM,2BAA2B,CAAC,KAAK,WAAY,QAAO;AAC/D,YAAM,UAAkC;AAAA,QACtC,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,OAAO;AAAA,QACP,IAAI;AAAA,MAAA;AAEN,aAAO,QAAQ,KAAK,UAAU,KAAK,KAAK,WAAW,OAAO,CAAC,EAAE,YAAA;AAAA,IAC/D;AAEA,aAAS,aAAa,MAAgC;;AACpD,UAAI,CAAC,MAAM,eAAgB,QAAO;AAClC,cAAO,UAAK,aAAL,mBAAe;AAAA,IACxB;AAEA,aAAS,aAAa,MAAoD;AACxE,UAAI,CAAC,MAAM,cAAc,CAAC,KAAK,SAAU,QAAO;AAChD,YAAM,QAAQ,KAAK,SAAS;AAC5B,UAAI,SAAS,QAAQ,GAAG;AACtB,eAAO,EAAE,MAAM,OAAO,KAAK,GAAG,OAAO,UAAA;AAAA,MACvC;AACA,UAAI,KAAK,SAAS,cAAc;AAC9B,eAAO,EAAE,MAAM,KAAK,OAAO,UAAA;AAAA,MAC7B;AACA,aAAO;AAAA,IACT;AAEA,aAAS,WAAW,QAAyB;AAC3C,aAAO,gBAAgB,MAAM,IAAI,MAAM,KAAK,kBAAkB,MAAM,IAAI,MAAM;AAAA,IAChF;AAEA,aAAS,gBAAgB,MAAY,OAAmB;AACtD,UAAI,MAAM,YAAY,MAAM,SAAU;AAEtC,WAAK,cAAc,KAAK,IAAI,KAAK;AAGjC,UAAI,MAAM,UAAU;AAClB,sBAAc,KAAK,IAAI,KAAK;AAC5B;AAAA,MACF;AAEA,UAAI,MAAM,kBAAkB,OAAQ;AAEpC,YAAM,sBAAsB,gBAAgB,MAAM,IAAI,KAAK,EAAE;AAC7D,YAAM,gBAAgB,MAAM,YAAY,MAAM,WAAW,MAAM;AAE/D,UAAI;AACJ,UAAI,MAAM,kBAAkB,UAAU;AACpC,uBAAe,sBAAsB,CAAA,IAAK,CAAC,KAAK,EAAE;AAAA,MACpD,WAAW,eAAe;AACxB,uBAAe,sBACX,MAAM,WAAW,OAAO,QAAM,OAAO,KAAK,EAAE,IAC5C,CAAC,GAAG,MAAM,YAAY,KAAK,EAAE;AAAA,MACnC,OAAO;AACL,uBAAe,uBAAuB,MAAM,WAAW,WAAW,IAAI,CAAA,IAAK,CAAC,KAAK,EAAE;AAAA,MACrF;AAEA,WAAK,qBAAqB,YAAY;AACtC,WAAK,oBAAoB,YAAY;AAAA,IACvC;AAEA,aAAS,cAAc,QAAgB,OAAmB;AACxD,YAAM,SAAS,MAAM;AACrB,YAAM,OAAO,OAAO,sBAAA;AACpB,wBAAkB,QAAQ;AAAA,QACxB,GAAG,KAAK,QAAQ;AAAA,QAChB,GAAG,KAAK;AAAA,MAAA;AAEV,oBAAc,QAAQ;AAAA,IACxB;AAEA,aAAS,eAAe,MAAoB;AAC1C,WAAK,aAAa,KAAK,QAAQ,IAAI;AACnC,oBAAc,QAAQ;AAAA,IACxB;AAEA,aAAS,kBAAkB;AACzB,UAAI,cAAc,OAAO;AACvB,aAAK,cAAc,cAAc,KAAK;AAAA,MACxC;AACA,oBAAc,QAAQ;AAAA,IACxB;AAEA,aAAS,kBAAkB;AACzB,oBAAc,QAAQ;AAAA,IACxB;AAEA,aAAS,oBAAoB,MAAY,OAAmB;AAC1D,UAAI,MAAM,YAAY,MAAM,YAAY,MAAM,kBAAkB,YAAa;AAC7E,UAAI,MAAM,SAAU;AACpB,UAAI,MAAM,WAAW,EAAG;AAExB,iBAAW,QAAQ;AACnB,gBAAU,QAAQ,EAAE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAA;AAC7C,cAAQ,QAAQ,EAAE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAA;AAAA,IAC7C;AAEA,aAAS,qBAAqB,MAAY,OAAmB;AAC3D,kBAAY,QAAQ,KAAK;AACzB,WAAK,cAAc,KAAK,IAAI,KAAK;AAEjC,UAAI,WAAW,SAAS,MAAM,kBAAkB,aAAa;AAC3D,gBAAQ,QAAQ,EAAE,KAAK,KAAK,KAAK,KAAK,KAAK,IAAA;AAAA,MAC7C;AAAA,IACF;AAEA,aAAS,uBAAuB;AAC9B,kBAAY,QAAQ;AACpB,WAAK,cAAc,IAAI;AAAA,IACzB;AAEA,aAAS,gBAAgB;AACvB,UAAI,CAAC,WAAW,SAAS,MAAM,kBAAkB,YAAa;AAE9D,YAAM,eAAe,MAAM,KAAK,kBAAkB,KAAK;AACvD,iBAAW,QAAQ;AACnB,gBAAU,QAAQ;AAClB,cAAQ,QAAQ;AAEhB,UAAI,aAAa,SAAS,GAAG;AAC3B,aAAK,qBAAqB,YAAY;AACtC,aAAK,oBAAoB,YAAY;AAAA,MACvC;AAAA,IACF;AAEA,aAAS,kBAAkB,MAAY,OAAmB;AACxD,YAAM,eAAA;AACN,WAAK,gBAAgB,KAAK,IAAI,KAAK;AAAA,IACrC;AAGA,aAAS,gBAAgB,MAAY,OAAkB;AACrD,UAAI,MAAM,YAAY,MAAM,YAAY,MAAM,kBAAkB,OAAQ;AACxE,UAAI,CAAC,KAAK,WAAY;AAEtB,qBAAe,QAAQ,KAAK;AAC5B,UAAI,MAAM,cAAc;AACtB,cAAM,aAAa,gBAAgB;AACnC,cAAM,aAAa,QAAQ,cAAc,KAAK,EAAE;AAAA,MAClD;AAAA,IACF;AAEA,aAAS,eAAe,MAAY,OAAkB;AACpD,UAAI,MAAM,kBAAkB,UAAU,CAAC,eAAe,MAAO;AAC7D,YAAM,eAAA;AACN,UAAI,MAAM,cAAc;AACtB,cAAM,aAAa,aAAa;AAAA,MAClC;AACA,qBAAe,QAAQ,KAAK;AAAA,IAC9B;AAEA,aAAS,kBAAkB;AACzB,qBAAe,QAAQ;AAAA,IACzB;AAEA,aAAS,WAAW,MAAY,OAAkB;AAChD,YAAM,eAAA;AACN,UAAI,MAAM,kBAAkB,UAAU,CAAC,eAAe,MAAO;AAE7D,YAAM,WAAW,eAAe;AAChC,YAAM,WAAW,KAAK;AAEtB,UAAI,aAAa,UAAU;AACzB,aAAK,aAAa,UAAU,QAAQ;AAAA,MACtC;AAEA,qBAAe,QAAQ;AACvB,qBAAe,QAAQ;AAAA,IACzB;AAEA,aAAS,gBAAgB;AACvB,qBAAe,QAAQ;AACvB,qBAAe,QAAQ;AAAA,IACzB;AAEA,aAAS,cAAc,OAAsB;AAC3C,UAAI,MAAM,YAAY,MAAM,SAAU;AAEtC,UAAI,MAAM,QAAQ,UAAU;AAC1B,YAAI,cAAc,OAAO;AACvB,wBAAc,QAAQ;AACtB;AAAA,QACF;AACA,aAAK,qBAAqB,EAAE;AAC5B,aAAK,oBAAoB,EAAE;AAAA,MAC7B;AAEA,WAAK,MAAM,QAAQ,OAAO,MAAM,QAAQ,SAAS,MAAM,WAAW,MAAM,UAAU;AAChF,cAAM,eAAA;AACN,cAAM,WAAW,SAAS,MAAM,KAAA,EAAO,IAAI,CAAA,MAAK,EAAE,EAAE;AACpD,aAAK,qBAAqB,QAAQ;AAClC,aAAK,oBAAoB,QAAQ;AAAA,MACnC;AAAA,IACF;AAEA,cAAU,MAAM;AACd,eAAS,iBAAiB,WAAW,aAAa;AAClD,eAAS,iBAAiB,WAAW,aAAa;AAAA,IACpD,CAAC;AAED,gBAAY,MAAM;AAChB,eAAS,oBAAoB,WAAW,aAAa;AACrD,eAAS,oBAAoB,WAAW,aAAa;AAAA,IACvD,CAAC;AAED,UAAM,iBAAiB;AAAA,MAAS,MAC9B,WAAW,QAAQ,KAAK;AAAA,QACtB,WAAW,SAAS,MAAM,IAAI;AAAA,QAC9B,iBAAiB;AAAA,MAAA;AAAA,IACnB;AAGF,UAAM,aAAa,SAAS,OAAO;AAAA,MACjC,gBAAgB;AAAA,MAChB,eAAe,WAAW,MAAM;AAAA,MAChC,GAAI,WAAW,QAAQ,EAAE,OAAO,QAAQ,aAAa,YAAqB,CAAA;AAAA,IAAC,EAC3E;;;0BAIAA,mBA2JM,OAAA;AAAA,iBA1JA;AAAA,QAAJ,KAAI;AAAA,QACH,yCAA0B,WAAA,QAAU,yBAAA,wBAAA,CAAA;AAAA,QACpC,sBAAO,eAAA,KAAc;AAAA,MAAA;QAEtBC,mBAwIM,OAxIN,YAwIM;AAAA,UAvIJA,mBAsIM,OAtIN,YAsIM;AAAA,YArIJA,mBAoGQ,SAAA;AAAA,uBAnGF;AAAA,cAAJ,KAAI;AAAA,cACJ,OAAM;AAAA,cACN,MAAK;AAAA,cACJ,cAAU,GAAK,MAAM,MAAM;AAAA,cAC3B,sBAAO,WAAA,KAAU;AAAA,YAAA;cAGP,MAAM,2BAAnBD,mBAYQ,SAAA,YAAA;AAAA,gBAXNC,mBAUK,MAAA,MAAA;AAAA,kBATHA,mBAAqF,MAAA;AAAA,oBAAhF,+BAAgB,WAAA,MAAW,aAAW,QAAU,WAAA,MAAW,aAAA,CAAY;AAAA,kBAAA;oCAC5ED,mBAOKE,UAAA,MAAAC,WANW,UAAA,OAAS,CAAhB,QAAG;wCADZH,mBAOK,MAAA;AAAA,sBALF,KAAK;AAAA,sBACN,OAAM;AAAA,sBACL,gCAAiB,WAAA,MAAW,cAAY,UAAY,WAAA,MAAW,SAAA,CAAQ;AAAA,oBAAA,mBAErE,GAAG,GAAA,CAAA;AAAA;;;cAIZC,mBA8EQ,SAAA,MAAA;AAAA,iBA7ENG,UAAA,IAAA,GAAAJ,mBA4EKE,UAAA,MAAAC,WA5EyB,SAAA,OAAQ,CAA1B,KAAK,aAAQ;sCAAzBH,mBA4EK,MAAA;AAAA,oBA5EoC,KAAK;AAAA,oBAAU,MAAK;AAAA,kBAAA;oBAGnD,MAAM,2BADdA,mBAMK,MAAA;AAAA;sBAJH,OAAM;AAAA,sBACL,+BAAgB,WAAA,MAAW,aAAW,QAAU,WAAA,MAAW,YAAU,UAAY,iBAAW,wBAAwB,WAAA,MAAW,YAAU,UAAY,WAAA,MAAW,SAAA,CAAQ;AAAA,oBAAA,GAEtKK,gBAAA,UAAA,MAAU,QAAQ,CAAA,GAAA,CAAA;sCAIvBL,mBAgEKE,UAAA,MAAAC,WAhEc,KAAG,CAAX,SAAI;0CAAfH,mBAgEK,MAAA;AAAA,wBAhEoB,KAAK,KAAK;AAAA,wBAAI,OAAM;AAAA,sBAAA;wBAC3CC,mBA8DM,OAAA;AAAA,0BA7DJ,MAAK;AAAA,0BACL,UAAS;AAAA,0BACR,cAAU,QAAU,KAAK,EAAE,GAAG,KAAK,aAAU,kBAAqB,KAAK,UAAU,KAAA,EAAA,GAAU,KAAK,UAAU,SAAS,YAAe,KAAK,KAAK,KAAA,EAAA;AAAA,0BAC5I,iBAAe,WAAW,KAAK,EAAE;AAAA,0BACjC,iBAAe,MAAM,YAAY,KAAK,UAAK;AAAA,0BAC3C,WAAW,MAAM,kBAAa,UAAA,CAAA,CAAiB,KAAK;AAAA,0BACpD,OAAKK,eAAE,eAAe,IAAI,CAAA;AAAA,0BAC1B,OAAKC,eAAA;AAAA,mCAA6B,WAAA,QAAU,SAAY,WAAA,MAAW;AAAA,4BAAqC,QAAA,WAAA,MAAW;AAAA,sCAAwC,WAAA,QAAU,MAAS,WAAA,MAAW;AAAA,4BAAwC,WAAA,WAAA,MAAW;AAAA;4BAAmF,UAAA,WAAA,MAAW;AAAA,4BAA+B,GAAA,aAAa,IAAI;AAAA,0BAAA;0BAS1X,UAAU,KAAK,EAAE,GAAG,KAAK,aAAU,KAAQ,KAAK,UAAU,UAAU,aAAa,IAAI,IAAA,MAAU,aAAa,IAAI,CAAA,KAAA,EAAA;AAAA,0BAChH,SAAK,CAAA,WAAE,gBAAgB,MAAM,MAAM;AAAA,0BACnC,aAAS,CAAA,WAAE,oBAAoB,MAAM,MAAM;AAAA,0BAC3C,cAAU,CAAA,WAAE,qBAAqB,MAAM,MAAM;AAAA,0BAC7C,cAAY;AAAA,0BACZ,eAAW,CAAA,WAAE,kBAAkB,MAAM,MAAM;AAAA,0BAC3C,aAAS,CAAA,WAAE,gBAAgB,MAAM,MAAM;AAAA,0BACvC,YAAQC,cAAA,CAAA,WAAU,eAAe,MAAM,MAAM,GAAA,CAAA,SAAA,CAAA;AAAA,0BAC7C,aAAW;AAAA,0BACX,QAAIA,cAAA,CAAA,WAAU,WAAW,MAAM,MAAM,GAAA,CAAA,SAAA,CAAA;AAAA,0BACrC,WAAS;AAAA,0BACT,WAAO;AAAA,iDAAQ,gBAAgB,MAAM,MAAM,GAAA,CAAA,OAAA,CAAA;AAAA,+DACpB,gBAAgB,MAAM,MAAM,GAAA,CAAA,SAAA,CAAA,GAAA,CAAA,OAAA,CAAA;AAAA,0BAAA;AAAA;0BAI5C,aAAa,IAAI,KADzBJ,UAAA,GAAAJ,mBAKO,QALP,YAKOK,gBADF,aAAa,IAAI,CAAA,GAAA,CAAA,KAIT,uBAAuB,IAAI,KADxCD,UAAA,GAAAJ,mBAKO,QALP,YAKOK,gBADF,uBAAuB,IAAI,CAAA,GAAA,CAAA,KAInB,MAAM,eADnBD,UAAA,GAAAJ,mBAKO,QALP,YAKOK,gBADF,KAAK,EAAE,GAAA,CAAA;0BAKJ,aAAa,IAAI,kBADzBL,mBAOO,QAAA;AAAA;4BALL,OAAM;AAAA,4BACL,OAAKO,eAAA,EAAA,iBAAqB,aAAa,IAAI,EAAG,OAAK;AAAA,4BACnD,OAAO,aAAa,IAAI,EAAG,SAAI,MAAA,kBAAA,GAAgC,aAAa,IAAI,EAAG,IAAI;AAAA,0BAAA,mBAErF,aAAa,IAAI,EAAG,IAAI,GAAA,IAAA,UAAA;;;;;;;;cAU7B,WAAM,YAAN,mBAAe,YAAW,MAAM,QAAQ,cADhDH,aAAAJ,mBAcM,OAdN,aAcM;AAAA,cAVJC,mBAA8E,QAA9E,aAA8EI,gBAAhC,MAAM,QAAQ,OAAG,CAAA,GAAA,CAAA;AAAA,cAC/DJ,mBAOM,OAPN,aAOM;AAAA,iBANJG,UAAA,IAAA,GAAAJ,mBAKEE,UAAA,MAAAC,WAJ0B,MAAM,QAAQ,eAAU,cAAiB,WAAM,QAAQ,iBAAd,mBAA4B,UAAS,MAAM,QAAQ,eAAe,cAAc,MAAM,QAAQ,cAAU,SAAA,GAAA,CAAnK,OAAO,UAAK;sCADtBH,mBAKE,OAAA;AAAA,oBAHC,KAAK;AAAA,oBACN,OAAM;AAAA,oBACL,yCAA0B,OAAK;AAAA,kBAAA;;;cAGpCC,mBAA8E,QAA9E,aAA8EI,gBAAhC,MAAM,QAAQ,OAAG,CAAA,GAAA,CAAA;AAAA,YAAA;YAItD,MAAM,cAAjBD,UAAA,GAAAJ,mBAYM,OAZN,aAYM;AAAA,gCAXJA,mBAUME,UAAA,MAAAC,WATW,kBAAA,OAAiB,CAAzB,SAAI;oCADbH,mBAUM,OAAA;AAAA,kBARH,KAAK,KAAK;AAAA,kBACX,OAAM;AAAA,gBAAA;kBAENC,mBAGE,QAAA;AAAA,oBAFA,OAAM;AAAA,oBACL,4CAA6B,KAAK,KAAK,MAAA,QAAA,aAA2B,KAAK,KAAK,MAAA;AAAA,kBAAA;kBAE/EA,mBAAwE,QAAxE,aAAwEI,gBAApB,KAAK,KAAK,GAAA,CAAA;AAAA,gBAAA;;;;;QAQ9D,QAAA,YAAY,cAAA,sBADpBI,YAUEC,aAAA;AAAA;UARC,WAAS,cAAA;AAAA,UACT,aAAW,QAAA,MAAM,cAAA,KAAa;AAAA,UAC9B,eAAa,QAAA;AAAA,UACb,4BAA0B,QAAA;AAAA,UAC1B,UAAU,kBAAA;AAAA,UACV,QAAM;AAAA,UACN,SAAO;AAAA,UACP,SAAO;AAAA,QAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"WellPlate.vue.js","sources":["../../src/components/WellPlate.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport type { WellPlateFormat, WellPlateSelectionMode, WellPlateSize, Well, HeatmapConfig, WellShape, WellEditField, WellEditData, WellLegendItem, ColumnCondition, RowCondition } from '../types'\nimport WellEditPopup from './WellEditPopup.vue'\n\ninterface Props {\n modelValue?: string[]\n format?: WellPlateFormat\n wells?: Record<string, Partial<Well>>\n selectionMode?: WellPlateSelectionMode\n showLabels?: boolean\n showWellIds?: boolean\n showSampleTypeIndicator?: boolean\n heatmap?: HeatmapConfig\n sampleColors?: Record<string, string>\n zoom?: number\n disabled?: boolean\n readonly?: boolean\n size?: WellPlateSize\n wellShape?: WellShape\n showWellLabels?: boolean\n showBadges?: boolean\n editable?: boolean\n editFields?: WellEditField[]\n defaultInjectionVolume?: number\n showLegend?: boolean\n legendItems?: WellLegendItem[]\n columnConditions?: ColumnCondition[]\n rowConditions?: RowCondition[]\n}\n\n// Drag state for moving wells\nconst dragSourceWell = ref<string | null>(null)\nconst dragTargetWell = ref<string | null>(null)\n\nconst props = withDefaults(defineProps<Props>(), {\n modelValue: () => [],\n format: 96,\n wells: () => ({}),\n selectionMode: 'multiple',\n showLabels: true,\n showWellIds: false,\n showSampleTypeIndicator: false,\n heatmap: () => ({ enabled: false }),\n sampleColors: () => ({}),\n zoom: 1,\n disabled: false,\n readonly: false,\n size: 'md',\n wellShape: 'rounded',\n showWellLabels: false,\n showBadges: false,\n editable: false,\n editFields: () => ['label', 'sampleType', 'injectionVolume', 'injectionCount', 'customMethod'],\n defaultInjectionVolume: 5,\n showLegend: false,\n legendItems: undefined,\n columnConditions: () => [],\n rowConditions: () => [],\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [wellIds: string[]]\n 'well-click': [wellId: string, event: MouseEvent]\n 'well-hover': [wellId: string | null, event?: MouseEvent]\n 'selection-change': [wellIds: string[]]\n 'context-menu': [wellId: string, event: MouseEvent]\n 'well-move': [sourceWellId: string, targetWellId: string]\n 'well-edit': [wellId: string, data: WellEditData]\n 'well-clear': [wellId: string]\n}>()\n\nconst plateRef = ref<HTMLElement | null>(null)\nconst tableRef = ref<HTMLElement | null>(null)\nconst isDragging = ref(false)\nconst dragStart = ref<{ row: number; col: number } | null>(null)\nconst dragEnd = ref<{ row: number; col: number } | null>(null)\nconst hoveredWell = ref<string | null>(null)\n\n// Edit popup state\nconst editingWellId = ref<string | null>(null)\nconst editPopupPosition = ref({ x: 0, y: 0 })\n\nconst PLATE_CONFIGS: Record<WellPlateFormat, { rows: number; cols: number }> = {\n 6: { rows: 2, cols: 3 },\n 12: { rows: 3, cols: 4 },\n 24: { rows: 4, cols: 6 },\n 48: { rows: 6, cols: 8 },\n 54: { rows: 6, cols: 9 },\n 96: { rows: 8, cols: 12 },\n 384: { rows: 16, cols: 24 },\n}\n\nconst plateConfig = computed(() => PLATE_CONFIGS[props.format])\n\nconst rowLabels = computed(() =>\n Array.from({ length: plateConfig.value.rows }, (_, i) => String.fromCharCode(65 + i))\n)\n\nconst colLabels = computed(() =>\n Array.from({ length: plateConfig.value.cols }, (_, i) => i + 1)\n)\n\nconst wellGrid = computed(() => {\n const grid: Well[][] = []\n for (let row = 0; row < plateConfig.value.rows; row++) {\n const rowWells: Well[] = []\n for (let col = 0; col < plateConfig.value.cols; col++) {\n const id = `${rowLabels.value[row]}${col + 1}`\n const wellData = props.wells[id] || {}\n rowWells.push({\n id,\n row,\n col,\n state: wellData.state || 'empty',\n sampleType: wellData.sampleType,\n value: wellData.value,\n metadata: wellData.metadata,\n })\n }\n grid.push(rowWells)\n }\n return grid\n})\n\nconst selectedWellSet = computed(() => new Set(props.modelValue))\n\nconst dragSelectedWells = computed(() => {\n if (!isDragging.value || !dragStart.value || !dragEnd.value) return new Set<string>()\n\n const minRow = Math.min(dragStart.value.row, dragEnd.value.row)\n const maxRow = Math.max(dragStart.value.row, dragEnd.value.row)\n const minCol = Math.min(dragStart.value.col, dragEnd.value.col)\n const maxCol = Math.max(dragStart.value.col, dragEnd.value.col)\n\n const wells = new Set<string>()\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const id = `${rowLabels.value[row]}${col + 1}`\n wells.add(id)\n }\n }\n return wells\n})\n\n// Size presets with pixel values for reliable sizing\nconst sizeConfig = computed(() => {\n const sizes = {\n sm: { cellWidth: '40px', cellHeight: '40px', headerWidth: '32px', headerHeight: '32px', fontSize: '0.625rem', gap: '2px' },\n md: { cellWidth: '56px', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '3px' },\n lg: { cellWidth: '80px', cellHeight: '40px', headerWidth: '40px', headerHeight: '32px', fontSize: '0.875rem', gap: '4px' },\n xl: { cellWidth: '96px', cellHeight: '48px', headerWidth: '48px', headerHeight: '40px', fontSize: '1rem', gap: '4px' },\n fill: { cellWidth: '100%', cellHeight: '32px', headerWidth: '32px', headerHeight: '24px', fontSize: '0.75rem', gap: '2px' },\n }\n return sizes[props.size]\n})\n\nconst isFillMode = computed(() => props.size === 'fill')\n\n// Default legend items\nconst defaultLegendItems: WellLegendItem[] = [\n { type: 'sample', label: 'Sample', color: '#10b981' },\n { type: 'blank', label: 'Blank', color: '#f97316' },\n { type: 'qc', label: 'QC', color: '#8b5cf6' },\n]\n\nconst activeLegendItems = computed(() => props.legendItems ?? defaultLegendItems)\n\n// --- Condition header helpers ---\n\nconst hasColumnConditions = computed(() => props.columnConditions.length > 0)\nconst hasRowConditions = computed(() => props.rowConditions.length > 0)\n\n// Map column index (1-based) → ColumnCondition\nconst colConditionMap = computed(() => {\n const map = new Map<number, { condition: ColumnCondition; indexInGroup: number }>()\n for (const cond of props.columnConditions) {\n cond.cols.forEach((col, i) => {\n map.set(col, { condition: cond, indexInGroup: i })\n })\n }\n return map\n})\n\n// Map row letter → RowCondition\nconst rowConditionMap = computed(() => {\n const map = new Map<string, { condition: RowCondition; indexInGroup: number }>()\n for (const cond of props.rowConditions) {\n cond.rows.forEach((row, i) => {\n map.set(row, { condition: cond, indexInGroup: i })\n })\n }\n return map\n})\n\ntype ColSpan = { condition: ColumnCondition; colspan: number } | { gap: true; colspan: number }\ntype RowSpan = { condition: RowCondition; rowspan: number; startRow: number } | { gap: true; rowspan: number; startRow: number }\n\n// Build column condition header spans for the label row (drug name + unit)\nconst colConditionSpans = computed<ColSpan[]>(() => {\n const spans: ColSpan[] = []\n const cols = colLabels.value\n let i = 0\n while (i < cols.length) {\n const entry = colConditionMap.value.get(cols[i])\n if (entry?.indexInGroup === 0) {\n spans.push({ condition: entry.condition, colspan: entry.condition.cols.length })\n i += entry.condition.cols.length\n } else {\n let gapCount = 0\n while (i + gapCount < cols.length && !colConditionMap.value.has(cols[i + gapCount])) {\n gapCount++\n }\n spans.push({ gap: true, colspan: gapCount || 1 })\n i += gapCount || 1\n }\n }\n return spans\n})\n\n// Build row condition spans for the label column (drug name rotated)\nconst rowConditionSpans = computed<RowSpan[]>(() => {\n const spans: RowSpan[] = []\n const rows = rowLabels.value\n let i = 0\n while (i < rows.length) {\n const entry = rowConditionMap.value.get(rows[i])\n if (entry?.indexInGroup === 0) {\n spans.push({ condition: entry.condition, rowspan: entry.condition.rows.length, startRow: i })\n i += entry.condition.rows.length\n } else {\n let gapCount = 0\n while (i + gapCount < rows.length && !rowConditionMap.value.has(rows[i + gapCount])) {\n gapCount++\n }\n spans.push({ gap: true, rowspan: gapCount || 1, startRow: i })\n i += gapCount || 1\n }\n }\n return spans\n})\n\n// Map row index → span info (only contains entries for first row of each span)\nconst rowConditionSpanByRow = computed(() => {\n const map = new Map<number, RowSpan>()\n for (const span of rowConditionSpans.value) {\n map.set(span.startRow, span)\n }\n return map\n})\n\n// Compute gradient background for a condition cell: opacity ramps from 12% to 50% across the group\nfunction conditionGradientBg(color: string, index: number, total: number): string {\n const t = total <= 1 ? 1 : index / (total - 1)\n const opacity = 0.12 + t * 0.38\n const r = parseInt(color.slice(1, 3), 16)\n const g = parseInt(color.slice(3, 5), 16)\n const b = parseInt(color.slice(5, 7), 16)\n return `rgba(${r}, ${g}, ${b}, ${opacity})`\n}\n\n// Format concentration value (drop trailing zeros)\nfunction formatConc(value: number): string {\n if (value >= 1000) return `${value / 1000}k`\n if (value < 0.01) return value.toExponential(0)\n return String(value)\n}\n\n// Sample type colors (matching MSExpDesigner)\nconst defaultSampleTypeColors: Record<string, { bg: string; border: string }> = {\n sample: { bg: 'rgba(16, 185, 129, 0.15)', border: 'rgba(16, 185, 129, 0.4)' },\n control: { bg: 'rgba(59, 130, 246, 0.15)', border: 'rgba(59, 130, 246, 0.4)' },\n blank: { bg: 'rgba(249, 115, 22, 0.15)', border: 'rgba(249, 115, 22, 0.4)' },\n qc: { bg: 'rgba(139, 92, 246, 0.15)', border: 'rgba(139, 92, 246, 0.4)' },\n}\n\nconst heatmapColors: Record<string, string[]> = {\n viridis: ['#440154', '#482878', '#3e4989', '#31688e', '#26828e', '#1f9e89', '#35b779', '#6ece58', '#b5de2b', '#fde725'],\n plasma: ['#0d0887', '#46039f', '#7201a8', '#9c179e', '#bd3786', '#d8576b', '#ed7953', '#fb9f3a', '#fdca26', '#f0f921'],\n turbo: ['#30123b', '#4145ab', '#4675ed', '#39a2fc', '#1bcfd4', '#24e79e', '#71f05f', '#c1f034', '#f1c83c', '#f99538', '#e45a31', '#ba2512', '#7a0403'],\n}\n\nfunction getHeatmapColor(value: number | undefined): string | null {\n if (!props.heatmap?.enabled || value === undefined) return null\n\n const min = props.heatmap.min ?? 0\n const max = props.heatmap.max ?? 1\n const normalized = Math.max(0, Math.min(1, (value - min) / (max - min)))\n\n const colors = props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length\n ? props.heatmap.customColors\n : heatmapColors[props.heatmap.colorScale || 'viridis']\n\n const index = Math.min(Math.floor(normalized * (colors.length - 1)), colors.length - 1)\n return colors[index]\n}\n\nfunction getWellClasses(well: Well): string[] {\n const isWellSelected = isSelected(well.id)\n const isDragOver = dragSelectedWells.value.has(well.id)\n const isHovered = hoveredWell.value === well.id\n const isDisabled = props.disabled || well.state === 'disabled'\n const isDragSource = dragSourceWell.value === well.id\n const isDragTarget = dragTargetWell.value === well.id\n\n const classes = [\n 'mld-well-plate__well',\n props.wellShape === 'circle' ? 'mld-well-plate__well--circle' : 'mld-well-plate__well--rounded',\n ]\n\n if (props.selectionMode === 'drag' && well.sampleType) {\n classes.push('mld-well-plate__well--draggable')\n }\n\n if (isDragSource) classes.push('mld-well-plate__well--drag-source')\n else if (isDragTarget) classes.push('mld-well-plate__well--drag-target')\n else if (isWellSelected) classes.push('mld-well-plate__well--selected')\n else if (isDragOver) classes.push('mld-well-plate__well--drag-over')\n else if (isHovered && !props.readonly) classes.push('mld-well-plate__well--hovered')\n\n if (isDisabled) classes.push('mld-well-plate__well--disabled')\n if (well.state === 'filled') classes.push('mld-well-plate__well--filled')\n\n return classes\n}\n\nfunction getWellStyle(well: Well): Record<string, string> {\n const heatmapColor = getHeatmapColor(well.value)\n if (heatmapColor) {\n return { backgroundColor: heatmapColor, border: '1px solid transparent' }\n }\n\n if (well.sampleType && props.sampleColors[well.sampleType]) {\n const color = props.sampleColors[well.sampleType]\n return {\n backgroundColor: `${color}26`,\n border: `1px solid ${color}66`,\n }\n }\n\n if (well.sampleType && defaultSampleTypeColors[well.sampleType]) {\n const colors = defaultSampleTypeColors[well.sampleType]\n return {\n backgroundColor: colors.bg,\n border: `1px solid ${colors.border}`,\n }\n }\n\n const borderStyle = well.state === 'filled' ? 'solid' : 'dashed'\n return {\n backgroundColor: 'var(--bg-tertiary)',\n border: `1px ${borderStyle} var(--border-color)`,\n }\n}\n\nfunction getSampleTypeIndicator(well: Well): string | null {\n if (!props.showSampleTypeIndicator || !well.sampleType) return null\n const typeMap: Record<string, string> = {\n sample: 'S',\n control: 'C',\n blank: 'B',\n qc: 'Q',\n }\n return typeMap[well.sampleType] || well.sampleType.charAt(0).toUpperCase()\n}\n\nfunction getWellLabel(well: Well): string | undefined {\n if (!props.showWellLabels) return undefined\n return well.metadata?.label as string | undefined\n}\n\nfunction getWellBadge(well: Well): { text: string; color: string } | null {\n if (!props.showBadges || !well.metadata) return null\n const count = well.metadata.injectionCount as number | undefined\n if (count && count > 1) {\n return { text: String(count), color: '#6366f1' }\n }\n if (well.metadata.customMethod) {\n return { text: '+', color: '#ec4899' }\n }\n return null\n}\n\nfunction isSelected(wellId: string): boolean {\n return selectedWellSet.value.has(wellId) || dragSelectedWells.value.has(wellId)\n}\n\nfunction handleWellClick(well: Well, event: MouseEvent) {\n if (props.disabled || props.readonly) return\n\n emit('well-click', well.id, event)\n\n // When editable, open popup instead of modifying selection\n if (props.editable) {\n openEditPopup(well.id, event)\n return\n }\n\n if (props.selectionMode === 'none') return\n\n const isCurrentlySelected = selectedWellSet.value.has(well.id)\n const isMultiSelect = event.shiftKey || event.metaKey || event.ctrlKey\n\n let newSelection: string[]\n if (props.selectionMode === 'single') {\n newSelection = isCurrentlySelected ? [] : [well.id]\n } else if (isMultiSelect) {\n newSelection = isCurrentlySelected\n ? props.modelValue.filter(id => id !== well.id)\n : [...props.modelValue, well.id]\n } else {\n newSelection = isCurrentlySelected && props.modelValue.length === 1 ? [] : [well.id]\n }\n\n emit('update:modelValue', newSelection)\n emit('selection-change', newSelection)\n}\n\nfunction openEditPopup(wellId: string, event: MouseEvent) {\n const target = event.currentTarget as HTMLElement\n const rect = target.getBoundingClientRect()\n editPopupPosition.value = {\n x: rect.right + 8,\n y: rect.top,\n }\n editingWellId.value = wellId\n}\n\nfunction handleEditSave(data: WellEditData) {\n emit('well-edit', data.wellId, data)\n editingWellId.value = null\n}\n\nfunction handleEditClear() {\n if (editingWellId.value) {\n emit('well-clear', editingWellId.value)\n }\n editingWellId.value = null\n}\n\nfunction handleEditClose() {\n editingWellId.value = null\n}\n\nfunction handleWellMouseDown(well: Well, event: MouseEvent) {\n if (props.disabled || props.readonly || props.selectionMode !== 'rectangle') return\n if (props.editable) return\n if (event.button !== 0) return\n\n isDragging.value = true\n dragStart.value = { row: well.row, col: well.col }\n dragEnd.value = { row: well.row, col: well.col }\n}\n\nfunction handleWellMouseEnter(well: Well, event: MouseEvent) {\n hoveredWell.value = well.id\n emit('well-hover', well.id, event)\n\n if (isDragging.value && props.selectionMode === 'rectangle') {\n dragEnd.value = { row: well.row, col: well.col }\n }\n}\n\nfunction handleWellMouseLeave() {\n hoveredWell.value = null\n emit('well-hover', null)\n}\n\nfunction handleMouseUp() {\n if (!isDragging.value || props.selectionMode !== 'rectangle') return\n\n const newSelection = Array.from(dragSelectedWells.value)\n isDragging.value = false\n dragStart.value = null\n dragEnd.value = null\n\n if (newSelection.length > 0) {\n emit('update:modelValue', newSelection)\n emit('selection-change', newSelection)\n }\n}\n\nfunction handleContextMenu(well: Well, event: MouseEvent) {\n event.preventDefault()\n emit('context-menu', well.id, event)\n}\n\n// Drag handlers for moving well contents\nfunction handleDragStart(well: Well, event: DragEvent) {\n if (props.disabled || props.readonly || props.selectionMode !== 'drag') return\n if (!well.sampleType) return\n\n dragSourceWell.value = well.id\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move'\n event.dataTransfer.setData('text/plain', well.id)\n }\n}\n\nfunction handleDragOver(well: Well, event: DragEvent) {\n if (props.selectionMode !== 'drag' || !dragSourceWell.value) return\n event.preventDefault()\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = 'move'\n }\n dragTargetWell.value = well.id\n}\n\nfunction handleDragLeave() {\n dragTargetWell.value = null\n}\n\nfunction handleDrop(well: Well, event: DragEvent) {\n event.preventDefault()\n if (props.selectionMode !== 'drag' || !dragSourceWell.value) return\n\n const sourceId = dragSourceWell.value\n const targetId = well.id\n\n if (sourceId !== targetId) {\n emit('well-move', sourceId, targetId)\n }\n\n dragSourceWell.value = null\n dragTargetWell.value = null\n}\n\nfunction handleDragEnd() {\n dragSourceWell.value = null\n dragTargetWell.value = null\n}\n\nfunction handleKeyDown(event: KeyboardEvent) {\n if (props.disabled || props.readonly) return\n\n if (event.key === 'Escape') {\n if (editingWellId.value) {\n editingWellId.value = null\n return\n }\n emit('update:modelValue', [])\n emit('selection-change', [])\n }\n\n if ((event.key === 'a' || event.key === 'A') && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n const allWells = wellGrid.value.flat().map(w => w.id)\n emit('update:modelValue', allWells)\n emit('selection-change', allWells)\n }\n}\n\nonMounted(() => {\n document.addEventListener('mouseup', handleMouseUp)\n document.addEventListener('keydown', handleKeyDown)\n})\n\nonUnmounted(() => {\n document.removeEventListener('mouseup', handleMouseUp)\n document.removeEventListener('keydown', handleKeyDown)\n})\n\nconst containerStyle = computed(() =>\n isFillMode.value ? {} : {\n transform: `scale(${props.zoom})`,\n transformOrigin: 'top left',\n }\n)\n\nconst tableStyle = computed(() => ({\n borderCollapse: 'separate' as const,\n borderSpacing: sizeConfig.value.gap,\n ...(isFillMode.value ? { width: '100%', tableLayout: 'fixed' as const } : {}),\n}))\n</script>\n\n<template>\n <div\n ref=\"plateRef\"\n :class=\"['mld-well-plate', isFillMode ? 'mld-well-plate--fill' : 'mld-well-plate--inline']\"\n :style=\"containerStyle\"\n >\n <div class=\"mld-well-plate__scroll\">\n <div class=\"mld-well-plate__content\">\n <table\n ref=\"tableRef\"\n class=\"mld-well-plate__table\"\n role=\"grid\"\n :aria-label=\"`${props.format}-well plate`\"\n :style=\"tableStyle\"\n >\n <!-- Column condition label row (drug name + unit) -->\n <thead v-if=\"hasColumnConditions\">\n <tr>\n <!-- Spacer for row header column -->\n <th :style=\"{ width: sizeConfig.headerWidth }\"></th>\n <!-- Spacer for row condition column -->\n <th v-if=\"hasRowConditions\" :style=\"{ width: sizeConfig.headerWidth }\"></th>\n <template v-for=\"(span, idx) in colConditionSpans\" :key=\"'clabel-' + idx\">\n <th\n v-if=\"'condition' in span\"\n :colspan=\"span.colspan\"\n class=\"mld-well-plate__condition-label\"\n :style=\"{\n height: sizeConfig.headerHeight,\n fontSize: sizeConfig.fontSize,\n color: span.condition.color,\n }\"\n >\n {{ span.condition.label }}<template v-if=\"span.condition.unit\"> ({{ span.condition.unit }})</template>\n </th>\n <th v-else :colspan=\"span.colspan\"></th>\n </template>\n </tr>\n </thead>\n <!-- Column headers (with concentration overlay when conditions present) -->\n <thead v-if=\"props.showLabels\">\n <tr>\n <th :style=\"{ width: sizeConfig.headerWidth, height: sizeConfig.headerHeight }\"></th>\n <!-- Spacer for row condition column in column header row -->\n <th v-if=\"hasRowConditions\" :style=\"{ width: sizeConfig.headerWidth, height: sizeConfig.headerHeight }\"></th>\n <th\n v-for=\"col in colLabels\"\n :key=\"col\"\n class=\"mld-well-plate__col-header\"\n :style=\"{ height: sizeConfig.headerHeight, fontSize: sizeConfig.fontSize }\"\n >\n <template v-for=\"entry in [colConditionMap.get(col)]\" :key=\"col\">\n <span\n v-if=\"entry\"\n class=\"mld-well-plate__condition-cell\"\n :style=\"{\n backgroundColor: conditionGradientBg(\n entry.condition.color,\n entry.indexInGroup,\n entry.condition.cols.length,\n ),\n }\"\n >\n {{ formatConc(entry.condition.concentrations[entry.indexInGroup]) }}\n </span>\n <template v-else>{{ col }}</template>\n </template>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, rowIndex) in wellGrid\" :key=\"rowIndex\" role=\"row\">\n <!-- Row condition label cell (drug name, spans multiple rows) -->\n <template v-if=\"hasRowConditions && rowConditionSpanByRow.has(rowIndex)\">\n <td\n v-for=\"span in [rowConditionSpanByRow.get(rowIndex)!]\"\n :key=\"rowIndex\"\n :rowspan=\"span.rowspan\"\n :class=\"[\n 'mld-well-plate__row-condition-label',\n 'gap' in span ? 'mld-well-plate__row-condition-label--empty' : '',\n ]\"\n :style=\"{\n width: sizeConfig.headerWidth,\n minWidth: sizeConfig.headerWidth,\n fontSize: sizeConfig.fontSize,\n ...('condition' in span ? { color: span.condition.color } : {}),\n }\"\n >\n <div v-if=\"'condition' in span\" class=\"mld-well-plate__row-condition-wrap\">\n <span class=\"mld-well-plate__row-condition-text\">{{ span.condition.label }}</span>\n </div>\n </td>\n </template>\n <!-- Row header (with concentration overlay when conditions present) -->\n <td\n v-if=\"props.showLabels\"\n class=\"mld-well-plate__row-header\"\n :style=\"{\n width: sizeConfig.headerWidth,\n height: sizeConfig.cellHeight,\n minWidth: sizeConfig.headerWidth,\n minHeight: sizeConfig.cellHeight,\n fontSize: sizeConfig.fontSize,\n }\"\n >\n <template v-for=\"entry in [rowConditionMap.get(rowLabels[rowIndex])]\" :key=\"rowIndex\">\n <span\n v-if=\"entry\"\n class=\"mld-well-plate__condition-cell\"\n :style=\"{\n backgroundColor: conditionGradientBg(\n entry.condition.color,\n entry.indexInGroup,\n entry.condition.rows.length,\n ),\n }\"\n >\n {{ formatConc(entry.condition.concentrations[entry.indexInGroup]) }}\n </span>\n <template v-else>{{ rowLabels[rowIndex] }}</template>\n </template>\n </td>\n\n <!-- Wells -->\n <td v-for=\"well in row\" :key=\"well.id\" class=\"mld-well-plate__cell\">\n <div\n role=\"gridcell\"\n tabindex=\"0\"\n :aria-label=\"`Well ${well.id}${well.sampleType ? `, Sample type: ${well.sampleType}` : ''}${well.value !== undefined ? `, Value: ${well.value}` : ''}`\"\n :aria-selected=\"isSelected(well.id)\"\n :aria-disabled=\"props.disabled || well.state === 'disabled'\"\n :draggable=\"props.selectionMode === 'drag' && !!well.sampleType\"\n :class=\"getWellClasses(well)\"\n :style=\"{\n width: isFillMode ? '100%' : sizeConfig.cellWidth,\n height: sizeConfig.cellHeight,\n minWidth: isFillMode ? '0' : sizeConfig.cellWidth,\n minHeight: sizeConfig.cellHeight,\n boxSizing: 'border-box',\n fontSize: sizeConfig.fontSize,\n ...getWellStyle(well),\n }\"\n :title=\"`${well.id}${well.sampleType ? `: ${well.sampleType}` : ''}${getWellLabel(well) ? ` - ${getWellLabel(well)}` : ''}`\"\n @click=\"handleWellClick(well, $event)\"\n @mousedown=\"handleWellMouseDown(well, $event)\"\n @mouseenter=\"handleWellMouseEnter(well, $event)\"\n @mouseleave=\"handleWellMouseLeave\"\n @contextmenu=\"handleContextMenu(well, $event)\"\n @dragstart=\"handleDragStart(well, $event)\"\n @dragover.prevent=\"handleDragOver(well, $event)\"\n @dragleave=\"handleDragLeave\"\n @drop.prevent=\"handleDrop(well, $event)\"\n @dragend=\"handleDragEnd\"\n @keydown.enter=\"handleWellClick(well, $event as unknown as MouseEvent)\"\n @keydown.space.prevent=\"handleWellClick(well, $event as unknown as MouseEvent)\"\n >\n <!-- Well label text (from metadata.label) -->\n <span\n v-if=\"getWellLabel(well)\"\n class=\"mld-well-plate__label\"\n >\n {{ getWellLabel(well) }}\n </span>\n <!-- Sample type indicator (S/B/Q/C) -->\n <span\n v-else-if=\"getSampleTypeIndicator(well)\"\n class=\"mld-well-plate__indicator\"\n >\n {{ getSampleTypeIndicator(well) }}\n </span>\n <!-- Well ID -->\n <span\n v-else-if=\"props.showWellIds\"\n class=\"mld-well-plate__well-id\"\n >\n {{ well.id }}\n </span>\n\n <!-- Badge (injection count or custom method) -->\n <span\n v-if=\"getWellBadge(well)\"\n class=\"mld-well-plate__badge\"\n :style=\"{ backgroundColor: getWellBadge(well)!.color }\"\n :title=\"getWellBadge(well)!.text === '+' ? 'Custom method' : `${getWellBadge(well)!.text}x injections`\"\n >\n {{ getWellBadge(well)!.text }}\n </span>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n\n <!-- Heatmap legend (inside content wrapper to match table width) -->\n <div\n v-if=\"props.heatmap?.enabled && props.heatmap.showLegend\"\n class=\"mld-well-plate__legend\"\n >\n <span class=\"mld-well-plate__legend-label\">{{ props.heatmap.min ?? 0 }}</span>\n <div class=\"mld-well-plate__legend-bar\">\n <div\n v-for=\"(color, index) in (props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length ? props.heatmap.customColors : heatmapColors[props.heatmap.colorScale || 'viridis'])\"\n :key=\"index\"\n class=\"mld-well-plate__legend-segment\"\n :style=\"{ backgroundColor: color }\"\n />\n </div>\n <span class=\"mld-well-plate__legend-label\">{{ props.heatmap.max ?? 1 }}</span>\n </div>\n\n <!-- Sample type legend bar -->\n <div v-if=\"props.showLegend\" class=\"mld-well-plate__sample-legend\">\n <div\n v-for=\"item in activeLegendItems\"\n :key=\"item.type\"\n class=\"mld-well-plate__sample-legend-item\"\n >\n <span\n class=\"mld-well-plate__sample-legend-dot\"\n :style=\"{ backgroundColor: `${item.color}26`, border: `1px solid ${item.color}66` }\"\n />\n <span class=\"mld-well-plate__sample-legend-text\">{{ item.label }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Edit popup -->\n <WellEditPopup\n v-if=\"editable && editingWellId\"\n :well-id=\"editingWellId\"\n :well-data=\"wells[editingWellId]\"\n :edit-fields=\"editFields\"\n :default-injection-volume=\"defaultInjectionVolume\"\n :position=\"editPopupPosition\"\n @save=\"handleEditSave\"\n @clear=\"handleEditClear\"\n @close=\"handleEditClose\"\n />\n </div>\n</template>\n\n<style>\n@import '../styles/components/well-plate.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_normalizeStyle","_openBlock","_Fragment","_renderList","_createTextVNode","_normalizeClass","_toDisplayString","_withModifiers","_createBlock","WellEditPopup"],"mappings":"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"}
|
package/dist/styles.css
CHANGED
|
@@ -1553,6 +1553,8 @@ html.dark .focus\:ring-offset-2:focus {
|
|
|
1553
1553
|
border-radius: 0.5rem;
|
|
1554
1554
|
font-weight: 500;
|
|
1555
1555
|
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
|
|
1556
|
+
line-height: 1.25;
|
|
1557
|
+
white-space: nowrap;
|
|
1556
1558
|
cursor: pointer;
|
|
1557
1559
|
border: none;
|
|
1558
1560
|
}
|
|
@@ -4817,22 +4819,6 @@ html.dark .mld-toggle__track:focus-visible {
|
|
|
4817
4819
|
border: none !important;
|
|
4818
4820
|
background: transparent !important;
|
|
4819
4821
|
}
|
|
4820
|
-
.mld-well-plate__table--fill {
|
|
4821
|
-
width: 100%;
|
|
4822
|
-
table-layout: fixed;
|
|
4823
|
-
}
|
|
4824
|
-
.mld-well-plate__table--sm {
|
|
4825
|
-
border-spacing: 2px;
|
|
4826
|
-
}
|
|
4827
|
-
.mld-well-plate__table--md {
|
|
4828
|
-
border-spacing: 4px;
|
|
4829
|
-
}
|
|
4830
|
-
.mld-well-plate__table--lg {
|
|
4831
|
-
border-spacing: 4px;
|
|
4832
|
-
}
|
|
4833
|
-
.mld-well-plate__table--xl {
|
|
4834
|
-
border-spacing: 6px;
|
|
4835
|
-
}
|
|
4836
4822
|
/* Header cells */
|
|
4837
4823
|
.mld-well-plate__col-header,
|
|
4838
4824
|
.mld-well-plate__row-header {
|
|
@@ -4840,22 +4826,6 @@ html.dark .mld-toggle__track:focus-visible {
|
|
|
4840
4826
|
text-align: center;
|
|
4841
4827
|
color: var(--text-muted);
|
|
4842
4828
|
}
|
|
4843
|
-
.mld-well-plate__col-header--sm,
|
|
4844
|
-
.mld-well-plate__row-header--sm {
|
|
4845
|
-
font-size: 0.625rem;
|
|
4846
|
-
}
|
|
4847
|
-
.mld-well-plate__col-header--md,
|
|
4848
|
-
.mld-well-plate__row-header--md {
|
|
4849
|
-
font-size: 0.75rem;
|
|
4850
|
-
}
|
|
4851
|
-
.mld-well-plate__col-header--lg,
|
|
4852
|
-
.mld-well-plate__row-header--lg {
|
|
4853
|
-
font-size: 0.875rem;
|
|
4854
|
-
}
|
|
4855
|
-
.mld-well-plate__col-header--xl,
|
|
4856
|
-
.mld-well-plate__row-header--xl {
|
|
4857
|
-
font-size: 1rem;
|
|
4858
|
-
}
|
|
4859
4829
|
.mld-well-plate__row-header {
|
|
4860
4830
|
vertical-align: middle;
|
|
4861
4831
|
}
|
|
@@ -4874,18 +4844,6 @@ html.dark .mld-toggle__track:focus-visible {
|
|
|
4874
4844
|
background-color: var(--bg-tertiary);
|
|
4875
4845
|
border: 1px dashed var(--border-color);
|
|
4876
4846
|
}
|
|
4877
|
-
.mld-well-plate__well--sm {
|
|
4878
|
-
font-size: 0.625rem;
|
|
4879
|
-
}
|
|
4880
|
-
.mld-well-plate__well--md {
|
|
4881
|
-
font-size: 0.75rem;
|
|
4882
|
-
}
|
|
4883
|
-
.mld-well-plate__well--lg {
|
|
4884
|
-
font-size: 0.875rem;
|
|
4885
|
-
}
|
|
4886
|
-
.mld-well-plate__well--xl {
|
|
4887
|
-
font-size: 1rem;
|
|
4888
|
-
}
|
|
4889
4847
|
.mld-well-plate__well--rounded {
|
|
4890
4848
|
border-radius: 0.5rem;
|
|
4891
4849
|
}
|
|
@@ -4964,6 +4922,51 @@ html.dark .mld-toggle__track:focus-visible {
|
|
|
4964
4922
|
background-color: rgba(139, 92, 246, 0.15);
|
|
4965
4923
|
border: 1px solid rgba(139, 92, 246, 0.4);
|
|
4966
4924
|
}
|
|
4925
|
+
/* Condition header - drug label row */
|
|
4926
|
+
.mld-well-plate__condition-label {
|
|
4927
|
+
font-weight: 600;
|
|
4928
|
+
text-align: center;
|
|
4929
|
+
white-space: nowrap;
|
|
4930
|
+
overflow: hidden;
|
|
4931
|
+
text-overflow: ellipsis;
|
|
4932
|
+
letter-spacing: 0.01em;
|
|
4933
|
+
padding: 2px 4px !important;
|
|
4934
|
+
}
|
|
4935
|
+
/* Condition cell - inner span with gradient bg (avoids table !important reset) */
|
|
4936
|
+
.mld-well-plate__condition-cell {
|
|
4937
|
+
display: flex;
|
|
4938
|
+
align-items: center;
|
|
4939
|
+
justify-content: center;
|
|
4940
|
+
width: 100%;
|
|
4941
|
+
height: 100%;
|
|
4942
|
+
border-radius: 4px;
|
|
4943
|
+
font-weight: 600;
|
|
4944
|
+
transition: background-color 0.15s ease;
|
|
4945
|
+
}
|
|
4946
|
+
/* Row condition label cell (rotated text) */
|
|
4947
|
+
.mld-well-plate__row-condition-label {
|
|
4948
|
+
text-align: center;
|
|
4949
|
+
vertical-align: middle;
|
|
4950
|
+
padding: 0 !important;
|
|
4951
|
+
position: relative;
|
|
4952
|
+
height: 1px; /* Trick: allows absolute child to use 100% height in rowspan cells */
|
|
4953
|
+
}
|
|
4954
|
+
.mld-well-plate__row-condition-wrap {
|
|
4955
|
+
position: absolute;
|
|
4956
|
+
inset: 0;
|
|
4957
|
+
display: flex;
|
|
4958
|
+
align-items: center;
|
|
4959
|
+
justify-content: center;
|
|
4960
|
+
}
|
|
4961
|
+
.mld-well-plate__row-condition-text {
|
|
4962
|
+
writing-mode: vertical-lr;
|
|
4963
|
+
transform: rotate(180deg);
|
|
4964
|
+
font-weight: 600;
|
|
4965
|
+
white-space: nowrap;
|
|
4966
|
+
overflow: hidden;
|
|
4967
|
+
text-overflow: ellipsis;
|
|
4968
|
+
letter-spacing: 0.01em;
|
|
4969
|
+
}
|
|
4967
4970
|
/* Heatmap legend */
|
|
4968
4971
|
.mld-well-plate__legend {
|
|
4969
4972
|
margin-top: 0.5rem;
|
|
@@ -9060,6 +9063,11 @@ html.dark .mld-dataframe__loading {
|
|
|
9060
9063
|
letter-spacing: 0.025em;
|
|
9061
9064
|
color: var(--text-muted);
|
|
9062
9065
|
}
|
|
9066
|
+
.mld-rack-editor__toolbar-section {
|
|
9067
|
+
display: flex;
|
|
9068
|
+
align-items: center;
|
|
9069
|
+
gap: 0.5rem;
|
|
9070
|
+
}
|
|
9063
9071
|
.mld-rack-editor__toolbar-divider {
|
|
9064
9072
|
width: 1px;
|
|
9065
9073
|
height: 1.5rem;
|
|
@@ -11121,6 +11129,9 @@ html.dark .mld-settings-modal__option-btn--active {
|
|
|
11121
11129
|
.mld-datetime-picker__footer-btn:hover {
|
|
11122
11130
|
opacity: 0.8;
|
|
11123
11131
|
}
|
|
11132
|
+
.mld-datetime-picker__footer-btn + .mld-datetime-picker__footer-btn {
|
|
11133
|
+
margin-left: 0.75rem;
|
|
11134
|
+
}
|
|
11124
11135
|
.mld-datetime-picker__footer-btn--muted {
|
|
11125
11136
|
color: var(--text-muted);
|
|
11126
11137
|
}
|
|
@@ -11909,6 +11920,8 @@ html.dark .mld-settings-modal__option-btn--active {
|
|
|
11909
11920
|
border-radius: 0.5rem;
|
|
11910
11921
|
font-weight: 500;
|
|
11911
11922
|
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
|
|
11923
|
+
line-height: 1.25;
|
|
11924
|
+
white-space: nowrap;
|
|
11912
11925
|
cursor: pointer;
|
|
11913
11926
|
border: none;
|
|
11914
11927
|
}
|
|
@@ -17196,22 +17209,6 @@ to {
|
|
|
17196
17209
|
border: none !important;
|
|
17197
17210
|
background: transparent !important;
|
|
17198
17211
|
}
|
|
17199
|
-
.mld-well-plate__table--fill {
|
|
17200
|
-
width: 100%;
|
|
17201
|
-
table-layout: fixed;
|
|
17202
|
-
}
|
|
17203
|
-
.mld-well-plate__table--sm {
|
|
17204
|
-
border-spacing: 2px;
|
|
17205
|
-
}
|
|
17206
|
-
.mld-well-plate__table--md {
|
|
17207
|
-
border-spacing: 4px;
|
|
17208
|
-
}
|
|
17209
|
-
.mld-well-plate__table--lg {
|
|
17210
|
-
border-spacing: 4px;
|
|
17211
|
-
}
|
|
17212
|
-
.mld-well-plate__table--xl {
|
|
17213
|
-
border-spacing: 6px;
|
|
17214
|
-
}
|
|
17215
17212
|
|
|
17216
17213
|
/* Header cells */
|
|
17217
17214
|
.mld-well-plate__col-header,
|
|
@@ -17220,22 +17217,6 @@ to {
|
|
|
17220
17217
|
text-align: center;
|
|
17221
17218
|
color: var(--text-muted);
|
|
17222
17219
|
}
|
|
17223
|
-
.mld-well-plate__col-header--sm,
|
|
17224
|
-
.mld-well-plate__row-header--sm {
|
|
17225
|
-
font-size: 0.625rem;
|
|
17226
|
-
}
|
|
17227
|
-
.mld-well-plate__col-header--md,
|
|
17228
|
-
.mld-well-plate__row-header--md {
|
|
17229
|
-
font-size: 0.75rem;
|
|
17230
|
-
}
|
|
17231
|
-
.mld-well-plate__col-header--lg,
|
|
17232
|
-
.mld-well-plate__row-header--lg {
|
|
17233
|
-
font-size: 0.875rem;
|
|
17234
|
-
}
|
|
17235
|
-
.mld-well-plate__col-header--xl,
|
|
17236
|
-
.mld-well-plate__row-header--xl {
|
|
17237
|
-
font-size: 1rem;
|
|
17238
|
-
}
|
|
17239
17220
|
.mld-well-plate__row-header {
|
|
17240
17221
|
vertical-align: middle;
|
|
17241
17222
|
}
|
|
@@ -17256,18 +17237,6 @@ to {
|
|
|
17256
17237
|
background-color: var(--bg-tertiary);
|
|
17257
17238
|
border: 1px dashed var(--border-color);
|
|
17258
17239
|
}
|
|
17259
|
-
.mld-well-plate__well--sm {
|
|
17260
|
-
font-size: 0.625rem;
|
|
17261
|
-
}
|
|
17262
|
-
.mld-well-plate__well--md {
|
|
17263
|
-
font-size: 0.75rem;
|
|
17264
|
-
}
|
|
17265
|
-
.mld-well-plate__well--lg {
|
|
17266
|
-
font-size: 0.875rem;
|
|
17267
|
-
}
|
|
17268
|
-
.mld-well-plate__well--xl {
|
|
17269
|
-
font-size: 1rem;
|
|
17270
|
-
}
|
|
17271
17240
|
.mld-well-plate__well--rounded {
|
|
17272
17241
|
border-radius: 0.5rem;
|
|
17273
17242
|
}
|
|
@@ -17353,6 +17322,54 @@ to {
|
|
|
17353
17322
|
border: 1px solid rgba(139, 92, 246, 0.4);
|
|
17354
17323
|
}
|
|
17355
17324
|
|
|
17325
|
+
/* Condition header - drug label row */
|
|
17326
|
+
.mld-well-plate__condition-label {
|
|
17327
|
+
font-weight: 600;
|
|
17328
|
+
text-align: center;
|
|
17329
|
+
white-space: nowrap;
|
|
17330
|
+
overflow: hidden;
|
|
17331
|
+
text-overflow: ellipsis;
|
|
17332
|
+
letter-spacing: 0.01em;
|
|
17333
|
+
padding: 2px 4px !important;
|
|
17334
|
+
}
|
|
17335
|
+
|
|
17336
|
+
/* Condition cell - inner span with gradient bg (avoids table !important reset) */
|
|
17337
|
+
.mld-well-plate__condition-cell {
|
|
17338
|
+
display: flex;
|
|
17339
|
+
align-items: center;
|
|
17340
|
+
justify-content: center;
|
|
17341
|
+
width: 100%;
|
|
17342
|
+
height: 100%;
|
|
17343
|
+
border-radius: 4px;
|
|
17344
|
+
font-weight: 600;
|
|
17345
|
+
transition: background-color 0.15s ease;
|
|
17346
|
+
}
|
|
17347
|
+
|
|
17348
|
+
/* Row condition label cell (rotated text) */
|
|
17349
|
+
.mld-well-plate__row-condition-label {
|
|
17350
|
+
text-align: center;
|
|
17351
|
+
vertical-align: middle;
|
|
17352
|
+
padding: 0 !important;
|
|
17353
|
+
position: relative;
|
|
17354
|
+
height: 1px; /* Trick: allows absolute child to use 100% height in rowspan cells */
|
|
17355
|
+
}
|
|
17356
|
+
.mld-well-plate__row-condition-wrap {
|
|
17357
|
+
position: absolute;
|
|
17358
|
+
inset: 0;
|
|
17359
|
+
display: flex;
|
|
17360
|
+
align-items: center;
|
|
17361
|
+
justify-content: center;
|
|
17362
|
+
}
|
|
17363
|
+
.mld-well-plate__row-condition-text {
|
|
17364
|
+
writing-mode: vertical-lr;
|
|
17365
|
+
transform: rotate(180deg);
|
|
17366
|
+
font-weight: 600;
|
|
17367
|
+
white-space: nowrap;
|
|
17368
|
+
overflow: hidden;
|
|
17369
|
+
text-overflow: ellipsis;
|
|
17370
|
+
letter-spacing: 0.01em;
|
|
17371
|
+
}
|
|
17372
|
+
|
|
17356
17373
|
/* Heatmap legend */
|
|
17357
17374
|
.mld-well-plate__legend {
|
|
17358
17375
|
margin-top: 0.5rem;
|
|
@@ -17575,6 +17592,11 @@ to {
|
|
|
17575
17592
|
letter-spacing: 0.025em;
|
|
17576
17593
|
color: var(--text-muted);
|
|
17577
17594
|
}
|
|
17595
|
+
.mld-rack-editor__toolbar-section {
|
|
17596
|
+
display: flex;
|
|
17597
|
+
align-items: center;
|
|
17598
|
+
gap: 0.5rem;
|
|
17599
|
+
}
|
|
17578
17600
|
.mld-rack-editor__toolbar-divider {
|
|
17579
17601
|
width: 1px;
|
|
17580
17602
|
height: 1.5rem;
|
|
@@ -22457,6 +22479,9 @@ to { transform: rotate(360deg);
|
|
|
22457
22479
|
.mld-datetime-picker__footer-btn:hover {
|
|
22458
22480
|
opacity: 0.8;
|
|
22459
22481
|
}
|
|
22482
|
+
.mld-datetime-picker__footer-btn + .mld-datetime-picker__footer-btn {
|
|
22483
|
+
margin-left: 0.75rem;
|
|
22484
|
+
}
|
|
22460
22485
|
.mld-datetime-picker__footer-btn--muted {
|
|
22461
22486
|
color: var(--text-muted);
|
|
22462
22487
|
}
|
|
@@ -127,6 +127,18 @@ export interface WellLegendItem {
|
|
|
127
127
|
label: string;
|
|
128
128
|
color: string;
|
|
129
129
|
}
|
|
130
|
+
export interface PlateCondition {
|
|
131
|
+
label: string;
|
|
132
|
+
color: string;
|
|
133
|
+
concentrations: number[];
|
|
134
|
+
unit?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface ColumnCondition extends PlateCondition {
|
|
137
|
+
cols: number[];
|
|
138
|
+
}
|
|
139
|
+
export interface RowCondition extends PlateCondition {
|
|
140
|
+
rows: string[];
|
|
141
|
+
}
|
|
130
142
|
export interface Rack {
|
|
131
143
|
id: string;
|
|
132
144
|
name: string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, } from './components';
|
|
1
|
+
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, PlateCondition, ColumnCondition, RowCondition, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, MoleculeData, StorageCondition, ReagentColumn, Reagent, TreeNodeType, BadgeVariant, TreeNode, } from './components';
|
|
2
2
|
export type { AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, } from './auth';
|
|
3
3
|
export type { PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformContextOptions, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './platform';
|
package/package.json
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref } from 'vue'
|
|
3
|
-
|
|
4
|
-
type AuditEntryType = 'create' | 'update' | 'delete' | 'system'
|
|
5
|
-
|
|
6
|
-
interface AuditEntry {
|
|
7
|
-
id: string
|
|
8
|
-
type: AuditEntryType
|
|
9
|
-
action: string
|
|
10
|
-
detail?: string
|
|
11
|
-
user?: string
|
|
12
|
-
timestamp: Date | string
|
|
13
|
-
metadata?: Record<string, unknown>
|
|
14
|
-
}
|
|
3
|
+
import type { AuditEntryType, AuditEntry } from '../types'
|
|
15
4
|
|
|
16
5
|
interface Props {
|
|
17
6
|
entries: AuditEntry[]
|
|
@@ -1,25 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, ref, watch, nextTick } from 'vue'
|
|
3
|
-
|
|
4
|
-
type BatchItemStatus = 'pending' | 'processing' | 'completed' | 'error' | 'skipped'
|
|
5
|
-
|
|
6
|
-
interface BatchItem {
|
|
7
|
-
id: string
|
|
8
|
-
label: string
|
|
9
|
-
status: BatchItemStatus
|
|
10
|
-
progress?: number
|
|
11
|
-
message?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface BatchSummary {
|
|
15
|
-
total: number
|
|
16
|
-
completed: number
|
|
17
|
-
processing: number
|
|
18
|
-
error: number
|
|
19
|
-
pending: number
|
|
20
|
-
skipped: number
|
|
21
|
-
percent: number
|
|
22
|
-
}
|
|
3
|
+
import type { BatchItem, BatchSummary } from '../types'
|
|
23
4
|
|
|
24
5
|
interface Props {
|
|
25
6
|
items: BatchItem[]
|
|
@@ -370,7 +370,7 @@ onUnmounted(() => {
|
|
|
370
370
|
<div class="mld-datetime-picker__footer">
|
|
371
371
|
<div>
|
|
372
372
|
<button type="button" class="mld-datetime-picker__footer-btn" @click="goToToday">Today</button>
|
|
373
|
-
<button type="button" class="mld-datetime-picker__footer-btn"
|
|
373
|
+
<button type="button" class="mld-datetime-picker__footer-btn" @click="goToNow">Now</button>
|
|
374
374
|
</div>
|
|
375
375
|
<button
|
|
376
376
|
v-if="clearable && modelValue"
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
|
3
|
-
|
|
4
|
-
export interface MoleculeData {
|
|
5
|
-
smiles: string
|
|
6
|
-
molfile: string
|
|
7
|
-
}
|
|
3
|
+
import type { MoleculeData } from '../types'
|
|
8
4
|
|
|
9
5
|
interface Props {
|
|
10
6
|
modelValue?: MoleculeData
|
|
@@ -287,7 +287,7 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
|
|
|
287
287
|
<div v-if="editor.activeRack.value && !readonly" class="mld-rack-editor__toolbar">
|
|
288
288
|
<div class="mld-rack-editor__toolbar-group">
|
|
289
289
|
<!-- Format selector -->
|
|
290
|
-
<div
|
|
290
|
+
<div class="mld-rack-editor__toolbar-section">
|
|
291
291
|
<span class="mld-rack-editor__toolbar-label">Plate</span>
|
|
292
292
|
<div class="mld-rack-editor__format-btns">
|
|
293
293
|
<button
|
|
@@ -307,7 +307,7 @@ const activeRackWells = computed(() => editor.activeRack.value?.wells ?? {})
|
|
|
307
307
|
<div class="mld-rack-editor__toolbar-divider" />
|
|
308
308
|
|
|
309
309
|
<!-- Slot selector -->
|
|
310
|
-
<div
|
|
310
|
+
<div class="mld-rack-editor__toolbar-section">
|
|
311
311
|
<span class="mld-rack-editor__toolbar-label">Slot</span>
|
|
312
312
|
<div class="mld-rack-editor__slot-btns">
|
|
313
313
|
<button
|