@genspectrum/dashboard-components 0.6.10 → 0.6.12

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 (39) hide show
  1. package/dist/dashboard-components.js +1006 -618
  2. package/dist/dashboard-components.js.map +1 -1
  3. package/dist/genspectrum-components.d.ts +7 -7
  4. package/dist/style.css +147 -1
  5. package/package.json +2 -2
  6. package/src/preact/aggregatedData/aggregate.tsx +12 -4
  7. package/src/preact/components/checkbox-selector.stories.tsx +93 -11
  8. package/src/preact/components/checkbox-selector.tsx +19 -0
  9. package/src/preact/components/color-scale-selector-dropdown.tsx +5 -3
  10. package/src/preact/components/dropdown.tsx +3 -3
  11. package/src/preact/components/info.tsx +88 -1
  12. package/src/preact/components/mutation-type-selector.stories.tsx +115 -0
  13. package/src/preact/components/mutation-type-selector.tsx +33 -8
  14. package/src/preact/components/percent-input.stories.tsx +93 -0
  15. package/src/preact/components/percent-intput.tsx +4 -0
  16. package/src/preact/components/proportion-selector-dropdown.stories.tsx +2 -2
  17. package/src/preact/components/proportion-selector-dropdown.tsx +9 -7
  18. package/src/preact/components/proportion-selector.stories.tsx +4 -4
  19. package/src/preact/components/proportion-selector.tsx +46 -12
  20. package/src/preact/components/segment-selector.stories.tsx +151 -0
  21. package/src/preact/components/{SegmentSelector.tsx → segment-selector.tsx} +29 -20
  22. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +1 -1
  23. package/src/preact/mutationComparison/mutation-comparison.tsx +1 -1
  24. package/src/preact/mutationComparison/queryMutationData.ts +1 -1
  25. package/src/preact/mutations/mutations-grid.tsx +5 -1
  26. package/src/preact/mutations/mutations.tsx +33 -3
  27. package/src/preact/mutations/queryMutations.ts +1 -1
  28. package/src/preact/mutationsOverTime/getFilteredMutationsOverTime.spec.ts +4 -4
  29. package/src/preact/mutationsOverTime/getFilteredMutationsOverTimeData.ts +3 -2
  30. package/src/preact/mutationsOverTime/mutations-over-time.tsx +1 -1
  31. package/src/preact/numberSequencesOverTime/number-sequences-over-time.tsx +43 -8
  32. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +2 -1
  33. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +44 -53
  34. package/src/preact/useQuery.ts +1 -1
  35. package/src/query/queryMutationsOverTime.ts +3 -3
  36. package/src/utils/map2d.spec.ts +83 -22
  37. package/src/utils/map2d.ts +158 -0
  38. package/src/web-components/visualization/gs-prevalence-over-time.tsx +2 -4
  39. package/src/utils/Map2d.ts +0 -75
@@ -5025,7 +5025,7 @@ function P$1() {
5025
5025
  }
5026
5026
  function S$2(n3, l2, u2, t2, i3, o2, r2, f2, e3, c2, s6) {
5027
5027
  var a2, v2, y2, d2, w2, _2 = t2 && t2.__k || p$2, g2 = l2.length;
5028
- for (u2.__d = e3, $$1(u2, l2, _2), e3 = u2.__d, a2 = 0; a2 < g2; a2++) null != (y2 = u2.__k[a2]) && "boolean" != typeof y2 && "function" != typeof y2 && (v2 = -1 === y2.__i ? h$2 : _2[y2.__i] || h$2, y2.__i = a2, O$1(n3, y2, v2, i3, o2, r2, f2, e3, c2, s6), d2 = y2.__e, y2.ref && v2.ref != y2.ref && (v2.ref && N$1(v2.ref, null, y2), s6.push(y2.ref, y2.__c || d2, y2)), null == w2 && null != d2 && (w2 = d2), 65536 & y2.__u || v2.__k === y2.__k ? (e3 && "string" == typeof y2.type && !n3.contains(e3) && (e3 = x$2(v2)), e3 = I$1(y2, e3, n3)) : "function" == typeof y2.type && void 0 !== y2.__d ? e3 = y2.__d : d2 && (e3 = d2.nextSibling), y2.__d = void 0, y2.__u &= -196609);
5028
+ for (u2.__d = e3, $$1(u2, l2, _2), e3 = u2.__d, a2 = 0; a2 < g2; a2++) null != (y2 = u2.__k[a2]) && "boolean" != typeof y2 && "function" != typeof y2 && (v2 = -1 === y2.__i ? h$2 : _2[y2.__i] || h$2, y2.__i = a2, O$1(n3, y2, v2, i3, o2, r2, f2, e3, c2, s6), d2 = y2.__e, y2.ref && v2.ref != y2.ref && (v2.ref && N$1(v2.ref, null, y2), s6.push(y2.ref, y2.__c || d2, y2)), null == w2 && null != d2 && (w2 = d2), 65536 & y2.__u || v2.__k === y2.__k ? e3 = I$1(y2, e3, n3) : "function" == typeof y2.type && void 0 !== y2.__d ? e3 = y2.__d : d2 && (e3 = d2.nextSibling), y2.__d = void 0, y2.__u &= -196609);
5029
5029
  u2.__d = e3, u2.__e = w2;
5030
5030
  }
5031
5031
  function $$1(n3, l2, u2) {
@@ -5039,7 +5039,7 @@ function I$1(n3, l2, u2) {
5039
5039
  for (t2 = n3.__k, i3 = 0; t2 && i3 < t2.length; i3++) t2[i3] && (t2[i3].__ = n3, l2 = I$1(t2[i3], l2, u2));
5040
5040
  return l2;
5041
5041
  }
5042
- n3.__e != l2 && (u2.insertBefore(n3.__e, l2 || null), l2 = n3.__e);
5042
+ n3.__e != l2 && (l2 && n3.type && !u2.contains(l2) && (l2 = x$2(n3)), u2.insertBefore(n3.__e, l2 || null), l2 = n3.__e);
5043
5043
  do {
5044
5044
  l2 = l2 && l2.nextSibling;
5045
5045
  } while (null != l2 && 8 === l2.nodeType);
@@ -5117,7 +5117,11 @@ function O$1(n3, u2, t2, i3, o2, r2, f2, e3, c2, s6) {
5117
5117
  } while (h3.__d && ++I3 < 25);
5118
5118
  h3.state = h3.__s, null != h3.getChildContext && (i3 = d$2(d$2({}, i3), h3.getChildContext())), x2 && !p2 && null != h3.getSnapshotBeforeUpdate && (_2 = h3.getSnapshotBeforeUpdate(v2, w2)), S$2(n3, y$2(L3 = null != a2 && a2.type === k$1 && null == a2.key ? a2.props.children : a2) ? L3 : [L3], u2, t2, i3, o2, r2, f2, e3, c2, s6), h3.base = u2.__e, u2.__u &= -161, h3.__h.length && f2.push(h3), g2 && (h3.__E = h3.__ = null);
5119
5119
  } catch (n4) {
5120
- u2.__v = null, c2 || null != r2 ? (u2.__e = e3, u2.__u |= c2 ? 160 : 32, r2[r2.indexOf(e3)] = null) : (u2.__e = t2.__e, u2.__k = t2.__k), l$2.__e(n4, u2, t2);
5120
+ if (u2.__v = null, c2 || null != r2) {
5121
+ for (u2.__u |= c2 ? 160 : 32; e3 && 8 === e3.nodeType && e3.nextSibling; ) e3 = e3.nextSibling;
5122
+ r2[r2.indexOf(e3)] = null, u2.__e = e3;
5123
+ } else u2.__e = t2.__e, u2.__k = t2.__k;
5124
+ l$2.__e(n4, u2, t2);
5121
5125
  }
5122
5126
  else null == r2 && u2.__v === t2.__v ? (u2.__k = t2.__k, u2.__e = t2.__e) : u2.__e = z$2(t2.__e, u2, t2, i3, o2, r2, f2, c2, s6);
5123
5127
  (a2 = l$2.diffed) && a2(u2);
@@ -5165,7 +5169,10 @@ function z$2(l2, u2, t2, i3, o2, r2, f2, e3, c2) {
5165
5169
  }
5166
5170
  function N$1(n3, u2, t2) {
5167
5171
  try {
5168
- "function" == typeof n3 ? n3(u2) : n3.current = u2;
5172
+ if ("function" == typeof n3) {
5173
+ var i3 = "function" == typeof n3.__u;
5174
+ i3 && n3.__u(), i3 && null == u2 || (n3.__u = n3(u2));
5175
+ } else n3.current = u2;
5169
5176
  } catch (n4) {
5170
5177
  l$2.__e(n4, t2);
5171
5178
  }
@@ -25870,6 +25877,242 @@ function filterBySegmentAndMutationType(data, displayedSegments, displayedMutati
25870
25877
  return data.filter(byDisplayedSegments).filter(byDisplayedMutationTypes);
25871
25878
  }
25872
25879
  const LapisUrlContext = G$1("");
25880
+ const CsvDownloadButton = ({
25881
+ label = "Download",
25882
+ filename = "data.csv",
25883
+ getData,
25884
+ className
25885
+ }) => {
25886
+ const download = () => {
25887
+ const content = getDownloadContent();
25888
+ const blob = new Blob([content], { type: "text/csv" });
25889
+ const url = URL.createObjectURL(blob);
25890
+ const a2 = document.createElement("a");
25891
+ a2.href = url;
25892
+ a2.download = filename;
25893
+ a2.click();
25894
+ URL.revokeObjectURL(url);
25895
+ };
25896
+ const getDownloadContent = () => {
25897
+ const data = getData();
25898
+ const keys = getDataKeys(data);
25899
+ const header = `${keys.join(",")}
25900
+ `;
25901
+ const rows = data.map((row) => keys.map((key) => row[key]).join(",")).join("\n");
25902
+ return header + rows;
25903
+ };
25904
+ const getDataKeys = (data) => {
25905
+ const keysSet = data.map((row) => Object.keys(row)).reduce((accumulatedKeys, keys) => {
25906
+ keys.forEach((key) => accumulatedKeys.add(key));
25907
+ return accumulatedKeys;
25908
+ }, /* @__PURE__ */ new Set());
25909
+ return [...keysSet];
25910
+ };
25911
+ return /* @__PURE__ */ u$2("button", { className, onClick: download, children: label });
25912
+ };
25913
+ class UserFacingError extends Error {
25914
+ constructor(headline, message) {
25915
+ super(message);
25916
+ this.headline = headline;
25917
+ this.name = "UserFacingError";
25918
+ }
25919
+ }
25920
+ const ErrorDisplay = ({ error }) => {
25921
+ console.error(error);
25922
+ const ref = A$1(null);
25923
+ return /* @__PURE__ */ u$2("div", { className: "h-full w-full rounded-md border-2 border-gray-100 p-2 flex items-center justify-center flex-col", children: [
25924
+ /* @__PURE__ */ u$2("div", { className: "text-red-700 font-bold", children: "Error" }),
25925
+ /* @__PURE__ */ u$2("div", { children: [
25926
+ "Oops! Something went wrong.",
25927
+ error instanceof UserFacingError && /* @__PURE__ */ u$2(k$1, { children: [
25928
+ " ",
25929
+ /* @__PURE__ */ u$2(
25930
+ "button",
25931
+ {
25932
+ className: "text-sm text-gray-600 hover:text-gray-300",
25933
+ onClick: () => {
25934
+ var _a2;
25935
+ return (_a2 = ref.current) == null ? void 0 : _a2.showModal();
25936
+ },
25937
+ children: "Show details."
25938
+ }
25939
+ ),
25940
+ /* @__PURE__ */ u$2("dialog", { ref, class: "modal", children: [
25941
+ /* @__PURE__ */ u$2("div", { class: "modal-box", children: [
25942
+ /* @__PURE__ */ u$2("form", { method: "dialog", children: /* @__PURE__ */ u$2("button", { className: "btn btn-sm btn-circle btn-ghost absolute right-2 top-2", children: "✕" }) }),
25943
+ /* @__PURE__ */ u$2("h1", { class: "text-lg", children: error.headline }),
25944
+ /* @__PURE__ */ u$2("p", { class: "py-4", children: error.message })
25945
+ ] }),
25946
+ /* @__PURE__ */ u$2("form", { method: "dialog", class: "modal-backdrop", children: /* @__PURE__ */ u$2("button", { children: "close" }) })
25947
+ ] })
25948
+ ] })
25949
+ ] })
25950
+ ] });
25951
+ };
25952
+ const ResizeContainer = ({ children, size }) => {
25953
+ return /* @__PURE__ */ u$2("div", { style: size, className: "bg-white", children });
25954
+ };
25955
+ const ErrorBoundary = ({ size, children }) => {
25956
+ const [internalError] = b$1();
25957
+ if (internalError) {
25958
+ return /* @__PURE__ */ u$2(ResizeContainer, { size, children: /* @__PURE__ */ u$2(ErrorDisplay, { error: internalError }) });
25959
+ }
25960
+ return /* @__PURE__ */ u$2(k$1, { children });
25961
+ };
25962
+ const Fullscreen = () => {
25963
+ const element = A$1(null);
25964
+ const isFullscreen = useFullscreenStatus();
25965
+ return /* @__PURE__ */ u$2(
25966
+ "button",
25967
+ {
25968
+ ref: element,
25969
+ onClick: async () => {
25970
+ if (element.current) {
25971
+ if (isFullscreen) {
25972
+ await document.exitFullscreen();
25973
+ } else {
25974
+ const componentRoot = findComponentRoot(element.current);
25975
+ if (componentRoot) {
25976
+ await componentRoot.requestFullscreen();
25977
+ }
25978
+ }
25979
+ }
25980
+ },
25981
+ className: `mt-0.5 iconify text-2xl ${isFullscreen ? "mdi--fullscreen-exit hover:scale-90" : "mdi--fullscreen hover:scale-110"}`,
25982
+ title: isFullscreen ? "Exit fullscreen" : "Enter fullscreen"
25983
+ }
25984
+ );
25985
+ };
25986
+ function findComponentRoot(element) {
25987
+ var _a2;
25988
+ return (_a2 = findShadowRoot(element)) == null ? void 0 : _a2.children[0];
25989
+ }
25990
+ function findShadowRoot(element) {
25991
+ let current = element;
25992
+ while (current) {
25993
+ if (current instanceof ShadowRoot) {
25994
+ return current;
25995
+ }
25996
+ if (current.parentNode === null) {
25997
+ return null;
25998
+ }
25999
+ current = current.parentNode;
26000
+ }
26001
+ return null;
26002
+ }
26003
+ function useFullscreenStatus() {
26004
+ const [isFullscreen, setIsFullscreen] = h$1(document.fullscreenElement !== null);
26005
+ y$1(() => {
26006
+ const handleFullscreenChange = () => {
26007
+ setIsFullscreen(document.fullscreenElement !== null);
26008
+ };
26009
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
26010
+ return () => {
26011
+ document.removeEventListener("fullscreenchange", handleFullscreenChange);
26012
+ };
26013
+ }, []);
26014
+ return isFullscreen;
26015
+ }
26016
+ const Info = ({ children }) => {
26017
+ const dialogRef = A$1(null);
26018
+ const toggleHelp = () => {
26019
+ var _a2;
26020
+ (_a2 = dialogRef.current) == null ? void 0 : _a2.showModal();
26021
+ };
26022
+ return /* @__PURE__ */ u$2("div", { className: "relative", children: [
26023
+ /* @__PURE__ */ u$2("button", { type: "button", className: "btn btn-xs", onClick: toggleHelp, children: "?" }),
26024
+ /* @__PURE__ */ u$2("dialog", { ref: dialogRef, className: "modal modal-bottom sm:modal-middle", children: [
26025
+ /* @__PURE__ */ u$2("div", { className: "modal-box sm:max-w-5xl", children: [
26026
+ /* @__PURE__ */ u$2("form", { method: "dialog", children: /* @__PURE__ */ u$2("button", { className: "btn btn-sm btn-circle btn-ghost absolute right-2 top-2", children: "✕" }) }),
26027
+ /* @__PURE__ */ u$2("div", { className: "flex flex-col", children }),
26028
+ /* @__PURE__ */ u$2("div", { className: "modal-action", children: /* @__PURE__ */ u$2("form", { method: "dialog", children: /* @__PURE__ */ u$2("button", { className: "float-right underline text-sm hover:text-blue-700 mr-2", children: "Close" }) }) })
26029
+ ] }),
26030
+ /* @__PURE__ */ u$2("form", { method: "dialog", className: "modal-backdrop", children: /* @__PURE__ */ u$2("button", { children: "Helper to close when clicked outside" }) })
26031
+ ] })
26032
+ ] });
26033
+ };
26034
+ const InfoHeadline1 = ({ children }) => {
26035
+ return /* @__PURE__ */ u$2("h1", { className: "text-lg font-bold", children });
26036
+ };
26037
+ const InfoHeadline2 = ({ children }) => {
26038
+ return /* @__PURE__ */ u$2("h2", { className: "text-base font-bold mt-4", children });
26039
+ };
26040
+ const InfoParagraph = ({ children }) => {
26041
+ return /* @__PURE__ */ u$2("p", { className: "text-justify my-1", children });
26042
+ };
26043
+ const InfoLink = ({ children, href }) => {
26044
+ return /* @__PURE__ */ u$2("a", { className: "text-blue-600 hover:text-blue-800", href, target: "_blank", rel: "noopener noreferrer", children });
26045
+ };
26046
+ const InfoComponentCode = ({ componentName, params, lapisUrl }) => {
26047
+ const componentCode = componentParametersToCode(componentName, params, lapisUrl);
26048
+ const codePenData = {
26049
+ title: "GenSpectrum dashboard component",
26050
+ html: generateFullExampleCode(componentCode, componentName),
26051
+ layout: "left",
26052
+ editors: "100"
26053
+ };
26054
+ return /* @__PURE__ */ u$2(k$1, { children: [
26055
+ /* @__PURE__ */ u$2(InfoHeadline2, { children: "Use this component yourself" }),
26056
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
26057
+ "This component was created using the following parameters:",
26058
+ /* @__PURE__ */ u$2("div", { className: "p-4 border border-gray-200 rounded-lg overflow-x-auto", children: /* @__PURE__ */ u$2("pre", { children: /* @__PURE__ */ u$2("code", { children: componentCode }) }) })
26059
+ ] }),
26060
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
26061
+ "You can add this component to your own website using the",
26062
+ " ",
26063
+ /* @__PURE__ */ u$2(InfoLink, { href: "https://github.com/GenSpectrum/dashboard-components", children: "GenSpectrum dashboard components library" }),
26064
+ " ",
26065
+ "and the code from above."
26066
+ ] }),
26067
+ /* @__PURE__ */ u$2(InfoParagraph, { children: /* @__PURE__ */ u$2("form", { action: "https://codepen.io/pen/define", method: "POST", target: "_blank", children: [
26068
+ /* @__PURE__ */ u$2(
26069
+ "input",
26070
+ {
26071
+ type: "hidden",
26072
+ name: "data",
26073
+ value: JSON.stringify(codePenData).replace(/"/g, "&quot;").replace(/'/g, "&apos;")
26074
+ }
26075
+ ),
26076
+ /* @__PURE__ */ u$2("button", { className: "text-blue-600 hover:text-blue-800", type: "submit", children: "Click here to try it out on CodePen." })
26077
+ ] }) })
26078
+ ] });
26079
+ };
26080
+ function componentParametersToCode(componentName, params, lapisUrl) {
26081
+ const stringifyIfNeeded = (value) => {
26082
+ return typeof value === "object" ? JSON.stringify(value) : value;
26083
+ };
26084
+ const attributes = indentLines(
26085
+ Object.entries(params).map(([key, value]) => `${key}='${stringifyIfNeeded(value)}'`).join("\n"),
26086
+ 4
26087
+ );
26088
+ return `<gs-app lapis="${lapisUrl}">
26089
+ <gs-${componentName}
26090
+ ${attributes}
26091
+ />
26092
+ </gs-app>`;
26093
+ }
26094
+ function generateFullExampleCode(componentCode, componentName) {
26095
+ const storyBookPath = `/docs/visualization-${componentName}--docs`;
26096
+ return `<html>
26097
+ <head>
26098
+ <script type="module" src="https://unpkg.com/@genspectrum/dashboard-components@latest/dist/dashboard-components.js"><\/script>
26099
+ <link rel="stylesheet" href="https://unpkg.com/@genspectrum/dashboard-components@latest/dist/style.css" />
26100
+ </head>
26101
+
26102
+ <body>
26103
+ <!-- Component documentation: https://genspectrum.github.io/dashboard-components/?path=${storyBookPath} -->
26104
+ ${indentLines(componentCode, 2)}
26105
+ </body>
26106
+ </html>
26107
+ `;
26108
+ }
26109
+ function indentLines(text, numberSpaces) {
26110
+ const spaces = " ".repeat(numberSpaces);
26111
+ return text.split("\n").map((line) => spaces + line).join("\n");
26112
+ }
26113
+ const LoadingDisplay = () => {
26114
+ return /* @__PURE__ */ u$2("div", { "aria-label": "Loading", className: "h-full w-full skeleton" });
26115
+ };
25873
26116
  const min = Math.min;
25874
26117
  const max = Math.max;
25875
26118
  const round = Math.round;
@@ -27181,8 +27424,8 @@ const Dropdown = ({ children, buttonTitle, placement }) => {
27181
27424
  const toggle = () => {
27182
27425
  setShowContent(!showContent);
27183
27426
  };
27184
- return /* @__PURE__ */ u$2("div", { children: [
27185
- /* @__PURE__ */ u$2("button", { type: "button", className: "btn btn-xs whitespace-nowrap", onClick: toggle, ref: referenceRef, children: buttonTitle }),
27427
+ return /* @__PURE__ */ u$2(k$1, { children: [
27428
+ /* @__PURE__ */ u$2("button", { type: "button", className: "btn btn-xs whitespace-nowrap w-full", onClick: toggle, ref: referenceRef, children: buttonTitle }),
27186
27429
  /* @__PURE__ */ u$2("div", { ref: floatingRef, className: `${dropdownClass} ${showContent ? "" : "hidden"}`, children })
27187
27430
  ] });
27188
27431
  };
@@ -27191,245 +27434,81 @@ const CheckboxSelector = ({
27191
27434
  label,
27192
27435
  setItems
27193
27436
  }) => {
27194
- return /* @__PURE__ */ u$2(Dropdown, { buttonTitle: label, placement: "bottom-start", children: /* @__PURE__ */ u$2("ul", { children: items.map((item, index2) => /* @__PURE__ */ u$2("li", { className: "flex flex-row items-center", children: /* @__PURE__ */ u$2("label", { children: [
27437
+ return /* @__PURE__ */ u$2(Dropdown, { buttonTitle: label, placement: "bottom-start", children: [
27195
27438
  /* @__PURE__ */ u$2(
27196
- "input",
27439
+ "button",
27197
27440
  {
27198
- className: "mr-2",
27199
- type: "checkbox",
27200
- id: `item-${index2}`,
27201
- checked: item.checked,
27202
- onChange: () => {
27203
- const newItems = items.map(
27204
- (item2, i3) => i3 === index2 ? { ...item2, checked: !item2.checked } : item2
27205
- );
27441
+ className: "btn btn-xs btn-ghost",
27442
+ onClick: () => {
27443
+ const newItems = items.map((item) => ({ ...item, checked: true }));
27206
27444
  setItems(newItems);
27207
- }
27445
+ },
27446
+ children: "Select all"
27208
27447
  }
27209
27448
  ),
27210
- item.label
27211
- ] }) }, item.label)) }) });
27212
- };
27213
- const ReferenceGenomeContext = G$1({ nucleotideSequences: [], genes: [] });
27214
- const getSegmentSelectorLabel = (displayedSegments, prefix) => {
27215
- const allSelectedSelected = displayedSegments.filter((segment) => segment.checked).map((segment) => segment.segment);
27216
- if (allSelectedSelected.length === 0) {
27217
- return `${prefix}none`;
27218
- }
27219
- if (displayedSegments.length === allSelectedSelected.length) {
27220
- return `${prefix}all`;
27221
- }
27222
- return prefix + allSelectedSelected.join(", ");
27449
+ /* @__PURE__ */ u$2(
27450
+ "button",
27451
+ {
27452
+ className: "btn btn-xs btn-ghost",
27453
+ onClick: () => {
27454
+ const newItems = items.map((item) => ({ ...item, checked: false }));
27455
+ setItems(newItems);
27456
+ },
27457
+ children: "Select none"
27458
+ }
27459
+ ),
27460
+ /* @__PURE__ */ u$2("div", { className: "divider mt-0 mb-0" }),
27461
+ /* @__PURE__ */ u$2("ul", { children: items.map((item, index2) => /* @__PURE__ */ u$2("li", { className: "flex flex-row items-center", children: /* @__PURE__ */ u$2("label", { children: [
27462
+ /* @__PURE__ */ u$2(
27463
+ "input",
27464
+ {
27465
+ className: "mr-2",
27466
+ type: "checkbox",
27467
+ id: `item-${index2}`,
27468
+ checked: item.checked,
27469
+ onChange: () => {
27470
+ const newItems = items.map(
27471
+ (item2, i3) => i3 === index2 ? { ...item2, checked: !item2.checked } : item2
27472
+ );
27473
+ setItems(newItems);
27474
+ }
27475
+ }
27476
+ ),
27477
+ item.label
27478
+ ] }) }, item.label)) })
27479
+ ] });
27223
27480
  };
27224
- const SegmentSelector = ({
27225
- displayedSegments,
27226
- setDisplayedSegments,
27227
- prefix
27481
+ const MutationTypeSelector = ({
27482
+ displayedMutationTypes,
27483
+ setDisplayedMutationTypes
27228
27484
  }) => {
27229
- if (displayedSegments.length <= 1) {
27230
- return null;
27231
- }
27232
- return /* @__PURE__ */ u$2(
27485
+ return /* @__PURE__ */ u$2("div", { className: "w-[6rem]", children: /* @__PURE__ */ u$2(
27233
27486
  CheckboxSelector,
27234
27487
  {
27235
- items: displayedSegments,
27236
- label: getSegmentSelectorLabel(displayedSegments, prefix || "Segments: "),
27237
- setItems: (items) => setDisplayedSegments(items)
27488
+ items: displayedMutationTypes,
27489
+ label: getMutationTypesSelectorLabel(displayedMutationTypes),
27490
+ setItems: (items) => setDisplayedMutationTypes(items)
27238
27491
  }
27239
- );
27492
+ ) });
27240
27493
  };
27241
- function useDisplayedSegments(sequenceType) {
27242
- const referenceGenome = x$1(ReferenceGenomeContext);
27243
- const displayedSegments = getSegmentNames(referenceGenome, sequenceType).map((segment) => ({
27244
- segment,
27245
- label: segment,
27246
- checked: true
27247
- }));
27248
- return h$1(displayedSegments);
27249
- }
27250
- const CsvDownloadButton = ({
27251
- label = "Download",
27252
- filename = "data.csv",
27253
- getData,
27254
- className
27255
- }) => {
27256
- const download = () => {
27257
- const content = getDownloadContent();
27258
- const blob = new Blob([content], { type: "text/csv" });
27259
- const url = URL.createObjectURL(blob);
27260
- const a2 = document.createElement("a");
27261
- a2.href = url;
27262
- a2.download = filename;
27263
- a2.click();
27264
- URL.revokeObjectURL(url);
27265
- };
27266
- const getDownloadContent = () => {
27267
- const data = getData();
27268
- const keys = getDataKeys(data);
27269
- const header = `${keys.join(",")}
27270
- `;
27271
- const rows = data.map((row) => keys.map((key) => row[key]).join(",")).join("\n");
27272
- return header + rows;
27273
- };
27274
- const getDataKeys = (data) => {
27275
- const keysSet = data.map((row) => Object.keys(row)).reduce((accumulatedKeys, keys) => {
27276
- keys.forEach((key) => accumulatedKeys.add(key));
27277
- return accumulatedKeys;
27278
- }, /* @__PURE__ */ new Set());
27279
- return [...keysSet];
27280
- };
27281
- return /* @__PURE__ */ u$2("button", { className, onClick: download, children: label });
27282
- };
27283
- class UserFacingError extends Error {
27284
- constructor(headline, message) {
27285
- super(message);
27286
- this.headline = headline;
27287
- this.name = "UserFacingError";
27288
- }
27289
- }
27290
- const ErrorDisplay = ({ error }) => {
27291
- console.error(error);
27292
- const ref = A$1(null);
27293
- return /* @__PURE__ */ u$2("div", { className: "h-full w-full rounded-md border-2 border-gray-100 p-2 flex items-center justify-center flex-col", children: [
27294
- /* @__PURE__ */ u$2("div", { className: "text-red-700 font-bold", children: "Error" }),
27295
- /* @__PURE__ */ u$2("div", { children: [
27296
- "Oops! Something went wrong.",
27297
- error instanceof UserFacingError && /* @__PURE__ */ u$2(k$1, { children: [
27298
- " ",
27299
- /* @__PURE__ */ u$2(
27300
- "button",
27301
- {
27302
- className: "text-sm text-gray-600 hover:text-gray-300",
27303
- onClick: () => {
27304
- var _a2;
27305
- return (_a2 = ref.current) == null ? void 0 : _a2.showModal();
27306
- },
27307
- children: "Show details."
27308
- }
27309
- ),
27310
- /* @__PURE__ */ u$2("dialog", { ref, class: "modal", children: [
27311
- /* @__PURE__ */ u$2("div", { class: "modal-box", children: [
27312
- /* @__PURE__ */ u$2("form", { method: "dialog", children: /* @__PURE__ */ u$2("button", { className: "btn btn-sm btn-circle btn-ghost absolute right-2 top-2", children: "✕" }) }),
27313
- /* @__PURE__ */ u$2("h1", { class: "text-lg", children: error.headline }),
27314
- /* @__PURE__ */ u$2("p", { class: "py-4", children: error.message })
27315
- ] }),
27316
- /* @__PURE__ */ u$2("form", { method: "dialog", class: "modal-backdrop", children: /* @__PURE__ */ u$2("button", { children: "close" }) })
27317
- ] })
27318
- ] })
27319
- ] })
27320
- ] });
27321
- };
27322
- const ResizeContainer = ({ children, size }) => {
27323
- return /* @__PURE__ */ u$2("div", { style: size, className: "bg-white", children });
27324
- };
27325
- const ErrorBoundary = ({ size, children }) => {
27326
- const [internalError] = b$1();
27327
- if (internalError) {
27328
- return /* @__PURE__ */ u$2(ResizeContainer, { size, children: /* @__PURE__ */ u$2(ErrorDisplay, { error: internalError }) });
27494
+ const getMutationTypesSelectorLabel = (displayedMutationTypes) => {
27495
+ const checkedLabels = displayedMutationTypes.filter((displayedMutationType) => displayedMutationType.checked);
27496
+ if (checkedLabels.length === 0) {
27497
+ return `No types`;
27329
27498
  }
27330
- return /* @__PURE__ */ u$2(k$1, { children });
27331
- };
27332
- const Fullscreen = () => {
27333
- const element = A$1(null);
27334
- const isFullscreen = useFullscreenStatus();
27335
- return /* @__PURE__ */ u$2(
27336
- "button",
27337
- {
27338
- ref: element,
27339
- onClick: async () => {
27340
- if (element.current) {
27341
- if (isFullscreen) {
27342
- await document.exitFullscreen();
27343
- } else {
27344
- const componentRoot = findComponentRoot(element.current);
27345
- if (componentRoot) {
27346
- await componentRoot.requestFullscreen();
27347
- }
27348
- }
27349
- }
27350
- },
27351
- className: `mt-0.5 iconify text-2xl ${isFullscreen ? "mdi--fullscreen-exit hover:scale-90" : "mdi--fullscreen hover:scale-110"}`,
27352
- title: isFullscreen ? "Exit fullscreen" : "Enter fullscreen"
27353
- }
27354
- );
27355
- };
27356
- function findComponentRoot(element) {
27357
- var _a2;
27358
- return (_a2 = findShadowRoot(element)) == null ? void 0 : _a2.children[0];
27359
- }
27360
- function findShadowRoot(element) {
27361
- let current = element;
27362
- while (current) {
27363
- if (current instanceof ShadowRoot) {
27364
- return current;
27365
- }
27366
- if (current.parentNode === null) {
27367
- return null;
27368
- }
27369
- current = current.parentNode;
27499
+ if (displayedMutationTypes.length === checkedLabels.length) {
27500
+ return displayedMutationTypes.map((type) => {
27501
+ switch (type.type) {
27502
+ case "substitution":
27503
+ return "Subst.";
27504
+ case "deletion":
27505
+ return "Del.";
27506
+ }
27507
+ }).join(", ");
27370
27508
  }
27371
- return null;
27372
- }
27373
- function useFullscreenStatus() {
27374
- const [isFullscreen, setIsFullscreen] = h$1(document.fullscreenElement !== null);
27375
- y$1(() => {
27376
- const handleFullscreenChange = () => {
27377
- setIsFullscreen(document.fullscreenElement !== null);
27378
- };
27379
- document.addEventListener("fullscreenchange", handleFullscreenChange);
27380
- return () => {
27381
- document.removeEventListener("fullscreenchange", handleFullscreenChange);
27382
- };
27383
- }, []);
27384
- return isFullscreen;
27385
- }
27386
- const Info = ({ children }) => {
27387
- const dialogRef = A$1(null);
27388
- const toggleHelp = () => {
27389
- var _a2;
27390
- (_a2 = dialogRef.current) == null ? void 0 : _a2.showModal();
27391
- };
27392
- return /* @__PURE__ */ u$2("div", { className: "relative", children: [
27393
- /* @__PURE__ */ u$2("button", { type: "button", className: "btn btn-xs", onClick: toggleHelp, children: "?" }),
27394
- /* @__PURE__ */ u$2("dialog", { ref: dialogRef, className: "modal modal-bottom sm:modal-middle", children: [
27395
- /* @__PURE__ */ u$2("div", { className: "modal-box", children: [
27396
- /* @__PURE__ */ u$2("form", { method: "dialog", children: /* @__PURE__ */ u$2("button", { className: "btn btn-sm btn-circle btn-ghost absolute right-2 top-2", children: "✕" }) }),
27397
- /* @__PURE__ */ u$2("div", { className: "flex flex-col", children }),
27398
- /* @__PURE__ */ u$2("div", { className: "modal-action", children: /* @__PURE__ */ u$2("form", { method: "dialog", children: /* @__PURE__ */ u$2("button", { className: "float-right underline text-sm hover:text-blue-700 mr-2", children: "Close" }) }) })
27399
- ] }),
27400
- /* @__PURE__ */ u$2("form", { method: "dialog", className: "modal-backdrop", children: /* @__PURE__ */ u$2("button", { children: "Helper to close when clicked outside" }) })
27401
- ] })
27402
- ] });
27403
- };
27404
- const InfoHeadline1 = ({ children }) => {
27405
- return /* @__PURE__ */ u$2("h1", { className: "text-lg font-bold", children });
27406
- };
27407
- const InfoHeadline2 = ({ children }) => {
27408
- return /* @__PURE__ */ u$2("h2", { className: "text-base font-bold mt-4", children });
27409
- };
27410
- const InfoParagraph = ({ children }) => {
27411
- return /* @__PURE__ */ u$2("p", { className: "text-justify my-1", children });
27412
- };
27413
- const InfoLink = ({ children, href }) => {
27414
- return /* @__PURE__ */ u$2("a", { className: "text-blue-600 hover:text-blue-800", href, target: "_blank", rel: "noopener noreferrer", children });
27415
- };
27416
- const LoadingDisplay = () => {
27417
- return /* @__PURE__ */ u$2("div", { "aria-label": "Loading", className: "h-full w-full skeleton" });
27418
- };
27419
- const MutationTypeSelector = ({
27420
- displayedMutationTypes,
27421
- setDisplayedMutationTypes
27422
- }) => {
27423
- const checkedLabels = displayedMutationTypes.filter((type) => type.checked).map((type) => type.label);
27424
- const mutationTypesSelectorLabel = `Types: ${checkedLabels.length > 0 ? checkedLabels.join(", ") : "None"}`;
27425
- return /* @__PURE__ */ u$2(
27426
- CheckboxSelector,
27427
- {
27428
- items: displayedMutationTypes,
27429
- label: mutationTypesSelectorLabel,
27430
- setItems: (items) => setDisplayedMutationTypes(items)
27431
- }
27432
- );
27509
+ return checkedLabels.map((type) => {
27510
+ return type.label;
27511
+ }).join(", ");
27433
27512
  };
27434
27513
  const NoDataDisplay = () => {
27435
27514
  return /* @__PURE__ */ u$2("div", { className: "h-full w-full rounded-md border-2 border-gray-100 p-2 flex items-center justify-center", children: /* @__PURE__ */ u$2("div", { children: "No data available." }) });
@@ -27521,6 +27600,9 @@ const PercentInput = ({ percentage, setPercentage }) => {
27521
27600
  const handleInputChange = (event) => {
27522
27601
  const input = event.target;
27523
27602
  const value = Number(input.value);
27603
+ if (value === internalPercentage || input.value === "") {
27604
+ return;
27605
+ }
27524
27606
  const inRange2 = percentageInRange(value);
27525
27607
  if (inRange2) {
27526
27608
  setPercentage(value);
@@ -27545,37 +27627,51 @@ const PercentInput = ({ percentage, setPercentage }) => {
27545
27627
  "%"
27546
27628
  ] });
27547
27629
  };
27630
+ function useUpdateExternalValueInIntervals(setExternalValue, updateIntervalInMs, internalValue) {
27631
+ const hasMounted = A$1(false);
27632
+ y$1(() => {
27633
+ if (!hasMounted.current) {
27634
+ hasMounted.current = true;
27635
+ return;
27636
+ }
27637
+ const minTimeout = setTimeout(() => {
27638
+ setExternalValue(internalValue);
27639
+ }, updateIntervalInMs);
27640
+ return () => clearTimeout(minTimeout);
27641
+ }, [internalValue]);
27642
+ }
27548
27643
  const ProportionSelector = ({
27549
27644
  proportionInterval,
27550
27645
  setMinProportion,
27551
27646
  setMaxProportion
27552
27647
  }) => {
27648
+ const updateIntervalInMs = 300;
27553
27649
  const { min: minProportion, max: maxProportion } = proportionInterval;
27650
+ const [internalMinProportion, setInternalMinProportion] = h$1(minProportion);
27651
+ const [internalMaxProportion, setInternalMaxProportion] = h$1(maxProportion);
27652
+ useUpdateExternalValueInIntervals(setMinProportion, updateIntervalInMs, internalMinProportion);
27653
+ const updateMinPercentage = (minPercentage) => {
27654
+ const newMinProportion = minPercentage / 100;
27655
+ setInternalMinProportion(newMinProportion);
27656
+ };
27657
+ useUpdateExternalValueInIntervals(setMaxProportion, updateIntervalInMs, internalMaxProportion);
27658
+ const updateMaxPercentage = (maxPercentage) => {
27659
+ const newMaxProportion = maxPercentage / 100;
27660
+ setInternalMaxProportion(newMaxProportion);
27661
+ };
27554
27662
  return /* @__PURE__ */ u$2("div", { class: "flex flex-col w-64 mb-2", children: [
27555
27663
  /* @__PURE__ */ u$2("div", { class: "flex items-center ", children: [
27556
- /* @__PURE__ */ u$2(
27557
- PercentInput,
27558
- {
27559
- percentage: minProportion * 100,
27560
- setPercentage: (percentage) => setMinProportion(percentage / 100)
27561
- }
27562
- ),
27664
+ /* @__PURE__ */ u$2(PercentInput, { percentage: internalMinProportion * 100, setPercentage: updateMinPercentage }),
27563
27665
  /* @__PURE__ */ u$2("div", { class: "m-2", children: "-" }),
27564
- /* @__PURE__ */ u$2(
27565
- PercentInput,
27566
- {
27567
- percentage: maxProportion * 100,
27568
- setPercentage: (percentage) => setMaxProportion(percentage / 100)
27569
- }
27570
- )
27666
+ /* @__PURE__ */ u$2(PercentInput, { percentage: internalMaxProportion * 100, setPercentage: updateMaxPercentage })
27571
27667
  ] }),
27572
27668
  /* @__PURE__ */ u$2("div", { class: "my-1", children: /* @__PURE__ */ u$2(
27573
27669
  MinMaxRangeSlider,
27574
27670
  {
27575
- min: minProportion * 100,
27576
- max: maxProportion * 100,
27577
- setMin: (percentage) => setMinProportion(percentage / 100),
27578
- setMax: (percentage) => setMaxProportion(percentage / 100)
27671
+ min: internalMinProportion * 100,
27672
+ max: internalMaxProportion * 100,
27673
+ setMin: updateMinPercentage,
27674
+ setMax: updateMaxPercentage
27579
27675
  }
27580
27676
  ) })
27581
27677
  ] });
@@ -27586,15 +27682,56 @@ const ProportionSelectorDropdown = ({
27586
27682
  setMaxProportion
27587
27683
  }) => {
27588
27684
  const label = `${(proportionInterval.min * 100).toFixed(1)}% - ${(proportionInterval.max * 100).toFixed(1)}%`;
27589
- return /* @__PURE__ */ u$2(Dropdown, { buttonTitle: `Proportion ${label}`, placement: "bottom-start", children: /* @__PURE__ */ u$2(
27685
+ return /* @__PURE__ */ u$2("div", { className: "w-44", children: /* @__PURE__ */ u$2(Dropdown, { buttonTitle: `Proportion ${label}`, placement: "bottom-start", children: /* @__PURE__ */ u$2(
27590
27686
  ProportionSelector,
27591
27687
  {
27592
27688
  proportionInterval,
27593
27689
  setMinProportion,
27594
27690
  setMaxProportion
27595
27691
  }
27692
+ ) }) });
27693
+ };
27694
+ const ReferenceGenomeContext = G$1({ nucleotideSequences: [], genes: [] });
27695
+ const SegmentSelector = ({
27696
+ displayedSegments,
27697
+ setDisplayedSegments
27698
+ }) => {
27699
+ if (displayedSegments.length <= 1) {
27700
+ return null;
27701
+ }
27702
+ return /* @__PURE__ */ u$2("div", { className: "w-24", children: /* @__PURE__ */ u$2(
27703
+ CheckboxSelector,
27704
+ {
27705
+ items: displayedSegments,
27706
+ label: getSegmentSelectorLabel(displayedSegments),
27707
+ setItems: (items) => setDisplayedSegments(items)
27708
+ }
27596
27709
  ) });
27597
27710
  };
27711
+ const getSegmentSelectorLabel = (displayedSegments) => {
27712
+ const allSelectedSelected = displayedSegments.filter((segment) => segment.checked).map((segment) => segment.segment);
27713
+ if (allSelectedSelected.length === 0) {
27714
+ return `No segments`;
27715
+ }
27716
+ if (displayedSegments.length === allSelectedSelected.length) {
27717
+ return `All segments`;
27718
+ }
27719
+ const longestDisplayString = `All segments`;
27720
+ const allSelectedSelectedString = allSelectedSelected.join(", ");
27721
+ if (longestDisplayString.length >= allSelectedSelectedString.length) {
27722
+ return allSelectedSelectedString;
27723
+ }
27724
+ return `${allSelectedSelected.length} ${allSelectedSelected.length === 1 ? "segment" : "segments"}`;
27725
+ };
27726
+ function useDisplayedSegments(sequenceType) {
27727
+ const referenceGenome = x$1(ReferenceGenomeContext);
27728
+ const displayedSegments = getSegmentNames(referenceGenome, sequenceType).map((segment) => ({
27729
+ segment,
27730
+ label: segment,
27731
+ checked: true
27732
+ }));
27733
+ return h$1(displayedSegments);
27734
+ }
27598
27735
  const Tabs = ({ tabs, toolbar }) => {
27599
27736
  const [activeTab, setActiveTab] = h$1(tabs[0].title);
27600
27737
  const [heightOfTabs, setHeightOfTabs] = h$1("3rem");
@@ -27640,7 +27777,7 @@ const Tabs = ({ tabs, toolbar }) => {
27640
27777
  )
27641
27778
  ] });
27642
27779
  };
27643
- function useQuery(fetchDataCallback, dependencies = []) {
27780
+ function useQuery(fetchDataCallback, dependencies) {
27644
27781
  const [data, setData] = h$1(null);
27645
27782
  const [error, setError] = h$1(null);
27646
27783
  const [isLoading, setIsLoading] = h$1(true);
@@ -27798,7 +27935,7 @@ const Toolbar$5 = ({
27798
27935
  const gridJsStyle = '.gridjs-head button, .gridjs-footer button {\n cursor: pointer;\n background-color: transparent;\n background-image: none;\n padding: 0;\n margin: 0;\n border: none;\n outline: none;\n}\n\n.gridjs-temp {\n position: relative;\n}\n\n.gridjs-head {\n width: 100%;\n margin-bottom: 5px;\n padding: 5px 1px;\n}\n.gridjs-head::after {\n content: "";\n display: block;\n clear: both;\n}\n.gridjs-head:empty {\n padding: 0;\n border: none;\n}\n\n.gridjs-container {\n overflow: hidden;\n display: inline-block;\n padding: 2px;\n color: #000;\n position: relative;\n z-index: 0;\n}\n\n.gridjs-footer {\n display: block;\n position: relative;\n width: 100%;\n z-index: 5;\n padding: 12px 24px;\n border-top: 1px solid #e5e7eb;\n background-color: #fff;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.26);\n border-radius: 0 0 8px 8px;\n border-bottom-width: 1px;\n border-color: #e5e7eb;\n}\n.gridjs-footer:empty {\n padding: 0;\n border: none;\n}\n\ninput.gridjs-input {\n outline: none;\n background-color: #fff;\n border: 1px solid #d2d6dc;\n border-radius: 5px;\n padding: 10px 13px;\n font-size: 14px;\n line-height: 1.45;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\ninput.gridjs-input:focus {\n box-shadow: 0 0 0 3px rgba(149, 189, 243, 0.5);\n border-color: #9bc2f7;\n}\n\n.gridjs-pagination {\n color: #3d4044;\n}\n.gridjs-pagination::after {\n content: "";\n display: block;\n clear: both;\n}\n.gridjs-pagination .gridjs-summary {\n float: left;\n margin-top: 5px;\n}\n.gridjs-pagination .gridjs-pages {\n float: right;\n}\n.gridjs-pagination .gridjs-pages button {\n padding: 5px 14px;\n border: 1px solid #d2d6dc;\n background-color: #fff;\n border-right: none;\n outline: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n}\n.gridjs-pagination .gridjs-pages button:focus {\n box-shadow: 0 0 0 2px rgba(149, 189, 243, 0.5);\n position: relative;\n margin-right: -1px;\n border-right: 1px solid #d2d6dc;\n}\n.gridjs-pagination .gridjs-pages button:hover {\n background-color: #f7f7f7;\n color: rgb(60, 66, 87);\n outline: none;\n}\n.gridjs-pagination .gridjs-pages button:disabled,\n.gridjs-pagination .gridjs-pages button[disabled],\n.gridjs-pagination .gridjs-pages button:hover:disabled {\n cursor: default;\n background-color: #fff;\n color: #6b7280;\n}\n.gridjs-pagination .gridjs-pages button.gridjs-spread {\n cursor: default;\n box-shadow: none;\n background-color: #fff;\n}\n.gridjs-pagination .gridjs-pages button.gridjs-currentPage {\n background-color: #f7f7f7;\n font-weight: bold;\n}\n.gridjs-pagination .gridjs-pages button:last-child {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n border-right: 1px solid #d2d6dc;\n}\n.gridjs-pagination .gridjs-pages button:first-child {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.gridjs-pagination .gridjs-pages button:last-child:focus {\n margin-right: 0;\n}\n\nbutton.gridjs-sort {\n float: right;\n height: 24px;\n width: 13px;\n background-color: transparent;\n background-repeat: no-repeat;\n background-position-x: center;\n cursor: pointer;\n padding: 0;\n margin: 0;\n border: none;\n outline: none;\n background-size: contain;\n}\nbutton.gridjs-sort-neutral {\n opacity: 0.3;\n background-image: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHdpZHRoPSI0MDEuOTk4cHgiIGhlaWdodD0iNDAxLjk5OHB4IiB2aWV3Qm94PSIwIDAgNDAxLjk5OCA0MDEuOTk4IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0MDEuOTk4IDQwMS45OTg7IgoJIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxnPgoJCTxwYXRoIGQ9Ik03My4wOTIsMTY0LjQ1MmgyNTUuODEzYzQuOTQ5LDAsOS4yMzMtMS44MDcsMTIuODQ4LTUuNDI0YzMuNjEzLTMuNjE2LDUuNDI3LTcuODk4LDUuNDI3LTEyLjg0NwoJCQljMC00Ljk0OS0xLjgxMy05LjIyOS01LjQyNy0xMi44NUwyMTMuODQ2LDUuNDI0QzIxMC4yMzIsMS44MTIsMjA1Ljk1MSwwLDIwMC45OTksMHMtOS4yMzMsMS44MTItMTIuODUsNS40MjRMNjAuMjQyLDEzMy4zMzEKCQkJYy0zLjYxNywzLjYxNy01LjQyNCw3LjkwMS01LjQyNCwxMi44NWMwLDQuOTQ4LDEuODA3LDkuMjMxLDUuNDI0LDEyLjg0N0M2My44NjMsMTYyLjY0NSw2OC4xNDQsMTY0LjQ1Miw3My4wOTIsMTY0LjQ1MnoiLz4KCQk8cGF0aCBkPSJNMzI4LjkwNSwyMzcuNTQ5SDczLjA5MmMtNC45NTIsMC05LjIzMywxLjgwOC0xMi44NSw1LjQyMWMtMy42MTcsMy42MTctNS40MjQsNy44OTgtNS40MjQsMTIuODQ3CgkJCWMwLDQuOTQ5LDEuODA3LDkuMjMzLDUuNDI0LDEyLjg0OEwxODguMTQ5LDM5Ni41N2MzLjYyMSwzLjYxNyw3LjkwMiw1LjQyOCwxMi44NSw1LjQyOHM5LjIzMy0xLjgxMSwxMi44NDctNS40MjhsMTI3LjkwNy0xMjcuOTA2CgkJCWMzLjYxMy0zLjYxNCw1LjQyNy03Ljg5OCw1LjQyNy0xMi44NDhjMC00Ljk0OC0xLjgxMy05LjIyOS01LjQyNy0xMi44NDdDMzM4LjEzOSwyMzkuMzUzLDMzMy44NTQsMjM3LjU0OSwzMjguOTA1LDIzNy41NDl6Ii8+Cgk8L2c+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+");\n background-position-y: center;\n}\nbutton.gridjs-sort-asc {\n background-image: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHdpZHRoPSIyOTIuMzYycHgiIGhlaWdodD0iMjkyLjM2MXB4IiB2aWV3Qm94PSIwIDAgMjkyLjM2MiAyOTIuMzYxIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyOTIuMzYyIDI5Mi4zNjE7IgoJIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGQ9Ik0yODYuOTM1LDE5Ny4yODdMMTU5LjAyOCw2OS4zODFjLTMuNjEzLTMuNjE3LTcuODk1LTUuNDI0LTEyLjg0Ny01LjQyNHMtOS4yMzMsMS44MDctMTIuODUsNS40MjRMNS40MjQsMTk3LjI4NwoJCUMxLjgwNywyMDAuOTA0LDAsMjA1LjE4NiwwLDIxMC4xMzRzMS44MDcsOS4yMzMsNS40MjQsMTIuODQ3YzMuNjIxLDMuNjE3LDcuOTAyLDUuNDI1LDEyLjg1LDUuNDI1aDI1NS44MTMKCQljNC45NDksMCw5LjIzMy0xLjgwOCwxMi44NDgtNS40MjVjMy42MTMtMy42MTMsNS40MjctNy44OTgsNS40MjctMTIuODQ3UzI5MC41NDgsMjAwLjkwNCwyODYuOTM1LDE5Ny4yODd6Ii8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+");\n background-position-y: 35%;\n background-size: 10px;\n}\nbutton.gridjs-sort-desc {\n background-image: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHdpZHRoPSIyOTIuMzYycHgiIGhlaWdodD0iMjkyLjM2MnB4IiB2aWV3Qm94PSIwIDAgMjkyLjM2MiAyOTIuMzYyIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyOTIuMzYyIDI5Mi4zNjI7IgoJIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8Zz4KCTxwYXRoIGQ9Ik0yODYuOTM1LDY5LjM3N2MtMy42MTQtMy42MTctNy44OTgtNS40MjQtMTIuODQ4LTUuNDI0SDE4LjI3NGMtNC45NTIsMC05LjIzMywxLjgwNy0xMi44NSw1LjQyNAoJCUMxLjgwNyw3Mi45OTgsMCw3Ny4yNzksMCw4Mi4yMjhjMCw0Ljk0OCwxLjgwNyw5LjIyOSw1LjQyNCwxMi44NDdsMTI3LjkwNywxMjcuOTA3YzMuNjIxLDMuNjE3LDcuOTAyLDUuNDI4LDEyLjg1LDUuNDI4CgkJczkuMjMzLTEuODExLDEyLjg0Ny01LjQyOEwyODYuOTM1LDk1LjA3NGMzLjYxMy0zLjYxNyw1LjQyNy03Ljg5OCw1LjQyNy0xMi44NDdDMjkyLjM2Miw3Ny4yNzksMjkwLjU0OCw3Mi45OTgsMjg2LjkzNSw2OS4zNzd6Ii8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+");\n background-position-y: 65%;\n background-size: 10px;\n}\nbutton.gridjs-sort:focus {\n outline: none;\n}\n\ntable.gridjs-table {\n width: 100%;\n max-width: 100%;\n border-collapse: collapse;\n text-align: left;\n display: table;\n margin: 0;\n padding: 0;\n overflow: auto;\n table-layout: fixed;\n}\n\n.gridjs-tbody {\n background-color: #fff;\n}\n\ntd.gridjs-td {\n border: 1px solid #e5e7eb;\n padding: 12px 24px;\n background-color: #fff;\n box-sizing: content-box;\n}\ntd.gridjs-td:first-child {\n border-left: none;\n}\ntd.gridjs-td:last-child {\n border-right: none;\n}\ntd.gridjs-message {\n text-align: center;\n}\n\nth.gridjs-th {\n position: relative;\n color: #6b7280;\n background-color: #f9fafb;\n border: 1px solid #e5e7eb;\n border-top: none;\n padding: 14px 24px;\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n box-sizing: border-box;\n white-space: nowrap;\n outline: none;\n vertical-align: middle;\n}\nth.gridjs-th .gridjs-th-content {\n text-overflow: ellipsis;\n overflow: hidden;\n width: 100%;\n float: left;\n}\nth.gridjs-th-sort {\n cursor: pointer;\n}\nth.gridjs-th-sort .gridjs-th-content {\n width: calc(100% - 15px);\n}\nth.gridjs-th-sort:hover {\n background-color: #e5e7eb;\n}\nth.gridjs-th-sort:focus {\n background-color: #e5e7eb;\n}\nth.gridjs-th-fixed {\n position: sticky;\n box-shadow: 0 1px 0 0 #e5e7eb;\n}\n@supports (-moz-appearance: none) {\n th.gridjs-th-fixed {\n box-shadow: 0 0 0 1px #e5e7eb;\n }\n}\nth.gridjs-th:first-child {\n border-left: none;\n}\nth.gridjs-th:last-child {\n border-right: none;\n}\n\n.gridjs-tr {\n border: none;\n}\n.gridjs-tr-selected td {\n background-color: #ebf5ff;\n}\n.gridjs-tr:last-child td {\n border-bottom: 0;\n}\n\n.gridjs *,\n.gridjs :after,\n.gridjs :before {\n box-sizing: border-box;\n}\n\n.gridjs-wrapper {\n position: relative;\n z-index: 1;\n overflow: auto;\n width: 100%;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.26);\n border-radius: 8px 8px 0 0;\n display: block;\n border-top-width: 1px;\n border-color: #e5e7eb;\n}\n.gridjs-wrapper:nth-last-of-type(2) {\n border-radius: 8px;\n border-bottom-width: 1px;\n}\n\n.gridjs-search {\n float: left;\n}\n.gridjs-search-input {\n width: 250px;\n}\n\n.gridjs-loading-bar {\n z-index: 10;\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n background-color: #fff;\n opacity: 0.5;\n}\n.gridjs-loading-bar::after {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n transform: translateX(-100%);\n background-image: linear-gradient(90deg, rgba(204, 204, 204, 0) 0, rgba(204, 204, 204, 0.2) 20%, rgba(204, 204, 204, 0.5) 60%, rgba(204, 204, 204, 0));\n animation: shimmer 2s infinite;\n content: "";\n}\n@keyframes shimmer {\n 100% {\n transform: translateX(100%);\n }\n}\n\n.gridjs-td .gridjs-checkbox {\n display: block;\n margin: auto;\n cursor: pointer;\n}\n\n.gridjs-resizable {\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n width: 5px;\n}\n.gridjs-resizable:hover {\n cursor: ew-resize;\n background-color: #9bc2f7;\n}\n/*# sourceMappingURL=mermaid.css?inline.map */';
27799
27936
  const minMaxPercentSliderCss = 'input[type=range]::-webkit-slider-thumb {\n -webkit-appearance: none;\n pointer-events: all;\n width: 24px;\n height: 24px;\n background-color: #fff;\n border-radius: 50%;\n box-shadow: 0 0 0 1px #C6C6C6;\n cursor: pointer;\n}\n\ninput[type=range]::-moz-range-thumb {\n -webkit-appearance: none;\n pointer-events: all;\n width: 24px;\n height: 24px;\n background-color: #fff;\n border-radius: 50%;\n box-shadow: 0 0 0 1px #C6C6C6;\n cursor: pointer;\n}\n\ninput[type=range]::-webkit-slider-thumb:hover {\n background: #f7f7f7;\n}\n\ninput[type=range]::-webkit-slider-thumb:active {\n box-shadow: inset 0 0 3px #387bbe, 0 0 9px #387bbe;\n -webkit-box-shadow: inset 0 0 3px #387bbe, 0 0 9px #387bbe;\n}\n\ninput[type="range"] {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n height: 2px;\n width: 100%;\n position: absolute;\n background-color: #C6C6C6;\n pointer-events: none;\n}';
27800
27937
  const tailwindStyle = `/*
27801
- ! tailwindcss v3.4.6 | MIT License | https://tailwindcss.com
27938
+ ! tailwindcss v3.4.7 | MIT License | https://tailwindcss.com
27802
27939
  *//*
27803
27940
  1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
27804
27941
  2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
@@ -28405,6 +28542,39 @@ html {
28405
28542
  --tw-contain-paint: ;
28406
28543
  --tw-contain-style: ;
28407
28544
  }
28545
+ .container {
28546
+ width: 100%;
28547
+ }
28548
+ @media (min-width: 640px) {
28549
+
28550
+ .container {
28551
+ max-width: 640px;
28552
+ }
28553
+ }
28554
+ @media (min-width: 768px) {
28555
+
28556
+ .container {
28557
+ max-width: 768px;
28558
+ }
28559
+ }
28560
+ @media (min-width: 1024px) {
28561
+
28562
+ .container {
28563
+ max-width: 1024px;
28564
+ }
28565
+ }
28566
+ @media (min-width: 1280px) {
28567
+
28568
+ .container {
28569
+ max-width: 1280px;
28570
+ }
28571
+ }
28572
+ @media (min-width: 1536px) {
28573
+
28574
+ .container {
28575
+ max-width: 1536px;
28576
+ }
28577
+ }
28408
28578
  .alert {
28409
28579
  display: grid;
28410
28580
  width: 100%;
@@ -28446,6 +28616,15 @@ html {
28446
28616
  color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
28447
28617
  }
28448
28618
 
28619
+ .menu li > *:not(ul, .menu-title, details, .btn):active,
28620
+ .menu li > *:not(ul, .menu-title, details, .btn).active,
28621
+ .menu li > details > summary:active {
28622
+ --tw-bg-opacity: 1;
28623
+ background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
28624
+ --tw-text-opacity: 1;
28625
+ color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
28626
+ }
28627
+
28449
28628
  .tab:hover {
28450
28629
  --tw-text-opacity: 1;
28451
28630
  }
@@ -28539,6 +28718,25 @@ html {
28539
28718
  container-type: inline-size;
28540
28719
  grid-template-columns: auto 1fr;
28541
28720
  }
28721
+ .divider {
28722
+ display: flex;
28723
+ flex-direction: row;
28724
+ align-items: center;
28725
+ align-self: stretch;
28726
+ margin-top: 1rem;
28727
+ margin-bottom: 1rem;
28728
+ height: 1rem;
28729
+ white-space: nowrap;
28730
+ }
28731
+ .divider:before,
28732
+ .divider:after {
28733
+ height: 0.125rem;
28734
+ width: 100%;
28735
+ flex-grow: 1;
28736
+ --tw-content: '';
28737
+ content: var(--tw-content);
28738
+ background-color: var(--fallback-bc,oklch(var(--bc)/0.1));
28739
+ }
28542
28740
  .dropdown {
28543
28741
  position: relative;
28544
28742
  display: inline-block;
@@ -28784,6 +28982,10 @@ html {
28784
28982
  border-radius: inherit;
28785
28983
  }
28786
28984
  }
28985
+ .link {
28986
+ cursor: pointer;
28987
+ text-decoration-line: underline;
28988
+ }
28787
28989
  .menu li.disabled {
28788
28990
  cursor: not-allowed;
28789
28991
  -webkit-user-select: none;
@@ -29051,6 +29253,11 @@ input.tab:checked + .tab-content,
29051
29253
  --alert-bg: var(--fallback-er,oklch(var(--er)/1));
29052
29254
  --alert-bg-mix: var(--fallback-b1,oklch(var(--b1)/1));
29053
29255
  }
29256
+ .btm-nav > *:where(.active) {
29257
+ border-top-width: 2px;
29258
+ --tw-bg-opacity: 1;
29259
+ background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity)));
29260
+ }
29054
29261
  .btm-nav > *.disabled,
29055
29262
  .btm-nav > *[disabled] {
29056
29263
  pointer-events: none;
@@ -29203,6 +29410,9 @@ input.tab:checked + .tab-content,
29203
29410
  background-position-y: 0;
29204
29411
  }
29205
29412
  }
29413
+ .divider:not(:empty) {
29414
+ gap: 1rem;
29415
+ }
29206
29416
  .dropdown.dropdown-open .dropdown-content,
29207
29417
  .dropdown:focus .dropdown-content,
29208
29418
  .dropdown:focus-within .dropdown-content {
@@ -29280,6 +29490,14 @@ input.tab:checked + .tab-content,
29280
29490
  .join > :where(*:not(:first-child)):is(.btn) {
29281
29491
  margin-inline-start: calc(var(--border-btn) * -1);
29282
29492
  }
29493
+ .link:focus {
29494
+ outline: 2px solid transparent;
29495
+ outline-offset: 2px;
29496
+ }
29497
+ .link:focus-visible {
29498
+ outline: 2px solid currentColor;
29499
+ outline-offset: 2px;
29500
+ }
29283
29501
  .loading {
29284
29502
  pointer-events: none;
29285
29503
  display: inline-block;
@@ -29310,6 +29528,14 @@ input.tab:checked + .tab-content,
29310
29528
  outline: 2px solid transparent;
29311
29529
  outline-offset: 2px;
29312
29530
  }
29531
+ .menu li > *:not(ul, .menu-title, details, .btn):active,
29532
+ .menu li > *:not(ul, .menu-title, details, .btn).active,
29533
+ .menu li > details > summary:active {
29534
+ --tw-bg-opacity: 1;
29535
+ background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
29536
+ --tw-text-opacity: 1;
29537
+ color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
29538
+ }
29313
29539
  .mockup-phone .display {
29314
29540
  overflow: hidden;
29315
29541
  border-radius: 40px;
@@ -29806,6 +30032,12 @@ input.tab:checked + .tab-content,
29806
30032
  --tw-bg-opacity: 1;
29807
30033
  background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
29808
30034
  }
30035
+ .table-zebra tr.active,
30036
+ .table-zebra tr.active:nth-child(even),
30037
+ .table-zebra-zebra tbody tr:nth-child(even) {
30038
+ --tw-bg-opacity: 1;
30039
+ background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)));
30040
+ }
29809
30041
  .table :where(thead tr, tbody tr:not(:last-child), tbody tr:first-child:last-child) {
29810
30042
  border-bottom-width: 1px;
29811
30043
  --tw-border-opacity: 1;
@@ -29878,6 +30110,18 @@ input.tab:checked + .tab-content,
29878
30110
  --togglehandleborder: 0 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset,
29879
30111
  var(--handleoffsetcalculator) 0 0 3px var(--fallback-bc,oklch(var(--bc)/1)) inset;
29880
30112
  }
30113
+ .btm-nav-xs > *:where(.active) {
30114
+ border-top-width: 1px;
30115
+ }
30116
+ .btm-nav-sm > *:where(.active) {
30117
+ border-top-width: 2px;
30118
+ }
30119
+ .btm-nav-md > *:where(.active) {
30120
+ border-top-width: 2px;
30121
+ }
30122
+ .btm-nav-lg > *:where(.active) {
30123
+ border-top-width: 4px;
30124
+ }
29881
30125
  .btn-xs {
29882
30126
  height: 1.5rem;
29883
30127
  min-height: 1.5rem;
@@ -30297,6 +30541,9 @@ input.tab:checked + .tab-content,
30297
30541
  margin-top: 1rem;
30298
30542
  margin-bottom: 1rem;
30299
30543
  }
30544
+ .mb-0 {
30545
+ margin-bottom: 0px;
30546
+ }
30300
30547
  .mb-1 {
30301
30548
  margin-bottom: 0.25rem;
30302
30549
  }
@@ -30306,6 +30553,9 @@ input.tab:checked + .tab-content,
30306
30553
  .ml-1 {
30307
30554
  margin-left: 0.25rem;
30308
30555
  }
30556
+ .ml-2 {
30557
+ margin-left: 0.5rem;
30558
+ }
30309
30559
  .ml-2\\.5 {
30310
30560
  margin-left: 0.625rem;
30311
30561
  }
@@ -30318,6 +30568,9 @@ input.tab:checked + .tab-content,
30318
30568
  .mr-2 {
30319
30569
  margin-right: 0.5rem;
30320
30570
  }
30571
+ .mt-0 {
30572
+ margin-top: 0px;
30573
+ }
30321
30574
  .mt-0\\.5 {
30322
30575
  margin-top: 0.125rem;
30323
30576
  }
@@ -30357,12 +30610,24 @@ input.tab:checked + .tab-content,
30357
30610
  .w-16 {
30358
30611
  width: 4rem;
30359
30612
  }
30613
+ .w-20 {
30614
+ width: 5rem;
30615
+ }
30616
+ .w-24 {
30617
+ width: 6rem;
30618
+ }
30360
30619
  .w-32 {
30361
30620
  width: 8rem;
30362
30621
  }
30622
+ .w-44 {
30623
+ width: 11rem;
30624
+ }
30363
30625
  .w-64 {
30364
30626
  width: 16rem;
30365
30627
  }
30628
+ .w-\\[6rem\\] {
30629
+ width: 6rem;
30630
+ }
30366
30631
  .w-\\[7\\.5rem\\] {
30367
30632
  width: 7.5rem;
30368
30633
  }
@@ -30399,6 +30664,12 @@ input.tab:checked + .tab-content,
30399
30664
  .resize {
30400
30665
  resize: both;
30401
30666
  }
30667
+ .list-inside {
30668
+ list-style-position: inside;
30669
+ }
30670
+ .list-disc {
30671
+ list-style-type: disc;
30672
+ }
30402
30673
  .flex-row {
30403
30674
  flex-direction: row;
30404
30675
  }
@@ -30429,6 +30700,9 @@ input.tab:checked + .tab-content,
30429
30700
  .overflow-auto {
30430
30701
  overflow: auto;
30431
30702
  }
30703
+ .overflow-x-auto {
30704
+ overflow-x: auto;
30705
+ }
30432
30706
  .whitespace-nowrap {
30433
30707
  white-space: nowrap;
30434
30708
  }
@@ -30438,6 +30712,9 @@ input.tab:checked + .tab-content,
30438
30712
  .rounded-full {
30439
30713
  border-radius: 9999px;
30440
30714
  }
30715
+ .rounded-lg {
30716
+ border-radius: 0.5rem;
30717
+ }
30441
30718
  .rounded-md {
30442
30719
  border-radius: 0.375rem;
30443
30720
  }
@@ -30693,6 +30970,12 @@ input.tab:checked + .tab-content,
30693
30970
  }
30694
30971
  .peer:hover ~ .peer-hover\\:visible {
30695
30972
  visibility: visible;
30973
+ }
30974
+ @media (min-width: 640px) {
30975
+
30976
+ .sm\\:max-w-5xl {
30977
+ max-width: 64rem;
30978
+ }
30696
30979
  }`;
30697
30980
  var __defProp$c = Object.defineProperty;
30698
30981
  var __decorateClass$c = (decorators, target, key, kind) => {
@@ -30934,7 +31217,10 @@ const MutationsGrid = ({
30934
31217
  }
30935
31218
  return {};
30936
31219
  };
30937
- const tableData = getMutationsGridData(data, sequenceType, proportionInterval).map((row) => Object.values(row));
31220
+ const tableData = T$1(
31221
+ () => getMutationsGridData(data, sequenceType, proportionInterval).map((row) => Object.values(row)),
31222
+ [data, proportionInterval, sequenceType]
31223
+ );
30938
31224
  return /* @__PURE__ */ u$2(Table, { data: tableData, columns: getHeaders(), pageSize });
30939
31225
  };
30940
31226
  const sortInsertions = (a2, b3) => {
@@ -31184,10 +31470,39 @@ const Toolbar$4 = ({
31184
31470
  filename: "insertions.csv"
31185
31471
  }
31186
31472
  ),
31187
- /* @__PURE__ */ u$2(Info, { children: "Info for mutations" }),
31473
+ /* @__PURE__ */ u$2(MutationsInfo, {}),
31188
31474
  /* @__PURE__ */ u$2(Fullscreen, {})
31189
31475
  ] });
31190
31476
  };
31477
+ const MutationsInfo = () => /* @__PURE__ */ u$2(Info, { children: [
31478
+ /* @__PURE__ */ u$2(InfoHeadline1, { children: "Mutations" }),
31479
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
31480
+ "This shows mutations of a variant. There are three types of mutations:",
31481
+ " ",
31482
+ /* @__PURE__ */ u$2(InfoLink, { href: "https://www.genome.gov/genetics-glossary/Substitution", children: "substitutions" }),
31483
+ ",",
31484
+ " ",
31485
+ /* @__PURE__ */ u$2(InfoLink, { href: "https://www.genome.gov/genetics-glossary/Deletion", children: "deletions" }),
31486
+ " and",
31487
+ " ",
31488
+ /* @__PURE__ */ u$2(InfoLink, { href: "https://www.genome.gov/genetics-glossary/Insertion", children: "insertions" }),
31489
+ "."
31490
+ ] }),
31491
+ /* @__PURE__ */ u$2(InfoHeadline2, { children: "Proportion calculation" }),
31492
+ /* @__PURE__ */ u$2(InfoParagraph, { children: "The proportion of a mutation is calculated by dividing the number of sequences with the mutation by the total number of sequences with a non-ambiguous symbol at the position." }),
31493
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
31494
+ /* @__PURE__ */ u$2("b", { children: "Example:" }),
31495
+ " Assume we look at nucleotide mutations at position 5 where the reference has a T and assume there are 10 sequences in total:",
31496
+ /* @__PURE__ */ u$2("ul", { className: "list-disc list-inside ml-2", children: [
31497
+ /* @__PURE__ */ u$2("li", { children: "3 sequences have a C," }),
31498
+ /* @__PURE__ */ u$2("li", { children: "2 sequences have a T," }),
31499
+ /* @__PURE__ */ u$2("li", { children: "1 sequence has a G," }),
31500
+ /* @__PURE__ */ u$2("li", { children: "3 sequences have an N," }),
31501
+ /* @__PURE__ */ u$2("li", { children: "1 sequence has a Y (which means T or C)," })
31502
+ ] }),
31503
+ "then the proportion of the T5C mutation is 50%. The 4 sequences that have an N or Y are excluded from the calculation."
31504
+ ] })
31505
+ ] });
31191
31506
  var __defProp$a = Object.defineProperty;
31192
31507
  var __getOwnPropDesc$a = Object.getOwnPropertyDescriptor;
31193
31508
  var __decorateClass$a = (decorators, target, key, kind) => {
@@ -33539,21 +33854,13 @@ const ScalingSelector = ({
33539
33854
  }
33540
33855
  );
33541
33856
  };
33542
- const PrevalenceOverTime = ({ width, height, ...innerProps }) => {
33857
+ const PrevalenceOverTime = (componentProps) => {
33858
+ const { width, height } = componentProps;
33543
33859
  const size = { height, width };
33544
- return /* @__PURE__ */ u$2(ErrorBoundary, { size, children: /* @__PURE__ */ u$2(ResizeContainer, { size, children: /* @__PURE__ */ u$2(PrevalenceOverTimeInner, { ...innerProps }) }) });
33860
+ return /* @__PURE__ */ u$2(ErrorBoundary, { size, children: /* @__PURE__ */ u$2(ResizeContainer, { size, children: /* @__PURE__ */ u$2(PrevalenceOverTimeInner, { ...componentProps }) }) });
33545
33861
  };
33546
- const PrevalenceOverTimeInner = ({
33547
- numeratorFilter,
33548
- denominatorFilter,
33549
- granularity,
33550
- smoothingWindow,
33551
- views,
33552
- confidenceIntervalMethods,
33553
- lapisDateField,
33554
- pageSize,
33555
- yAxisMaxConfig
33556
- }) => {
33862
+ const PrevalenceOverTimeInner = (componentProps) => {
33863
+ const { numeratorFilter, denominatorFilter, granularity, smoothingWindow, lapisDateField } = componentProps;
33557
33864
  const lapis = x$1(LapisUrlContext);
33558
33865
  const { data, error, isLoading } = useQuery(
33559
33866
  () => queryPrevalenceOverTime(
@@ -33575,30 +33882,15 @@ const PrevalenceOverTimeInner = ({
33575
33882
  if (data === null) {
33576
33883
  return /* @__PURE__ */ u$2(NoDataDisplay, {});
33577
33884
  }
33578
- return /* @__PURE__ */ u$2(
33579
- PrevalenceOverTimeTabs,
33580
- {
33581
- views,
33582
- data,
33583
- granularity,
33584
- confidenceIntervalMethods,
33585
- pageSize,
33586
- yAxisMaxConfig
33587
- }
33588
- );
33885
+ return /* @__PURE__ */ u$2(PrevalenceOverTimeTabs, { data, ...componentProps });
33589
33886
  };
33590
- const PrevalenceOverTimeTabs = ({
33591
- views,
33592
- data,
33593
- granularity,
33594
- confidenceIntervalMethods,
33595
- pageSize,
33596
- yAxisMaxConfig
33597
- }) => {
33887
+ const PrevalenceOverTimeTabs = ({ data, ...componentProps }) => {
33888
+ const { views, granularity, confidenceIntervalMethods, pageSize, yAxisMaxLinear, yAxisMaxLogarithmic } = componentProps;
33598
33889
  const [yAxisScaleType, setYAxisScaleType] = h$1("linear");
33599
33890
  const [confidenceIntervalMethod, setConfidenceIntervalMethod] = h$1(
33600
33891
  confidenceIntervalMethods.length > 0 ? confidenceIntervalMethods[0] : "none"
33601
33892
  );
33893
+ const yAxisMaxConfig = { linear: yAxisMaxLinear, logarithmic: yAxisMaxLogarithmic };
33602
33894
  const getTab = (view) => {
33603
33895
  switch (view) {
33604
33896
  case "bar":
@@ -33654,10 +33946,9 @@ const PrevalenceOverTimeTabs = ({
33654
33946
  yAxisScaleType,
33655
33947
  setYAxisScaleType,
33656
33948
  data,
33657
- granularity,
33658
- confidenceIntervalMethods,
33659
33949
  confidenceIntervalMethod,
33660
- setConfidenceIntervalMethod
33950
+ setConfidenceIntervalMethod,
33951
+ ...componentProps
33661
33952
  }
33662
33953
  );
33663
33954
  return /* @__PURE__ */ u$2(Tabs, { tabs, toolbar });
@@ -33666,12 +33957,12 @@ const Toolbar$3 = ({
33666
33957
  activeTab,
33667
33958
  yAxisScaleType,
33668
33959
  setYAxisScaleType,
33669
- confidenceIntervalMethods,
33670
33960
  confidenceIntervalMethod,
33671
33961
  setConfidenceIntervalMethod,
33672
33962
  data,
33673
- granularity
33963
+ ...componentProps
33674
33964
  }) => {
33965
+ const { confidenceIntervalMethods, granularity } = componentProps;
33675
33966
  return /* @__PURE__ */ u$2(k$1, { children: [
33676
33967
  activeTab !== "Table" && /* @__PURE__ */ u$2(ScalingSelector, { yAxisScaleType, setYAxisScaleType }),
33677
33968
  (activeTab === "Bar" || activeTab === "Line") && /* @__PURE__ */ u$2(
@@ -33690,14 +33981,34 @@ const Toolbar$3 = ({
33690
33981
  filename: "prevalence_over_time.csv"
33691
33982
  }
33692
33983
  ),
33693
- /* @__PURE__ */ u$2(PrevalenceOverTimeInfo, {}),
33984
+ /* @__PURE__ */ u$2(PrevalenceOverTimeInfo, { ...componentProps }),
33694
33985
  /* @__PURE__ */ u$2(Fullscreen, {})
33695
33986
  ] });
33696
33987
  };
33697
- const PrevalenceOverTimeInfo = () => {
33988
+ const PrevalenceOverTimeInfo = (componentProps) => {
33989
+ const { granularity, smoothingWindow, views } = componentProps;
33990
+ const lapis = x$1(LapisUrlContext);
33698
33991
  return /* @__PURE__ */ u$2(Info, { children: [
33699
33992
  /* @__PURE__ */ u$2(InfoHeadline1, { children: "Prevalence over time" }),
33700
- /* @__PURE__ */ u$2(InfoParagraph, { children: "Prevalence over time info." })
33993
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
33994
+ "This presents the proportion of one or more variants per ",
33995
+ /* @__PURE__ */ u$2("b", { children: granularity }),
33996
+ smoothingWindow > 0 && `, smoothed using a ${smoothingWindow}-${granularity} sliding window`,
33997
+ ". The proportion is calculated as the number of sequences of the variant(s) divided by the number of sequences that match the ",
33998
+ /* @__PURE__ */ u$2("code", { children: "denominatorFilter" }),
33999
+ " (see below)."
34000
+ ] }),
34001
+ /* @__PURE__ */ u$2(InfoParagraph, { children: 'Sequences that have no assigned date will not be shown in the line and bubble chart. They will show up in the bar and table view with date "unknown".' }),
34002
+ views.includes("bubble") && /* @__PURE__ */ u$2(k$1, { children: [
34003
+ /* @__PURE__ */ u$2(InfoHeadline2, { children: "Bubble chart" }),
34004
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
34005
+ "The size of the bubble scales with the total number of available sequences from the",
34006
+ " ",
34007
+ granularity,
34008
+ "."
34009
+ ] })
34010
+ ] }),
34011
+ /* @__PURE__ */ u$2(InfoComponentCode, { componentName: "prevalence-over-time", params: componentProps, lapisUrl: lapis })
33701
34012
  ] });
33702
34013
  };
33703
34014
  const maxInData = (data) => Math.max(...data.flatMap((variant) => variant.content.map((dataPoint) => dataPoint.prevalence)));
@@ -33741,10 +34052,8 @@ let PrevalenceOverTimeComponent = class extends PreactLitAdapterWithGridJsStyles
33741
34052
  height: this.height,
33742
34053
  lapisDateField: this.lapisDateField,
33743
34054
  pageSize: this.pageSize,
33744
- yAxisMaxConfig: {
33745
- linear: this.yAxisMaxLinear,
33746
- logarithmic: this.yAxisMaxLogarithmic
33747
- }
34055
+ yAxisMaxLinear: this.yAxisMaxLinear,
34056
+ yAxisMaxLogarithmic: this.yAxisMaxLogarithmic
33748
34057
  }
33749
34058
  );
33750
34059
  }
@@ -34268,12 +34577,20 @@ const AggregatedDataTabs = ({ data, views, fields, pageSize }) => {
34268
34577
  }
34269
34578
  };
34270
34579
  const tabs = views.map((view) => getTab(view));
34271
- return /* @__PURE__ */ u$2(Tabs, { tabs, toolbar: /* @__PURE__ */ u$2(Toolbar$2, { data }) });
34580
+ return /* @__PURE__ */ u$2(Tabs, { tabs, toolbar: /* @__PURE__ */ u$2(Toolbar$2, { data, fields }) });
34272
34581
  };
34273
- const Toolbar$2 = ({ data }) => {
34582
+ const Toolbar$2 = ({ data, fields }) => {
34274
34583
  return /* @__PURE__ */ u$2("div", { class: "flex flex-row", children: [
34275
34584
  /* @__PURE__ */ u$2(CsvDownloadButton, { className: "mx-1 btn btn-xs", getData: () => data, filename: "aggregate.csv" }),
34276
- /* @__PURE__ */ u$2(Info, { children: "Info for aggregate" }),
34585
+ /* @__PURE__ */ u$2(Info, { children: [
34586
+ /* @__PURE__ */ u$2(InfoHeadline1, { children: "Aggregated data" }),
34587
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
34588
+ "This table shows the number and proportion of sequences stratified by the following fields:",
34589
+ " ",
34590
+ fields.join(", "),
34591
+ ". The proportion is calculated with respect to the total count within the filtered dataset."
34592
+ ] })
34593
+ ] }),
34277
34594
  /* @__PURE__ */ u$2(Fullscreen, {})
34278
34595
  ] });
34279
34596
  };
@@ -34512,7 +34829,8 @@ const NumberSequencesOverTimeInner = ({
34512
34829
  }) => {
34513
34830
  const lapis = x$1(LapisUrlContext);
34514
34831
  const { data, error, isLoading } = useQuery(
34515
- () => queryNumberOfSequencesOverTime(lapis, lapisFilter, lapisDateField, granularity, smoothingWindow)
34832
+ () => queryNumberOfSequencesOverTime(lapis, lapisFilter, lapisDateField, granularity, smoothingWindow),
34833
+ [lapis, lapisFilter, lapisDateField, granularity, smoothingWindow]
34516
34834
  );
34517
34835
  if (isLoading) {
34518
34836
  return /* @__PURE__ */ u$2(LoadingDisplay, {});
@@ -34523,9 +34841,24 @@ const NumberSequencesOverTimeInner = ({
34523
34841
  if (data === null) {
34524
34842
  return /* @__PURE__ */ u$2(NoDataDisplay, {});
34525
34843
  }
34526
- return /* @__PURE__ */ u$2(NumberSequencesOverTimeTabs, { views, data, granularity, pageSize });
34844
+ return /* @__PURE__ */ u$2(
34845
+ NumberSequencesOverTimeTabs,
34846
+ {
34847
+ views,
34848
+ data,
34849
+ granularity,
34850
+ smoothingWindow,
34851
+ pageSize
34852
+ }
34853
+ );
34527
34854
  };
34528
- const NumberSequencesOverTimeTabs = ({ views, data, granularity, pageSize }) => {
34855
+ const NumberSequencesOverTimeTabs = ({
34856
+ views,
34857
+ data,
34858
+ granularity,
34859
+ smoothingWindow,
34860
+ pageSize
34861
+ }) => {
34529
34862
  const [yAxisScaleType, setYAxisScaleType] = h$1("linear");
34530
34863
  const getTab = (view) => {
34531
34864
  switch (view) {
@@ -34558,6 +34891,7 @@ const NumberSequencesOverTimeTabs = ({ views, data, granularity, pageSize }) =>
34558
34891
  activeTab,
34559
34892
  data,
34560
34893
  granularity,
34894
+ smoothingWindow,
34561
34895
  yAxisScaleType,
34562
34896
  setYAxisScaleType
34563
34897
  }
@@ -34565,7 +34899,14 @@ const NumberSequencesOverTimeTabs = ({ views, data, granularity, pageSize }) =>
34565
34899
  }
34566
34900
  );
34567
34901
  };
34568
- const Toolbar$1 = ({ activeTab, data, granularity, yAxisScaleType, setYAxisScaleType }) => {
34902
+ const Toolbar$1 = ({
34903
+ activeTab,
34904
+ data,
34905
+ granularity,
34906
+ yAxisScaleType,
34907
+ setYAxisScaleType,
34908
+ smoothingWindow
34909
+ }) => {
34569
34910
  return /* @__PURE__ */ u$2(k$1, { children: [
34570
34911
  activeTab !== "Table" && /* @__PURE__ */ u$2(
34571
34912
  ScalingSelector,
@@ -34583,13 +34924,21 @@ const Toolbar$1 = ({ activeTab, data, granularity, yAxisScaleType, setYAxisScale
34583
34924
  filename: "number_of_sequences_over_time.csv"
34584
34925
  }
34585
34926
  ),
34586
- /* @__PURE__ */ u$2(NumberSequencesOverTimeInfo, {}),
34927
+ /* @__PURE__ */ u$2(NumberSequencesOverTimeInfo, { granularity, smoothingWindow }),
34587
34928
  /* @__PURE__ */ u$2(Fullscreen, {})
34588
34929
  ] });
34589
34930
  };
34590
- const NumberSequencesOverTimeInfo = () => /* @__PURE__ */ u$2(Info, { children: [
34931
+ const NumberSequencesOverTimeInfo = ({
34932
+ granularity,
34933
+ smoothingWindow
34934
+ }) => /* @__PURE__ */ u$2(Info, { children: [
34591
34935
  /* @__PURE__ */ u$2(InfoHeadline1, { children: "Number of sequences over time" }),
34592
- /* @__PURE__ */ u$2(InfoParagraph, { children: /* @__PURE__ */ u$2("a", { href: "https://github.com/GenSpectrum/dashboard-components/issues/315", children: "TODO" }) })
34936
+ /* @__PURE__ */ u$2(InfoParagraph, { children: [
34937
+ "This presents the number of available sequences of a variant per ",
34938
+ /* @__PURE__ */ u$2("b", { children: granularity }),
34939
+ smoothingWindow > 0 && `, smoothed using a ${smoothingWindow}-${granularity} sliding window`,
34940
+ "."
34941
+ ] })
34593
34942
  ] });
34594
34943
  var __defProp$6 = Object.defineProperty;
34595
34944
  var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
@@ -34656,308 +35005,43 @@ __decorateClass$6([
34656
35005
  NumberSequencesOverTimeComponent = __decorateClass$6([
34657
35006
  t$2("gs-number-sequences-over-time")
34658
35007
  ], NumberSequencesOverTimeComponent);
34659
- function getFilteredMutationOverTimeData(data, overallMutationData, displayedSegments, displayedMutationTypes, proportionInterval) {
34660
- const filteredData = data.copy();
34661
- filterDisplayedSegments(displayedSegments, filteredData);
34662
- filterMutationTypes(displayedMutationTypes, filteredData);
34663
- filterProportion(filteredData, overallMutationData, proportionInterval);
34664
- return filteredData;
35008
+ function getDefaultExportFromCjs(x2) {
35009
+ return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
34665
35010
  }
34666
- function filterDisplayedSegments(displayedSegments, data) {
34667
- displayedSegments.forEach((segment) => {
34668
- if (!segment.checked) {
34669
- data.getFirstAxisKeys().forEach((mutation) => {
34670
- if (mutation.segment === segment.segment) {
34671
- data.deleteRow(mutation);
34672
- }
34673
- });
34674
- }
34675
- });
35011
+ function commonjsRequire(path) {
35012
+ throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
34676
35013
  }
34677
- function filterMutationTypes(displayedMutationTypes, data) {
34678
- displayedMutationTypes.forEach((mutationType) => {
34679
- if (!mutationType.checked) {
34680
- data.getFirstAxisKeys().forEach((mutation) => {
34681
- if (mutationType.type === mutation.type) {
34682
- data.deleteRow(mutation);
35014
+ var object_hash = { exports: {} };
35015
+ (function(module, exports) {
35016
+ !function(e3) {
35017
+ module.exports = e3();
35018
+ }(function() {
35019
+ return function r2(o2, i3, u2) {
35020
+ function s6(n3, e4) {
35021
+ if (!i3[n3]) {
35022
+ if (!o2[n3]) {
35023
+ var t2 = "function" == typeof commonjsRequire && commonjsRequire;
35024
+ if (!e4 && t2) return t2(n3, true);
35025
+ if (a2) return a2(n3, true);
35026
+ throw new Error("Cannot find module '" + n3 + "'");
35027
+ }
35028
+ e4 = i3[n3] = { exports: {} };
35029
+ o2[n3][0].call(e4.exports, function(e5) {
35030
+ var t3 = o2[n3][1][e5];
35031
+ return s6(t3 || e5);
35032
+ }, e4, e4.exports, r2, o2, i3, u2);
34683
35033
  }
34684
- });
34685
- }
34686
- });
34687
- }
34688
- function filterProportion(data, overallMutationData, proportionInterval) {
34689
- const overallProportionsByMutation = overallMutationData.content.reduce(
34690
- (acc, { mutation, proportion }) => ({
34691
- ...acc,
34692
- [mutation.toString()]: proportion
34693
- }),
34694
- {}
34695
- );
34696
- data.getFirstAxisKeys().forEach((mutation) => {
34697
- const overallProportion = overallProportionsByMutation[mutation.toString()] || -1;
34698
- if (overallProportion < proportionInterval.min || overallProportion > proportionInterval.max) {
34699
- data.deleteRow(mutation);
34700
- }
34701
- });
34702
- }
34703
- const ColorScaleSelector = ({ colorScale, setColorScale }) => {
34704
- const colorDisplayCss = `w-10 h-8 border border-gray-200 mx-2 text-xs flex items-center justify-center`;
34705
- return /* @__PURE__ */ u$2("div", { className: "flex items-center", children: [
34706
- /* @__PURE__ */ u$2(
34707
- "div",
34708
- {
34709
- style: {
34710
- backgroundColor: singleGraphColorRGBByName(colorScale.color, 0),
34711
- color: "black"
34712
- },
34713
- className: colorDisplayCss,
34714
- children: formatProportion(colorScale.min, 0)
35034
+ return i3[n3].exports;
34715
35035
  }
34716
- ),
34717
- /* @__PURE__ */ u$2("div", { className: "w-64", children: /* @__PURE__ */ u$2(
34718
- MinMaxRangeSlider,
34719
- {
34720
- min: colorScale.min * 100,
34721
- max: colorScale.max * 100,
34722
- setMin: (percentage) => {
34723
- setColorScale({ ...colorScale, min: percentage / 100 });
34724
- },
34725
- setMax: (percentage) => {
34726
- setColorScale({ ...colorScale, max: percentage / 100 });
34727
- }
34728
- }
34729
- ) }),
34730
- /* @__PURE__ */ u$2(
34731
- "div",
34732
- {
34733
- style: {
34734
- backgroundColor: singleGraphColorRGBByName(colorScale.color, 1),
34735
- color: "white"
34736
- },
34737
- className: colorDisplayCss,
34738
- children: formatProportion(colorScale.max, 0)
34739
- }
34740
- )
34741
- ] });
34742
- };
34743
- const getColorWithingScale = (value, colorScale) => {
34744
- if (colorScale.min === colorScale.max) {
34745
- return singleGraphColorRGBByName(colorScale.color, 0);
34746
- }
34747
- const colorRange = colorScale.max - colorScale.min;
34748
- const alpha2 = (value - colorScale.min) / colorRange;
34749
- return singleGraphColorRGBByName(colorScale.color, alpha2);
34750
- };
34751
- const getTextColorForScale = (value, colorScale) => {
34752
- if (colorScale.min === colorScale.max) {
34753
- return "black";
34754
- }
34755
- const colorRange = colorScale.max - colorScale.min;
34756
- const alpha2 = (value - colorScale.min) / colorRange;
34757
- return alpha2 <= 0.5 ? "black" : "white";
34758
- };
34759
- function getPositionCss(position) {
34760
- switch (position) {
34761
- case "top":
34762
- return "bottom-full translate-x-[-50%] left-1/2 mb-1";
34763
- case "top-start":
34764
- return "bottom-full mr-1 mb-1";
34765
- case "top-end":
34766
- return "bottom-full right-0 ml-1 mb-1";
34767
- case "bottom":
34768
- return "top-full translate-x-[-50%] left-1/2 mt-1";
34769
- case "bottom-start":
34770
- return "mr-1 mt-1";
34771
- case "bottom-end":
34772
- return "right-0 ml-1 mt-1";
34773
- case "left":
34774
- return "right-full translate-y-[-50%] top-1/2 mr-1";
34775
- case "right":
34776
- return "left-full translate-y-[-50%] top-1/2 ml-1";
34777
- case void 0:
34778
- return "";
34779
- }
34780
- }
34781
- const Tooltip = ({ children, content, position = "bottom" }) => {
34782
- return /* @__PURE__ */ u$2("div", { className: "relative w-full h-full", children: [
34783
- /* @__PURE__ */ u$2("div", { className: "peer w-full h-full", children }),
34784
- /* @__PURE__ */ u$2(
34785
- "div",
34786
- {
34787
- className: `absolute z-10 w-max bg-white p-4 border border-gray-200 rounded-md invisible peer-hover:visible ${getPositionCss(position)}`,
34788
- children: content
34789
- }
34790
- )
34791
- ] });
34792
- };
34793
- const MAX_NUMBER_OF_GRID_ROWS = 100;
34794
- const MUTATION_CELL_WIDTH_REM = 8;
34795
- const MutationsOverTimeGrid = ({ data, colorScale }) => {
34796
- const allMutations = data.getFirstAxisKeys().sort(sortSubstitutionsAndDeletions);
34797
- const shownMutations = allMutations.slice(0, MAX_NUMBER_OF_GRID_ROWS);
34798
- const dates = data.getSecondAxisKeys().sort((a2, b3) => compareTemporal(a2, b3));
34799
- const [showProportionText, setShowProportionText] = h$1(false);
34800
- const gridRef = A$1(null);
34801
- useShowProportion(gridRef, dates.length, setShowProportionText);
34802
- return /* @__PURE__ */ u$2(k$1, { children: [
34803
- allMutations.length > MAX_NUMBER_OF_GRID_ROWS && /* @__PURE__ */ u$2("div", { className: "pl-2", children: [
34804
- "Showing ",
34805
- MAX_NUMBER_OF_GRID_ROWS,
34806
- " of ",
34807
- allMutations.length,
34808
- " mutations. You can narrow the filter to reduce the number of mutations."
34809
- ] }),
34810
- /* @__PURE__ */ u$2(
34811
- "div",
34812
- {
34813
- ref: gridRef,
34814
- style: {
34815
- display: "grid",
34816
- gridTemplateRows: `repeat(${shownMutations.length}, 24px)`,
34817
- gridTemplateColumns: `${MUTATION_CELL_WIDTH_REM}rem repeat(${dates.length}, minmax(0.05rem, 1fr))`
34818
- },
34819
- children: shownMutations.map((mutation, rowIndex) => {
34820
- return /* @__PURE__ */ u$2(k$1, { children: [
34821
- /* @__PURE__ */ u$2(
34822
- "div",
34823
- {
34824
- style: { gridRowStart: rowIndex + 1, gridColumnStart: 1 },
34825
- children: /* @__PURE__ */ u$2(MutationCell, { mutation })
34826
- },
34827
- `mutation-${mutation.toString()}`
34828
- ),
34829
- dates.map((date, columnIndex) => {
34830
- const value = data.get(mutation, date) ?? { proportion: 0, count: 0 };
34831
- const tooltipPosition = getTooltipPosition(
34832
- rowIndex,
34833
- shownMutations.length,
34834
- columnIndex,
34835
- dates.length
34836
- );
34837
- return /* @__PURE__ */ u$2(
34838
- "div",
34839
- {
34840
- style: { gridRowStart: rowIndex + 1, gridColumnStart: columnIndex + 2 },
34841
- children: /* @__PURE__ */ u$2(
34842
- ProportionCell,
34843
- {
34844
- value,
34845
- date,
34846
- mutation,
34847
- tooltipPosition,
34848
- showProportionText,
34849
- colorScale
34850
- }
34851
- )
34852
- },
34853
- `${mutation.toString()}-${date.toString()}`
34854
- );
34855
- })
34856
- ] }, `fragment-${mutation.toString()}`);
34857
- })
34858
- }
34859
- )
34860
- ] });
34861
- };
34862
- function useShowProportion(gridRef, girdColumns, setShowProportionText) {
34863
- y$1(() => {
34864
- const checkWidth = () => {
34865
- if (gridRef.current) {
34866
- const width = gridRef.current.getBoundingClientRect().width;
34867
- const widthPerDate = (width - remToPx(MUTATION_CELL_WIDTH_REM)) / girdColumns;
34868
- const maxWidthProportionText = 28;
34869
- setShowProportionText(widthPerDate > maxWidthProportionText);
34870
- }
34871
- };
34872
- checkWidth();
34873
- window.addEventListener("resize", checkWidth);
34874
- return () => {
34875
- window.removeEventListener("resize", checkWidth);
34876
- };
34877
- }, [girdColumns, gridRef, setShowProportionText]);
34878
- }
34879
- const remToPx = (rem) => rem * parseFloat(getComputedStyle(document.documentElement).fontSize);
34880
- function getTooltipPosition(rowIndex, rows, columnIndex, columns) {
34881
- const tooltipX = rowIndex < rows / 2 ? "bottom" : "top";
34882
- const tooltipY = columnIndex < columns / 2 ? "start" : "end";
34883
- return `${tooltipX}-${tooltipY}`;
34884
- }
34885
- const ProportionCell = ({ value, mutation, date, tooltipPosition, showProportionText, colorScale }) => {
34886
- const tooltipContent = /* @__PURE__ */ u$2("div", { children: [
34887
- /* @__PURE__ */ u$2("p", { children: /* @__PURE__ */ u$2("span", { className: "font-bold", children: date.englishName() }) }),
34888
- /* @__PURE__ */ u$2("p", { children: [
34889
- "(",
34890
- timeIntervalDisplay(date),
34891
- ")"
34892
- ] }),
34893
- /* @__PURE__ */ u$2("p", { children: mutation.code }),
34894
- /* @__PURE__ */ u$2("p", { children: [
34895
- "Proportion: ",
34896
- formatProportion(value.proportion)
34897
- ] }),
34898
- /* @__PURE__ */ u$2("p", { children: [
34899
- "Count: ",
34900
- value.count
34901
- ] })
34902
- ] });
34903
- return /* @__PURE__ */ u$2("div", { className: "py-1 w-full h-full", children: /* @__PURE__ */ u$2(Tooltip, { content: tooltipContent, position: tooltipPosition, children: /* @__PURE__ */ u$2(
34904
- "div",
34905
- {
34906
- style: {
34907
- backgroundColor: getColorWithingScale(value.proportion, colorScale),
34908
- color: getTextColorForScale(value.proportion, colorScale)
34909
- },
34910
- className: `w-full h-full text-center hover:font-bold text-xs group`,
34911
- children: showProportionText ? formatProportion(value.proportion, 0) : void 0
34912
- }
34913
- ) }) });
34914
- };
34915
- const timeIntervalDisplay = (date) => {
34916
- if (date instanceof YearMonthDay) {
34917
- return date.toString();
34918
- }
34919
- return `${date.firstDay.toString()} - ${date.lastDay.toString()}`;
34920
- };
34921
- const MutationCell = ({ mutation }) => {
34922
- return /* @__PURE__ */ u$2("div", { className: "text-center", children: mutation.toString() });
34923
- };
34924
- function getDefaultExportFromCjs(x2) {
34925
- return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
34926
- }
34927
- function commonjsRequire(path) {
34928
- throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
34929
- }
34930
- var object_hash = { exports: {} };
34931
- (function(module, exports) {
34932
- !function(e3) {
34933
- module.exports = e3();
34934
- }(function() {
34935
- return function r2(o2, i3, u2) {
34936
- function s6(n3, e4) {
34937
- if (!i3[n3]) {
34938
- if (!o2[n3]) {
34939
- var t2 = "function" == typeof commonjsRequire && commonjsRequire;
34940
- if (!e4 && t2) return t2(n3, true);
34941
- if (a2) return a2(n3, true);
34942
- throw new Error("Cannot find module '" + n3 + "'");
34943
- }
34944
- e4 = i3[n3] = { exports: {} };
34945
- o2[n3][0].call(e4.exports, function(e5) {
34946
- var t3 = o2[n3][1][e5];
34947
- return s6(t3 || e5);
34948
- }, e4, e4.exports, r2, o2, i3, u2);
34949
- }
34950
- return i3[n3].exports;
34951
- }
34952
- for (var a2 = "function" == typeof commonjsRequire && commonjsRequire, e3 = 0; e3 < u2.length; e3++) s6(u2[e3]);
34953
- return s6;
34954
- }({ 1: [function(w2, b3, m2) {
34955
- !(function(e3, n3, s6, c2, d2, h3, p2, g2, y2) {
34956
- var r2 = w2("crypto");
34957
- function t2(e4, t3) {
34958
- t3 = u2(e4, t3);
34959
- var n4;
34960
- return void 0 === (n4 = "passthrough" !== t3.algorithm ? r2.createHash(t3.algorithm) : new l2()).write && (n4.write = n4.update, n4.end = n4.update), f2(t3, n4).dispatch(e4), n4.update || n4.end(""), n4.digest ? n4.digest("buffer" === t3.encoding ? void 0 : t3.encoding) : (e4 = n4.read(), "buffer" !== t3.encoding ? e4.toString(t3.encoding) : e4);
35036
+ for (var a2 = "function" == typeof commonjsRequire && commonjsRequire, e3 = 0; e3 < u2.length; e3++) s6(u2[e3]);
35037
+ return s6;
35038
+ }({ 1: [function(w2, b3, m2) {
35039
+ !(function(e3, n3, s6, c2, d2, h3, p2, g2, y2) {
35040
+ var r2 = w2("crypto");
35041
+ function t2(e4, t3) {
35042
+ t3 = u2(e4, t3);
35043
+ var n4;
35044
+ return void 0 === (n4 = "passthrough" !== t3.algorithm ? r2.createHash(t3.algorithm) : new l2()).write && (n4.write = n4.update, n4.end = n4.update), f2(t3, n4).dispatch(e4), n4.update || n4.end(""), n4.digest ? n4.digest("buffer" === t3.encoding ? void 0 : t3.encoding) : (e4 = n4.read(), "buffer" !== t3.encoding ? e4.toString(t3.encoding) : e4);
34961
35045
  }
34962
35046
  (m2 = b3.exports = t2).sha1 = function(e4) {
34963
35047
  return t2(e4);
@@ -35712,7 +35796,7 @@ var object_hash = { exports: {} };
35712
35796
  })(object_hash);
35713
35797
  var object_hashExports = object_hash.exports;
35714
35798
  const hash = /* @__PURE__ */ getDefaultExportFromCjs(object_hashExports);
35715
- class Map2d {
35799
+ class Map2dBase {
35716
35800
  constructor(serializeFirstAxis = (key) => typeof key === "string" ? key : hash(key), serializeSecondAxis = (key) => typeof key === "string" ? key : hash(key)) {
35717
35801
  this.serializeFirstAxis = serializeFirstAxis;
35718
35802
  this.serializeSecondAxis = serializeSecondAxis;
@@ -35762,18 +35846,322 @@ class Map2d {
35762
35846
  });
35763
35847
  });
35764
35848
  }
35765
- copy() {
35766
- const copy = new Map2d(this.serializeFirstAxis, this.serializeSecondAxis);
35767
- this.data.forEach((value, key) => {
35768
- const keyFirstAxis = this.keysFirstAxis.get(key);
35769
- value.forEach((value2, key2) => {
35770
- const keySecondAxis = this.keysSecondAxis.get(key2);
35771
- copy.set(keyFirstAxis, keySecondAxis, value2);
35849
+ }
35850
+ class Map2dView {
35851
+ constructor(map2) {
35852
+ this.keysFirstAxis = new Map(map2.keysFirstAxis);
35853
+ this.keysSecondAxis = new Map(map2.keysSecondAxis);
35854
+ if (map2 instanceof Map2dView) {
35855
+ this.baseMap = map2.baseMap;
35856
+ }
35857
+ this.baseMap = map2;
35858
+ }
35859
+ serializeFirstAxis(key) {
35860
+ return this.baseMap.serializeFirstAxis(key);
35861
+ }
35862
+ serializeSecondAxis(key) {
35863
+ return this.baseMap.serializeSecondAxis(key);
35864
+ }
35865
+ deleteRow(key) {
35866
+ this.keysFirstAxis.delete(this.serializeFirstAxis(key));
35867
+ }
35868
+ get(keyFirstAxis, keySecondAxis) {
35869
+ const firstAxisKey = this.serializeFirstAxis(keyFirstAxis);
35870
+ const secondAxisKey = this.serializeSecondAxis(keySecondAxis);
35871
+ if (!this.keysFirstAxis.has(firstAxisKey) || !this.keysSecondAxis.has(secondAxisKey)) {
35872
+ return void 0;
35873
+ }
35874
+ return this.baseMap.get(keyFirstAxis, keySecondAxis);
35875
+ }
35876
+ set() {
35877
+ throw new Error("Cannot set value on a Map2dView");
35878
+ }
35879
+ getFirstAxisKeys() {
35880
+ return Array.from(this.keysFirstAxis.values());
35881
+ }
35882
+ getSecondAxisKeys() {
35883
+ return Array.from(this.keysSecondAxis.values());
35884
+ }
35885
+ getAsArray(fillEmptyWith) {
35886
+ return this.getFirstAxisKeys().map((firstAxisKey) => {
35887
+ return this.getSecondAxisKeys().map((secondAxisKey) => {
35888
+ return this.baseMap.get(firstAxisKey, secondAxisKey) ?? fillEmptyWith;
35772
35889
  });
35773
35890
  });
35774
- return copy;
35891
+ }
35892
+ getRow(key, fillEmptyWith) {
35893
+ const serializedKeyFirstAxis = this.serializeFirstAxis(key);
35894
+ if (!this.keysFirstAxis.has(serializedKeyFirstAxis)) {
35895
+ return [];
35896
+ }
35897
+ return this.baseMap.getRow(key, fillEmptyWith);
35898
+ }
35899
+ }
35900
+ function getFilteredMutationOverTimeData(data, overallMutationData, displayedSegments, displayedMutationTypes, proportionInterval) {
35901
+ const filteredData = new Map2dView(data);
35902
+ filterDisplayedSegments(displayedSegments, filteredData);
35903
+ filterMutationTypes(displayedMutationTypes, filteredData);
35904
+ filterProportion(filteredData, overallMutationData, proportionInterval);
35905
+ return filteredData;
35906
+ }
35907
+ function filterDisplayedSegments(displayedSegments, data) {
35908
+ displayedSegments.forEach((segment) => {
35909
+ if (!segment.checked) {
35910
+ data.getFirstAxisKeys().forEach((mutation) => {
35911
+ if (mutation.segment === segment.segment) {
35912
+ data.deleteRow(mutation);
35913
+ }
35914
+ });
35915
+ }
35916
+ });
35917
+ }
35918
+ function filterMutationTypes(displayedMutationTypes, data) {
35919
+ displayedMutationTypes.forEach((mutationType) => {
35920
+ if (!mutationType.checked) {
35921
+ data.getFirstAxisKeys().forEach((mutation) => {
35922
+ if (mutationType.type === mutation.type) {
35923
+ data.deleteRow(mutation);
35924
+ }
35925
+ });
35926
+ }
35927
+ });
35928
+ }
35929
+ function filterProportion(data, overallMutationData, proportionInterval) {
35930
+ const overallProportionsByMutation = overallMutationData.content.reduce(
35931
+ (acc, { mutation, proportion }) => ({
35932
+ ...acc,
35933
+ [mutation.toString()]: proportion
35934
+ }),
35935
+ {}
35936
+ );
35937
+ data.getFirstAxisKeys().forEach((mutation) => {
35938
+ const overallProportion = overallProportionsByMutation[mutation.toString()] || -1;
35939
+ if (overallProportion < proportionInterval.min || overallProportion > proportionInterval.max) {
35940
+ data.deleteRow(mutation);
35941
+ }
35942
+ });
35943
+ }
35944
+ const ColorScaleSelector = ({ colorScale, setColorScale }) => {
35945
+ const colorDisplayCss = `w-10 h-8 border border-gray-200 mx-2 text-xs flex items-center justify-center`;
35946
+ return /* @__PURE__ */ u$2("div", { className: "flex items-center", children: [
35947
+ /* @__PURE__ */ u$2(
35948
+ "div",
35949
+ {
35950
+ style: {
35951
+ backgroundColor: singleGraphColorRGBByName(colorScale.color, 0),
35952
+ color: "black"
35953
+ },
35954
+ className: colorDisplayCss,
35955
+ children: formatProportion(colorScale.min, 0)
35956
+ }
35957
+ ),
35958
+ /* @__PURE__ */ u$2("div", { className: "w-64", children: /* @__PURE__ */ u$2(
35959
+ MinMaxRangeSlider,
35960
+ {
35961
+ min: colorScale.min * 100,
35962
+ max: colorScale.max * 100,
35963
+ setMin: (percentage) => {
35964
+ setColorScale({ ...colorScale, min: percentage / 100 });
35965
+ },
35966
+ setMax: (percentage) => {
35967
+ setColorScale({ ...colorScale, max: percentage / 100 });
35968
+ }
35969
+ }
35970
+ ) }),
35971
+ /* @__PURE__ */ u$2(
35972
+ "div",
35973
+ {
35974
+ style: {
35975
+ backgroundColor: singleGraphColorRGBByName(colorScale.color, 1),
35976
+ color: "white"
35977
+ },
35978
+ className: colorDisplayCss,
35979
+ children: formatProportion(colorScale.max, 0)
35980
+ }
35981
+ )
35982
+ ] });
35983
+ };
35984
+ const getColorWithingScale = (value, colorScale) => {
35985
+ if (colorScale.min === colorScale.max) {
35986
+ return singleGraphColorRGBByName(colorScale.color, 0);
35987
+ }
35988
+ const colorRange = colorScale.max - colorScale.min;
35989
+ const alpha2 = (value - colorScale.min) / colorRange;
35990
+ return singleGraphColorRGBByName(colorScale.color, alpha2);
35991
+ };
35992
+ const getTextColorForScale = (value, colorScale) => {
35993
+ if (colorScale.min === colorScale.max) {
35994
+ return "black";
35995
+ }
35996
+ const colorRange = colorScale.max - colorScale.min;
35997
+ const alpha2 = (value - colorScale.min) / colorRange;
35998
+ return alpha2 <= 0.5 ? "black" : "white";
35999
+ };
36000
+ function getPositionCss(position) {
36001
+ switch (position) {
36002
+ case "top":
36003
+ return "bottom-full translate-x-[-50%] left-1/2 mb-1";
36004
+ case "top-start":
36005
+ return "bottom-full mr-1 mb-1";
36006
+ case "top-end":
36007
+ return "bottom-full right-0 ml-1 mb-1";
36008
+ case "bottom":
36009
+ return "top-full translate-x-[-50%] left-1/2 mt-1";
36010
+ case "bottom-start":
36011
+ return "mr-1 mt-1";
36012
+ case "bottom-end":
36013
+ return "right-0 ml-1 mt-1";
36014
+ case "left":
36015
+ return "right-full translate-y-[-50%] top-1/2 mr-1";
36016
+ case "right":
36017
+ return "left-full translate-y-[-50%] top-1/2 ml-1";
36018
+ case void 0:
36019
+ return "";
35775
36020
  }
35776
36021
  }
36022
+ const Tooltip = ({ children, content, position = "bottom" }) => {
36023
+ return /* @__PURE__ */ u$2("div", { className: "relative w-full h-full", children: [
36024
+ /* @__PURE__ */ u$2("div", { className: "peer w-full h-full", children }),
36025
+ /* @__PURE__ */ u$2(
36026
+ "div",
36027
+ {
36028
+ className: `absolute z-10 w-max bg-white p-4 border border-gray-200 rounded-md invisible peer-hover:visible ${getPositionCss(position)}`,
36029
+ children: content
36030
+ }
36031
+ )
36032
+ ] });
36033
+ };
36034
+ const MAX_NUMBER_OF_GRID_ROWS = 100;
36035
+ const MUTATION_CELL_WIDTH_REM = 8;
36036
+ const MutationsOverTimeGrid = ({ data, colorScale }) => {
36037
+ const allMutations = data.getFirstAxisKeys().sort(sortSubstitutionsAndDeletions);
36038
+ const shownMutations = allMutations.slice(0, MAX_NUMBER_OF_GRID_ROWS);
36039
+ const dates = data.getSecondAxisKeys().sort((a2, b3) => compareTemporal(a2, b3));
36040
+ const [showProportionText, setShowProportionText] = h$1(false);
36041
+ const gridRef = A$1(null);
36042
+ useShowProportion(gridRef, dates.length, setShowProportionText);
36043
+ return /* @__PURE__ */ u$2(k$1, { children: [
36044
+ allMutations.length > MAX_NUMBER_OF_GRID_ROWS && /* @__PURE__ */ u$2("div", { className: "pl-2", children: [
36045
+ "Showing ",
36046
+ MAX_NUMBER_OF_GRID_ROWS,
36047
+ " of ",
36048
+ allMutations.length,
36049
+ " mutations. You can narrow the filter to reduce the number of mutations."
36050
+ ] }),
36051
+ /* @__PURE__ */ u$2(
36052
+ "div",
36053
+ {
36054
+ ref: gridRef,
36055
+ style: {
36056
+ display: "grid",
36057
+ gridTemplateRows: `repeat(${shownMutations.length}, 24px)`,
36058
+ gridTemplateColumns: `${MUTATION_CELL_WIDTH_REM}rem repeat(${dates.length}, minmax(0.05rem, 1fr))`
36059
+ },
36060
+ children: shownMutations.map((mutation, rowIndex) => {
36061
+ return /* @__PURE__ */ u$2(k$1, { children: [
36062
+ /* @__PURE__ */ u$2(
36063
+ "div",
36064
+ {
36065
+ style: { gridRowStart: rowIndex + 1, gridColumnStart: 1 },
36066
+ children: /* @__PURE__ */ u$2(MutationCell, { mutation })
36067
+ },
36068
+ `mutation-${mutation.toString()}`
36069
+ ),
36070
+ dates.map((date, columnIndex) => {
36071
+ const value = data.get(mutation, date) ?? { proportion: 0, count: 0 };
36072
+ const tooltipPosition = getTooltipPosition(
36073
+ rowIndex,
36074
+ shownMutations.length,
36075
+ columnIndex,
36076
+ dates.length
36077
+ );
36078
+ return /* @__PURE__ */ u$2(
36079
+ "div",
36080
+ {
36081
+ style: { gridRowStart: rowIndex + 1, gridColumnStart: columnIndex + 2 },
36082
+ children: /* @__PURE__ */ u$2(
36083
+ ProportionCell,
36084
+ {
36085
+ value,
36086
+ date,
36087
+ mutation,
36088
+ tooltipPosition,
36089
+ showProportionText,
36090
+ colorScale
36091
+ }
36092
+ )
36093
+ },
36094
+ `${mutation.toString()}-${date.toString()}`
36095
+ );
36096
+ })
36097
+ ] }, `fragment-${mutation.toString()}`);
36098
+ })
36099
+ }
36100
+ )
36101
+ ] });
36102
+ };
36103
+ function useShowProportion(gridRef, girdColumns, setShowProportionText) {
36104
+ y$1(() => {
36105
+ const checkWidth = () => {
36106
+ if (gridRef.current) {
36107
+ const width = gridRef.current.getBoundingClientRect().width;
36108
+ const widthPerDate = (width - remToPx(MUTATION_CELL_WIDTH_REM)) / girdColumns;
36109
+ const maxWidthProportionText = 28;
36110
+ setShowProportionText(widthPerDate > maxWidthProportionText);
36111
+ }
36112
+ };
36113
+ checkWidth();
36114
+ window.addEventListener("resize", checkWidth);
36115
+ return () => {
36116
+ window.removeEventListener("resize", checkWidth);
36117
+ };
36118
+ }, [girdColumns, gridRef, setShowProportionText]);
36119
+ }
36120
+ const remToPx = (rem) => rem * parseFloat(getComputedStyle(document.documentElement).fontSize);
36121
+ function getTooltipPosition(rowIndex, rows, columnIndex, columns) {
36122
+ const tooltipX = rowIndex < rows / 2 ? "bottom" : "top";
36123
+ const tooltipY = columnIndex < columns / 2 ? "start" : "end";
36124
+ return `${tooltipX}-${tooltipY}`;
36125
+ }
36126
+ const ProportionCell = ({ value, mutation, date, tooltipPosition, showProportionText, colorScale }) => {
36127
+ const tooltipContent = /* @__PURE__ */ u$2("div", { children: [
36128
+ /* @__PURE__ */ u$2("p", { children: /* @__PURE__ */ u$2("span", { className: "font-bold", children: date.englishName() }) }),
36129
+ /* @__PURE__ */ u$2("p", { children: [
36130
+ "(",
36131
+ timeIntervalDisplay(date),
36132
+ ")"
36133
+ ] }),
36134
+ /* @__PURE__ */ u$2("p", { children: mutation.code }),
36135
+ /* @__PURE__ */ u$2("p", { children: [
36136
+ "Proportion: ",
36137
+ formatProportion(value.proportion)
36138
+ ] }),
36139
+ /* @__PURE__ */ u$2("p", { children: [
36140
+ "Count: ",
36141
+ value.count
36142
+ ] })
36143
+ ] });
36144
+ return /* @__PURE__ */ u$2("div", { className: "py-1 w-full h-full", children: /* @__PURE__ */ u$2(Tooltip, { content: tooltipContent, position: tooltipPosition, children: /* @__PURE__ */ u$2(
36145
+ "div",
36146
+ {
36147
+ style: {
36148
+ backgroundColor: getColorWithingScale(value.proportion, colorScale),
36149
+ color: getTextColorForScale(value.proportion, colorScale)
36150
+ },
36151
+ className: `w-full h-full text-center hover:font-bold text-xs group`,
36152
+ children: showProportionText ? formatProportion(value.proportion, 0) : void 0
36153
+ }
36154
+ ) }) });
36155
+ };
36156
+ const timeIntervalDisplay = (date) => {
36157
+ if (date instanceof YearMonthDay) {
36158
+ return date.toString();
36159
+ }
36160
+ return `${date.firstDay.toString()} - ${date.lastDay.toString()}`;
36161
+ };
36162
+ const MutationCell = ({ mutation }) => {
36163
+ return /* @__PURE__ */ u$2("div", { className: "text-center", children: mutation.toString() });
36164
+ };
35777
36165
  const MAX_NUMBER_OF_GRID_COLUMNS = 200;
35778
36166
  async function queryOverallMutationData(lapisFilter, sequenceType, lapis, signal) {
35779
36167
  return fetchAndPrepareSubstitutionsOrDeletions(lapisFilter, sequenceType).evaluate(lapis, signal);
@@ -35845,7 +36233,7 @@ function fetchAndPrepareSubstitutionsOrDeletions(filter, sequenceType) {
35845
36233
  return new FetchSubstitutionsOrDeletionsOperator(filter, sequenceType, 1e-3);
35846
36234
  }
35847
36235
  function groupByMutation(data) {
35848
- const dataArray = new Map2d(
36236
+ const dataArray = new Map2dBase(
35849
36237
  (mutation) => mutation.code,
35850
36238
  (date) => date.toString()
35851
36239
  );
@@ -35874,7 +36262,7 @@ const ColorScaleSelectorDropdown = ({
35874
36262
  colorScale,
35875
36263
  setColorScale
35876
36264
  }) => {
35877
- return /* @__PURE__ */ u$2(Dropdown, { buttonTitle: `Color scale`, placement: "bottom-start", children: /* @__PURE__ */ u$2(ColorScaleSelector, { colorScale, setColorScale }) });
36265
+ return /* @__PURE__ */ u$2("div", { className: "w-20", children: /* @__PURE__ */ u$2(Dropdown, { buttonTitle: `Color scale`, placement: "bottom-start", children: /* @__PURE__ */ u$2(ColorScaleSelector, { colorScale, setColorScale }) }) });
35878
36266
  };
35879
36267
  const MutationsOverTime = ({ width, height, ...innerProps }) => {
35880
36268
  const size = { height, width };