@platforma-sdk/ui-vue 1.42.53 → 1.43.1

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.
Files changed (84) hide show
  1. package/.turbo/turbo-build.log +213 -207
  2. package/.turbo/turbo-type-check.log +1 -1
  3. package/CHANGELOG.md +20 -0
  4. package/dist/AgGridVue/useAgGridOptions.js +2 -3
  5. package/dist/AgGridVue/useAgGridOptions.js.map +1 -1
  6. package/dist/assets/multi-sequence-alignment.worker-Cm0gZp19.js +6 -0
  7. package/dist/assets/multi-sequence-alignment.worker-Cm0gZp19.js.map +1 -0
  8. package/dist/assets/phylogenetic-tree.worker-4CrExYEo.js +5 -0
  9. package/dist/assets/phylogenetic-tree.worker-4CrExYEo.js.map +1 -0
  10. package/dist/components/PlAgDataTable/PlAgRowCount.vue.js +2 -3
  11. package/dist/components/PlAgDataTable/PlAgRowCount.vue.js.map +1 -1
  12. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js +11 -12
  13. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js.map +1 -1
  14. package/dist/components/PlAgRowNumHeader.vue.js +8 -9
  15. package/dist/components/PlAgRowNumHeader.vue.js.map +1 -1
  16. package/dist/components/PlMultiSequenceAlignment/Consensus.vue.d.ts +1 -0
  17. package/dist/components/PlMultiSequenceAlignment/Consensus.vue2.js +48 -46
  18. package/dist/components/PlMultiSequenceAlignment/Consensus.vue2.js.map +1 -1
  19. package/dist/components/PlMultiSequenceAlignment/Consensus.vue3.js +5 -7
  20. package/dist/components/PlMultiSequenceAlignment/Consensus.vue3.js.map +1 -1
  21. package/dist/components/PlMultiSequenceAlignment/Legend.vue2.js +14 -13
  22. package/dist/components/PlMultiSequenceAlignment/Legend.vue2.js.map +1 -1
  23. package/dist/components/PlMultiSequenceAlignment/Legend.vue3.js +9 -8
  24. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.d.ts +16 -9
  25. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue2.js +117 -85
  26. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue2.js.map +1 -1
  27. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue3.js +25 -18
  28. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue3.js.map +1 -1
  29. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue.d.ts +8 -0
  30. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue.js +10 -0
  31. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue.js.map +1 -0
  32. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue2.js +77 -0
  33. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue2.js.map +1 -0
  34. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue3.js +9 -0
  35. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue3.js.map +1 -0
  36. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.d.ts +26 -18
  37. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue2.js +119 -120
  38. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue2.js.map +1 -1
  39. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue.js +7 -124
  40. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue.js.map +1 -1
  41. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue2.js +124 -2
  42. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue2.js.map +1 -1
  43. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue3.js +9 -0
  44. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue3.js.map +1 -0
  45. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js +90 -90
  46. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js.map +1 -1
  47. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue3.js +9 -7
  48. package/dist/components/PlMultiSequenceAlignment/cell-size.d.ts +4 -0
  49. package/dist/components/PlMultiSequenceAlignment/cell-size.js +8 -0
  50. package/dist/components/PlMultiSequenceAlignment/cell-size.js.map +1 -0
  51. package/dist/components/PlMultiSequenceAlignment/data.d.ts +15 -10
  52. package/dist/components/PlMultiSequenceAlignment/data.js +309 -202
  53. package/dist/components/PlMultiSequenceAlignment/data.js.map +1 -1
  54. package/dist/components/PlMultiSequenceAlignment/markup.js +9 -7
  55. package/dist/components/PlMultiSequenceAlignment/markup.js.map +1 -1
  56. package/dist/components/PlMultiSequenceAlignment/migrations.js +15 -13
  57. package/dist/components/PlMultiSequenceAlignment/migrations.js.map +1 -1
  58. package/dist/components/PlMultiSequenceAlignment/multi-sequence-alignment.worker.d.ts +6 -0
  59. package/dist/components/PlMultiSequenceAlignment/phylogenetic-tree.worker.d.ts +7 -0
  60. package/dist/components/PlMultiSequenceAlignment/settings.js +3 -4
  61. package/dist/components/PlMultiSequenceAlignment/settings.js.map +1 -1
  62. package/dist/index.js +25 -27
  63. package/dist/index.js.map +1 -1
  64. package/dist/lib.d.ts +1 -2
  65. package/package.json +6 -6
  66. package/src/components/PlMultiSequenceAlignment/Consensus.vue +38 -39
  67. package/src/components/PlMultiSequenceAlignment/Legend.vue +9 -9
  68. package/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue +222 -126
  69. package/src/components/PlMultiSequenceAlignment/PhylogeneticTree.vue +110 -0
  70. package/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue +28 -22
  71. package/src/components/PlMultiSequenceAlignment/SeqLogo.vue +77 -69
  72. package/src/components/PlMultiSequenceAlignment/Toolbar.vue +47 -39
  73. package/src/components/PlMultiSequenceAlignment/cell-size.ts +4 -0
  74. package/src/components/PlMultiSequenceAlignment/data.ts +361 -149
  75. package/src/components/PlMultiSequenceAlignment/markup.ts +10 -8
  76. package/src/components/PlMultiSequenceAlignment/migrations.ts +6 -1
  77. package/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.worker.ts +54 -0
  78. package/src/components/PlMultiSequenceAlignment/phylogenetic-tree.worker.ts +89 -0
  79. package/src/components/PlMultiSequenceAlignment/settings.ts +1 -2
  80. package/src/lib.ts +1 -3
  81. package/dist/components/PlMultiSequenceAlignment/multi-sequence-alignment.d.ts +0 -7
  82. package/dist/components/PlMultiSequenceAlignment/multi-sequence-alignment.js +0 -51
  83. package/dist/components/PlMultiSequenceAlignment/multi-sequence-alignment.js.map +0 -1
  84. package/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.ts +0 -101
@@ -9,20 +9,25 @@ import {
9
9
  computed,
10
10
  onBeforeUnmount,
11
11
  shallowRef,
12
+ useCssModule,
12
13
  useTemplateRef,
13
14
  watchEffect,
14
15
  } from 'vue';
16
+ import { cellSize } from './cell-size';
15
17
  import type { ResidueCounts } from './types';
16
18
  import { useMiPlots } from './useMiPlots';
17
19
 
18
- const { residueCounts } = defineProps<{
20
+ const props = defineProps<{
19
21
  residueCounts: ResidueCounts;
22
+ labelsClass: string;
20
23
  }>();
21
24
 
25
+ const classes = useCssModule();
26
+
22
27
  const plotEl = useTemplateRef('plotEl');
23
28
 
24
- const columns = computed(() => {
25
- return residueCounts.map((column) => {
29
+ const columns = computed(() =>
30
+ props.residueCounts.map((column) => {
26
31
  let totalCount = 0;
27
32
  let topResidue = { label: '', count: 0 };
28
33
  for (const [residue, count] of Object.entries(column)) {
@@ -35,11 +40,11 @@ const columns = computed(() => {
35
40
  label: topResidue.label,
36
41
  color: `color-mix(in oklab, ${confidence} #3056AE, #C1CDE9)`,
37
42
  };
38
- });
39
- });
43
+ }),
44
+ );
40
45
 
41
- const settings = computed<Settings | undefined>(() => {
42
- const width = residueCounts.length * 20;
46
+ const settings = computed(() => {
47
+ const width = props.residueCounts.length * cellSize.inline;
43
48
  return ({
44
49
  type: 'discrete',
45
50
  y: {
@@ -52,7 +57,7 @@ const settings = computed<Settings | undefined>(() => {
52
57
  type: 'column',
53
58
  value: 'columnKey',
54
59
  },
55
- order: residueCounts.map((_, i) => i),
60
+ order: props.residueCounts.map((_, i) => i),
56
61
  inheritedAes: Object.fromEntries(
57
62
  columns.value.map(({ color }) => ({ fillColor: color })).entries(),
58
63
  ),
@@ -61,8 +66,9 @@ const settings = computed<Settings | undefined>(() => {
61
66
  type: 'bar',
62
67
  height: 'max',
63
68
  aes: {
64
- ...residueCounts.length && {
65
- width: (width - residueCounts.length + 1) / residueCounts.length,
69
+ ...props.residueCounts.length && {
70
+ width: (width - props.residueCounts.length + 1)
71
+ / props.residueCounts.length,
66
72
  },
67
73
  fillColor: {
68
74
  type: 'primaryGrouping',
@@ -95,34 +101,32 @@ const settings = computed<Settings | undefined>(() => {
95
101
  frame: {
96
102
  type: 'empty',
97
103
  },
98
- });
104
+ } satisfies Settings);
99
105
  });
100
106
 
101
- const data = computed<DataByColumns>(
102
- () => {
103
- const countKey: number[] = [];
104
- const columnKey: number[] = [];
105
- for (const [columnIndex, column] of residueCounts.entries()) {
106
- for (const [residue, count] of Object.entries(column)) {
107
- if (residue === '-') continue;
108
- countKey.push(residue === ' ' ? 0 : count);
109
- columnKey.push(columnIndex);
110
- }
107
+ const data = computed<DataByColumns>(() => {
108
+ const countKey: number[] = [];
109
+ const columnKey: number[] = [];
110
+ for (const [columnIndex, column] of props.residueCounts.entries()) {
111
+ for (const [residue, count] of Object.entries(column)) {
112
+ if (residue === '-') continue;
113
+ countKey.push(count);
114
+ columnKey.push(columnIndex);
111
115
  }
112
- return ({
113
- type: 'columns',
114
- id: `consensus-${crypto.randomUUID()}`,
115
- values: { countKey, columnKey },
116
- });
117
- },
118
- );
116
+ }
117
+ return ({
118
+ type: 'columns',
119
+ id: `consensus-${crypto.randomUUID()}`,
120
+ values: { countKey, columnKey },
121
+ });
122
+ });
119
123
 
120
124
  const plot = shallowRef<ChartInterface>();
121
125
 
122
126
  const { miplots, error } = useMiPlots();
123
127
 
124
128
  watchEffect(async () => {
125
- if (!settings.value || !plotEl.value || !miplots.value) return;
129
+ if (!plotEl.value || !miplots.value) return;
126
130
  if (!plot.value) {
127
131
  plot.value = miplots.value.newPlot(data.value, settings.value);
128
132
  plot.value.mount(plotEl.value);
@@ -140,8 +144,8 @@ onBeforeUnmount(() => {
140
144
  <PlAlert v-if="error" type="error">
141
145
  {{ error.message }}
142
146
  </PlAlert>
143
- <div v-else :class="$style.container">
144
- <div :class="$style.labels">
147
+ <div v-else :class="classes.container">
148
+ <div :class="props.labelsClass">
145
149
  {{ columns.map(column => column.label).join('') }}
146
150
  </div>
147
151
  <div ref="plotEl" />
@@ -153,14 +157,9 @@ onBeforeUnmount(() => {
153
157
  display: flex;
154
158
  flex-direction: column;
155
159
  gap: 4px;
156
- }
157
160
 
158
- .labels {
159
- font-family: Spline Sans Mono;
160
- font-weight: 600;
161
- line-height: 24px;
162
- letter-spacing: 11.6px;
163
- text-indent: 5.8px;
164
- margin-inline-end: -5.8px;
161
+ svg {
162
+ display: block;
163
+ }
165
164
  }
166
165
  </style>
@@ -1,22 +1,22 @@
1
1
  <script setup lang="ts">
2
+ import { useCssModule } from 'vue';
2
3
  import type { HighlightLegend } from './types';
3
4
 
4
- defineProps<{
5
+ const props = defineProps<{
5
6
  legend: HighlightLegend;
6
7
  }>();
8
+
9
+ const classes = useCssModule();
7
10
  </script>
8
11
 
9
12
  <template>
10
- <div :class="$style.container">
13
+ <div :class="classes.container">
11
14
  <div
12
- v-for="([key, { label, color }]) of Object.entries(legend)"
15
+ v-for="({ label, color }, key) of props.legend"
13
16
  :key="key"
14
- :class="$style.item"
17
+ :class="classes.item"
15
18
  >
16
- <div
17
- :class="$style['color-sample']"
18
- :style="{ backgroundColor: color }"
19
- />
19
+ <div :class="classes.colorSample" :style="{ backgroundColor: color }" />
20
20
  {{ label }}
21
21
  </div>
22
22
  </div>
@@ -35,7 +35,7 @@ defineProps<{
35
35
  gap: 4px;
36
36
  }
37
37
 
38
- .color-sample {
38
+ .colorSample {
39
39
  display: inline-block;
40
40
  block-size: 18px;
41
41
  inline-size: 18px;
@@ -1,83 +1,165 @@
1
1
  <script lang="ts" setup>
2
- import { useObjectUrl } from '@vueuse/core';
3
- import { computed, useTemplateRef } from 'vue';
2
+ import type { PlMultiSequenceAlignmentWidget } from '@platforma-sdk/model';
3
+ import {
4
+ computed,
5
+ onBeforeMount,
6
+ onBeforeUnmount,
7
+ onWatcherCleanup,
8
+ ref,
9
+ useCssModule,
10
+ useTemplateRef,
11
+ watch,
12
+ } from 'vue';
13
+ import { cellSize } from './cell-size';
4
14
  import Consensus from './Consensus.vue';
5
15
  import Legend from './Legend.vue';
16
+ import type { TreeNodeData } from './phylogenetic-tree.worker';
17
+ import PhylogeneticTree from './PhylogeneticTree.vue';
6
18
  import SeqLogo from './SeqLogo.vue';
7
19
  import type { HighlightLegend, ResidueCounts } from './types';
8
20
 
9
- const { sequences, highlightImage } = defineProps<{
10
- sequences: string[];
11
- sequenceNames: string[];
12
- labelRows: string[][];
13
- residueCounts: ResidueCounts;
14
- highlightImage: {
15
- blob: Blob;
16
- legend: HighlightLegend;
17
- } | undefined;
18
- widgets: ('consensus' | 'seqLogo' | 'legend')[];
21
+ const props = defineProps<{
22
+ sequences: {
23
+ name: string;
24
+ rows: string[];
25
+ residueCounts: ResidueCounts;
26
+ highlightImageUrl?: string;
27
+ }[];
28
+ labels: {
29
+ rows: string[];
30
+ }[];
31
+ highlightLegend: HighlightLegend | undefined;
32
+ phylogeneticTree: TreeNodeData[] | undefined;
33
+ widgets: PlMultiSequenceAlignmentWidget[];
19
34
  }>();
20
35
 
36
+ const classes = useCssModule();
37
+
21
38
  const rootEl = useTemplateRef('rootRef');
22
39
  defineExpose({ rootEl });
23
40
 
24
- const highlightImageObjectUrl = useObjectUrl(() => highlightImage?.blob);
25
- const highlightImageCssUrl = computed(() =>
26
- highlightImageObjectUrl.value
27
- ? `url('${highlightImageObjectUrl.value}')`
28
- : 'none',
41
+ const rowCount = computed(() => props.sequences.at(0)?.rows.length ?? 0);
42
+
43
+ const targetCellInlineSize = CSS.px(cellSize.inline).toString();
44
+ const targetCellBlockSize = CSS.px(cellSize.block).toString();
45
+
46
+ const referenceCellRef = useTemplateRef('referenceCell');
47
+ const referenceCellInlineSize = ref<number>();
48
+
49
+ const cornerRef = useTemplateRef('corner');
50
+ const cornerInlineSize = ref<number>();
51
+
52
+ const letterSpacing = computed(() =>
53
+ referenceCellInlineSize.value
54
+ ? CSS.px(cellSize.inline - referenceCellInlineSize.value).toString()
55
+ : undefined,
29
56
  );
30
57
 
31
- const sequenceLengths = computed(() =>
32
- sequences.at(0)?.split(' ').map(({ length }) => length),
58
+ const sequenceNameInsetInlineStart = computed(() =>
59
+ CSS.px(cornerInlineSize.value ?? 0).toString(),
33
60
  );
61
+
62
+ let observer: ResizeObserver;
63
+
64
+ onBeforeMount(() => {
65
+ const getInlineSize = (entry: ResizeObserverEntry) =>
66
+ entry.borderBoxSize.find(Boolean)?.inlineSize;
67
+
68
+ observer = new ResizeObserver((entries) => {
69
+ for (const entry of entries) {
70
+ switch (entry.target) {
71
+ case referenceCellRef.value:
72
+ referenceCellInlineSize.value = getInlineSize(entry);
73
+ break;
74
+ case cornerRef.value:
75
+ cornerInlineSize.value = getInlineSize(entry);
76
+ break;
77
+ }
78
+ }
79
+ });
80
+ });
81
+
82
+ onBeforeUnmount(() => {
83
+ observer.disconnect();
84
+ });
85
+
86
+ for (const ref of [referenceCellRef, cornerRef]) {
87
+ watch(ref, (el, prevEl) => {
88
+ if (el) observer.observe(el);
89
+ onWatcherCleanup(() => {
90
+ if (prevEl) observer.unobserve(prevEl);
91
+ });
92
+ });
93
+ }
34
94
  </script>
35
95
 
36
96
  <template>
37
- <div ref="rootRef" :class="$style.root">
38
- <div :class="['pl-scrollable', $style.table]">
39
- <div :class="$style.corner">
40
- <div :class="$style['label-scroll-indicator']" />
41
- </div>
42
- <div :class="$style.header">
43
- <div v-if="sequenceNames.length > 1" :class="$style['sequence-names']">
44
- <span
45
- v-for="(name, index) of sequenceNames"
46
- :key="index"
47
- :style="{
48
- inlineSize: ((sequenceLengths?.at(index) ?? 0) * 20)
49
- + 'px',
50
- }"
51
- >{{ name }}</span>
52
- </div>
53
- <Consensus v-if="widgets.includes('consensus')" :residue-counts />
54
- <SeqLogo v-if="widgets.includes('seqLogo')" :residue-counts />
55
- </div>
56
- <div :class="$style.labels">
57
- <div :class="$style['labels-grid']">
58
- <template v-for="(labelRow, rowIndex) of labelRows">
59
- <div
60
- v-for="(label, labelIndex) of labelRow"
61
- :key="labelIndex"
62
- :style="{ gridRow: rowIndex + 1 }"
63
- >
64
- {{ label }}
97
+ <div ref="rootRef" :class="classes.root">
98
+ <div ref="referenceCell" :class="classes.referenceCell">x</div>
99
+ <div :class="['pl-scrollable', classes.table]">
100
+ <div :class="classes.sidebar">
101
+ <PhylogeneticTree
102
+ v-if="props.widgets.includes('tree') && props.phylogeneticTree"
103
+ :tree="props.phylogeneticTree"
104
+ :class="classes.phylogeneticTree"
105
+ />
106
+ <div :class="classes.labels">
107
+ <template
108
+ v-for="({ rows }, columnIndex) of props.labels"
109
+ :key="columnIndex"
110
+ >
111
+ <div v-for="(row, rowIndex) of rows" :key="rowIndex">
112
+ {{ row }}
65
113
  </div>
66
114
  </template>
67
115
  </div>
68
116
  </div>
69
- <div :class="$style.sequences">
117
+ <template v-if="letterSpacing !== undefined">
70
118
  <div
71
- v-for="(sequence, index) of sequences"
72
- :key="index"
119
+ v-for="(column, columnIndex) of props.sequences"
120
+ :key="columnIndex"
121
+ :class="classes.sequenceColumn"
73
122
  >
74
- {{ sequence }}
123
+ <div :class="classes.sequenceHeader">
124
+ <div
125
+ v-show="props.sequences.length > 1"
126
+ :class="classes.sequenceName"
127
+ >
128
+ {{ column.name }}
129
+ </div>
130
+ <Consensus
131
+ v-if="props.widgets.includes('consensus')"
132
+ :residue-counts="column.residueCounts"
133
+ :labels-class="classes.sequenceRow"
134
+ />
135
+ <SeqLogo
136
+ v-if="props.widgets.includes('seqLogo')"
137
+ :residue-counts="column.residueCounts"
138
+ />
139
+ </div>
140
+ <div
141
+ :class="classes.sequenceRowsContainer"
142
+ :style="{
143
+ backgroundImage: column.highlightImageUrl
144
+ ? `url(${column.highlightImageUrl})`
145
+ : undefined,
146
+ }"
147
+ >
148
+ <div
149
+ v-for="(row, rowIndex) of column.rows"
150
+ :key="rowIndex"
151
+ :class="classes.sequenceRow"
152
+ >
153
+ {{ row }}
154
+ </div>
155
+ </div>
75
156
  </div>
76
- </div>
157
+ </template>
158
+ <div ref="corner" :class="classes.corner" />
77
159
  </div>
78
160
  <Legend
79
- v-if="widgets?.includes('legend') && highlightImage?.legend"
80
- :legend="highlightImage.legend"
161
+ v-if="props.widgets.includes('legend') && props.highlightLegend"
162
+ :legend="props.highlightLegend"
81
163
  />
82
164
  </div>
83
165
  </template>
@@ -90,114 +172,128 @@ const sequenceLengths = computed(() =>
90
172
  min-block-size: 0;
91
173
  -webkit-print-color-adjust: exact;
92
174
  print-color-adjust: exact;
175
+ container-type: inline-size;
93
176
 
94
177
  &[data-pre-print] {
95
- .table {
96
- container-type: unset;
97
- }
98
- .labels {
178
+ container-type: unset;
179
+
180
+ .sidebar {
99
181
  max-inline-size: unset;
100
182
  }
101
183
  }
102
184
  }
103
185
 
186
+ .referenceCell {
187
+ position: fixed;
188
+ visibility: hidden;
189
+ font-family: Spline Sans Mono;
190
+ font-weight: 600;
191
+ line-height: v-bind('targetCellBlockSize');
192
+ }
193
+
104
194
  .table {
105
- container-type: inline-size;
106
195
  display: grid;
107
- grid-template-areas:
108
- "corner header"
109
- "labels sequences";
196
+ grid-template-columns:
197
+ [sidebar-start] auto [sidebar-end] repeat(
198
+ v-bind('props.sequences.length'),
199
+ [column-start] auto [column-end]
200
+ );
201
+ grid-template-rows:
202
+ [header-start] auto [header-end]
203
+ repeat(v-bind('rowCount'), [row-start] auto [row-end]);
110
204
  justify-content: start;
111
- timeline-scope: --msa-labels-scroll;
205
+ position: relative;
112
206
  @media print {
113
207
  overflow: visible;
114
208
  }
115
209
  }
116
210
 
117
- .corner {
118
- grid-area: corner;
119
- background-color: #fff;
211
+ .sidebar {
212
+ grid-column: sidebar;
213
+ grid-row: 1 row-start / -1 row-end;
214
+ display: grid;
215
+ grid-template-rows: subgrid;
120
216
  position: sticky;
121
217
  inset-inline-start: 0;
122
- inset-block-start: 0;
123
- z-index: 2;
218
+ background-color: #fff;
219
+ inline-size: min-content;
220
+ max-inline-size: 30cqi;
221
+ overflow: scroll;
222
+ overscroll-behavior-inline: none;
223
+ scrollbar-width: none;
124
224
  }
125
225
 
126
- .label-scroll-indicator {
127
- position: absolute;
128
- inset-inline-end: 0;
129
- block-size: 100cqb;
130
- inline-size: 8px;
131
- animation-name: hide;
132
- animation-timeline: --msa-labels-scroll;
133
- visibility: hidden;
134
- background: #fff;
135
- box-shadow: -4px 0 4px -2px rgba(0, 0, 0, 0.10);
226
+ .phylogeneticTree {
227
+ grid-row: 1 row-start / -1 row-end;
136
228
  }
137
229
 
138
- .header {
139
- grid-area: header;
140
- background-color: #fff;
230
+ .labels {
231
+ grid-row: 1 row-start / -1 row-end;
232
+ display: grid;
233
+ grid-template-columns: repeat(v-bind('props.labels.length'), auto);
234
+ grid-template-rows: subgrid;
235
+ grid-auto-flow: column;
236
+ column-gap: 12px;
237
+ padding-inline-end: 12px;
238
+ font-family: Spline Sans Mono;
239
+ line-height: v-bind('targetCellBlockSize');
240
+ white-space: nowrap;
241
+ }
242
+
243
+ .sequenceColumn {
244
+ grid-row: header-start / -1 row-end;
245
+ display: grid;
246
+ grid-template-rows: subgrid;
247
+ & + & {
248
+ margin-inline-start: 24px;
249
+ }
250
+ }
251
+
252
+ .sequenceHeader {
253
+ grid-row: header;
254
+ display: flex;
255
+ flex-direction: column;
256
+ justify-content: end;
257
+ min-inline-size: 0;
141
258
  position: sticky;
142
259
  inset-block-start: 0;
143
- z-index: 1;
260
+ background-color: #fff;
144
261
  }
145
262
 
146
- .sequence-names {
147
- display: flex;
263
+ .sequenceName {
264
+ margin-block-end: 4px;
148
265
  font-weight: 700;
149
266
  line-height: 20px;
150
- margin-block-end: 4px;
151
- gap: 20px;
152
- }
153
-
154
- .labels {
155
- grid-area: labels;
156
- background-color: #fff;
267
+ inline-size: fit-content;
157
268
  position: sticky;
158
- inset-inline-start: 0;
159
- z-index: 1;
160
- inline-size: max-content;
161
- max-inline-size: 30cqi;
162
- overflow: scroll;
163
- scrollbar-width: none;
164
- overscroll-behavior-inline: none;
165
- scroll-timeline: --msa-labels-scroll inline;
269
+ inset-inline-start: v-bind('sequenceNameInsetInlineStart');
166
270
  }
167
271
 
168
- .labels-grid {
272
+ .sequenceRowsContainer {
273
+ grid-row: 1 row-start / -1 row-end;
169
274
  display: grid;
170
- grid-auto-flow: dense;
171
- font-family: Spline Sans Mono;
172
- line-height: 24px;
173
- text-wrap: nowrap;
174
-
175
- > * {
176
- padding-inline-end: 12px;
177
- }
275
+ grid-template-rows: subgrid;
178
276
  }
179
277
 
180
- .sequences {
181
- grid-area: sequences;
182
- display: flex;
183
- flex-direction: column;
278
+ .sequenceRow {
184
279
  font-family: Spline Sans Mono;
185
280
  font-weight: 600;
186
- line-height: 24px;
187
- letter-spacing: 11.6px;
188
- text-indent: 5.8px;
189
- margin-inline-end: -5.8px;
190
- background-image: v-bind(highlightImageCssUrl);
191
- background-repeat: no-repeat;
192
- background-size: calc(100% - 5.8px) 100%;
281
+ line-height: v-bind('targetCellBlockSize');
282
+ letter-spacing: v-bind('letterSpacing');
283
+ text-indent: calc(v-bind('letterSpacing') / 2);
284
+ inline-size: calc-size(
285
+ min-content,
286
+ round(down, size, v-bind('targetCellInlineSize'))
287
+ );
288
+ white-space: nowrap;
193
289
  }
194
290
 
195
- @keyframes hide {
196
- from {
197
- visibility: visible;
198
- }
199
- to {
200
- visibility: hidden;
201
- }
291
+ .corner {
292
+ grid-column: sidebar;
293
+ grid-row: header;
294
+ position: sticky;
295
+ inset-inline-start: 0;
296
+ inset-block-start: 0;
297
+ background-color: #fff;
202
298
  }
203
299
  </style>