Fixed #2916 - Add autoFilterFocus property to Dropdown and MultiSelect

pull/2929/head
mertsincan 2022-09-01 00:30:06 +01:00
parent bc17ff6022
commit 12190e45fd
8 changed files with 61 additions and 15 deletions

View File

@ -197,6 +197,12 @@ const DropdownProps = [
default: "true",
description: "Whether to focus on the first visible or selected element when the overlay panel is shown."
},
{
name: "autoFilterFocus",
type: "boolean",
default: "false",
description: "Whether to focus on the filter element when the overlay panel is shown."
},
{
name: "selectOnFocus",
type: "boolean",

View File

@ -209,6 +209,12 @@ const MultiSelectProps = [
default: "true",
description: "Whether to focus on the first visible or selected element when the overlay panel is shown."
},
{
name: "autoFilterFocus",
type: "boolean",
default: "false",
description: "Whether to focus on the filter element when the overlay panel is shown."
},
{
name: "filterMessage",
type: "string",

View File

@ -182,6 +182,11 @@ export interface DropdownProps {
* Default value is true.
*/
autoOptionFocus?: boolean | undefined;
/**
* Whether to focus on the filter element when the overlay panel is shown.
* Default value is false.
*/
autoFilterFocus?: boolean | undefined;
/**
* When enabled, the focused option is selected.
* Default value is false.

View File

@ -21,7 +21,7 @@
<slot name="header" :value="modelValue" :options="visibleOptions"></slot>
<div v-if="filter" class="p-dropdown-header">
<div class="p-dropdown-filter-container">
<input type="text" ref="filterInput" :value="filterValue" @vnode-updated="onFilterUpdated" class="p-dropdown-filter p-inputtext p-component" :placeholder="filterPlaceholder"
<input ref="filterInput" type="text" :value="filterValue" @vnode-updated="onFilterUpdated" class="p-dropdown-filter p-inputtext p-component" :placeholder="filterPlaceholder"
role="searchbox" autocomplete="off" :aria-owns="id + '_list'" :aria-activedescendant="focusedOptionId"
@keydown="onFilterKeyDown" @blur="onFilterBlur" @input="onFilterChange" v-bind="filterInputProps"/>
<span class="p-dropdown-filter-icon pi pi-search"></span>
@ -144,6 +144,10 @@ export default {
type: Boolean,
default: true
},
autoFilterFocus: {
type: Boolean,
default: false
},
selectOnFocus: {
type: Boolean,
default: false
@ -267,7 +271,7 @@ export default {
this.overlayVisible = true;
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : (this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1);
isFocus && this.$refs.focusInput.focus();
isFocus && DomHandler.focus(this.$refs.focusInput);
},
hide(isFocus) {
const _hide = () => {
@ -277,7 +281,7 @@ export default {
this.searchValue = '';
this.resetFilterOnHide && (this.filterValue = null);
isFocus && this.$refs.focusInput && this.$refs.focusInput.focus();
isFocus && DomHandler.focus(this.$refs.focusInput);
}
setTimeout(() => { _hide() }, 0); // For ScreenReaders
@ -390,14 +394,14 @@ export default {
if (relatedTarget === this.$refs.focusInput) {
const firstFocusableEl = DomHandler.getFirstFocusableElement(this.overlay, ':not(.p-hidden-focusable)');
firstFocusableEl && firstFocusableEl.focus();
DomHandler.focus(firstFocusableEl);
}
else {
this.$refs.focusInput.focus();
DomHandler.focus(this.$refs.focusInput);
}
},
onLastHiddenFocus() {
this.$refs.firstHiddenFocusableElementOnOverlay.focus();
DomHandler.focus(this.$refs.firstHiddenFocusableElementOnOverlay);
},
onOptionSelect(event, option, isHide = true) {
const value = this.getOptionValue(option);
@ -571,7 +575,7 @@ export default {
onTabKey(event, pressedInInputText = false) {
if (!pressedInInputText) {
if (this.overlayVisible && this.hasFocusableElements()) {
this.$refs.firstHiddenFocusableElementOnOverlay.focus();
DomHandler.focus(this.$refs.firstHiddenFocusableElementOnOverlay);
event.preventDefault();
}
@ -593,6 +597,8 @@ export default {
ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay);
this.alignOverlay();
this.scrollInView();
this.autoFilterFocus && DomHandler.focus(this.$refs.filterInput);
},
onOverlayAfterEnter() {
this.bindOutsideClickListener();

View File

@ -202,6 +202,11 @@ export interface MultiSelectProps {
* Default value is true.
*/
autoOptionFocus?: boolean | undefined;
/**
* Whether to focus on the filter element when the overlay panel is shown.
* Default value is false.
*/
autoFilterFocus?: boolean | undefined;
/**
* Text to be displayed in hidden accessible field when filtering returns any results. Defaults to value from PrimeVue locale configuration.
* Default value is '{0} results are available'.

View File

@ -44,7 +44,7 @@
</div>
</div>
<div v-if="filter" class="p-multiselect-filter-container">
<input type="text" ref="filterInput" :value="filterValue" @vnode-updated="onFilterUpdated" class="p-multiselect-filter p-inputtext p-component" :placeholder="filterPlaceholder"
<input ref="filterInput" type="text" :value="filterValue" @vnode-updated="onFilterUpdated" class="p-multiselect-filter p-inputtext p-component" :placeholder="filterPlaceholder"
role="searchbox" autocomplete="off" :aria-owns="id + '_list'" :aria-activedescendant="focusedOptionId"
@keydown="onFilterKeyDown" @blur="onFilterBlur" @input="onFilterChange" v-bind="filterInputProps"/>
<span class="p-multiselect-filter-icon pi pi-search"></span>
@ -197,6 +197,10 @@ export default {
type: Boolean,
default: true
},
autoFilterFocus: {
type: Boolean,
default: false
},
filterMessage: {
type: String,
default: null
@ -312,7 +316,7 @@ export default {
this.overlayVisible = true;
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : (this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1);
isFocus && this.$refs.focusInput.focus();
isFocus && DomHandler.focus(this.$refs.focusInput);
},
hide(isFocus) {
this.$emit('before-hide');
@ -321,7 +325,7 @@ export default {
this.searchValue = '';
this.resetFilterOnHide && (this.filterValue = null);
isFocus && this.$refs.focusInput.focus();
isFocus && DomHandler.focus(this.$refs.focusInput);
},
onFocus(event) {
this.focused = true;
@ -413,14 +417,14 @@ export default {
if (relatedTarget === this.$refs.focusInput) {
const firstFocusableEl = DomHandler.getFirstFocusableElement(this.overlay, ':not(.p-hidden-focusable)');
firstFocusableEl && firstFocusableEl.focus();
DomHandler.focus(firstFocusableEl);
}
else {
this.$refs.focusInput.focus();
DomHandler.focus(this.$refs.focusInput);
}
},
onLastHiddenFocus() {
this.$refs.firstHiddenFocusableElementOnOverlay.focus();
DomHandler.focus(this.$refs.firstHiddenFocusableElementOnOverlay);
},
onCloseClick() {
this.hide(true);
@ -445,7 +449,7 @@ export default {
value = [...(this.modelValue || []), this.getOptionValue(option)];
this.updateModel(event, value);
isFocus && this.$refs.focusInput.focus();
isFocus && DomHandler.focus(this.$refs.focusInput);
index !== -1 && (this.focusedOptionIndex = index);
},
onOptionMouseMove(event, index) {
@ -646,7 +650,7 @@ export default {
onTabKey(event, pressedInInputText = false) {
if (!pressedInInputText) {
if (this.overlayVisible && this.hasFocusableElements()) {
this.$refs.firstHiddenFocusableElementOnOverlay.focus();
DomHandler.focus(this.$refs.firstHiddenFocusableElementOnOverlay);
event.preventDefault();
}
@ -666,6 +670,8 @@ export default {
ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay);
this.alignOverlay();
this.scrollInView();
this.autoFilterFocus && DomHandler.focus(this.$refs.filterInput);
},
onOverlayAfterEnter() {
this.bindOutsideClickListener();

View File

@ -330,6 +330,12 @@ export default {
<td>true</td>
<td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td>
</tr>
<tr>
<td>autoFilterFocus</td>
<td>boolean</td>
<td>false</td>
<td>Whether to focus on the filter element when the overlay panel is shown.</td>
</tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>

View File

@ -351,6 +351,12 @@ export default {
<td>true</td>
<td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td>
</tr>
<tr>
<td>autoFilterFocus</td>
<td>boolean</td>
<td>false</td>
<td>Whether to focus on the filter element when the overlay panel is shown.</td>
</tr>
<tr>
<td>filterMessage</td>
<td>string</td>