@morscherlab/mld-sdk 0.6.2 → 0.6.3
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/ConcentrationInput.vue.js +17 -16
- package/dist/components/ConcentrationInput.vue.js.map +1 -1
- package/dist/components/NumberInput.vue.js +1 -0
- package/dist/components/NumberInput.vue.js.map +1 -1
- package/dist/components/UnitInput.vue.js +19 -18
- package/dist/components/UnitInput.vue.js.map +1 -1
- package/dist/components/WellPlate.vue.js +23 -18
- package/dist/components/WellPlate.vue.js.map +1 -1
- package/dist/styles.css +143 -0
- package/package.json +1 -1
- package/src/components/ConcentrationInput.vue +1 -1
- package/src/components/NumberInput.vue +1 -0
- package/src/components/UnitInput.vue +1 -1
- package/src/components/WellPlate.vue +26 -19
- package/src/styles/components/button.css +4 -0
- package/src/styles/components/concentration-input.css +14 -0
- package/src/styles/components/date-picker.css +5 -0
- package/src/styles/components/dropdown-button.css +5 -0
- package/src/styles/components/icon-button.css +4 -0
- package/src/styles/components/input.css +5 -0
- package/src/styles/components/number-input.css +14 -0
- package/src/styles/components/segmented-control.css +4 -0
- package/src/styles/components/select.css +5 -0
- package/src/styles/components/tags-input.css +4 -0
- package/src/styles/components/unit-input.css +14 -0
- package/src/styles/variables.css +5 -0
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { defineComponent, computed, watch, openBlock, createElementBlock, normalizeClass, createElementVNode, Fragment, renderList, toDisplayString, createCommentVNode } from "vue";
|
|
2
2
|
import { useConcentrationUnits } from "../composables/useConcentrationUnits.js";
|
|
3
|
-
const _hoisted_1 =
|
|
4
|
-
const _hoisted_2 =
|
|
5
|
-
const _hoisted_3 =
|
|
6
|
-
const _hoisted_4 = ["
|
|
7
|
-
const _hoisted_5 = ["
|
|
3
|
+
const _hoisted_1 = ["value", "min", "max", "disabled", "placeholder"];
|
|
4
|
+
const _hoisted_2 = { class: "mld-concentration-input__unit" };
|
|
5
|
+
const _hoisted_3 = ["value", "disabled"];
|
|
6
|
+
const _hoisted_4 = ["label"];
|
|
7
|
+
const _hoisted_5 = ["value"];
|
|
8
8
|
const _hoisted_6 = ["value"];
|
|
9
|
-
const _hoisted_7 =
|
|
10
|
-
const _hoisted_8 = {
|
|
9
|
+
const _hoisted_7 = {
|
|
11
10
|
key: 0,
|
|
12
11
|
class: "mld-concentration-input__conversion"
|
|
13
12
|
};
|
|
@@ -97,7 +96,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
97
96
|
__props.disabled ? "mld-concentration-input--disabled" : ""
|
|
98
97
|
])
|
|
99
98
|
}, [
|
|
100
|
-
createElementVNode("div",
|
|
99
|
+
createElementVNode("div", {
|
|
100
|
+
class: normalizeClass(["mld-concentration-input__controls", `mld-concentration-input__controls--${__props.size}`])
|
|
101
|
+
}, [
|
|
101
102
|
createElementVNode("input", {
|
|
102
103
|
type: "number",
|
|
103
104
|
value: currentValue.value,
|
|
@@ -112,8 +113,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
112
113
|
]),
|
|
113
114
|
"aria-label": "Concentration value",
|
|
114
115
|
onInput: handleValueInput
|
|
115
|
-
}, null, 42,
|
|
116
|
-
createElementVNode("div",
|
|
116
|
+
}, null, 42, _hoisted_1),
|
|
117
|
+
createElementVNode("div", _hoisted_2, [
|
|
117
118
|
createElementVNode("select", {
|
|
118
119
|
value: currentUnit.value,
|
|
119
120
|
disabled: __props.disabled,
|
|
@@ -137,20 +138,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
137
138
|
return openBlock(), createElementBlock("option", {
|
|
138
139
|
key: unit,
|
|
139
140
|
value: unit
|
|
140
|
-
}, toDisplayString(unit), 9,
|
|
141
|
+
}, toDisplayString(unit), 9, _hoisted_5);
|
|
141
142
|
}), 128))
|
|
142
|
-
], 8,
|
|
143
|
+
], 8, _hoisted_4)) : (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(category.units, (unit) => {
|
|
143
144
|
return openBlock(), createElementBlock("option", {
|
|
144
145
|
key: unit,
|
|
145
146
|
value: unit
|
|
146
|
-
}, toDisplayString(unit), 9,
|
|
147
|
+
}, toDisplayString(unit), 9, _hoisted_6);
|
|
147
148
|
}), 128))
|
|
148
149
|
], 64);
|
|
149
150
|
}), 128))
|
|
150
|
-
], 42,
|
|
151
|
+
], 42, _hoisted_3)
|
|
151
152
|
])
|
|
152
|
-
]),
|
|
153
|
-
__props.showConversion && conversionHint.value ? (openBlock(), createElementBlock("div",
|
|
153
|
+
], 2),
|
|
154
|
+
__props.showConversion && conversionHint.value ? (openBlock(), createElementBlock("div", _hoisted_7, toDisplayString(conversionHint.value), 1)) : createCommentVNode("", true)
|
|
154
155
|
], 2);
|
|
155
156
|
};
|
|
156
157
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcentrationInput.vue.js","sources":["../../src/components/ConcentrationInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, watch } from 'vue'\nimport {\n useConcentrationUnits,\n type ConcentrationValue,\n type ConcentrationUnit,\n} from '../composables/useConcentrationUnits'\n\ninterface Props {\n modelValue?: ConcentrationValue\n allowedUnits?: ConcentrationUnit[]\n showConversion?: boolean\n molecularWeight?: number\n min?: number\n max?: number\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n placeholder?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showConversion: true,\n disabled: false,\n error: false,\n size: 'md',\n placeholder: 'Enter value',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: ConcentrationValue | undefined]\n}>()\n\nconst { unitCategories, getConversionHint } = useConcentrationUnits()\n\n// Filter categories based on allowedUnits\nconst filteredCategories = computed(() => {\n if (!props.allowedUnits || props.allowedUnits.length === 0) {\n return unitCategories.value\n }\n return unitCategories.value\n .map(cat => ({\n label: cat.label,\n units: cat.units.filter(u => props.allowedUnits!.includes(u)),\n }))\n .filter(cat => cat.units.length > 0)\n})\n\n// Flatten all available units\nconst availableUnits = computed(() => {\n return filteredCategories.value.flatMap(cat => cat.units)\n})\n\n// Current value and unit\nconst currentValue = computed(() => props.modelValue?.value)\nconst currentUnit = computed(() => props.modelValue?.unit || availableUnits.value[0] || 'µM')\n\n// Conversion hint\nconst conversionHint = computed(() => {\n if (!props.showConversion || !props.modelValue) return null\n return getConversionHint(props.modelValue)\n})\n\nfunction handleValueInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? undefined : Number(target.value)\n\n if (value === undefined || isNaN(value)) {\n emit('update:modelValue', undefined)\n return\n }\n\n // Apply min/max constraints\n let clampedValue = value\n if (props.min !== undefined && clampedValue < props.min) {\n clampedValue = props.min\n }\n if (props.max !== undefined && clampedValue > props.max) {\n clampedValue = props.max\n }\n\n emit('update:modelValue', {\n value: clampedValue,\n unit: currentUnit.value,\n })\n}\n\nfunction handleUnitChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const unit = target.value as ConcentrationUnit\n\n emit('update:modelValue', {\n value: currentValue.value ?? 0,\n unit,\n })\n}\n\n// Ensure modelValue always has a valid unit\nwatch(availableUnits, (units) => {\n if (props.modelValue && !units.includes(props.modelValue.unit)) {\n emit('update:modelValue', {\n value: props.modelValue.value,\n unit: units[0] || 'µM',\n })\n }\n}, { immediate: true })\n</script>\n\n<template>\n <div\n :class=\"[\n 'mld-concentration-input',\n error ? 'mld-concentration-input--error' : '',\n disabled ? 'mld-concentration-input--disabled' : '',\n ]\"\n >\n <div class=\"mld-concentration-input__controls\">\n <input\n type=\"number\"\n :value=\"currentValue\"\n :min=\"min\"\n :max=\"max\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :class=\"[\n 'mld-concentration-input__value',\n `mld-concentration-input__value--${size}`,\n disabled ? 'mld-concentration-input__value--disabled' : '',\n ]\"\n aria-label=\"Concentration value\"\n @input=\"handleValueInput\"\n />\n\n <div class=\"mld-concentration-input__unit\">\n <select\n :value=\"currentUnit\"\n :disabled=\"disabled\"\n :class=\"[\n 'mld-concentration-input__unit-select',\n `mld-concentration-input__unit-select--${size}`,\n ]\"\n aria-label=\"Concentration unit\"\n @change=\"handleUnitChange\"\n >\n <template v-for=\"category in filteredCategories\" :key=\"category.label\">\n <optgroup\n v-if=\"filteredCategories.length > 1\"\n :label=\"category.label\"\n class=\"mld-concentration-input__unit-group\"\n >\n <option\n v-for=\"unit in category.units\"\n :key=\"unit\"\n :value=\"unit\"\n >\n {{ unit }}\n </option>\n </optgroup>\n <template v-else>\n <option\n v-for=\"unit in category.units\"\n :key=\"unit\"\n :value=\"unit\"\n >\n {{ unit }}\n </option>\n </template>\n </template>\n </select>\n </div>\n </div>\n\n <div\n v-if=\"showConversion && conversionHint\"\n class=\"mld-concentration-input__conversion\"\n >\n {{ conversionHint }}\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/concentration-input.css';\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_Fragment","_renderList","_openBlock","_toDisplayString"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConcentrationInput.vue.js","sources":["../../src/components/ConcentrationInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, watch } from 'vue'\nimport {\n useConcentrationUnits,\n type ConcentrationValue,\n type ConcentrationUnit,\n} from '../composables/useConcentrationUnits'\n\ninterface Props {\n modelValue?: ConcentrationValue\n allowedUnits?: ConcentrationUnit[]\n showConversion?: boolean\n molecularWeight?: number\n min?: number\n max?: number\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n placeholder?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showConversion: true,\n disabled: false,\n error: false,\n size: 'md',\n placeholder: 'Enter value',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: ConcentrationValue | undefined]\n}>()\n\nconst { unitCategories, getConversionHint } = useConcentrationUnits()\n\n// Filter categories based on allowedUnits\nconst filteredCategories = computed(() => {\n if (!props.allowedUnits || props.allowedUnits.length === 0) {\n return unitCategories.value\n }\n return unitCategories.value\n .map(cat => ({\n label: cat.label,\n units: cat.units.filter(u => props.allowedUnits!.includes(u)),\n }))\n .filter(cat => cat.units.length > 0)\n})\n\n// Flatten all available units\nconst availableUnits = computed(() => {\n return filteredCategories.value.flatMap(cat => cat.units)\n})\n\n// Current value and unit\nconst currentValue = computed(() => props.modelValue?.value)\nconst currentUnit = computed(() => props.modelValue?.unit || availableUnits.value[0] || 'µM')\n\n// Conversion hint\nconst conversionHint = computed(() => {\n if (!props.showConversion || !props.modelValue) return null\n return getConversionHint(props.modelValue)\n})\n\nfunction handleValueInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? undefined : Number(target.value)\n\n if (value === undefined || isNaN(value)) {\n emit('update:modelValue', undefined)\n return\n }\n\n // Apply min/max constraints\n let clampedValue = value\n if (props.min !== undefined && clampedValue < props.min) {\n clampedValue = props.min\n }\n if (props.max !== undefined && clampedValue > props.max) {\n clampedValue = props.max\n }\n\n emit('update:modelValue', {\n value: clampedValue,\n unit: currentUnit.value,\n })\n}\n\nfunction handleUnitChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const unit = target.value as ConcentrationUnit\n\n emit('update:modelValue', {\n value: currentValue.value ?? 0,\n unit,\n })\n}\n\n// Ensure modelValue always has a valid unit\nwatch(availableUnits, (units) => {\n if (props.modelValue && !units.includes(props.modelValue.unit)) {\n emit('update:modelValue', {\n value: props.modelValue.value,\n unit: units[0] || 'µM',\n })\n }\n}, { immediate: true })\n</script>\n\n<template>\n <div\n :class=\"[\n 'mld-concentration-input',\n error ? 'mld-concentration-input--error' : '',\n disabled ? 'mld-concentration-input--disabled' : '',\n ]\"\n >\n <div :class=\"['mld-concentration-input__controls', `mld-concentration-input__controls--${size}`]\">\n <input\n type=\"number\"\n :value=\"currentValue\"\n :min=\"min\"\n :max=\"max\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :class=\"[\n 'mld-concentration-input__value',\n `mld-concentration-input__value--${size}`,\n disabled ? 'mld-concentration-input__value--disabled' : '',\n ]\"\n aria-label=\"Concentration value\"\n @input=\"handleValueInput\"\n />\n\n <div class=\"mld-concentration-input__unit\">\n <select\n :value=\"currentUnit\"\n :disabled=\"disabled\"\n :class=\"[\n 'mld-concentration-input__unit-select',\n `mld-concentration-input__unit-select--${size}`,\n ]\"\n aria-label=\"Concentration unit\"\n @change=\"handleUnitChange\"\n >\n <template v-for=\"category in filteredCategories\" :key=\"category.label\">\n <optgroup\n v-if=\"filteredCategories.length > 1\"\n :label=\"category.label\"\n class=\"mld-concentration-input__unit-group\"\n >\n <option\n v-for=\"unit in category.units\"\n :key=\"unit\"\n :value=\"unit\"\n >\n {{ unit }}\n </option>\n </optgroup>\n <template v-else>\n <option\n v-for=\"unit in category.units\"\n :key=\"unit\"\n :value=\"unit\"\n >\n {{ unit }}\n </option>\n </template>\n </template>\n </select>\n </div>\n </div>\n\n <div\n v-if=\"showConversion && conversionHint\"\n class=\"mld-concentration-input__conversion\"\n >\n {{ conversionHint }}\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/concentration-input.css';\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_Fragment","_renderList","_openBlock","_toDisplayString"],"mappings":"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"}
|
|
@@ -57,6 +57,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
57
57
|
return openBlock(), createElementBlock("div", {
|
|
58
58
|
class: normalizeClass([
|
|
59
59
|
"mld-number-input",
|
|
60
|
+
`mld-number-input--${__props.size}`,
|
|
60
61
|
__props.error ? "mld-number-input--error" : "",
|
|
61
62
|
__props.disabled ? "mld-number-input--disabled" : ""
|
|
62
63
|
])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberInput.vue.js","sources":["../../src/components/NumberInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n modelValue?: number\n min?: number\n max?: number\n step?: number\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n placeholder?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n step: 1,\n disabled: false,\n error: false,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number | undefined]\n}>()\n\nconst canDecrement = computed(() => {\n if (props.modelValue === undefined) return true\n if (props.min === undefined) return true\n return props.modelValue > props.min\n})\n\nconst canIncrement = computed(() => {\n if (props.modelValue === undefined) return true\n if (props.max === undefined) return true\n return props.modelValue < props.max\n})\n\nfunction clamp(value: number): number {\n let result = value\n if (props.min !== undefined && result < props.min) result = props.min\n if (props.max !== undefined && result > props.max) result = props.max\n return result\n}\n\nfunction handleInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? undefined : Number(target.value)\n if (value !== undefined && !isNaN(value)) {\n emit('update:modelValue', clamp(value))\n } else {\n emit('update:modelValue', undefined)\n }\n}\n\nfunction decrement() {\n if (props.disabled || !canDecrement.value) return\n const current = props.modelValue ?? (props.max ?? 0)\n emit('update:modelValue', clamp(current - props.step))\n}\n\nfunction increment() {\n if (props.disabled || !canIncrement.value) return\n const current = props.modelValue ?? (props.min ?? 0)\n emit('update:modelValue', clamp(current + props.step))\n}\n</script>\n\n<template>\n <div\n :class=\"[\n 'mld-number-input',\n error ? 'mld-number-input--error' : '',\n disabled ? 'mld-number-input--disabled' : '',\n ]\"\n >\n <button\n type=\"button\"\n aria-label=\"Decrease value\"\n :disabled=\"disabled || !canDecrement\"\n :class=\"[\n 'mld-number-input__button',\n 'mld-number-input__button--decrement',\n `mld-number-input__button--${size}`,\n ]\"\n @click=\"decrement\"\n >\n <svg class=\"mld-number-input__button-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M5 12h14\" />\n </svg>\n </button>\n\n <input\n type=\"number\"\n :value=\"modelValue\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :class=\"[\n 'mld-number-input__input',\n `mld-number-input__input--${size}`,\n disabled ? 'mld-number-input__input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n />\n\n <button\n type=\"button\"\n aria-label=\"Increase value\"\n :disabled=\"disabled || !canIncrement\"\n :class=\"[\n 'mld-number-input__button',\n 'mld-number-input__button--increment',\n `mld-number-input__button--${size}`,\n ]\"\n @click=\"increment\"\n >\n <svg class=\"mld-number-input__button-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M5 12h14\" /><path d=\"M12 5v14\" />\n </svg>\n </button>\n </div>\n</template>\n\n<style>\n@import '../styles/components/number-input.css';\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode"],"mappings":";;;;;;;;;;;;;;;;;;AAcA,UAAM,QAAQ;AAOd,UAAM,OAAO;AAIb,UAAM,eAAe,SAAS,MAAM;AAClC,UAAI,MAAM,eAAe,OAAW,QAAO;AAC3C,UAAI,MAAM,QAAQ,OAAW,QAAO;AACpC,aAAO,MAAM,aAAa,MAAM;AAAA,IAClC,CAAC;AAED,UAAM,eAAe,SAAS,MAAM;AAClC,UAAI,MAAM,eAAe,OAAW,QAAO;AAC3C,UAAI,MAAM,QAAQ,OAAW,QAAO;AACpC,aAAO,MAAM,aAAa,MAAM;AAAA,IAClC,CAAC;AAED,aAAS,MAAM,OAAuB;AACpC,UAAI,SAAS;AACb,UAAI,MAAM,QAAQ,UAAa,SAAS,MAAM,cAAc,MAAM;AAClE,UAAI,MAAM,QAAQ,UAAa,SAAS,MAAM,cAAc,MAAM;AAClE,aAAO;AAAA,IACT;AAEA,aAAS,YAAY,OAAc;AACjC,YAAM,SAAS,MAAM;AACrB,YAAM,QAAQ,OAAO,UAAU,KAAK,SAAY,OAAO,OAAO,KAAK;AACnE,UAAI,UAAU,UAAa,CAAC,MAAM,KAAK,GAAG;AACxC,aAAK,qBAAqB,MAAM,KAAK,CAAC;AAAA,MACxC,OAAO;AACL,aAAK,qBAAqB,MAAS;AAAA,MACrC;AAAA,IACF;AAEA,aAAS,YAAY;AACnB,UAAI,MAAM,YAAY,CAAC,aAAa,MAAO;AAC3C,YAAM,UAAU,MAAM,eAAe,MAAM,OAAO;AAClD,WAAK,qBAAqB,MAAM,UAAU,MAAM,IAAI,CAAC;AAAA,IACvD;AAEA,aAAS,YAAY;AACnB,UAAI,MAAM,YAAY,CAAC,aAAa,MAAO;AAC3C,YAAM,UAAU,MAAM,eAAe,MAAM,OAAO;AAClD,WAAK,qBAAqB,MAAM,UAAU,MAAM,IAAI,CAAC;AAAA,IACvD;;0BAIEA,
|
|
1
|
+
{"version":3,"file":"NumberInput.vue.js","sources":["../../src/components/NumberInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\ninterface Props {\n modelValue?: number\n min?: number\n max?: number\n step?: number\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n placeholder?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n step: 1,\n disabled: false,\n error: false,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number | undefined]\n}>()\n\nconst canDecrement = computed(() => {\n if (props.modelValue === undefined) return true\n if (props.min === undefined) return true\n return props.modelValue > props.min\n})\n\nconst canIncrement = computed(() => {\n if (props.modelValue === undefined) return true\n if (props.max === undefined) return true\n return props.modelValue < props.max\n})\n\nfunction clamp(value: number): number {\n let result = value\n if (props.min !== undefined && result < props.min) result = props.min\n if (props.max !== undefined && result > props.max) result = props.max\n return result\n}\n\nfunction handleInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? undefined : Number(target.value)\n if (value !== undefined && !isNaN(value)) {\n emit('update:modelValue', clamp(value))\n } else {\n emit('update:modelValue', undefined)\n }\n}\n\nfunction decrement() {\n if (props.disabled || !canDecrement.value) return\n const current = props.modelValue ?? (props.max ?? 0)\n emit('update:modelValue', clamp(current - props.step))\n}\n\nfunction increment() {\n if (props.disabled || !canIncrement.value) return\n const current = props.modelValue ?? (props.min ?? 0)\n emit('update:modelValue', clamp(current + props.step))\n}\n</script>\n\n<template>\n <div\n :class=\"[\n 'mld-number-input',\n `mld-number-input--${size}`,\n error ? 'mld-number-input--error' : '',\n disabled ? 'mld-number-input--disabled' : '',\n ]\"\n >\n <button\n type=\"button\"\n aria-label=\"Decrease value\"\n :disabled=\"disabled || !canDecrement\"\n :class=\"[\n 'mld-number-input__button',\n 'mld-number-input__button--decrement',\n `mld-number-input__button--${size}`,\n ]\"\n @click=\"decrement\"\n >\n <svg class=\"mld-number-input__button-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M5 12h14\" />\n </svg>\n </button>\n\n <input\n type=\"number\"\n :value=\"modelValue\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :class=\"[\n 'mld-number-input__input',\n `mld-number-input__input--${size}`,\n disabled ? 'mld-number-input__input--disabled' : '',\n ]\"\n @input=\"handleInput\"\n />\n\n <button\n type=\"button\"\n aria-label=\"Increase value\"\n :disabled=\"disabled || !canIncrement\"\n :class=\"[\n 'mld-number-input__button',\n 'mld-number-input__button--increment',\n `mld-number-input__button--${size}`,\n ]\"\n @click=\"increment\"\n >\n <svg class=\"mld-number-input__button-icon\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" viewBox=\"0 0 24 24\">\n <path d=\"M5 12h14\" /><path d=\"M12 5v14\" />\n </svg>\n </button>\n </div>\n</template>\n\n<style>\n@import '../styles/components/number-input.css';\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode"],"mappings":"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"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { defineComponent, ref, computed, watch, openBlock, createElementBlock, normalizeClass, createElementVNode, Fragment, renderList, toDisplayString, createCommentVNode } from "vue";
|
|
2
|
-
const _hoisted_1 =
|
|
3
|
-
const _hoisted_2 =
|
|
4
|
-
const _hoisted_3 =
|
|
5
|
-
const _hoisted_4 = ["value"
|
|
6
|
-
const _hoisted_5 = ["
|
|
7
|
-
const _hoisted_6 = ["
|
|
2
|
+
const _hoisted_1 = ["value", "min", "max", "step", "disabled", "placeholder"];
|
|
3
|
+
const _hoisted_2 = { class: "mld-unit-input__unit" };
|
|
4
|
+
const _hoisted_3 = ["value", "disabled"];
|
|
5
|
+
const _hoisted_4 = ["value"];
|
|
6
|
+
const _hoisted_5 = ["label"];
|
|
7
|
+
const _hoisted_6 = ["value"];
|
|
8
8
|
const _hoisted_7 = ["value"];
|
|
9
|
-
const _hoisted_8 =
|
|
10
|
-
const _hoisted_9 = {
|
|
9
|
+
const _hoisted_8 = {
|
|
11
10
|
key: 0,
|
|
12
11
|
class: "mld-unit-input__conversion-hint"
|
|
13
12
|
};
|
|
@@ -109,7 +108,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
109
108
|
__props.disabled ? "mld-unit-input--disabled" : ""
|
|
110
109
|
])
|
|
111
110
|
}, [
|
|
112
|
-
createElementVNode("div",
|
|
111
|
+
createElementVNode("div", {
|
|
112
|
+
class: normalizeClass(["mld-unit-input__controls", `mld-unit-input__controls--${__props.size}`])
|
|
113
|
+
}, [
|
|
113
114
|
createElementVNode("input", {
|
|
114
115
|
type: "number",
|
|
115
116
|
value: __props.modelValue,
|
|
@@ -125,8 +126,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
125
126
|
]),
|
|
126
127
|
"aria-label": "Value",
|
|
127
128
|
onInput: handleValueInput
|
|
128
|
-
}, null, 42,
|
|
129
|
-
createElementVNode("div",
|
|
129
|
+
}, null, 42, _hoisted_1),
|
|
130
|
+
createElementVNode("div", _hoisted_2, [
|
|
130
131
|
createElementVNode("select", {
|
|
131
132
|
value: currentUnit.value,
|
|
132
133
|
disabled: __props.disabled,
|
|
@@ -142,7 +143,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
142
143
|
return openBlock(), createElementBlock("option", {
|
|
143
144
|
key: u.value,
|
|
144
145
|
value: u.value
|
|
145
|
-
}, toDisplayString(u.label), 9,
|
|
146
|
+
}, toDisplayString(u.label), 9, _hoisted_4);
|
|
146
147
|
}), 128)) : createCommentVNode("", true),
|
|
147
148
|
(openBlock(true), createElementBlock(Fragment, null, renderList(groupedUnits.value.groups, ([groupLabel, groupUnits]) => {
|
|
148
149
|
return openBlock(), createElementBlock("optgroup", {
|
|
@@ -154,20 +155,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
154
155
|
return openBlock(), createElementBlock("option", {
|
|
155
156
|
key: u.value,
|
|
156
157
|
value: u.value
|
|
157
|
-
}, toDisplayString(u.label), 9,
|
|
158
|
+
}, toDisplayString(u.label), 9, _hoisted_6);
|
|
158
159
|
}), 128))
|
|
159
|
-
], 8,
|
|
160
|
+
], 8, _hoisted_5);
|
|
160
161
|
}), 128))
|
|
161
162
|
], 64)) : (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(__props.units, (u) => {
|
|
162
163
|
return openBlock(), createElementBlock("option", {
|
|
163
164
|
key: u.value,
|
|
164
165
|
value: u.value
|
|
165
|
-
}, toDisplayString(u.label), 9,
|
|
166
|
+
}, toDisplayString(u.label), 9, _hoisted_7);
|
|
166
167
|
}), 128))
|
|
167
|
-
], 42,
|
|
168
|
+
], 42, _hoisted_3)
|
|
168
169
|
])
|
|
169
|
-
]),
|
|
170
|
-
conversionHint.value ? (openBlock(), createElementBlock("div",
|
|
170
|
+
], 2),
|
|
171
|
+
conversionHint.value ? (openBlock(), createElementBlock("div", _hoisted_8, toDisplayString(conversionHint.value), 1)) : createCommentVNode("", true)
|
|
171
172
|
], 2);
|
|
172
173
|
};
|
|
173
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UnitInput.vue.js","sources":["../../src/components/UnitInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport type { UnitOption } from '../types'\n\ninterface Props {\n modelValue?: number\n unit?: string\n units: UnitOption[]\n precision?: number\n min?: number\n max?: number\n step?: number\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n convertOnUnitChange?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n precision: undefined,\n step: undefined,\n placeholder: 'Enter value',\n disabled: false,\n error: false,\n size: 'md',\n convertOnUnitChange: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number | undefined]\n 'update:unit': [unit: string]\n 'change': [data: { value: number | undefined; unit: string }]\n}>()\n\nconst conversionHint = ref<string | null>(null)\n\nconst currentUnit = computed(() => props.unit || (props.units.length > 0 ? props.units[0].value : ''))\n\n// Group units by their group property\nconst hasGroups = computed(() => props.units.some(u => u.group))\n\nconst groupedUnits = computed(() => {\n if (!hasGroups.value) return null\n const groups = new Map<string, UnitOption[]>()\n const ungrouped: UnitOption[] = []\n for (const u of props.units) {\n if (u.group) {\n if (!groups.has(u.group)) groups.set(u.group, [])\n groups.get(u.group)!.push(u)\n } else {\n ungrouped.push(u)\n }\n }\n return { groups, ungrouped }\n})\n\nfunction findUnit(value: string): UnitOption | undefined {\n return props.units.find(u => u.value === value)\n}\n\nfunction roundToPrecision(value: number): number {\n if (props.precision === undefined) return value\n const factor = Math.pow(10, props.precision)\n return Math.round(value * factor) / factor\n}\n\nfunction clamp(value: number): number {\n let result = value\n if (props.min !== undefined && result < props.min) result = props.min\n if (props.max !== undefined && result > props.max) result = props.max\n return result\n}\n\nfunction handleValueInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? undefined : Number(target.value)\n\n conversionHint.value = null\n\n if (value === undefined || isNaN(value)) {\n emit('update:modelValue', undefined)\n emit('change', { value: undefined, unit: currentUnit.value })\n return\n }\n\n const clamped = clamp(value)\n emit('update:modelValue', clamped)\n emit('change', { value: clamped, unit: currentUnit.value })\n}\n\nfunction handleUnitChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const newUnitValue = target.value\n const oldUnitValue = currentUnit.value\n\n let newValue = props.modelValue\n\n if (props.convertOnUnitChange && newValue !== undefined) {\n const oldUnit = findUnit(oldUnitValue)\n const newUnit = findUnit(newUnitValue)\n\n if (oldUnit?.factor !== undefined && newUnit?.factor !== undefined && newUnit.factor !== 0) {\n const converted = newValue * (oldUnit.factor / newUnit.factor)\n newValue = roundToPrecision(converted)\n newValue = clamp(newValue)\n conversionHint.value = `Converted from ${oldUnit.label} to ${newUnit.label}`\n emit('update:modelValue', newValue)\n }\n }\n\n emit('update:unit', newUnitValue)\n emit('change', { value: newValue, unit: newUnitValue })\n}\n\n// Clear conversion hint after a delay\nwatch(conversionHint, (hint) => {\n if (hint) {\n setTimeout(() => {\n conversionHint.value = null\n }, 3000)\n }\n})\n</script>\n\n<template>\n <div\n :class=\"[\n 'mld-unit-input',\n error ? 'mld-unit-input--error' : '',\n disabled ? 'mld-unit-input--disabled' : '',\n ]\"\n >\n <div class=\"mld-unit-input__controls\">\n <input\n type=\"number\"\n :value=\"modelValue\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :class=\"[\n 'mld-unit-input__value',\n `mld-unit-input__value--${size}`,\n disabled ? 'mld-unit-input__value--disabled' : '',\n ]\"\n aria-label=\"Value\"\n @input=\"handleValueInput\"\n />\n\n <div class=\"mld-unit-input__unit\">\n <select\n :value=\"currentUnit\"\n :disabled=\"disabled\"\n :class=\"[\n 'mld-unit-input__unit-select',\n `mld-unit-input__unit-select--${size}`,\n ]\"\n aria-label=\"Unit\"\n @change=\"handleUnitChange\"\n >\n <template v-if=\"groupedUnits\">\n <template v-if=\"groupedUnits.ungrouped.length > 0\">\n <option\n v-for=\"u in groupedUnits.ungrouped\"\n :key=\"u.value\"\n :value=\"u.value\"\n >\n {{ u.label }}\n </option>\n </template>\n <optgroup\n v-for=\"[groupLabel, groupUnits] in groupedUnits.groups\"\n :key=\"groupLabel\"\n :label=\"groupLabel\"\n class=\"mld-unit-input__unit-group\"\n >\n <option\n v-for=\"u in groupUnits\"\n :key=\"u.value\"\n :value=\"u.value\"\n >\n {{ u.label }}\n </option>\n </optgroup>\n </template>\n <template v-else>\n <option\n v-for=\"u in units\"\n :key=\"u.value\"\n :value=\"u.value\"\n >\n {{ u.label }}\n </option>\n </template>\n </select>\n </div>\n </div>\n\n <div\n v-if=\"conversionHint\"\n class=\"mld-unit-input__conversion-hint\"\n >\n {{ conversionHint }}\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/unit-input.css';\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_Fragment","_openBlock","_renderList","_toDisplayString"],"mappings":"
|
|
1
|
+
{"version":3,"file":"UnitInput.vue.js","sources":["../../src/components/UnitInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport type { UnitOption } from '../types'\n\ninterface Props {\n modelValue?: number\n unit?: string\n units: UnitOption[]\n precision?: number\n min?: number\n max?: number\n step?: number\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n convertOnUnitChange?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n precision: undefined,\n step: undefined,\n placeholder: 'Enter value',\n disabled: false,\n error: false,\n size: 'md',\n convertOnUnitChange: false,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: number | undefined]\n 'update:unit': [unit: string]\n 'change': [data: { value: number | undefined; unit: string }]\n}>()\n\nconst conversionHint = ref<string | null>(null)\n\nconst currentUnit = computed(() => props.unit || (props.units.length > 0 ? props.units[0].value : ''))\n\n// Group units by their group property\nconst hasGroups = computed(() => props.units.some(u => u.group))\n\nconst groupedUnits = computed(() => {\n if (!hasGroups.value) return null\n const groups = new Map<string, UnitOption[]>()\n const ungrouped: UnitOption[] = []\n for (const u of props.units) {\n if (u.group) {\n if (!groups.has(u.group)) groups.set(u.group, [])\n groups.get(u.group)!.push(u)\n } else {\n ungrouped.push(u)\n }\n }\n return { groups, ungrouped }\n})\n\nfunction findUnit(value: string): UnitOption | undefined {\n return props.units.find(u => u.value === value)\n}\n\nfunction roundToPrecision(value: number): number {\n if (props.precision === undefined) return value\n const factor = Math.pow(10, props.precision)\n return Math.round(value * factor) / factor\n}\n\nfunction clamp(value: number): number {\n let result = value\n if (props.min !== undefined && result < props.min) result = props.min\n if (props.max !== undefined && result > props.max) result = props.max\n return result\n}\n\nfunction handleValueInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? undefined : Number(target.value)\n\n conversionHint.value = null\n\n if (value === undefined || isNaN(value)) {\n emit('update:modelValue', undefined)\n emit('change', { value: undefined, unit: currentUnit.value })\n return\n }\n\n const clamped = clamp(value)\n emit('update:modelValue', clamped)\n emit('change', { value: clamped, unit: currentUnit.value })\n}\n\nfunction handleUnitChange(event: Event) {\n const target = event.target as HTMLSelectElement\n const newUnitValue = target.value\n const oldUnitValue = currentUnit.value\n\n let newValue = props.modelValue\n\n if (props.convertOnUnitChange && newValue !== undefined) {\n const oldUnit = findUnit(oldUnitValue)\n const newUnit = findUnit(newUnitValue)\n\n if (oldUnit?.factor !== undefined && newUnit?.factor !== undefined && newUnit.factor !== 0) {\n const converted = newValue * (oldUnit.factor / newUnit.factor)\n newValue = roundToPrecision(converted)\n newValue = clamp(newValue)\n conversionHint.value = `Converted from ${oldUnit.label} to ${newUnit.label}`\n emit('update:modelValue', newValue)\n }\n }\n\n emit('update:unit', newUnitValue)\n emit('change', { value: newValue, unit: newUnitValue })\n}\n\n// Clear conversion hint after a delay\nwatch(conversionHint, (hint) => {\n if (hint) {\n setTimeout(() => {\n conversionHint.value = null\n }, 3000)\n }\n})\n</script>\n\n<template>\n <div\n :class=\"[\n 'mld-unit-input',\n error ? 'mld-unit-input--error' : '',\n disabled ? 'mld-unit-input--disabled' : '',\n ]\"\n >\n <div :class=\"['mld-unit-input__controls', `mld-unit-input__controls--${size}`]\">\n <input\n type=\"number\"\n :value=\"modelValue\"\n :min=\"min\"\n :max=\"max\"\n :step=\"step\"\n :disabled=\"disabled\"\n :placeholder=\"placeholder\"\n :class=\"[\n 'mld-unit-input__value',\n `mld-unit-input__value--${size}`,\n disabled ? 'mld-unit-input__value--disabled' : '',\n ]\"\n aria-label=\"Value\"\n @input=\"handleValueInput\"\n />\n\n <div class=\"mld-unit-input__unit\">\n <select\n :value=\"currentUnit\"\n :disabled=\"disabled\"\n :class=\"[\n 'mld-unit-input__unit-select',\n `mld-unit-input__unit-select--${size}`,\n ]\"\n aria-label=\"Unit\"\n @change=\"handleUnitChange\"\n >\n <template v-if=\"groupedUnits\">\n <template v-if=\"groupedUnits.ungrouped.length > 0\">\n <option\n v-for=\"u in groupedUnits.ungrouped\"\n :key=\"u.value\"\n :value=\"u.value\"\n >\n {{ u.label }}\n </option>\n </template>\n <optgroup\n v-for=\"[groupLabel, groupUnits] in groupedUnits.groups\"\n :key=\"groupLabel\"\n :label=\"groupLabel\"\n class=\"mld-unit-input__unit-group\"\n >\n <option\n v-for=\"u in groupUnits\"\n :key=\"u.value\"\n :value=\"u.value\"\n >\n {{ u.label }}\n </option>\n </optgroup>\n </template>\n <template v-else>\n <option\n v-for=\"u in units\"\n :key=\"u.value\"\n :value=\"u.value\"\n >\n {{ u.label }}\n </option>\n </template>\n </select>\n </div>\n </div>\n\n <div\n v-if=\"conversionHint\"\n class=\"mld-unit-input__conversion-hint\"\n >\n {{ conversionHint }}\n </div>\n </div>\n</template>\n\n<style>\n@import '../styles/components/unit-input.css';\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_Fragment","_openBlock","_renderList","_toDisplayString"],"mappings":"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"}
|
|
@@ -218,13 +218,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
218
218
|
}
|
|
219
219
|
return map;
|
|
220
220
|
});
|
|
221
|
-
function
|
|
222
|
-
const
|
|
223
|
-
const
|
|
221
|
+
function conditionGradientStyle(color, conc, concentrations) {
|
|
222
|
+
const min = Math.min(...concentrations);
|
|
223
|
+
const max = Math.max(...concentrations);
|
|
224
|
+
const t = max <= min ? 1 : (conc - min) / (max - min);
|
|
225
|
+
const opacity = 0.25 + t * 0.5;
|
|
224
226
|
const r = parseInt(color.slice(1, 3), 16);
|
|
225
227
|
const g = parseInt(color.slice(3, 5), 16);
|
|
226
228
|
const b = parseInt(color.slice(5, 7), 16);
|
|
227
|
-
|
|
229
|
+
const er = 255 * (1 - opacity) + r * opacity;
|
|
230
|
+
const eg = 255 * (1 - opacity) + g * opacity;
|
|
231
|
+
const eb = 255 * (1 - opacity) + b * opacity;
|
|
232
|
+
const luminance = (0.299 * er + 0.587 * eg + 0.114 * eb) / 255;
|
|
233
|
+
return {
|
|
234
|
+
backgroundColor: `rgba(${r}, ${g}, ${b}, ${opacity})`,
|
|
235
|
+
color: luminance > 0.55 ? "#1e293b" : "#ffffff"
|
|
236
|
+
};
|
|
228
237
|
}
|
|
229
238
|
function formatConc(value) {
|
|
230
239
|
if (value >= 1e3) return `${value / 1e3}k`;
|
|
@@ -550,13 +559,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
550
559
|
entry ? (openBlock(), createElementBlock("span", {
|
|
551
560
|
key: 0,
|
|
552
561
|
class: "mld-well-plate__condition-cell",
|
|
553
|
-
style: normalizeStyle(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
)
|
|
559
|
-
})
|
|
562
|
+
style: normalizeStyle(conditionGradientStyle(
|
|
563
|
+
entry.condition.color,
|
|
564
|
+
entry.condition.concentrations[entry.indexInGroup],
|
|
565
|
+
entry.condition.concentrations
|
|
566
|
+
))
|
|
560
567
|
}, toDisplayString(formatConc(entry.condition.concentrations[entry.indexInGroup])), 5)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
561
568
|
createTextVNode(toDisplayString(col), 1)
|
|
562
569
|
], 64))
|
|
@@ -608,13 +615,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
608
615
|
entry ? (openBlock(), createElementBlock("span", {
|
|
609
616
|
key: 0,
|
|
610
617
|
class: "mld-well-plate__condition-cell",
|
|
611
|
-
style: normalizeStyle(
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
)
|
|
617
|
-
})
|
|
618
|
+
style: normalizeStyle(conditionGradientStyle(
|
|
619
|
+
entry.condition.color,
|
|
620
|
+
entry.condition.concentrations[entry.indexInGroup],
|
|
621
|
+
entry.condition.concentrations
|
|
622
|
+
))
|
|
618
623
|
}, toDisplayString(formatConc(entry.condition.concentrations[entry.indexInGroup])), 5)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
619
624
|
createTextVNode(toDisplayString(rowLabels.value[rowIndex]), 1)
|
|
620
625
|
], 64))
|
|
@@ -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, 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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"}
|
|
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 style for a condition cell: background opacity scales with concentration,\n// text color adapts based on effective luminance against white background\nfunction conditionGradientStyle(color: string, conc: number, concentrations: number[]): Record<string, string> {\n const min = Math.min(...concentrations)\n const max = Math.max(...concentrations)\n const t = max <= min ? 1 : (conc - min) / (max - min)\n const opacity = 0.25 + t * 0.50\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 // Blend with white to get effective RGB, then compute relative luminance\n const er = 255 * (1 - opacity) + r * opacity\n const eg = 255 * (1 - opacity) + g * opacity\n const eb = 255 * (1 - opacity) + b * opacity\n const luminance = (0.299 * er + 0.587 * eg + 0.114 * eb) / 255\n return {\n backgroundColor: `rgba(${r}, ${g}, ${b}, ${opacity})`,\n color: luminance > 0.55 ? '#1e293b' : '#ffffff',\n }\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=\"conditionGradientStyle(\n entry.condition.color,\n entry.condition.concentrations[entry.indexInGroup],\n entry.condition.concentrations,\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=\"conditionGradientStyle(\n entry.condition.color,\n entry.condition.concentrations[entry.indexInGroup],\n entry.condition.concentrations,\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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"}
|