@genspectrum/dashboard-components 0.1.3 → 0.1.4

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 (75) hide show
  1. package/custom-elements.json +311 -75
  2. package/dist/dashboard-components.js +622 -434
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/genspectrum-components.d.ts +229 -42
  5. package/dist/style.css +132 -139
  6. package/package.json +9 -5
  7. package/src/preact/aggregatedData/aggregate.stories.tsx +5 -5
  8. package/src/preact/aggregatedData/aggregate.tsx +8 -4
  9. package/src/preact/components/ReferenceGenomesAwaiter.tsx +25 -0
  10. package/src/preact/components/csv-download-button.tsx +8 -2
  11. package/src/preact/components/headline.tsx +16 -4
  12. package/src/preact/components/min-max-range-slider.tsx +4 -4
  13. package/src/preact/components/percent-intput.tsx +2 -3
  14. package/src/preact/components/resize-container.tsx +23 -0
  15. package/src/preact/components/table.tsx +1 -0
  16. package/src/preact/components/tabs.stories.tsx +2 -2
  17. package/src/preact/components/tabs.tsx +47 -24
  18. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +36 -4
  19. package/src/preact/dateRangeSelector/date-range-selector.tsx +57 -43
  20. package/src/preact/locationFilter/location-filter.tsx +2 -2
  21. package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +5 -5
  22. package/src/preact/mutationComparison/getMutationComparisonTableData.ts +45 -10
  23. package/src/preact/mutationComparison/mutation-comparison-table.tsx +20 -22
  24. package/src/preact/mutationComparison/mutation-comparison-venn.tsx +6 -3
  25. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +8 -1
  26. package/src/preact/mutationComparison/mutation-comparison.tsx +13 -4
  27. package/src/preact/mutationFilter/mutation-filter.stories.tsx +70 -31
  28. package/src/preact/mutationFilter/mutation-filter.tsx +62 -14
  29. package/src/preact/mutations/getInsertionsTableData.spec.ts +6 -4
  30. package/src/preact/mutations/getInsertionsTableData.ts +1 -1
  31. package/src/preact/mutations/getMutationsTableData.spec.ts +9 -19
  32. package/src/preact/mutations/getMutationsTableData.ts +1 -1
  33. package/src/preact/mutations/mutations-insertions-table.tsx +3 -1
  34. package/src/preact/mutations/mutations-table.tsx +3 -1
  35. package/src/preact/mutations/mutations.stories.tsx +8 -1
  36. package/src/preact/mutations/mutations.tsx +16 -5
  37. package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +1 -0
  38. package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -0
  39. package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +1 -0
  40. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
  41. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +17 -9
  42. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +8 -5
  43. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +12 -0
  44. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +13 -8
  45. package/src/preact/shared/sort/sortInsertions.spec.ts +11 -10
  46. package/src/preact/shared/sort/sortInsertions.ts +10 -17
  47. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +19 -10
  48. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +45 -12
  49. package/src/preact/textInput/text-input.stories.tsx +22 -1
  50. package/src/preact/textInput/text-input.tsx +3 -1
  51. package/src/utils/typeAssertions.spec.ts +31 -0
  52. package/src/utils/typeAssertions.ts +16 -0
  53. package/src/web-components/PreactLitAdapter.tsx +0 -1
  54. package/src/web-components/app.stories.ts +129 -0
  55. package/src/web-components/app.ts +27 -6
  56. package/src/web-components/display/aggregate-component.stories.ts +21 -11
  57. package/src/web-components/display/aggregate-component.tsx +12 -5
  58. package/src/web-components/display/mutation-comparison-component.stories.ts +29 -11
  59. package/src/web-components/display/mutation-comparison-component.tsx +72 -4
  60. package/src/web-components/display/mutations-component.stories.ts +14 -13
  61. package/src/web-components/display/mutations-component.tsx +14 -1
  62. package/src/web-components/display/prevalence-over-time-component.stories.ts +20 -18
  63. package/src/web-components/display/prevalence-over-time-component.tsx +12 -0
  64. package/src/web-components/display/relative-growth-advantage-component.stories.ts +11 -10
  65. package/src/web-components/display/relative-growth-advantage-component.tsx +12 -0
  66. package/src/web-components/input/date-range-selector-component.stories.ts +35 -8
  67. package/src/web-components/input/date-range-selector-component.tsx +18 -5
  68. package/src/web-components/input/location-filter-component.stories.ts +15 -4
  69. package/src/web-components/input/location-filter-component.tsx +2 -6
  70. package/src/web-components/input/mutation-filter-component.stories.ts +20 -9
  71. package/src/web-components/input/mutation-filter-component.tsx +10 -2
  72. package/src/web-components/input/text-input-component.stories.ts +13 -4
  73. package/src/web-components/input/text-input-component.tsx +11 -2
  74. package/src/web-components/display/aggregate-component.mdx +0 -25
  75. package/src/web-components/input/location-filter.mdx +0 -25
@@ -2,10 +2,11 @@ import { createContext, provide, consume } from "@lit/context";
2
2
  import { Task } from "@lit/task";
3
3
  import { LitElement, html, unsafeCSS } from "lit";
4
4
  import z$1 from "zod";
5
- import { options, Fragment, createContext as createContext$1, render } from "preact";
5
+ import { options, createContext as createContext$1, Fragment, render } from "preact";
6
6
  import { Grid } from "gridjs";
7
7
  import { Chart, registerables, Scale } from "chart.js";
8
8
  import { VennDiagramController, ArcSlice, extractSets } from "chartjs-chart-venn";
9
+ import { ReactiveElement } from "@lit/reactive-element";
9
10
  import { BarWithErrorBarsController, BarWithErrorBar } from "chartjs-chart-error-bars";
10
11
  import flatpickr from "flatpickr";
11
12
  /**
@@ -490,14 +491,10 @@ let App = class extends LitElement {
490
491
  }
491
492
  render() {
492
493
  return this.updateReferenceGenome.render({
493
- complete: () => {
494
- return html` <slot></slot>`;
495
- },
494
+ complete: () => html` <slot></slot>`,
496
495
  error: () => html`<p>Error</p>`,
497
496
  // TODO(#143): Add more advanced error handling
498
- pending: () => {
499
- return html`<p>Loading...</p>`;
500
- }
497
+ pending: () => html` <p>Loading reference genomes...</p> `
501
498
  });
502
499
  }
503
500
  createRenderRoot() {
@@ -516,9 +513,11 @@ App = __decorateClass$a([
516
513
  ], App);
517
514
  var f$1 = 0;
518
515
  function u$1(e2, t2, n3, o2, i2, u2) {
519
- var a2, c2, p2 = {};
520
- for (c2 in t2)
521
- "ref" == c2 ? a2 = t2[c2] : p2[c2] = t2[c2];
516
+ t2 || (t2 = {});
517
+ var a2, c2, p2 = t2;
518
+ if ("ref" in p2)
519
+ for (c2 in p2 = {}, t2)
520
+ "ref" == c2 ? a2 = t2[c2] : p2[c2] = t2[c2];
522
521
  var l2 = { type: e2, props: p2, key: n3, ref: a2, __k: null, __: null, __b: 0, __e: null, __d: void 0, __c: null, constructor: void 0, __v: --f$1, __i: -1, __u: 0, __source: i2, __self: u2 };
523
522
  if ("function" == typeof e2 && (a2 = e2.defaultProps))
524
523
  for (c2 in a2)
@@ -662,18 +661,29 @@ function getMutationComparisonTableData(data, proportionInterval) {
662
661
  const mutationsToProportions = /* @__PURE__ */ new Map();
663
662
  for (const mutationData of data.content) {
664
663
  for (const mutationEntry of mutationData.data) {
665
- const mutation = mutationEntry.mutation.toString();
666
- const proportions = mutationsToProportions.get(mutation) || {};
667
- proportions[mutationData.displayName] = mutationEntry.proportion;
668
- mutationsToProportions.set(mutation, proportions);
664
+ const mutationKey = mutationEntry.mutation.toString();
665
+ const existingRow = mutationsToProportions.get(mutationKey);
666
+ if (!existingRow) {
667
+ mutationsToProportions.set(
668
+ mutationKey,
669
+ initializeMutationRow(mutationEntry.mutation, mutationData.displayName, mutationEntry.proportion)
670
+ );
671
+ } else {
672
+ existingRow.proportions = updateProportions(
673
+ existingRow.proportions,
674
+ mutationData.displayName,
675
+ mutationEntry.proportion
676
+ );
677
+ mutationsToProportions.set(mutationKey, existingRow);
678
+ }
669
679
  }
670
680
  }
671
- return [...mutationsToProportions.entries()].map(([mutation, proportions]) => {
681
+ return [...mutationsToProportions.values()].map((row) => {
672
682
  return {
673
- mutation,
683
+ mutation: row.mutation,
674
684
  ...data.content.map((mutationData) => {
675
685
  return {
676
- [`${mutationData.displayName} prevalence`]: proportions[mutationData.displayName] || 0
686
+ [`${mutationData.displayName} prevalence`]: row.proportions[mutationData.displayName] || 0
677
687
  };
678
688
  }).reduce((acc, val) => ({ ...acc, ...val }), {})
679
689
  };
@@ -683,6 +693,17 @@ function getMutationComparisonTableData(data, proportionInterval) {
683
693
  )
684
694
  );
685
695
  }
696
+ function initializeMutationRow(mutation, displayName, proportion) {
697
+ return {
698
+ mutation,
699
+ proportions: {
700
+ [displayName]: proportion
701
+ }
702
+ };
703
+ }
704
+ function updateProportions(proportions, displayName, proportion) {
705
+ return { ...proportions, [displayName]: proportion };
706
+ }
686
707
  const tableStyle = {
687
708
  table: {
688
709
  fontSize: "12px"
@@ -717,49 +738,183 @@ const Table = ({ data, columns, pagination }) => {
717
738
  });
718
739
  return /* @__PURE__ */ u$1("div", { ref: wrapper3 });
719
740
  };
720
- const substitutionAndDeletionRegex = /(?:([A-Za-z0-9]+):)?([A-Za-z])(\d+)([A-Za-z]|-|\*)/;
721
- const sortSubstitutionsAndDeletions = (a2, b2) => {
722
- const aMatch = a2.match(substitutionAndDeletionRegex);
723
- const bMatch = b2.match(substitutionAndDeletionRegex);
724
- if (aMatch && bMatch) {
725
- if (aMatch[1] !== bMatch[1]) {
726
- return aMatch[1].localeCompare(bMatch[1]);
741
+ const substitutionRegex = /^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtReference>[A-Za-z])?(?<position>\d+)(?<substitutionValue>[A-Za-z.])?$/;
742
+ class Substitution {
743
+ constructor(segment, valueAtReference, substitutionValue, position) {
744
+ this.segment = segment;
745
+ this.valueAtReference = valueAtReference;
746
+ this.substitutionValue = substitutionValue;
747
+ this.position = position;
748
+ const segmentString = this.segment ? `${this.segment}:` : "";
749
+ const valueAtReferenceString = this.valueAtReference ? `${this.valueAtReference}` : "";
750
+ const substitutionValueString = this.substitutionValue ? `${this.substitutionValue}` : "";
751
+ this.code = `${segmentString}${valueAtReferenceString}${this.position}${substitutionValueString}`;
752
+ }
753
+ equals(other) {
754
+ if (!(other instanceof Substitution)) {
755
+ return false;
727
756
  }
728
- if (aMatch[3] !== bMatch[3]) {
729
- return parseInt(aMatch[3], 10) - parseInt(bMatch[3], 10);
757
+ return this.segment === other.segment && this.valueAtReference === other.valueAtReference && this.substitutionValue === other.substitutionValue && this.position === other.position;
758
+ }
759
+ toString() {
760
+ return this.code;
761
+ }
762
+ static parse(mutationStr) {
763
+ const match = mutationStr.match(substitutionRegex);
764
+ if (match === null || match.groups === void 0) {
765
+ return null;
730
766
  }
731
- return aMatch[4].localeCompare(bMatch[4]);
767
+ return new Substitution(
768
+ match.groups.segment,
769
+ match.groups.valueAtReference,
770
+ match.groups.substitutionValue,
771
+ parseInt(match.groups.position, 10)
772
+ );
773
+ }
774
+ }
775
+ const deletionRegex = /^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtReference>[A-Za-z])?(?<position>\d+)(-)$/;
776
+ class Deletion {
777
+ constructor(segment, valueAtReference, position) {
778
+ this.segment = segment;
779
+ this.valueAtReference = valueAtReference;
780
+ this.position = position;
781
+ const segmentString = this.segment ? `${this.segment}:` : "";
782
+ const valueAtReferenceString = this.valueAtReference ? `${this.valueAtReference}` : "";
783
+ this.code = `${segmentString}${valueAtReferenceString}${this.position}-`;
784
+ }
785
+ equals(other) {
786
+ if (!(other instanceof Deletion)) {
787
+ return false;
788
+ }
789
+ return this.segment === other.segment && this.valueAtReference === other.valueAtReference && this.position === other.position;
790
+ }
791
+ toString() {
792
+ return this.code;
793
+ }
794
+ static parse(mutationStr) {
795
+ const match = mutationStr.match(deletionRegex);
796
+ if (match === null || match.groups === void 0) {
797
+ return null;
798
+ }
799
+ return new Deletion(match.groups.segment, match.groups.valueAtReference, parseInt(match.groups.position, 10));
732
800
  }
733
- throw new Error(`Invalid substitution or deletion: ${a2} or ${b2}`);
801
+ }
802
+ const insertionRegexp = /^ins_((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<position>\d+):(?<insertedSymbols>(([A-Za-z?]|(\.\*))+))$/i;
803
+ class Insertion {
804
+ constructor(segment, position, insertedSymbols) {
805
+ this.segment = segment;
806
+ this.position = position;
807
+ this.insertedSymbols = insertedSymbols;
808
+ this.code = `ins_${this.segment ? `${this.segment}:` : ""}${this.position}:${this.insertedSymbols}`;
809
+ }
810
+ equals(other) {
811
+ if (!(other instanceof Insertion)) {
812
+ return false;
813
+ }
814
+ return this.segment === other.segment && this.insertedSymbols === other.insertedSymbols && this.position === other.position;
815
+ }
816
+ toString() {
817
+ return this.code;
818
+ }
819
+ static parse(mutationStr) {
820
+ const match = mutationStr.match(insertionRegexp);
821
+ if (match === null || match.groups === void 0) {
822
+ return null;
823
+ }
824
+ return new Insertion(match.groups.segment, parseInt(match.groups.position, 10), match.groups.insertedSymbols);
825
+ }
826
+ }
827
+ const bases = {
828
+ nucleotide: ["A", "C", "G", "T", "-"],
829
+ "amino acid": [
830
+ "I",
831
+ "L",
832
+ "V",
833
+ "F",
834
+ "M",
835
+ "C",
836
+ "A",
837
+ "G",
838
+ "P",
839
+ "T",
840
+ "S",
841
+ "Y",
842
+ "W",
843
+ "Q",
844
+ "N",
845
+ "H",
846
+ "E",
847
+ "D",
848
+ "K",
849
+ "R",
850
+ "-"
851
+ ]
852
+ };
853
+ const sortSubstitutionsAndDeletions = (a2, b2) => {
854
+ if (a2.segment !== b2.segment) {
855
+ compareSegments(a2.segment, b2.segment);
856
+ }
857
+ if (a2.position !== b2.position) {
858
+ return comparePositions(a2.position, b2.position);
859
+ }
860
+ const aIsDeletion = a2 instanceof Deletion;
861
+ const bIsDeletion = b2 instanceof Deletion;
862
+ if (aIsDeletion !== bIsDeletion) {
863
+ return aIsDeletion ? 1 : -1;
864
+ }
865
+ if (!aIsDeletion && !bIsDeletion) {
866
+ if (a2.substitutionValue !== b2.substitutionValue) {
867
+ return compareSubstitutionValues(a2.substitutionValue, b2.substitutionValue);
868
+ }
869
+ }
870
+ return 0;
871
+ };
872
+ const compareSegments = (a2, b2) => {
873
+ if (a2 === void 0) {
874
+ return -1;
875
+ }
876
+ if (b2 === void 0) {
877
+ return 1;
878
+ }
879
+ return a2.localeCompare(b2);
880
+ };
881
+ const comparePositions = (a2, b2) => {
882
+ return a2 - b2;
883
+ };
884
+ const compareSubstitutionValues = (a2, b2) => {
885
+ if (a2 === void 0) {
886
+ return -1;
887
+ }
888
+ if (b2 === void 0) {
889
+ return 1;
890
+ }
891
+ return a2.localeCompare(b2);
734
892
  };
735
893
  const formatProportion = (proportion) => {
736
894
  return `${(proportion * 100).toFixed(2)}%`;
737
895
  };
738
896
  const MutationComparisonTable = ({ data, proportionInterval }) => {
739
- const getHeaders = () => {
740
- return [
741
- {
742
- name: "Mutation",
743
- sort: {
744
- compare: (a2, b2) => {
745
- return sortSubstitutionsAndDeletions(a2, b2);
746
- }
747
- }
897
+ const headers = [
898
+ {
899
+ name: "Mutation",
900
+ sort: {
901
+ compare: sortSubstitutionsAndDeletions
748
902
  },
749
- {
750
- name: "Prevalence",
751
- columns: data.content.map((mutationData) => {
752
- return {
753
- name: mutationData.displayName,
754
- sort: true,
755
- formatter: (cell) => formatProportion(cell)
756
- };
757
- })
758
- }
759
- ];
760
- };
903
+ formatter: (cell) => cell.toString()
904
+ },
905
+ {
906
+ name: "Prevalence",
907
+ columns: data.content.map((mutationData) => {
908
+ return {
909
+ name: mutationData.displayName,
910
+ sort: true,
911
+ formatter: (cell) => formatProportion(cell)
912
+ };
913
+ })
914
+ }
915
+ ];
761
916
  const tableData = getMutationComparisonTableData(data, proportionInterval).map((row) => Object.values(row));
762
- return /* @__PURE__ */ u$1(Table, { data: tableData, columns: getHeaders(), pagination: true });
917
+ return /* @__PURE__ */ u$1(Table, { data: tableData, columns: headers, pagination: true });
763
918
  };
764
919
  const GsChart = ({ configuration }) => {
765
920
  const canvasRef = F(null);
@@ -821,6 +976,7 @@ const MutationComparisonVenn = ({
821
976
  type: "venn",
822
977
  data: sets,
823
978
  options: {
979
+ maintainAspectRatio: false,
824
980
  scales: {
825
981
  x: {
826
982
  ticks: {
@@ -862,128 +1018,16 @@ const MutationComparisonVenn = ({
862
1018
  }
863
1019
  }
864
1020
  }
865
- }),
866
- [sets]
867
- );
868
- if (data.content.length > 5) {
869
- return /* @__PURE__ */ u$1("div", { children: "Too many variants to display. Maximum are five. " });
870
- }
871
- return /* @__PURE__ */ u$1(Fragment, { children: [
872
- /* @__PURE__ */ u$1(GsChart, { configuration: config }),
873
- /* @__PURE__ */ u$1("div", { class: "flex flex-wrap break-words m-2", ref: divRef })
874
- ] });
875
- };
876
- const substitutionRegex = /^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtReference>[A-Za-z])?(?<position>\d+)(?<substitutionValue>[A-Za-z.])?$/;
877
- class Substitution {
878
- constructor(segment, valueAtReference, substitutionValue, position) {
879
- this.segment = segment;
880
- this.valueAtReference = valueAtReference;
881
- this.substitutionValue = substitutionValue;
882
- this.position = position;
883
- const segmentString = this.segment ? `${this.segment}:` : "";
884
- const valueAtReferenceString = this.valueAtReference ? `${this.valueAtReference}` : "";
885
- const substitutionValueString = this.substitutionValue ? `${this.substitutionValue}` : "";
886
- this.code = `${segmentString}${valueAtReferenceString}${this.position}${substitutionValueString}`;
887
- }
888
- equals(other) {
889
- if (!(other instanceof Substitution)) {
890
- return false;
891
- }
892
- return this.segment === other.segment && this.valueAtReference === other.valueAtReference && this.substitutionValue === other.substitutionValue && this.position === other.position;
893
- }
894
- toString() {
895
- return this.code;
896
- }
897
- static parse(mutationStr) {
898
- const match = mutationStr.match(substitutionRegex);
899
- if (match === null || match.groups === void 0) {
900
- return null;
901
- }
902
- return new Substitution(
903
- match.groups.segment,
904
- match.groups.valueAtReference,
905
- match.groups.substitutionValue,
906
- parseInt(match.groups.position, 10)
907
- );
908
- }
909
- }
910
- const deletionRegex = /^((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<valueAtReference>[A-Za-z])?(?<position>\d+)(-)$/;
911
- class Deletion {
912
- constructor(segment, valueAtReference, position) {
913
- this.segment = segment;
914
- this.valueAtReference = valueAtReference;
915
- this.position = position;
916
- const segmentString = this.segment ? `${this.segment}:` : "";
917
- const valueAtReferenceString = this.valueAtReference ? `${this.valueAtReference}` : "";
918
- this.code = `${segmentString}${valueAtReferenceString}${this.position}-`;
919
- }
920
- equals(other) {
921
- if (!(other instanceof Deletion)) {
922
- return false;
923
- }
924
- return this.segment === other.segment && this.valueAtReference === other.valueAtReference && this.position === other.position;
925
- }
926
- toString() {
927
- return this.code;
928
- }
929
- static parse(mutationStr) {
930
- const match = mutationStr.match(deletionRegex);
931
- if (match === null || match.groups === void 0) {
932
- return null;
933
- }
934
- return new Deletion(match.groups.segment, match.groups.valueAtReference, parseInt(match.groups.position, 10));
935
- }
936
- }
937
- const insertionRegexp = /^ins_((?<segment>[A-Za-z0-9_-]+)(?=:):)?(?<position>\d+):(?<insertedSymbols>(([A-Za-z?]|(\.\*))+))$/i;
938
- class Insertion {
939
- constructor(segment, position, insertedSymbols) {
940
- this.segment = segment;
941
- this.position = position;
942
- this.insertedSymbols = insertedSymbols;
943
- this.code = `ins_${this.segment ? `${this.segment}:` : ""}${this.position}:${this.insertedSymbols}`;
944
- }
945
- equals(other) {
946
- if (!(other instanceof Insertion)) {
947
- return false;
948
- }
949
- return this.segment === other.segment && this.insertedSymbols === other.insertedSymbols && this.position === other.position;
950
- }
951
- toString() {
952
- return this.code;
953
- }
954
- static parse(mutationStr) {
955
- const match = mutationStr.match(insertionRegexp);
956
- if (match === null || match.groups === void 0) {
957
- return null;
958
- }
959
- return new Insertion(match.groups.segment, parseInt(match.groups.position, 10), match.groups.insertedSymbols);
960
- }
961
- }
962
- const bases = {
963
- nucleotide: ["A", "C", "G", "T", "-"],
964
- "amino acid": [
965
- "I",
966
- "L",
967
- "V",
968
- "F",
969
- "M",
970
- "C",
971
- "A",
972
- "G",
973
- "P",
974
- "T",
975
- "S",
976
- "Y",
977
- "W",
978
- "Q",
979
- "N",
980
- "H",
981
- "E",
982
- "D",
983
- "K",
984
- "R",
985
- "-"
986
- ]
1021
+ }),
1022
+ [sets]
1023
+ );
1024
+ if (data.content.length > 5) {
1025
+ return /* @__PURE__ */ u$1("div", { children: "Too many variants to display. Maximum are five. " });
1026
+ }
1027
+ return /* @__PURE__ */ u$1("div", { className: "h-full flex flex-col", children: [
1028
+ /* @__PURE__ */ u$1("div", { className: "flex-1", children: /* @__PURE__ */ u$1(GsChart, { configuration: config }) }),
1029
+ /* @__PURE__ */ u$1("div", { class: "flex flex-wrap break-words m-2", ref: divRef })
1030
+ ] });
987
1031
  };
988
1032
  class FetchSubstitutionsOrDeletionsOperator {
989
1033
  constructor(filter, sequenceType, minProportion) {
@@ -1181,9 +1225,17 @@ const ErrorDisplay = ({ error }) => {
1181
1225
  ] });
1182
1226
  };
1183
1227
  const Headline = ({ heading, children }) => {
1184
- return /* @__PURE__ */ u$1(Fragment, { children: [
1185
- /* @__PURE__ */ u$1("h1", { children: heading }),
1186
- children
1228
+ const ref = F(null);
1229
+ const [h1Height, setH1Height] = p("2rem");
1230
+ _(() => {
1231
+ if (ref.current) {
1232
+ const h1Height2 = ref.current.getBoundingClientRect().height;
1233
+ setH1Height(`${h1Height2}px`);
1234
+ }
1235
+ }, []);
1236
+ return /* @__PURE__ */ u$1("div", { className: "h-full w-full", children: [
1237
+ /* @__PURE__ */ u$1("h1", { ref, children: heading }),
1238
+ /* @__PURE__ */ u$1("div", { style: { height: `calc(100% - ${h1Height})` }, children })
1187
1239
  ] });
1188
1240
  };
1189
1241
  const Info = ({ content, className }) => {
@@ -1379,30 +1431,51 @@ const ProportionSelectorDropdown = ({
1379
1431
  ) }) })
1380
1432
  ] });
1381
1433
  };
1434
+ const ResizeContainer = ({ children, size, defaultSize }) => {
1435
+ return /* @__PURE__ */ u$1("div", { style: extendByDefault(size, defaultSize), children });
1436
+ };
1437
+ const extendByDefault = (size, defaultSize) => {
1438
+ if (size === void 0) {
1439
+ return defaultSize;
1440
+ }
1441
+ return { ...defaultSize, ...size };
1442
+ };
1382
1443
  const Tabs = ({ tabs, toolbar }) => {
1383
1444
  const [activeTab, setActiveTab] = p(tabs[0].title);
1384
- const tabNames = tabs.map((tab) => tab.title).join(", ");
1385
- const tabElements = tabs.map((tab) => {
1386
- return /* @__PURE__ */ u$1(Fragment, { children: [
1387
- /* @__PURE__ */ u$1(
1388
- "input",
1389
- {
1390
- type: "radio",
1391
- name: tabNames,
1392
- role: "tab",
1393
- className: "tab",
1394
- "aria-label": tab.title,
1395
- checked: activeTab === tab.title,
1396
- onChange: () => setActiveTab(tab.title)
1397
- }
1398
- ),
1399
- /* @__PURE__ */ u$1("div", { role: "tabpanel", className: "tab-content bg-base-100 border-base-300 rounded-box p-1", children: tab.content })
1400
- ] }, tab.title);
1401
- });
1445
+ const [heightOfTabs, setHeightOfTabs] = p("3rem");
1446
+ const tabRef = F(null);
1447
+ _(() => {
1448
+ if (tabRef.current) {
1449
+ const heightOfTabs2 = tabRef.current.getBoundingClientRect().height;
1450
+ setHeightOfTabs(`${heightOfTabs2}px`);
1451
+ }
1452
+ }, []);
1453
+ const tabElements = /* @__PURE__ */ u$1("div", { className: "flex flex-row", children: tabs.map((tab) => {
1454
+ return /* @__PURE__ */ u$1(Fragment, { children: /* @__PURE__ */ u$1(
1455
+ "button",
1456
+ {
1457
+ className: `px-4 py-2 text-sm font-medium leading-5 transition-colors duration-150 ${activeTab === tab.title ? "border-b-2 border-gray-400" : "text-gray-600 hover:bg-gray-100 hover:text-gray-700"}`,
1458
+ onClick: () => {
1459
+ setActiveTab(tab.title);
1460
+ },
1461
+ children: tab.title
1462
+ }
1463
+ ) }, tab.title);
1464
+ }) });
1402
1465
  const toolbarElement = typeof toolbar === "function" ? toolbar(activeTab) : toolbar;
1403
- return /* @__PURE__ */ u$1("div", { role: "tablist", className: "tabs tabs-lifted", children: [
1404
- tabElements,
1405
- toolbar && /* @__PURE__ */ u$1("div", { className: "m-1 col-[9999]", children: toolbarElement })
1466
+ return /* @__PURE__ */ u$1("div", { className: "h-full w-full", children: [
1467
+ /* @__PURE__ */ u$1("div", { ref: tabRef, className: "flex flex-row justify-between", children: [
1468
+ tabElements,
1469
+ toolbar && /* @__PURE__ */ u$1("div", { className: "py-2", children: toolbarElement })
1470
+ ] }),
1471
+ /* @__PURE__ */ u$1(
1472
+ "div",
1473
+ {
1474
+ className: `p-2 border-2 border-gray-100 rounded-b-md rounded-tr-md ${activeTab === tabs[0].title ? "" : "rounded-tl-md"}`,
1475
+ style: { height: `calc(100% - ${heightOfTabs})` },
1476
+ children: tabs.map((tab) => /* @__PURE__ */ u$1("div", { className: "h-full overflow-auto", hidden: activeTab !== tab.title, children: tab.content }, tab.title))
1477
+ }
1478
+ )
1406
1479
  ] });
1407
1480
  };
1408
1481
  function useQuery(fetchDataCallback, dependencies = []) {
@@ -1426,7 +1499,12 @@ function useQuery(fetchDataCallback, dependencies = []) {
1426
1499
  }, [JSON.stringify(dependencies)]);
1427
1500
  return { data, error, isLoading };
1428
1501
  }
1429
- const MutationComparison = ({ variants, sequenceType, views }) => {
1502
+ const MutationComparison = ({
1503
+ variants,
1504
+ sequenceType,
1505
+ views,
1506
+ size
1507
+ }) => {
1430
1508
  const lapis = P(LapisUrlContext);
1431
1509
  const { data, error, isLoading } = useQuery(async () => {
1432
1510
  return queryMutationData(variants, sequenceType, lapis);
@@ -1441,7 +1519,7 @@ const MutationComparison = ({ variants, sequenceType, views }) => {
1441
1519
  if (data === null) {
1442
1520
  return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(NoDataDisplay, {}) });
1443
1521
  }
1444
- return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(MutationComparisonTabs, { data: data.mutationData, sequenceType, views }) });
1522
+ return /* @__PURE__ */ u$1(ResizeContainer, { size, defaultSize: { height: "700px", width: "100%" }, children: /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(MutationComparisonTabs, { data: data.mutationData, sequenceType, views }) }) });
1445
1523
  };
1446
1524
  const MutationComparisonTabs = ({ data, views, sequenceType }) => {
1447
1525
  const [proportionInterval, setProportionInterval] = p({ min: 0.5, max: 1 });
@@ -2032,108 +2110,6 @@ html {
2032
2110
  --bc: 27.8078% 0.029596 256.847952;
2033
2111
  }
2034
2112
 
2035
- @media (prefers-color-scheme: dark) {
2036
-
2037
- :root {
2038
- color-scheme: dark;
2039
- --in: 72.06% 0.191 231.6;
2040
- --su: 64.8% 0.150 160;
2041
- --wa: 84.71% 0.199 83.87;
2042
- --er: 71.76% 0.221 22.18;
2043
- --pc: 13.138% 0.0392 275.75;
2044
- --sc: 14.96% 0.052 342.55;
2045
- --ac: 14.902% 0.0334 183.61;
2046
- --inc: 0% 0 0;
2047
- --suc: 0% 0 0;
2048
- --wac: 0% 0 0;
2049
- --erc: 0% 0 0;
2050
- --rounded-box: 1rem;
2051
- --rounded-btn: 0.5rem;
2052
- --rounded-badge: 1.9rem;
2053
- --animation-btn: 0.25s;
2054
- --animation-input: .2s;
2055
- --btn-focus-scale: 0.95;
2056
- --border-btn: 1px;
2057
- --tab-border: 1px;
2058
- --tab-radius: 0.5rem;
2059
- --p: 65.69% 0.196 275.75;
2060
- --s: 74.8% 0.26 342.55;
2061
- --a: 74.51% 0.167 183.61;
2062
- --n: 31.3815% 0.021108 254.139175;
2063
- --nc: 74.6477% 0.0216 264.435964;
2064
- --b1: 25.3267% 0.015896 252.417568;
2065
- --b2: 23.2607% 0.013807 253.100675;
2066
- --b3: 21.1484% 0.01165 254.087939;
2067
- --bc: 74.6477% 0.0216 264.435964;
2068
- }
2069
- }
2070
-
2071
- [data-theme=light] {
2072
- color-scheme: light;
2073
- --in: 72.06% 0.191 231.6;
2074
- --su: 64.8% 0.150 160;
2075
- --wa: 84.71% 0.199 83.87;
2076
- --er: 71.76% 0.221 22.18;
2077
- --pc: 89.824% 0.06192 275.75;
2078
- --ac: 15.352% 0.0368 183.61;
2079
- --inc: 0% 0 0;
2080
- --suc: 0% 0 0;
2081
- --wac: 0% 0 0;
2082
- --erc: 0% 0 0;
2083
- --rounded-box: 1rem;
2084
- --rounded-btn: 0.5rem;
2085
- --rounded-badge: 1.9rem;
2086
- --animation-btn: 0.25s;
2087
- --animation-input: .2s;
2088
- --btn-focus-scale: 0.95;
2089
- --border-btn: 1px;
2090
- --tab-border: 1px;
2091
- --tab-radius: 0.5rem;
2092
- --p: 49.12% 0.3096 275.75;
2093
- --s: 69.71% 0.329 342.55;
2094
- --sc: 98.71% 0.0106 342.55;
2095
- --a: 76.76% 0.184 183.61;
2096
- --n: 32.1785% 0.02476 255.701624;
2097
- --nc: 89.4994% 0.011585 252.096176;
2098
- --b1: 100% 0 0;
2099
- --b2: 96.1151% 0 0;
2100
- --b3: 92.4169% 0.00108 197.137559;
2101
- --bc: 27.8078% 0.029596 256.847952;
2102
- }
2103
-
2104
- [data-theme=dark] {
2105
- color-scheme: dark;
2106
- --in: 72.06% 0.191 231.6;
2107
- --su: 64.8% 0.150 160;
2108
- --wa: 84.71% 0.199 83.87;
2109
- --er: 71.76% 0.221 22.18;
2110
- --pc: 13.138% 0.0392 275.75;
2111
- --sc: 14.96% 0.052 342.55;
2112
- --ac: 14.902% 0.0334 183.61;
2113
- --inc: 0% 0 0;
2114
- --suc: 0% 0 0;
2115
- --wac: 0% 0 0;
2116
- --erc: 0% 0 0;
2117
- --rounded-box: 1rem;
2118
- --rounded-btn: 0.5rem;
2119
- --rounded-badge: 1.9rem;
2120
- --animation-btn: 0.25s;
2121
- --animation-input: .2s;
2122
- --btn-focus-scale: 0.95;
2123
- --border-btn: 1px;
2124
- --tab-border: 1px;
2125
- --tab-radius: 0.5rem;
2126
- --p: 65.69% 0.196 275.75;
2127
- --s: 74.8% 0.26 342.55;
2128
- --a: 74.51% 0.167 183.61;
2129
- --n: 31.3815% 0.021108 254.139175;
2130
- --nc: 74.6477% 0.0216 264.435964;
2131
- --b1: 25.3267% 0.015896 252.417568;
2132
- --b2: 23.2607% 0.013807 253.100675;
2133
- --b3: 21.1484% 0.01165 254.087939;
2134
- --bc: 74.6477% 0.0216 264.435964;
2135
- }
2136
-
2137
2113
  *, ::before, ::after {
2138
2114
  --tw-border-spacing-x: 0;
2139
2115
  --tw-border-spacing-y: 0;
@@ -2241,6 +2217,39 @@ html {
2241
2217
  --tw-contain-paint: ;
2242
2218
  --tw-contain-style: ;
2243
2219
  }
2220
+ .container {
2221
+ width: 100%;
2222
+ }
2223
+ @media (min-width: 640px) {
2224
+
2225
+ .container {
2226
+ max-width: 640px;
2227
+ }
2228
+ }
2229
+ @media (min-width: 768px) {
2230
+
2231
+ .container {
2232
+ max-width: 768px;
2233
+ }
2234
+ }
2235
+ @media (min-width: 1024px) {
2236
+
2237
+ .container {
2238
+ max-width: 1024px;
2239
+ }
2240
+ }
2241
+ @media (min-width: 1280px) {
2242
+
2243
+ .container {
2244
+ max-width: 1280px;
2245
+ }
2246
+ }
2247
+ @media (min-width: 1536px) {
2248
+
2249
+ .container {
2250
+ max-width: 1536px;
2251
+ }
2252
+ }
2244
2253
  .avatar.placeholder > div {
2245
2254
  display: flex;
2246
2255
  align-items: center;
@@ -2832,19 +2841,6 @@ html {
2832
2841
  cursor: default;
2833
2842
  grid-column-start: span 9999;
2834
2843
  }
2835
- .tab-content {
2836
- grid-column-start: 1;
2837
- grid-column-end: span 9999;
2838
- grid-row-start: 2;
2839
- margin-top: calc(var(--tab-border) * -1);
2840
- display: none;
2841
- border-color: transparent;
2842
- border-width: var(--tab-border, 0);
2843
- }
2844
- :checked + .tab-content:nth-child(2),
2845
- .tab-active + .tab-content:nth-child(2) {
2846
- border-start-start-radius: 0px;
2847
- }
2848
2844
  input.tab:checked + .tab-content,
2849
2845
  .tab-active + .tab-content {
2850
2846
  display: block;
@@ -2992,6 +2988,14 @@ input.tab:checked + .tab-content,
2992
2988
  outline-offset: 2px;
2993
2989
  outline-color: var(--fallback-bc,oklch(var(--bc)/1));
2994
2990
  }
2991
+ .checkbox:disabled {
2992
+ border-width: 0px;
2993
+ cursor: not-allowed;
2994
+ border-color: transparent;
2995
+ --tw-bg-opacity: 1;
2996
+ background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
2997
+ opacity: 0.2;
2998
+ }
2995
2999
  .checkbox:checked,
2996
3000
  .checkbox[aria-checked="true"] {
2997
3001
  background-repeat: no-repeat;
@@ -3018,13 +3022,6 @@ input.tab:checked + .tab-content,
3018
3022
  linear-gradient(-90deg, transparent 80%, var(--chkbg) 80%),
3019
3023
  linear-gradient(0deg, var(--chkbg) 43%, var(--chkfg) 43%, var(--chkfg) 57%, var(--chkbg) 57%);
3020
3024
  }
3021
- .checkbox:disabled {
3022
- cursor: not-allowed;
3023
- border-color: transparent;
3024
- --tw-bg-opacity: 1;
3025
- background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
3026
- opacity: 0.2;
3027
- }
3028
3025
  @keyframes checkmark {
3029
3026
 
3030
3027
  0% {
@@ -3080,7 +3077,8 @@ input.tab:checked + .tab-content,
3080
3077
  border-color: var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)));
3081
3078
  outline-color: var(--fallback-er,oklch(var(--er)/1));
3082
3079
  }
3083
- .input-disabled,
3080
+ .input:has(> input[disabled]),
3081
+ .input-disabled,
3084
3082
  .input:disabled,
3085
3083
  .input[disabled] {
3086
3084
  cursor: not-allowed;
@@ -3090,16 +3088,20 @@ input.tab:checked + .tab-content,
3090
3088
  background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
3091
3089
  color: var(--fallback-bc,oklch(var(--bc)/0.4));
3092
3090
  }
3093
- .input-disabled::-moz-placeholder, .input:disabled::-moz-placeholder, .input[disabled]::-moz-placeholder {
3091
+ .input:has(> input[disabled])::-moz-placeholder, .input-disabled::-moz-placeholder, .input:disabled::-moz-placeholder, .input[disabled]::-moz-placeholder {
3094
3092
  color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));
3095
3093
  --tw-placeholder-opacity: 0.2;
3096
3094
  }
3097
- .input-disabled::placeholder,
3095
+ .input:has(> input[disabled])::placeholder,
3096
+ .input-disabled::placeholder,
3098
3097
  .input:disabled::placeholder,
3099
3098
  .input[disabled]::placeholder {
3100
3099
  color: var(--fallback-bc,oklch(var(--bc)/var(--tw-placeholder-opacity)));
3101
3100
  --tw-placeholder-opacity: 0.2;
3102
3101
  }
3102
+ .input:has(> input[disabled]) > input[disabled] {
3103
+ cursor: not-allowed;
3104
+ }
3103
3105
  .input::-webkit-date-and-time-value {
3104
3106
  text-align: inherit;
3105
3107
  }
@@ -3126,6 +3128,13 @@ input.tab:checked + .tab-content,
3126
3128
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E.spinner_V8m1%7Btransform-origin:center;animation:spinner_zKoa 2s linear infinite%7D.spinner_V8m1 circle%7Bstroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite%7D%40keyframes spinner_zKoa%7B100%25%7Btransform:rotate(360deg)%7D%7D%40keyframes spinner_YpZS%7B0%25%7Bstroke-dasharray:0 150;stroke-dashoffset:0%7D47.5%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-16%7D95%25%2C100%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-59%7D%7D%3C%2Fstyle%3E%3Cg class='spinner_V8m1'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3E%3C%2Fcircle%3E%3C%2Fg%3E%3C%2Fsvg%3E");
3127
3129
  mask-image: url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E.spinner_V8m1%7Btransform-origin:center;animation:spinner_zKoa 2s linear infinite%7D.spinner_V8m1 circle%7Bstroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite%7D%40keyframes spinner_zKoa%7B100%25%7Btransform:rotate(360deg)%7D%7D%40keyframes spinner_YpZS%7B0%25%7Bstroke-dasharray:0 150;stroke-dashoffset:0%7D47.5%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-16%7D95%25%2C100%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-59%7D%7D%3C%2Fstyle%3E%3Cg class='spinner_V8m1'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3E%3C%2Fcircle%3E%3C%2Fg%3E%3C%2Fsvg%3E");
3128
3130
  }
3131
+ .loading-spinner {
3132
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E.spinner_V8m1%7Btransform-origin:center;animation:spinner_zKoa 2s linear infinite%7D.spinner_V8m1 circle%7Bstroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite%7D%40keyframes spinner_zKoa%7B100%25%7Btransform:rotate(360deg)%7D%7D%40keyframes spinner_YpZS%7B0%25%7Bstroke-dasharray:0 150;stroke-dashoffset:0%7D47.5%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-16%7D95%25%2C100%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-59%7D%7D%3C%2Fstyle%3E%3Cg class='spinner_V8m1'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3E%3C%2Fcircle%3E%3C%2Fg%3E%3C%2Fsvg%3E");
3133
+ mask-image: url("data:image/svg+xml,%3Csvg width='24' height='24' stroke='%23000' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cstyle%3E.spinner_V8m1%7Btransform-origin:center;animation:spinner_zKoa 2s linear infinite%7D.spinner_V8m1 circle%7Bstroke-linecap:round;animation:spinner_YpZS 1.5s ease-out infinite%7D%40keyframes spinner_zKoa%7B100%25%7Btransform:rotate(360deg)%7D%7D%40keyframes spinner_YpZS%7B0%25%7Bstroke-dasharray:0 150;stroke-dashoffset:0%7D47.5%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-16%7D95%25%2C100%25%7Bstroke-dasharray:42 150;stroke-dashoffset:-59%7D%7D%3C%2Fstyle%3E%3Cg class='spinner_V8m1'%3E%3Ccircle cx='12' cy='12' r='9.5' fill='none' stroke-width='3'%3E%3C%2Fcircle%3E%3C%2Fg%3E%3C%2Fsvg%3E");
3134
+ }
3135
+ .loading-md {
3136
+ width: 1.5rem;
3137
+ }
3129
3138
  :where(.menu li:empty) {
3130
3139
  --tw-bg-opacity: 1;
3131
3140
  background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity)));
@@ -3882,12 +3891,6 @@ input.tab:checked + .tab-content,
3882
3891
  .z-\\[1\\] {
3883
3892
  z-index: 1;
3884
3893
  }
3885
- .col-\\[9999\\] {
3886
- grid-column: 9999;
3887
- }
3888
- .m-1 {
3889
- margin: 0.25rem;
3890
- }
3891
3894
  .m-2 {
3892
3895
  margin: 0.5rem;
3893
3896
  }
@@ -3933,8 +3936,11 @@ input.tab:checked + .tab-content,
3933
3936
  .grid {
3934
3937
  display: grid;
3935
3938
  }
3936
- .w-11\\/12 {
3937
- width: 91.666667%;
3939
+ .hidden {
3940
+ display: none;
3941
+ }
3942
+ .h-full {
3943
+ height: 100%;
3938
3944
  }
3939
3945
  .w-16 {
3940
3946
  width: 4rem;
@@ -3957,6 +3963,9 @@ input.tab:checked + .tab-content,
3957
3963
  .max-w-screen-lg {
3958
3964
  max-width: 1024px;
3959
3965
  }
3966
+ .flex-1 {
3967
+ flex: 1 1 0%;
3968
+ }
3960
3969
  .grow {
3961
3970
  flex-grow: 1;
3962
3971
  }
@@ -3978,12 +3987,18 @@ input.tab:checked + .tab-content,
3978
3987
  .justify-center {
3979
3988
  justify-content: center;
3980
3989
  }
3990
+ .justify-between {
3991
+ justify-content: space-between;
3992
+ }
3981
3993
  .gap-1 {
3982
3994
  gap: 0.25rem;
3983
3995
  }
3984
3996
  .gap-2 {
3985
3997
  gap: 0.5rem;
3986
3998
  }
3999
+ .overflow-auto {
4000
+ overflow: auto;
4001
+ }
3987
4002
  .whitespace-nowrap {
3988
4003
  white-space: nowrap;
3989
4004
  }
@@ -4005,24 +4020,41 @@ input.tab:checked + .tab-content,
4005
4020
  .rounded-none {
4006
4021
  border-radius: 0px;
4007
4022
  }
4023
+ .rounded-b-md {
4024
+ border-bottom-right-radius: 0.375rem;
4025
+ border-bottom-left-radius: 0.375rem;
4026
+ }
4027
+ .rounded-tl-md {
4028
+ border-top-left-radius: 0.375rem;
4029
+ }
4030
+ .rounded-tr-md {
4031
+ border-top-right-radius: 0.375rem;
4032
+ }
4008
4033
  .border {
4009
4034
  border-width: 1px;
4010
4035
  }
4011
4036
  .border-2 {
4012
4037
  border-width: 2px;
4013
4038
  }
4014
- .border-base-300 {
4015
- --tw-border-opacity: 1;
4016
- border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity)));
4039
+ .border-b-2 {
4040
+ border-bottom-width: 2px;
4017
4041
  }
4018
4042
  .border-error {
4019
4043
  --tw-border-opacity: 1;
4020
4044
  border-color: var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)));
4021
4045
  }
4046
+ .border-gray-100 {
4047
+ --tw-border-opacity: 1;
4048
+ border-color: rgb(243 244 246 / var(--tw-border-opacity));
4049
+ }
4022
4050
  .border-gray-300 {
4023
4051
  --tw-border-opacity: 1;
4024
4052
  border-color: rgb(209 213 219 / var(--tw-border-opacity));
4025
4053
  }
4054
+ .border-gray-400 {
4055
+ --tw-border-opacity: 1;
4056
+ border-color: rgb(156 163 175 / var(--tw-border-opacity));
4057
+ }
4026
4058
  .bg-base-100 {
4027
4059
  --tw-bg-opacity: 1;
4028
4060
  background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
@@ -4035,9 +4067,6 @@ input.tab:checked + .tab-content,
4035
4067
  --tw-bg-opacity: 1;
4036
4068
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
4037
4069
  }
4038
- .p-1 {
4039
- padding: 0.25rem;
4040
- }
4041
4070
  .p-2 {
4042
4071
  padding: 0.5rem;
4043
4072
  }
@@ -4065,13 +4094,39 @@ input.tab:checked + .tab-content,
4065
4094
  padding-top: 4rem;
4066
4095
  padding-bottom: 4rem;
4067
4096
  }
4097
+ .py-2 {
4098
+ padding-top: 0.5rem;
4099
+ padding-bottom: 0.5rem;
4100
+ }
4101
+ .text-lg {
4102
+ font-size: 1.125rem;
4103
+ line-height: 1.75rem;
4104
+ }
4105
+ .text-sm {
4106
+ font-size: 0.875rem;
4107
+ line-height: 1.25rem;
4108
+ }
4109
+ .text-xl {
4110
+ font-size: 1.25rem;
4111
+ line-height: 1.75rem;
4112
+ }
4068
4113
  .text-xs {
4069
4114
  font-size: 0.75rem;
4070
4115
  line-height: 1rem;
4071
4116
  }
4117
+ .font-bold {
4118
+ font-weight: 700;
4119
+ }
4072
4120
  .font-medium {
4073
4121
  font-weight: 500;
4074
4122
  }
4123
+ .leading-5 {
4124
+ line-height: 1.25rem;
4125
+ }
4126
+ .text-gray-600 {
4127
+ --tw-text-opacity: 1;
4128
+ color: rgb(75 85 99 / var(--tw-text-opacity));
4129
+ }
4075
4130
  .shadow {
4076
4131
  --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
4077
4132
  --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
@@ -4079,6 +4134,22 @@ input.tab:checked + .tab-content,
4079
4134
  }
4080
4135
  .filter {
4081
4136
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
4137
+ }
4138
+ .transition-colors {
4139
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
4140
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
4141
+ transition-duration: 150ms;
4142
+ }
4143
+ .duration-150 {
4144
+ transition-duration: 150ms;
4145
+ }
4146
+ .hover\\:bg-gray-100:hover {
4147
+ --tw-bg-opacity: 1;
4148
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity));
4149
+ }
4150
+ .hover\\:text-gray-700:hover {
4151
+ --tw-text-opacity: 1;
4152
+ color: rgb(55 65 81 / var(--tw-text-opacity));
4082
4153
  }`;
4083
4154
  var __defProp$9 = Object.defineProperty;
4084
4155
  var __getOwnPropDesc$9 = Object.getOwnPropertyDescriptor;
@@ -4093,7 +4164,7 @@ var __decorateClass$9 = (decorators, target, key, kind) => {
4093
4164
  };
4094
4165
  const tailwindElementCss = unsafeCSS(tailwindStyle);
4095
4166
  const minMaxPercentSliderElementCss = unsafeCSS(minMaxPercentSliderCss);
4096
- const _PreactLitAdapter = class _PreactLitAdapter extends b {
4167
+ const _PreactLitAdapter = class _PreactLitAdapter extends ReactiveElement {
4097
4168
  constructor() {
4098
4169
  super(...arguments);
4099
4170
  this.lapis = "";
@@ -4103,7 +4174,6 @@ const _PreactLitAdapter = class _PreactLitAdapter extends b {
4103
4174
  };
4104
4175
  }
4105
4176
  update(changedProperties) {
4106
- console.log("this.lapis", this.lapis);
4107
4177
  const vdom = /* @__PURE__ */ u$1(LapisUrlContext.Provider, { value: this.lapis, children: /* @__PURE__ */ u$1(ReferenceGenomeContext.Provider, { value: this.referenceGenome, children: this.render() }) });
4108
4178
  super.update(changedProperties);
4109
4179
  render(vdom, this.renderRoot);
@@ -4139,9 +4209,18 @@ let MutationComparisonComponent = class extends PreactLitAdapterWithGridJsStyles
4139
4209
  this.variants = [];
4140
4210
  this.sequenceType = "nucleotide";
4141
4211
  this.views = ["table"];
4212
+ this.size = void 0;
4142
4213
  }
4143
4214
  render() {
4144
- return /* @__PURE__ */ u$1(MutationComparison, { variants: this.variants, sequenceType: this.sequenceType, views: this.views });
4215
+ return /* @__PURE__ */ u$1(
4216
+ MutationComparison,
4217
+ {
4218
+ variants: this.variants,
4219
+ sequenceType: this.sequenceType,
4220
+ views: this.views,
4221
+ size: this.size
4222
+ }
4223
+ );
4145
4224
  }
4146
4225
  };
4147
4226
  __decorateClass$8([
@@ -4153,13 +4232,16 @@ __decorateClass$8([
4153
4232
  __decorateClass$8([
4154
4233
  n2({ type: Array })
4155
4234
  ], MutationComparisonComponent.prototype, "views", 2);
4235
+ __decorateClass$8([
4236
+ n2({ type: Object })
4237
+ ], MutationComparisonComponent.prototype, "size", 2);
4156
4238
  MutationComparisonComponent = __decorateClass$8([
4157
4239
  t$2("gs-mutation-comparison-component")
4158
4240
  ], MutationComparisonComponent);
4159
4241
  function getInsertionsTableData(data) {
4160
4242
  return data.map((mutationEntry) => {
4161
4243
  return {
4162
- insertion: mutationEntry.mutation.toString(),
4244
+ insertion: mutationEntry.mutation,
4163
4245
  count: mutationEntry.count
4164
4246
  };
4165
4247
  });
@@ -4170,7 +4252,7 @@ function getMutationsTableData(data, proportionInterval) {
4170
4252
  };
4171
4253
  return data.filter(byProportion2).map((mutationEntry) => {
4172
4254
  return {
4173
- mutation: mutationEntry.mutation.toString(),
4255
+ mutation: mutationEntry.mutation,
4174
4256
  type: mutationEntry.type,
4175
4257
  count: mutationEntry.count,
4176
4258
  proportion: mutationEntry.proportion
@@ -4301,22 +4383,13 @@ const MutationsGrid = ({ data, sequenceType, proportionInterval }) => {
4301
4383
  return /* @__PURE__ */ u$1(Table, { data: tableData, columns: getHeaders(), pagination: true });
4302
4384
  };
4303
4385
  const sortInsertions = (a2, b2) => {
4304
- const insertionA = Insertion.parse(a2);
4305
- const insertionB = Insertion.parse(b2);
4306
- if (insertionA && insertionB) {
4307
- const segmentA = insertionA.segment;
4308
- const segmentB = insertionB.segment;
4309
- if (segmentA !== void 0 && segmentB !== void 0 && segmentA !== segmentB) {
4310
- return segmentA.localeCompare(segmentB);
4311
- }
4312
- const positionA = insertionA.position;
4313
- const positionB = insertionB.position;
4314
- if (positionA !== positionB) {
4315
- return positionA - positionB;
4316
- }
4317
- return insertionA.insertedSymbols.localeCompare(insertionB.insertedSymbols);
4386
+ if (a2.segment !== b2.segment) {
4387
+ return compareSegments(a2.segment, b2.segment);
4388
+ }
4389
+ if (a2.position !== b2.position) {
4390
+ return comparePositions(a2.position, b2.position);
4318
4391
  }
4319
- throw new Error(`Invalid insertion: ${a2} or ${b2}`);
4392
+ return a2.insertedSymbols.localeCompare(b2.insertedSymbols);
4320
4393
  };
4321
4394
  const InsertionsTable = ({ data }) => {
4322
4395
  const getHeaders = () => {
@@ -4327,7 +4400,8 @@ const InsertionsTable = ({ data }) => {
4327
4400
  compare: (a2, b2) => {
4328
4401
  return sortInsertions(a2, b2);
4329
4402
  }
4330
- }
4403
+ },
4404
+ formatter: (cell) => cell.toString()
4331
4405
  },
4332
4406
  {
4333
4407
  name: "Count",
@@ -4347,7 +4421,8 @@ const MutationsTable = ({ data, proportionInterval }) => {
4347
4421
  compare: (a2, b2) => {
4348
4422
  return sortSubstitutionsAndDeletions(a2, b2);
4349
4423
  }
4350
- }
4424
+ },
4425
+ formatter: (cell) => cell.toString()
4351
4426
  },
4352
4427
  {
4353
4428
  name: "Type",
@@ -4421,7 +4496,7 @@ function filterMutationsData(data, displayedSegments, displayedMutationTypes) {
4421
4496
  gridData: filteredSubstitutionsOrDeletions
4422
4497
  };
4423
4498
  }
4424
- const Mutations = ({ variant, sequenceType, views }) => {
4499
+ const Mutations = ({ variant, sequenceType, views, size }) => {
4425
4500
  const lapis = P(LapisUrlContext);
4426
4501
  const { data, error, isLoading } = useQuery(async () => {
4427
4502
  return queryMutationsData(variant, sequenceType, lapis);
@@ -4436,7 +4511,7 @@ const Mutations = ({ variant, sequenceType, views }) => {
4436
4511
  if (data === null) {
4437
4512
  return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(NoDataDisplay, {}) });
4438
4513
  }
4439
- return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(MutationsTabs, { mutationsData: data, sequenceType, views }) });
4514
+ return /* @__PURE__ */ u$1(ResizeContainer, { size, defaultSize: { height: "700px", width: "100%" }, children: /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(MutationsTabs, { mutationsData: data, sequenceType, views }) }) });
4440
4515
  };
4441
4516
  const MutationsTabs = ({ mutationsData, sequenceType, views }) => {
4442
4517
  const [proportionInterval, setProportionInterval] = p({ min: 0.05, max: 1 });
@@ -4530,7 +4605,12 @@ const Toolbar$2 = ({
4530
4605
  CsvDownloadButton,
4531
4606
  {
4532
4607
  className: "mx-1 btn btn-xs",
4533
- getData: () => getInsertionsTableData(filteredData.insertions),
4608
+ getData: () => getInsertionsTableData(filteredData.insertions).map((row) => {
4609
+ return {
4610
+ insertion: row.insertion.toString(),
4611
+ count: row.count
4612
+ };
4613
+ }),
4534
4614
  filename: "insertions.csv"
4535
4615
  }
4536
4616
  ),
@@ -4554,9 +4634,10 @@ let MutationsComponent = class extends PreactLitAdapterWithGridJsStyles {
4554
4634
  this.variant = { displayName: "" };
4555
4635
  this.sequenceType = "nucleotide";
4556
4636
  this.views = ["table", "grid"];
4637
+ this.size = void 0;
4557
4638
  }
4558
4639
  render() {
4559
- return /* @__PURE__ */ u$1(Mutations, { variant: this.variant, sequenceType: this.sequenceType, views: this.views });
4640
+ return /* @__PURE__ */ u$1(Mutations, { variant: this.variant, sequenceType: this.sequenceType, views: this.views, size: this.size });
4560
4641
  }
4561
4642
  };
4562
4643
  __decorateClass$7([
@@ -4568,6 +4649,9 @@ __decorateClass$7([
4568
4649
  __decorateClass$7([
4569
4650
  n2({ type: Array })
4570
4651
  ], MutationsComponent.prototype, "views", 2);
4652
+ __decorateClass$7([
4653
+ n2({ type: Object })
4654
+ ], MutationsComponent.prototype, "size", 2);
4571
4655
  MutationsComponent = __decorateClass$7([
4572
4656
  t$2("gs-mutations-component")
4573
4657
  ], MutationsComponent);
@@ -4680,6 +4764,7 @@ const PrevalenceOverTimeBarChart = ({
4680
4764
  datasets: data.map((graphData, index) => datasets$1(graphData, index, confidenceIntervalMethod))
4681
4765
  },
4682
4766
  options: {
4767
+ maintainAspectRatio: false,
4683
4768
  animation: false,
4684
4769
  scales: {
4685
4770
  y: getYAxisScale(yAxisScaleType)
@@ -5633,6 +5718,7 @@ const PrevalenceOverTimeBubbleChart = ({ data, yAxisScaleType }) => {
5633
5718
  },
5634
5719
  options: {
5635
5720
  animation: false,
5721
+ maintainAspectRatio: false,
5636
5722
  scales: {
5637
5723
  x: {
5638
5724
  ticks: {
@@ -5690,6 +5776,7 @@ const PrevalenceOverTimeLineChart = ({
5690
5776
  },
5691
5777
  options: {
5692
5778
  animation: false,
5779
+ maintainAspectRatio: false,
5693
5780
  scales: {
5694
5781
  y: getYAxisScale(yAxisScaleType)
5695
5782
  },
@@ -6106,7 +6193,8 @@ const PrevalenceOverTime = ({
6106
6193
  granularity,
6107
6194
  smoothingWindow,
6108
6195
  views,
6109
- confidenceIntervalMethods
6196
+ confidenceIntervalMethods,
6197
+ size
6110
6198
  }) => {
6111
6199
  const lapis = P(LapisUrlContext);
6112
6200
  const { data, error, isLoading } = useQuery(
@@ -6123,7 +6211,7 @@ const PrevalenceOverTime = ({
6123
6211
  if (data === null) {
6124
6212
  return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(NoDataDisplay, {}) });
6125
6213
  }
6126
- return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(
6214
+ return /* @__PURE__ */ u$1(ResizeContainer, { size, defaultSize: { height: "600px", width: "100%" }, children: /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(
6127
6215
  PrevalenceOverTimeTabs,
6128
6216
  {
6129
6217
  views,
@@ -6131,7 +6219,7 @@ const PrevalenceOverTime = ({
6131
6219
  granularity,
6132
6220
  confidenceIntervalMethods
6133
6221
  }
6134
- ) });
6222
+ ) }) });
6135
6223
  };
6136
6224
  const PrevalenceOverTimeTabs = ({
6137
6225
  views,
@@ -6175,7 +6263,10 @@ const PrevalenceOverTimeTabs = ({
6175
6263
  content: /* @__PURE__ */ u$1(PrevalenceOverTimeBubbleChart, { data, yAxisScaleType })
6176
6264
  };
6177
6265
  case "table":
6178
- return { title: "Table", content: /* @__PURE__ */ u$1(PrevalenceOverTimeTable, { data, granularity }) };
6266
+ return {
6267
+ title: "Table",
6268
+ content: /* @__PURE__ */ u$1(PrevalenceOverTimeTable, { data, granularity })
6269
+ };
6179
6270
  }
6180
6271
  };
6181
6272
  const tabs = views.map((view) => getTab(view));
@@ -6245,6 +6336,7 @@ let PrevalenceOverTimeComponent = class extends PreactLitAdapterWithGridJsStyles
6245
6336
  this.smoothingWindow = 0;
6246
6337
  this.views = ["bar", "line", "bubble", "table"];
6247
6338
  this.confidenceIntervalMethods = ["wilson"];
6339
+ this.size = void 0;
6248
6340
  }
6249
6341
  render() {
6250
6342
  return /* @__PURE__ */ u$1(
@@ -6255,7 +6347,8 @@ let PrevalenceOverTimeComponent = class extends PreactLitAdapterWithGridJsStyles
6255
6347
  granularity: this.granularity,
6256
6348
  smoothingWindow: this.smoothingWindow,
6257
6349
  views: this.views,
6258
- confidenceIntervalMethods: this.confidenceIntervalMethods
6350
+ confidenceIntervalMethods: this.confidenceIntervalMethods,
6351
+ size: this.size
6259
6352
  }
6260
6353
  );
6261
6354
  }
@@ -6278,6 +6371,9 @@ __decorateClass$6([
6278
6371
  __decorateClass$6([
6279
6372
  n2({ type: Array })
6280
6373
  ], PrevalenceOverTimeComponent.prototype, "confidenceIntervalMethods", 2);
6374
+ __decorateClass$6([
6375
+ n2({ type: Object })
6376
+ ], PrevalenceOverTimeComponent.prototype, "size", 2);
6281
6377
  PrevalenceOverTimeComponent = __decorateClass$6([
6282
6378
  t$2("gs-prevalence-over-time")
6283
6379
  ], PrevalenceOverTimeComponent);
@@ -6290,6 +6386,7 @@ const RelativeGrowthAdvantageChart = ({ data, yAxisScaleType }) => {
6290
6386
  datasets: datasets(data)
6291
6387
  },
6292
6388
  options: {
6389
+ maintainAspectRatio: false,
6293
6390
  animation: false,
6294
6391
  scales: {
6295
6392
  y: getYAxisScale(yAxisScaleType)
@@ -6302,9 +6399,9 @@ const RelativeGrowthAdvantageChart = ({ data, yAxisScaleType }) => {
6302
6399
  }
6303
6400
  }
6304
6401
  };
6305
- return /* @__PURE__ */ u$1(Fragment, { children: [
6306
- /* @__PURE__ */ u$1(GsChart, { configuration: config }),
6307
- /* @__PURE__ */ u$1("div", { children: [
6402
+ return /* @__PURE__ */ u$1("div", { className: "flex flex-col h-full", children: [
6403
+ /* @__PURE__ */ u$1("div", { className: "flex-1", children: /* @__PURE__ */ u$1(GsChart, { configuration: config }) }),
6404
+ /* @__PURE__ */ u$1("p", { children: [
6308
6405
  "Advantage: ",
6309
6406
  (data.params.fd.value * 100).toFixed(2),
6310
6407
  "% (",
@@ -6469,7 +6566,8 @@ const RelativeGrowthAdvantage = ({
6469
6566
  numerator,
6470
6567
  denominator,
6471
6568
  generationTime,
6472
- views
6569
+ views,
6570
+ size
6473
6571
  }) => {
6474
6572
  const lapis = P(LapisUrlContext);
6475
6573
  const [yAxisScaleType, setYAxisScaleType] = p("linear");
@@ -6487,7 +6585,7 @@ const RelativeGrowthAdvantage = ({
6487
6585
  if (data === null) {
6488
6586
  return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(NoDataDisplay, {}) });
6489
6587
  }
6490
- return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(
6588
+ return /* @__PURE__ */ u$1(ResizeContainer, { size, defaultSize: { height: "700px", width: "100%" }, children: /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(
6491
6589
  RelativeGrowthAdvantageTabs,
6492
6590
  {
6493
6591
  data,
@@ -6495,7 +6593,7 @@ const RelativeGrowthAdvantage = ({
6495
6593
  setYAxisScaleType,
6496
6594
  views
6497
6595
  }
6498
- ) });
6596
+ ) }) });
6499
6597
  };
6500
6598
  const RelativeGrowthAdvantageTabs = ({
6501
6599
  data,
@@ -6553,6 +6651,7 @@ let RelativeGrowthAdvantageComponent = class extends PreactLitAdapter {
6553
6651
  this.denominator = {};
6554
6652
  this.generationTime = 7;
6555
6653
  this.views = ["line"];
6654
+ this.size = void 0;
6556
6655
  }
6557
6656
  render() {
6558
6657
  return /* @__PURE__ */ u$1(
@@ -6561,7 +6660,8 @@ let RelativeGrowthAdvantageComponent = class extends PreactLitAdapter {
6561
6660
  numerator: this.numerator,
6562
6661
  denominator: this.denominator,
6563
6662
  generationTime: this.generationTime,
6564
- views: this.views
6663
+ views: this.views,
6664
+ size: this.size
6565
6665
  }
6566
6666
  );
6567
6667
  }
@@ -6578,6 +6678,9 @@ __decorateClass$5([
6578
6678
  __decorateClass$5([
6579
6679
  n2({ type: Array })
6580
6680
  ], RelativeGrowthAdvantageComponent.prototype, "views", 2);
6681
+ __decorateClass$5([
6682
+ n2({ type: Object })
6683
+ ], RelativeGrowthAdvantageComponent.prototype, "size", 2);
6581
6684
  RelativeGrowthAdvantageComponent = __decorateClass$5([
6582
6685
  t$2("gs-relative-growth-advantage")
6583
6686
  ], RelativeGrowthAdvantageComponent);
@@ -6612,7 +6715,7 @@ async function queryAggregateData(variant, fields, lapis, signal) {
6612
6715
  })
6613
6716
  );
6614
6717
  }
6615
- const Aggregate = ({ fields, views, filter }) => {
6718
+ const Aggregate = ({ fields, views, filter, size }) => {
6616
6719
  const lapis = P(LapisUrlContext);
6617
6720
  const { data, error, isLoading } = useQuery(async () => {
6618
6721
  return queryAggregateData(filter, fields, lapis);
@@ -6627,7 +6730,7 @@ const Aggregate = ({ fields, views, filter }) => {
6627
6730
  if (data === null) {
6628
6731
  return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(NoDataDisplay, {}) });
6629
6732
  }
6630
- return /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(AggregatedDataTabs, { data, views, fields }) });
6733
+ return /* @__PURE__ */ u$1(ResizeContainer, { size, defaultSize: { height: "700px", width: "100%" }, children: /* @__PURE__ */ u$1(Headline, { heading: headline, children: /* @__PURE__ */ u$1(AggregatedDataTabs, { data, views, fields }) }) });
6631
6734
  };
6632
6735
  const AggregatedDataTabs = ({ data, views, fields }) => {
6633
6736
  const getTab = (view) => {
@@ -6665,9 +6768,10 @@ let AggregateComponent = class extends PreactLitAdapterWithGridJsStyles {
6665
6768
  this.fields = [];
6666
6769
  this.views = ["table"];
6667
6770
  this.filter = {};
6771
+ this.size = void 0;
6668
6772
  }
6669
6773
  render() {
6670
- return /* @__PURE__ */ u$1(Aggregate, { fields: this.fields, views: this.views, filter: this.filter });
6774
+ return /* @__PURE__ */ u$1(Aggregate, { fields: this.fields, views: this.views, filter: this.filter, size: this.size });
6671
6775
  }
6672
6776
  };
6673
6777
  __decorateClass$4([
@@ -6679,6 +6783,9 @@ __decorateClass$4([
6679
6783
  __decorateClass$4([
6680
6784
  n2({ type: Object })
6681
6785
  ], AggregateComponent.prototype, "filter", 2);
6786
+ __decorateClass$4([
6787
+ n2({ type: Object })
6788
+ ], AggregateComponent.prototype, "size", 2);
6682
6789
  AggregateComponent = __decorateClass$4([
6683
6790
  t$2("gs-aggregate-component")
6684
6791
  ], AggregateComponent);
@@ -6689,16 +6796,36 @@ const toYYYYMMDD = (date) => {
6689
6796
  const options2 = { year: "numeric", month: "2-digit", day: "2-digit" };
6690
6797
  return date.toLocaleDateString("en-CA", options2);
6691
6798
  };
6799
+ const PRESET_VALUE_CUSTOM = "custom";
6800
+ const PRESET_VALUE_ALL_TIMES = "allTimes";
6801
+ const PRESET_VALUE_LAST_2_WEEKS = "last2Weeks";
6802
+ const PRESET_VALUE_LAST_MONTH = "lastMonth";
6803
+ const PRESET_VALUE_LAST_2_MONTHS = "last2Months";
6804
+ const PRESET_VALUE_LAST_3_MONTHS = "last3Months";
6805
+ const PRESET_VALUE_LAST_6_MONTHS = "last6Months";
6806
+ const presets = {
6807
+ [PRESET_VALUE_CUSTOM]: { label: "Custom" },
6808
+ [PRESET_VALUE_ALL_TIMES]: { label: "All times" },
6809
+ [PRESET_VALUE_LAST_2_WEEKS]: { label: "Last 2 weeks" },
6810
+ [PRESET_VALUE_LAST_MONTH]: { label: "Last month" },
6811
+ [PRESET_VALUE_LAST_2_MONTHS]: { label: "Last 2 months" },
6812
+ [PRESET_VALUE_LAST_3_MONTHS]: { label: "Last 3 months" },
6813
+ [PRESET_VALUE_LAST_6_MONTHS]: { label: "Last 6 months" }
6814
+ };
6692
6815
  const DateRangeSelector = ({
6693
6816
  customSelectOptions,
6694
- earliestDate = "1900-01-01"
6817
+ earliestDate = "1900-01-01",
6818
+ initialValue
6695
6819
  }) => {
6696
6820
  const datePickerRef = F(null);
6697
6821
  const endDatePickerRef = F(null);
6698
6822
  const divRef = F(null);
6699
6823
  const [dateFromPicker, setDateFromPicker] = p(null);
6700
6824
  const [dateToPicker, setDateToPicker] = p(null);
6701
- const [selectedDateRange, setSelectedDateRange] = p("last6Months");
6825
+ const selectableOptions = getSelectableOptions(customSelectOptions);
6826
+ const [selectedDateRange, setSelectedDateRange] = p(
6827
+ initialValue !== void 0 && selectableOptions.some((option) => option.value === initialValue) ? initialValue : PRESET_VALUE_LAST_6_MONTHS
6828
+ );
6702
6829
  const [selectedDates, setSelectedDates] = p({
6703
6830
  dateFrom: getDatesForSelectorValue("last6Months", customSelectOptions, earliestDate).dateFrom,
6704
6831
  dateTo: getDatesForSelectorValue("last6Months", customSelectOptions, earliestDate).dateTo
@@ -6729,23 +6856,6 @@ const DateRangeSelector = ({
6729
6856
  dateToPicker == null ? void 0 : dateToPicker.destroy();
6730
6857
  };
6731
6858
  }, [datePickerRef, endDatePickerRef]);
6732
- const selectableOptions = () => {
6733
- const presetOptions = [
6734
- { label: "Custom", value: "custom" },
6735
- { label: "All times", value: "allTimes" },
6736
- { label: "Last 2 weeks", value: "last2Weeks" },
6737
- { label: "Last month", value: "lastMonth" },
6738
- { label: "Last 2 weeks", value: "last2Weeks" },
6739
- { label: "Last month", value: "lastMonth" },
6740
- { label: "Last 2 months", value: "last2Months" },
6741
- { label: "Last 3 months", value: "last3Months" },
6742
- { label: "Last 6 months", value: "last6Months" }
6743
- ];
6744
- const customOptions = customSelectOptions.map((customSelectOption) => {
6745
- return { label: customSelectOption.label, value: customLabelToOptionValue(customSelectOption.label) };
6746
- });
6747
- return [...presetOptions, ...customOptions];
6748
- };
6749
6859
  const onSelectChange = (value) => {
6750
6860
  setSelectedDateRange(value);
6751
6861
  const dateRange = getDatesForSelectorValue(value, customSelectOptions, earliestDate);
@@ -6797,7 +6907,7 @@ const DateRangeSelector = ({
6797
6907
  /* @__PURE__ */ u$1(
6798
6908
  Select,
6799
6909
  {
6800
- items: selectableOptions(),
6910
+ items: selectableOptions,
6801
6911
  selected: selectedDateRange,
6802
6912
  selectStyle: "select-bordered rounded-none join-item",
6803
6913
  onChange: (event) => {
@@ -6832,44 +6942,48 @@ const DateRangeSelector = ({
6832
6942
  )
6833
6943
  ] });
6834
6944
  };
6835
- const customLabelToOptionValue = (customLabel) => {
6836
- return `${customLabel}customLabel`;
6945
+ const getSelectableOptions = (customSelectOptions) => {
6946
+ const presetOptions = Object.entries(presets).map(([key, value]) => {
6947
+ return { label: value.label, value: key };
6948
+ });
6949
+ const customOptions = customSelectOptions.map((customSelectOption) => {
6950
+ return { label: customSelectOption.label, value: customSelectOption.label };
6951
+ });
6952
+ return [...presetOptions, ...customOptions];
6837
6953
  };
6838
6954
  const getDatesForSelectorValue = (selectorValue, customSelectOptions, earliestDate) => {
6839
6955
  const today = /* @__PURE__ */ new Date();
6840
- const customSelectOption = customSelectOptions.find(
6841
- (option) => customLabelToOptionValue(option.label) === selectorValue
6842
- );
6956
+ const customSelectOption = customSelectOptions.find((option) => option.label === selectorValue);
6843
6957
  if (customSelectOption) {
6844
6958
  return { dateFrom: new Date(customSelectOption.dateFrom), dateTo: new Date(customSelectOption.dateTo) };
6845
6959
  }
6846
6960
  switch (selectorValue) {
6847
- case "last2Weeks": {
6961
+ case PRESET_VALUE_LAST_2_WEEKS: {
6848
6962
  const twoWeeksAgo = new Date(today);
6849
6963
  twoWeeksAgo.setDate(today.getDate() - 14);
6850
6964
  return { dateFrom: twoWeeksAgo, dateTo: today };
6851
6965
  }
6852
- case "lastMonth": {
6966
+ case PRESET_VALUE_LAST_MONTH: {
6853
6967
  const lastMonth = new Date(today);
6854
6968
  lastMonth.setMonth(today.getMonth() - 1);
6855
6969
  return { dateFrom: lastMonth, dateTo: today };
6856
6970
  }
6857
- case "last2Months": {
6971
+ case PRESET_VALUE_LAST_2_MONTHS: {
6858
6972
  const twoMonthsAgo = new Date(today);
6859
6973
  twoMonthsAgo.setMonth(today.getMonth() - 2);
6860
6974
  return { dateFrom: twoMonthsAgo, dateTo: today };
6861
6975
  }
6862
- case "last3Months": {
6976
+ case PRESET_VALUE_LAST_3_MONTHS: {
6863
6977
  const threeMonthsAgo = new Date(today);
6864
6978
  threeMonthsAgo.setMonth(today.getMonth() - 3);
6865
6979
  return { dateFrom: threeMonthsAgo, dateTo: today };
6866
6980
  }
6867
- case "last6Months": {
6981
+ case PRESET_VALUE_LAST_6_MONTHS: {
6868
6982
  const sixMonthsAgo = new Date(today);
6869
6983
  sixMonthsAgo.setMonth(today.getMonth() - 6);
6870
6984
  return { dateFrom: sixMonthsAgo, dateTo: today };
6871
6985
  }
6872
- case "allTimes": {
6986
+ case PRESET_VALUE_ALL_TIMES: {
6873
6987
  return { dateFrom: new Date(earliestDate), dateTo: today };
6874
6988
  }
6875
6989
  default:
@@ -6892,9 +7006,17 @@ let DateRangeSelectorComponent = class extends PreactLitAdapter {
6892
7006
  super(...arguments);
6893
7007
  this.customSelectOptions = [];
6894
7008
  this.earliestDate = "1900-01-01";
7009
+ this.initialValue = "";
6895
7010
  }
6896
7011
  render() {
6897
- return /* @__PURE__ */ u$1(DateRangeSelector, { customSelectOptions: this.customSelectOptions, earliestDate: this.earliestDate });
7012
+ return /* @__PURE__ */ u$1(
7013
+ DateRangeSelector,
7014
+ {
7015
+ customSelectOptions: this.customSelectOptions,
7016
+ earliestDate: this.earliestDate,
7017
+ initialValue: this.initialValue
7018
+ }
7019
+ );
6898
7020
  }
6899
7021
  };
6900
7022
  __decorateClass$3([
@@ -6903,6 +7025,9 @@ __decorateClass$3([
6903
7025
  __decorateClass$3([
6904
7026
  n2({ type: String })
6905
7027
  ], DateRangeSelectorComponent.prototype, "earliestDate", 2);
7028
+ __decorateClass$3([
7029
+ n2()
7030
+ ], DateRangeSelectorComponent.prototype, "initialValue", 2);
6906
7031
  DateRangeSelectorComponent = __decorateClass$3([
6907
7032
  t$2("gs-date-range-selector")
6908
7033
  ], DateRangeSelectorComponent);
@@ -6938,7 +7063,7 @@ function compareLocationEntries(fields) {
6938
7063
  return 0;
6939
7064
  };
6940
7065
  }
6941
- const LocationFilter = ({ value: initialValue, fields }) => {
7066
+ const LocationFilter = ({ initialValue, fields }) => {
6942
7067
  const lapis = P(LapisUrlContext);
6943
7068
  const [value, setValue] = p(initialValue ?? "");
6944
7069
  const [unknownLocation, setUnknownLocation] = p(false);
@@ -7031,16 +7156,16 @@ var __decorateClass$2 = (decorators, target, key, kind) => {
7031
7156
  let LocationFilterComponent = class extends PreactLitAdapter {
7032
7157
  constructor() {
7033
7158
  super(...arguments);
7034
- this.value = "";
7159
+ this.initialValue = "";
7035
7160
  this.fields = [];
7036
7161
  }
7037
7162
  render() {
7038
- return /* @__PURE__ */ u$1(LocationFilter, { value: this.value, fields: this.fields });
7163
+ return /* @__PURE__ */ u$1(LocationFilter, { initialValue: this.initialValue, fields: this.fields });
7039
7164
  }
7040
7165
  };
7041
7166
  __decorateClass$2([
7042
7167
  n2()
7043
- ], LocationFilterComponent.prototype, "value", 2);
7168
+ ], LocationFilterComponent.prototype, "initialValue", 2);
7044
7169
  __decorateClass$2([
7045
7170
  n2({ type: Array })
7046
7171
  ], LocationFilterComponent.prototype, "fields", 2);
@@ -7052,7 +7177,7 @@ async function fetchAutocompleteList(lapis, field, signal) {
7052
7177
  const data = (await fetchAggregatedOperator.evaluate(lapis, signal)).content;
7053
7178
  return data.map((item) => item[field]);
7054
7179
  }
7055
- const TextInput = ({ lapisField, placeholderText }) => {
7180
+ const TextInput = ({ lapisField, placeholderText, initialValue }) => {
7056
7181
  const lapis = P(LapisUrlContext);
7057
7182
  const inputRef = F(null);
7058
7183
  const { data, error, isLoading } = useQuery(() => fetchAutocompleteList(lapis, lapisField), [lapisField, lapis]);
@@ -7093,7 +7218,8 @@ const TextInput = ({ lapisField, placeholderText }) => {
7093
7218
  placeholder: placeholderText !== void 0 ? placeholderText : lapisField,
7094
7219
  onInput,
7095
7220
  ref: inputRef,
7096
- list: lapisField
7221
+ list: lapisField,
7222
+ value: initialValue
7097
7223
  }
7098
7224
  ),
7099
7225
  /* @__PURE__ */ u$1("datalist", { id: lapisField, children: data.map((item) => /* @__PURE__ */ u$1("option", { value: item }, item)) })
@@ -7113,13 +7239,24 @@ var __decorateClass$1 = (decorators, target, key, kind) => {
7113
7239
  let TextInputComponent = class extends PreactLitAdapter {
7114
7240
  constructor() {
7115
7241
  super(...arguments);
7242
+ this.initialValue = "";
7116
7243
  this.lapisField = "";
7117
7244
  this.placeholderText = "";
7118
7245
  }
7119
7246
  render() {
7120
- return /* @__PURE__ */ u$1(TextInput, { lapisField: this.lapisField, placeholderText: this.placeholderText });
7247
+ return /* @__PURE__ */ u$1(
7248
+ TextInput,
7249
+ {
7250
+ lapisField: this.lapisField,
7251
+ placeholderText: this.placeholderText,
7252
+ initialValue: this.initialValue
7253
+ }
7254
+ );
7121
7255
  }
7122
7256
  };
7257
+ __decorateClass$1([
7258
+ n2()
7259
+ ], TextInputComponent.prototype, "initialValue", 2);
7123
7260
  __decorateClass$1([
7124
7261
  n2()
7125
7262
  ], TextInputComponent.prototype, "lapisField", 2);
@@ -7129,6 +7266,16 @@ __decorateClass$1([
7129
7266
  TextInputComponent = __decorateClass$1([
7130
7267
  t$2("gs-text-input")
7131
7268
  ], TextInputComponent);
7269
+ const ReferenceGenomesAwaiter = ({ children }) => {
7270
+ const referenceGenome = P(ReferenceGenomeContext);
7271
+ if (isNotInitialized(referenceGenome)) {
7272
+ return /* @__PURE__ */ u$1("div", { className: "laoding loading-spinner loading-md", children: "Loading..." });
7273
+ }
7274
+ return /* @__PURE__ */ u$1(Fragment, { children });
7275
+ };
7276
+ function isNotInitialized(referenceGenome) {
7277
+ return referenceGenome.nucleotideSequences.length === 0 && referenceGenome.genes.length === 0;
7278
+ }
7132
7279
  const sequenceTypeFromSegment = (possibleSegment, referenceGenome) => {
7133
7280
  if (possibleSegment === void 0) {
7134
7281
  return referenceGenome.nucleotideSequences.length === 1 ? "nucleotide" : void 0;
@@ -7195,14 +7342,11 @@ const DeleteIcon = () => {
7195
7342
  }
7196
7343
  );
7197
7344
  };
7198
- const MutationFilter = () => {
7345
+ const MutationFilter = ({ initialValue }) => {
7199
7346
  const referenceGenome = P(ReferenceGenomeContext);
7200
- const [selectedFilters, setSelectedFilters] = p({
7201
- nucleotideMutations: [],
7202
- aminoAcidMutations: [],
7203
- nucleotideInsertions: [],
7204
- aminoAcidInsertions: []
7205
- });
7347
+ const [selectedFilters, setSelectedFilters] = p(
7348
+ getInitialState(initialValue, referenceGenome)
7349
+ );
7206
7350
  const [inputValue, setInputValue] = p("");
7207
7351
  const [isError, setIsError] = p(false);
7208
7352
  const formRef = F(null);
@@ -7248,14 +7392,17 @@ const MutationFilter = () => {
7248
7392
  setIsError(false);
7249
7393
  };
7250
7394
  return /* @__PURE__ */ u$1("div", { class: `rounded-lg border border-gray-300 bg-white p-2`, children: [
7251
- /* @__PURE__ */ u$1(
7252
- SelectedMutationDisplay,
7253
- {
7254
- selectedFilters,
7255
- setSelectedFilters,
7256
- fireChangeEvent
7257
- }
7258
- ),
7395
+ /* @__PURE__ */ u$1("div", { class: "flex justify-between", children: [
7396
+ /* @__PURE__ */ u$1(
7397
+ SelectedMutationDisplay,
7398
+ {
7399
+ selectedFilters,
7400
+ setSelectedFilters,
7401
+ fireChangeEvent
7402
+ }
7403
+ ),
7404
+ /* @__PURE__ */ u$1(Info, { className: "mx-1", content: "Info for mutation filter" })
7405
+ ] }),
7259
7406
  /* @__PURE__ */ u$1("form", { className: "mt-2 w-full", onSubmit: handleSubmit, ref: formRef, children: /* @__PURE__ */ u$1("label", { className: `input flex items-center gap-2 ${isError ? "input-error" : "input-bordered"}`, children: [
7260
7407
  /* @__PURE__ */ u$1(
7261
7408
  "input",
@@ -7264,7 +7411,7 @@ const MutationFilter = () => {
7264
7411
  type: "text",
7265
7412
  value: inputValue,
7266
7413
  onInput: handleInputChange,
7267
- placeholder: "Enter a mutation",
7414
+ placeholder: getPlaceholder(referenceGenome),
7268
7415
  onBlur: handleOnBlur
7269
7416
  }
7270
7417
  ),
@@ -7272,6 +7419,40 @@ const MutationFilter = () => {
7272
7419
  ] }) })
7273
7420
  ] });
7274
7421
  };
7422
+ function getInitialState(initialValue, referenceGenome) {
7423
+ if (initialValue === void 0) {
7424
+ return {
7425
+ nucleotideMutations: [],
7426
+ aminoAcidMutations: [],
7427
+ nucleotideInsertions: [],
7428
+ aminoAcidInsertions: []
7429
+ };
7430
+ }
7431
+ const values = Array.isArray(initialValue) ? initialValue : Object.values(initialValue).flatMap((it) => it);
7432
+ return values.reduce(
7433
+ (selectedFilters, value) => {
7434
+ const parsedMutation = parseAndValidateMutation(value, referenceGenome);
7435
+ if (parsedMutation === null) {
7436
+ return selectedFilters;
7437
+ }
7438
+ return {
7439
+ ...selectedFilters,
7440
+ [parsedMutation.type]: [...selectedFilters[parsedMutation.type], parsedMutation.value]
7441
+ };
7442
+ },
7443
+ {
7444
+ nucleotideMutations: [],
7445
+ aminoAcidMutations: [],
7446
+ nucleotideInsertions: [],
7447
+ aminoAcidInsertions: []
7448
+ }
7449
+ );
7450
+ }
7451
+ function getPlaceholder(referenceGenome) {
7452
+ const segmentPrefix = referenceGenome.nucleotideSequences.length > 1 ? `${referenceGenome.nucleotideSequences[0].name}:` : "";
7453
+ const firstGene = referenceGenome.genes[0].name;
7454
+ return `Enter a mutation (e.g. ${segmentPrefix}A123T, ins_${segmentPrefix}123:AT, ${firstGene}:M123E, ins_${firstGene}:123:ME)`;
7455
+ }
7275
7456
  const SelectedMutationDisplay = ({ selectedFilters, setSelectedFilters, fireChangeEvent }) => {
7276
7457
  const onSelectedRemoved = (mutation, key) => {
7277
7458
  const newSelectedValues = {
@@ -7402,10 +7583,17 @@ var __decorateClass = (decorators, target, key, kind) => {
7402
7583
  return result;
7403
7584
  };
7404
7585
  let MutationFilterComponent = class extends PreactLitAdapter {
7586
+ constructor() {
7587
+ super(...arguments);
7588
+ this.initialValue = void 0;
7589
+ }
7405
7590
  render() {
7406
- return /* @__PURE__ */ u$1(MutationFilter, {});
7591
+ return /* @__PURE__ */ u$1(ReferenceGenomesAwaiter, { children: /* @__PURE__ */ u$1(MutationFilter, { initialValue: this.initialValue }) });
7407
7592
  }
7408
7593
  };
7594
+ __decorateClass([
7595
+ n2()
7596
+ ], MutationFilterComponent.prototype, "initialValue", 2);
7409
7597
  MutationFilterComponent = __decorateClass([
7410
7598
  t$2("gs-mutation-filter")
7411
7599
  ], MutationFilterComponent);