@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
@@ -4,13 +4,22 @@ import type { Meta, StoryObj } from '@storybook/web-components';
4
4
  import { html } from 'lit';
5
5
 
6
6
  import { LAPIS_URL } from '../../constants';
7
- import { type DateRangeSelectorProps } from '../../preact/dateRangeSelector/date-range-selector';
7
+ import {
8
+ type DateRangeSelectorProps,
9
+ PRESET_VALUE_ALL_TIMES,
10
+ PRESET_VALUE_CUSTOM,
11
+ PRESET_VALUE_LAST_2_MONTHS,
12
+ PRESET_VALUE_LAST_2_WEEKS,
13
+ PRESET_VALUE_LAST_3_MONTHS,
14
+ PRESET_VALUE_LAST_6_MONTHS,
15
+ PRESET_VALUE_LAST_MONTH,
16
+ } from '../../preact/dateRangeSelector/date-range-selector';
8
17
  import './date-range-selector-component';
9
18
  import '../app';
10
19
  import { toYYYYMMDD } from '../../preact/dateRangeSelector/dateConversion';
11
20
  import { withinShadowRoot } from '../withinShadowRoot.story';
12
21
 
13
- const meta: Meta<DateRangeSelectorProps> = {
22
+ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
14
23
  title: 'Input/DateRangeSelector',
15
24
  component: 'gs-date-range-selector',
16
25
  parameters: {
@@ -19,22 +28,44 @@ const meta: Meta<DateRangeSelectorProps> = {
19
28
  },
20
29
  fetchMock: {},
21
30
  },
31
+ argTypes: {
32
+ initialValue: {
33
+ control: {
34
+ type: 'select',
35
+ },
36
+ options: [
37
+ PRESET_VALUE_CUSTOM,
38
+ PRESET_VALUE_ALL_TIMES,
39
+ PRESET_VALUE_LAST_2_WEEKS,
40
+ PRESET_VALUE_LAST_MONTH,
41
+ PRESET_VALUE_LAST_2_MONTHS,
42
+ PRESET_VALUE_LAST_3_MONTHS,
43
+ PRESET_VALUE_LAST_6_MONTHS,
44
+ 'CustomDateRange',
45
+ ],
46
+ },
47
+ },
48
+ args: {
49
+ customSelectOptions: [{ label: 'CustomDateRange', dateFrom: '2021-01-01', dateTo: '2021-12-31' }],
50
+ earliestDate: '1970-01-01',
51
+ initialValue: PRESET_VALUE_LAST_6_MONTHS,
52
+ },
22
53
  decorators: [withActions],
23
54
  };
24
55
 
25
56
  export default meta;
26
57
 
27
- export const DateRangeSelectorStory: StoryObj<DateRangeSelectorProps> = {
58
+ export const DateRangeSelectorStory: StoryObj<DateRangeSelectorProps<'CustomDateRange'>> = {
28
59
  render: (args) =>
29
60
  html` <gs-app lapis="${LAPIS_URL}">
30
61
  <div class="max-w-screen-lg">
31
62
  <gs-date-range-selector
32
63
  .customSelectOptions=${args.customSelectOptions}
33
64
  .earliestDate=${args.earliestDate}
65
+ .initialValue=${args.initialValue}
34
66
  ></gs-date-range-selector>
35
67
  </div>
36
68
  </gs-app>`,
37
-
38
69
  play: async ({ canvasElement, step }) => {
39
70
  const canvas = await withinShadowRoot(canvasElement, 'gs-date-range-selector');
40
71
  const dateTo = () => canvas.getByPlaceholderText('Date to');
@@ -46,8 +77,4 @@ export const DateRangeSelectorStory: StoryObj<DateRangeSelectorProps> = {
46
77
  });
47
78
  });
48
79
  },
49
- args: {
50
- customSelectOptions: [{ label: 'CustomDateRange', dateFrom: '2021-01-01', dateTo: '2021-12-31' }],
51
- earliestDate: '1970-01-01',
52
- },
53
80
  };
@@ -1,27 +1,40 @@
1
1
  import { customElement, property } from 'lit/decorators.js';
2
2
 
3
- import { type CustomSelectOption, DateRangeSelector } from '../../preact/dateRangeSelector/date-range-selector';
3
+ import {
4
+ type CustomSelectOption,
5
+ DateRangeSelector,
6
+ type PresetOptionValues,
7
+ } from '../../preact/dateRangeSelector/date-range-selector';
4
8
  import { PreactLitAdapter } from '../PreactLitAdapter';
5
9
 
6
10
  /**
7
11
  * @fires {CustomEvent<{ dateFrom: string; dateTo: string; }>} gs-date-range-changed - When the date range has changed
8
12
  */
9
13
  @customElement('gs-date-range-selector')
10
- export class DateRangeSelectorComponent extends PreactLitAdapter {
14
+ export class DateRangeSelectorComponent<CustomLabel extends string> extends PreactLitAdapter {
11
15
  @property({ type: Array })
12
- customSelectOptions: CustomSelectOption[] = [];
16
+ customSelectOptions: CustomSelectOption<CustomLabel>[] = [];
13
17
 
14
18
  @property({ type: String })
15
19
  earliestDate: string | undefined = '1900-01-01';
16
20
 
21
+ @property()
22
+ initialValue: PresetOptionValues | CustomLabel | string | undefined = '';
23
+
17
24
  override render() {
18
- return <DateRangeSelector customSelectOptions={this.customSelectOptions} earliestDate={this.earliestDate} />;
25
+ return (
26
+ <DateRangeSelector
27
+ customSelectOptions={this.customSelectOptions}
28
+ earliestDate={this.earliestDate}
29
+ initialValue={this.initialValue}
30
+ />
31
+ );
19
32
  }
20
33
  }
21
34
 
22
35
  declare global {
23
36
  interface HTMLElementTagNameMap {
24
- 'gs-date-range-selector': DateRangeSelectorComponent;
37
+ 'gs-date-range-selector': DateRangeSelectorComponent<string>;
25
38
  }
26
39
 
27
40
  interface HTMLElementEventMap {
@@ -4,6 +4,7 @@ import type { Meta, StoryObj } from '@storybook/web-components';
4
4
  import { html } from 'lit';
5
5
  import { ifDefined } from 'lit/directives/if-defined.js';
6
6
 
7
+ import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
7
8
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
8
9
  import '../app';
9
10
  import './location-filter-component';
@@ -14,12 +15,19 @@ import { withinShadowRoot } from '../withinShadowRoot.story';
14
15
  const meta: Meta = {
15
16
  title: 'Input/Location filter',
16
17
  component: 'gs-location-filter',
17
- parameters: {
18
+ parameters: withComponentDocs({
18
19
  actions: {
19
20
  handles: ['gs-location-changed'],
20
21
  },
21
- },
22
+ componentDocs: {
23
+ tag: 'gs-location-filter',
24
+ opensShadowDom: true,
25
+ expectsChildren: false,
26
+ codeExample: `<gs-location-filter fields="['continent', 'country']" value='Europe / Switzerland'></gs-location-filter>`,
27
+ },
28
+ }),
22
29
  decorators: [withActions],
30
+ tags: ['autodocs'],
23
31
  };
24
32
 
25
33
  export default meta;
@@ -28,13 +36,16 @@ const Template: StoryObj<LocationFilterProps> = {
28
36
  render: (args) => {
29
37
  return html` <gs-app lapis="${LAPIS_URL}">
30
38
  <div class="max-w-screen-lg">
31
- <gs-location-filter .fields=${args.fields} value=${ifDefined(args.value)}></gs-location-filter>
39
+ <gs-location-filter
40
+ .fields=${args.fields}
41
+ initialValue=${ifDefined(args.initialValue)}
42
+ ></gs-location-filter>
32
43
  </div>
33
44
  </gs-app>`;
34
45
  },
35
46
  args: {
36
47
  fields: ['region', 'country', 'division', 'location'],
37
- value: '',
48
+ initialValue: '',
38
49
  },
39
50
  };
40
51
 
@@ -4,10 +4,6 @@ import { LocationFilter } from '../../preact/locationFilter/location-filter';
4
4
  import { PreactLitAdapter } from '../PreactLitAdapter';
5
5
 
6
6
  /**
7
- * ## Tag
8
- *
9
- * `gs-location-filter`
10
- *
11
7
  * ## Context
12
8
  *
13
9
  * This component provides an input field to specify filters for locations.
@@ -41,7 +37,7 @@ export class LocationFilterComponent extends PreactLitAdapter {
41
37
  * Must be of the form `valueForField1 / valueForField2 / ... / valueForFieldN`.
42
38
  */
43
39
  @property()
44
- value = '';
40
+ initialValue = '';
45
41
 
46
42
  /**
47
43
  * The fields to display in the location filter, in hierarchical order.
@@ -53,7 +49,7 @@ export class LocationFilterComponent extends PreactLitAdapter {
53
49
  fields: string[] = [];
54
50
 
55
51
  override render() {
56
- return <LocationFilter value={this.value} fields={this.fields} />;
52
+ return <LocationFilter initialValue={this.initialValue} fields={this.fields} />;
57
53
  }
58
54
  }
59
55
 
@@ -5,6 +5,7 @@ import { html } from 'lit';
5
5
 
6
6
  import { LAPIS_URL } from '../../constants';
7
7
  import '../app';
8
+ import { type MutationFilterProps } from '../../preact/mutationFilter/mutation-filter';
8
9
  import { withinShadowRoot } from '../withinShadowRoot.story';
9
10
  import './mutation-filter-component';
10
11
 
@@ -22,22 +23,32 @@ const meta: Meta = {
22
23
 
23
24
  export default meta;
24
25
 
25
- export const Default: StoryObj<{ lapisField: string; placeholderText: string }> = {
26
- render: () => {
26
+ const Template: StoryObj<MutationFilterProps> = {
27
+ render: (args) => {
27
28
  return html` <gs-app lapis="${LAPIS_URL}">
28
29
  <div class="max-w-screen-lg">
29
- <gs-mutation-filter></gs-mutation-filter>
30
+ <gs-mutation-filter .initialValue=${args.initialValue}></gs-mutation-filter>
30
31
  </div>
31
32
  </gs-app>`;
32
33
  },
34
+ args: {
35
+ initialValue: [],
36
+ },
37
+ };
38
+
39
+ export const Default: StoryObj<MutationFilterProps> = {
40
+ ...Template,
41
+ args: {
42
+ initialValue: ['A123T'],
43
+ },
33
44
  };
34
45
 
35
- export const FiresFilterChangedEvent: StoryObj<{ lapisField: string; placeholderText: string }> = {
36
- ...Default,
46
+ export const FiresFilterChangedEvent: StoryObj<MutationFilterProps> = {
47
+ ...Template,
37
48
  play: async ({ canvasElement, step }) => {
38
49
  const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-filter');
39
50
 
40
- const inputField = () => canvas.getByPlaceholderText('Enter a mutation');
51
+ const inputField = () => canvas.getByPlaceholderText('Enter a mutation', { exact: false });
41
52
  const submitButton = () => canvas.getByRole('button', { name: '+' });
42
53
  const listenerMock = fn();
43
54
  await step('Setup event listener mock', async () => {
@@ -70,12 +81,12 @@ export const FiresFilterChangedEvent: StoryObj<{ lapisField: string; placeholder
70
81
  },
71
82
  };
72
83
 
73
- export const FiresFilterOnBlurEvent: StoryObj<{ lapisField: string; placeholderText: string }> = {
74
- ...Default,
84
+ export const FiresFilterOnBlurEvent: StoryObj<MutationFilterProps> = {
85
+ ...Template,
75
86
  play: async ({ canvasElement, step }) => {
76
87
  const canvas = await withinShadowRoot(canvasElement, 'gs-mutation-filter');
77
88
 
78
- const inputField = () => canvas.getByPlaceholderText('Enter a mutation');
89
+ const inputField = () => canvas.getByPlaceholderText('Enter a mutation', { exact: false });
79
90
  const listenerMock = fn();
80
91
  await step('Setup event listener mock', async () => {
81
92
  canvasElement.addEventListener('gs-mutation-filter-on-blur', listenerMock);
@@ -1,6 +1,7 @@
1
- import { customElement } from 'lit/decorators.js';
1
+ import { customElement, property } from 'lit/decorators.js';
2
2
 
3
3
  import { type TextInputComponent } from './text-input-component';
4
+ import { ReferenceGenomesAwaiter } from '../../preact/components/ReferenceGenomesAwaiter';
4
5
  import { MutationFilter, type SelectedMutationFilterStrings } from '../../preact/mutationFilter/mutation-filter';
5
6
  import { PreactLitAdapter } from '../PreactLitAdapter';
6
7
 
@@ -10,8 +11,15 @@ import { PreactLitAdapter } from '../PreactLitAdapter';
10
11
  */
11
12
  @customElement('gs-mutation-filter')
12
13
  export class MutationFilterComponent extends PreactLitAdapter {
14
+ @property()
15
+ initialValue: SelectedMutationFilterStrings | string[] | undefined = undefined;
16
+
13
17
  override render() {
14
- return <MutationFilter />;
18
+ return (
19
+ <ReferenceGenomesAwaiter>
20
+ <MutationFilter initialValue={this.initialValue} />
21
+ </ReferenceGenomesAwaiter>
22
+ );
15
23
  }
16
24
  }
17
25
 
@@ -7,6 +7,7 @@ import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
7
7
  import '../app';
8
8
  import './text-input-component';
9
9
  import data from '../../preact/textInput/__mockData__/aggregated_hosts.json';
10
+ import type { TextInputProps } from '../../preact/textInput/text-input';
10
11
  import { withinShadowRoot } from '../withinShadowRoot.story';
11
12
 
12
13
  const meta: Meta = {
@@ -35,26 +36,30 @@ const meta: Meta = {
35
36
  },
36
37
  },
37
38
  decorators: [withActions],
38
- tags: ['autodocs'],
39
39
  };
40
40
 
41
41
  export default meta;
42
42
 
43
- export const Default: StoryObj<{ lapisField: string; placeholderText: string }> = {
43
+ export const Default: StoryObj<TextInputProps> = {
44
44
  render: (args) => {
45
45
  return html` <gs-app lapis="${LAPIS_URL}">
46
46
  <div class="max-w-screen-lg">
47
- <gs-text-input .lapisField=${args.lapisField} .placeholderText=${args.placeholderText}></gs-text-input>
47
+ <gs-text-input
48
+ .lapisField=${args.lapisField}
49
+ .placeholderText=${args.placeholderText}
50
+ .initialValue=${args.initialValue}
51
+ ></gs-text-input>
48
52
  </div>
49
53
  </gs-app>`;
50
54
  },
51
55
  args: {
52
56
  lapisField: 'host',
53
57
  placeholderText: 'Enter host name',
58
+ initialValue: 'Homo sapiens',
54
59
  },
55
60
  };
56
61
 
57
- export const FiresEvent: StoryObj<{ lapisField: string; placeholderText: string }> = {
62
+ export const FiresEvent: StoryObj<TextInputProps> = {
58
63
  ...Default,
59
64
  play: async ({ canvasElement, step }) => {
60
65
  const canvas = await withinShadowRoot(canvasElement, 'gs-text-input');
@@ -89,4 +94,8 @@ export const FiresEvent: StoryObj<{ lapisField: string; placeholderText: string
89
94
  );
90
95
  });
91
96
  },
97
+ args: {
98
+ ...Default.args,
99
+ initialValue: '',
100
+ },
92
101
  };
@@ -8,14 +8,23 @@ import { PreactLitAdapter } from '../PreactLitAdapter';
8
8
  */
9
9
  @customElement('gs-text-input')
10
10
  export class TextInputComponent extends PreactLitAdapter {
11
+ @property()
12
+ initialValue: string | undefined = '';
13
+
11
14
  @property()
12
15
  lapisField = '';
13
16
 
14
17
  @property()
15
- placeholderText = '';
18
+ placeholderText: string | undefined = '';
16
19
 
17
20
  override render() {
18
- return <TextInput lapisField={this.lapisField} placeholderText={this.placeholderText} />;
21
+ return (
22
+ <TextInput
23
+ lapisField={this.lapisField}
24
+ placeholderText={this.placeholderText}
25
+ initialValue={this.initialValue}
26
+ />
27
+ );
19
28
  }
20
29
  }
21
30
 
@@ -1,25 +0,0 @@
1
- import { ArgTypes, Description, Meta, Story, Title, Source } from '@storybook/blocks';
2
-
3
- import * as AggregateComponentStories from './aggregate-component.stories.ts';
4
-
5
- <Meta of={AggregateComponentStories} name='Docs' />
6
-
7
- <Title of={AggregateComponentStories} />
8
-
9
- <Description of={AggregateComponentStories} />
10
-
11
- ## Specification
12
-
13
- <ArgTypes of={AggregateComponentStories} />
14
-
15
- ## Example
16
-
17
- <Source
18
- code={`<gs-aggregate-component fields="['division', 'host']" filter='{"country": "USA"}'></gs-aggregate-component>`}
19
- />
20
-
21
- ### Live Example
22
-
23
- [See here](?path=/story/visualization-aggregate--template)
24
-
25
- <Story of={AggregateComponentStories.Table} />
@@ -1,25 +0,0 @@
1
- import { ArgTypes, Description, Meta, Story, Title, Source } from '@storybook/blocks';
2
-
3
- import * as LocationFilterStories from './location-filter-component.stories.ts';
4
-
5
- <Meta of={LocationFilterStories} name='Docs' />
6
-
7
- <Title of={LocationFilterStories} />
8
-
9
- <Description of={LocationFilterStories} />
10
-
11
- ## Specification
12
-
13
- <ArgTypes of={LocationFilterStories} />
14
-
15
- ## Example
16
-
17
- <Source
18
- code={`<gs-location-filter fields="['continent', 'country']" value='Europe / Switzerland'></gs-location-filter>`}
19
- />
20
-
21
- ### Live Example
22
-
23
- [See here](?path=/story/input-location-filter--location-filter)
24
-
25
- <Story of={LocationFilterStories.LocationFilter} />