Skip to content

Commit

Permalink
feat(vue-autocomplete): add autofocus and validation (#448)
Browse files Browse the repository at this point in the history
closes #447
  • Loading branch information
devCrossNet committed Aug 26, 2019
1 parent 0aa9eea commit 89b4ad7
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 29 deletions.
29 changes: 29 additions & 0 deletions src/app/shared/components/VueAutocomplete/VueAutocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -27,6 +29,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
isLoading: true,
Expand All @@ -41,6 +45,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -59,6 +65,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -83,6 +91,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -106,6 +116,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
options: AutocompleteOptionsFixture,
},
});
Expand All @@ -124,6 +136,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -147,6 +161,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -169,6 +185,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -190,6 +208,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
options: AutocompleteOptionsFixture,
},
Expand All @@ -208,6 +228,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
maxOptions: 10,
},
Expand Down Expand Up @@ -239,6 +261,8 @@ describe('VueAutocomplete.vue', () => {
localVue,
i18n,
propsData: {
id: 'foo',
name: 'foo',
placeholder: 'Type something',
maxOptions: 10,
},
Expand Down Expand Up @@ -301,5 +325,10 @@ describe('VueAutocomplete.vue', () => {

wrapper.vm.onFocusItem();
expect((wrapper as any).vm.$refs.resultContainer.scrollTop).toBe(100);

document.querySelector = (): any => null;

wrapper.vm.onFocusItem();
expect((wrapper as any).vm.$refs.resultContainer.scrollTop).toBe(100);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ story.add(
change: action('@change'),
},
template: `<vue-autocomplete
name="foo"
id="foo"
:options="autocompleteOptions"
:max-options="3"
placeholder="Type something (e.g. foo)"
Expand Down Expand Up @@ -72,10 +74,16 @@ story.add(
change: action('@change'),
},
template: `<vue-autocomplete
name="foo"
id="foo"
validation="required"
required
:options="autocompleteOptions"
message="Type something (e.g. foo)"
error-message="This field is mandatory"
:max-options="3"
:is-loading="isLoading"
placeholder="Type something (e.g. foo)"
placeholder="Search query"
@request="onRequest($event);request($event)"
@change="change"/>`,
i18n,
Expand Down
88 changes: 61 additions & 27 deletions src/app/shared/components/VueAutocomplete/VueAutocomplete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,25 @@
<vue-input
role="searchbox"
aria-autocomplete="list"
aria-controls="autocomplete-results"
:name="name || instanceId"
:id="id || instanceId"
:aria-controls="`autocomplete-results-${id}`"
:name="name"
:id="id"
:placeholder="placeholder"
:required="required"
:autofocus="autofocus"
:value="searchQuery"
:disabled="disabled"
:required="required"
:placeholder="placeholder"
:aria-activedescendant="hasOptions ? `result-item${selectedOptionIndex}-${instanceId}` : null"
:readonly="readonly"
:message="message"
:errorMessage="errorMessage"
:validation="validation"
:autocomplete="autocomplete"
:aria-activedescendant="hasOptions ? `result-item-${selectedOptionIndex}-${id}` : null"
@input="onInput"
@keyup.down="onArrowDown"
@keydown.up="onArrowUp"
@keydown.enter="onEnterKeyPress"
@focus="onFocus"
@keyup.stop.prevent.down="onArrowDown"
@keydown.stop.prevent.up="onArrowUp"
@keydown.stop.prevent.enter="onEnterKeyPress"
@focus.stop.prevent="onFocus"
/>

<vue-icon-search v-show="isLoading === false" />
Expand All @@ -30,7 +36,7 @@
<ul
ref="resultContainer"
role="listbox"
id="autocomplete-results"
:id="`autocomplete-results-${id}`"
:style="{ height: resultContainerHeight + 'px' }"
v-show="isOpen === true && isLoading === false"
>
Expand All @@ -44,7 +50,7 @@
v-else
v-for="(option, index) in options"
:key="index"
:id="`result-item-${index}-${instanceId}`"
:id="`result-item-${index}-${id}`"
:aria-selected="isSelected(index)"
:class="isSelected(index) ? $style.isSelected : ''"
@click="onOptionClick(index)"
Expand Down Expand Up @@ -73,19 +79,51 @@ export default {
props: {
name: {
type: String,
default: '',
required: true,
},
id: {
type: String,
default: '',
required: true,
},
placeholder: {
type: String,
},
required: {
type: Boolean,
},
autofocus: {
type: Boolean,
},
value: {
type: String,
},
type: {
type: String,
default: 'text',
},
disabled: {
type: Boolean,
},
readonly: {
type: Boolean,
},
message: {
type: String,
},
errorMessage: {
type: String,
},
validation: {
type: String,
},
autocomplete: {
type: String,
default: 'off',
},
options: {
type: Array,
default: (): any[] => [],
},
placeholder: {
type: String,
},
maxOptions: {
type: Number,
default: 5,
Expand All @@ -98,14 +136,6 @@ export default {
type: Boolean,
default: false,
},
required: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
},
data(): any {
return {
Expand All @@ -114,7 +144,6 @@ export default {
previousQuery: '',
selectedOptionIndex: 0,
resultContainerHeight: 0,
instanceId: getGUID(),
};
},
computed: {
Expand Down Expand Up @@ -153,8 +182,13 @@ export default {
if (resultContainerScrollHeight > resultContainerClientHeight) {
const element: HTMLElement = document.querySelector(
`#result-item-${this.selectedOptionIndex}-${this.instanceId}`,
`#result-item-${this.selectedOptionIndex}-${this.id}`,
) as HTMLElement;
if (element === null) {
return;
}
const scrollBottom: number = resultContainerClientHeight + resultContainer.scrollTop;
const elementBottom: number = element.offsetTop + element.offsetHeight;
Expand Down
2 changes: 1 addition & 1 deletion src/app/shared/designSystem/variables/_autocomplete.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
$autocomplete-bg: $brand-bg-color;
$autocomplete-padding: 0;
$autocomplete-margin: -$space-20 0 0 0;
$autocomplete-margin: -$space-16 0 0 0;
$autocomplete-shadow: none;
$autocomplete-border: 1px solid $brand-border-color;

Expand Down

0 comments on commit 89b4ad7

Please sign in to comment.