Skip to content

Commit 2a45b8d

Browse files
otAAAhJenkins
authored andcommitted
feat(cmk-ui-library): add a search button
The search only ran on Enter, which gave no visible way to execute it. CmkSearchInput now renders a submit button next to the field, running the same handler Enter does. The decorative magnifier inside the field is gone: with the button carrying that icon, keeping a second one only made the field noisier. CMK-37080 Change-Id: Iff9e743240dc62e415302db22315dc3d9eb145bb
1 parent a1c0df2 commit 2a45b8d

3 files changed

Lines changed: 82 additions & 29 deletions

File tree

packages/cmk-frontend-vue/ui-component-library/components/form-elements/CmkSearchInput/UclCmkSearchInput.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ export const a11yData = [
2020
{
2121
keys: ['Enter'],
2222
description: 'Submits the current query, emitting the search event.'
23+
},
24+
{
25+
keys: ['Space'],
26+
description:
27+
'Activates the focused clear or search button, clearing or submitting the query respectively.'
2328
}
2429
]
2530

packages/cmk-ui-library/components/CmkSearchInput.vue

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,39 +42,51 @@ function clear(): void {
4242

4343
<template>
4444
<div class="cmk-search-input">
45-
<CmkMultitoneIcon
46-
class="cmk-search-input__icon"
47-
name="search"
48-
primary-color="others"
49-
size="small"
50-
aria-hidden="true"
51-
/>
52-
<input
53-
ref="input"
54-
v-model="query"
55-
type="search"
56-
role="searchbox"
57-
class="cmk-search-input__field"
58-
:aria-label="placeholder"
59-
:placeholder="placeholder"
60-
autocomplete="off"
61-
@keydown.enter="submit"
62-
/>
63-
<CmkIconButton
64-
class="cmk-search-input__clear"
65-
:class="{ 'cmk-search-input__clear--hidden': query.length === 0 }"
66-
name="close"
67-
size="small"
68-
:title="_t('Clear search')"
69-
@click="clear"
70-
/>
45+
<div class="cmk-search-input__box">
46+
<input
47+
ref="input"
48+
v-model="query"
49+
type="search"
50+
role="searchbox"
51+
class="cmk-search-input__field"
52+
:aria-label="placeholder"
53+
:placeholder="placeholder"
54+
autocomplete="off"
55+
@keydown.enter="submit"
56+
/>
57+
<CmkIconButton
58+
class="cmk-search-input__clear"
59+
:class="{ 'cmk-search-input__clear--hidden': query.length === 0 }"
60+
name="close"
61+
size="small"
62+
:title="_t('Clear search')"
63+
@click="clear"
64+
/>
65+
</div>
66+
<button
67+
type="button"
68+
class="cmk-search-input__submit"
69+
:aria-label="_t('Search')"
70+
:title="_t('Search')"
71+
@click="submit"
72+
>
73+
<CmkMultitoneIcon name="search" primary-color="others" size="small" aria-hidden="true" />
74+
</button>
7175
</div>
7276
</template>
7377

7478
<style scoped>
7579
.cmk-search-input {
7680
display: flex;
7781
align-items: center;
82+
gap: var(--dimension-4);
83+
}
84+
85+
.cmk-search-input__box {
86+
display: flex;
87+
flex: 1 1 auto;
88+
min-width: 0;
89+
align-items: center;
7890
height: 27px;
7991
padding: 0 var(--spacing);
8092
background-color: var(--default-form-element-bg-color);
@@ -86,15 +98,34 @@ function clear(): void {
8698
}
8799
}
88100
89-
.cmk-search-input__icon {
101+
.cmk-search-input__submit {
102+
display: flex;
90103
flex: 0 0 auto;
91-
opacity: 0.6;
104+
align-items: center;
105+
justify-content: center;
106+
box-sizing: border-box;
107+
width: 27px;
108+
height: 27px;
109+
margin: 0;
110+
padding: 0;
111+
background-color: var(--default-form-element-bg-color);
112+
border: 1px solid var(--default-form-element-border-color);
113+
border-radius: var(--border-radius);
114+
cursor: pointer;
115+
116+
&:hover {
117+
border-color: var(--success);
118+
}
119+
120+
&:focus-visible {
121+
outline: revert;
122+
}
92123
}
93124
94125
.cmk-search-input__field {
95126
flex: 1 1 auto;
96127
height: 100%;
97-
margin: 0 var(--dimension-4);
128+
margin: 0 var(--dimension-4) 0 0;
98129
padding: 0;
99130
background: transparent;
100131
border: 0;

packages/cmk-ui-library/tests/components/CmkSearchInput.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@ test('emits the typed query on Enter', async () => {
5151
expect(emitted('search')).toEqual([['db']])
5252
})
5353

54+
test('emits the typed query when the search button is clicked', async () => {
55+
const { emitted } = renderInput()
56+
57+
await fireEvent.update(screen.getByRole('searchbox'), 'db')
58+
await fireEvent.click(screen.getByRole('button', { name: 'Search' }))
59+
60+
expect(emitted('search')).toEqual([['db']])
61+
})
62+
63+
test('emits an empty query when the search button is clicked on an empty field', async () => {
64+
const { emitted } = renderInput()
65+
66+
await fireEvent.click(screen.getByRole('button', { name: 'Search' }))
67+
68+
expect(emitted('search')).toEqual([['']])
69+
})
70+
5471
test('keeps the model value in sync while typing', async () => {
5572
const { emitted } = renderInput()
5673

0 commit comments

Comments
 (0)