@genspectrum/dashboard-components 0.4.1 → 0.4.2

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.
@@ -767,20 +767,20 @@ declare global {
767
767
 
768
768
  declare global {
769
769
  interface HTMLElementTagNameMap {
770
- 'gs-text-input': TextInputComponent;
770
+ 'gs-location-filter': LocationFilterComponent;
771
771
  }
772
772
  interface HTMLElementEventMap {
773
- 'gs-text-input-changed': CustomEvent<Record<string, string>>;
773
+ 'gs-location-changed': CustomEvent<Record<string, string>>;
774
774
  }
775
775
  }
776
776
 
777
777
 
778
778
  declare global {
779
779
  interface HTMLElementTagNameMap {
780
- 'gs-location-filter': LocationFilterComponent;
780
+ 'gs-text-input': TextInputComponent;
781
781
  }
782
782
  interface HTMLElementEventMap {
783
- 'gs-location-changed': CustomEvent<Record<string, string>>;
783
+ 'gs-text-input-changed': CustomEvent<Record<string, string>>;
784
784
  }
785
785
  }
786
786
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genspectrum/dashboard-components",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "GenSpectrum web components for building dashboards",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",
@@ -51,11 +51,11 @@ export const LocationFilterInner = ({ initialValue, fields }: LocationFilterInne
51
51
  const onInput = (event: JSXInternal.TargetedInputEvent<HTMLInputElement>) => {
52
52
  const inputValue = event.currentTarget.value;
53
53
  setValue(inputValue);
54
- if (inputValue.trim() === value.trim()) {
54
+ if (inputValue.trim() === value.trim() && inputValue !== '') {
55
55
  return;
56
56
  }
57
57
  const eventDetail = parseLocation(inputValue, fields);
58
- if (hasMatchingEntry(data, eventDetail)) {
58
+ if (hasAllUndefined(eventDetail) || hasMatchingEntry(data, eventDetail)) {
59
59
  divRef.current?.dispatchEvent(
60
60
  new CustomEvent('gs-location-changed', {
61
61
  detail: eventDetail,
@@ -92,10 +92,17 @@ export const LocationFilterInner = ({ initialValue, fields }: LocationFilterInne
92
92
  };
93
93
 
94
94
  const parseLocation = (location: string, fields: string[]) => {
95
+ if (location === '') {
96
+ return fields.reduce((acc, field) => ({ ...acc, [field]: undefined }), {});
97
+ }
95
98
  const fieldValues = location.split('/').map((part) => part.trim());
99
+
96
100
  return fields.reduce((acc, field, i) => ({ ...acc, [field]: fieldValues[i] }), {});
97
101
  };
98
102
 
103
+ const hasAllUndefined = (obj: Record<string, string | undefined>) =>
104
+ Object.values(obj).every((value) => value === undefined);
105
+
99
106
  const hasMatchingEntry = (data: Record<string, string>[] | null, eventDetail: Record<string, string>) => {
100
107
  if (data === null) {
101
108
  return false;
@@ -56,7 +56,7 @@ export const TextInputInner: FunctionComponent<TextInputInnerProps> = ({
56
56
  }
57
57
 
58
58
  const onInput = () => {
59
- const value = inputRef.current?.value;
59
+ const value = inputRef.current?.value === '' ? undefined : inputRef.current?.value;
60
60
 
61
61
  if (isValidValue(value)) {
62
62
  inputRef.current?.dispatchEvent(
@@ -71,7 +71,7 @@ export const TextInputInner: FunctionComponent<TextInputInnerProps> = ({
71
71
 
72
72
  const isValidValue = (value: string | undefined) => {
73
73
  if (value === undefined) {
74
- return false;
74
+ return true;
75
75
  }
76
76
  return data.includes(value);
77
77
  };
@@ -185,7 +185,16 @@ export const FiresEvent: StoryObj<LocationFilterProps> = {
185
185
  await step('Input invalid location', async () => {
186
186
  await userEvent.type(inputField(), 'Not / A / Location');
187
187
  await expect(listenerMock).not.toHaveBeenCalled();
188
+ });
189
+
190
+ await step('Empty input', async () => {
188
191
  await userEvent.type(inputField(), '{backspace>18/}');
192
+ await expect(listenerMock.mock.calls.at(-1)[0].detail).toStrictEqual({
193
+ region: undefined,
194
+ country: undefined,
195
+ division: undefined,
196
+ location: undefined,
197
+ });
189
198
  });
190
199
 
191
200
  await step('Select Asia', async () => {
@@ -118,7 +118,13 @@ export const FiresEvent: StoryObj<Required<TextInputProps>> = {
118
118
  await step('Enters an invalid host name', async () => {
119
119
  await userEvent.type(inputField(), 'notInList');
120
120
  await expect(listenerMock).not.toHaveBeenCalled();
121
+ });
122
+
123
+ await step('Empty input', async () => {
121
124
  await userEvent.type(inputField(), '{backspace>9/}');
125
+ await expect(listenerMock.mock.calls.at(-1)[0].detail).toStrictEqual({
126
+ host: undefined,
127
+ });
122
128
  });
123
129
 
124
130
  await step('Enter a valid host name', async () => {