Skip to content

Commit a1955bf

Browse files
Merge pull request #689 from samply/feautre/add-input-fields-to-searchbar
Feautre/add input fields to searchbar
2 parents 9ed0e2b + 846d7a4 commit a1955bf

13 files changed

+576
-194
lines changed

book/src/components/searchbar.md

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Search Bar
22

3-
The `lens-searchbar` component offers an interface for exploring of all single-select items. It serves as the primary interface for users to search, apply, and adjust query criteria. Selected items appear as interactive chips within the component, giving users a clear visual of their active filters. Users can easily refine their search by removing individual values or entire criteria directly from the chip display.
3+
The `lens-searchbar` component offers an interface for exploring of all catalogue items. It serves as the primary interface for users to search, apply, and adjust query criteria. Selected items appear as interactive chips within the component, giving users a clear visual of their active filters. Users can easily refine their search by removing individual values or entire criteria directly from the chip display.
44

55
---
66

@@ -41,18 +41,6 @@ The `lens-searchbar` component offers an interface for exploring of all single-s
4141

4242
---
4343

44-
## Events
45-
46-
### `on:clear-search`
47-
48-
Triggered when the group clear button is clicked.
49-
50-
```svelte
51-
<lens-search-bar on:clear-search={handleClear} />
52-
```
53-
54-
---
55-
5644
## Example
5745

5846
```html
@@ -66,13 +54,27 @@ Triggered when the group clear button is clicked.
6654

6755
## Styling
6856

69-
| Part | Purpose |
70-
| ------------------------------------------------------ | -------------------------------- |
71-
| `lens-searchbar` | Wrapper for the entire component |
72-
| `lens-searchbar-input` | Main input element |
73-
| `lens-searchbar-chip`, `chip-name`, `chip-item` | Visual query chips |
74-
| `lens-searchbar-autocomplete-options` | Autocomplete container |
75-
| `lens-searchbar-autocomplete-options-item` | Individual result |
76-
| `lens-searchbar-autocomplete-options-item-focused` | Highlighted result |
77-
| `lens-searchbar-autocomplete-options-item-description` | Optional description |
78-
| `lens-searchbar-autocomplete-options-item-facet-count` | Facet count badge |
57+
| Part | Purpose |
58+
| -------------------------------------------------------------- | ------------------------------------ |
59+
| `lens-searchbar` | Wrapper for the entire component |
60+
| `lens-searchbar-active` | Active searchbar |
61+
| `lens-searchbar-chips` | Visual query chip wrapper |
62+
| `lens-searchbar-chip` | Query chip |
63+
| `lens-searchbar-chip-name` | Query chip criterion name |
64+
| `lens-searchbar-chip-item` | Query chip values wrapper |
65+
| `lens-searchbar-chip-item-text` | Query chip singular value |
66+
| `lens-searchbar-input` | Main input element |
67+
| `lens-searchbar-input-options-open` | Main input when autocomplete is open |
68+
| `lens-searchbar-autocomplete-options` | Autocomplete container |
69+
| `lens-searchbar-autocomplete-options-heading` | Autocomplete group heading |
70+
| `lens-searchbar-autocomplete-options-item` | Individual result |
71+
| `lens-searchbar-autocomplete-options-item-focused` | Highlighted result |
72+
| `lens-searchbar-autocomplete-options-item-criterion` | Single select result |
73+
| `lens-searchbar-autocomplete-options-item-numeric` | Numeric result input wrapper |
74+
| `lens-searchbar-autocomplete-options-item-date` | Date result input wrapper |
75+
| `lens-searchbar-autocomplete-options-item-string` | String result input wrapper |
76+
| `lens-searchbar-autocomplete-options-item-name` | Option name |
77+
| `lens-searchbar-autocomplete-options-item-description` | Optional description |
78+
| `lens-searchbar-autocomplete-options-item-description-focused` | Focused optional description |
79+
| `lens-searchbar-autocomplete-options-item-facet-count` | Facet count badge |
80+
| `lens-searchbar-autocomplete-options-type-more-message` | Wrapper for type more message |

demo.svelte

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@
235235
fieldType: "number",
236236
type: "BETWEEN",
237237
},
238+
{
239+
fieldType: "date",
240+
key: "date-of-diagnosis",
241+
name: "Date of diagnosis",
242+
type: "BETWEEN",
243+
max: "2025-09-04",
244+
},
238245
],
239246
},
240247
{
@@ -482,7 +489,7 @@
482489
}
483490
484491
.card {
485-
background-color: white;
492+
background-color: var(--white);
486493
border-radius: var(--border-radius-small);
487494
border: 1px solid var(--lightest-gray);
488495
padding: var(--gap-xs);

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import svelte from "eslint-plugin-svelte";
77
import svelteConfig from "./svelte.config.js";
88

99
export default defineConfig([
10-
globalIgnores(["dist", "book/book", "docs/assets"]),
10+
globalIgnores(["dist", "book", "docs/assets"]),
1111
// Recommended JavaScript and TypeScript lints
1212
pluginJs.configs.recommended,
1313
...tseslint.configs.recommended,

src/components/buttons/SearchButtonComponent.wc.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
const onclick = (): void => {
1919
queryModified.set(false);
2020
window.dispatchEvent(new CustomEvent("lens-search-triggered"));
21+
window.dispatchEvent(new CustomEvent("reset-all-searchbar-inputs"));
2122
};
2223
</script>
2324

src/components/buttons/StoreDeleteButtonComponent.svelte

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414
index: number;
1515
item?: QueryItem;
1616
};
17+
resetToEmptySearchBar?: () => void;
1718
}
1819
19-
let { itemToDelete }: Props = $props();
20+
let { itemToDelete, resetToEmptySearchBar = () => {} }: Props = $props();
2021
2122
const { type, index, item } = itemToDelete;
2223
@@ -51,7 +52,7 @@
5152
if (searchBarInputs) {
5253
searchBarInputs[$activeQueryGroupIndex].focus();
5354
}
54-
55+
resetToEmptySearchBar();
5556
return query;
5657
});
5758
}

src/components/catalogue/AddButton.svelte

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
11
<script lang="ts">
2-
let { ...props } = $props();
2+
import type {
3+
KeyboardEventHandler,
4+
MouseEventHandler,
5+
} from "svelte/elements";
6+
interface Props {
7+
inSearchBar: boolean;
8+
onkeydown?: KeyboardEventHandler<HTMLButtonElement>;
9+
onclick?: MouseEventHandler<HTMLButtonElement>;
10+
}
11+
let { inSearchBar, onkeydown, onclick }: Props = $props();
312
</script>
413

5-
<button aria-label="Add to query" part="lens-add-to-query-button" {...props}>
14+
<button
15+
tabindex="0"
16+
aria-label="Add to query"
17+
part="lens-add-to-query-button {inSearchBar
18+
? 'lens-add-to-query-button-searchbar'
19+
: ''}"
20+
{onkeydown}
21+
{onclick}
22+
type="button"
23+
>
624
<svg
725
xmlns="http://www.w3.org/2000/svg"
826
viewBox="0 0 24 24"
@@ -31,4 +49,11 @@
3149
[part~="lens-add-to-query-button"]:hover svg {
3250
color: var(--light-blue);
3351
}
52+
53+
[part~="lens-add-to-query-button-searchbar"] svg {
54+
color: var(--white);
55+
}
56+
[part~="lens-add-to-query-button-searchbar"]:hover svg {
57+
color: var(--light-gray);
58+
}
3459
</style>

src/components/catalogue/DatePickerComponent.svelte

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,37 @@
88
99
let {
1010
element,
11+
inSearchBar = false,
12+
resetToEmptySearchBar = () => {},
1113
}: {
1214
element: DateRangeCategory;
15+
inSearchBar?: boolean;
16+
resetToEmptySearchBar?: (focus?: boolean) => void;
1317
} = $props();
1418
19+
let form: HTMLFormElement;
1520
let fromInput: HTMLInputElement;
1621
let toInput: HTMLInputElement;
1722
let from: string = $state("");
1823
let to: string = $state("");
1924
2025
onMount(() => {
21-
fromInput.focus();
26+
if (inSearchBar === false) fromInput.focus();
2227
});
2328
24-
$effect(() => {
25-
if (from === "" && to === "") {
29+
let formVlaid = $derived(validateForm(from, to));
30+
31+
function validateForm(from: string, to: string): boolean {
32+
fromInput.setCustomValidity("");
33+
if (!from && !to) {
2634
fromInput.setCustomValidity(translate("cannot_both_be_empty"));
27-
} else if (from !== "" && to !== "" && from > to) {
35+
return false;
36+
} else if (from && to && from > to) {
2837
fromInput.setCustomValidity(translate("min_must_be_less_than_max"));
29-
} else {
30-
fromInput.setCustomValidity("");
38+
return false;
3139
}
32-
});
40+
return true;
41+
}
3342
3443
function getMinMax(min: string | null, max: string | null): string {
3544
if (min && max && min === max) return `${min}`;
@@ -39,8 +48,12 @@
3948
return "";
4049
}
4150
42-
function onsubmit(event: SubmitEvent): void {
43-
event.preventDefault();
51+
function addItem(): void {
52+
if (!formVlaid) {
53+
fromInput.reportValidity();
54+
return;
55+
}
56+
4457
addItemToQuery(
4558
{
4659
id: uuidv4(),
@@ -57,17 +70,47 @@
5770
},
5871
$activeQueryGroupIndex,
5972
);
73+
74+
resetToEmptySearchBar();
75+
}
76+
77+
function onkeydown(event: KeyboardEvent) {
78+
if (inSearchBar === false) return;
79+
80+
if (event.key === "Enter") {
81+
addItem();
82+
}
83+
84+
if (event.key === "ArrowUp" || event.key === "ArrowDown") {
85+
event.preventDefault();
86+
}
87+
}
88+
89+
function onfocusin(event: FocusEvent) {
90+
if (!inSearchBar) return;
91+
// toInput can not be reached by tab when the focus is outside the form,
92+
// so this can handle the focus via mouse click instead of using another event listener
93+
if (event.target === toInput) return;
94+
95+
const relatedTargetOutside =
96+
event.relatedTarget instanceof Node &&
97+
!form.contains(event.relatedTarget);
98+
99+
if (relatedTargetOutside) {
100+
fromInput.focus();
101+
}
60102
}
61103
</script>
62104

63-
<form part="lens-date-input-form" {onsubmit}>
105+
<form part="lens-date-input-form" bind:this={form} {onfocusin}>
64106
<input
65107
part="lens-date-input-formfield"
66108
type="date"
67109
min={element.min}
68110
max={element.max}
69111
bind:value={from}
70112
bind:this={fromInput}
113+
{onkeydown}
71114
/>
72115
<span part="date-input-range-separator">-</span>
73116
<input
@@ -77,8 +120,9 @@
77120
max={element.max}
78121
bind:value={to}
79122
bind:this={toInput}
123+
{onkeydown}
80124
/>
81-
<AddButton />
125+
<AddButton onclick={addItem} {onkeydown} {inSearchBar} />
82126
</form>
83127

84128
<style>

0 commit comments

Comments
 (0)