@genspectrum/dashboard-components 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/custom-elements.json +1013 -931
  2. package/dist/dashboard-components.js +350 -171
  3. package/dist/dashboard-components.js.map +1 -1
  4. package/dist/genspectrum-components.d.ts +48 -57
  5. package/dist/style.css +74 -23
  6. package/package.json +2 -2
  7. package/src/preact/aggregatedData/aggregate.tsx +28 -28
  8. package/src/preact/components/error-boundary.stories.tsx +62 -0
  9. package/src/preact/components/error-boundary.tsx +31 -0
  10. package/src/preact/components/error-display.stories.tsx +24 -3
  11. package/src/preact/components/error-display.tsx +14 -1
  12. package/src/preact/components/loading-display.stories.tsx +6 -6
  13. package/src/preact/components/loading-display.tsx +1 -1
  14. package/src/preact/components/no-data-display.tsx +5 -1
  15. package/src/preact/dateRangeSelector/date-range-selector.stories.tsx +17 -0
  16. package/src/preact/dateRangeSelector/date-range-selector.tsx +33 -5
  17. package/src/preact/locationFilter/location-filter.stories.tsx +23 -6
  18. package/src/preact/locationFilter/location-filter.tsx +29 -18
  19. package/src/preact/mutationComparison/mutation-comparison.tsx +29 -25
  20. package/src/preact/mutationFilter/mutation-filter.stories.tsx +17 -2
  21. package/src/preact/mutationFilter/mutation-filter.tsx +25 -7
  22. package/src/preact/mutations/mutations.tsx +23 -23
  23. package/src/preact/prevalenceOverTime/prevalence-over-time.tsx +44 -28
  24. package/src/preact/relativeGrowthAdvantage/relative-growth-advantage.tsx +43 -31
  25. package/src/preact/textInput/text-input.tsx +26 -3
  26. package/src/web-components/app.stories.ts +1 -2
  27. package/src/web-components/app.ts +4 -2
  28. package/src/web-components/index.ts +1 -1
  29. package/src/web-components/input/{date-range-selector-component.stories.ts → gs-date-range-selector.stories.ts} +19 -2
  30. package/src/web-components/input/{date-range-selector-component.tsx → gs-date-range-selector.tsx} +12 -0
  31. package/src/web-components/input/{location-filter-component.stories.ts → gs-location-filter.stories.ts} +29 -4
  32. package/src/web-components/input/{location-filter-component.tsx → gs-location-filter.tsx} +12 -1
  33. package/src/web-components/input/{mutation-filter-component.stories.ts → gs-mutation-filter.stories.ts} +20 -4
  34. package/src/web-components/input/{mutation-filter-component.tsx → gs-mutation-filter.tsx} +36 -5
  35. package/src/web-components/input/{text-input-component.stories.ts → gs-text-input.stories.ts} +31 -3
  36. package/src/web-components/input/{text-input-component.tsx → gs-text-input.tsx} +12 -0
  37. package/src/web-components/input/index.ts +4 -4
  38. package/src/web-components/visualization/data_visualization_statistical_analysis.mdx +26 -0
  39. package/src/web-components/{display/aggregate-component.stories.ts → visualization/gs-aggregate.stories.ts} +5 -6
  40. package/src/web-components/{display/aggregate-component.tsx → visualization/gs-aggregate.tsx} +1 -1
  41. package/src/web-components/{display/mutation-comparison-component.stories.ts → visualization/gs-mutation-comparison.stories.ts} +8 -9
  42. package/src/web-components/{display/mutation-comparison-component.tsx → visualization/gs-mutation-comparison.tsx} +1 -1
  43. package/src/web-components/{display/mutations-component.stories.ts → visualization/gs-mutations.stories.ts} +6 -7
  44. package/src/web-components/{display/mutations-component.tsx → visualization/gs-mutations.tsx} +2 -2
  45. package/src/web-components/{display/prevalence-over-time-component.stories.ts → visualization/gs-prevalence-over-time.stories.ts} +1 -2
  46. package/src/web-components/{display/prevalence-over-time-component.tsx → visualization/gs-prevalence-over-time.tsx} +3 -1
  47. package/src/web-components/{display/relative-growth-advantage-component.stories.ts → visualization/gs-relative-growth-advantage.stories.ts} +1 -2
  48. package/src/web-components/visualization/index.ts +5 -0
  49. package/src/web-components/display/index.ts +0 -5
  50. /package/src/web-components/{display/relative-growth-advantage-component.tsx → visualization/gs-relative-growth-advantage.tsx} +0 -0
@@ -8,6 +8,7 @@ import {
8
8
  } from '../../query/queryRelativeGrowthAdvantage';
9
9
  import { type LapisFilter } from '../../types';
10
10
  import { LapisUrlContext } from '../LapisUrlContext';
11
+ import { ErrorBoundary } from '../components/error-boundary';
11
12
  import { ErrorDisplay } from '../components/error-display';
12
13
  import Headline from '../components/headline';
13
14
  import Info, { InfoHeadline1, InfoHeadline2, InfoLink, InfoParagraph } from '../components/info';
@@ -21,22 +22,49 @@ import { useQuery } from '../useQuery';
21
22
 
22
23
  export type View = 'line';
23
24
 
24
- export interface RelativeGrowthAdvantageProps {
25
+ export interface RelativeGrowthAdvantageProps extends RelativeGrowthAdvantagePropsInner {
26
+ size?: Size;
27
+ headline?: string;
28
+ }
29
+
30
+ export interface RelativeGrowthAdvantagePropsInner {
25
31
  numerator: LapisFilter;
26
32
  denominator: LapisFilter;
27
33
  generationTime: number;
28
34
  views: View[];
29
- size?: Size;
30
- headline?: string;
31
35
  }
32
36
 
33
37
  export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageProps> = ({
38
+ views,
39
+ size,
34
40
  numerator,
35
41
  denominator,
36
42
  generationTime,
37
- views,
38
- size,
39
43
  headline = 'Relative growth advantage',
44
+ }) => {
45
+ const defaultSize = { height: '600px', width: '100%' };
46
+
47
+ return (
48
+ <ErrorBoundary size={size} defaultSize={defaultSize} headline={headline}>
49
+ <ResizeContainer size={size} defaultSize={defaultSize}>
50
+ <Headline heading={headline}>
51
+ <RelativeGrowthAdvantageInner
52
+ views={views}
53
+ numerator={numerator}
54
+ denominator={denominator}
55
+ generationTime={generationTime}
56
+ />
57
+ </Headline>
58
+ </ResizeContainer>
59
+ </ErrorBoundary>
60
+ );
61
+ };
62
+
63
+ export const RelativeGrowthAdvantageInner: FunctionComponent<RelativeGrowthAdvantageProps> = ({
64
+ numerator,
65
+ denominator,
66
+ generationTime,
67
+ views,
40
68
  }) => {
41
69
  const lapis = useContext(LapisUrlContext);
42
70
  const [yAxisScaleType, setYAxisScaleType] = useState<ScaleType>('linear');
@@ -47,41 +75,25 @@ export const RelativeGrowthAdvantage: FunctionComponent<RelativeGrowthAdvantageP
47
75
  );
48
76
 
49
77
  if (isLoading) {
50
- return (
51
- <Headline heading={headline}>
52
- <LoadingDisplay />
53
- </Headline>
54
- );
78
+ return <LoadingDisplay />;
55
79
  }
56
80
 
57
81
  if (error !== null) {
58
- return (
59
- <Headline heading={headline}>
60
- <ErrorDisplay error={error} />
61
- </Headline>
62
- );
82
+ return <ErrorDisplay error={error} />;
63
83
  }
64
84
 
65
85
  if (data === null) {
66
- return (
67
- <Headline heading={headline}>
68
- <NoDataDisplay />
69
- </Headline>
70
- );
86
+ return <NoDataDisplay />;
71
87
  }
72
88
 
73
89
  return (
74
- <ResizeContainer size={size} defaultSize={{ height: '700px', width: '100%' }}>
75
- <Headline heading={headline}>
76
- <RelativeGrowthAdvantageTabs
77
- data={data}
78
- yAxisScaleType={yAxisScaleType}
79
- setYAxisScaleType={setYAxisScaleType}
80
- views={views}
81
- generationTime={generationTime}
82
- />
83
- </Headline>
84
- </ResizeContainer>
90
+ <RelativeGrowthAdvantageTabs
91
+ data={data}
92
+ yAxisScaleType={yAxisScaleType}
93
+ setYAxisScaleType={setYAxisScaleType}
94
+ views={views}
95
+ generationTime={generationTime}
96
+ />
85
97
  );
86
98
  };
87
99
 
@@ -3,18 +3,41 @@ import { useContext, useRef } from 'preact/hooks';
3
3
 
4
4
  import { fetchAutocompleteList } from './fetchAutocompleteList';
5
5
  import { LapisUrlContext } from '../LapisUrlContext';
6
+ import { ErrorBoundary } from '../components/error-boundary';
6
7
  import { ErrorDisplay } from '../components/error-display';
7
8
  import { LoadingDisplay } from '../components/loading-display';
8
9
  import { NoDataDisplay } from '../components/no-data-display';
10
+ import { ResizeContainer } from '../components/resize-container';
9
11
  import { useQuery } from '../useQuery';
10
12
 
11
- export interface TextInputProps {
13
+ export interface TextInputInnerProps {
12
14
  lapisField: string;
13
15
  placeholderText?: string;
14
16
  initialValue?: string;
15
17
  }
16
18
 
17
- export const TextInput: FunctionComponent<TextInputProps> = ({ lapisField, placeholderText, initialValue }) => {
19
+ export interface TextInputProps extends TextInputInnerProps {
20
+ width?: string;
21
+ }
22
+
23
+ export const TextInput: FunctionComponent<TextInputProps> = ({ width, lapisField, placeholderText, initialValue }) => {
24
+ const defaultSize = { width: '100%', height: '3rem' };
25
+ const size = width === undefined ? undefined : { width, height: defaultSize.height };
26
+
27
+ return (
28
+ <ErrorBoundary defaultSize={defaultSize} size={size}>
29
+ <ResizeContainer size={size} defaultSize={defaultSize}>
30
+ <TextInputInner lapisField={lapisField} placeholderText={placeholderText} initialValue={initialValue} />
31
+ </ResizeContainer>
32
+ </ErrorBoundary>
33
+ );
34
+ };
35
+
36
+ export const TextInputInner: FunctionComponent<TextInputInnerProps> = ({
37
+ lapisField,
38
+ placeholderText,
39
+ initialValue,
40
+ }) => {
18
41
  const lapis = useContext(LapisUrlContext);
19
42
 
20
43
  const inputRef = useRef<HTMLInputElement>(null);
@@ -58,7 +81,7 @@ export const TextInput: FunctionComponent<TextInputProps> = ({ lapisField, place
58
81
  <>
59
82
  <input
60
83
  type='text'
61
- class='input input-bordered'
84
+ class='input input-bordered w-full'
62
85
  placeholder={placeholderText !== undefined ? placeholderText : lapisField}
63
86
  onInput={onInput}
64
87
  ref={inputRef}
@@ -25,7 +25,6 @@ const meta: Meta = {
25
25
  parameters: withComponentDocs({
26
26
  fetchMock: {},
27
27
  componentDocs: {
28
- tag: 'gs-app',
29
28
  opensShadowDom: false,
30
29
  expectsChildren: true,
31
30
  codeExample,
@@ -92,7 +91,7 @@ export const FailsToFetchReferenceGenome: StoryObj<{ lapis: string }> = {
92
91
  const canvas = within(canvasElement);
93
92
 
94
93
  await waitFor(() => {
95
- expect(canvas.getByText('Error')).toBeVisible();
94
+ expect(canvas.getByText('Error', { exact: false })).toBeVisible();
96
95
  });
97
96
  },
98
97
  };
@@ -55,8 +55,10 @@ export class App extends LitElement {
55
55
  override render() {
56
56
  return this.updateReferenceGenome.render({
57
57
  complete: () => html` <slot></slot>`,
58
- error: () => html`<p>Error</p>`, // TODO(#143): Add more advanced error handling
59
- pending: () => html` <p>Loading reference genomes...</p> `,
58
+ error: () =>
59
+ html` <div class="m-2 w-full alert alert-error">
60
+ Error: Cannot fetch reference genome. Is LAPIS available?
61
+ </div>`,
60
62
  });
61
63
  }
62
64
 
@@ -1,3 +1,3 @@
1
1
  export { App } from './app.js';
2
- export * from './display';
2
+ export * from './visualization';
3
3
  export * from './input';
@@ -15,7 +15,7 @@ import {
15
15
  PRESET_VALUE_LAST_6_MONTHS,
16
16
  PRESET_VALUE_LAST_MONTH,
17
17
  } from '../../preact/dateRangeSelector/date-range-selector';
18
- import './date-range-selector-component';
18
+ import './gs-date-range-selector';
19
19
  import '../app';
20
20
  import { toYYYYMMDD } from '../../preact/dateRangeSelector/dateConversion';
21
21
  import { withinShadowRoot } from '../withinShadowRoot.story';
@@ -25,6 +25,7 @@ const codeExample = String.raw`
25
25
  customSelectOptions='[{ "label": "Year 2021", "dateFrom": "2021-01-01", "dateTo": "2021-12-31" }]'
26
26
  earliestDate="1970-01-01"
27
27
  initialValue="${PRESET_VALUE_LAST_6_MONTHS}"
28
+ width="100%"
28
29
  ></gs-date-range-selector>`;
29
30
 
30
31
  const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
@@ -36,7 +37,6 @@ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
36
37
  },
37
38
  fetchMock: {},
38
39
  componentDocs: {
39
- tag: 'gs-date-range-selector',
40
40
  opensShadowDom: true,
41
41
  expectsChildren: false,
42
42
  codeExample,
@@ -58,11 +58,27 @@ const meta: Meta<DateRangeSelectorProps<'CustomDateRange'>> = {
58
58
  'CustomDateRange',
59
59
  ],
60
60
  },
61
+ customSelectOptions: {
62
+ control: {
63
+ type: 'object',
64
+ },
65
+ },
66
+ earliestDate: {
67
+ control: {
68
+ type: 'text',
69
+ },
70
+ },
71
+ width: {
72
+ control: {
73
+ type: 'text',
74
+ },
75
+ },
61
76
  },
62
77
  args: {
63
78
  customSelectOptions: [{ label: 'CustomDateRange', dateFrom: '2021-01-01', dateTo: '2021-12-31' }],
64
79
  earliestDate: '1970-01-01',
65
80
  initialValue: PRESET_VALUE_LAST_6_MONTHS,
81
+ width: '100%',
66
82
  },
67
83
  decorators: [withActions],
68
84
  tags: ['autodocs'],
@@ -78,6 +94,7 @@ export const DateRangeSelectorStory: StoryObj<DateRangeSelectorProps<'CustomDate
78
94
  .customSelectOptions=${args.customSelectOptions}
79
95
  .earliestDate=${args.earliestDate}
80
96
  .initialValue=${args.initialValue}
97
+ .width=${args.width}
81
98
  ></gs-date-range-selector>
82
99
  </div>
83
100
  </gs-app>`,
@@ -64,12 +64,24 @@ export class DateRangeSelectorComponent extends PreactLitAdapter {
64
64
  | string
65
65
  | undefined = 'last6Months';
66
66
 
67
+ /**
68
+ * The width of the component.
69
+ *
70
+ * If not set, the component will take the full width of its container.
71
+ *
72
+ * The width should be a string with a unit in css style, e.g. '100%', '500px' or '50vw'.
73
+ * If the unit is %, the size will be relative to the container of the component.
74
+ */
75
+ @property({ type: Object })
76
+ width: string | undefined = undefined;
77
+
67
78
  override render() {
68
79
  return (
69
80
  <DateRangeSelector
70
81
  customSelectOptions={this.customSelectOptions}
71
82
  earliestDate={this.earliestDate}
72
83
  initialValue={this.initialValue}
84
+ width={this.width}
73
85
  />
74
86
  );
75
87
  }
@@ -7,11 +7,18 @@ import { ifDefined } from 'lit/directives/if-defined.js';
7
7
  import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
8
8
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
9
9
  import '../app';
10
- import './location-filter-component';
10
+ import './gs-location-filter';
11
11
  import data from '../../preact/locationFilter/__mockData__/aggregated.json';
12
12
  import { type LocationFilterProps } from '../../preact/locationFilter/location-filter';
13
13
  import { withinShadowRoot } from '../withinShadowRoot.story';
14
14
 
15
+ const codeExample = String.raw`
16
+ <gs-location-filter
17
+ fields="['region', 'country']"
18
+ value='Europe / Switzerland'
19
+ width="100%"
20
+ ></gs-location-filter>`;
21
+
15
22
  const meta: Meta = {
16
23
  title: 'Input/Location filter',
17
24
  component: 'gs-location-filter',
@@ -20,12 +27,28 @@ const meta: Meta = {
20
27
  handles: ['gs-location-changed'],
21
28
  },
22
29
  componentDocs: {
23
- tag: 'gs-location-filter',
24
30
  opensShadowDom: true,
25
31
  expectsChildren: false,
26
- codeExample: `<gs-location-filter fields="['continent', 'country']" value='Europe / Switzerland'></gs-location-filter>`,
32
+ codeExample,
27
33
  },
28
34
  }),
35
+ argTypes: {
36
+ fields: {
37
+ control: {
38
+ type: 'object',
39
+ },
40
+ },
41
+ initialValue: {
42
+ control: {
43
+ type: 'text',
44
+ },
45
+ },
46
+ width: {
47
+ control: {
48
+ type: 'text',
49
+ },
50
+ },
51
+ },
29
52
  decorators: [withActions],
30
53
  tags: ['autodocs'],
31
54
  };
@@ -39,6 +62,7 @@ const Template: StoryObj<LocationFilterProps> = {
39
62
  <gs-location-filter
40
63
  .fields=${args.fields}
41
64
  initialValue=${ifDefined(args.initialValue)}
65
+ .width=${args.width}
42
66
  ></gs-location-filter>
43
67
  </div>
44
68
  </gs-app>`;
@@ -46,6 +70,7 @@ const Template: StoryObj<LocationFilterProps> = {
46
70
  args: {
47
71
  fields: ['region', 'country', 'division', 'location'],
48
72
  initialValue: '',
73
+ width: '100%',
49
74
  },
50
75
  };
51
76
 
@@ -119,7 +144,7 @@ export const FetchingLocationsFails: StoryObj<LocationFilterProps> = {
119
144
  const canvas = await withinShadowRoot(canvasElement, 'gs-location-filter');
120
145
 
121
146
  await waitFor(() =>
122
- expect(canvas.getByText('Bad Request: {"error":"no data"} ', { exact: false })).toBeInTheDocument(),
147
+ expect(canvas.getByText('Oops! Something went wrong.', { exact: false })).toBeInTheDocument(),
123
148
  );
124
149
  },
125
150
  };
@@ -48,8 +48,19 @@ export class LocationFilterComponent extends PreactLitAdapter {
48
48
  @property({ type: Array })
49
49
  fields: string[] = [];
50
50
 
51
+ /**
52
+ * The width of the component.
53
+ *
54
+ * If not set, the component will take the full width of its container.
55
+ *
56
+ * The width should be a string with a unit in css style, e.g. '100%', '500px' or '50vw'.
57
+ * If the unit is %, the size will be relative to the container of the component.
58
+ */
59
+ @property({ type: Object })
60
+ width: string | undefined = undefined;
61
+
51
62
  override render() {
52
- return <LocationFilter initialValue={this.initialValue} fields={this.fields} />;
63
+ return <LocationFilter initialValue={this.initialValue} fields={this.fields} width={this.width} />;
53
64
  }
54
65
  }
55
66
 
@@ -8,9 +8,13 @@ import { LAPIS_URL } from '../../constants';
8
8
  import '../app';
9
9
  import { type MutationFilterProps } from '../../preact/mutationFilter/mutation-filter';
10
10
  import { withinShadowRoot } from '../withinShadowRoot.story';
11
- import './mutation-filter-component';
11
+ import './gs-mutation-filter';
12
12
 
13
- const codeExample = String.raw`<gs-mutation-filter initialValue='["A123T"]'></gs-mutation-filter>`;
13
+ const codeExample = String.raw`
14
+ <gs-mutation-filter
15
+ initialValue='["A123T"]'
16
+ size='{ "width": "100%", "height": "6.5rem" }'
17
+ ></gs-mutation-filter>`;
14
18
 
15
19
  const meta: Meta<MutationFilterProps> = {
16
20
  title: 'Input/Mutation filter',
@@ -21,12 +25,23 @@ const meta: Meta<MutationFilterProps> = {
21
25
  },
22
26
  fetchMock: {},
23
27
  componentDocs: {
24
- tag: 'gs-mutation-filter',
25
28
  opensShadowDom: true,
26
29
  expectsChildren: false,
27
30
  codeExample,
28
31
  },
29
32
  }),
33
+ argTypes: {
34
+ initialValue: {
35
+ control: {
36
+ type: 'object',
37
+ },
38
+ },
39
+ size: {
40
+ control: {
41
+ type: 'object',
42
+ },
43
+ },
44
+ },
30
45
  decorators: [withActions],
31
46
  tags: ['autodocs'],
32
47
  };
@@ -37,12 +52,13 @@ const Template: StoryObj<MutationFilterProps> = {
37
52
  render: (args) => {
38
53
  return html` <gs-app lapis="${LAPIS_URL}">
39
54
  <div class="max-w-screen-lg">
40
- <gs-mutation-filter .initialValue=${args.initialValue}></gs-mutation-filter>
55
+ <gs-mutation-filter .initialValue=${args.initialValue} .size=${args.size}></gs-mutation-filter>
41
56
  </div>
42
57
  </gs-app>`;
43
58
  },
44
59
  args: {
45
60
  initialValue: [],
61
+ size: { width: '100%', height: '3rem' },
46
62
  },
47
63
  };
48
64
 
@@ -1,8 +1,12 @@
1
1
  import { customElement, property } from 'lit/decorators.js';
2
2
 
3
- import { type TextInputComponent } from './text-input-component';
4
3
  import { ReferenceGenomesAwaiter } from '../../preact/components/ReferenceGenomesAwaiter';
5
- import { MutationFilter, type SelectedMutationFilterStrings } from '../../preact/mutationFilter/mutation-filter';
4
+ import {
5
+ MutationFilter,
6
+ type MutationFilterProps,
7
+ type SelectedMutationFilterStrings,
8
+ } from '../../preact/mutationFilter/mutation-filter';
9
+ import type { Equals, Expect } from '../../utils/typeAssertions';
6
10
  import { PreactLitAdapter } from '../PreactLitAdapter';
7
11
 
8
12
  /**
@@ -53,6 +57,8 @@ import { PreactLitAdapter } from '../PreactLitAdapter';
53
57
  */
54
58
  @customElement('gs-mutation-filter')
55
59
  export class MutationFilterComponent extends PreactLitAdapter {
60
+ // prettier-ignore
61
+ // The multiline union type must not start with `|` because it looks weird in the Storybook docs
56
62
  /**
57
63
  * The initial value to use for this mutation filter.
58
64
  * Must be either
@@ -60,12 +66,31 @@ export class MutationFilterComponent extends PreactLitAdapter {
60
66
  * - an object with the keys `nucleotideMutations`, `aminoAcidMutations`, `nucleotideInsertions` and `aminoAcidInsertions` and corresponding string arrays.
61
67
  */
62
68
  @property()
63
- initialValue: SelectedMutationFilterStrings | string[] | undefined = undefined;
69
+ initialValue:
70
+ {
71
+ nucleotideMutations: string[];
72
+ aminoAcidMutations: string[];
73
+ nucleotideInsertions: string[];
74
+ aminoAcidInsertions: string[];
75
+ }
76
+ | string[]
77
+ | undefined = undefined;
78
+
79
+ /**
80
+ * The size of the component.
81
+ *
82
+ * If not set, the component will take the full width of its container with height 700px.
83
+ *
84
+ * The width and height should be a string with a unit in css style, e.g. '100%', '500px' or '50vh'.
85
+ * If the unit is %, the size will be relative to the container of the component.
86
+ */
87
+ @property({ type: Object })
88
+ size: { width?: string; height?: string } | undefined = undefined;
64
89
 
65
90
  override render() {
66
91
  return (
67
92
  <ReferenceGenomesAwaiter>
68
- <MutationFilter initialValue={this.initialValue} />
93
+ <MutationFilter initialValue={this.initialValue} size={this.size} />
69
94
  </ReferenceGenomesAwaiter>
70
95
  );
71
96
  }
@@ -73,7 +98,7 @@ export class MutationFilterComponent extends PreactLitAdapter {
73
98
 
74
99
  declare global {
75
100
  interface HTMLElementTagNameMap {
76
- 'gs-mutation-filter': TextInputComponent;
101
+ 'gs-mutation-filter': MutationFilterComponent;
77
102
  }
78
103
 
79
104
  interface HTMLElementEventMap {
@@ -81,3 +106,9 @@ declare global {
81
106
  'gs-mutation-filter-on-blur': CustomEvent<SelectedMutationFilterStrings>;
82
107
  }
83
108
  }
109
+
110
+ /* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
111
+ type InitialValueMatches = Expect<
112
+ Equals<typeof MutationFilterComponent.prototype.initialValue, MutationFilterProps['initialValue']>
113
+ >;
114
+ /* eslint-enable @typescript-eslint/no-unused-vars, no-unused-vars */
@@ -6,13 +6,18 @@ import { html } from 'lit';
6
6
  import { withComponentDocs } from '../../../.storybook/ComponentDocsBlock';
7
7
  import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants';
8
8
  import '../app';
9
- import './text-input-component';
9
+ import './gs-text-input';
10
10
  import data from '../../preact/textInput/__mockData__/aggregated_hosts.json';
11
11
  import type { TextInputProps } from '../../preact/textInput/text-input';
12
12
  import { withinShadowRoot } from '../withinShadowRoot.story';
13
13
 
14
14
  const codeExample = String.raw`
15
- <gs-text-input lapisField="host" placeholderText="Enter host name" initialValue="Homo sapiens"></gs-text-input>`;
15
+ <gs-text-input
16
+ lapisField="host"
17
+ placeholderText="Enter host name"
18
+ initialValue="Homo sapiens"
19
+ width="50%">
20
+ </gs-text-input>`;
16
21
 
17
22
  const meta: Meta<TextInputProps> = {
18
23
  title: 'Input/Text input',
@@ -39,12 +44,33 @@ const meta: Meta<TextInputProps> = {
39
44
  ],
40
45
  },
41
46
  componentDocs: {
42
- tag: 'gs-text-input',
43
47
  opensShadowDom: true,
44
48
  expectsChildren: false,
45
49
  codeExample,
46
50
  },
47
51
  }),
52
+ argTypes: {
53
+ lapisField: {
54
+ control: {
55
+ type: 'text',
56
+ },
57
+ },
58
+ placeholderText: {
59
+ control: {
60
+ type: 'text',
61
+ },
62
+ },
63
+ initialValue: {
64
+ control: {
65
+ type: 'text',
66
+ },
67
+ },
68
+ width: {
69
+ control: {
70
+ type: 'text',
71
+ },
72
+ },
73
+ },
48
74
  decorators: [withActions],
49
75
  tags: ['autodocs'],
50
76
  };
@@ -59,6 +85,7 @@ export const Default: StoryObj<TextInputProps> = {
59
85
  .lapisField=${args.lapisField}
60
86
  .placeholderText=${args.placeholderText}
61
87
  .initialValue=${args.initialValue}
88
+ .width=${args.width}
62
89
  ></gs-text-input>
63
90
  </div>
64
91
  </gs-app>`;
@@ -67,6 +94,7 @@ export const Default: StoryObj<TextInputProps> = {
67
94
  lapisField: 'host',
68
95
  placeholderText: 'Enter host name',
69
96
  initialValue: 'Homo sapiens',
97
+ width: '100%',
70
98
  },
71
99
  };
72
100
 
@@ -39,12 +39,24 @@ export class TextInputComponent extends PreactLitAdapter {
39
39
  @property()
40
40
  placeholderText: string | undefined = '';
41
41
 
42
+ /**
43
+ * The width of the component.
44
+ *
45
+ * If not set, the component will take the full width of its container.
46
+ *
47
+ * The width should be a string with a unit in css style, e.g. '100%', '500px' or '50vw'.
48
+ * If the unit is %, the size will be relative to the container of the component.
49
+ */
50
+ @property({ type: Object })
51
+ width: string | undefined = undefined;
52
+
42
53
  override render() {
43
54
  return (
44
55
  <TextInput
45
56
  lapisField={this.lapisField}
46
57
  placeholderText={this.placeholderText}
47
58
  initialValue={this.initialValue}
59
+ width={this.width}
48
60
  />
49
61
  );
50
62
  }
@@ -1,4 +1,4 @@
1
- export { DateRangeSelectorComponent } from './date-range-selector-component';
2
- export { LocationFilterComponent } from './location-filter-component';
3
- export { TextInputComponent } from './text-input-component';
4
- export { MutationFilterComponent } from './mutation-filter-component';
1
+ export { DateRangeSelectorComponent } from './gs-date-range-selector';
2
+ export { LocationFilterComponent } from './gs-location-filter';
3
+ export { TextInputComponent } from './gs-text-input';
4
+ export { MutationFilterComponent } from './gs-mutation-filter';
@@ -0,0 +1,26 @@
1
+ import { Meta } from '@storybook/blocks';
2
+
3
+ <Meta title='Visualization/Data Visualization and Statistical Analysis' />
4
+
5
+ # Data Visualization and Statistical Analysis
6
+
7
+ ## Scales
8
+
9
+ On most plots, users can select the y-axis scaling through a dropdown.
10
+ They can choose between linear, logarithmic and logistic scaling.
11
+ By default, it is set to a linear scale.
12
+
13
+ In general, for each scale the displayed height of a value is calculated by applying the corresponding scale function.
14
+
15
+ - Linear: `value`
16
+ - Logarithmic: `ln(value)`
17
+ - Logistic: `ln(value / (1 - value))`
18
+
19
+ ## Confidence Intervals
20
+
21
+ On bar and line plots, users can choose to display confidence intervals.
22
+ For line plots, this is done by shading the area between the upper and lower bounds.
23
+ For bar plots, this is done by adding error bars to the top of each bar.
24
+
25
+ Currently, only one method is available for calculating the confidence intervals:
26
+ the [wilson score interval](https://en.wikipedia.org/wiki/Binomial_proportion_confidence_interval#Wilson_score_interval) with a confidence level of 95%.