@morscherlab/mint-sdk 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{SettingsModal-DOcCf0Vo.js → SettingsModal-DELMkUFR.js} +3 -3
- package/dist/{SettingsModal-DOcCf0Vo.js.map → SettingsModal-DELMkUFR.js.map} +1 -1
- package/dist/__tests__/components/ChartContainer.test.d.ts +1 -0
- package/dist/__tests__/components/ChemicalFormula.test.d.ts +1 -0
- package/dist/__tests__/components/LayoutResizeHandle.test.d.ts +1 -0
- package/dist/__tests__/components/SearchableSelect.test.d.ts +1 -0
- package/dist/__tests__/components/WellPlate.decoration.test.d.ts +1 -0
- package/dist/__tests__/composables/useManualLayoutResize.test.d.ts +1 -0
- package/dist/components/AdductText.vue.d.ts +17 -0
- package/dist/components/ChartContainer.vue.d.ts +19 -5
- package/dist/components/ChemicalFormula.vue.d.ts +28 -2
- package/dist/components/DataFrame.vue.d.ts +1 -1
- package/dist/components/LayoutResizeHandle.vue.d.ts +23 -0
- package/dist/components/PlotlyChart.vue.d.ts +34 -6
- package/dist/components/SearchableSelect.vue.d.ts +57 -0
- package/dist/components/WellPlate.vue.d.ts +5 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +4 -4
- package/dist/{components-Cp8DcNrU.js → components-CxQVQCpP.js} +773 -317
- package/dist/components-CxQVQCpP.js.map +1 -0
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +6 -6
- package/dist/composables/useManualLayoutResize.d.ts +56 -0
- package/dist/{composables-D_4qqOlp.js → composables-DAqOU8Aq.js} +96 -7
- package/dist/composables-DAqOU8Aq.js.map +1 -0
- package/dist/index.js +8 -8
- package/dist/install.js +2 -2
- package/dist/styles.css +294 -16
- package/dist/templates/index.js +2 -2
- package/dist/{templates-Dd9bBSs6.js → templates-NuaNHohp.js} +2 -2
- package/dist/{templates-Dd9bBSs6.js.map → templates-NuaNHohp.js.map} +1 -1
- package/dist/types/componentLabTypes.d.ts +3 -0
- package/dist/types/components.d.ts +5 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/{useControlSchema-BB2GRPhW.js → useControlSchema-vLiRPUmj.js} +37 -7
- package/dist/useControlSchema-vLiRPUmj.js.map +1 -0
- package/dist/{useFormBuilder-BnGSdSRG.js → useFormBuilder-D37ajgS8.js} +2 -2
- package/dist/{useFormBuilder-BnGSdSRG.js.map → useFormBuilder-D37ajgS8.js.map} +1 -1
- package/dist/{validation-CTxuzLIX.js → validation-ChMyixAf.js} +3 -3
- package/dist/{validation-CTxuzLIX.js.map → validation-ChMyixAf.js.map} +1 -1
- package/package.json +1 -1
- package/src/__tests__/components/ChartContainer.test.ts +24 -0
- package/src/__tests__/components/ChemicalFormula.test.ts +27 -0
- package/src/__tests__/components/LayoutResizeHandle.test.ts +19 -0
- package/src/__tests__/components/NumberInput.test.ts +45 -1
- package/src/__tests__/components/PlotlyChart.test.ts +48 -0
- package/src/__tests__/components/RackEditor.test.ts +9 -0
- package/src/__tests__/components/SearchableSelect.test.ts +61 -0
- package/src/__tests__/components/WellPlate.decoration.test.ts +28 -0
- package/src/__tests__/composables/useManualLayoutResize.test.ts +21 -0
- package/src/components/AdductText.story.vue +15 -0
- package/src/components/AdductText.vue +40 -0
- package/src/components/ChartContainer.story.vue +21 -0
- package/src/components/ChartContainer.vue +27 -6
- package/src/components/ChemicalFormula.story.vue +7 -0
- package/src/components/ChemicalFormula.vue +40 -11
- package/src/components/LayoutResizeHandle.story.vue +26 -0
- package/src/components/LayoutResizeHandle.vue +62 -0
- package/src/components/NumberInput.story.vue +1 -1
- package/src/components/NumberInput.vue +37 -9
- package/src/components/PlotlyChart.vue +77 -11
- package/src/components/RackEditor.vue +38 -32
- package/src/components/SearchableSelect.story.vue +24 -0
- package/src/components/SearchableSelect.vue +223 -0
- package/src/components/WellPlate.story.vue +16 -0
- package/src/components/WellPlate.vue +17 -8
- package/src/components/index.ts +3 -1
- package/src/composables/index.ts +10 -0
- package/src/composables/useManualLayoutResize.ts +165 -0
- package/src/styles/components/adduct-text.css +45 -0
- package/src/styles/components/chart-container.css +92 -0
- package/src/styles/components/chemical-formula.css +34 -4
- package/src/styles/components/layout-resize-handle.css +60 -0
- package/src/styles/components/number-input.css +2 -0
- package/src/styles/components/rack-editor.css +31 -9
- package/src/styles/components/searchable-select.css +63 -0
- package/src/styles/components/well-plate.css +9 -0
- package/src/styles/index.css +3 -0
- package/src/types/componentLabTypes.ts +6 -0
- package/src/types/components.ts +7 -0
- package/src/types/index.ts +3 -0
- package/dist/components-Cp8DcNrU.js.map +0 -1
- package/dist/composables-D_4qqOlp.js.map +0 -1
- package/dist/useControlSchema-BB2GRPhW.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/** Interactive 96/384-well plate grid with drag-to-select, heatmap overlays, per-well editing, and sample-color mapping. */
|
|
3
3
|
import { ref, computed } from 'vue'
|
|
4
|
-
import type { WellPlateFormat, WellPlateSelectionMode, WellPlateSize, Well, HeatmapConfig, WellShape, WellEditField, WellEditData, WellLegendItem, ColumnCondition, RowCondition, WellSampleDropData, WellSampleDropParser } from '../types'
|
|
4
|
+
import type { WellPlateFormat, WellPlateSelectionMode, WellPlateSize, Well, HeatmapConfig, WellShape, WellEditField, WellEditData, WellLegendItem, ColumnCondition, RowCondition, WellSampleDropData, WellSampleDropParser, WellClassResolver, WellClassValue, WellStyleResolver } from '../types'
|
|
5
5
|
import { useEventListener } from '../composables/useEventListener'
|
|
6
6
|
import WellEditPopupInternal from './internal/WellEditPopupInternal.vue'
|
|
7
7
|
import {
|
|
@@ -73,6 +73,10 @@ interface Props {
|
|
|
73
73
|
* carry data.
|
|
74
74
|
*/
|
|
75
75
|
emptyMessage?: string
|
|
76
|
+
/** Add semantic classes to individual wells without overloading sample data. */
|
|
77
|
+
wellClass?: WellClassResolver
|
|
78
|
+
/** Add or override individual well styles after heatmap/sample styling. */
|
|
79
|
+
wellStyle?: WellStyleResolver
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -213,8 +217,8 @@ const {
|
|
|
213
217
|
emitSampleDrop: (wellId, data, event) => emit('sample-drop', wellId, data, event),
|
|
214
218
|
})
|
|
215
219
|
|
|
216
|
-
function getWellClasses(well: Well):
|
|
217
|
-
|
|
220
|
+
function getWellClasses(well: Well): WellClassValue[] {
|
|
221
|
+
const base = wellClasses(well, {
|
|
218
222
|
wellShape: props.wellShape,
|
|
219
223
|
selectionMode: props.selectionMode,
|
|
220
224
|
selected: isSelected(well.id),
|
|
@@ -225,13 +229,18 @@ function getWellClasses(well: Well): string[] {
|
|
|
225
229
|
dragSource: dragSourceWell.value === well.id,
|
|
226
230
|
dragTarget: dragTargetWell.value === well.id,
|
|
227
231
|
})
|
|
232
|
+
const custom = props.wellClass?.(well)
|
|
233
|
+
return custom ? [base, custom] : [base]
|
|
228
234
|
}
|
|
229
235
|
|
|
230
|
-
function getWellStyle(well: Well): Record<string, string> {
|
|
231
|
-
return
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
236
|
+
function getWellStyle(well: Well): Record<string, string | number | undefined> {
|
|
237
|
+
return {
|
|
238
|
+
...wellStyle(well, {
|
|
239
|
+
heatmap: props.heatmap,
|
|
240
|
+
sampleColors: props.sampleColors,
|
|
241
|
+
}),
|
|
242
|
+
...props.wellStyle?.(well),
|
|
243
|
+
}
|
|
235
244
|
}
|
|
236
245
|
|
|
237
246
|
function getSampleTypeIndicator(well: Well): string | null {
|
package/src/components/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { default as BaseButton } from './BaseButton.vue'
|
|
|
3
3
|
export { default as BaseInput } from './BaseInput.vue'
|
|
4
4
|
export { default as BaseTextarea } from './BaseTextarea.vue'
|
|
5
5
|
export { default as BaseSelect } from './BaseSelect.vue'
|
|
6
|
+
export { default as SearchableSelect } from './SearchableSelect.vue'
|
|
6
7
|
export { default as BaseCheckbox } from './BaseCheckbox.vue'
|
|
7
8
|
export { default as BaseToggle } from './BaseToggle.vue'
|
|
8
9
|
export { default as BaseRadioGroup } from './BaseRadioGroup.vue'
|
|
@@ -55,6 +56,7 @@ export { default as ControlWorkspaceView } from './ControlWorkspaceView.vue'
|
|
|
55
56
|
export { default as DoseDesignWorkspaceView } from './DoseDesignWorkspaceView.vue'
|
|
56
57
|
export { default as AppContainer } from './AppContainer.vue'
|
|
57
58
|
export { default as PluginIcon } from './PluginIcon.vue'
|
|
59
|
+
export { default as LayoutResizeHandle } from './LayoutResizeHandle.vue'
|
|
58
60
|
|
|
59
61
|
// Utility components
|
|
60
62
|
export { default as Skeleton } from './Skeleton.vue'
|
|
@@ -68,6 +70,7 @@ export { default as Breadcrumb } from './Breadcrumb.vue'
|
|
|
68
70
|
export { default as Tooltip } from './Tooltip.vue'
|
|
69
71
|
export { default as ConfirmDialog } from './ConfirmDialog.vue'
|
|
70
72
|
export { default as ChartContainer } from './ChartContainer.vue'
|
|
73
|
+
export { default as AdductText } from './AdductText.vue'
|
|
71
74
|
export { default as SettingsModal } from './SettingsModal.vue'
|
|
72
75
|
|
|
73
76
|
// Biological experiment components
|
|
@@ -101,7 +104,6 @@ export { default as ProtocolStepEditor } from './ProtocolStepEditor.vue'
|
|
|
101
104
|
// Scientific display components
|
|
102
105
|
export { default as PlotlyChart } from './PlotlyChart.vue'
|
|
103
106
|
export { default as ScientificNumber } from './ScientificNumber.vue'
|
|
104
|
-
/** Renders a chemical formula string (H₂O, C₆H₁₂O₆, Ca(OH)₂) with typographically correct subscripts and superscripts for charges. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; no platform replacement is planned. */
|
|
105
107
|
export { default as ChemicalFormula } from './ChemicalFormula.vue'
|
|
106
108
|
export { default as SequenceProgressBar } from './SequenceProgressBar.vue'
|
|
107
109
|
/** Filterable instrument alert/event list keyed by each alert's required stable event_key. @deprecated Unused by the MINT platform and scheduled for removal in MINT 1.3; instrument UI moves to the mld-ms plugins. */
|
package/src/composables/index.ts
CHANGED
|
@@ -139,6 +139,16 @@ export {
|
|
|
139
139
|
type UseDebouncedWatchOptions,
|
|
140
140
|
type UseDebouncedWatchReturn,
|
|
141
141
|
} from './useDebouncedWatch'
|
|
142
|
+
export {
|
|
143
|
+
resizedLeadingPanelWidth,
|
|
144
|
+
resizedTrailingPanelWidth,
|
|
145
|
+
resizedVerticalSplitPercent,
|
|
146
|
+
useManualLayoutResize,
|
|
147
|
+
type ManualLayoutResizeContext,
|
|
148
|
+
type ManualLayoutResizeTarget,
|
|
149
|
+
type ResizePanelWidthConstraints,
|
|
150
|
+
type ResizePercentConstraints,
|
|
151
|
+
} from './useManualLayoutResize'
|
|
142
152
|
export { useFormBuilder, evaluateCondition } from './useFormBuilder'
|
|
143
153
|
export {
|
|
144
154
|
createGeneratedAnalysisTransport,
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { computed, onBeforeUnmount, shallowRef, toValue, watch, type MaybeRefOrGetter } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface ResizePanelWidthConstraints {
|
|
4
|
+
minWidth: number
|
|
5
|
+
maxWidth: number
|
|
6
|
+
mainMinWidth?: number
|
|
7
|
+
layoutGap?: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ResizePercentConstraints {
|
|
11
|
+
minPercent: number
|
|
12
|
+
maxPercent: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function clamp(value: number, min: number, max: number): number {
|
|
16
|
+
return Math.min(max, Math.max(min, value))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function availablePanelWidth(
|
|
20
|
+
containerWidth: number,
|
|
21
|
+
constraints: ResizePanelWidthConstraints,
|
|
22
|
+
): number {
|
|
23
|
+
return Math.min(
|
|
24
|
+
constraints.maxWidth,
|
|
25
|
+
containerWidth - (constraints.mainMinWidth ?? 0) - (constraints.layoutGap ?? 0),
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function resizedLeadingPanelWidth(
|
|
30
|
+
startWidth: number,
|
|
31
|
+
deltaX: number,
|
|
32
|
+
containerWidth: number,
|
|
33
|
+
constraints: ResizePanelWidthConstraints,
|
|
34
|
+
): number {
|
|
35
|
+
return Math.round(clamp(
|
|
36
|
+
startWidth + deltaX,
|
|
37
|
+
constraints.minWidth,
|
|
38
|
+
Math.max(constraints.minWidth, availablePanelWidth(containerWidth, constraints)),
|
|
39
|
+
))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function resizedTrailingPanelWidth(
|
|
43
|
+
startWidth: number,
|
|
44
|
+
deltaX: number,
|
|
45
|
+
containerWidth: number,
|
|
46
|
+
constraints: ResizePanelWidthConstraints,
|
|
47
|
+
): number {
|
|
48
|
+
return resizedLeadingPanelWidth(startWidth, -deltaX, containerWidth, constraints)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function resizedVerticalSplitPercent(
|
|
52
|
+
startPercent: number,
|
|
53
|
+
deltaY: number,
|
|
54
|
+
containerHeight: number,
|
|
55
|
+
constraints: ResizePercentConstraints,
|
|
56
|
+
): number {
|
|
57
|
+
if (containerHeight <= 0) return startPercent
|
|
58
|
+
return Math.round(clamp(
|
|
59
|
+
startPercent + (deltaY / containerHeight) * 100,
|
|
60
|
+
constraints.minPercent,
|
|
61
|
+
constraints.maxPercent,
|
|
62
|
+
))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ManualLayoutResizeContext<TKind extends string> {
|
|
66
|
+
kind: TKind
|
|
67
|
+
startValue: number
|
|
68
|
+
deltaX: number
|
|
69
|
+
deltaY: number
|
|
70
|
+
containerRect: DOMRectReadOnly
|
|
71
|
+
secondaryRect: DOMRectReadOnly | null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ManualLayoutResizeTarget<TKind extends string> {
|
|
75
|
+
cursor?: string
|
|
76
|
+
getContainerElement: () => HTMLElement | null
|
|
77
|
+
getSecondaryElement?: () => HTMLElement | null
|
|
78
|
+
getStartValue: () => number
|
|
79
|
+
onResize: (context: ManualLayoutResizeContext<TKind>) => void
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Coordinates pointer-driven resizing for one or more layout splitters. */
|
|
83
|
+
export function useManualLayoutResize<TKind extends string>(options: {
|
|
84
|
+
enabled: MaybeRefOrGetter<boolean>
|
|
85
|
+
resolveTarget: (kind: TKind) => ManualLayoutResizeTarget<TKind> | null
|
|
86
|
+
}) {
|
|
87
|
+
const activeResize = shallowRef<{
|
|
88
|
+
kind: TKind
|
|
89
|
+
startClientX: number
|
|
90
|
+
startClientY: number
|
|
91
|
+
startValue: number
|
|
92
|
+
containerRect: DOMRectReadOnly
|
|
93
|
+
secondaryRect: DOMRectReadOnly | null
|
|
94
|
+
cursor: string
|
|
95
|
+
} | null>(null)
|
|
96
|
+
const isResizing = computed(() => activeResize.value !== null)
|
|
97
|
+
let previousBodyCursor = ''
|
|
98
|
+
let previousBodyUserSelect = ''
|
|
99
|
+
|
|
100
|
+
function stopResize(): void {
|
|
101
|
+
if (!activeResize.value) return
|
|
102
|
+
activeResize.value = null
|
|
103
|
+
window.removeEventListener('pointermove', handlePointerMove)
|
|
104
|
+
window.removeEventListener('pointerup', stopResize)
|
|
105
|
+
window.removeEventListener('pointercancel', stopResize)
|
|
106
|
+
if (typeof document !== 'undefined') {
|
|
107
|
+
document.body.style.cursor = previousBodyCursor
|
|
108
|
+
document.body.style.userSelect = previousBodyUserSelect
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function handlePointerMove(event: PointerEvent): void {
|
|
113
|
+
const state = activeResize.value
|
|
114
|
+
if (!state) return
|
|
115
|
+
options.resolveTarget(state.kind)?.onResize({
|
|
116
|
+
kind: state.kind,
|
|
117
|
+
startValue: state.startValue,
|
|
118
|
+
deltaX: event.clientX - state.startClientX,
|
|
119
|
+
deltaY: event.clientY - state.startClientY,
|
|
120
|
+
containerRect: state.containerRect,
|
|
121
|
+
secondaryRect: state.secondaryRect,
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function startResize(kind: TKind, event: PointerEvent): void {
|
|
126
|
+
if (!toValue(options.enabled) || event.button !== 0) return
|
|
127
|
+
const target = options.resolveTarget(kind)
|
|
128
|
+
const containerRect = target?.getContainerElement()?.getBoundingClientRect()
|
|
129
|
+
if (!target || !containerRect) return
|
|
130
|
+
|
|
131
|
+
event.preventDefault()
|
|
132
|
+
if (event.currentTarget instanceof HTMLElement) {
|
|
133
|
+
event.currentTarget.setPointerCapture(event.pointerId)
|
|
134
|
+
}
|
|
135
|
+
const secondary = target.getSecondaryElement?.() ?? null
|
|
136
|
+
activeResize.value = {
|
|
137
|
+
kind,
|
|
138
|
+
startClientX: event.clientX,
|
|
139
|
+
startClientY: event.clientY,
|
|
140
|
+
startValue: target.getStartValue(),
|
|
141
|
+
containerRect,
|
|
142
|
+
secondaryRect: secondary?.getBoundingClientRect() ?? null,
|
|
143
|
+
cursor: target.cursor ?? 'col-resize',
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (typeof document !== 'undefined') {
|
|
147
|
+
previousBodyCursor = document.body.style.cursor
|
|
148
|
+
previousBodyUserSelect = document.body.style.userSelect
|
|
149
|
+
document.body.style.cursor = activeResize.value.cursor
|
|
150
|
+
document.body.style.userSelect = 'none'
|
|
151
|
+
}
|
|
152
|
+
window.addEventListener('pointermove', handlePointerMove)
|
|
153
|
+
window.addEventListener('pointerup', stopResize)
|
|
154
|
+
window.addEventListener('pointercancel', stopResize)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isResizingKind(kind: TKind): boolean {
|
|
158
|
+
return activeResize.value?.kind === kind
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
watch(() => toValue(options.enabled), enabled => { if (!enabled) stopResize() })
|
|
162
|
+
onBeforeUnmount(stopResize)
|
|
163
|
+
|
|
164
|
+
return { activeResize, isResizing, isResizingKind, startResize, stopResize }
|
|
165
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
.mint-adduct-text {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
flex-shrink: 0;
|
|
5
|
+
max-width: 100%;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
color: var(--text-muted);
|
|
8
|
+
font-variant-numeric: tabular-nums;
|
|
9
|
+
font-weight: 600;
|
|
10
|
+
letter-spacing: 0;
|
|
11
|
+
text-overflow: ellipsis;
|
|
12
|
+
white-space: nowrap;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.mint-adduct-text--mono { font-family: var(--font-mono); font-feature-settings: 'liga' 0, 'calt' 0; }
|
|
16
|
+
.mint-adduct-text--sans { font-family: var(--font-sans); font-feature-settings: 'liga' 1, 'calt' 1; font-weight: 650; }
|
|
17
|
+
|
|
18
|
+
.mint-adduct-text--xs {
|
|
19
|
+
font-size: 0.625rem;
|
|
20
|
+
line-height: 1rem;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.mint-adduct-text--inherit {
|
|
24
|
+
font-size: inherit;
|
|
25
|
+
line-height: inherit;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.mint-adduct-text--badge {
|
|
29
|
+
padding: 0.125rem 0.25rem;
|
|
30
|
+
border-radius: var(--radius-sm);
|
|
31
|
+
background: var(--bg-tertiary);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.mint-adduct-text--on-primary {
|
|
35
|
+
color: rgb(255 255 255 / 0.82);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.mint-adduct-text--badge.mint-adduct-text--on-primary {
|
|
39
|
+
background: rgb(255 255 255 / 0.2);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.mint-adduct-text--muted,
|
|
43
|
+
.mint-adduct-text--empty {
|
|
44
|
+
color: var(--text-muted);
|
|
45
|
+
}
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
overflow: hidden;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
.mint-chart--frame {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
height: 100%;
|
|
14
|
+
min-height: 0;
|
|
15
|
+
border: 0;
|
|
16
|
+
border-radius: 0;
|
|
17
|
+
background: var(--bg-card);
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
.mint-chart__header {
|
|
11
21
|
display: flex;
|
|
12
22
|
align-items: flex-start;
|
|
@@ -51,6 +61,44 @@
|
|
|
51
61
|
min-height: 12rem;
|
|
52
62
|
}
|
|
53
63
|
|
|
64
|
+
.mint-chart--frame .mint-chart__header {
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: 0.5rem;
|
|
67
|
+
padding: 0.625rem 0.875rem;
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.mint-chart--frame .mint-chart__header-text {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 0.5rem;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.mint-chart--frame .mint-chart__title {
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
font-size: 0.8125rem;
|
|
80
|
+
letter-spacing: -0.005em;
|
|
81
|
+
text-overflow: ellipsis;
|
|
82
|
+
white-space: nowrap;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.mint-chart--frame .mint-chart__description {
|
|
86
|
+
margin-top: 0 !important;
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
font-size: 0.75rem;
|
|
89
|
+
text-overflow: ellipsis;
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.mint-chart--frame .mint-chart__toolbar {
|
|
94
|
+
gap: 0.375rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.mint-chart--frame .mint-chart__body {
|
|
98
|
+
flex: 1;
|
|
99
|
+
min-height: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
54
102
|
.mint-chart__loading-overlay {
|
|
55
103
|
position: absolute;
|
|
56
104
|
inset: 0;
|
|
@@ -61,9 +109,53 @@
|
|
|
61
109
|
z-index: 1;
|
|
62
110
|
}
|
|
63
111
|
|
|
112
|
+
.mint-chart--frame .mint-chart__loading-overlay {
|
|
113
|
+
z-index: 10;
|
|
114
|
+
padding: 1.5rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.mint-chart--frame .mint-chart__body > .mint-empty-state {
|
|
118
|
+
position: absolute;
|
|
119
|
+
inset: 0;
|
|
120
|
+
z-index: 10;
|
|
121
|
+
max-width: none;
|
|
122
|
+
padding: 1.5rem;
|
|
123
|
+
background: var(--bg-card);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.mint-chart--frame .mint-empty-state__icon-wrapper {
|
|
127
|
+
width: 2.5rem;
|
|
128
|
+
height: 2.5rem;
|
|
129
|
+
margin-bottom: 0.5rem;
|
|
130
|
+
background: transparent;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.mint-chart--frame .mint-empty-state__title {
|
|
134
|
+
font-size: 0.8125rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
64
137
|
.mint-chart__legend {
|
|
65
138
|
padding: 0.75rem 1.5rem;
|
|
66
139
|
border-top: 1px solid var(--border-color);
|
|
67
140
|
font-size: 0.8125rem;
|
|
68
141
|
color: var(--text-secondary);
|
|
69
142
|
}
|
|
143
|
+
|
|
144
|
+
.mint-chart__footer {
|
|
145
|
+
padding: 0.625rem 0.875rem;
|
|
146
|
+
border-top: 1px solid var(--border-color);
|
|
147
|
+
color: var(--text-secondary);
|
|
148
|
+
font-size: 0.75rem;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.mint-chart--frame .mint-chart__footer {
|
|
152
|
+
display: flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
gap: 0.75rem;
|
|
155
|
+
padding: 0.4375rem 0.875rem;
|
|
156
|
+
background: var(--bg-primary);
|
|
157
|
+
color: var(--text-muted);
|
|
158
|
+
font-family: var(--font-mono);
|
|
159
|
+
font-size: 0.65625rem;
|
|
160
|
+
flex-shrink: 0;
|
|
161
|
+
}
|
|
@@ -1,18 +1,48 @@
|
|
|
1
1
|
/* ChemicalFormula Component Styles */
|
|
2
2
|
|
|
3
3
|
.mint-chem-formula {
|
|
4
|
-
display: inline;
|
|
5
|
-
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: baseline;
|
|
6
|
+
gap: 0.25rem;
|
|
7
|
+
max-width: 100%;
|
|
8
|
+
font-family: var(--font-mono);
|
|
9
|
+
font-weight: 600;
|
|
6
10
|
color: var(--text-primary);
|
|
7
|
-
letter-spacing: 0
|
|
11
|
+
letter-spacing: 0;
|
|
12
|
+
white-space: nowrap;
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
.mint-chem-formula--block {
|
|
11
|
-
display:
|
|
16
|
+
display: flex;
|
|
12
17
|
font-size: 1.25em;
|
|
13
18
|
padding: 0.25rem 0;
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
.mint-chem-formula--xs { font-size: 0.625rem; line-height: 1rem; }
|
|
22
|
+
.mint-chem-formula--sm { font-size: 0.75rem; line-height: 1rem; }
|
|
23
|
+
.mint-chem-formula--primary { color: var(--text-primary); }
|
|
24
|
+
.mint-chem-formula--secondary { color: var(--text-secondary); }
|
|
25
|
+
.mint-chem-formula--muted,
|
|
26
|
+
.mint-chem-formula--empty { color: var(--text-muted); }
|
|
27
|
+
|
|
28
|
+
.mint-chem-formula--pill {
|
|
29
|
+
padding: 0.125rem 0.375rem;
|
|
30
|
+
border-radius: 0.375rem;
|
|
31
|
+
background: var(--bg-tertiary);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.mint-chem-formula--pill.mint-chem-formula--sm {
|
|
35
|
+
padding: 0.125rem 0.625rem;
|
|
36
|
+
border: 1px solid var(--border-color);
|
|
37
|
+
border-radius: 999px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.mint-chem-formula__formula {
|
|
41
|
+
min-width: 0;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
text-overflow: ellipsis;
|
|
44
|
+
}
|
|
45
|
+
|
|
16
46
|
.mint-chem-formula__element {
|
|
17
47
|
/* default styling inherited */
|
|
18
48
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
.mint-layout-resize-handle {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-shrink: 0;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
background: transparent;
|
|
7
|
+
cursor: col-resize;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.mint-layout-resize-handle--vertical { width: 1rem; min-height: 2.75rem; }
|
|
11
|
+
.mint-layout-resize-handle--horizontal { min-width: 2.75rem; height: 1rem; cursor: row-resize; }
|
|
12
|
+
.mint-layout-resize-handle--edge-left,
|
|
13
|
+
.mint-layout-resize-handle--edge-right { position: absolute; top: 0; bottom: 0; z-index: 10; height: auto; }
|
|
14
|
+
.mint-layout-resize-handle--edge-left { left: 0; transform: translateX(-100%); }
|
|
15
|
+
.mint-layout-resize-handle--edge-right { right: 0; transform: translateX(100%); }
|
|
16
|
+
|
|
17
|
+
.mint-layout-resize-handle__bar {
|
|
18
|
+
display: block;
|
|
19
|
+
width: 0.25rem;
|
|
20
|
+
height: 2.75rem;
|
|
21
|
+
border-radius: 999px;
|
|
22
|
+
background: var(--border-color);
|
|
23
|
+
opacity: 0.72;
|
|
24
|
+
transition: background-color 150ms ease, opacity 150ms ease, transform 150ms ease;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.mint-layout-resize-handle--horizontal .mint-layout-resize-handle__bar {
|
|
28
|
+
width: 2.75rem;
|
|
29
|
+
height: 0.25rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.mint-layout-resize-handle:hover .mint-layout-resize-handle__bar,
|
|
33
|
+
.mint-layout-resize-handle:focus-visible .mint-layout-resize-handle__bar {
|
|
34
|
+
background: var(--color-primary);
|
|
35
|
+
opacity: 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.mint-layout-resize-handle--vertical:hover .mint-layout-resize-handle__bar,
|
|
39
|
+
.mint-layout-resize-handle--vertical:focus-visible .mint-layout-resize-handle__bar { transform: scaleX(1.35); }
|
|
40
|
+
.mint-layout-resize-handle--horizontal:hover .mint-layout-resize-handle__bar,
|
|
41
|
+
.mint-layout-resize-handle--horizontal:focus-visible .mint-layout-resize-handle__bar { transform: scaleY(1.35); }
|
|
42
|
+
|
|
43
|
+
.mint-layout-resize-handle:focus-visible {
|
|
44
|
+
outline: 2px solid var(--color-primary);
|
|
45
|
+
outline-offset: 2px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.mint-layout-resize-handle--edge-left:focus-visible,
|
|
49
|
+
.mint-layout-resize-handle--edge-right:focus-visible { outline-offset: -2px; }
|
|
50
|
+
|
|
51
|
+
.mint-layout-resize-handle[aria-disabled='true'] { cursor: not-allowed; opacity: 0.5; }
|
|
52
|
+
|
|
53
|
+
@media (prefers-reduced-motion: reduce) {
|
|
54
|
+
.mint-layout-resize-handle__bar { transition: none; }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@media (pointer: coarse) {
|
|
58
|
+
.mint-layout-resize-handle--vertical { width: 2.75rem; }
|
|
59
|
+
.mint-layout-resize-handle--horizontal { height: 2.75rem; }
|
|
60
|
+
}
|
|
@@ -20,6 +20,12 @@
|
|
|
20
20
|
gap: 2px;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
.mint-rack-editor__tab-item {
|
|
24
|
+
position: relative;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: flex-end;
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
.mint-rack-editor__tab {
|
|
24
30
|
position: relative;
|
|
25
31
|
display: flex;
|
|
@@ -32,7 +38,7 @@
|
|
|
32
38
|
border-top-right-radius: 0.5rem;
|
|
33
39
|
border: 1px solid transparent;
|
|
34
40
|
cursor: grab;
|
|
35
|
-
transition:
|
|
41
|
+
transition: background-color 0.2s, border-color 0.2s, color 0.2s, opacity 0.2s;
|
|
36
42
|
background: transparent;
|
|
37
43
|
color: var(--text-muted);
|
|
38
44
|
white-space: nowrap;
|
|
@@ -47,6 +53,11 @@
|
|
|
47
53
|
color: var(--text-secondary);
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
.mint-rack-editor__tab:focus-visible {
|
|
57
|
+
outline: 2px solid var(--color-primary);
|
|
58
|
+
outline-offset: -2px;
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
.mint-rack-editor__tab--active {
|
|
51
62
|
background-color: var(--bg-secondary);
|
|
52
63
|
color: var(--text-primary);
|
|
@@ -61,7 +72,7 @@
|
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
.mint-rack-editor__tab--drag-over {
|
|
64
|
-
box-shadow:
|
|
75
|
+
box-shadow: var(--focus-ring);
|
|
65
76
|
}
|
|
66
77
|
|
|
67
78
|
/* Slot color dot */
|
|
@@ -82,8 +93,8 @@
|
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
.mint-rack-editor__count--active {
|
|
85
|
-
background-color:
|
|
86
|
-
color:
|
|
96
|
+
background-color: color-mix(in srgb, var(--mint-success) 15%, transparent);
|
|
97
|
+
color: var(--mint-success);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
.mint-rack-editor__count--inactive {
|
|
@@ -104,7 +115,7 @@
|
|
|
104
115
|
justify-content: center;
|
|
105
116
|
font-size: 10px;
|
|
106
117
|
font-weight: 700;
|
|
107
|
-
background-color:
|
|
118
|
+
background-color: color-mix(in srgb, var(--mint-error) 90%, transparent);
|
|
108
119
|
color: white;
|
|
109
120
|
border: none;
|
|
110
121
|
cursor: pointer;
|
|
@@ -112,7 +123,8 @@
|
|
|
112
123
|
transition: opacity 0.15s, transform 0.15s;
|
|
113
124
|
}
|
|
114
125
|
|
|
115
|
-
.mint-rack-editor__tab:hover .mint-rack-editor__tab-remove
|
|
126
|
+
.mint-rack-editor__tab-item:hover .mint-rack-editor__tab-remove,
|
|
127
|
+
.mint-rack-editor__tab-item:focus-within .mint-rack-editor__tab-remove {
|
|
116
128
|
opacity: 1;
|
|
117
129
|
}
|
|
118
130
|
|
|
@@ -120,6 +132,16 @@
|
|
|
120
132
|
transform: scale(1.1);
|
|
121
133
|
}
|
|
122
134
|
|
|
135
|
+
.mint-rack-editor__tab-remove:focus-visible {
|
|
136
|
+
opacity: 1;
|
|
137
|
+
outline: 2px solid var(--color-primary);
|
|
138
|
+
outline-offset: 2px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@media (hover: none) {
|
|
142
|
+
.mint-rack-editor__tab-remove { opacity: 1; }
|
|
143
|
+
}
|
|
144
|
+
|
|
123
145
|
/* Add rack button */
|
|
124
146
|
.mint-rack-editor__add-btn {
|
|
125
147
|
display: flex;
|
|
@@ -131,15 +153,15 @@
|
|
|
131
153
|
font-weight: 500;
|
|
132
154
|
border-radius: var(--radius-md);
|
|
133
155
|
cursor: pointer;
|
|
134
|
-
transition:
|
|
156
|
+
transition: background-color 0.2s, color 0.2s;
|
|
135
157
|
border: none;
|
|
136
158
|
background: transparent;
|
|
137
159
|
color: var(--text-muted);
|
|
138
160
|
}
|
|
139
161
|
|
|
140
162
|
.mint-rack-editor__add-btn:hover {
|
|
141
|
-
background-color:
|
|
142
|
-
color:
|
|
163
|
+
background-color: color-mix(in srgb, var(--mint-success) 10%, transparent);
|
|
164
|
+
color: var(--mint-success);
|
|
143
165
|
}
|
|
144
166
|
|
|
145
167
|
/* Toolbar */
|