Fixed #2902 - Add selectOnFocus property to Overlay components

pull/2910/head
mertsincan 2022-08-30 12:05:10 +01:00
parent 7bdbeecf69
commit c391fa4268
16 changed files with 111 additions and 28 deletions

View File

@ -179,6 +179,12 @@ const AutoCompleteProps = [
default: "true", default: "true",
description: "Whether to focus on the first visible or selected element when the overlay panel is shown." description: "Whether to focus on the first visible or selected element when the overlay panel is shown."
}, },
{
name: "selectOnFocus",
type: "boolean",
default: "false",
description: "When enabled, the focused option is selected."
},
{ {
name: "searchLocale", name: "searchLocale",
type: "string", type: "string",

View File

@ -119,6 +119,12 @@ const CascadeSelectProps = [
default: "true", default: "true",
description: "Whether to focus on the first visible or selected element when the overlay panel is shown." description: "Whether to focus on the first visible or selected element when the overlay panel is shown."
}, },
{
name: "selectOnFocus",
type: "boolean",
default: "false",
description: "When enabled, the focused option is selected/opened."
},
{ {
name: "searchLocale", name: "searchLocale",
type: "string", type: "string",

View File

@ -191,6 +191,12 @@ const DropdownProps = [
default: "true", default: "true",
description: "Whether to focus on the first visible or selected element when the overlay panel is shown." description: "Whether to focus on the first visible or selected element when the overlay panel is shown."
}, },
{
name: "selectOnFocus",
type: "boolean",
default: "false",
description: "When enabled, the focused option is selected."
},
{ {
name: "filterMessage", name: "filterMessage",
type: "string", type: "string",

View File

@ -119,6 +119,12 @@ const ListboxProps = [
default: "true", default: "true",
description: "Whether to focus on the first visible or selected element." description: "Whether to focus on the first visible or selected element."
}, },
{
name: "selectOnFocus",
type: "boolean",
default: "false",
description: "When enabled, the focused option is selected."
},
{ {
name: "filterMessage", name: "filterMessage",
type: "string", type: "string",

View File

@ -202,6 +202,11 @@ export interface AutoCompleteProps {
* Default value is true. * Default value is true.
*/ */
autoOptionFocus?: boolean | undefined; autoOptionFocus?: boolean | undefined;
/**
* When enabled, the focused option is selected.
* Default value is false.
*/
selectOnFocus?: boolean | undefined;
/** /**
* Locale to use in searching. The default locale is the host environment's current locale. * Locale to use in searching. The default locale is the host environment's current locale.
*/ */

View File

@ -95,7 +95,7 @@ export default {
type: String, type: String,
default: 'blank' default: 'blank'
}, },
autoHighlight: { // TODO: Deprecated since v3.16.0 autoHighlight: { // TODO: Deprecated since v3.16.0. Use selectOnFocus property instead.
type: Boolean, type: Boolean,
default: false default: false
}, },
@ -154,6 +154,10 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
selectOnFocus: {
type: Boolean,
default: false
},
searchLocale: { searchLocale: {
type: String, type: String,
default: undefined default: undefined
@ -193,7 +197,6 @@ export default {
overlay: null, overlay: null,
virtualScroller: null, virtualScroller: null,
searchTimeout: null, searchTimeout: null,
selectOnFocus: false,
focusOnHover: false, focusOnHover: false,
dirty: false, dirty: false,
data() { data() {
@ -464,7 +467,7 @@ export default {
this.$emit('dropdown-click', { originalEvent: event, query }); this.$emit('dropdown-click', { originalEvent: event, query });
}, },
onOptionSelect(event, option) { onOptionSelect(event, option, isHide = true) {
const value = this.getOptionValue(option); const value = this.getOptionValue(option);
if (this.multiple) { if (this.multiple) {
@ -480,7 +483,7 @@ export default {
this.$emit('item-select', { originalEvent: event, value: option }); this.$emit('item-select', { originalEvent: event, value: option });
this.hide(true); isHide && this.hide(true);
}, },
onOptionMouseMove(event, index) { onOptionMouseMove(event, index) {
if (this.focusOnHover) { if (this.focusOnHover) {
@ -788,7 +791,7 @@ export default {
this.scrollInView(); this.scrollInView();
if (this.selectOnFocus || this.autoHighlight) { if (this.selectOnFocus || this.autoHighlight) {
this.updateModel(event, this.getOptionValue(this.visibleOptions[index])); this.onOptionSelect(event, this.visibleOptions[index], false);
} }
} }
}, },
@ -807,8 +810,7 @@ export default {
autoUpdateModel() { autoUpdateModel() {
if ((this.selectOnFocus || this.autoHighlight) && this.autoOptionFocus && !this.hasSelectedOption) { if ((this.selectOnFocus || this.autoHighlight) && this.autoOptionFocus && !this.hasSelectedOption) {
this.focusedOptionIndex = this.findFirstFocusedOptionIndex(); this.focusedOptionIndex = this.findFirstFocusedOptionIndex();
const value = this.getOptionValue(this.visibleOptions[this.focusedOptionIndex]); this.onOptionSelect(null, this.visibleOptions[this.focusedOptionIndex], false);
this.updateModel(null, this.multiple ? [value] : value);
} }
}, },
updateModel(event, value) { updateModel(event, value) {

View File

@ -121,6 +121,11 @@ export interface CascadeSelectProps {
* Default value is true. * Default value is true.
*/ */
autoOptionFocus?: boolean | undefined; autoOptionFocus?: boolean | undefined;
/**
* When enabled, the focused option is selected/opened.
* Default value is false.
*/
selectOnFocus?: boolean | undefined;
/** /**
* Locale to use in searching. The default locale is the host environment's current locale. * Locale to use in searching. The default locale is the host environment's current locale.
*/ */

View File

@ -79,6 +79,10 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
selectOnFocus: {
type: Boolean,
default: false
},
searchLocale: { searchLocale: {
type: String, type: String,
default: undefined default: undefined
@ -122,7 +126,6 @@ export default {
overlay: null, overlay: null,
searchTimeout: null, searchTimeout: null,
searchValue: null, searchValue: null,
selectOnFocus: false,
focusOnHover: false, focusOnHover: false,
data() { data() {
return { return {
@ -141,6 +144,8 @@ export default {
}, },
mounted() { mounted() {
this.id = this.$attrs.id || this.id; this.id = this.$attrs.id || this.id;
this.autoUpdateModel();
}, },
beforeUnmount() { beforeUnmount() {
this.unbindOutsideClickListener(); this.unbindOutsideClickListener();
@ -185,7 +190,7 @@ export default {
show(isFocus) { show(isFocus) {
this.$emit('before-show'); this.$emit('before-show');
this.overlayVisible = true; this.overlayVisible = true;
this.activeOptionPath = this.findOptionPathByValue(this.modelValue); this.activeOptionPath = this.hasSelectedOption ? this.findOptionPathByValue(this.modelValue) : this.activeOptionPath;
if (this.hasSelectedOption && ObjectUtils.isNotEmpty(this.activeOptionPath)) { if (this.hasSelectedOption && ObjectUtils.isNotEmpty(this.activeOptionPath)) {
const processedOption = this.activeOptionPath[this.activeOptionPath.length - 1]; const processedOption = this.activeOptionPath[this.activeOptionPath.length - 1];
@ -286,7 +291,10 @@ export default {
} }
}, },
onOptionChange(event) { onOptionChange(event) {
const { originalEvent, processedOption, isFocus } = event; const { originalEvent, processedOption, isFocus, isHide } = event;
if (ObjectUtils.isEmpty(processedOption)) return;
const { index, level, parentKey, children } = processedOption; const { index, level, parentKey, children } = processedOption;
const grouped = ObjectUtils.isNotEmpty(children); const grouped = ObjectUtils.isNotEmpty(children);
@ -296,15 +304,15 @@ export default {
this.focusedOptionInfo = { index, level, parentKey }; this.focusedOptionInfo = { index, level, parentKey };
this.activeOptionPath = activeOptionPath; this.activeOptionPath = activeOptionPath;
grouped ? this.onOptionGroupSelect(originalEvent, processedOption) : this.onOptionSelect(originalEvent, processedOption); grouped ? this.onOptionGroupSelect(originalEvent, processedOption) : this.onOptionSelect(originalEvent, processedOption, isHide);
isFocus && this.$refs.focusInput.focus(); isFocus && this.$refs.focusInput.focus();
}, },
onOptionSelect(event, processedOption) { onOptionSelect(event, processedOption, isHide = true) {
const value = this.getOptionValue(processedOption.option); const value = this.getOptionValue(processedOption.option);
this.activeOptionPath.forEach(p => p.selected = true); this.activeOptionPath.forEach(p => p.selected = true);
this.updateModel(event, value); this.updateModel(event, value);
this.hide(true); isHide && this.hide(true);
}, },
onOptionGroupSelect(event, processedOption) { onOptionGroupSelect(event, processedOption) {
this.dirty = true; this.dirty = true;
@ -634,7 +642,7 @@ export default {
this.scrollInView(); this.scrollInView();
if (this.selectOnFocus) { if (this.selectOnFocus) {
this.updateModel(event, this.getOptionValue(this.visibleOptions[index])); this.onOptionChange({ originalEvent: event, processedOption: this.visibleOptions[index], isHide: false });
} }
} }
}, },
@ -648,8 +656,9 @@ export default {
autoUpdateModel() { autoUpdateModel() {
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) { if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
this.focusedOptionInfo.index = this.findFirstFocusedOptionIndex(); this.focusedOptionInfo.index = this.findFirstFocusedOptionIndex();
const value = this.getOptionValue(this.visibleOptions[this.focusedOptionInfo.index]); this.onOptionChange({ processedOption: this.visibleOptions[this.focusedOptionInfo.index], isHide: false });
this.updateModel(null, value);
!this.overlayVisible && (this.focusedOptionInfo = { index: -1, level: 0, parentKey: '' });
} }
}, },
updateModel(event, value) { updateModel(event, value) {
@ -713,7 +722,7 @@ export default {
if (this.hasSelectedOption) { if (this.hasSelectedOption) {
const activeOptionPath = this.findOptionPathByValue(this.modelValue); const activeOptionPath = this.findOptionPathByValue(this.modelValue);
const processedOption = activeOptionPath.length ? activeOptionPath[activeOptionPath.length - 1] : null; const processedOption = ObjectUtils.isNotEmpty(activeOptionPath) ? activeOptionPath[activeOptionPath.length - 1] : null;
return processedOption ? this.getOptionLabel(processedOption.option) : label; return processedOption ? this.getOptionLabel(processedOption.option) : label;
} }

View File

@ -178,6 +178,11 @@ export interface DropdownProps {
* Default value is true. * Default value is true.
*/ */
autoOptionFocus?: boolean | undefined; autoOptionFocus?: boolean | undefined;
/**
* When enabled, the focused option is selected.
* Default value is false.
*/
selectOnFocus?: boolean | undefined;
/** /**
* Text to be displayed in hidden accessible field when filtering returns any results. Defaults to value from PrimeVue locale configuration. * 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'. * Default value is '{0} results are available'.

View File

@ -140,6 +140,10 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
selectOnFocus: {
type: Boolean,
default: false
},
filterMessage: { filterMessage: {
type: String, type: String,
default: null default: null
@ -182,7 +186,6 @@ export default {
searchTimeout: null, searchTimeout: null,
searchValue: null, searchValue: null,
isModelValueChanged: false, isModelValueChanged: false,
selectOnFocus: false,
focusOnHover: false, focusOnHover: false,
data() { data() {
return { return {
@ -391,11 +394,11 @@ export default {
onLastHiddenFocus() { onLastHiddenFocus() {
this.$refs.firstHiddenFocusableElementOnOverlay.focus(); this.$refs.firstHiddenFocusableElementOnOverlay.focus();
}, },
onOptionSelect(event, option) { onOptionSelect(event, option, isHide = true) {
const value = this.getOptionValue(option); const value = this.getOptionValue(option);
this.updateModel(event, value); this.updateModel(event, value);
this.hide(true); isHide && this.hide(true);
}, },
onOptionMouseMove(event, index) { onOptionMouseMove(event, index) {
if (this.focusOnHover) { if (this.focusOnHover) {
@ -744,7 +747,7 @@ export default {
this.scrollInView(); this.scrollInView();
if (this.selectOnFocus) { if (this.selectOnFocus) {
this.updateModel(event, this.getOptionValue(this.visibleOptions[index])); this.onOptionSelect(event, this.visibleOptions[index], false);
} }
} }
}, },
@ -763,8 +766,7 @@ export default {
autoUpdateModel() { autoUpdateModel() {
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) { if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
this.focusedOptionIndex = this.findFirstFocusedOptionIndex(); this.focusedOptionIndex = this.findFirstFocusedOptionIndex();
const value = this.getOptionValue(this.visibleOptions[this.focusedOptionIndex]); this.onOptionSelect(null, this.visibleOptions[this.focusedOptionIndex], false);
this.updateModel(null, value);
} }
}, },
updateModel(event, value) { updateModel(event, value) {

View File

@ -122,6 +122,11 @@ export interface ListboxProps {
* Default value is true. * Default value is true.
*/ */
autoOptionFocus?: boolean | undefined; autoOptionFocus?: boolean | undefined;
/**
* When enabled, the focused option is selected.
* Default value is false.
*/
selectOnFocus?: boolean | undefined;
/** /**
* Text to be displayed in hidden accessible field when filtering returns any results. Defaults to value from PrimeVue locale configuration. * 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'. * Default value is '{0} results are available'.

View File

@ -96,6 +96,10 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
selectOnFocus: {
type: Boolean,
default: false
},
filterMessage: { filterMessage: {
type: String, type: String,
default: null default: null
@ -135,7 +139,6 @@ export default {
startRangeIndex: -1, startRangeIndex: -1,
searchTimeout: null, searchTimeout: null,
searchValue: '', searchValue: '',
selectOnFocus: false,
focusOnHover: false, focusOnHover: false,
data() { data() {
return { return {
@ -598,7 +601,7 @@ export default {
this.scrollInView(); this.scrollInView();
if (this.selectOnFocus && !this.multiple) { if (this.selectOnFocus && !this.multiple) {
this.updateModel(event, this.getOptionValue(this.visibleOptions[index])); this.onOptionSelect(event, this.visibleOptions[index]);
} }
} }
}, },
@ -613,10 +616,9 @@ export default {
} }
}, },
autoUpdateModel() { autoUpdateModel() {
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) { if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption && !this.multiple) {
this.focusedOptionIndex = this.findFirstFocusedOptionIndex(); this.focusedOptionIndex = this.findFirstFocusedOptionIndex();
const value = this.getOptionValue(this.visibleOptions[this.focusedOptionIndex]); this.onOptionSelect(null, this.visibleOptions[this.focusedOptionIndex]);
this.updateModel(null, this.multiple ? [value] : value);
} }
}, },
updateModel(event, value) { updateModel(event, value) {

View File

@ -328,6 +328,12 @@ export default {
<td>true</td> <td>true</td>
<td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td> <td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td>
</tr> </tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, the focused option is selected.</td>
</tr>
<tr> <tr>
<td>searchLocale</td> <td>searchLocale</td>
<td>string</td> <td>string</td>

View File

@ -267,6 +267,12 @@ data() &#123;
<td>true</td> <td>true</td>
<td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td> <td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td>
</tr> </tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, the focused option is selected/opened.</td>
</tr>
<tr> <tr>
<td>searchLocale</td> <td>searchLocale</td>
<td>string</td> <td>string</td>

View File

@ -324,6 +324,12 @@ export default {
<td>true</td> <td>true</td>
<td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td> <td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td>
</tr> </tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, the focused option is selected.</td>
</tr>
<tr> <tr>
<td>filterMessage</td> <td>filterMessage</td>
<td>string</td> <td>string</td>

View File

@ -249,6 +249,12 @@ export default {
<td>true</td> <td>true</td>
<td>Whether to focus on the first visible or selected element.</td> <td>Whether to focus on the first visible or selected element.</td>
</tr> </tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, the focused option is selected.</td>
</tr>
<tr> <tr>
<td>filterMessage</td> <td>filterMessage</td>
<td>string</td> <td>string</td>