Skip to content

Commit

Permalink
[CHUX-336] Emit search value from dropdown search and provide custom …
Browse files Browse the repository at this point in the history
…search prop (#1918)
  • Loading branch information
Anton Lazarev authored Apr 9, 2024
1 parent b0c6022 commit bd7ef1a
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/components/ec-dropdown-search/ec-dropdown-search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,16 @@ describe('EcDropdownSearch', () => {
expect(wrapper.find('.ec-dropdown-search__item--is-selected').exists()).toBe(false);
});

it('should emit search-change', async () => {
const wrapper = mountDropdownSearch({ items });
expect(wrapper.emitted('search-change')).toBeUndefined();
expect((wrapper.findByDataTest<HTMLInputElement>('ec-dropdown-search__search-input').element).value).toBe('');

await wrapper.findByDataTest('ec-dropdown-search__search-input').setValue('some text');
expect(wrapper.emitted()['search-change']?.[0]).toEqual(['some text']);
expect((wrapper.findByDataTest<HTMLInputElement>('ec-dropdown-search__search-input').element).value).toBe('some text');
});

it('should add a tooltip for any disabled item', () => {
const wrapper = mountDropdownSearch({ items });

Expand Down Expand Up @@ -294,6 +304,14 @@ describe('EcDropdownSearch', () => {
expect(getItemTexts(wrapper)).toEqual(['Item ABC', 'Item BCD']);
});

it('should not filter items if isCustomSearchEnabled is true', async () => {
const wrapper = mountDropdownSearch({ items: itemsToFilter, isCustomSearchEnabled: true });
expect(wrapper.findAllByDataTest('ec-dropdown-search__item').length).toBe(itemsToFilter.length);

await wrapper.findByDataTest('ec-dropdown-search__search-input').setValue('B');
expect(getItemTexts(wrapper)).toEqual(['Item ABC', 'Item BCD', 'Item cdf']);
});

it('should filter items using case insensitive', async () => {
const wrapper = mountDropdownSearch({ items: itemsToFilter });
expect(wrapper.findAllByDataTest('ec-dropdown-search__item').length).toBe(itemsToFilter.length);
Expand Down
5 changes: 3 additions & 2 deletions src/components/ec-dropdown-search/ec-dropdown-search.story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const all: EcDropdownSearchStory = storyArgs => ({
argsComplex,
args,
onChange: action('change'),
onSearchChange: action('search-change'),
};
},
template: `
Expand All @@ -115,7 +116,7 @@ export const all: EcDropdownSearchStory = storyArgs => ({
v-bind="args"
v-model="selectedItem"
:popover-options="dropdownSearch.popoverOptions"
v-on="{ change: onChange }"
v-on="{ change: onChange, searchChange: onSearchChange }"
>
<a href="#" @click.prevent>
<span>Open</span>
Expand All @@ -137,7 +138,7 @@ export const all: EcDropdownSearchStory = storyArgs => ({
<ec-dropdown-search
v-bind="argsComplex"
v-model="selectedItem"
v-on="{ change: onChange }"
v-on="{ change: onChange, searchChange: onSearchChange }"
>
<a href="#" @click.prevent>
<span>Open</span>
Expand Down
18 changes: 17 additions & 1 deletion src/components/ec-dropdown-search/ec-dropdown-search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
/>
<input
ref="searchInput"
v-model.trim="filterText"
v-model.trim="filterTextModel"
autocomplete="off"
:placeholder="placeholder"
class="ec-dropdown-search__search-input"
Expand Down Expand Up @@ -174,6 +174,7 @@ const props = withDefaults(defineProps<DropdownSearchProps<TValue, TDropdownSear
noResultsText: 'No results found',
tooltipCta: '',
isSearchEnabled: true,
isCustomSearchEnabled: false,
items: () => [],
maxVisibleItems: 4,
});
Expand All @@ -185,6 +186,7 @@ const emit = defineEmits<{
'open': [],
'after-close': [],
'after-open': [],
'search-change': [value: string],
}>();
// popover styles
Expand Down Expand Up @@ -300,6 +302,16 @@ function focusFirstItem() {
// search
const filterText = ref('');
const filterTextModel = computed({
get() {
return filterText.value;
},
set(value) {
filterText.value = value;
emit('search-change', value);
},
});
const isSearchInputFocused = ref(false);
const searchInput = ref<Maybe<HTMLInputElement>>(null);
Expand All @@ -310,6 +322,10 @@ function makeIndexText(item: TDropdownSearchItem, searchFields: ReadonlyArray<ke
}
const filteredItems = computed(() => {
if (props.isCustomSearchEnabled) {
return props.items;
}
const sanitisedText = removeDiacritics(filterText.value.toLowerCase());
if (!sanitisedText) {
return props.items;
Expand Down
1 change: 1 addition & 0 deletions src/components/ec-dropdown-search/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface DropdownSearchProps<TValue = string, TDropdownSearchItem extend
placeholder?: string,
level?: ZIndexLevel,
isSearchEnabled?: boolean,
isCustomSearchEnabled?: boolean,
isSensitive?: boolean,
items?: TDropdownSearchItem[],
searchFields?: ReadonlyArray<keyof TDropdownSearchItem>,
Expand Down
25 changes: 25 additions & 0 deletions src/components/ec-dropdown/ec-dropdown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,31 @@ describe('EcDropdown', () => {
expect(wrapper.emitted('close')?.length).toBe(1);
});

it('should emit search-change', async () => {
const wrapper = mountDropdown({ items, isSearchEnabled: true });
expect(wrapper.emitted('search-change')).toBeUndefined();
expect((wrapper.findByDataTest<HTMLInputElement>('ec-dropdown-search__search-input').element).value).toBe('');

await wrapper.findByDataTest('ec-dropdown-search__search-input').setValue('some text');
expect(wrapper.emitted()['search-change']?.[0]).toEqual(['some text']);
expect((wrapper.findByDataTest<HTMLInputElement>('ec-dropdown-search__search-input').element).value).toBe('some text');
});

it('should not filter items if isCustomSearchEnabled is true', async () => {
const itemsToFilter = [
{ text: 'Item ABC' },
{ text: 'Item BCD' },
{ text: 'Item cdf' },
];

const wrapper = mountDropdown({ items: itemsToFilter, isCustomSearchEnabled: true, isSearchEnabled: true });
expect(wrapper.findAllByDataTest('ec-dropdown-search__item').length).toBe(itemsToFilter.length);

await wrapper.findByDataTest('ec-dropdown-search__search-input').setValue('B');
const itemsText = wrapper.findAllByDataTest('ec-dropdown-search__item').map(itemWrapper => itemWrapper.text());
expect(itemsText).toEqual(['Item ABC', 'Item BCD', 'Item cdf']);
});

it('should not return focus back to readonly input if it already has it', async () => {
const focusSpy = vi.fn();

Expand Down
2 changes: 2 additions & 0 deletions src/components/ec-dropdown/ec-dropdown.story.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const Template: StoryFn<DropdownProps<never>> = storyArgs => ({
onFocus: action('focus'),
onOpen: action('open'),
onClose: action('close'),
onSearchChange: action('search-change'),
};
},
template: `
Expand All @@ -79,6 +80,7 @@ const Template: StoryFn<DropdownProps<never>> = storyArgs => ({
focus: onFocus,
open: onOpen,
close: onClose,
searchChange: onSearchChange
}"
>
<template #cta>
Expand Down
3 changes: 3 additions & 0 deletions src/components/ec-dropdown/ec-dropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:placeholder="searchPlaceholder"
:no-results-text="noResultsText"
:is-search-enabled="isSearchEnabled"
:is-custom-search-enabled="isCustomSearchEnabled"
:search-fields="searchFields"
:disabled="disabled"
:level="level"
Expand All @@ -20,6 +21,7 @@
@close="$emit('close')"
@after-open="$emit('after-open')"
@after-close="$emit('after-close')"
@search-change="$emit('search-change', $event)"
>
<ec-input-field
:id="id"
Expand Down Expand Up @@ -84,6 +86,7 @@ const emit = defineEmits<{
'close': [],
'after-open': [],
'after-close': [],
'search-change': [value: string]
}>();
const props = withDefaults(defineProps<DropdownProps<TValue, TDropdownItem>>(), {
Expand Down

0 comments on commit bd7ef1a

Please sign in to comment.