@genspectrum/dashboard-components 0.6.5 → 0.6.6

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 (26) hide show
  1. package/custom-elements.json +35 -3
  2. package/dist/dashboard-components.js +142 -23
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/style.css +50 -2
  5. package/package.json +1 -1
  6. package/src/constants.ts +1 -0
  7. package/src/preact/components/tooltip.stories.tsx +12 -2
  8. package/src/preact/components/tooltip.tsx +37 -13
  9. package/src/preact/mutationsOverTime/__mockData__/aggregated_byDay.json +38 -0
  10. package/src/preact/mutationsOverTime/__mockData__/aggregated_byWeek.json +122 -0
  11. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_20_01_2024.json +6778 -0
  12. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_21_01_2024.json +7129 -0
  13. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_22_01_2024.json +4681 -0
  14. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_23_01_2024.json +10738 -0
  15. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_24_01_2024.json +11710 -0
  16. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_25_01_2024.json +11557 -0
  17. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutations_26_01_2024.json +8596 -0
  18. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week3_2024.json +8812 -0
  19. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week4_2024.json +9730 -0
  20. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week5_2024.json +9865 -0
  21. package/src/preact/mutationsOverTime/__mockData__/nucleotideMutations_week6_2024.json +11314 -0
  22. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +26 -8
  23. package/src/preact/mutationsOverTime/mutations-over-time.tsx +32 -8
  24. package/src/utils/temporal.spec.ts +3 -4
  25. package/src/utils/temporal.ts +9 -4
  26. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +254 -2
@@ -1791,11 +1791,27 @@
1791
1791
  },
1792
1792
  {
1793
1793
  "kind": "variable",
1794
- "name": "Default",
1794
+ "name": "ByMonth",
1795
1795
  "type": {
1796
1796
  "text": "StoryObj<Required<MutationsOverTimeProps>>"
1797
1797
  },
1798
1798
  "default": "{ ...Template, parameters: { fetchMock: { mocks: [ { matcher: { name: 'aggregated_dates', url: AGGREGATED_ENDPOINT, body: { dateFrom: '2024-01-15', dateTo: '2024-07-10', fields: ['date'], pangoLineage: 'JN.1*', }, }, response: { status: 200, body: aggregated_date, }, }, { matcher: { name: 'nucleotideMutations_01', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-01', dateTo: '2024-01-31', minProportion: 0.001, }, }, response: { status: 200, body: nucleotideMutation_01, }, }, { matcher: { name: 'nucleotideMutations_02', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-02-01', dateTo: '2024-02-29', minProportion: 0.001, }, }, response: { status: 200, body: nucleotideMutation_02, }, }, { matcher: { name: 'nucleotideMutations_03', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-03-01', dateTo: '2024-03-31', minProportion: 0.001, }, response: { status: 200, body: nucleotideMutation_03, }, }, }, { matcher: { name: 'nucleotideMutations_04', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-04-01', dateTo: '2024-04-30', minProportion: 0.001, }, response: { status: 200, body: nucleotideMutation_04, }, }, }, { matcher: { name: 'nucleotideMutations_05', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-05-01', dateTo: '2024-05-31', minProportion: 0.001, }, response: { status: 200, body: nucleotideMutation_05, }, }, }, { matcher: { name: 'nucleotideMutations_06', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-06-01', dateTo: '2024-06-30', minProportion: 0.001, }, response: { status: 200, body: nucleotideMutation_06, }, }, }, { matcher: { name: 'nucleotideMutations_07', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-07-01', dateTo: '2024-07-31', minProportion: 0.001, }, response: { status: 200, body: nucleotideMutation_07, }, }, }, ], }, }, }"
1799
+ },
1800
+ {
1801
+ "kind": "variable",
1802
+ "name": "ByWeek",
1803
+ "type": {
1804
+ "text": "StoryObj<Required<MutationsOverTimeProps>>"
1805
+ },
1806
+ "default": "{ ...Template, args: { ...Template.args, lapisFilter: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-02-11' }, granularity: 'week', }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'aggregated_dates', url: AGGREGATED_ENDPOINT, body: { dateFrom: '2024-01-15', dateTo: '2024-02-11', fields: ['date'], pangoLineage: 'JN.1*', }, }, response: { status: 200, body: aggregated_byWeek, }, }, { matcher: { name: 'nucleotideMutation_week3', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-15', dateTo: '2024-01-21', minProportion: 0.001, }, }, response: { status: 200, body: nucleotideMutation_week3, }, }, { matcher: { name: 'nucleotideMutation_week4', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-22', dateTo: '2024-01-28', minProportion: 0.001, }, }, response: { status: 200, body: nucleotideMutation_week4, }, }, { matcher: { name: 'nucleotideMutation_week5', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-29', dateTo: '2024-02-04', minProportion: 0.001, }, }, response: { status: 200, body: nucleotideMutation_week5, }, }, { matcher: { name: 'nucleotideMutation_week6', url: NUCLEOTIDE_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-02-05', dateTo: '2024-02-11', minProportion: 0.001, }, }, response: { status: 200, body: nucleotideMutation_week6, }, }, ], }, }, }"
1807
+ },
1808
+ {
1809
+ "kind": "variable",
1810
+ "name": "AminoAcidMutationsByDay",
1811
+ "type": {
1812
+ "text": "StoryObj<Required<MutationsOverTimeProps>>"
1813
+ },
1814
+ "default": "{ ...Template, args: { ...Template.args, lapisFilter: { pangoLineage: 'JN.1*', dateFrom: '2024-01-20', dateTo: '2024-01-26' }, granularity: 'day', sequenceType: 'amino acid', }, parameters: { fetchMock: { mocks: [ { matcher: { name: 'aggregated_byDay', url: AGGREGATED_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-20', dateTo: '2024-01-26', fields: ['date'] }, }, response: { status: 200, body: aggregated_byDay, }, }, { matcher: { name: 'aminoAcidMutations_20_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-20', dateTo: '2024-01-20', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_20_01_2024, }, }, { matcher: { name: 'aminoAcidMutations_21_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-21', dateTo: '2024-01-21', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_21_01_2024, }, }, { matcher: { name: 'aminoAcidMutations_22_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-22', dateTo: '2024-01-22', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_22_01_2024, }, }, { matcher: { name: 'aminoAcidMutations_23_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-23', dateTo: '2024-01-23', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_23_01_2024, }, }, { matcher: { name: 'aminoAcidMutations_24_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-24', dateTo: '2024-01-24', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_24_01_2024, }, }, { matcher: { name: 'aminoAcidMutations_25_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-25', dateTo: '2024-01-25', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_25_01_2024, }, }, { matcher: { name: 'aminoAcidMutations_26_01_2024', url: AMINO_ACID_MUTATIONS_ENDPOINT, body: { pangoLineage: 'JN.1*', dateFrom: '2024-01-26', dateTo: '2024-01-26', minProportion: 0.001, }, }, response: { status: 200, body: aminoAcidMutations_26_01_2024, }, }, ], }, }, }"
1799
1815
  }
1800
1816
  ],
1801
1817
  "exports": [
@@ -1809,9 +1825,25 @@
1809
1825
  },
1810
1826
  {
1811
1827
  "kind": "js",
1812
- "name": "Default",
1828
+ "name": "ByMonth",
1813
1829
  "declaration": {
1814
- "name": "Default",
1830
+ "name": "ByMonth",
1831
+ "module": "src/web-components/visualization/gs-mutations-over-time.stories.ts"
1832
+ }
1833
+ },
1834
+ {
1835
+ "kind": "js",
1836
+ "name": "ByWeek",
1837
+ "declaration": {
1838
+ "name": "ByWeek",
1839
+ "module": "src/web-components/visualization/gs-mutations-over-time.stories.ts"
1840
+ }
1841
+ },
1842
+ {
1843
+ "kind": "js",
1844
+ "name": "AminoAcidMutationsByDay",
1845
+ "declaration": {
1846
+ "name": "AminoAcidMutationsByDay",
1815
1847
  "module": "src/web-components/visualization/gs-mutations-over-time.stories.ts"
1816
1848
  }
1817
1849
  }
@@ -4202,6 +4202,9 @@ input.tab:checked + .tab-content,
4202
4202
  .visible {
4203
4203
  visibility: visible;
4204
4204
  }
4205
+ .invisible {
4206
+ visibility: hidden;
4207
+ }
4205
4208
  .static {
4206
4209
  position: static;
4207
4210
  }
@@ -4217,18 +4220,39 @@ input.tab:checked + .tab-content,
4217
4220
  .-top-3 {
4218
4221
  top: -0.75rem;
4219
4222
  }
4223
+ .bottom-full {
4224
+ bottom: 100%;
4225
+ }
4220
4226
  .left-0 {
4221
4227
  left: 0px;
4222
4228
  }
4229
+ .left-1\\/2 {
4230
+ left: 50%;
4231
+ }
4232
+ .left-full {
4233
+ left: 100%;
4234
+ }
4235
+ .right-0 {
4236
+ right: 0px;
4237
+ }
4223
4238
  .right-2 {
4224
4239
  right: 0.5rem;
4225
4240
  }
4241
+ .right-full {
4242
+ right: 100%;
4243
+ }
4226
4244
  .top-0 {
4227
4245
  top: 0px;
4228
4246
  }
4247
+ .top-1\\/2 {
4248
+ top: 50%;
4249
+ }
4229
4250
  .top-2 {
4230
4251
  top: 0.5rem;
4231
4252
  }
4253
+ .top-full {
4254
+ top: 100%;
4255
+ }
4232
4256
  .z-10 {
4233
4257
  z-index: 10;
4234
4258
  }
@@ -4257,18 +4281,30 @@ input.tab:checked + .tab-content,
4257
4281
  margin-top: 1rem;
4258
4282
  margin-bottom: 1rem;
4259
4283
  }
4284
+ .mb-1 {
4285
+ margin-bottom: 0.25rem;
4286
+ }
4260
4287
  .mb-2 {
4261
4288
  margin-bottom: 0.5rem;
4262
4289
  }
4290
+ .ml-1 {
4291
+ margin-left: 0.25rem;
4292
+ }
4263
4293
  .ml-2\\.5 {
4264
4294
  margin-left: 0.625rem;
4265
4295
  }
4266
4296
  .ml-3 {
4267
4297
  margin-left: 0.75rem;
4268
4298
  }
4299
+ .mr-1 {
4300
+ margin-right: 0.25rem;
4301
+ }
4269
4302
  .mr-2 {
4270
4303
  margin-right: 0.5rem;
4271
4304
  }
4305
+ .mt-1 {
4306
+ margin-top: 0.25rem;
4307
+ }
4272
4308
  .mt-4 {
4273
4309
  margin-top: 1rem;
4274
4310
  }
@@ -4327,6 +4363,14 @@ input.tab:checked + .tab-content,
4327
4363
  .grow {
4328
4364
  flex-grow: 1;
4329
4365
  }
4366
+ .translate-x-\\[-50\\%\\] {
4367
+ --tw-translate-x: -50%;
4368
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
4369
+ }
4370
+ .translate-y-\\[-50\\%\\] {
4371
+ --tw-translate-y: -50%;
4372
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
4373
+ }
4330
4374
  .resize {
4331
4375
  resize: both;
4332
4376
  }
@@ -4427,6 +4471,10 @@ input.tab:checked + .tab-content,
4427
4471
  --tw-border-opacity: 1;
4428
4472
  border-color: rgb(239 68 68 / var(--tw-border-opacity));
4429
4473
  }
4474
+ .bg-red-200 {
4475
+ --tw-bg-opacity: 1;
4476
+ background-color: rgb(254 202 202 / var(--tw-bg-opacity));
4477
+ }
4430
4478
  .bg-white {
4431
4479
  --tw-bg-opacity: 1;
4432
4480
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@@ -4589,8 +4637,8 @@ input.tab:checked + .tab-content,
4589
4637
  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);
4590
4638
  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
4591
4639
  }
4592
- .peer:hover ~ .peer-hover\\:block {
4593
- display: block;
4640
+ .peer:hover ~ .peer-hover\\:visible {
4641
+ visibility: visible;
4594
4642
  }`;
4595
4643
  var __defProp$c = Object.defineProperty;
4596
4644
  var __decorateClass$c = (decorators, target, key, kind) => {
@@ -5892,6 +5940,7 @@ const isoWeek = function(o2, c2, d2) {
5892
5940
  };
5893
5941
  dayjs.extend(isoWeek);
5894
5942
  dayjs.extend(advancedFormat);
5943
+ const FORMAT_ISO_WEEK_YEAR_WEEK = "GGGG-[W]WW";
5895
5944
  const _TemporalCache = class _TemporalCache {
5896
5945
  constructor() {
5897
5946
  this.yearMonthDayCache = /* @__PURE__ */ new Map();
@@ -5960,7 +6009,7 @@ class YearMonthDay {
5960
6009
  return this.cache.getYearMonth(this.dayjs.format("YYYY-MM"));
5961
6010
  }
5962
6011
  get week() {
5963
- return this.cache.getYearWeek(this.dayjs.format("GGGG-WW"));
6012
+ return this.cache.getYearWeek(this.dayjs.format(FORMAT_ISO_WEEK_YEAR_WEEK));
5964
6013
  }
5965
6014
  addDays(days) {
5966
6015
  const date = this.dayjs.add(days, "day");
@@ -5982,7 +6031,7 @@ class YearWeek {
5982
6031
  this.cache = cache;
5983
6032
  }
5984
6033
  get text() {
5985
- return this.firstDay.dayjs.format("YYYY-WW");
6034
+ return this.firstDay.dayjs.format(FORMAT_ISO_WEEK_YEAR_WEEK);
5986
6035
  }
5987
6036
  toString() {
5988
6037
  return this.text;
@@ -6004,14 +6053,14 @@ class YearWeek {
6004
6053
  }
6005
6054
  addWeeks(weeks) {
6006
6055
  const date = this.firstDay.dayjs.add(weeks, "week");
6007
- const s2 = date.format("YYYY-WW");
6056
+ const s2 = date.format(FORMAT_ISO_WEEK_YEAR_WEEK);
6008
6057
  return this.cache.getYearWeek(s2);
6009
6058
  }
6010
6059
  minus(other) {
6011
6060
  return this.firstDay.dayjs.diff(other.firstDay.dayjs, "week");
6012
6061
  }
6013
6062
  static parse(s2, cache) {
6014
- const [year, week] = s2.split("-").map((s22) => parseInt(s22, 10));
6063
+ const [year, week] = s2.split("-W").map((s22) => parseInt(s22, 10));
6015
6064
  return new YearWeek(year, week, cache);
6016
6065
  }
6017
6066
  }
@@ -7917,13 +7966,38 @@ function filterProportion(data, proportionInterval) {
7917
7966
  }
7918
7967
  });
7919
7968
  }
7920
- const Tooltip = ({ children, content }) => {
7921
- const referenceRef = A(null);
7922
- const floatingRef = A(null);
7923
- useFloatingUi(referenceRef, floatingRef, [offset(5), shift(), flip()]);
7969
+ function getPositionCss(position) {
7970
+ switch (position) {
7971
+ case "top":
7972
+ return "bottom-full translate-x-[-50%] left-1/2 mb-1";
7973
+ case "top-start":
7974
+ return "bottom-full mr-1 mb-1";
7975
+ case "top-end":
7976
+ return "bottom-full right-0 ml-1 mb-1";
7977
+ case "bottom":
7978
+ return "top-full translate-x-[-50%] left-1/2 mt-1";
7979
+ case "bottom-start":
7980
+ return "mr-1 mt-1";
7981
+ case "bottom-end":
7982
+ return "right-0 ml-1 mt-1";
7983
+ case "left":
7984
+ return "right-full translate-y-[-50%] top-1/2 mr-1";
7985
+ case "right":
7986
+ return "left-full translate-y-[-50%] top-1/2 ml-1";
7987
+ case void 0:
7988
+ return "";
7989
+ }
7990
+ }
7991
+ const Tooltip = ({ children, content, position = "bottom" }) => {
7924
7992
  return /* @__PURE__ */ u$1("div", { className: "relative", children: [
7925
- /* @__PURE__ */ u$1("div", { className: "peer", ref: referenceRef, children }),
7926
- /* @__PURE__ */ u$1("div", { ref: floatingRef, className: `${dropdownClass} hidden peer-hover:block`, children: content })
7993
+ /* @__PURE__ */ u$1("div", { className: "peer", children }),
7994
+ /* @__PURE__ */ u$1(
7995
+ "div",
7996
+ {
7997
+ className: `absolute z-10 w-max bg-white p-4 border border-gray-200 rounded-md invisible peer-hover:visible ${getPositionCss(position)}`,
7998
+ children: content
7999
+ }
8000
+ )
7927
8001
  ] });
7928
8002
  };
7929
8003
  const MAX_NUMBER_OF_GRID_ROWS = 100;
@@ -7947,23 +8021,37 @@ const MutationsOverTimeGrid = ({ data }) => {
7947
8021
  gridTemplateRows: `repeat(${shownMutations.length}, 24px)`,
7948
8022
  gridTemplateColumns: `8rem repeat(${dates.length}, minmax(1.5rem, 1fr))`
7949
8023
  },
7950
- children: shownMutations.map((mutation, i2) => {
8024
+ children: shownMutations.map((mutation, rowIndex) => {
7951
8025
  return /* @__PURE__ */ u$1(Fragment, { children: [
7952
8026
  /* @__PURE__ */ u$1(
7953
8027
  "div",
7954
8028
  {
7955
- style: { gridRowStart: i2 + 1, gridColumnStart: 1 },
8029
+ style: { gridRowStart: rowIndex + 1, gridColumnStart: 1 },
7956
8030
  children: /* @__PURE__ */ u$1(MutationCell, { mutation })
7957
8031
  },
7958
8032
  `mutation-${mutation.toString()}`
7959
8033
  ),
7960
- dates.map((date, j2) => {
8034
+ dates.map((date, columnIndex) => {
7961
8035
  const value = data.get(mutation, date) ?? { proportion: 0, count: 0 };
8036
+ const tooltipPosition = getTooltipPosition(
8037
+ rowIndex,
8038
+ shownMutations.length,
8039
+ columnIndex,
8040
+ dates.length
8041
+ );
7962
8042
  return /* @__PURE__ */ u$1(
7963
8043
  "div",
7964
8044
  {
7965
- style: { gridRowStart: i2 + 1, gridColumnStart: j2 + 2 },
7966
- children: /* @__PURE__ */ u$1(ProportionCell, { value, date, mutation })
8045
+ style: { gridRowStart: rowIndex + 1, gridColumnStart: columnIndex + 2 },
8046
+ children: /* @__PURE__ */ u$1(
8047
+ ProportionCell,
8048
+ {
8049
+ value,
8050
+ date,
8051
+ mutation,
8052
+ tooltipPosition
8053
+ }
8054
+ )
7967
8055
  },
7968
8056
  `${mutation.toString()}-${date.toString()}`
7969
8057
  );
@@ -7974,7 +8062,12 @@ const MutationsOverTimeGrid = ({ data }) => {
7974
8062
  )
7975
8063
  ] });
7976
8064
  };
7977
- const ProportionCell = ({ value, mutation, date }) => {
8065
+ function getTooltipPosition(rowIndex, rows, columnIndex, columns) {
8066
+ const tooltipX = rowIndex < rows / 2 ? "bottom" : "top";
8067
+ const tooltipY = columnIndex < columns / 2 ? "start" : "end";
8068
+ return `${tooltipX}-${tooltipY}`;
8069
+ }
8070
+ const ProportionCell = ({ value, mutation, date, tooltipPosition }) => {
7978
8071
  const tooltipContent = /* @__PURE__ */ u$1("div", { children: [
7979
8072
  /* @__PURE__ */ u$1("p", { children: [
7980
8073
  /* @__PURE__ */ u$1("span", { className: "font-bold", children: date.englishName() }),
@@ -7992,7 +8085,7 @@ const ProportionCell = ({ value, mutation, date }) => {
7992
8085
  value.count
7993
8086
  ] })
7994
8087
  ] });
7995
- return /* @__PURE__ */ u$1(Fragment, { children: /* @__PURE__ */ u$1("div", { className: "py-1", children: /* @__PURE__ */ u$1(Tooltip, { content: tooltipContent, children: /* @__PURE__ */ u$1(
8088
+ return /* @__PURE__ */ u$1(Fragment, { children: /* @__PURE__ */ u$1("div", { className: "py-1", children: /* @__PURE__ */ u$1(Tooltip, { content: tooltipContent, position: tooltipPosition, children: /* @__PURE__ */ u$1(
7996
8089
  "div",
7997
8090
  {
7998
8091
  style: {
@@ -8241,7 +8334,8 @@ const MutationsOverTimeTabs = ({
8241
8334
  displayedMutationTypes,
8242
8335
  setDisplayedMutationTypes,
8243
8336
  proportionInterval,
8244
- setProportionInterval
8337
+ setProportionInterval,
8338
+ filteredData
8245
8339
  }
8246
8340
  );
8247
8341
  return /* @__PURE__ */ u$1(Tabs, { tabs, toolbar });
@@ -8252,7 +8346,8 @@ const Toolbar = ({
8252
8346
  displayedMutationTypes,
8253
8347
  setDisplayedMutationTypes,
8254
8348
  proportionInterval,
8255
- setProportionInterval
8349
+ setProportionInterval,
8350
+ filteredData
8256
8351
  }) => {
8257
8352
  return /* @__PURE__ */ u$1(Fragment, { children: [
8258
8353
  /* @__PURE__ */ u$1(SegmentSelector, { displayedSegments, setDisplayedSegments }),
@@ -8263,17 +8358,41 @@ const Toolbar = ({
8263
8358
  displayedMutationTypes
8264
8359
  }
8265
8360
  ),
8266
- /* @__PURE__ */ u$1(Fragment, { children: /* @__PURE__ */ u$1(
8361
+ /* @__PURE__ */ u$1(
8267
8362
  ProportionSelectorDropdown,
8268
8363
  {
8269
8364
  proportionInterval,
8270
8365
  setMinProportion: (min) => setProportionInterval((prev) => ({ ...prev, min })),
8271
8366
  setMaxProportion: (max) => setProportionInterval((prev) => ({ ...prev, max }))
8272
8367
  }
8273
- ) }),
8368
+ ),
8369
+ /* @__PURE__ */ u$1(
8370
+ CsvDownloadButton,
8371
+ {
8372
+ className: "mx-1 btn btn-xs",
8373
+ getData: () => getDownloadData(filteredData),
8374
+ filename: "mutations_over_time.csv"
8375
+ }
8376
+ ),
8274
8377
  /* @__PURE__ */ u$1(Info, { height: "100px", children: "Info for mutations over time" })
8275
8378
  ] });
8276
8379
  };
8380
+ function getDownloadData(filteredData) {
8381
+ const dates = filteredData.getSecondAxisKeys().sort((a2, b3) => compareTemporal(a2, b3));
8382
+ return filteredData.getFirstAxisKeys().map((mutation) => {
8383
+ return dates.reduce(
8384
+ (accumulated, date) => {
8385
+ var _a;
8386
+ const proportion = ((_a = filteredData.get(mutation, date)) == null ? void 0 : _a.proportion) ?? 0;
8387
+ return {
8388
+ ...accumulated,
8389
+ [date.toString()]: proportion
8390
+ };
8391
+ },
8392
+ { mutation: mutation.toString() }
8393
+ );
8394
+ });
8395
+ }
8277
8396
  var __defProp$5 = Object.defineProperty;
8278
8397
  var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
8279
8398
  var __decorateClass$5 = (decorators, target, key, kind) => {