@genspectrum/dashboard-components 0.16.3 → 0.17.0

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 (61) hide show
  1. package/custom-elements.json +86 -61
  2. package/dist/{LineageFilterChangedEvent-COWV-Y0k.js → LineageFilterChangedEvent-DkvWdq_G.js} +2 -2
  3. package/dist/LineageFilterChangedEvent-DkvWdq_G.js.map +1 -0
  4. package/dist/assets/{mutationOverTimeWorker-DJcZmEH9.js.map → mutationOverTimeWorker-CPfQDLe6.js.map} +1 -1
  5. package/dist/components.d.ts +64 -51
  6. package/dist/components.js +1134 -937
  7. package/dist/components.js.map +1 -1
  8. package/dist/style.css +81 -9
  9. package/dist/util.d.ts +76 -34
  10. package/dist/util.js +1 -1
  11. package/package.json +2 -1
  12. package/src/preact/components/annotated-mutation.stories.tsx +2 -1
  13. package/src/preact/components/annotated-mutation.tsx +6 -2
  14. package/src/preact/components/clearable-select.stories.tsx +75 -0
  15. package/src/preact/components/clearable-select.tsx +76 -0
  16. package/src/preact/components/downshift-combobox.tsx +9 -7
  17. package/src/preact/dateRangeFilter/computeInitialValues.spec.ts +31 -33
  18. package/src/preact/dateRangeFilter/computeInitialValues.ts +2 -15
  19. package/src/preact/dateRangeFilter/date-picker.tsx +66 -0
  20. package/src/preact/dateRangeFilter/date-range-filter.stories.tsx +69 -31
  21. package/src/preact/dateRangeFilter/date-range-filter.tsx +136 -139
  22. package/src/preact/dateRangeFilter/dateRangeOption.ts +11 -11
  23. package/src/preact/mutationComparison/mutation-comparison-table.tsx +14 -1
  24. package/src/preact/mutationComparison/mutation-comparison-venn.tsx +39 -8
  25. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +36 -12
  26. package/src/preact/mutationComparison/mutation-comparison.tsx +2 -0
  27. package/src/preact/mutations/mutations.stories.tsx +3 -9
  28. package/src/preact/mutationsOverTime/mutations-over-time.stories.tsx +3 -8
  29. package/src/preact/shared/WithClassName/WithClassName.ts +1 -0
  30. package/src/preact/shared/icons/DeleteIcon.tsx +3 -0
  31. package/src/preact/shared/stories/expectMutationAnnotation.ts +13 -0
  32. package/src/preact/shared/stories/expectOptionSelected.tsx +7 -0
  33. package/src/utilEntrypoint.ts +3 -1
  34. package/src/web-components/MutationAnnotations.mdx +33 -0
  35. package/src/web-components/ResizeContainer.mdx +1 -1
  36. package/src/web-components/errorHandling.mdx +1 -1
  37. package/src/web-components/gs-app.ts +2 -2
  38. package/src/web-components/input/gs-date-range-filter.stories.ts +38 -32
  39. package/src/web-components/input/gs-date-range-filter.tsx +8 -2
  40. package/src/web-components/input/gs-lineage-filter.tsx +1 -1
  41. package/src/web-components/input/gs-location-filter.tsx +1 -1
  42. package/src/web-components/input/gs-mutation-filter.tsx +1 -1
  43. package/src/web-components/input/gs-text-filter.tsx +1 -1
  44. package/src/web-components/visualization/gs-aggregate.tsx +2 -2
  45. package/src/web-components/visualization/gs-mutation-comparison.stories.ts +18 -1
  46. package/src/web-components/visualization/gs-mutation-comparison.tsx +24 -10
  47. package/src/web-components/visualization/gs-mutations-over-time.stories.ts +2 -1
  48. package/src/web-components/visualization/gs-mutations-over-time.tsx +5 -2
  49. package/src/web-components/visualization/gs-mutations.stories.ts +2 -1
  50. package/src/web-components/visualization/gs-mutations.tsx +5 -2
  51. package/src/web-components/visualization/gs-number-sequences-over-time.tsx +2 -2
  52. package/src/web-components/visualization/gs-prevalence-over-time.tsx +2 -2
  53. package/src/web-components/visualization/gs-relative-growth-advantage.tsx +2 -2
  54. package/src/web-components/visualization/gs-sequences-by-location.tsx +2 -2
  55. package/src/web-components/visualization/gs-statistics.tsx +2 -2
  56. package/src/web-components/wastewaterVisualization/gs-wastewater-mutations-over-time.tsx +2 -2
  57. package/standalone-bundle/assets/mutationOverTimeWorker-CERZSdcA.js.map +1 -1
  58. package/standalone-bundle/dashboard-components.js +13293 -12635
  59. package/standalone-bundle/dashboard-components.js.map +1 -1
  60. package/standalone-bundle/style.css +1 -1
  61. package/dist/LineageFilterChangedEvent-COWV-Y0k.js.map +0 -1
package/dist/style.css CHANGED
@@ -1073,12 +1073,6 @@ html {
1073
1073
  --tw-bg-opacity: 1;
1074
1074
  background-color: var(--fallback-b2,oklch(var(--b2)/var(--tw-bg-opacity)));
1075
1075
  }
1076
-
1077
- .table-zebra tr.hover:hover,
1078
- .table-zebra tr.hover:nth-child(even):hover {
1079
- --tw-bg-opacity: 1;
1080
- background-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-bg-opacity)));
1081
- }
1082
1076
  }
1083
1077
  .btn {
1084
1078
  display: inline-flex;
@@ -3098,6 +3092,9 @@ input.tab:checked + .tab-content,
3098
3092
  .right-0 {
3099
3093
  right: 0px;
3100
3094
  }
3095
+ .right-10 {
3096
+ right: 2.5rem;
3097
+ }
3101
3098
  .right-2 {
3102
3099
  right: 0.5rem;
3103
3100
  }
@@ -3247,9 +3244,6 @@ input.tab:checked + .tab-content,
3247
3244
  .w-\[6rem\] {
3248
3245
  width: 6rem;
3249
3246
  }
3250
- .w-\[7\.5rem\] {
3251
- width: 7.5rem;
3252
- }
3253
3247
  .w-full {
3254
3248
  width: 100%;
3255
3249
  }
@@ -3257,6 +3251,9 @@ input.tab:checked + .tab-content,
3257
3251
  width: -moz-max-content;
3258
3252
  width: max-content;
3259
3253
  }
3254
+ .min-w-24 {
3255
+ min-width: 6rem;
3256
+ }
3260
3257
  .min-w-32 {
3261
3258
  min-width: 8rem;
3262
3259
  }
@@ -3278,6 +3275,10 @@ input.tab:checked + .tab-content,
3278
3275
  .grow {
3279
3276
  flex-grow: 1;
3280
3277
  }
3278
+ .-translate-y-1\/2 {
3279
+ --tw-translate-y: -50%;
3280
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
3281
+ }
3281
3282
  .translate-x-\[-50\%\] {
3282
3283
  --tw-translate-x: -50%;
3283
3284
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@@ -3292,6 +3293,11 @@ input.tab:checked + .tab-content,
3292
3293
  .cursor-pointer {
3293
3294
  cursor: pointer;
3294
3295
  }
3296
+ .select-text {
3297
+ -webkit-user-select: text;
3298
+ -moz-user-select: text;
3299
+ user-select: text;
3300
+ }
3295
3301
  .list-inside {
3296
3302
  list-style-position: inside;
3297
3303
  }
@@ -3371,12 +3377,27 @@ input.tab:checked + .tab-content,
3371
3377
  border-bottom-right-radius: 0.375rem;
3372
3378
  border-bottom-left-radius: 0.375rem;
3373
3379
  }
3380
+ .rounded-b-none {
3381
+ border-bottom-right-radius: 0px;
3382
+ border-bottom-left-radius: 0px;
3383
+ }
3384
+ .rounded-t-md {
3385
+ border-top-left-radius: 0.375rem;
3386
+ border-top-right-radius: 0.375rem;
3387
+ }
3388
+ .rounded-t-none {
3389
+ border-top-left-radius: 0px;
3390
+ border-top-right-radius: 0px;
3391
+ }
3374
3392
  .rounded-tr-md {
3375
3393
  border-top-right-radius: 0.375rem;
3376
3394
  }
3377
3395
  .border {
3378
3396
  border-width: 1px;
3379
3397
  }
3398
+ .border-0 {
3399
+ border-width: 0px;
3400
+ }
3380
3401
  .border-2 {
3381
3402
  border-width: 2px;
3382
3403
  }
@@ -3418,6 +3439,9 @@ input.tab:checked + .tab-content,
3418
3439
  --tw-bg-opacity: 1;
3419
3440
  background-color: rgb(226 232 240 / var(--tw-bg-opacity, 1));
3420
3441
  }
3442
+ .bg-transparent {
3443
+ background-color: transparent;
3444
+ }
3421
3445
  .bg-white {
3422
3446
  --tw-bg-opacity: 1;
3423
3447
  background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
@@ -3465,6 +3489,9 @@ input.tab:checked + .tab-content,
3465
3489
  .pl-2 {
3466
3490
  padding-left: 0.5rem;
3467
3491
  }
3492
+ .pr-14 {
3493
+ padding-right: 3.5rem;
3494
+ }
3468
3495
  .text-center {
3469
3496
  text-align: center;
3470
3497
  }
@@ -3663,6 +3690,51 @@ input.tab:checked + .tab-content,
3663
3690
  visibility: visible;
3664
3691
  }
3665
3692
  }
3693
+ @container (min-width: 14rem) {
3694
+
3695
+ .\@4xs\:flex-row {
3696
+ flex-direction: row;
3697
+ }
3698
+
3699
+ .\@4xs\:rounded-l-none {
3700
+ border-top-left-radius: 0px;
3701
+ border-bottom-left-radius: 0px;
3702
+ }
3703
+
3704
+ .\@4xs\:rounded-bl-md {
3705
+ border-bottom-left-radius: 0.375rem;
3706
+ }
3707
+
3708
+ .\@4xs\:rounded-tr-none {
3709
+ border-top-right-radius: 0px;
3710
+ }
3711
+ }
3712
+ @container (min-width: 28rem) {
3713
+
3714
+ .\@md\:flex-row {
3715
+ flex-direction: row;
3716
+ }
3717
+
3718
+ .\@md\:rounded-l-md {
3719
+ border-top-left-radius: 0.375rem;
3720
+ border-bottom-left-radius: 0.375rem;
3721
+ }
3722
+
3723
+ .\@md\:rounded-l-none {
3724
+ border-top-left-radius: 0px;
3725
+ border-bottom-left-radius: 0px;
3726
+ }
3727
+
3728
+ .\@md\:rounded-r-md {
3729
+ border-top-right-radius: 0.375rem;
3730
+ border-bottom-right-radius: 0.375rem;
3731
+ }
3732
+
3733
+ .\@md\:rounded-r-none {
3734
+ border-top-right-radius: 0px;
3735
+ border-bottom-right-radius: 0px;
3736
+ }
3737
+ }
3666
3738
  @media (min-width: 640px) {
3667
3739
 
3668
3740
  .sm\:max-w-5xl {
package/dist/util.d.ts CHANGED
@@ -73,8 +73,8 @@ declare const confidenceIntervalMethodSchema: default_2.ZodUnion<[default_2.ZodL
73
73
 
74
74
  export declare type DateRangeOption = default_2.infer<typeof dateRangeOptionSchema>;
75
75
 
76
- export declare class DateRangeOptionChangedEvent extends CustomEvent<DateRangeSelectOption> {
77
- constructor(detail: DateRangeSelectOption);
76
+ export declare class DateRangeOptionChangedEvent extends CustomEvent<DateRangeValue> {
77
+ constructor(detail: DateRangeValue);
78
78
  }
79
79
 
80
80
  /**
@@ -136,11 +136,9 @@ declare const dateRangeOptionSchema: default_2.ZodObject<{
136
136
  dateTo?: string | undefined;
137
137
  }>;
138
138
 
139
- export declare type DateRangeSelectOption = Required<DateRangeValue>;
139
+ export declare type DateRangeValue = default_2.infer<typeof dateRangeValueSchema>;
140
140
 
141
- declare type DateRangeValue = default_2.infer<typeof dateRangeValueSchema>;
142
-
143
- declare const dateRangeValueSchema: default_2.ZodUnion<[default_2.ZodString, default_2.ZodObject<{
141
+ declare const dateRangeValueSchema: default_2.ZodOptional<default_2.ZodUnion<[default_2.ZodString, default_2.ZodObject<{
144
142
  dateFrom: default_2.ZodOptional<default_2.ZodString>;
145
143
  dateTo: default_2.ZodOptional<default_2.ZodString>;
146
144
  }, "strip", default_2.ZodTypeAny, {
@@ -149,7 +147,7 @@ declare const dateRangeValueSchema: default_2.ZodUnion<[default_2.ZodString, def
149
147
  }, {
150
148
  dateFrom?: string | undefined;
151
149
  dateTo?: string | undefined;
152
- }>]>;
150
+ }>]>>;
153
151
 
154
152
  export declare type LapisFilter = default_2.infer<typeof lapisFilterSchema>;
155
153
 
@@ -202,6 +200,50 @@ declare const mapSourceSchema: default_2.ZodObject<{
202
200
  topologyObjectsKey: string;
203
201
  }>;
204
202
 
203
+ export declare type MutationAnnotation = default_2.infer<typeof mutationAnnotationSchema>;
204
+
205
+ export declare type MutationAnnotations = default_2.infer<typeof mutationAnnotationsSchema>;
206
+
207
+ declare const mutationAnnotationSchema: default_2.ZodObject<{
208
+ name: default_2.ZodString;
209
+ description: default_2.ZodString;
210
+ symbol: default_2.ZodString;
211
+ nucleotideMutations: default_2.ZodArray<default_2.ZodString, "many">;
212
+ aminoAcidMutations: default_2.ZodArray<default_2.ZodString, "many">;
213
+ }, "strip", default_2.ZodTypeAny, {
214
+ symbol: string;
215
+ name: string;
216
+ description: string;
217
+ nucleotideMutations: string[];
218
+ aminoAcidMutations: string[];
219
+ }, {
220
+ symbol: string;
221
+ name: string;
222
+ description: string;
223
+ nucleotideMutations: string[];
224
+ aminoAcidMutations: string[];
225
+ }>;
226
+
227
+ declare const mutationAnnotationsSchema: default_2.ZodArray<default_2.ZodObject<{
228
+ name: default_2.ZodString;
229
+ description: default_2.ZodString;
230
+ symbol: default_2.ZodString;
231
+ nucleotideMutations: default_2.ZodArray<default_2.ZodString, "many">;
232
+ aminoAcidMutations: default_2.ZodArray<default_2.ZodString, "many">;
233
+ }, "strip", default_2.ZodTypeAny, {
234
+ symbol: string;
235
+ name: string;
236
+ description: string;
237
+ nucleotideMutations: string[];
238
+ aminoAcidMutations: string[];
239
+ }, {
240
+ symbol: string;
241
+ name: string;
242
+ description: string;
243
+ nucleotideMutations: string[];
244
+ aminoAcidMutations: string[];
245
+ }>, "many">;
246
+
205
247
  export declare type MutationComparisonProps = default_2.infer<typeof mutationComparisonPropsSchema>;
206
248
 
207
249
  declare const mutationComparisonPropsSchema: default_2.ZodObject<{
@@ -247,6 +289,7 @@ declare const mutationComparisonPropsSchema: default_2.ZodObject<{
247
289
  pageSize: default_2.ZodUnion<[default_2.ZodBoolean, default_2.ZodNumber]>;
248
290
  }, "strip", default_2.ZodTypeAny, {
249
291
  width: string;
292
+ sequenceType: "nucleotide" | "amino acid";
250
293
  pageSize: number | boolean;
251
294
  lapisFilters: {
252
295
  lapisFilter: Record<string, string | number | boolean | string[] | null | undefined> & {
@@ -257,11 +300,11 @@ declare const mutationComparisonPropsSchema: default_2.ZodObject<{
257
300
  };
258
301
  displayName: string;
259
302
  }[];
260
- sequenceType: "nucleotide" | "amino acid";
261
303
  views: ("table" | "venn")[];
262
304
  height?: string | undefined;
263
305
  }, {
264
306
  width: string;
307
+ sequenceType: "nucleotide" | "amino acid";
265
308
  pageSize: number | boolean;
266
309
  lapisFilters: {
267
310
  lapisFilter: Record<string, string | number | boolean | string[] | null | undefined> & {
@@ -272,7 +315,6 @@ declare const mutationComparisonPropsSchema: default_2.ZodObject<{
272
315
  };
273
316
  displayName: string;
274
317
  }[];
275
- sequenceType: "nucleotide" | "amino acid";
276
318
  views: ("table" | "venn")[];
277
319
  height?: string | undefined;
278
320
  }>;
@@ -348,8 +390,8 @@ declare const mutationsPropsSchema: default_2.ZodObject<{
348
390
  aminoAcidInsertions?: string[] | undefined;
349
391
  };
350
392
  width: string;
351
- pageSize: number | boolean;
352
393
  sequenceType: "nucleotide" | "amino acid";
394
+ pageSize: number | boolean;
353
395
  views: ("table" | "grid" | "insertions")[];
354
396
  height?: string | undefined;
355
397
  baselineLapisFilter?: (Record<string, string | number | boolean | string[] | null | undefined> & {
@@ -366,8 +408,8 @@ declare const mutationsPropsSchema: default_2.ZodObject<{
366
408
  aminoAcidInsertions?: string[] | undefined;
367
409
  };
368
410
  width: string;
369
- pageSize: number | boolean;
370
411
  sequenceType: "nucleotide" | "amino acid";
412
+ pageSize: number | boolean;
371
413
  views: ("table" | "grid" | "insertions")[];
372
414
  height?: string | undefined;
373
415
  baselineLapisFilter?: (Record<string, string | number | boolean | string[] | null | undefined> & {
@@ -880,7 +922,7 @@ declare global {
880
922
 
881
923
  declare global {
882
924
  interface HTMLElementTagNameMap {
883
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
925
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
884
926
  }
885
927
  }
886
928
 
@@ -888,7 +930,7 @@ declare global {
888
930
  declare global {
889
931
  namespace JSX {
890
932
  interface IntrinsicElements {
891
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
933
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
892
934
  }
893
935
  }
894
936
  }
@@ -896,7 +938,7 @@ declare global {
896
938
 
897
939
  declare global {
898
940
  interface HTMLElementTagNameMap {
899
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
941
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
900
942
  }
901
943
  }
902
944
 
@@ -904,7 +946,7 @@ declare global {
904
946
  declare global {
905
947
  namespace JSX {
906
948
  interface IntrinsicElements {
907
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
949
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
908
950
  }
909
951
  }
910
952
  }
@@ -912,7 +954,7 @@ declare global {
912
954
 
913
955
  declare global {
914
956
  interface HTMLElementTagNameMap {
915
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
957
+ 'gs-aggregate': AggregateComponent;
916
958
  }
917
959
  }
918
960
 
@@ -920,7 +962,7 @@ declare global {
920
962
  declare global {
921
963
  namespace JSX {
922
964
  interface IntrinsicElements {
923
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
965
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
924
966
  }
925
967
  }
926
968
  }
@@ -928,7 +970,7 @@ declare global {
928
970
 
929
971
  declare global {
930
972
  interface HTMLElementTagNameMap {
931
- 'gs-mutations-over-time': MutationsOverTimeComponent;
973
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
932
974
  }
933
975
  }
934
976
 
@@ -936,7 +978,7 @@ declare global {
936
978
  declare global {
937
979
  namespace JSX {
938
980
  interface IntrinsicElements {
939
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
981
+ 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
940
982
  }
941
983
  }
942
984
  }
@@ -944,7 +986,7 @@ declare global {
944
986
 
945
987
  declare global {
946
988
  interface HTMLElementTagNameMap {
947
- 'gs-aggregate': AggregateComponent;
989
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
948
990
  }
949
991
  }
950
992
 
@@ -952,7 +994,7 @@ declare global {
952
994
  declare global {
953
995
  namespace JSX {
954
996
  interface IntrinsicElements {
955
- 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
997
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
956
998
  }
957
999
  }
958
1000
  }
@@ -960,7 +1002,7 @@ declare global {
960
1002
 
961
1003
  declare global {
962
1004
  interface HTMLElementTagNameMap {
963
- 'gs-statistics': StatisticsComponent;
1005
+ 'gs-sequences-by-location': SequencesByLocationComponent;
964
1006
  }
965
1007
  }
966
1008
 
@@ -968,7 +1010,7 @@ declare global {
968
1010
  declare global {
969
1011
  namespace JSX {
970
1012
  interface IntrinsicElements {
971
- 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1013
+ 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
972
1014
  }
973
1015
  }
974
1016
  }
@@ -976,10 +1018,7 @@ declare global {
976
1018
 
977
1019
  declare global {
978
1020
  interface HTMLElementTagNameMap {
979
- 'gs-location-filter': LocationFilterComponent;
980
- }
981
- interface HTMLElementEventMap {
982
- 'gs-location-changed': LocationChangedEvent;
1021
+ 'gs-statistics': StatisticsComponent;
983
1022
  }
984
1023
  }
985
1024
 
@@ -987,7 +1026,7 @@ declare global {
987
1026
  declare global {
988
1027
  namespace JSX {
989
1028
  interface IntrinsicElements {
990
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1029
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
991
1030
  }
992
1031
  }
993
1032
  }
@@ -995,7 +1034,11 @@ declare global {
995
1034
 
996
1035
  declare global {
997
1036
  interface HTMLElementTagNameMap {
998
- 'gs-sequences-by-location': SequencesByLocationComponent;
1037
+ 'gs-date-range-filter': DateRangeFilterComponent;
1038
+ }
1039
+ interface HTMLElementEventMap {
1040
+ 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
1041
+ 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
999
1042
  }
1000
1043
  }
1001
1044
 
@@ -1003,7 +1046,7 @@ declare global {
1003
1046
  declare global {
1004
1047
  namespace JSX {
1005
1048
  interface IntrinsicElements {
1006
- 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1049
+ 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1007
1050
  }
1008
1051
  }
1009
1052
  }
@@ -1027,11 +1070,10 @@ declare global {
1027
1070
 
1028
1071
  declare global {
1029
1072
  interface HTMLElementTagNameMap {
1030
- 'gs-date-range-filter': DateRangeFilterComponent;
1073
+ 'gs-location-filter': LocationFilterComponent;
1031
1074
  }
1032
1075
  interface HTMLElementEventMap {
1033
- 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
1034
- 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
1076
+ 'gs-location-changed': LocationChangedEvent;
1035
1077
  }
1036
1078
  }
1037
1079
 
@@ -1039,7 +1081,7 @@ declare global {
1039
1081
  declare global {
1040
1082
  namespace JSX {
1041
1083
  interface IntrinsicElements {
1042
- 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1084
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1043
1085
  }
1044
1086
  }
1045
1087
  }
package/dist/util.js CHANGED
@@ -1,4 +1,4 @@
1
- import { D, a, L, T, d, v } from "./LineageFilterChangedEvent-COWV-Y0k.js";
1
+ import { D, a, L, T, d, v } from "./LineageFilterChangedEvent-DkvWdq_G.js";
2
2
  export {
3
3
  D as DateRangeOptionChangedEvent,
4
4
  a as LineageFilterChangedEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -87,6 +87,7 @@
87
87
  "chartjs-chart-error-bars": "^4.4.0",
88
88
  "chartjs-chart-venn": "^4.3.0",
89
89
  "dayjs": "^1.11.10",
90
+ "dompurify": "^3.2.4",
90
91
  "downshift": "^9.0.8",
91
92
  "flatpickr": "^4.6.13",
92
93
  "gridjs": "^6.2.0",
@@ -66,7 +66,7 @@ export const MutationWithAnnotationEntry: StoryObj<AnnotatedMutationProps & { an
66
66
  annotations: [
67
67
  {
68
68
  name: 'Test annotation',
69
- description: 'This is a test annotation',
69
+ description: 'This is a test annotation <a class="link" href="/">with a link.</a>',
70
70
  symbol: '*',
71
71
  nucleotideMutations: ['A23403G'],
72
72
  aminoAcidMutations: [],
@@ -81,6 +81,7 @@ export const MutationWithAnnotationEntry: StoryObj<AnnotatedMutationProps & { an
81
81
 
82
82
  await userEvent.click(canvas.getByText('A23403G'));
83
83
  await waitFor(() => expect(getAnnotationName(canvas)).toBeVisible());
84
+ await expect(canvas.getByRole('link', { name: 'with a link.' })).toBeVisible();
84
85
  },
85
86
  };
86
87
 
@@ -1,3 +1,4 @@
1
+ import DOMPurify from 'dompurify';
1
2
  import { useRef } from 'gridjs';
2
3
  import { Fragment, type FunctionComponent, type RefObject } from 'preact';
3
4
 
@@ -56,14 +57,17 @@ const AnnotatedMutationWithoutContext: FunctionComponent<AnnotatedMutationWithou
56
57
  {mutationAnnotations.map((annotation) => (
57
58
  <Fragment key={annotation.name}>
58
59
  <InfoHeadline2>{annotation.name}</InfoHeadline2>
59
- <InfoParagraph>{annotation.description}</InfoParagraph>
60
+ <InfoParagraph>
61
+ {/* eslint-disable-next-line react/no-danger */}
62
+ <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(annotation.description) }} />
63
+ </InfoParagraph>
60
64
  </Fragment>
61
65
  ))}
62
66
  </div>
63
67
  );
64
68
 
65
69
  return (
66
- <ButtonWithModalDialog modalContent={modalContent} modalRef={modalRef}>
70
+ <ButtonWithModalDialog buttonClassName={'select-text'} modalContent={modalContent} modalRef={modalRef}>
67
71
  {mutation.code}
68
72
  <sup>
69
73
  {mutationAnnotations
@@ -0,0 +1,75 @@
1
+ import { type Meta, type StoryObj } from '@storybook/preact';
2
+ import { fn, userEvent, within } from '@storybook/test';
3
+
4
+ import { ClearableSelect, type ClearableSelectProps } from './clearable-select';
5
+ import { expectOptionSelected } from '../shared/stories/expectOptionSelected';
6
+
7
+ const meta: Meta<ClearableSelectProps> = {
8
+ title: 'Component/ClearableSelect',
9
+ component: ClearableSelect,
10
+ parameters: { fetchMock: {} },
11
+ };
12
+
13
+ export default meta;
14
+
15
+ export const Default: StoryObj<ClearableSelectProps> = {
16
+ render: (args) => (
17
+ <div class='flex justify-center px-4 py-16'>
18
+ <ClearableSelect {...args} />
19
+ </div>
20
+ ),
21
+ args: {
22
+ items: ['firstOption', 'secondOption'],
23
+ onChange: fn(),
24
+ },
25
+ play: async ({ canvasElement, step }) => {
26
+ await step('Show default placeholder', async () => {
27
+ await expectOptionSelected(canvasElement, 'Select an option');
28
+ });
29
+ },
30
+ };
31
+
32
+ export const UseInitialSelectedItem: StoryObj<ClearableSelectProps> = {
33
+ ...Default,
34
+ args: {
35
+ ...Default.args,
36
+ initiallySelectedItem: 'firstOption',
37
+ },
38
+ play: async ({ canvasElement, step }) => {
39
+ await step('Show initiallySelectedItem', async () => {
40
+ await expectOptionSelected(canvasElement, 'firstOption');
41
+ });
42
+ },
43
+ };
44
+
45
+ export const SwitchToOption: StoryObj<ClearableSelectProps> = {
46
+ ...Default,
47
+ play: async ({ canvasElement, step }) => {
48
+ const canvas = within(canvasElement);
49
+
50
+ await step('Select an option', async () => {
51
+ await userEvent.selectOptions(getSelectElement(canvas), 'firstOption');
52
+ await expectOptionSelected(canvasElement, 'firstOption');
53
+ });
54
+ },
55
+ };
56
+
57
+ export const ClearOption: StoryObj<ClearableSelectProps> = {
58
+ ...Default,
59
+ args: {
60
+ ...Default.args,
61
+ initiallySelectedItem: 'firstOption',
62
+ },
63
+ play: async ({ canvasElement, step }) => {
64
+ const canvas = within(canvasElement);
65
+
66
+ await step('Clear the selected option', async () => {
67
+ await userEvent.click(canvas.getByRole('button', { name: '×' }));
68
+ await expectOptionSelected(canvasElement, 'Select an option');
69
+ });
70
+ },
71
+ };
72
+
73
+ const getSelectElement = (canvas: ReturnType<typeof within>) => {
74
+ return canvas.getByRole('combobox');
75
+ };
@@ -0,0 +1,76 @@
1
+ import { type ChangeEvent } from 'preact/compat';
2
+ import { useEffect, useState } from 'preact/hooks';
3
+
4
+ import { type WithClassName } from '../shared/WithClassName/WithClassName';
5
+ import { DeleteIcon } from '../shared/icons/DeleteIcon';
6
+
7
+ export const undefinedValue = '__undefined__';
8
+
9
+ export type ClearableSelectProps = {
10
+ items: string[];
11
+ initiallySelectedItem?: string | null;
12
+ onChange?: (item: string | null) => void;
13
+ placeholderText?: string;
14
+ value?: string | null;
15
+ selectClassName?: string;
16
+ };
17
+
18
+ export function ClearableSelect({
19
+ items,
20
+ initiallySelectedItem,
21
+ onChange,
22
+ placeholderText,
23
+ className,
24
+ value,
25
+ selectClassName,
26
+ }: WithClassName<ClearableSelectProps>) {
27
+ const [selectedOption, setSelectedOption] = useState<string | null>(initiallySelectedItem ?? null);
28
+
29
+ useEffect(() => {
30
+ if (value !== undefined) {
31
+ setSelectedOption(value);
32
+ }
33
+ }, [value]);
34
+
35
+ const handleClear = () => {
36
+ setSelectedOption(null);
37
+ if (onChange) {
38
+ onChange(null);
39
+ }
40
+ };
41
+
42
+ const handleChange = (event: ChangeEvent<HTMLSelectElement>) => {
43
+ const newValue = event.currentTarget.value;
44
+ setSelectedOption(newValue);
45
+ if (onChange) {
46
+ onChange(newValue);
47
+ }
48
+ };
49
+
50
+ return (
51
+ <div className={`relative inline min-w-24 ${className}`}>
52
+ <select
53
+ className={`w-full select select-bordered pr-14 ${selectClassName}`}
54
+ value={selectedOption ?? undefinedValue}
55
+ onChange={handleChange}
56
+ >
57
+ <option value={undefinedValue} disabled>
58
+ {placeholderText ?? 'Select an option'}
59
+ </option>
60
+ {items.map((item) => (
61
+ <option key={item} value={item}>
62
+ {item}
63
+ </option>
64
+ ))}
65
+ </select>
66
+ {selectedOption && (
67
+ <button
68
+ onClick={handleClear}
69
+ className='absolute right-10 top-1/2 -translate-y-1/2 bg-transparent border-0 cursor-pointer'
70
+ >
71
+ <DeleteIcon />
72
+ </button>
73
+ )}
74
+ </div>
75
+ );
76
+ }