@genspectrum/dashboard-components 0.18.6 → 0.19.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.
package/dist/util.d.ts CHANGED
@@ -902,7 +902,7 @@ declare global {
902
902
 
903
903
  declare global {
904
904
  interface HTMLElementTagNameMap {
905
- 'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
905
+ 'gs-mutation-comparison-component': MutationComparisonComponent;
906
906
  }
907
907
  }
908
908
 
@@ -910,7 +910,7 @@ declare global {
910
910
  declare global {
911
911
  namespace JSX {
912
912
  interface IntrinsicElements {
913
- 'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
913
+ 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
914
914
  }
915
915
  }
916
916
  }
@@ -918,7 +918,7 @@ declare global {
918
918
 
919
919
  declare global {
920
920
  interface HTMLElementTagNameMap {
921
- 'gs-mutation-comparison-component': MutationComparisonComponent;
921
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
922
922
  }
923
923
  }
924
924
 
@@ -926,7 +926,7 @@ declare global {
926
926
  declare global {
927
927
  namespace JSX {
928
928
  interface IntrinsicElements {
929
- 'gs-mutation-comparison-component': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
929
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
930
930
  }
931
931
  }
932
932
  }
@@ -966,7 +966,7 @@ declare global {
966
966
 
967
967
  declare global {
968
968
  interface HTMLElementTagNameMap {
969
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
969
+ 'gs-aggregate': AggregateComponent;
970
970
  }
971
971
  }
972
972
 
@@ -974,7 +974,7 @@ declare global {
974
974
  declare global {
975
975
  namespace JSX {
976
976
  interface IntrinsicElements {
977
- 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
977
+ 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
978
978
  }
979
979
  }
980
980
  }
@@ -998,7 +998,7 @@ declare global {
998
998
 
999
999
  declare global {
1000
1000
  interface HTMLElementTagNameMap {
1001
- 'gs-aggregate': AggregateComponent;
1001
+ 'gs-mutations-over-time': MutationsOverTimeComponent;
1002
1002
  }
1003
1003
  }
1004
1004
 
@@ -1006,7 +1006,7 @@ declare global {
1006
1006
  declare global {
1007
1007
  namespace JSX {
1008
1008
  interface IntrinsicElements {
1009
- 'gs-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1009
+ 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1010
1010
  }
1011
1011
  }
1012
1012
  }
@@ -1014,7 +1014,7 @@ declare global {
1014
1014
 
1015
1015
  declare global {
1016
1016
  interface HTMLElementTagNameMap {
1017
- 'gs-mutations-over-time': MutationsOverTimeComponent;
1017
+ 'gs-sequences-by-location': SequencesByLocationComponent;
1018
1018
  }
1019
1019
  }
1020
1020
 
@@ -1022,7 +1022,7 @@ declare global {
1022
1022
  declare global {
1023
1023
  namespace JSX {
1024
1024
  interface IntrinsicElements {
1025
- 'gs-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1025
+ 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1026
1026
  }
1027
1027
  }
1028
1028
  }
@@ -1030,7 +1030,7 @@ declare global {
1030
1030
 
1031
1031
  declare global {
1032
1032
  interface HTMLElementTagNameMap {
1033
- 'gs-sequences-by-location': SequencesByLocationComponent;
1033
+ 'gs-statistics': StatisticsComponent;
1034
1034
  }
1035
1035
  }
1036
1036
 
@@ -1038,7 +1038,7 @@ declare global {
1038
1038
  declare global {
1039
1039
  namespace JSX {
1040
1040
  interface IntrinsicElements {
1041
- 'gs-sequences-by-location': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1041
+ 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1042
1042
  }
1043
1043
  }
1044
1044
  }
@@ -1046,7 +1046,7 @@ declare global {
1046
1046
 
1047
1047
  declare global {
1048
1048
  interface HTMLElementTagNameMap {
1049
- 'gs-statistics': StatisticsComponent;
1049
+ 'gs-wastewater-mutations-over-time': WastewaterMutationsOverTimeComponent;
1050
1050
  }
1051
1051
  }
1052
1052
 
@@ -1054,7 +1054,7 @@ declare global {
1054
1054
  declare global {
1055
1055
  namespace JSX {
1056
1056
  interface IntrinsicElements {
1057
- 'gs-statistics': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1057
+ 'gs-wastewater-mutations-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1058
1058
  }
1059
1059
  }
1060
1060
  }
@@ -1062,11 +1062,10 @@ declare global {
1062
1062
 
1063
1063
  declare global {
1064
1064
  interface HTMLElementTagNameMap {
1065
- 'gs-date-range-filter': DateRangeFilterComponent;
1065
+ 'gs-location-filter': LocationFilterComponent;
1066
1066
  }
1067
1067
  interface HTMLElementEventMap {
1068
- 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
1069
- 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
1068
+ 'gs-location-changed': LocationChangedEvent;
1070
1069
  }
1071
1070
  }
1072
1071
 
@@ -1074,7 +1073,7 @@ declare global {
1074
1073
  declare global {
1075
1074
  namespace JSX {
1076
1075
  interface IntrinsicElements {
1077
- 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1076
+ 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1078
1077
  }
1079
1078
  }
1080
1079
  }
@@ -1082,10 +1081,10 @@ declare global {
1082
1081
 
1083
1082
  declare global {
1084
1083
  interface HTMLElementTagNameMap {
1085
- 'gs-location-filter': LocationFilterComponent;
1084
+ 'gs-text-filter': TextFilterComponent;
1086
1085
  }
1087
1086
  interface HTMLElementEventMap {
1088
- 'gs-location-changed': LocationChangedEvent;
1087
+ 'gs-text-filter-changed': TextFilterChangedEvent;
1089
1088
  }
1090
1089
  }
1091
1090
 
@@ -1093,7 +1092,7 @@ declare global {
1093
1092
  declare global {
1094
1093
  namespace JSX {
1095
1094
  interface IntrinsicElements {
1096
- 'gs-location-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1095
+ 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1097
1096
  }
1098
1097
  }
1099
1098
  }
@@ -1101,10 +1100,11 @@ declare global {
1101
1100
 
1102
1101
  declare global {
1103
1102
  interface HTMLElementTagNameMap {
1104
- 'gs-text-filter': TextFilterComponent;
1103
+ 'gs-date-range-filter': DateRangeFilterComponent;
1105
1104
  }
1106
1105
  interface HTMLElementEventMap {
1107
- 'gs-text-filter-changed': TextFilterChangedEvent;
1106
+ 'gs-date-range-filter-changed': CustomEvent<Record<string, string>>;
1107
+ 'gs-date-range-option-changed': DateRangeOptionChangedEvent;
1108
1108
  }
1109
1109
  }
1110
1110
 
@@ -1112,7 +1112,7 @@ declare global {
1112
1112
  declare global {
1113
1113
  namespace JSX {
1114
1114
  interface IntrinsicElements {
1115
- 'gs-text-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1115
+ 'gs-date-range-filter': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1116
1116
  }
1117
1117
  }
1118
1118
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.18.6",
3
+ "version": "0.19.0",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -38,8 +38,7 @@
38
38
  "require": "./dist/util.js"
39
39
  },
40
40
  "./custom-elements.json": "./custom-elements.json",
41
- "./package.json": "./package.json",
42
- "./style.css": "./dist/style.css"
41
+ "./package.json": "./package.json"
43
42
  },
44
43
  "files": [
45
44
  "dist",
@@ -103,7 +103,6 @@ function generateFullExampleCode(componentCode: string, componentName: string) {
103
103
  return `<html>
104
104
  <head>
105
105
  <script type="module" src="https://unpkg.com/@genspectrum/dashboard-components@latest/standalone-bundle/dashboard-components.js"></script>
106
- <link rel="stylesheet" href="https://unpkg.com/@genspectrum/dashboard-components@latest/dist/style.css" />
107
106
  </head>
108
107
 
109
108
  <body>
@@ -1,8 +1,6 @@
1
1
  import { type FunctionComponent, type JSX } from 'preact';
2
2
  import { useState } from 'preact/hooks';
3
3
 
4
- import './min-max-percent-slider.css';
5
-
6
4
  export interface MinMaxPercentSliderProps {
7
5
  min: number;
8
6
  max: number;
@@ -3,8 +3,6 @@ import { type OneDArray, type TColumn, type TData } from 'gridjs/dist/src/types'
3
3
  import { type ComponentChild } from 'preact';
4
4
  import { useEffect, useRef } from 'preact/hooks';
5
5
 
6
- import 'gridjs/dist/theme/mermaid.css';
7
-
8
6
  export const tableStyle = {
9
7
  table: {
10
8
  fontSize: '12px',
@@ -1,4 +1,3 @@
1
- import 'flatpickr/dist/flatpickr.min.css';
2
1
  import flatpickr from 'flatpickr';
3
2
  import { useEffect, useRef, useState } from 'preact/hooks';
4
3
 
@@ -22,8 +21,10 @@ export function DatePicker({
22
21
 
23
22
  const [datePicker, setDatePicker] = useState<flatpickr.Instance | null>(null);
24
23
 
24
+ const calendarRef = useRef<HTMLDivElement>(null);
25
+
25
26
  useEffect(() => {
26
- if (!inputRef.current) {
27
+ if (!inputRef.current || !calendarRef.current) {
27
28
  return;
28
29
  }
29
30
 
@@ -33,6 +34,7 @@ export function DatePicker({
33
34
  defaultDate: value,
34
35
  minDate,
35
36
  maxDate,
37
+ appendTo: calendarRef.current,
36
38
  });
37
39
 
38
40
  setDatePicker(instance);
@@ -54,13 +56,16 @@ export function DatePicker({
54
56
  };
55
57
 
56
58
  return (
57
- <input
58
- className={`input w-full ${className}`}
59
- type='text'
60
- placeholder={placeholderText}
61
- ref={inputRef}
62
- onChange={handleChange}
63
- onBlur={handleChange}
64
- />
59
+ <div className={'w-full'}>
60
+ <input
61
+ className={`input w-full ${className}`}
62
+ type='text'
63
+ placeholder={placeholderText}
64
+ ref={inputRef}
65
+ onChange={handleChange}
66
+ onBlur={handleChange}
67
+ />
68
+ <div ref={calendarRef} />
69
+ </div>
65
70
  );
66
71
  }
@@ -0,0 +1,49 @@
1
+ import { css } from '@lit/reactive-element';
2
+ import { type Meta, type StoryObj } from '@storybook/preact';
3
+ import { expect } from '@storybook/test';
4
+ import { type FunctionComponent } from 'preact';
5
+
6
+ import { replaceCssProperties } from './replaceCssProperties';
7
+
8
+ const DummyComponent: FunctionComponent = () => 'This just runs a function in the browser';
9
+
10
+ const meta: Meta = {
11
+ title: 'Test/replaceCssProperties',
12
+ component: DummyComponent,
13
+ };
14
+
15
+ export default meta;
16
+
17
+ /**
18
+ * This test somehow doesn't work with vitest on node, because the @properties are not parsed by `css()`.
19
+ */
20
+ export const InvalidProps: StoryObj = {
21
+ play: async () => {
22
+ const styleSheet = css`
23
+ .some-other-rule {
24
+ color: red;
25
+ }
26
+
27
+ @property --test-with-initial-value {
28
+ syntax: '*';
29
+ inherits: false;
30
+ initial-value: solid;
31
+ }
32
+
33
+ @property --test-without-initial-value {
34
+ syntax: '*';
35
+ inherits: false;
36
+ }
37
+ `.styleSheet!;
38
+
39
+ replaceCssProperties(styleSheet);
40
+
41
+ const resultingCss = [...styleSheet.cssRules]
42
+ .map((rule) => rule.cssText)
43
+ .join('\n')
44
+ .replaceAll(' ', '');
45
+
46
+ await expect(resultingCss).toContain(':host{--test-with-initial-value:solid;}');
47
+ await expect(resultingCss).toContain('.some-other-rule{color:red;}');
48
+ },
49
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Replaces `@property` rules in a CSSStyleSheet with a `:host` rule.
3
+ *
4
+ * Tailwind uses `@property` rules, but they don't work in the shadow DOM.
5
+ * https://github.com/tailwindlabs/tailwindcss/issues/15005
6
+ *
7
+ * Inspired by https://github.com/tailwindlabs/tailwindcss/issues/15005#issuecomment-2737489813
8
+ */
9
+ export function replaceCssProperties(styleSheet: CSSStyleSheet) {
10
+ const properties: string[] = [];
11
+
12
+ [...styleSheet.cssRules]
13
+ .map((rule, index) => [rule, index] as const)
14
+ .reverse()
15
+ .forEach(([rule, index]) => {
16
+ if (rule instanceof CSSPropertyRule && rule.initialValue !== null) {
17
+ styleSheet.deleteRule(index);
18
+ properties.push(`${rule.name}: ${rule.initialValue}`);
19
+ }
20
+ });
21
+
22
+ if (properties.length > 0) {
23
+ styleSheet.insertRule(`:host { ${properties.join('; ')} }`);
24
+ }
25
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  @plugin "daisyui" {
4
4
  themes: light --default;
5
+ root: ':host';
5
6
  }
6
7
  @plugin "@iconify/tailwind4" {
7
8
  prefixes: mdi, mdi-light;
@@ -10,14 +10,17 @@ import { type ReferenceGenome } from '../lapisApi/ReferenceGenome';
10
10
  import { LapisUrlContextProvider } from '../preact/LapisUrlContext';
11
11
  import { INITIAL_REFERENCE_GENOMES, ReferenceGenomeContext } from '../preact/ReferenceGenomeContext';
12
12
  import minMaxPercentSliderCss from '../preact/components/min-max-percent-slider.css?inline';
13
+ import { replaceCssProperties } from '../styles/replaceCssProperties';
13
14
  import tailwindStyle from '../styles/tailwind.css?inline';
14
15
 
15
- import '../styles/tailwind.css';
16
- import '../preact/components/min-max-percent-slider.css';
17
-
18
16
  const tailwindElementCss = unsafeCSS(tailwindStyle);
19
17
  const minMaxPercentSliderElementCss = unsafeCSS(minMaxPercentSliderCss);
20
18
 
19
+ const styleSheet = tailwindElementCss.styleSheet;
20
+ if (styleSheet !== undefined) {
21
+ replaceCssProperties(styleSheet);
22
+ }
23
+
21
24
  export abstract class PreactLitAdapter extends ReactiveElement {
22
25
  static override styles = [tailwindElementCss, minMaxPercentSliderElementCss];
23
26
 
@@ -3,8 +3,6 @@ import { unsafeCSS } from 'lit';
3
3
 
4
4
  import { PreactLitAdapter } from './PreactLitAdapter';
5
5
 
6
- import 'gridjs/dist/theme/mermaid.css';
7
-
8
6
  const gridJsElementCss = unsafeCSS(gridJsStyle);
9
7
 
10
8
  export abstract class PreactLitAdapterWithGridJsStyles extends PreactLitAdapter {
@@ -82,7 +82,9 @@ export const WithNoLapisUrl: StoryObj<StoryProps> = {
82
82
  const canvas = within(canvasElement);
83
83
 
84
84
  await waitFor(async () => {
85
- await expect(canvas.getByText("Error: Invalid LAPIS URL: 'notAValidUrl'", { exact: false })).toBeVisible();
85
+ await expect(
86
+ canvas.getByText("Error in gs-app: Invalid LAPIS URL: 'notAValidUrl'", { exact: false }),
87
+ ).toBeVisible();
86
88
  });
87
89
  },
88
90
  };
@@ -119,7 +121,9 @@ export const FailsToFetchReferenceGenome: StoryObj<StoryProps> = {
119
121
  const canvas = within(canvasElement);
120
122
 
121
123
  await waitFor(async () => {
122
- await expect(canvas.getByText('Error: Cannot fetch reference genome.', { exact: false })).toBeVisible();
124
+ await expect(
125
+ canvas.getByText('Error in gs-app: Cannot fetch reference genome.', { exact: false }),
126
+ ).toBeVisible();
123
127
  });
124
128
  },
125
129
  };
@@ -98,7 +98,10 @@ export class AppComponent extends LitElement {
98
98
  }
99
99
 
100
100
  function GsAppError(error: string) {
101
- return html` <div class="m-2 w-full alert alert-error">Error: ${error}</div>`;
101
+ // We're in the light dom, we must not use Tailwind so that we don't pollute the user's styles.
102
+ return html`<div style="padding: 0.5rem; border: solid red; background-color: lightcoral; border-radius: 0.5rem;">
103
+ Error in gs-app: ${error}
104
+ </div>`;
102
105
  }
103
106
 
104
107
  declare global {
@@ -1,3 +1,5 @@
1
+ import flatpickrStyle from 'flatpickr/dist/flatpickr.css?inline';
2
+ import { unsafeCSS } from 'lit';
1
3
  import { customElement, property } from 'lit/decorators.js';
2
4
  import type { DetailedHTMLProps, HTMLAttributes } from 'react';
3
5
 
@@ -6,6 +8,8 @@ import { type DateRangeOptionChangedEvent } from '../../preact/dateRangeFilter/d
6
8
  import { type Equals, type Expect } from '../../utils/typeAssertions';
7
9
  import { PreactLitAdapter } from '../PreactLitAdapter';
8
10
 
11
+ const flatpickrCss = unsafeCSS(flatpickrStyle);
12
+
9
13
  /**
10
14
  * ## Context
11
15
  * This component is a group of input fields designed to specify date range filters
@@ -52,6 +56,8 @@ import { PreactLitAdapter } from '../PreactLitAdapter';
52
56
  */
53
57
  @customElement('gs-date-range-filter')
54
58
  export class DateRangeFilterComponent extends PreactLitAdapter {
59
+ static override styles = [...PreactLitAdapter.styles, flatpickrCss];
60
+
55
61
  /**
56
62
  * An array of date range options that the select field should provide.
57
63
  * The `label` will be shown to the user, and it will be available as `value`.