@genspectrum/dashboard-components 0.1.4 → 0.1.5
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.
- package/custom-elements.json +213 -78
- package/dist/dashboard-components.js +303 -53
- package/dist/dashboard-components.js.map +1 -1
- package/dist/genspectrum-components.d.ts +288 -69
- package/dist/style.css +142 -15
- package/package.json +3 -3
- package/src/preact/aggregatedData/aggregate.stories.tsx +2 -0
- package/src/preact/aggregatedData/aggregate.tsx +9 -4
- package/src/preact/components/headline.stories.tsx +19 -1
- package/src/preact/components/headline.tsx +9 -1
- package/src/preact/components/info.stories.tsx +24 -3
- package/src/preact/components/info.tsx +49 -5
- package/src/preact/dateRangeSelector/date-range-selector.tsx +10 -10
- package/src/preact/mutationComparison/mutation-comparison.stories.tsx +3 -0
- package/src/preact/mutationComparison/mutation-comparison.tsx +3 -3
- package/src/preact/mutationFilter/mutation-filter.tsx +1 -1
- package/src/preact/mutations/mutations.stories.tsx +3 -0
- package/src/preact/mutations/mutations.tsx +9 -3
- package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
- package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +14 -4
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +3 -0
- package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +49 -4
- package/src/web-components/display/aggregate-component.stories.ts +3 -0
- package/src/web-components/display/aggregate-component.tsx +15 -1
- package/src/web-components/display/mutation-comparison-component.stories.ts +3 -0
- package/src/web-components/display/mutation-comparison-component.tsx +7 -0
- package/src/web-components/display/mutations-component.stories.ts +27 -7
- package/src/web-components/display/mutations-component.tsx +58 -4
- package/src/web-components/display/prevalence-over-time-component.stories.ts +24 -0
- package/src/web-components/display/prevalence-over-time-component.tsx +93 -5
- package/src/web-components/display/relative-growth-advantage-component.stories.ts +21 -0
- package/src/web-components/display/relative-growth-advantage-component.tsx +54 -3
- package/src/web-components/input/date-range-selector-component.stories.ts +17 -2
- package/src/web-components/input/date-range-selector-component.tsx +57 -5
- package/src/web-components/input/mutation-filter-component.stories.ts +13 -3
- package/src/web-components/input/mutation-filter-component.tsx +50 -2
- package/src/web-components/input/text-input-component.stories.ts +14 -3
- package/src/web-components/input/text-input-component.tsx +23 -1
package/dist/style.css
CHANGED
|
@@ -1065,7 +1065,6 @@ html {
|
|
|
1065
1065
|
transition-duration: 200ms;
|
|
1066
1066
|
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
|
1067
1067
|
border-width: var(--border-btn, 1px);
|
|
1068
|
-
animation: button-pop var(--animation-btn, 0.25s) ease-out;
|
|
1069
1068
|
transition-property: color, background-color, border-color, opacity, box-shadow, transform;
|
|
1070
1069
|
--tw-text-opacity: 1;
|
|
1071
1070
|
color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity)));
|
|
@@ -1540,6 +1539,14 @@ html {
|
|
|
1540
1539
|
z-index: 3;
|
|
1541
1540
|
opacity: 1;
|
|
1542
1541
|
}
|
|
1542
|
+
.steps {
|
|
1543
|
+
display: inline-grid;
|
|
1544
|
+
grid-auto-flow: column;
|
|
1545
|
+
overflow: hidden;
|
|
1546
|
+
overflow-x: auto;
|
|
1547
|
+
counter-reset: step;
|
|
1548
|
+
grid-auto-columns: 1fr;
|
|
1549
|
+
}
|
|
1543
1550
|
.steps .step {
|
|
1544
1551
|
display: grid;
|
|
1545
1552
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
@@ -1554,8 +1561,7 @@ html {
|
|
|
1554
1561
|
display: grid;
|
|
1555
1562
|
align-items: flex-end;
|
|
1556
1563
|
}
|
|
1557
|
-
.tabs-lifted:has(.tab-content[class^="rounded-"]) .tab:first-child:not(.tab-active),
|
|
1558
|
-
.tabs-lifted:has(.tab-content[class*=" rounded-"]) .tab:first-child:not(.tab-active) {
|
|
1564
|
+
.tabs-lifted:has(.tab-content[class^="rounded-"]) .tab:first-child:not(:is(.tab-active, [aria-selected="true"])), .tabs-lifted:has(.tab-content[class*=" rounded-"]) .tab:first-child:not(:is(.tab-active, [aria-selected="true"])) {
|
|
1559
1565
|
border-bottom-color: transparent;
|
|
1560
1566
|
}
|
|
1561
1567
|
.tab {
|
|
@@ -1600,7 +1606,7 @@ html {
|
|
|
1600
1606
|
grid-column-start: span 9999;
|
|
1601
1607
|
}
|
|
1602
1608
|
input.tab:checked + .tab-content,
|
|
1603
|
-
.tab-active + .tab-content {
|
|
1609
|
+
:is(.tab-active, [aria-selected="true"]) + .tab-content {
|
|
1604
1610
|
display: block;
|
|
1605
1611
|
}
|
|
1606
1612
|
.table {
|
|
@@ -1645,6 +1651,12 @@ input.tab:checked + .tab-content,
|
|
|
1645
1651
|
font-size: 1rem;
|
|
1646
1652
|
line-height: 1.5rem;
|
|
1647
1653
|
}
|
|
1654
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1655
|
+
|
|
1656
|
+
.btn {
|
|
1657
|
+
animation: button-pop var(--animation-btn, 0.25s) ease-out;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1648
1660
|
.btn:active:hover,
|
|
1649
1661
|
.btn:active:focus {
|
|
1650
1662
|
animation: button-pop 0s ease-out;
|
|
@@ -2222,12 +2234,79 @@ input.tab:checked + .tab-content,
|
|
|
2222
2234
|
.steps .step[data-content]:after {
|
|
2223
2235
|
content: attr(data-content);
|
|
2224
2236
|
}
|
|
2237
|
+
.steps .step-neutral + .step-neutral:before,
|
|
2238
|
+
.steps .step-neutral:after {
|
|
2239
|
+
--tw-bg-opacity: 1;
|
|
2240
|
+
background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity)));
|
|
2241
|
+
--tw-text-opacity: 1;
|
|
2242
|
+
color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity)));
|
|
2243
|
+
}
|
|
2244
|
+
.steps .step-primary + .step-primary:before,
|
|
2245
|
+
.steps .step-primary:after {
|
|
2246
|
+
--tw-bg-opacity: 1;
|
|
2247
|
+
background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity)));
|
|
2248
|
+
--tw-text-opacity: 1;
|
|
2249
|
+
color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity)));
|
|
2250
|
+
}
|
|
2251
|
+
.steps .step-secondary + .step-secondary:before,
|
|
2252
|
+
.steps .step-secondary:after {
|
|
2253
|
+
--tw-bg-opacity: 1;
|
|
2254
|
+
background-color: var(--fallback-s,oklch(var(--s)/var(--tw-bg-opacity)));
|
|
2255
|
+
--tw-text-opacity: 1;
|
|
2256
|
+
color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity)));
|
|
2257
|
+
}
|
|
2258
|
+
.steps .step-accent + .step-accent:before,
|
|
2259
|
+
.steps .step-accent:after {
|
|
2260
|
+
--tw-bg-opacity: 1;
|
|
2261
|
+
background-color: var(--fallback-a,oklch(var(--a)/var(--tw-bg-opacity)));
|
|
2262
|
+
--tw-text-opacity: 1;
|
|
2263
|
+
color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity)));
|
|
2264
|
+
}
|
|
2265
|
+
.steps .step-info + .step-info:before {
|
|
2266
|
+
--tw-bg-opacity: 1;
|
|
2267
|
+
background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)));
|
|
2268
|
+
}
|
|
2269
|
+
.steps .step-info:after {
|
|
2270
|
+
--tw-bg-opacity: 1;
|
|
2271
|
+
background-color: var(--fallback-in,oklch(var(--in)/var(--tw-bg-opacity)));
|
|
2272
|
+
--tw-text-opacity: 1;
|
|
2273
|
+
color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity)));
|
|
2274
|
+
}
|
|
2275
|
+
.steps .step-success + .step-success:before {
|
|
2276
|
+
--tw-bg-opacity: 1;
|
|
2277
|
+
background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)));
|
|
2278
|
+
}
|
|
2279
|
+
.steps .step-success:after {
|
|
2280
|
+
--tw-bg-opacity: 1;
|
|
2281
|
+
background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity)));
|
|
2282
|
+
--tw-text-opacity: 1;
|
|
2283
|
+
color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity)));
|
|
2284
|
+
}
|
|
2285
|
+
.steps .step-warning + .step-warning:before {
|
|
2286
|
+
--tw-bg-opacity: 1;
|
|
2287
|
+
background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)));
|
|
2288
|
+
}
|
|
2289
|
+
.steps .step-warning:after {
|
|
2290
|
+
--tw-bg-opacity: 1;
|
|
2291
|
+
background-color: var(--fallback-wa,oklch(var(--wa)/var(--tw-bg-opacity)));
|
|
2292
|
+
--tw-text-opacity: 1;
|
|
2293
|
+
color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity)));
|
|
2294
|
+
}
|
|
2295
|
+
.steps .step-error + .step-error:before {
|
|
2296
|
+
--tw-bg-opacity: 1;
|
|
2297
|
+
background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)));
|
|
2298
|
+
}
|
|
2299
|
+
.steps .step-error:after {
|
|
2300
|
+
--tw-bg-opacity: 1;
|
|
2301
|
+
background-color: var(--fallback-er,oklch(var(--er)/var(--tw-bg-opacity)));
|
|
2302
|
+
--tw-text-opacity: 1;
|
|
2303
|
+
color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity)));
|
|
2304
|
+
}
|
|
2225
2305
|
.tabs-lifted > .tab:focus-visible {
|
|
2226
2306
|
border-end-end-radius: 0;
|
|
2227
2307
|
border-end-start-radius: 0;
|
|
2228
2308
|
}
|
|
2229
|
-
.tab.tab-active:not(.tab-disabled):not([disabled]),
|
|
2230
|
-
.tab:is(input:checked) {
|
|
2309
|
+
.tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tab:is(input:checked) {
|
|
2231
2310
|
border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity)));
|
|
2232
2311
|
--tw-border-opacity: 1;
|
|
2233
2312
|
--tw-text-opacity: 1;
|
|
@@ -2262,8 +2341,7 @@ input.tab:checked + .tab-content,
|
|
|
2262
2341
|
padding-inline-end: var(--tab-padding, 1rem);
|
|
2263
2342
|
padding-top: var(--tab-border, 1px);
|
|
2264
2343
|
}
|
|
2265
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]),
|
|
2266
|
-
.tabs-lifted > .tab:is(input:checked) {
|
|
2344
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]), .tabs-lifted > .tab:is(input:checked) {
|
|
2267
2345
|
background-color: var(--tab-bg);
|
|
2268
2346
|
border-width: var(--tab-border, 1px) var(--tab-border, 1px) 0 var(--tab-border, 1px);
|
|
2269
2347
|
border-inline-start-color: var(--tab-border-color);
|
|
@@ -2274,7 +2352,7 @@ input.tab:checked + .tab-content,
|
|
|
2274
2352
|
padding-bottom: var(--tab-border, 1px);
|
|
2275
2353
|
padding-top: 0;
|
|
2276
2354
|
}
|
|
2277
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked):before {
|
|
2355
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked):before {
|
|
2278
2356
|
z-index: 1;
|
|
2279
2357
|
content: "";
|
|
2280
2358
|
display: block;
|
|
@@ -2303,26 +2381,26 @@ input.tab:checked + .tab-content,
|
|
|
2303
2381
|
);
|
|
2304
2382
|
background-image: var(--radius-start), var(--radius-end);
|
|
2305
2383
|
}
|
|
2306
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):first-child:before, .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2384
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):first-child:before, .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2307
2385
|
background-image: var(--radius-end);
|
|
2308
2386
|
background-position: top right;
|
|
2309
2387
|
}
|
|
2310
|
-
[dir="rtl"] .tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):first-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2388
|
+
[dir="rtl"] .tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):first-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):first-child:before {
|
|
2311
2389
|
background-image: var(--radius-start);
|
|
2312
2390
|
background-position: top left;
|
|
2313
2391
|
}
|
|
2314
|
-
.tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):last-child:before, .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2392
|
+
.tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):last-child:before, .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2315
2393
|
background-image: var(--radius-start);
|
|
2316
2394
|
background-position: top left;
|
|
2317
2395
|
}
|
|
2318
|
-
[dir="rtl"] .tabs-lifted > .tab.tab-active:not(.tab-disabled):not([disabled]):last-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2396
|
+
[dir="rtl"] .tabs-lifted > .tab:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):last-child:before, [dir="rtl"] .tabs-lifted > .tab:is(input:checked):last-child:before {
|
|
2319
2397
|
background-image: var(--radius-end);
|
|
2320
2398
|
background-position: top right;
|
|
2321
2399
|
}
|
|
2322
2400
|
.tabs-lifted
|
|
2323
|
-
> .tab-active:not(.tab-disabled):not([disabled])
|
|
2401
|
+
> :is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled])
|
|
2324
2402
|
+ .tabs-lifted
|
|
2325
|
-
.tab-active:not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked) + .tabs-lifted .tab:is(input:checked):before {
|
|
2403
|
+
:is(.tab-active, [aria-selected="true"]):not(.tab-disabled):not([disabled]):before, .tabs-lifted > .tab:is(input:checked) + .tabs-lifted .tab:is(input:checked):before {
|
|
2326
2404
|
background-image: var(--radius-end);
|
|
2327
2405
|
background-position: top right;
|
|
2328
2406
|
}
|
|
@@ -2643,9 +2721,21 @@ input.tab:checked + .tab-content,
|
|
|
2643
2721
|
.static {
|
|
2644
2722
|
position: static;
|
|
2645
2723
|
}
|
|
2724
|
+
.absolute {
|
|
2725
|
+
position: absolute;
|
|
2726
|
+
}
|
|
2646
2727
|
.relative {
|
|
2647
2728
|
position: relative;
|
|
2648
2729
|
}
|
|
2730
|
+
.right-6 {
|
|
2731
|
+
right: 1.5rem;
|
|
2732
|
+
}
|
|
2733
|
+
.top-8 {
|
|
2734
|
+
top: 2rem;
|
|
2735
|
+
}
|
|
2736
|
+
.z-50 {
|
|
2737
|
+
z-index: 50;
|
|
2738
|
+
}
|
|
2649
2739
|
.z-\[1\] {
|
|
2650
2740
|
z-index: 1;
|
|
2651
2741
|
}
|
|
@@ -2682,6 +2772,9 @@ input.tab:checked + .tab-content,
|
|
|
2682
2772
|
.mt-2 {
|
|
2683
2773
|
margin-top: 0.5rem;
|
|
2684
2774
|
}
|
|
2775
|
+
.mt-4 {
|
|
2776
|
+
margin-top: 1rem;
|
|
2777
|
+
}
|
|
2685
2778
|
.inline {
|
|
2686
2779
|
display: inline;
|
|
2687
2780
|
}
|
|
@@ -2742,6 +2835,9 @@ input.tab:checked + .tab-content,
|
|
|
2742
2835
|
.items-center {
|
|
2743
2836
|
align-items: center;
|
|
2744
2837
|
}
|
|
2838
|
+
.justify-end {
|
|
2839
|
+
justify-content: flex-end;
|
|
2840
|
+
}
|
|
2745
2841
|
.justify-center {
|
|
2746
2842
|
justify-content: center;
|
|
2747
2843
|
}
|
|
@@ -2797,6 +2893,10 @@ input.tab:checked + .tab-content,
|
|
|
2797
2893
|
.border-b-2 {
|
|
2798
2894
|
border-bottom-width: 2px;
|
|
2799
2895
|
}
|
|
2896
|
+
.border-black {
|
|
2897
|
+
--tw-border-opacity: 1;
|
|
2898
|
+
border-color: rgb(0 0 0 / var(--tw-border-opacity));
|
|
2899
|
+
}
|
|
2800
2900
|
.border-error {
|
|
2801
2901
|
--tw-border-opacity: 1;
|
|
2802
2902
|
border-color: var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity)));
|
|
@@ -2856,6 +2956,13 @@ input.tab:checked + .tab-content,
|
|
|
2856
2956
|
padding-top: 0.5rem;
|
|
2857
2957
|
padding-bottom: 0.5rem;
|
|
2858
2958
|
}
|
|
2959
|
+
.text-justify {
|
|
2960
|
+
text-align: justify;
|
|
2961
|
+
}
|
|
2962
|
+
.text-base {
|
|
2963
|
+
font-size: 1rem;
|
|
2964
|
+
line-height: 1.5rem;
|
|
2965
|
+
}
|
|
2859
2966
|
.text-lg {
|
|
2860
2967
|
font-size: 1.125rem;
|
|
2861
2968
|
line-height: 1.75rem;
|
|
@@ -2881,15 +2988,31 @@ input.tab:checked + .tab-content,
|
|
|
2881
2988
|
.leading-5 {
|
|
2882
2989
|
line-height: 1.25rem;
|
|
2883
2990
|
}
|
|
2991
|
+
.text-blue-600 {
|
|
2992
|
+
--tw-text-opacity: 1;
|
|
2993
|
+
color: rgb(37 99 235 / var(--tw-text-opacity));
|
|
2994
|
+
}
|
|
2884
2995
|
.text-gray-600 {
|
|
2885
2996
|
--tw-text-opacity: 1;
|
|
2886
2997
|
color: rgb(75 85 99 / var(--tw-text-opacity));
|
|
2887
2998
|
}
|
|
2999
|
+
.underline {
|
|
3000
|
+
text-decoration-line: underline;
|
|
3001
|
+
}
|
|
2888
3002
|
.shadow {
|
|
2889
3003
|
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
2890
3004
|
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
2891
3005
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
2892
3006
|
}
|
|
3007
|
+
.shadow-lg {
|
|
3008
|
+
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
3009
|
+
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
|
|
3010
|
+
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
3011
|
+
}
|
|
3012
|
+
.blur {
|
|
3013
|
+
--tw-blur: blur(8px);
|
|
3014
|
+
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
3015
|
+
}
|
|
2893
3016
|
.filter {
|
|
2894
3017
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
|
2895
3018
|
}
|
|
@@ -2905,6 +3028,10 @@ input.tab:checked + .tab-content,
|
|
|
2905
3028
|
--tw-bg-opacity: 1;
|
|
2906
3029
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
|
2907
3030
|
}
|
|
3031
|
+
.hover\:text-blue-800:hover {
|
|
3032
|
+
--tw-text-opacity: 1;
|
|
3033
|
+
color: rgb(30 64 175 / var(--tw-text-opacity));
|
|
3034
|
+
}
|
|
2908
3035
|
.hover\:text-gray-700:hover {
|
|
2909
3036
|
--tw-text-opacity: 1;
|
|
2910
3037
|
color: rgb(55 65 81 / var(--tw-text-opacity));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genspectrum/dashboard-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "GenSpectrum web components for building dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"zod": "^3.23.0"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"@custom-elements-manifest/analyzer": "^0.
|
|
73
|
+
"@custom-elements-manifest/analyzer": "^0.10.2",
|
|
74
74
|
"@playwright/test": "^1.43.1",
|
|
75
75
|
"@storybook/addon-actions": "^8.0.9",
|
|
76
76
|
"@storybook/addon-essentials": "^8.0.9",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@storybook/preact": "^8.0.9",
|
|
81
81
|
"@storybook/preact-vite": "^8.0.9",
|
|
82
82
|
"@storybook/test": "^8.0.0",
|
|
83
|
-
"@storybook/test-runner": "^0.
|
|
83
|
+
"@storybook/test-runner": "^0.18.0",
|
|
84
84
|
"@storybook/types": "^8.0.9",
|
|
85
85
|
"@storybook/web-components": "^8.0.9",
|
|
86
86
|
"@storybook/web-components-vite": "^8.0.9",
|
|
@@ -11,6 +11,7 @@ const meta: Meta<AggregateProps> = {
|
|
|
11
11
|
argTypes: {
|
|
12
12
|
fields: [{ control: 'object' }],
|
|
13
13
|
size: [{ control: 'object' }],
|
|
14
|
+
headline: { control: 'text' },
|
|
14
15
|
},
|
|
15
16
|
parameters: {
|
|
16
17
|
fetchMock: {
|
|
@@ -49,5 +50,6 @@ export const Default: StoryObj<AggregateProps> = {
|
|
|
49
50
|
country: 'USA',
|
|
50
51
|
},
|
|
51
52
|
size: { width: '100%', height: '70vh' },
|
|
53
|
+
headline: 'Aggregate',
|
|
52
54
|
},
|
|
53
55
|
};
|
|
@@ -22,17 +22,22 @@ export interface AggregateProps {
|
|
|
22
22
|
fields: string[];
|
|
23
23
|
views: View[];
|
|
24
24
|
size?: Size;
|
|
25
|
+
headline?: string;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
28
|
+
export const Aggregate: FunctionComponent<AggregateProps> = ({
|
|
29
|
+
fields,
|
|
30
|
+
views,
|
|
31
|
+
filter,
|
|
32
|
+
size,
|
|
33
|
+
headline = 'Aggregate',
|
|
34
|
+
}) => {
|
|
28
35
|
const lapis = useContext(LapisUrlContext);
|
|
29
36
|
|
|
30
37
|
const { data, error, isLoading } = useQuery(async () => {
|
|
31
38
|
return queryAggregateData(filter, fields, lapis);
|
|
32
39
|
}, [filter, fields, lapis]);
|
|
33
40
|
|
|
34
|
-
const headline = 'Aggregate';
|
|
35
|
-
|
|
36
41
|
if (isLoading) {
|
|
37
42
|
return (
|
|
38
43
|
<Headline heading={headline}>
|
|
@@ -96,7 +101,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({ data }) => {
|
|
|
96
101
|
return (
|
|
97
102
|
<div class='flex flex-row'>
|
|
98
103
|
<CsvDownloadButton className='mx-1 btn btn-xs' getData={() => data} filename='aggregate.csv' />
|
|
99
|
-
<Info
|
|
104
|
+
<Info>Info for aggregate</Info>
|
|
100
105
|
</div>
|
|
101
106
|
);
|
|
102
107
|
};
|
|
@@ -3,10 +3,13 @@ import { expect, within } from '@storybook/test';
|
|
|
3
3
|
|
|
4
4
|
import Headline, { type HeadlineProps } from './headline';
|
|
5
5
|
|
|
6
|
-
const meta: Meta<
|
|
6
|
+
const meta: Meta<HeadlineProps> = {
|
|
7
7
|
title: 'Component/Headline',
|
|
8
8
|
component: Headline,
|
|
9
9
|
parameters: { fetchMock: {} },
|
|
10
|
+
argTypes: {
|
|
11
|
+
heading: { control: 'text' },
|
|
12
|
+
},
|
|
10
13
|
};
|
|
11
14
|
|
|
12
15
|
export default meta;
|
|
@@ -27,3 +30,18 @@ export const HeadlineStory: StoryObj<HeadlineProps> = {
|
|
|
27
30
|
await expect(canvas.getByText('Some Content')).toBeInTheDocument();
|
|
28
31
|
},
|
|
29
32
|
};
|
|
33
|
+
|
|
34
|
+
export const NoHeadlineStory: StoryObj<HeadlineProps> = {
|
|
35
|
+
render: (args) => (
|
|
36
|
+
<Headline {...args}>
|
|
37
|
+
<div class='flex justify-center px-4 py-16 bg-base-200'>Some Content</div>
|
|
38
|
+
</Headline>
|
|
39
|
+
),
|
|
40
|
+
args: {},
|
|
41
|
+
play: async ({ canvasElement }) => {
|
|
42
|
+
const canvas = within(canvasElement);
|
|
43
|
+
|
|
44
|
+
await expect(canvas.queryByText('My Headline')).not.toBeInTheDocument();
|
|
45
|
+
await expect(canvas.getByText('Some Content')).toBeInTheDocument();
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -2,10 +2,18 @@ import { type FunctionComponent } from 'preact';
|
|
|
2
2
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
3
3
|
|
|
4
4
|
export interface HeadlineProps {
|
|
5
|
-
heading
|
|
5
|
+
heading?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
const Headline: FunctionComponent<HeadlineProps> = ({ heading, children }) => {
|
|
9
|
+
if (!heading) {
|
|
10
|
+
return <>{children}</>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return <ResizingHeadline heading={heading}>{children}</ResizingHeadline>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const ResizingHeadline: FunctionComponent<HeadlineProps> = ({ heading, children }) => {
|
|
9
17
|
const ref = useRef<HTMLHeadingElement>(null);
|
|
10
18
|
|
|
11
19
|
const [h1Height, setH1Height] = useState('2rem');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Meta, type StoryObj } from '@storybook/preact';
|
|
2
|
+
import { expect, fireEvent, waitFor, within } from '@storybook/test';
|
|
2
3
|
|
|
3
4
|
import Info, { type InfoProps } from './info';
|
|
4
5
|
|
|
@@ -7,16 +8,36 @@ const meta: Meta<InfoProps> = {
|
|
|
7
8
|
component: Info,
|
|
8
9
|
parameters: { fetchMock: {} },
|
|
9
10
|
args: {
|
|
10
|
-
|
|
11
|
+
size: { width: '400px', height: '100px' },
|
|
11
12
|
},
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export default meta;
|
|
15
16
|
|
|
17
|
+
const tooltipText = 'This is a tooltip which shows some information.';
|
|
18
|
+
|
|
16
19
|
export const InfoStory: StoryObj<InfoProps> = {
|
|
17
20
|
render: (args) => (
|
|
18
|
-
<div class='flex justify-center px-4 py-16
|
|
19
|
-
<Info {...args}
|
|
21
|
+
<div class='flex justify-center px-4 py-16'>
|
|
22
|
+
<Info {...args}>{tooltipText}</Info>
|
|
20
23
|
</div>
|
|
21
24
|
),
|
|
22
25
|
};
|
|
26
|
+
|
|
27
|
+
export const ShowsInfoOnClick: StoryObj<InfoProps> = {
|
|
28
|
+
...InfoStory,
|
|
29
|
+
play: async ({ canvasElement }) => {
|
|
30
|
+
const canvas = within(canvasElement);
|
|
31
|
+
const loading = canvas.getByRole('button', { name: '?' });
|
|
32
|
+
|
|
33
|
+
await waitFor(() => expect(loading).toBeInTheDocument());
|
|
34
|
+
|
|
35
|
+
await fireEvent.click(loading);
|
|
36
|
+
|
|
37
|
+
await waitFor(() => expect(canvas.getByText(tooltipText, { exact: false })).toBeInTheDocument());
|
|
38
|
+
|
|
39
|
+
await fireEvent.click(canvas.getByRole('button', { name: 'Close' }));
|
|
40
|
+
|
|
41
|
+
await waitFor(() => expect(canvas.queryByText(tooltipText, { exact: false })).not.toBeInTheDocument());
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -1,16 +1,60 @@
|
|
|
1
1
|
import { type FunctionComponent } from 'preact';
|
|
2
|
+
import { useState } from 'preact/hooks';
|
|
2
3
|
|
|
3
4
|
export interface InfoProps {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
size?: {
|
|
6
|
+
height?: string;
|
|
7
|
+
width?: string;
|
|
8
|
+
};
|
|
6
9
|
}
|
|
7
10
|
|
|
8
|
-
const Info: FunctionComponent<InfoProps> = ({
|
|
11
|
+
const Info: FunctionComponent<InfoProps> = ({ children, size }) => {
|
|
12
|
+
const [showHelp, setShowHelp] = useState(false);
|
|
13
|
+
|
|
14
|
+
const toggleHelp = () => {
|
|
15
|
+
setShowHelp(!showHelp);
|
|
16
|
+
};
|
|
17
|
+
|
|
9
18
|
return (
|
|
10
|
-
<div
|
|
11
|
-
<button
|
|
19
|
+
<div className='relative'>
|
|
20
|
+
<button className='btn btn-xs' onClick={toggleHelp}>
|
|
21
|
+
?
|
|
22
|
+
</button>
|
|
23
|
+
{showHelp && (
|
|
24
|
+
<div
|
|
25
|
+
className='absolute top-8 right-6 bg-white p-2 border border-black flex flex-col overflow-auto shadow-lg rounded z-50'
|
|
26
|
+
style={size}
|
|
27
|
+
>
|
|
28
|
+
<div className='flex flex-col'>{children}</div>
|
|
29
|
+
<div className='flex justify-end'>
|
|
30
|
+
<button className='text-sm underline mt-2' onClick={toggleHelp}>
|
|
31
|
+
Close
|
|
32
|
+
</button>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
)}
|
|
12
36
|
</div>
|
|
13
37
|
);
|
|
14
38
|
};
|
|
15
39
|
|
|
40
|
+
export const InfoHeadline1: FunctionComponent = ({ children }) => {
|
|
41
|
+
return <h1 className='text-lg font-bold'>{children}</h1>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const InfoHeadline2: FunctionComponent = ({ children }) => {
|
|
45
|
+
return <h2 className='text-base font-bold mt-4'>{children}</h2>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const InfoParagraph: FunctionComponent = ({ children }) => {
|
|
49
|
+
return <p className='text-justify my-1'>{children}</p>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const InfoLink: FunctionComponent<{ href: string }> = ({ children, href }) => {
|
|
53
|
+
return (
|
|
54
|
+
<a className='text-blue-600 hover:text-blue-800' href={href} target='_blank' rel='noopener noreferrer'>
|
|
55
|
+
{children}
|
|
56
|
+
</a>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
16
60
|
export default Info;
|
|
@@ -39,8 +39,8 @@ export const DateRangeSelector = <CustomLabel extends string>({
|
|
|
39
39
|
earliestDate = '1900-01-01',
|
|
40
40
|
initialValue,
|
|
41
41
|
}: DateRangeSelectorProps<CustomLabel>) => {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
42
|
+
const fromDatePickerRef = useRef<HTMLInputElement>(null);
|
|
43
|
+
const toDatePickerRef = useRef<HTMLInputElement>(null);
|
|
44
44
|
const divRef = useRef<HTMLDivElement>(null);
|
|
45
45
|
const [dateFromPicker, setDateFromPicker] = useState<flatpickr.Instance | null>(null);
|
|
46
46
|
const [dateToPicker, setDateToPicker] = useState<flatpickr.Instance | null>(null);
|
|
@@ -64,18 +64,18 @@ export const DateRangeSelector = <CustomLabel extends string>({
|
|
|
64
64
|
dateFormat: 'Y-m-d',
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
if (
|
|
67
|
+
if (fromDatePickerRef.current) {
|
|
68
68
|
setDateFromPicker(
|
|
69
|
-
flatpickr(
|
|
69
|
+
flatpickr(fromDatePickerRef.current, {
|
|
70
70
|
...commonConfig,
|
|
71
71
|
defaultDate: selectedDates.dateFrom,
|
|
72
72
|
}),
|
|
73
73
|
);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
if (
|
|
76
|
+
if (toDatePickerRef.current) {
|
|
77
77
|
setDateToPicker(
|
|
78
|
-
flatpickr(
|
|
78
|
+
flatpickr(toDatePickerRef.current, {
|
|
79
79
|
...commonConfig,
|
|
80
80
|
defaultDate: selectedDates.dateTo,
|
|
81
81
|
}),
|
|
@@ -87,7 +87,7 @@ export const DateRangeSelector = <CustomLabel extends string>({
|
|
|
87
87
|
dateToPicker?.destroy();
|
|
88
88
|
};
|
|
89
89
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
-
}, [
|
|
90
|
+
}, [fromDatePickerRef, toDatePickerRef]);
|
|
91
91
|
|
|
92
92
|
const onSelectChange = (value: CustomLabel | PresetOptionValues) => {
|
|
93
93
|
setSelectedDateRange(value);
|
|
@@ -167,7 +167,7 @@ export const DateRangeSelector = <CustomLabel extends string>({
|
|
|
167
167
|
class='input input-bordered rounded-none join-item'
|
|
168
168
|
type='text'
|
|
169
169
|
placeholder='Date from'
|
|
170
|
-
ref={
|
|
170
|
+
ref={fromDatePickerRef}
|
|
171
171
|
onChange={onChangeDateFrom}
|
|
172
172
|
onBlur={onChangeDateFrom}
|
|
173
173
|
/>
|
|
@@ -175,9 +175,9 @@ export const DateRangeSelector = <CustomLabel extends string>({
|
|
|
175
175
|
class='input input-bordered rounded-none join-item'
|
|
176
176
|
type='text'
|
|
177
177
|
placeholder='Date to'
|
|
178
|
-
ref={
|
|
178
|
+
ref={toDatePickerRef}
|
|
179
179
|
onChange={onChangeDateTo}
|
|
180
|
-
onBlur={
|
|
180
|
+
onBlur={onChangeDateTo}
|
|
181
181
|
/>
|
|
182
182
|
</div>
|
|
183
183
|
);
|
|
@@ -28,6 +28,7 @@ const meta: Meta<MutationComparisonProps> = {
|
|
|
28
28
|
control: { type: 'check' },
|
|
29
29
|
},
|
|
30
30
|
size: [{ control: 'object' }],
|
|
31
|
+
headline: { control: 'text' },
|
|
31
32
|
},
|
|
32
33
|
parameters: {
|
|
33
34
|
fetchMock: {
|
|
@@ -81,6 +82,7 @@ const Template: StoryObj<MutationComparisonProps> = {
|
|
|
81
82
|
sequenceType={args.sequenceType}
|
|
82
83
|
views={args.views}
|
|
83
84
|
size={args.size}
|
|
85
|
+
headline={args.headline}
|
|
84
86
|
/>
|
|
85
87
|
</ReferenceGenomeContext.Provider>
|
|
86
88
|
</LapisUrlContext.Provider>
|
|
@@ -108,6 +110,7 @@ export const TwoVariants: StoryObj<MutationComparisonProps> = {
|
|
|
108
110
|
sequenceType: 'nucleotide',
|
|
109
111
|
views: ['table', 'venn'],
|
|
110
112
|
size: { width: '100%', height: '700px' },
|
|
113
|
+
headline: 'Mutation comparison',
|
|
111
114
|
},
|
|
112
115
|
};
|
|
113
116
|
|
|
@@ -33,6 +33,7 @@ export interface MutationComparisonProps {
|
|
|
33
33
|
sequenceType: SequenceType;
|
|
34
34
|
views: View[];
|
|
35
35
|
size?: Size;
|
|
36
|
+
headline?: string;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
@@ -40,6 +41,7 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
|
40
41
|
sequenceType,
|
|
41
42
|
views,
|
|
42
43
|
size,
|
|
44
|
+
headline = 'Mutation comparison',
|
|
43
45
|
}) => {
|
|
44
46
|
const lapis = useContext(LapisUrlContext);
|
|
45
47
|
|
|
@@ -47,8 +49,6 @@ export const MutationComparison: FunctionComponent<MutationComparisonProps> = ({
|
|
|
47
49
|
return queryMutationData(variants, sequenceType, lapis);
|
|
48
50
|
}, [variants, sequenceType, lapis]);
|
|
49
51
|
|
|
50
|
-
const headline = 'Mutation comparison';
|
|
51
|
-
|
|
52
52
|
if (isLoading) {
|
|
53
53
|
return (
|
|
54
54
|
<Headline heading={headline}>
|
|
@@ -182,7 +182,7 @@ const Toolbar: FunctionComponent<ToolbarProps> = ({
|
|
|
182
182
|
getData={() => getMutationComparisonTableData({ content: filteredData }, proportionInterval)}
|
|
183
183
|
filename='mutation_comparison.csv'
|
|
184
184
|
/>
|
|
185
|
-
<Info
|
|
185
|
+
<Info>Info for mutation comparison</Info>
|
|
186
186
|
</div>
|
|
187
187
|
);
|
|
188
188
|
};
|
|
@@ -90,7 +90,7 @@ export const MutationFilter: FunctionComponent<MutationFilterProps> = ({ initial
|
|
|
90
90
|
setSelectedFilters={setSelectedFilters}
|
|
91
91
|
fireChangeEvent={fireChangeEvent}
|
|
92
92
|
/>
|
|
93
|
-
<Info
|
|
93
|
+
<Info>Info for mutation filter</Info>
|
|
94
94
|
</div>
|
|
95
95
|
|
|
96
96
|
<form className='mt-2 w-full' onSubmit={handleSubmit} ref={formRef}>
|