-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fdfa904
commit 5e1b601
Showing
7 changed files
with
260 additions
and
1 deletion.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
components/src/preact/textInput/__mockData__/aggregated_hosts.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"errors": [], | ||
"info": { | ||
"apiVersion": 1, | ||
"dataVersion": 1709685650, | ||
"deprecationDate": null, | ||
"deprecationInfo": null, | ||
"acknowledgement": null | ||
}, | ||
"data": [ | ||
{ | ||
"host": "Homo", | ||
"count": 123 | ||
}, | ||
{ | ||
"host": "Homo sapiens", | ||
"count": 234 | ||
}, | ||
{ | ||
"host": "Ape", | ||
"count": 345 | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { FetchAggregatedOperator } from '../../operator/FetchAggregatedOperator'; | ||
|
||
export async function fetchAutocompleteList(lapis: string, field: string, signal?: AbortSignal) { | ||
const fetchAggregatedOperator = new FetchAggregatedOperator<Record<string, string>>({}, [field]); | ||
|
||
const data = (await fetchAggregatedOperator.evaluate(lapis, signal)).content; | ||
|
||
return data.map((item) => item[field]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Meta, StoryObj } from '@storybook/preact'; | ||
Check failure on line 1 in components/src/preact/textInput/test-input.stories.tsx GitHub Actions / Run linter
|
||
import { TextInput, TextInputProps } from './text-input'; | ||
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants'; | ||
import { LapisUrlContext } from '../LapisUrlContext'; | ||
import data from './__mockData__/aggregated_hosts.json'; | ||
|
||
const meta: Meta<TextInputProps> = { | ||
title: 'Input/TextInput', | ||
component: TextInput, | ||
parameters: { | ||
fetchMock: { | ||
mocks: [ | ||
{ | ||
matcher: { | ||
name: 'hosts', | ||
url: AGGREGATED_ENDPOINT, | ||
query: { | ||
fields: 'host', | ||
}, | ||
}, | ||
response: { | ||
status: 200, | ||
body: data, | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
export const Default: StoryObj<TextInputProps> = { | ||
render: (args) => ( | ||
<LapisUrlContext.Provider value={LAPIS_URL}> | ||
<TextInput lapisField={args.lapisField} placeholderText={args.placeholderText} /> | ||
</LapisUrlContext.Provider> | ||
), | ||
args: { | ||
lapisField: 'host', | ||
placeholderText: 'Enter a host name', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { FunctionComponent } from 'preact'; | ||
import { useContext, useRef } from 'preact/hooks'; | ||
import { LapisUrlContext } from '../LapisUrlContext'; | ||
import { useQuery } from '../useQuery'; | ||
import { fetchAutocompleteList } from './fetchAutocompleteList'; | ||
import { LoadingDisplay } from '../components/loading-display'; | ||
import { ErrorDisplay } from '../components/error-display'; | ||
import { NoDataDisplay } from '../components/no-data-display'; | ||
|
||
export interface TextInputProps { | ||
lapisField: string; | ||
placeholderText?: string; | ||
} | ||
|
||
export const TextInput: FunctionComponent<TextInputProps> = ({ lapisField, placeholderText }) => { | ||
const lapis = useContext(LapisUrlContext); | ||
|
||
const inputRef = useRef<HTMLInputElement>(null); | ||
|
||
const { data, error, isLoading } = useQuery(() => fetchAutocompleteList(lapis, lapisField), [lapisField, lapis]); | ||
|
||
if (isLoading) { | ||
return <LoadingDisplay />; | ||
} | ||
|
||
if (error !== null) { | ||
return <ErrorDisplay error={error} />; | ||
} | ||
|
||
if (data === null) { | ||
return <NoDataDisplay />; | ||
} | ||
|
||
const onInput = () => { | ||
const value = inputRef.current?.value; | ||
|
||
if (isValidValue(value)) { | ||
inputRef.current?.dispatchEvent( | ||
new CustomEvent('gs-text-input-changed', { | ||
detail: { [lapisField]: value }, | ||
bubbles: true, | ||
composed: true, | ||
}), | ||
); | ||
} | ||
}; | ||
|
||
const isValidValue = (value: string | undefined) => { | ||
if (value === undefined) { | ||
return false; | ||
} | ||
return data.includes(value); | ||
}; | ||
|
||
return ( | ||
<> | ||
<input | ||
type='text' | ||
class='input input-bordered' | ||
placeholder={placeholderText !== undefined ? placeholderText : lapisField} | ||
onInput={onInput} | ||
ref={inputRef} | ||
list={lapisField} | ||
/> | ||
<datalist id={lapisField}> | ||
{data.map((item) => ( | ||
<option value={item} key={item} /> | ||
))} | ||
</datalist> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
components/src/web-components/input/text-input-component.stories.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import type { Meta, StoryObj } from '@storybook/web-components'; | ||
import { AGGREGATED_ENDPOINT, LAPIS_URL } from '../../constants'; | ||
|
||
import { html } from 'lit'; | ||
import '../app'; | ||
import './text-input-component'; | ||
import { withinShadowRoot } from '../withinShadowRoot.story'; | ||
import { expect, fn, userEvent, waitFor } from '@storybook/test'; | ||
import data from '../../preact/textInput/__mockData__/aggregated_hosts.json'; | ||
|
||
const meta: Meta = { | ||
title: 'Input/Text input', | ||
component: 'gs-text-input', | ||
parameters: { | ||
actions: { | ||
handles: ['gs-text-input-changed'], | ||
}, | ||
fetchMock: { | ||
mocks: [ | ||
{ | ||
matcher: { | ||
name: 'hosts', | ||
url: AGGREGATED_ENDPOINT, | ||
query: { | ||
fields: 'host', | ||
}, | ||
}, | ||
response: { | ||
status: 200, | ||
body: data, | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
export const Default: StoryObj<{ lapisField: string; placeholderText: string }> = { | ||
render: (args) => { | ||
return html` <gs-app lapis="${LAPIS_URL}"> | ||
<div class="max-w-screen-lg"> | ||
<gs-text-input .lapisField=${args.lapisField} .placeholderText=${args.placeholderText}></gs-text-input> | ||
</div> | ||
</gs-app>`; | ||
}, | ||
args: { | ||
lapisField: 'host', | ||
placeholderText: 'Enter host name', | ||
}, | ||
}; | ||
|
||
export const FiresEvent: StoryObj<{ lapisField: string; placeholderText: string }> = { | ||
...Default, | ||
play: async ({ canvasElement, step }) => { | ||
const canvas = await withinShadowRoot(canvasElement, 'gs-text-input'); | ||
|
||
const inputField = () => canvas.getByPlaceholderText('Enter host name'); | ||
const listenerMock = fn(); | ||
await step('Setup event listener mock', async () => { | ||
canvasElement.addEventListener('gs-text-input-changed', listenerMock); | ||
}); | ||
|
||
await step('wait until data is loaded', async () => { | ||
await waitFor(() => { | ||
return expect(inputField()).toBeEnabled(); | ||
}); | ||
}); | ||
|
||
await step('Enters an invalid host name', async () => { | ||
await userEvent.type(inputField(), 'notInList'); | ||
await expect(listenerMock).not.toHaveBeenCalled(); | ||
await userEvent.type(inputField(), '{backspace>9/}'); | ||
}); | ||
|
||
await step('Enter a valid host name', async () => { | ||
await userEvent.type(inputField(), 'Homo'); | ||
|
||
await expect(listenerMock).toHaveBeenCalledWith( | ||
expect.objectContaining({ | ||
detail: { | ||
host: 'Homo', | ||
}, | ||
}), | ||
); | ||
}); | ||
}, | ||
}; |
22 changes: 22 additions & 0 deletions
22
components/src/web-components/input/text-input-component.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { PreactLitAdapter } from '../PreactLitAdapter'; | ||
import { customElement, property } from 'lit/decorators.js'; | ||
import { TextInput } from '../../preact/textInput/text-input'; | ||
|
||
@customElement('gs-text-input') | ||
export class TextInputComponent extends PreactLitAdapter { | ||
@property() | ||
lapisField = ''; | ||
|
||
@property() | ||
placeholderText = ''; | ||
|
||
override render() { | ||
return <TextInput lapisField={this.lapisField} placeholderText={this.placeholderText} />; | ||
} | ||
} | ||
|
||
declare global { | ||
interface HTMLElementTagNameMap { | ||
'gs-text-input': TextInputComponent; | ||
} | ||
} |