@genspectrum/dashboard-components 0.18.6 → 0.19.1

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
@@ -950,7 +950,7 @@ declare global {
950
950
 
951
951
  declare global {
952
952
  interface HTMLElementTagNameMap {
953
- 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
953
+ 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
954
954
  }
955
955
  }
956
956
 
@@ -958,7 +958,7 @@ declare global {
958
958
  declare global {
959
959
  namespace JSX {
960
960
  interface IntrinsicElements {
961
- 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
961
+ 'gs-prevalence-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
962
962
  }
963
963
  }
964
964
  }
@@ -966,7 +966,7 @@ declare global {
966
966
 
967
967
  declare global {
968
968
  interface HTMLElementTagNameMap {
969
- 'gs-prevalence-over-time': PrevalenceOverTimeComponent;
969
+ 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
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-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
978
978
  }
979
979
  }
980
980
  }
@@ -982,7 +982,7 @@ declare global {
982
982
 
983
983
  declare global {
984
984
  interface HTMLElementTagNameMap {
985
- 'gs-number-sequences-over-time': NumberSequencesOverTimeComponent;
985
+ 'gs-relative-growth-advantage': RelativeGrowthAdvantageComponent;
986
986
  }
987
987
  }
988
988
 
@@ -990,7 +990,7 @@ declare global {
990
990
  declare global {
991
991
  namespace JSX {
992
992
  interface IntrinsicElements {
993
- 'gs-number-sequences-over-time': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
993
+ 'gs-relative-growth-advantage': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
994
994
  }
995
995
  }
996
996
  }
@@ -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-aggregate': AggregateComponent;
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-aggregate': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
1026
1026
  }
1027
1027
  }
1028
1028
  }
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.1",
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
  }
@@ -47,7 +47,7 @@ export function getFilteredMutationOverTimeData({
47
47
  return true;
48
48
  }
49
49
 
50
- if (displayMutationsSet !== null && !displayMutationsSet.has(entry.mutation.code)) {
50
+ if (displayMutationsSet !== null && !displayMutationsSet.has(entry.mutation.code.toUpperCase())) {
51
51
  return true;
52
52
  }
53
53
 
@@ -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`.