@genspectrum/dashboard-components 0.1.3 → 0.1.4

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 (75) hide show
  1. package/custom-elements.json +311 -75
  2. package/dist/dashboard-components.js +622 -434
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/genspectrum-components.d.ts +229 -42
  5. package/dist/style.css +132 -139
  6. package/package.json +9 -5
  7. package/src/preact/aggregatedData/aggregate.stories.tsx +5 -5
  8. package/src/preact/aggregatedData/aggregate.tsx +8 -4
  9. package/src/preact/components/ReferenceGenomesAwaiter.tsx +25 -0
  10. package/src/preact/components/csv-download-button.tsx +8 -2
  11. package/src/preact/components/headline.tsx +16 -4
  12. package/src/preact/components/min-max-range-slider.tsx +4 -4
  13. package/src/preact/components/percent-intput.tsx +2 -3
  14. package/src/preact/components/resize-container.tsx +23 -0
  15. package/src/preact/components/table.tsx +1 -0
  16. package/src/preact/components/tabs.stories.tsx +2 -2
  17. package/src/preact/components/tabs.tsx +47 -24
  18. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +36 -4
  19. package/src/preact/dateRangeSelector/date-range-selector.tsx +57 -43
  20. package/src/preact/locationFilter/location-filter.tsx +2 -2
  21. package/src/preact/mutationComparison/getMutationComparisonTableData.spec.ts +5 -5
  22. package/src/preact/mutationComparison/getMutationComparisonTableData.ts +45 -10
  23. package/src/preact/mutationComparison/mutation-comparison-table.tsx +20 -22
  24. package/src/preact/mutationComparison/mutation-comparison-venn.tsx +6 -3
  25. package/src/preact/mutationComparison/mutation-comparison.stories.tsx +8 -1
  26. package/src/preact/mutationComparison/mutation-comparison.tsx +13 -4
  27. package/src/preact/mutationFilter/mutation-filter.stories.tsx +70 -31
  28. package/src/preact/mutationFilter/mutation-filter.tsx +62 -14
  29. package/src/preact/mutations/getInsertionsTableData.spec.ts +6 -4
  30. package/src/preact/mutations/getInsertionsTableData.ts +1 -1
  31. package/src/preact/mutations/getMutationsTableData.spec.ts +9 -19
  32. package/src/preact/mutations/getMutationsTableData.ts +1 -1
  33. package/src/preact/mutations/mutations-insertions-table.tsx +3 -1
  34. package/src/preact/mutations/mutations-table.tsx +3 -1
  35. package/src/preact/mutations/mutations.stories.tsx +8 -1
  36. package/src/preact/mutations/mutations.tsx +16 -5
  37. package/src/preact/prevalenceOverTime/prevalence-over-time-bar-chart.tsx +1 -0
  38. package/src/preact/prevalenceOverTime/prevalence-over-time-bubble-chart.tsx +1 -0
  39. package/src/preact/prevalenceOverTime/prevalence-over-time-line-chart.tsx +1 -0
  40. package/src/preact/prevalenceOverTime/prevalence-over-time.stories.tsx +4 -0
  41. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +17 -9
  42. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage-chart.tsx +8 -5
  43. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.stories.tsx +12 -0
  44. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +13 -8
  45. package/src/preact/shared/sort/sortInsertions.spec.ts +11 -10
  46. package/src/preact/shared/sort/sortInsertions.ts +10 -17
  47. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.spec.ts +19 -10
  48. package/src/preact/shared/sort/sortSubstitutionsAndDeletions.ts +45 -12
  49. package/src/preact/textInput/text-input.stories.tsx +22 -1
  50. package/src/preact/textInput/text-input.tsx +3 -1
  51. package/src/utils/typeAssertions.spec.ts +31 -0
  52. package/src/utils/typeAssertions.ts +16 -0
  53. package/src/web-components/PreactLitAdapter.tsx +0 -1
  54. package/src/web-components/app.stories.ts +129 -0
  55. package/src/web-components/app.ts +27 -6
  56. package/src/web-components/display/aggregate-component.stories.ts +21 -11
  57. package/src/web-components/display/aggregate-component.tsx +12 -5
  58. package/src/web-components/display/mutation-comparison-component.stories.ts +29 -11
  59. package/src/web-components/display/mutation-comparison-component.tsx +72 -4
  60. package/src/web-components/display/mutations-component.stories.ts +14 -13
  61. package/src/web-components/display/mutations-component.tsx +14 -1
  62. package/src/web-components/display/prevalence-over-time-component.stories.ts +20 -18
  63. package/src/web-components/display/prevalence-over-time-component.tsx +12 -0
  64. package/src/web-components/display/relative-growth-advantage-component.stories.ts +11 -10
  65. package/src/web-components/display/relative-growth-advantage-component.tsx +12 -0
  66. package/src/web-components/input/date-range-selector-component.stories.ts +35 -8
  67. package/src/web-components/input/date-range-selector-component.tsx +18 -5
  68. package/src/web-components/input/location-filter-component.stories.ts +15 -4
  69. package/src/web-components/input/location-filter-component.tsx +2 -6
  70. package/src/web-components/input/mutation-filter-component.stories.ts +20 -9
  71. package/src/web-components/input/mutation-filter-component.tsx +10 -2
  72. package/src/web-components/input/text-input-component.stories.ts +13 -4
  73. package/src/web-components/input/text-input-component.tsx +11 -2
  74. package/src/web-components/display/aggregate-component.mdx +0 -25
  75. package/src/web-components/input/location-filter.mdx +0 -25
@@ -8,18 +8,43 @@ import { referenceGenomeContext } from './reference-genome-context';
8
8
  import { type ReferenceGenome } from '../lapisApi/ReferenceGenome';
9
9
  import { fetchReferenceGenome } from '../lapisApi/lapisApi';
10
10
 
11
+ /**
12
+ * ## Context
13
+ *
14
+ * This component provides the main application context.
15
+ * All other `gs-*` components must be (possibly nested) children of this component.
16
+ * It makes use of the [Lit Context](https://lit.dev/docs/data/context/) to
17
+ * - provide the URL to the LAPIS instance to all its children
18
+ * - fetch the reference genomes from LAPIS and provide it to all its children
19
+ *
20
+ * This will show an error message if the reference genome cannot be fetched
21
+ * (e.g., due to an invalid LAPIS URL).
22
+ *
23
+ * ## Shadow DOM
24
+ *
25
+ * This component does __not__ use a shadow DOM. Children of this component will be rendered directly in the light DOM.
26
+ */
11
27
  @customElement('gs-app')
12
28
  export class App extends LitElement {
29
+ /**
30
+ * The URL of the LAPIS instance that all children of this component will use.
31
+ */
13
32
  @provide({ context: lapisContext })
14
33
  @property()
15
34
  lapis: string = '';
16
35
 
36
+ /**
37
+ * @internal
38
+ */
17
39
  @provide({ context: referenceGenomeContext })
18
40
  referenceGenome: ReferenceGenome = {
19
41
  nucleotideSequences: [],
20
42
  genes: [],
21
43
  };
22
44
 
45
+ /**
46
+ * @internal
47
+ */
23
48
  private updateReferenceGenome = new Task(this, {
24
49
  task: async () => {
25
50
  this.referenceGenome = await fetchReferenceGenome(this.lapis);
@@ -29,13 +54,9 @@ export class App extends LitElement {
29
54
 
30
55
  override render() {
31
56
  return this.updateReferenceGenome.render({
32
- complete: () => {
33
- return html` <slot></slot>`;
34
- },
57
+ complete: () => html` <slot></slot>`,
35
58
  error: () => html`<p>Error</p>`, // TODO(#143): Add more advanced error handling
36
- pending: () => {
37
- return html`<p>Loading...</p>`;
38
- },
59
+ pending: () => html` <p>Loading reference genomes...</p> `,
39
60
  });
40
61
  }
41
62
 
@@ -1,9 +1,11 @@
1
1
  import { type Meta, type StoryObj } from '@storybook/web-components';
2
2
  import { html } from 'lit';
3
3
 
4
+ import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
4
5
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
5
6
  import aggregatedData from '../../preact/aggregatedData/__mockData__/aggregated.json';
6
7
  import type { AggregateProps } from '../../preact/aggregatedData/aggregate';
8
+
7
9
  import './aggregate-component';
8
10
  import '../app';
9
11
 
@@ -16,8 +18,9 @@ const meta: Meta<AggregateProps> = {
16
18
  options: ['table'],
17
19
  control: { type: 'check' },
18
20
  },
21
+ size: [{ control: 'object' }],
19
22
  },
20
- parameters: {
23
+ parameters: withComponentDocs({
21
24
  fetchMock: {
22
25
  mocks: [
23
26
  {
@@ -36,22 +39,28 @@ const meta: Meta<AggregateProps> = {
36
39
  },
37
40
  ],
38
41
  },
39
- },
42
+ componentDocs: {
43
+ tag: 'gs-aggregate-component',
44
+ opensShadowDom: true,
45
+ expectsChildren: false,
46
+ codeExample: `<gs-aggregate-component fields='["division", "host"]' filter='{"country": "USA"}' views='["table"]'></gs-aggregate-component>`,
47
+ },
48
+ }),
49
+ tags: ['autodocs'],
40
50
  };
41
51
 
42
52
  export default meta;
43
53
 
44
54
  export const Table: StoryObj<AggregateProps> = {
45
55
  render: (args) => html`
46
- <div class="w-11/12 h-11/12">
47
- <gs-app lapis="${LAPIS_URL}">
48
- <gs-aggregate-component
49
- .fields=${args.fields}
50
- .filter=${args.filter}
51
- .views=${args.views}
52
- ></gs-aggregate-component>
53
- </gs-app>
54
- </div>
56
+ <gs-app lapis="${LAPIS_URL}">
57
+ <gs-aggregate-component
58
+ .fields=${args.fields}
59
+ .filter=${args.filter}
60
+ .views=${args.views}
61
+ .size=${args.size}
62
+ ></gs-aggregate-component>
63
+ </gs-app>
55
64
  `,
56
65
  args: {
57
66
  fields: ['division', 'host'],
@@ -59,5 +68,6 @@ export const Table: StoryObj<AggregateProps> = {
59
68
  filter: {
60
69
  country: 'USA',
61
70
  },
71
+ size: { width: '100%', height: '700px' },
62
72
  },
63
73
  };
@@ -5,10 +5,6 @@ import { type LapisFilter } from '../../types';
5
5
  import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
6
6
 
7
7
  /**
8
- * ## Tag
9
- *
10
- * `gs-aggregate-component`
11
- *
12
8
  * ## Context
13
9
  *
14
10
  * This component displays aggregated data, which can provide an overview of the underlying data.
@@ -39,8 +35,19 @@ export class AggregateComponent extends PreactLitAdapterWithGridJsStyles {
39
35
  @property({ type: Object })
40
36
  filter: LapisFilter = {};
41
37
 
38
+ /**
39
+ * The size of the component.
40
+ *
41
+ * If not set, the component will take the full width of its container with height 700px.
42
+ *
43
+ * The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
44
+ * If the unit is %, the size will be relative to the container of the component.
45
+ */
46
+ @property({ type: Object })
47
+ size: { width?: string; height?: string } | undefined = undefined;
48
+
42
49
  override render() {
43
- return <Aggregate fields={this.fields} views={this.views} filter={this.filter} />;
50
+ return <Aggregate fields={this.fields} views={this.views} filter={this.filter} size={this.size} />;
44
51
  }
45
52
  }
46
53
 
@@ -4,12 +4,20 @@ import { html } from 'lit';
4
4
 
5
5
  import './mutation-comparison-component';
6
6
  import '../app';
7
+ import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
7
8
  import { LAPIS_URL, NUCLEOTIDE_MUTATIONS_ENDPOINT } from '../../constants';
8
9
  import nucleotideMutationsOtherVariant from '../../preact/mutationComparison/__mockData__/nucleotideMutationsOtherVariant.json';
9
10
  import nucleotideMutationsSomeVariant from '../../preact/mutationComparison/__mockData__/nucleotideMutationsSomeVariant.json';
10
11
  import { type MutationComparisonProps } from '../../preact/mutationComparison/mutation-comparison';
11
12
  import { withinShadowRoot } from '../withinShadowRoot.story';
12
13
 
14
+ const codeExample = String.raw`
15
+ <gs-mutation-comparison-component
16
+ variants='[{ "displayName": "variant1", "lapisFilter": { "country": "Switzerland" }}, { "displayName": "variant2", "lapisFilter": { "country": "Germany" }}]'
17
+ sequenceType="nucleotide"
18
+ views='["table", "venn"]'
19
+ ></gs-mutation-comparison-component>`;
20
+
13
21
  const meta: Meta<MutationComparisonProps> = {
14
22
  title: 'Visualization/Mutation comparison',
15
23
  component: 'gs-mutation-comparison-component',
@@ -23,22 +31,31 @@ const meta: Meta<MutationComparisonProps> = {
23
31
  options: ['table', 'venn'],
24
32
  control: { type: 'check' },
25
33
  },
34
+ size: { control: 'object' },
26
35
  },
36
+ parameters: withComponentDocs({
37
+ componentDocs: {
38
+ tag: 'gs-mutation-comparison-component',
39
+ opensShadowDom: true,
40
+ expectsChildren: false,
41
+ codeExample,
42
+ },
43
+ }),
44
+ tags: ['autodocs'],
27
45
  };
28
46
 
29
47
  export default meta;
30
48
 
31
49
  const Template: StoryObj<MutationComparisonProps> = {
32
50
  render: (args) => html`
33
- <div class="w-11/12 h-11/12">
34
- <gs-app lapis="${LAPIS_URL}">
35
- <gs-mutation-comparison-component
36
- .variants=${args.variants}
37
- .sequenceType=${args.sequenceType}
38
- .views=${args.views}
39
- ></gs-mutation-comparison-component>
40
- </gs-app>
41
- </div>
51
+ <gs-app lapis="${LAPIS_URL}">
52
+ <gs-mutation-comparison-component
53
+ .variants=${args.variants}
54
+ .sequenceType=${args.sequenceType}
55
+ .views=${args.views}
56
+ .size=${args.size}
57
+ ></gs-mutation-comparison-component>
58
+ </gs-app>
42
59
  `,
43
60
  };
44
61
 
@@ -65,6 +82,7 @@ export const Default: StoryObj<MutationComparisonProps> = {
65
82
  ],
66
83
  sequenceType: 'nucleotide',
67
84
  views: ['table', 'venn'],
85
+ size: { width: '100%', height: '700px' },
68
86
  },
69
87
  parameters: {
70
88
  fetchMock: {
@@ -124,9 +142,9 @@ export const VennDiagram: StoryObj<MutationComparisonProps> = {
124
142
  const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-comparison-component');
125
143
 
126
144
  await step('Switch to Venn diagram view', async () => {
127
- await waitFor(() => expect(canvas.getByLabelText('Venn', { selector: 'input' })).toBeInTheDocument());
145
+ await waitFor(() => expect(canvas.getByRole('button', { name: 'Venn' })).toBeInTheDocument());
128
146
 
129
- await fireEvent.click(canvas.getByLabelText('Venn', { selector: 'input' }));
147
+ await fireEvent.click(canvas.getByRole('button', { name: 'Venn' }));
130
148
 
131
149
  await waitFor(() =>
132
150
  expect(
@@ -6,21 +6,81 @@ import {
6
6
  type View,
7
7
  } from '../../preact/mutationComparison/mutation-comparison';
8
8
  import { type SequenceType } from '../../types';
9
+ import { type Equals, type Expect } from '../../utils/typeAssertions';
9
10
  import { PreactLitAdapterWithGridJsStyles } from '../PreactLitAdapterWithGridJsStyles';
10
11
 
12
+ /**
13
+ * This component allows to compare mutations between different variants.
14
+ * A variant is defined by its LAPIS filter.
15
+ *
16
+ * It only shows substitutions and deletions, it does not show insertions.
17
+ *
18
+ * ## Views
19
+ *
20
+ * ### Table View
21
+ *
22
+ * The table view shows mutations
23
+ * and the proportions with which the mutation occurs in the respective variant.
24
+ * It only shows mutations that are present in at least one of the variants
25
+ * and where the proportion is within the selected proportion interval for at least one variant.
26
+ *
27
+ * ### Venn View
28
+ *
29
+ * The Venn view shows the overlap of mutations between the variants in a Venn diagram.
30
+ * A variant is considered to have a certain mutation,
31
+ * if the proportion of the mutation in the variant is within the selected proportion interval.
32
+ * Thus, changing the proportion interval may change a mutations from being "common" between variant
33
+ * to being "for one variant only".
34
+ */
11
35
  @customElement('gs-mutation-comparison-component')
12
36
  export class MutationComparisonComponent extends PreactLitAdapterWithGridJsStyles {
37
+ /**
38
+ * An array of variants to compare.
39
+ *
40
+ * The `lapisFilter` will be sent as is to LAPIS to filter the mutation data.
41
+ * It must be a valid LAPIS filter object.
42
+ *
43
+ * The `displayName` will be used as the label for the variant in the views.
44
+ * It should be human-readable.
45
+ */
13
46
  @property({ type: Array })
14
- variants: MutationComparisonVariant[] = [];
47
+ variants: {
48
+ lapisFilter: Record<string, string | number | null | boolean>;
49
+ displayName: string;
50
+ }[] = [];
15
51
 
52
+ /**
53
+ * The type of the sequence for which the mutations should be shown.
54
+ */
16
55
  @property({ type: String })
17
- sequenceType: SequenceType = 'nucleotide';
56
+ sequenceType: 'nucleotide' | 'amino acid' = 'nucleotide';
18
57
 
58
+ /**
59
+ * A list of tabs with views that this component should provide.
60
+ */
19
61
  @property({ type: Array })
20
- views: View[] = ['table'];
62
+ views: ('table' | 'venn')[] = ['table'];
63
+
64
+ /**
65
+ * The size of the component.
66
+ *
67
+ * If not set, the component will take the full width of its container with height 700px.
68
+ *
69
+ * The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
70
+ * If the unit is %, the size will be relative to the container of the component.
71
+ */
72
+ @property({ type: Object })
73
+ size: { width?: string; height?: string } | undefined = undefined;
21
74
 
22
75
  override render() {
23
- return <MutationComparison variants={this.variants} sequenceType={this.sequenceType} views={this.views} />;
76
+ return (
77
+ <MutationComparison
78
+ variants={this.variants}
79
+ sequenceType={this.sequenceType}
80
+ views={this.views}
81
+ size={this.size}
82
+ />
83
+ );
24
84
  }
25
85
  }
26
86
 
@@ -29,3 +89,11 @@ declare global {
29
89
  'gs-mutation-comparison-component': MutationComparisonComponent;
30
90
  }
31
91
  }
92
+
93
+ /* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
94
+ type VariantsMatches = Expect<
95
+ Equals<typeof MutationComparisonComponent.prototype.variants, MutationComparisonVariant[]>
96
+ >;
97
+ type SequenceTypeMatches = Expect<Equals<typeof MutationComparisonComponent.prototype.sequenceType, SequenceType>>;
98
+ type ViewsMatches = Expect<Equals<typeof MutationComparisonComponent.prototype.views, View[]>>;
99
+ /* eslint-enable @typescript-eslint/no-unused-vars, no-unused-vars */
@@ -23,6 +23,7 @@ const meta: Meta<MutationsProps> = {
23
23
  options: ['table', 'grid', 'insertions'],
24
24
  control: { type: 'check' },
25
25
  },
26
+ size: { control: 'object' },
26
27
  },
27
28
  };
28
29
 
@@ -30,15 +31,14 @@ export default meta;
30
31
 
31
32
  const Template: StoryObj<MutationsProps> = {
32
33
  render: (args) => html`
33
- <div class="w-11/12 h-11/12">
34
- <gs-app lapis="${LAPIS_URL}">
35
- <gs-mutations-component
36
- .variant=${args.variant}
37
- .sequenceType=${args.sequenceType}
38
- .views=${args.views}
39
- ></gs-mutations-component>
40
- </gs-app>
41
- </div>
34
+ <gs-app lapis="${LAPIS_URL}">
35
+ <gs-mutations-component
36
+ .variant=${args.variant}
37
+ .sequenceType=${args.sequenceType}
38
+ .views=${args.views}
39
+ .size=${args.size}
40
+ ></gs-mutations-component>
41
+ </gs-app>
42
42
  `,
43
43
  };
44
44
 
@@ -48,6 +48,7 @@ export const Default: StoryObj<MutationsProps> = {
48
48
  variant: { country: 'Switzerland', pangoLineage: 'B.1.1.7', dateTo: '2022-01-01' },
49
49
  sequenceType: 'nucleotide',
50
50
  views: ['grid', 'table', 'insertions'],
51
+ size: { width: '100%', height: '700px' },
51
52
  },
52
53
  parameters: {
53
54
  fetchMock: {
@@ -89,9 +90,9 @@ export const OnTableTab: StoryObj<MutationsProps> = {
89
90
  play: async ({ canvasElement }) => {
90
91
  const canvas = await withinShadowRoot(canvasElement, 'gs-mutations-component');
91
92
 
92
- await waitFor(() => expect(canvas.getByLabelText('Table', { selector: 'input' })).toBeInTheDocument());
93
+ await waitFor(() => expect(canvas.getByRole('button', { name: 'Table' })).toBeInTheDocument());
93
94
 
94
- await fireEvent.click(canvas.getByLabelText('Table', { selector: 'input' }));
95
+ await fireEvent.click(canvas.getByRole('button', { name: 'Table' }));
95
96
  },
96
97
  };
97
98
 
@@ -100,8 +101,8 @@ export const OnInsertionsTab: StoryObj<MutationsProps> = {
100
101
  play: async ({ canvasElement }) => {
101
102
  const canvas = await withinShadowRoot(canvasElement, 'gs-mutations-component');
102
103
 
103
- await waitFor(() => expect(canvas.getByLabelText('Insertions', { selector: 'input' })).toBeInTheDocument());
104
+ await waitFor(() => expect(canvas.getByRole('button', { name: 'Insertions' })).toBeInTheDocument());
104
105
 
105
- await fireEvent.click(canvas.getByLabelText('Insertions', { selector: 'input' }));
106
+ await fireEvent.click(canvas.getByRole('button', { name: 'Insertions' }));
106
107
  },
107
108
  };
@@ -15,8 +15,21 @@ export class MutationsComponent extends PreactLitAdapterWithGridJsStyles {
15
15
  @property({ type: Array })
16
16
  views: View[] = ['table', 'grid'];
17
17
 
18
+ /**
19
+ * The size of the component.
20
+ *
21
+ * If not set, the component will take the full width of its container with height 700px.
22
+ *
23
+ * The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
24
+ * If the unit is %, the size will be relative to the container of the component.
25
+ */
26
+ @property({ type: Object })
27
+ size: { width?: string; height?: string } | undefined = undefined;
28
+
18
29
  override render() {
19
- return <Mutations variant={this.variant} sequenceType={this.sequenceType} views={this.views} />;
30
+ return (
31
+ <Mutations variant={this.variant} sequenceType={this.sequenceType} views={this.views} size={this.size} />
32
+ );
20
33
  }
21
34
  }
22
35
 
@@ -32,6 +32,7 @@ const meta: Meta<PrevalenceOverTimeProps> = {
32
32
  options: ['wilson'],
33
33
  control: { type: 'check' },
34
34
  },
35
+ size: [{ control: 'object' }],
35
36
  },
36
37
  };
37
38
 
@@ -39,18 +40,17 @@ export default meta;
39
40
 
40
41
  const Template: StoryObj<PrevalenceOverTimeProps> = {
41
42
  render: (args) => html`
42
- <div class="w-11/12 h-11/12">
43
- <gs-app lapis="${LAPIS_URL}">
44
- <gs-prevalence-over-time
45
- .numerator=${args.numerator}
46
- .denominator=${args.denominator}
47
- .granularity=${args.granularity}
48
- .smoothingWindow=${args.smoothingWindow}
49
- .views=${args.views}
50
- .confidenceIntervalMethods=${args.confidenceIntervalMethods}
51
- ></gs-prevalence-over-time>
52
- </gs-app>
53
- </div>
43
+ <gs-app lapis="${LAPIS_URL}">
44
+ <gs-prevalence-over-time
45
+ .numerator=${args.numerator}
46
+ .denominator=${args.denominator}
47
+ .granularity=${args.granularity}
48
+ .smoothingWindow=${args.smoothingWindow}
49
+ .views=${args.views}
50
+ .confidenceIntervalMethods=${args.confidenceIntervalMethods}
51
+ .size=${args.size}
52
+ ></gs-prevalence-over-time>
53
+ </gs-app>
54
54
  `,
55
55
  };
56
56
 
@@ -66,6 +66,7 @@ export const TwoVariants: StoryObj<PrevalenceOverTimeProps> = {
66
66
  smoothingWindow: 0,
67
67
  views: ['bar', 'line', 'bubble', 'table'],
68
68
  confidenceIntervalMethods: ['wilson'],
69
+ size: { width: '100%', height: '700px' },
69
70
  },
70
71
  parameters: {
71
72
  fetchMock: {
@@ -131,6 +132,7 @@ export const OneVariant: StoryObj<PrevalenceOverTimeProps> = {
131
132
  smoothingWindow: 7,
132
133
  views: ['bar', 'line', 'bubble', 'table'],
133
134
  confidenceIntervalMethods: ['wilson'],
135
+ size: { width: '100%', height: '700px' },
134
136
  },
135
137
  parameters: {
136
138
  fetchMock: {
@@ -176,9 +178,9 @@ export const OneVariantOnLineTab: StoryObj<PrevalenceOverTimeProps> = {
176
178
  play: async ({ canvasElement }) => {
177
179
  const canvas = await withinShadowRoot(canvasElement, 'gs-prevalence-over-time');
178
180
 
179
- await waitFor(() => expect(canvas.getByLabelText('Line', { selector: 'input' })).toBeInTheDocument());
181
+ await waitFor(() => expect(canvas.getByRole('button', { name: 'Line' })).toBeInTheDocument());
180
182
 
181
- await fireEvent.click(canvas.getByLabelText('Line', { selector: 'input' }));
183
+ await fireEvent.click(canvas.getByRole('button', { name: 'Line' }));
182
184
  },
183
185
  };
184
186
 
@@ -187,9 +189,9 @@ export const OneVariantOnBubbleTab: StoryObj<PrevalenceOverTimeProps> = {
187
189
  play: async ({ canvasElement }) => {
188
190
  const canvas = await withinShadowRoot(canvasElement, 'gs-prevalence-over-time');
189
191
 
190
- await waitFor(() => expect(canvas.getByLabelText('Bubble', { selector: 'input' })).toBeInTheDocument());
192
+ await waitFor(() => expect(canvas.getByRole('button', { name: 'Bubble' })).toBeInTheDocument());
191
193
 
192
- await fireEvent.click(canvas.getByLabelText('Bubble', { selector: 'input' }));
194
+ await fireEvent.click(canvas.getByRole('button', { name: 'Bubble' }));
193
195
  },
194
196
  };
195
197
 
@@ -198,8 +200,8 @@ export const OneVariantOnTableTab: StoryObj<PrevalenceOverTimeProps> = {
198
200
  play: async ({ canvasElement }) => {
199
201
  const canvas = await withinShadowRoot(canvasElement, 'gs-prevalence-over-time');
200
202
 
201
- await waitFor(() => expect(canvas.getByLabelText('Table', { selector: 'input' })).toBeInTheDocument());
203
+ await waitFor(() => expect(canvas.getByRole('button', { name: 'Table' })).toBeInTheDocument());
202
204
 
203
- await fireEvent.click(canvas.getByLabelText('Table', { selector: 'input' }));
205
+ await fireEvent.click(canvas.getByRole('button', { name: 'Table' }));
204
206
  },
205
207
  };
@@ -25,6 +25,17 @@ export class PrevalenceOverTimeComponent extends PreactLitAdapterWithGridJsStyle
25
25
  @property({ type: Array })
26
26
  confidenceIntervalMethods: ConfidenceIntervalMethod[] = ['wilson'];
27
27
 
28
+ /**
29
+ * The size of the component.
30
+ *
31
+ * If not set, the component will take the full width of its container with height 700px.
32
+ *
33
+ * The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
34
+ * If the unit is %, the size will be relative to the container of the component.
35
+ */
36
+ @property({ type: Object })
37
+ size: { width?: string; height?: string } | undefined = undefined;
38
+
28
39
  override render() {
29
40
  return (
30
41
  <PrevalenceOverTime
@@ -34,6 +45,7 @@ export class PrevalenceOverTimeComponent extends PreactLitAdapterWithGridJsStyle
34
45
  smoothingWindow={this.smoothingWindow}
35
46
  views={this.views}
36
47
  confidenceIntervalMethods={this.confidenceIntervalMethods}
48
+ size={this.size}
37
49
  />
38
50
  );
39
51
  }
@@ -19,6 +19,7 @@ const meta: Meta<RelativeGrowthAdvantageProps> = {
19
19
  options: ['line'],
20
20
  control: { type: 'check' },
21
21
  },
22
+ size: [{ control: 'object' }],
22
23
  },
23
24
  };
24
25
 
@@ -26,16 +27,15 @@ export default meta;
26
27
 
27
28
  const Template: StoryObj<RelativeGrowthAdvantageProps> = {
28
29
  render: (args) => html`
29
- <div class="w-11/12 h-11/12">
30
- <gs-app lapis="${LAPIS_URL}">
31
- <gs-relative-growth-advantage
32
- .numerator=${args.numerator}
33
- .denominator=${args.denominator}
34
- .generationTime=${args.generationTime}
35
- .views=${args.views}
36
- ></gs-relative-growth-advantage>
37
- </gs-app>
38
- </div>
30
+ <gs-app lapis="${LAPIS_URL}">
31
+ <gs-relative-growth-advantage
32
+ .numerator=${args.numerator}
33
+ .denominator=${args.denominator}
34
+ .generationTime=${args.generationTime}
35
+ .views=${args.views}
36
+ .size=${args.size}
37
+ ></gs-relative-growth-advantage>
38
+ </gs-app>
39
39
  `,
40
40
  };
41
41
 
@@ -46,6 +46,7 @@ export const Default: StoryObj<RelativeGrowthAdvantageProps> = {
46
46
  denominator: { country: 'Switzerland', dateFrom: '2020-12-01', dateTo: '2021-03-01' },
47
47
  generationTime: 7,
48
48
  views: ['line'],
49
+ size: { width: '100%', height: '700px' },
49
50
  },
50
51
  parameters: {
51
52
  fetchMock: {
@@ -18,6 +18,17 @@ export class RelativeGrowthAdvantageComponent extends PreactLitAdapter {
18
18
  @property({ type: Array })
19
19
  views: View[] = ['line'];
20
20
 
21
+ /**
22
+ * The size of the component.
23
+ *
24
+ * If not set, the component will take the full width of its container with height 700px.
25
+ *
26
+ * The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
27
+ * If the unit is %, the size will be relative to the container of the component.
28
+ */
29
+ @property({ type: Object })
30
+ size: { width?: string; height?: string } | undefined = undefined;
31
+
21
32
  override render() {
22
33
  return (
23
34
  <RelativeGrowthAdvantage
@@ -25,6 +36,7 @@ export class RelativeGrowthAdvantageComponent extends PreactLitAdapter {
25
36
  denominator={this.denominator}
26
37
  generationTime={this.generationTime}
27
38
  views={this.views}
39
+ size={this.size}
28
40
  />
29
41
  );
30
42
  }