@genspectrum/dashboard-components 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/custom-elements.json +186 -23
  2. package/dist/assets/{mutationOverTimeWorker-CvZg52rf.js.map → mutationOverTimeWorker-Di6yP1e6.js.map} +1 -1
  3. package/dist/components.d.ts +95 -45
  4. package/dist/components.js +402 -182
  5. package/dist/components.js.map +1 -1
  6. package/dist/{utilEntrypoint-g4DsyhU7.js → dateRangeOption-du8H7LWu.js} +33 -2
  7. package/dist/dateRangeOption-du8H7LWu.js.map +1 -0
  8. package/dist/style.css +41 -0
  9. package/dist/util.d.ts +114 -56
  10. package/dist/util.js +3 -2
  11. package/package.json +2 -2
  12. package/src/preact/components/color-scale-selector.tsx +7 -3
  13. package/src/preact/components/error-boundary.tsx +39 -5
  14. package/src/preact/components/error-display.tsx +40 -5
  15. package/src/preact/components/min-max-range-slider.tsx +4 -4
  16. package/src/preact/components/percent-intput.tsx +2 -2
  17. package/src/preact/dateRangeSelector/computeInitialValues.spec.ts +8 -2
  18. package/src/preact/dateRangeSelector/computeInitialValues.ts +6 -0
  19. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +16 -2
  20. package/src/preact/dateRangeSelector/date-range-selector.tsx +20 -15
  21. package/src/preact/dateRangeSelector/dateRangeOption.ts +10 -5
  22. package/src/preact/lineageFilter/lineage-filter.stories.tsx +18 -4
  23. package/src/preact/lineageFilter/lineage-filter.tsx +15 -10
  24. package/src/preact/locationFilter/location-filter.stories.tsx +14 -0
  25. package/src/preact/locationFilter/location-filter.tsx +15 -10
  26. package/src/preact/mutationComparison/mutation-comparison-venn.tsx +17 -18
  27. package/src/preact/mutationComparison/mutation-comparison.tsx +18 -12
  28. package/src/preact/mutationFilter/mutation-filter.tsx +0 -1
  29. package/src/preact/mutationsOverTime/__mockData__/aminoAcidMutationsByDay.ts +1326 -9341
  30. package/src/preact/mutationsOverTime/__mockData__/byWeek.ts +615 -4920
  31. package/src/preact/mutationsOverTime/__mockData__/defaultMockData.ts +2203 -17624
  32. package/src/preact/mutationsOverTime/mutations-over-time-grid.tsx +16 -8
  33. package/src/preact/mutationsOverTime/mutations-over-time.tsx +1 -3
  34. package/src/preact/shared/stories/expectInvalidAttributesErrorMessage.ts +13 -0
  35. package/src/preact/statistic/__mockData__/denominator.json +13 -0
  36. package/src/preact/statistic/__mockData__/numerator.json +13 -0
  37. package/src/preact/statistic/statistics.stories.tsx +81 -0
  38. package/src/preact/statistic/statistics.tsx +78 -0
  39. package/src/preact/webWorkers/useWebWorker.ts +8 -4
  40. package/src/query/queryGeneralStatistics.ts +18 -0
  41. package/src/query/queryMutationsOverTime.spec.ts +12 -27
  42. package/src/query/queryMutationsOverTime.ts +2 -6
  43. package/src/types.ts +19 -6
  44. package/src/utilEntrypoint.ts +8 -0
  45. package/src/utils/map2d.spec.ts +10 -10
  46. package/src/utils/map2d.ts +10 -10
  47. package/src/web-components/input/gs-date-range-selector.stories.ts +2 -2
  48. package/src/web-components/input/gs-date-range-selector.tsx +3 -3
  49. package/src/web-components/input/gs-lineage-filter.tsx +1 -1
  50. package/src/web-components/input/gs-location-filter.tsx +2 -2
  51. package/src/web-components/visualization/gs-aggregate.tsx +2 -2
  52. package/src/web-components/visualization/gs-statistics.stories.ts +95 -0
  53. package/src/web-components/visualization/gs-statistics.tsx +83 -0
  54. package/src/web-components/visualization/index.ts +1 -0
  55. package/standalone-bundle/assets/{mutationOverTimeWorker-CypX_PYM.js.map → mutationOverTimeWorker-cIyshfj_.js.map} +1 -1
  56. package/standalone-bundle/dashboard-components.js +7747 -7592
  57. package/standalone-bundle/dashboard-components.js.map +1 -1
  58. package/standalone-bundle/style.css +1 -1
  59. package/dist/utilEntrypoint-g4DsyhU7.js.map +0 -1
@@ -1,7 +1,33 @@
1
+ import z from "zod";
2
+ const lapisFilterSchema = z.record(z.union([z.string(), z.number(), z.null(), z.boolean()]));
3
+ const namedLapisFilterSchema = z.object({
4
+ lapisFilter: lapisFilterSchema,
5
+ displayName: z.string()
6
+ });
7
+ const sequenceTypeSchema = z.union([z.literal("nucleotide"), z.literal("amino acid")]);
8
+ const views = {
9
+ table: "table",
10
+ venn: "venn"
11
+ };
12
+ const mutationComparisonViewSchema = z.union([z.literal(views.table), z.literal(views.venn)]);
1
13
  const toYYYYMMDD = (date) => {
2
14
  const options = { year: "numeric", month: "2-digit", day: "2-digit" };
3
15
  return date.toLocaleDateString("en-CA", options);
4
16
  };
17
+ const dateRangeOptionSchema = z.object({
18
+ /** The label of the date range option that will be shown to the user */
19
+ label: z.string(),
20
+ /**
21
+ * The start date of the date range in the format `YYYY-MM-DD`.
22
+ * If not set, the date range selector will default to the `earliestDate` property.
23
+ */
24
+ dateFrom: z.string().date().optional(),
25
+ /**
26
+ * The end date of the date range in the format `YYYY-MM-DD`.
27
+ * If not set, the date range selector will default to the current date.
28
+ */
29
+ dateTo: z.string().date().optional()
30
+ });
5
31
  class DateRangeOptionChangedEvent extends CustomEvent {
6
32
  constructor(detail) {
7
33
  super("gs-date-range-option-changed", {
@@ -55,7 +81,12 @@ const dateRangeOptionPresets = {
55
81
  };
56
82
  export {
57
83
  DateRangeOptionChangedEvent as D,
84
+ dateRangeOptionSchema as a,
58
85
  dateRangeOptionPresets as d,
59
- toYYYYMMDD as t
86
+ mutationComparisonViewSchema as m,
87
+ namedLapisFilterSchema as n,
88
+ sequenceTypeSchema as s,
89
+ toYYYYMMDD as t,
90
+ views as v
60
91
  };
61
- //# sourceMappingURL=utilEntrypoint-g4DsyhU7.js.map
92
+ //# sourceMappingURL=dateRangeOption-du8H7LWu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dateRangeOption-du8H7LWu.js","sources":["../src/types.ts","../src/preact/dateRangeSelector/dateConversion.ts","../src/preact/dateRangeSelector/dateRangeOption.ts"],"sourcesContent":["import z from 'zod';\n\nimport {\n type Deletion,\n type DeletionClass,\n type Insertion,\n type InsertionClass,\n type Substitution,\n type SubstitutionClass,\n} from './utils/mutations';\n\nexport const lapisFilterSchema = z.record(z.union([z.string(), z.number(), z.null(), z.boolean()]));\nexport type LapisFilter = z.infer<typeof lapisFilterSchema>;\n\nexport const namedLapisFilterSchema = z.object({\n lapisFilter: lapisFilterSchema,\n displayName: z.string(),\n});\nexport type NamedLapisFilter = z.infer<typeof namedLapisFilterSchema>;\n\nexport type TemporalGranularity = 'day' | 'week' | 'month' | 'year';\n\nexport const sequenceTypeSchema = z.union([z.literal('nucleotide'), z.literal('amino acid')]);\nexport type SequenceType = z.infer<typeof sequenceTypeSchema>;\n\nexport type SubstitutionOrDeletion = 'substitution' | 'deletion';\n\nexport type MutationType = SubstitutionOrDeletion | 'insertion';\n\nexport type SubstitutionEntry<T extends Substitution = SubstitutionClass> = {\n type: 'substitution';\n mutation: T;\n count: number;\n proportion: number;\n};\n\nexport type DeletionEntry<T extends Deletion = DeletionClass> = {\n type: 'deletion';\n mutation: T;\n count: number;\n proportion: number;\n};\n\nexport type InsertionEntry<T extends Insertion = InsertionClass> = { type: 'insertion'; mutation: T; count: number };\n\nexport type SubstitutionOrDeletionEntry<\n S extends Substitution = SubstitutionClass,\n D extends Deletion = DeletionClass,\n> = SubstitutionEntry<S> | DeletionEntry<D>;\n\nexport type MutationEntry = SubstitutionEntry | DeletionEntry | InsertionEntry;\n\nexport const views = {\n table: 'table',\n venn: 'venn',\n} as const;\n\nexport const mutationComparisonViewSchema = z.union([z.literal(views.table), z.literal(views.venn)]);\nexport type MutationComparisonView = z.infer<typeof mutationComparisonViewSchema>;\n","export const toYYYYMMDD = (date: Date) => {\n const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: '2-digit', day: '2-digit' };\n return date.toLocaleDateString('en-CA', options);\n};\n","import z from 'zod';\n\nimport { toYYYYMMDD } from './dateConversion';\n\n/**\n * A date range option that can be used in the `gs-date-range-selector` component.\n */\nexport const dateRangeOptionSchema = z.object({\n /** The label of the date range option that will be shown to the user */\n label: z.string(),\n /**\n * The start date of the date range in the format `YYYY-MM-DD`.\n * If not set, the date range selector will default to the `earliestDate` property.\n */\n dateFrom: z.string().date().optional(),\n /**\n * The end date of the date range in the format `YYYY-MM-DD`.\n * If not set, the date range selector will default to the current date.\n */\n dateTo: z.string().date().optional(),\n});\n\nexport type DateRangeOption = z.infer<typeof dateRangeOptionSchema>;\n\nexport type DateRangeSelectOption = string | { dateFrom: string; dateTo: string };\n\nexport class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {\n constructor(detail: DateRangeSelectOption) {\n super('gs-date-range-option-changed', {\n detail,\n bubbles: true,\n composed: true,\n });\n }\n}\n\nconst today = new Date();\n\nconst twoWeeksAgo = new Date();\ntwoWeeksAgo.setDate(today.getDate() - 14);\n\nconst lastMonth = new Date(today);\nlastMonth.setMonth(today.getMonth() - 1);\n\nconst last2Months = new Date(today);\nlast2Months.setMonth(today.getMonth() - 2);\n\nconst last3Months = new Date(today);\nlast3Months.setMonth(today.getMonth() - 3);\n\nconst last6Months = new Date(today);\nlast6Months.setMonth(today.getMonth() - 6);\n\nconst lastYear = new Date(today);\nlastYear.setFullYear(today.getFullYear() - 1);\n\n/**\n * Presets for the `gs-date-range-selector` component that can be used as `dateRangeOptions`.\n */\nexport const dateRangeOptionPresets = {\n last2Weeks: {\n label: 'Last 2 weeks',\n dateFrom: toYYYYMMDD(twoWeeksAgo),\n },\n lastMonth: {\n label: 'Last month',\n dateFrom: toYYYYMMDD(lastMonth),\n },\n last2Months: {\n label: 'Last 2 months',\n dateFrom: toYYYYMMDD(last2Months),\n },\n last3Months: {\n label: 'Last 3 months',\n dateFrom: toYYYYMMDD(last3Months),\n },\n last6Months: {\n label: 'Last 6 months',\n dateFrom: toYYYYMMDD(last6Months),\n },\n lastYear: {\n label: 'Last year',\n dateFrom: toYYYYMMDD(lastYear),\n },\n allTimes: {\n label: 'All times',\n },\n} satisfies Record<string, DateRangeOption>;\n"],"names":[],"mappings":";AAWO,MAAM,oBAAoB,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGrF,MAAA,yBAAyB,EAAE,OAAO;AAAA,EAC3C,aAAa;AAAA,EACb,aAAa,EAAE,OAAO;AAC1B,CAAC;AAKM,MAAM,qBAAqB,EAAE,MAAM,CAAC,EAAE,QAAQ,YAAY,GAAG,EAAE,QAAQ,YAAY,CAAC,CAAC;AA8BrF,MAAM,QAAQ;AAAA,EACjB,OAAO;AAAA,EACP,MAAM;AACV;AAEO,MAAM,+BAA+B,EAAE,MAAM,CAAC,EAAE,QAAQ,MAAM,KAAK,GAAG,EAAE,QAAQ,MAAM,IAAI,CAAC,CAAC;ACzDtF,MAAA,aAAa,CAAC,SAAe;AACtC,QAAM,UAAsC,EAAE,MAAM,WAAW,OAAO,WAAW,KAAK;AAC/E,SAAA,KAAK,mBAAmB,SAAS,OAAO;AACnD;ACIa,MAAA,wBAAwB,EAAE,OAAO;AAAA;AAAA,EAE1C,OAAO,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhB,UAAU,EAAE,OAAS,EAAA,KAAA,EAAO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrC,QAAQ,EAAE,OAAS,EAAA,KAAA,EAAO,SAAS;AACvC,CAAC;AAMM,MAAM,oCAAoC,YAAmC;AAAA,EAChF,YAAY,QAA+B;AACvC,UAAM,gCAAgC;AAAA,MAClC;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IAAA,CACb;AAAA,EACL;AACJ;AAEA,MAAM,4BAAY;AAElB,MAAM,kCAAkB;AACxB,YAAY,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAExC,MAAM,YAAY,IAAI,KAAK,KAAK;AAChC,UAAU,SAAS,MAAM,SAAS,IAAI,CAAC;AAEvC,MAAM,cAAc,IAAI,KAAK,KAAK;AAClC,YAAY,SAAS,MAAM,SAAS,IAAI,CAAC;AAEzC,MAAM,cAAc,IAAI,KAAK,KAAK;AAClC,YAAY,SAAS,MAAM,SAAS,IAAI,CAAC;AAEzC,MAAM,cAAc,IAAI,KAAK,KAAK;AAClC,YAAY,SAAS,MAAM,SAAS,IAAI,CAAC;AAEzC,MAAM,WAAW,IAAI,KAAK,KAAK;AAC/B,SAAS,YAAY,MAAM,YAAY,IAAI,CAAC;AAKrC,MAAM,yBAAyB;AAAA,EAClC,YAAY;AAAA,IACR,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,WAAW;AAAA,IACP,OAAO;AAAA,IACP,UAAU,WAAW,SAAS;AAAA,EAClC;AAAA,EACA,aAAa;AAAA,IACT,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,aAAa;AAAA,IACT,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,aAAa;AAAA,IACT,OAAO;AAAA,IACP,UAAU,WAAW,WAAW;AAAA,EACpC;AAAA,EACA,UAAU;AAAA,IACN,OAAO;AAAA,IACP,UAAU,WAAW,QAAQ;AAAA,EACjC;AAAA,EACA,UAAU;AAAA,IACN,OAAO;AAAA,EACX;AACJ;"}
package/dist/style.css CHANGED
@@ -1561,6 +1561,38 @@ html {
1561
1561
  .select[multiple] {
1562
1562
  height: auto;
1563
1563
  }
1564
+ .stat {
1565
+ display: inline-grid;
1566
+ width: 100%;
1567
+ grid-template-columns: repeat(1, 1fr);
1568
+ -moz-column-gap: 1rem;
1569
+ column-gap: 1rem;
1570
+ border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
1571
+ --tw-border-opacity: 0.1;
1572
+ padding-left: 1.5rem;
1573
+ padding-right: 1.5rem;
1574
+ padding-top: 1rem;
1575
+ padding-bottom: 1rem;
1576
+ }
1577
+ .stat-title {
1578
+ grid-column-start: 1;
1579
+ white-space: nowrap;
1580
+ color: var(--fallback-bc,oklch(var(--bc)/0.6));
1581
+ }
1582
+ .stat-value {
1583
+ grid-column-start: 1;
1584
+ white-space: nowrap;
1585
+ font-size: 2.25rem;
1586
+ line-height: 2.5rem;
1587
+ font-weight: 800;
1588
+ }
1589
+ .stat-desc {
1590
+ grid-column-start: 1;
1591
+ white-space: nowrap;
1592
+ font-size: 0.75rem;
1593
+ line-height: 1rem;
1594
+ color: var(--fallback-bc,oklch(var(--bc)/0.6));
1595
+ }
1564
1596
  .steps {
1565
1597
  display: inline-grid;
1566
1598
  grid-auto-flow: column;
@@ -3427,6 +3459,15 @@ input.tab:checked + .tab-content,
3427
3459
  .sm\:max-w-5xl {
3428
3460
  max-width: 64rem;
3429
3461
  }
3462
+
3463
+ .sm\:flex-row {
3464
+ flex-direction: row;
3465
+ }
3466
+
3467
+ .sm\:text-4xl {
3468
+ font-size: 2.25rem;
3469
+ line-height: 2.5rem;
3470
+ }
3430
3471
  }.flatpickr-calendar{background:transparent;opacity:0;display:none;text-align:center;visibility:hidden;padding:0;-webkit-animation:none;animation:none;direction:ltr;border:0;font-size:14px;line-height:24px;border-radius:5px;position:absolute;width:307.875px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-touch-action:manipulation;touch-action:manipulation;background:#fff;-webkit-box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08);box-shadow:1px 0 0 #e6e6e6,-1px 0 0 #e6e6e6,0 1px 0 #e6e6e6,0 -1px 0 #e6e6e6,0 3px 13px rgba(0,0,0,0.08)}.flatpickr-calendar.open,.flatpickr-calendar.inline{opacity:1;max-height:640px;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1);animation:fpFadeInDown 300ms cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px)}.flatpickr-calendar.static.open{z-index:999;display:block}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){-webkit-box-shadow:none !important;box-shadow:none !important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){-webkit-box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6;box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasWeeks .dayContainer,.flatpickr-calendar .hasTime .dayContainer{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.hasTime .flatpickr-time{height:40px;border-top:1px solid #e6e6e6}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:before,.flatpickr-calendar:after{position:absolute;display:block;pointer-events:none;border:solid transparent;content:'';height:0;width:0;left:22px}.flatpickr-calendar.rightMost:before,.flatpickr-calendar.arrowRight:before,.flatpickr-calendar.rightMost:after,.flatpickr-calendar.arrowRight:after{left:auto;right:22px}.flatpickr-calendar.arrowCenter:before,.flatpickr-calendar.arrowCenter:after{left:50%;right:50%}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:before,.flatpickr-calendar.arrowTop:after{bottom:100%}.flatpickr-calendar.arrowTop:before{border-bottom-color:#e6e6e6}.flatpickr-calendar.arrowTop:after{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:before,.flatpickr-calendar.arrowBottom:after{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{position:relative;display:inline-block}.flatpickr-months{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.flatpickr-months .flatpickr-month{background:transparent;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9);height:34px;line-height:1;text-align:center;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:hidden;-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}.flatpickr-months .flatpickr-prev-month,.flatpickr-months .flatpickr-next-month{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;cursor:pointer;position:absolute;top:0;height:34px;padding:10px;z-index:3;color:rgba(0,0,0,0.9);fill:rgba(0,0,0,0.9)}.flatpickr-months .flatpickr-prev-month.flatpickr-disabled,.flatpickr-months .flatpickr-next-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-prev-month i,.flatpickr-months .flatpickr-next-month i{position:relative}.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month,.flatpickr-months .flatpickr-next-month.flatpickr-prev-month{/*
3431
3472
  /*rtl:begin:ignore*/left:0/*
3432
3473
  /*rtl:end:ignore*/}/*
package/dist/util.d.ts CHANGED
@@ -1,20 +1,6 @@
1
- /**
2
- * A date range option that can be used in the `gs-date-range-selector` component.
3
- */
4
- export declare type DateRangeOption = {
5
- /** The label of the date range option that will be shown to the user */
6
- label: string;
7
- /**
8
- * The start date of the date range in the format `YYYY-MM-DD`.
9
- * If not set, the date range selector will default to the `earliestDate` property.
10
- */
11
- dateFrom?: string;
12
- /**
13
- * The end date of the date range in the format `YYYY-MM-DD`.
14
- * If not set, the date range selector will default to the current date.
15
- */
16
- dateTo?: string;
17
- };
1
+ import { default as default_2 } from 'zod';
2
+
3
+ export declare type DateRangeOption = default_2.infer<typeof dateRangeOptionSchema>;
18
4
 
19
5
  export declare class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {
20
6
  constructor(detail: DateRangeSelectOption);
@@ -53,11 +39,67 @@ export declare const dateRangeOptionPresets: {
53
39
  };
54
40
  };
55
41
 
42
+ /**
43
+ * A date range option that can be used in the `gs-date-range-selector` component.
44
+ */
45
+ declare const dateRangeOptionSchema: default_2.ZodObject<{
46
+ /** The label of the date range option that will be shown to the user */
47
+ label: default_2.ZodString;
48
+ /**
49
+ * The start date of the date range in the format `YYYY-MM-DD`.
50
+ * If not set, the date range selector will default to the `earliestDate` property.
51
+ */
52
+ dateFrom: default_2.ZodOptional<default_2.ZodString>;
53
+ /**
54
+ * The end date of the date range in the format `YYYY-MM-DD`.
55
+ * If not set, the date range selector will default to the current date.
56
+ */
57
+ dateTo: default_2.ZodOptional<default_2.ZodString>;
58
+ }, "strip", default_2.ZodTypeAny, {
59
+ label: string;
60
+ dateFrom?: string | undefined;
61
+ dateTo?: string | undefined;
62
+ }, {
63
+ label: string;
64
+ dateFrom?: string | undefined;
65
+ dateTo?: string | undefined;
66
+ }>;
67
+
56
68
  export declare type DateRangeSelectOption = string | {
57
69
  dateFrom: string;
58
70
  dateTo: string;
59
71
  };
60
72
 
73
+ export declare type LapisFilter = default_2.infer<typeof lapisFilterSchema>;
74
+
75
+ declare const lapisFilterSchema: default_2.ZodRecord<default_2.ZodString, default_2.ZodUnion<[default_2.ZodString, default_2.ZodNumber, default_2.ZodNull, default_2.ZodBoolean]>>;
76
+
77
+ export declare type MutationComparisonView = default_2.infer<typeof mutationComparisonViewSchema>;
78
+
79
+ declare const mutationComparisonViewSchema: default_2.ZodUnion<[default_2.ZodLiteral<"table">, default_2.ZodLiteral<"venn">]>;
80
+
81
+ export declare type NamedLapisFilter = default_2.infer<typeof namedLapisFilterSchema>;
82
+
83
+ declare const namedLapisFilterSchema: default_2.ZodObject<{
84
+ lapisFilter: default_2.ZodRecord<default_2.ZodString, default_2.ZodUnion<[default_2.ZodString, default_2.ZodNumber, default_2.ZodNull, default_2.ZodBoolean]>>;
85
+ displayName: default_2.ZodString;
86
+ }, "strip", default_2.ZodTypeAny, {
87
+ lapisFilter: Record<string, string | number | boolean | null>;
88
+ displayName: string;
89
+ }, {
90
+ lapisFilter: Record<string, string | number | boolean | null>;
91
+ displayName: string;
92
+ }>;
93
+
94
+ export declare type SequenceType = default_2.infer<typeof sequenceTypeSchema>;
95
+
96
+ declare const sequenceTypeSchema: default_2.ZodUnion<[default_2.ZodLiteral<"nucleotide">, default_2.ZodLiteral<"amino acid">]>;
97
+
98
+ export declare const views: {
99
+ readonly table: "table";
100
+ readonly venn: "venn";
101
+ };
102
+
61
103
  export { }
62
104
 
63
105
 
@@ -86,7 +128,11 @@ declare global {
86
128
 
87
129
  declare global {
88
130
  interface HTMLElementTagNameMap {
89
- 'gs-mutation-comparison-component': MutationComparisonComponent;
131
+ 'gs-date-range-selector': DateRangeSelectorComponent;
132
+ }
133
+ interface HTMLElementEventMap {
134
+ 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
135
+ 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
90
136
  }
91
137
  }
92
138
 
@@ -94,7 +140,7 @@ declare global {
94
140
  declare global {
95
141
  namespace JSX {
96
142
  interface IntrinsicElements {
97
- 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
143
+ 'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
98
144
  }
99
145
  }
100
146
  }
@@ -102,7 +148,10 @@ declare global {
102
148
 
103
149
  declare global {
104
150
  interface HTMLElementTagNameMap {
105
- 'gs-mutations-component': MutationsComponent;
151
+ 'gs-location-filter': LocationFilterComponent;
152
+ }
153
+ interface HTMLElementEventMap {
154
+ 'gs-location-changed': CustomEvent<Record<string, string>>;
106
155
  }
107
156
  }
108
157
 
@@ -110,7 +159,7 @@ declare global {
110
159
  declare global {
111
160
  namespace JSX {
112
161
  interface IntrinsicElements {
113
- 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
162
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
114
163
  }
115
164
  }
116
165
  }
@@ -118,7 +167,10 @@ declare global {
118
167
 
119
168
  declare global {
120
169
  interface HTMLElementTagNameMap {
121
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
170
+ 'gs-text-input': TextInputComponent;
171
+ }
172
+ interface HTMLElementEventMap {
173
+ 'gs-text-input-changed': CustomEvent<Record<string, string>>;
122
174
  }
123
175
  }
124
176
 
@@ -126,7 +178,7 @@ declare global {
126
178
  declare global {
127
179
  namespace JSX {
128
180
  interface IntrinsicElements {
129
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
181
+ 'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
130
182
  }
131
183
  }
132
184
  }
@@ -134,7 +186,10 @@ declare global {
134
186
 
135
187
  declare global {
136
188
  interface HTMLElementTagNameMap {
137
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
189
+ 'gs-mutation-filter': MutationFilterComponent;
190
+ }
191
+ interface HTMLElementEventMap {
192
+ 'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
138
193
  }
139
194
  }
140
195
 
@@ -142,7 +197,7 @@ declare global {
142
197
  declare global {
143
198
  namespace JSX {
144
199
  interface IntrinsicElements {
145
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
200
+ 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
146
201
  }
147
202
  }
148
203
  }
@@ -150,7 +205,10 @@ declare global {
150
205
 
151
206
  declare global {
152
207
  interface HTMLElementTagNameMap {
153
- 'gs-aggregate-component': AggregateComponent;
208
+ 'gs-lineage-filter': LineageFilterComponent;
209
+ }
210
+ interface HTMLElementEventMap {
211
+ 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
154
212
  }
155
213
  }
156
214
 
@@ -158,7 +216,7 @@ declare global {
158
216
  declare global {
159
217
  namespace JSX {
160
218
  interface IntrinsicElements {
161
- 'gs-aggregate-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
219
+ 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
162
220
  }
163
221
  }
164
222
  }
@@ -166,7 +224,7 @@ declare global {
166
224
 
167
225
  declare global {
168
226
  interface HTMLElementTagNameMap {
169
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
227
+ 'gs-mutation-comparison-component': MutationComparisonComponent;
170
228
  }
171
229
  }
172
230
 
@@ -174,7 +232,7 @@ declare global {
174
232
  declare global {
175
233
  namespace JSX {
176
234
  interface IntrinsicElements {
177
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
235
+ 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
178
236
  }
179
237
  }
180
238
  }
@@ -182,7 +240,7 @@ declare global {
182
240
 
183
241
  declare global {
184
242
  interface HTMLElementTagNameMap {
185
- 'gs-mutations-over-time': MutationsOverTimeComponent;
243
+ 'gs-mutations-component': MutationsComponent;
186
244
  }
187
245
  }
188
246
 
@@ -190,7 +248,7 @@ declare global {
190
248
  declare global {
191
249
  namespace JSX {
192
250
  interface IntrinsicElements {
193
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
251
+ 'gs-mutations-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
194
252
  }
195
253
  }
196
254
  }
@@ -198,11 +256,7 @@ declare global {
198
256
 
199
257
  declare global {
200
258
  interface HTMLElementTagNameMap {
201
- 'gs-date-range-selector': DateRangeSelectorComponent;
202
- }
203
- interface HTMLElementEventMap {
204
- 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
205
- 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
259
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
206
260
  }
207
261
  }
208
262
 
@@ -210,7 +264,7 @@ declare global {
210
264
  declare global {
211
265
  namespace JSX {
212
266
  interface IntrinsicElements {
213
- 'gs-date-range-selector': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
267
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
214
268
  }
215
269
  }
216
270
  }
@@ -218,10 +272,7 @@ declare global {
218
272
 
219
273
  declare global {
220
274
  interface HTMLElementTagNameMap {
221
- 'gs-location-filter': LocationFilterComponent;
222
- }
223
- interface HTMLElementEventMap {
224
- 'gs-location-changed': CustomEvent<Record<string, string>>;
275
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
225
276
  }
226
277
  }
227
278
 
@@ -229,7 +280,7 @@ declare global {
229
280
  declare global {
230
281
  namespace JSX {
231
282
  interface IntrinsicElements {
232
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
283
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
233
284
  }
234
285
  }
235
286
  }
@@ -237,10 +288,7 @@ declare global {
237
288
 
238
289
  declare global {
239
290
  interface HTMLElementTagNameMap {
240
- 'gs-text-input': TextInputComponent;
241
- }
242
- interface HTMLElementEventMap {
243
- 'gs-text-input-changed': CustomEvent<Record<string, string>>;
291
+ 'gs-aggregate': AggregateComponent;
244
292
  }
245
293
  }
246
294
 
@@ -248,7 +296,7 @@ declare global {
248
296
  declare global {
249
297
  namespace JSX {
250
298
  interface IntrinsicElements {
251
- 'gs-text-input': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
299
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
252
300
  }
253
301
  }
254
302
  }
@@ -256,10 +304,7 @@ declare global {
256
304
 
257
305
  declare global {
258
306
  interface HTMLElementTagNameMap {
259
- 'gs-mutation-filter': MutationFilterComponent;
260
- }
261
- interface HTMLElementEventMap {
262
- 'gs-mutation-filter-changed': CustomEvent<SelectedMutationFilterStrings>;
307
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
263
308
  }
264
309
  }
265
310
 
@@ -267,7 +312,7 @@ declare global {
267
312
  declare global {
268
313
  namespace JSX {
269
314
  interface IntrinsicElements {
270
- 'gs-mutation-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
315
+ 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
271
316
  }
272
317
  }
273
318
  }
@@ -275,10 +320,23 @@ declare global {
275
320
 
276
321
  declare global {
277
322
  interface HTMLElementTagNameMap {
278
- 'gs-lineage-filter': LineageFilterComponent;
323
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
279
324
  }
280
- interface HTMLElementEventMap {
281
- 'gs-lineage-filter-changed': CustomEvent<Record<string, string>>;
325
+ }
326
+
327
+
328
+ declare global {
329
+ namespace JSX {
330
+ interface IntrinsicElements {
331
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
332
+ }
333
+ }
334
+ }
335
+
336
+
337
+ declare global {
338
+ interface HTMLElementTagNameMap {
339
+ 'gs-statistics': StatisticsComponent;
282
340
  }
283
341
  }
284
342
 
@@ -286,7 +344,7 @@ declare global {
286
344
  declare global {
287
345
  namespace JSX {
288
346
  interface IntrinsicElements {
289
- 'gs-lineage-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
347
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
290
348
  }
291
349
  }
292
350
  }
package/dist/util.js CHANGED
@@ -1,6 +1,7 @@
1
- import { D, d } from "./utilEntrypoint-g4DsyhU7.js";
1
+ import { D, d, v } from "./dateRangeOption-du8H7LWu.js";
2
2
  export {
3
3
  D as DateRangeOptionChangedEvent,
4
- d as dateRangeOptionPresets
4
+ d as dateRangeOptionPresets,
5
+ v as views
5
6
  };
6
7
  //# sourceMappingURL=util.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -132,7 +132,7 @@
132
132
  "storybook": "^8.0.9",
133
133
  "storybook-addon-fetch-mock": "^2.0.0",
134
134
  "tailwindcss": "^3.4.3",
135
- "typescript": "~5.6.2",
135
+ "typescript": "~5.7.2",
136
136
  "vite": "^5.2.10",
137
137
  "vite-plugin-dts": "^4.0.3",
138
138
  "vitest": "^2.0.1"
@@ -54,7 +54,11 @@ export const ColorScaleSelector: FunctionComponent<ColorScaleSelectorProps> = ({
54
54
  );
55
55
  };
56
56
 
57
- export const getColorWithingScale = (value: number, colorScale: ColorScale) => {
57
+ export const getColorWithingScale = (value: number | undefined, colorScale: ColorScale) => {
58
+ if (value === undefined) {
59
+ return 'lightgrey';
60
+ }
61
+
58
62
  if (colorScale.min === colorScale.max) {
59
63
  return singleGraphColorRGBByName(colorScale.color, 0);
60
64
  }
@@ -66,8 +70,8 @@ export const getColorWithingScale = (value: number, colorScale: ColorScale) => {
66
70
  return singleGraphColorRGBByName(colorScale.color, alpha);
67
71
  };
68
72
 
69
- export const getTextColorForScale = (value: number, colorScale: ColorScale) => {
70
- if (colorScale.min === colorScale.max) {
73
+ export const getTextColorForScale = (value: number | undefined, colorScale: ColorScale) => {
74
+ if (value === undefined || colorScale.min === colorScale.max) {
71
75
  return 'black';
72
76
  }
73
77
 
@@ -1,16 +1,26 @@
1
- import type { FunctionComponent } from 'preact';
2
- import { useErrorBoundary } from 'preact/hooks';
1
+ import { type RenderableProps } from 'preact';
2
+ import { useErrorBoundary, useMemo } from 'preact/hooks';
3
+ import { type ZodSchema } from 'zod';
3
4
 
4
- import { ErrorDisplay, type ErrorDisplayProps } from './error-display';
5
+ import { ErrorDisplay, type ErrorDisplayProps, InvalidPropsError } from './error-display';
5
6
  import { ResizeContainer, type Size } from './resize-container';
6
7
 
7
- type ErrorBoundaryProps = {
8
+ type ErrorBoundaryProps<T> = {
8
9
  size: Size;
9
10
  layout?: ErrorDisplayProps['layout'];
11
+ componentProps?: T;
12
+ schema?: ZodSchema<T>;
10
13
  };
11
14
 
12
- export const ErrorBoundary: FunctionComponent<ErrorBoundaryProps> = ({ size, layout, children }) => {
15
+ export const ErrorBoundary = <T extends Record<string, unknown>>({
16
+ size,
17
+ layout,
18
+ componentProps,
19
+ schema,
20
+ children,
21
+ }: RenderableProps<ErrorBoundaryProps<T>>) => {
13
22
  const [internalError, resetError] = useErrorBoundary();
23
+ const componentPropsParseError = useCheckComponentProps(schema, componentProps);
14
24
 
15
25
  if (internalError) {
16
26
  return (
@@ -20,5 +30,29 @@ export const ErrorBoundary: FunctionComponent<ErrorBoundaryProps> = ({ size, lay
20
30
  );
21
31
  }
22
32
 
33
+ if (componentPropsParseError !== undefined) {
34
+ return (
35
+ <ResizeContainer size={size}>
36
+ <ErrorDisplay error={componentPropsParseError} layout={layout} />
37
+ </ResizeContainer>
38
+ );
39
+ }
40
+
23
41
  return <>{children}</>;
24
42
  };
43
+
44
+ // TODO #554 - make both arguments required once all components validate their props
45
+ function useCheckComponentProps<T extends Record<string, unknown>>(schema?: ZodSchema<T>, componentProps?: T) {
46
+ return useMemo(() => {
47
+ if (schema === undefined || componentProps === undefined) {
48
+ return undefined;
49
+ }
50
+
51
+ const parseResult = schema.safeParse(componentProps);
52
+ if (parseResult.success) {
53
+ return undefined;
54
+ }
55
+
56
+ return new InvalidPropsError(parseResult.error, componentProps);
57
+ }, [componentProps, schema]);
58
+ }
@@ -1,5 +1,6 @@
1
1
  import { type FunctionComponent } from 'preact';
2
2
  import { useEffect, useRef } from 'preact/hooks';
3
+ import { type ZodError } from 'zod';
3
4
 
4
5
  import { LapisError, UnknownLapisError } from '../../lapisApi/lapisApi';
5
6
 
@@ -24,9 +25,19 @@ export class UserFacingError extends Error {
24
25
  }
25
26
  }
26
27
 
28
+ export class InvalidPropsError extends Error {
29
+ constructor(
30
+ public readonly zodError: ZodError,
31
+ public readonly componentProps: Record<string, unknown>,
32
+ ) {
33
+ super(zodError.message);
34
+ this.name = 'InvalidPropsError';
35
+ }
36
+ }
37
+
27
38
  export type ErrorDisplayProps = {
28
39
  error: Error;
29
- resetError: () => void;
40
+ resetError?: () => void;
30
41
  layout?: 'horizontal' | 'vertical';
31
42
  };
32
43
 
@@ -76,10 +87,12 @@ export const ErrorDisplay: FunctionComponent<ErrorDisplayProps> = ({ error, rese
76
87
  )}
77
88
  </div>
78
89
  </div>
79
- <button onClick={resetError} className='btn btn-sm flex items-center m-4'>
80
- <span className='iconify mdi--reload text-lg' />
81
- Try again
82
- </button>
90
+ {resetError !== undefined && (
91
+ <button onClick={resetError} className='btn btn-sm flex items-center m-4'>
92
+ <span className='iconify mdi--reload text-lg' />
93
+ Try again
94
+ </button>
95
+ )}
83
96
  </div>
84
97
  );
85
98
  };
@@ -115,5 +128,27 @@ function getDisplayedErrorMessage(error: Error) {
115
128
  };
116
129
  }
117
130
 
131
+ if (error instanceof InvalidPropsError) {
132
+ const firstError = error.zodError.errors[0];
133
+ let message = error.zodError.issues
134
+ .map((issue) => {
135
+ const actual =
136
+ issue.path[0] in error.componentProps
137
+ ? ` '${JSON.stringify(error.componentProps[issue.path[0]])}'`
138
+ : '';
139
+ return `Unexpected value${actual} for "${issue.path.join('.')}": ${issue.message}`;
140
+ })
141
+ .join(' - ');
142
+
143
+ if (firstError.code === 'invalid_type' && firstError.received === 'null') {
144
+ message = `Is the "${firstError.path[0]}" attribute in the HTML of the correct type? ${message}`;
145
+ }
146
+
147
+ return {
148
+ headline: 'Error - Invalid component attributes',
149
+ details: { headline: 'Invalid component attributes', message },
150
+ };
151
+ }
152
+
118
153
  return { headline: 'Error', details: undefined };
119
154
  }