Fixed #5130 - Add focusOnHover props to some components
parent
f0880cda5a
commit
2072631cda
|
@ -30,7 +30,7 @@ const FilterService = {
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
startsWith(value, filter, filterLocale) {
|
startsWith(value, filter, filterLocale) {
|
||||||
if (filter === undefined || filter === null || filter.trim() === '') {
|
if (filter === undefined || filter === null || filter === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ const FilterService = {
|
||||||
return stringValue.slice(0, filterValue.length) === filterValue;
|
return stringValue.slice(0, filterValue.length) === filterValue;
|
||||||
},
|
},
|
||||||
contains(value, filter, filterLocale) {
|
contains(value, filter, filterLocale) {
|
||||||
if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
if (filter === undefined || filter === null || filter === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ const FilterService = {
|
||||||
return stringValue.indexOf(filterValue) !== -1;
|
return stringValue.indexOf(filterValue) !== -1;
|
||||||
},
|
},
|
||||||
notContains(value, filter, filterLocale) {
|
notContains(value, filter, filterLocale) {
|
||||||
if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
if (filter === undefined || filter === null || filter === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ const FilterService = {
|
||||||
return stringValue.indexOf(filterValue) === -1;
|
return stringValue.indexOf(filterValue) === -1;
|
||||||
},
|
},
|
||||||
endsWith(value, filter, filterLocale) {
|
endsWith(value, filter, filterLocale) {
|
||||||
if (filter === undefined || filter === null || filter.trim() === '') {
|
if (filter === undefined || filter === null || filter === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ const FilterService = {
|
||||||
return stringValue.indexOf(filterValue, stringValue.length - filterValue.length) !== -1;
|
return stringValue.indexOf(filterValue, stringValue.length - filterValue.length) !== -1;
|
||||||
},
|
},
|
||||||
equals(value, filter, filterLocale) {
|
equals(value, filter, filterLocale) {
|
||||||
if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
if (filter === undefined || filter === null || filter === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ const FilterService = {
|
||||||
else return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) == ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale);
|
else return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) == ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale);
|
||||||
},
|
},
|
||||||
notEquals(value, filter, filterLocale) {
|
notEquals(value, filter, filterLocale) {
|
||||||
if (filter === undefined || filter === null || (typeof filter === 'string' && filter.trim() === '')) {
|
if (filter === undefined || filter === null || filter === '') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -447,6 +447,11 @@ export interface AutoCompleteProps {
|
||||||
* @defaultValue false
|
* @defaultValue false
|
||||||
*/
|
*/
|
||||||
selectOnFocus?: boolean | undefined;
|
selectOnFocus?: boolean | undefined;
|
||||||
|
/**
|
||||||
|
* When enabled, the focus is placed on the hovered option.
|
||||||
|
* @defaultValue true
|
||||||
|
*/
|
||||||
|
focusOnHover?: 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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -197,11 +197,11 @@ export default {
|
||||||
overlay: null,
|
overlay: null,
|
||||||
virtualScroller: null,
|
virtualScroller: null,
|
||||||
searchTimeout: null,
|
searchTimeout: null,
|
||||||
focusOnHover: false,
|
|
||||||
dirty: false,
|
dirty: false,
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
id: this.$attrs.id,
|
id: this.$attrs.id,
|
||||||
|
clicked: false,
|
||||||
focused: false,
|
focused: false,
|
||||||
focusedOptionIndex: -1,
|
focusedOptionIndex: -1,
|
||||||
focusedMultipleOptionIndex: -1,
|
focusedMultipleOptionIndex: -1,
|
||||||
|
@ -298,6 +298,7 @@ export default {
|
||||||
this.$emit('before-hide');
|
this.$emit('before-hide');
|
||||||
this.dirty = isFocus;
|
this.dirty = isFocus;
|
||||||
this.overlayVisible = false;
|
this.overlayVisible = false;
|
||||||
|
this.clicked = false;
|
||||||
this.focusedOptionIndex = -1;
|
this.focusedOptionIndex = -1;
|
||||||
|
|
||||||
isFocus && DomHandler.focus(this.$refs.focusInput);
|
isFocus && DomHandler.focus(this.$refs.focusInput);
|
||||||
|
@ -319,8 +320,12 @@ export default {
|
||||||
|
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
this.focused = true;
|
this.focused = true;
|
||||||
|
|
||||||
|
if (this.overlayVisible) {
|
||||||
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
||||||
this.overlayVisible && this.scrollInView(this.focusedOptionIndex);
|
this.scrollInView(this.focusedOptionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
this.$emit('focus', event);
|
this.$emit('focus', event);
|
||||||
},
|
},
|
||||||
onBlur(event) {
|
onBlur(event) {
|
||||||
|
@ -394,6 +399,8 @@ export default {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = false;
|
||||||
},
|
},
|
||||||
onInput(event) {
|
onInput(event) {
|
||||||
if (this.searchTimeout) {
|
if (this.searchTimeout) {
|
||||||
|
@ -479,6 +486,8 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onContainerClick(event) {
|
onContainerClick(event) {
|
||||||
|
this.clicked = true;
|
||||||
|
|
||||||
if (this.disabled || this.searching || this.loading || this.isInputClicked(event) || this.isDropdownClicked(event)) {
|
if (this.disabled || this.searching || this.loading || this.isInputClicked(event) || this.isDropdownClicked(event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -545,7 +554,7 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.findFirstFocusedOptionIndex();
|
const optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findFirstOptionIndex() : this.findFirstFocusedOptionIndex();
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
|
||||||
|
@ -564,7 +573,7 @@ export default {
|
||||||
this.overlayVisible && this.hide();
|
this.overlayVisible && this.hide();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else {
|
} else {
|
||||||
const optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.findLastFocusedOptionIndex();
|
const optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findLastOptionIndex() : this.findLastFocusedOptionIndex();
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
|
||||||
|
@ -618,6 +627,7 @@ export default {
|
||||||
},
|
},
|
||||||
onEnterKey(event) {
|
onEnterKey(event) {
|
||||||
if (!this.overlayVisible) {
|
if (!this.overlayVisible) {
|
||||||
|
this.focusedOptionIndex = -1; // reset
|
||||||
this.onArrowDownKey(event);
|
this.onArrowDownKey(event);
|
||||||
} else {
|
} else {
|
||||||
if (this.focusedOptionIndex !== -1) {
|
if (this.focusedOptionIndex !== -1) {
|
||||||
|
@ -838,16 +848,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollInView(index = -1) {
|
scrollInView(index = -1) {
|
||||||
|
this.$nextTick(() => {
|
||||||
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
||||||
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
||||||
} else if (!this.virtualScrollerDisabled) {
|
} else if (!this.virtualScrollerDisabled) {
|
||||||
setTimeout(() => {
|
|
||||||
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
autoUpdateModel() {
|
autoUpdateModel() {
|
||||||
if ((this.selectOnFocus || this.autoHighlight) && this.autoOptionFocus && !this.hasSelectedOption) {
|
if ((this.selectOnFocus || this.autoHighlight) && this.autoOptionFocus && !this.hasSelectedOption) {
|
||||||
|
|
|
@ -133,6 +133,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
focusOnHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
searchLocale: {
|
searchLocale: {
|
||||||
type: String,
|
type: String,
|
||||||
default: undefined
|
default: undefined
|
||||||
|
|
|
@ -72,6 +72,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
focusOnHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
searchLocale: {
|
searchLocale: {
|
||||||
type: String,
|
type: String,
|
||||||
default: undefined
|
default: undefined
|
||||||
|
|
|
@ -343,6 +343,11 @@ export interface CascadeSelectProps {
|
||||||
* @defaultValue false
|
* @defaultValue false
|
||||||
*/
|
*/
|
||||||
selectOnFocus?: boolean | undefined;
|
selectOnFocus?: boolean | undefined;
|
||||||
|
/**
|
||||||
|
* When enabled, the focus is placed on the hovered option.
|
||||||
|
* @defaultValue true
|
||||||
|
*/
|
||||||
|
focusOnHover?: 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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
:optionGroupLabel="optionGroupLabel"
|
:optionGroupLabel="optionGroupLabel"
|
||||||
:optionGroupChildren="optionGroupChildren"
|
:optionGroupChildren="optionGroupChildren"
|
||||||
@option-change="onOptionChange"
|
@option-change="onOptionChange"
|
||||||
|
@option-focus-change="onOptionFocusChange"
|
||||||
:pt="pt"
|
:pt="pt"
|
||||||
:unstyled="unstyled"
|
:unstyled="unstyled"
|
||||||
/>
|
/>
|
||||||
|
@ -95,10 +96,10 @@ export default {
|
||||||
overlay: null,
|
overlay: null,
|
||||||
searchTimeout: null,
|
searchTimeout: null,
|
||||||
searchValue: null,
|
searchValue: null,
|
||||||
focusOnHover: false,
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
id: this.$attrs.id,
|
id: this.$attrs.id,
|
||||||
|
clicked: false,
|
||||||
focused: false,
|
focused: false,
|
||||||
focusedOptionInfo: { index: -1, level: 0, parentKey: '' },
|
focusedOptionInfo: { index: -1, level: 0, parentKey: '' },
|
||||||
activeOptionPath: [],
|
activeOptionPath: [],
|
||||||
|
@ -169,9 +170,9 @@ export default {
|
||||||
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];
|
||||||
|
|
||||||
this.focusedOptionInfo = { index: this.autoOptionFocus ? processedOption.index : -1, level: processedOption.level, parentKey: processedOption.parentKey };
|
this.focusedOptionInfo = { index: processedOption.index, level: processedOption.level, parentKey: processedOption.parentKey };
|
||||||
} else {
|
} else {
|
||||||
this.focusedOptionInfo = { index: this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1, level: 0, parentKey: '' };
|
this.focusedOptionInfo = { index: this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : this.findSelectedOptionIndex(), level: 0, parentKey: '' };
|
||||||
}
|
}
|
||||||
|
|
||||||
isFocus && DomHandler.focus(this.$refs.focusInput);
|
isFocus && DomHandler.focus(this.$refs.focusInput);
|
||||||
|
@ -180,6 +181,7 @@ export default {
|
||||||
const _hide = () => {
|
const _hide = () => {
|
||||||
this.$emit('before-hide');
|
this.$emit('before-hide');
|
||||||
this.overlayVisible = false;
|
this.overlayVisible = false;
|
||||||
|
this.clicked = false;
|
||||||
this.activeOptionPath = [];
|
this.activeOptionPath = [];
|
||||||
this.focusedOptionInfo = { index: -1, level: 0, parentKey: '' };
|
this.focusedOptionInfo = { index: -1, level: 0, parentKey: '' };
|
||||||
|
|
||||||
|
@ -272,6 +274,8 @@ export default {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = false;
|
||||||
},
|
},
|
||||||
onOptionChange(event) {
|
onOptionChange(event) {
|
||||||
const { originalEvent, processedOption, isFocus, isHide } = event;
|
const { originalEvent, processedOption, isFocus, isHide } = event;
|
||||||
|
@ -285,12 +289,21 @@ export default {
|
||||||
|
|
||||||
activeOptionPath.push(processedOption);
|
activeOptionPath.push(processedOption);
|
||||||
|
|
||||||
this.focusedOptionInfo = originalEvent?.type === 'click' ? { index: -1, level, parentKey } : { index, level, parentKey };
|
this.focusedOptionInfo = { index, level, parentKey };
|
||||||
this.activeOptionPath = activeOptionPath;
|
this.activeOptionPath = activeOptionPath;
|
||||||
|
|
||||||
grouped ? this.onOptionGroupSelect(originalEvent, processedOption) : this.onOptionSelect(originalEvent, processedOption, isHide);
|
grouped ? this.onOptionGroupSelect(originalEvent, processedOption) : this.onOptionSelect(originalEvent, processedOption, isHide);
|
||||||
isFocus && DomHandler.focus(this.$refs.focusInput);
|
isFocus && DomHandler.focus(this.$refs.focusInput);
|
||||||
},
|
},
|
||||||
|
onOptionFocusChange(event) {
|
||||||
|
if (this.focusOnHover) {
|
||||||
|
const { originalEvent, processedOption } = event;
|
||||||
|
const { index, level, parentKey } = processedOption;
|
||||||
|
|
||||||
|
this.focusedOptionInfo = { index, level, parentKey };
|
||||||
|
this.changeFocusedOptionIndex(originalEvent, index);
|
||||||
|
}
|
||||||
|
},
|
||||||
onOptionSelect(event, processedOption, isHide = true) {
|
onOptionSelect(event, processedOption, isHide = true) {
|
||||||
const value = this.getOptionValue(processedOption?.option);
|
const value = this.getOptionValue(processedOption?.option);
|
||||||
|
|
||||||
|
@ -312,6 +325,7 @@ export default {
|
||||||
DomHandler.focus(this.$refs.focusInput);
|
DomHandler.focus(this.$refs.focusInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = true;
|
||||||
this.$emit('click', event);
|
this.$emit('click', event);
|
||||||
},
|
},
|
||||||
onOverlayClick(event) {
|
onOverlayClick(event) {
|
||||||
|
@ -331,11 +345,14 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onArrowDownKey(event) {
|
onArrowDownKey(event) {
|
||||||
const optionIndex = this.focusedOptionInfo.index !== -1 ? this.findNextOptionIndex(this.focusedOptionInfo.index) : this.findFirstFocusedOptionIndex();
|
if (!this.overlayVisible) {
|
||||||
|
this.show();
|
||||||
|
} else {
|
||||||
|
const optionIndex = this.focusedOptionInfo.index !== -1 ? this.findNextOptionIndex(this.focusedOptionInfo.index) : this.clicked ? this.findFirstOptionIndex() : this.findFirstFocusedOptionIndex();
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
!this.overlayVisible && this.show();
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
onArrowUpKey(event) {
|
onArrowUpKey(event) {
|
||||||
|
@ -350,7 +367,7 @@ export default {
|
||||||
this.overlayVisible && this.hide();
|
this.overlayVisible && this.hide();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else {
|
} else {
|
||||||
const optionIndex = this.focusedOptionInfo.index !== -1 ? this.findPrevOptionIndex(this.focusedOptionInfo.index) : this.findLastFocusedOptionIndex();
|
const optionIndex = this.focusedOptionInfo.index !== -1 ? this.findPrevOptionIndex(this.focusedOptionInfo.index) : this.clicked ? this.findLastOptionIndex() : this.findLastFocusedOptionIndex();
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
|
||||||
|
@ -412,6 +429,7 @@ export default {
|
||||||
},
|
},
|
||||||
onEnterKey(event) {
|
onEnterKey(event) {
|
||||||
if (!this.overlayVisible) {
|
if (!this.overlayVisible) {
|
||||||
|
this.focusedOptionInfo.index !== -1; // reset
|
||||||
this.onArrowDownKey(event);
|
this.onArrowDownKey(event);
|
||||||
} else {
|
} else {
|
||||||
if (this.focusedOptionInfo.index !== -1) {
|
if (this.focusedOptionInfo.index !== -1) {
|
||||||
|
@ -595,6 +613,7 @@ export default {
|
||||||
let optionIndex = -1;
|
let optionIndex = -1;
|
||||||
let matched = false;
|
let matched = false;
|
||||||
|
|
||||||
|
if (ObjectUtils.isNotEmpty(this.searchValue)) {
|
||||||
if (this.focusedOptionInfo.index !== -1) {
|
if (this.focusedOptionInfo.index !== -1) {
|
||||||
optionIndex = this.visibleOptions.slice(this.focusedOptionInfo.index).findIndex((processedOption) => this.isOptionMatched(processedOption));
|
optionIndex = this.visibleOptions.slice(this.focusedOptionInfo.index).findIndex((processedOption) => this.isOptionMatched(processedOption));
|
||||||
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionInfo.index).findIndex((processedOption) => this.isOptionMatched(processedOption)) : optionIndex + this.focusedOptionInfo.index;
|
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionInfo.index).findIndex((processedOption) => this.isOptionMatched(processedOption)) : optionIndex + this.focusedOptionInfo.index;
|
||||||
|
@ -613,6 +632,7 @@ export default {
|
||||||
if (optionIndex !== -1) {
|
if (optionIndex !== -1) {
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.searchTimeout) {
|
if (this.searchTimeout) {
|
||||||
clearTimeout(this.searchTimeout);
|
clearTimeout(this.searchTimeout);
|
||||||
|
@ -636,12 +656,14 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollInView(index = -1) {
|
scrollInView(index = -1) {
|
||||||
|
this.$nextTick(() => {
|
||||||
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
||||||
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
autoUpdateModel() {
|
autoUpdateModel() {
|
||||||
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
|
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
:data-p-focus="isOptionFocused(processedOption)"
|
:data-p-focus="isOptionFocused(processedOption)"
|
||||||
:data-p-disabled="isOptionDisabled(processedOption)"
|
:data-p-disabled="isOptionDisabled(processedOption)"
|
||||||
>
|
>
|
||||||
<div v-ripple :class="cx('content')" @click="onOptionClick($event, processedOption)" v-bind="getPTOptions(processedOption, index, 'content')">
|
<div v-ripple :class="cx('content')" @click="onOptionClick($event, processedOption)" @mousemove="onOptionMouseMove($event, processedOption)" v-bind="getPTOptions(processedOption, index, 'content')">
|
||||||
<component v-if="templates['option']" :is="templates['option']" :option="processedOption.option" />
|
<component v-if="templates['option']" :is="templates['option']" :option="processedOption.option" />
|
||||||
<span v-else :class="cx('text')" v-bind="getPTOptions(processedOption, index, 'text')">{{ getOptionLabelToRender(processedOption) }}</span>
|
<span v-else :class="cx('text')" v-bind="getPTOptions(processedOption, index, 'text')">{{ getOptionLabelToRender(processedOption) }}</span>
|
||||||
<template v-if="isOptionGroup(processedOption)">
|
<template v-if="isOptionGroup(processedOption)">
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
:optionGroupLabel="optionGroupLabel"
|
:optionGroupLabel="optionGroupLabel"
|
||||||
:optionGroupChildren="optionGroupChildren"
|
:optionGroupChildren="optionGroupChildren"
|
||||||
@option-change="onOptionChange"
|
@option-change="onOptionChange"
|
||||||
|
@option-focus-change="onOptionFocusChange"
|
||||||
:pt="pt"
|
:pt="pt"
|
||||||
:unstyled="unstyled"
|
:unstyled="unstyled"
|
||||||
:isParentMount="mounted"
|
:isParentMount="mounted"
|
||||||
|
@ -62,7 +63,7 @@ export default {
|
||||||
name: 'CascadeSelectSub',
|
name: 'CascadeSelectSub',
|
||||||
hostName: 'CascadeSelect',
|
hostName: 'CascadeSelect',
|
||||||
extends: BaseComponent,
|
extends: BaseComponent,
|
||||||
emits: ['option-change'],
|
emits: ['option-change', 'option-focus-change'],
|
||||||
container: null,
|
container: null,
|
||||||
props: {
|
props: {
|
||||||
selectId: String,
|
selectId: String,
|
||||||
|
@ -149,9 +150,15 @@ export default {
|
||||||
onOptionClick(event, processedOption) {
|
onOptionClick(event, processedOption) {
|
||||||
this.$emit('option-change', { originalEvent: event, processedOption, isFocus: true });
|
this.$emit('option-change', { originalEvent: event, processedOption, isFocus: true });
|
||||||
},
|
},
|
||||||
|
onOptionMouseMove(event, processedOption) {
|
||||||
|
this.$emit('option-focus-change', { originalEvent: event, processedOption });
|
||||||
|
},
|
||||||
onOptionChange(event) {
|
onOptionChange(event) {
|
||||||
this.$emit('option-change', event);
|
this.$emit('option-change', event);
|
||||||
},
|
},
|
||||||
|
onOptionFocusChange(event) {
|
||||||
|
this.$emit('option-focus-change', event);
|
||||||
|
},
|
||||||
containerRef(el) {
|
containerRef(el) {
|
||||||
this.container = el;
|
this.container = el;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
focusOnHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
filterMessage: {
|
filterMessage: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
|
|
|
@ -413,6 +413,11 @@ export interface DropdownProps {
|
||||||
* @defaultValue false
|
* @defaultValue false
|
||||||
*/
|
*/
|
||||||
selectOnFocus?: boolean | undefined;
|
selectOnFocus?: boolean | undefined;
|
||||||
|
/**
|
||||||
|
* When enabled, the focus is placed on the hovered option.
|
||||||
|
* @defaultValue true
|
||||||
|
*/
|
||||||
|
focusOnHover?: 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.
|
||||||
* @defaultValue '{0} results are available'
|
* @defaultValue '{0} results are available'
|
||||||
|
|
|
@ -194,10 +194,10 @@ export default {
|
||||||
searchTimeout: null,
|
searchTimeout: null,
|
||||||
searchValue: null,
|
searchValue: null,
|
||||||
isModelValueChanged: false,
|
isModelValueChanged: false,
|
||||||
focusOnHover: false,
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
id: this.$attrs.id,
|
id: this.$attrs.id,
|
||||||
|
clicked: false,
|
||||||
focused: false,
|
focused: false,
|
||||||
focusedOptionIndex: -1,
|
focusedOptionIndex: -1,
|
||||||
filterValue: null,
|
filterValue: null,
|
||||||
|
@ -284,7 +284,7 @@ export default {
|
||||||
show(isFocus) {
|
show(isFocus) {
|
||||||
this.$emit('before-show');
|
this.$emit('before-show');
|
||||||
this.overlayVisible = true;
|
this.overlayVisible = true;
|
||||||
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : this.editable ? -1 : this.findSelectedOptionIndex();
|
||||||
|
|
||||||
isFocus && DomHandler.focus(this.$refs.focusInput);
|
isFocus && DomHandler.focus(this.$refs.focusInput);
|
||||||
},
|
},
|
||||||
|
@ -292,6 +292,7 @@ export default {
|
||||||
const _hide = () => {
|
const _hide = () => {
|
||||||
this.$emit('before-hide');
|
this.$emit('before-hide');
|
||||||
this.overlayVisible = false;
|
this.overlayVisible = false;
|
||||||
|
this.clicked = false;
|
||||||
this.focusedOptionIndex = -1;
|
this.focusedOptionIndex = -1;
|
||||||
this.searchValue = '';
|
this.searchValue = '';
|
||||||
|
|
||||||
|
@ -310,8 +311,12 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.focused = true;
|
this.focused = true;
|
||||||
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
|
||||||
this.overlayVisible && this.scrollInView(this.focusedOptionIndex);
|
if (this.overlayVisible) {
|
||||||
|
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : this.editable ? -1 : this.findSelectedOptionIndex();
|
||||||
|
this.scrollInView(this.focusedOptionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
this.$emit('focus', event);
|
this.$emit('focus', event);
|
||||||
},
|
},
|
||||||
onBlur(event) {
|
onBlur(event) {
|
||||||
|
@ -396,6 +401,8 @@ export default {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = false;
|
||||||
},
|
},
|
||||||
onEditableInput(event) {
|
onEditableInput(event) {
|
||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
|
@ -419,6 +426,8 @@ export default {
|
||||||
} else if (!this.overlay || !this.overlay.contains(event.target)) {
|
} else if (!this.overlay || !this.overlay.contains(event.target)) {
|
||||||
this.overlayVisible ? this.hide(true) : this.show(true);
|
this.overlayVisible ? this.hide(true) : this.show(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = true;
|
||||||
},
|
},
|
||||||
onClearClick(event) {
|
onClearClick(event) {
|
||||||
this.updateModel(event, null);
|
this.updateModel(event, null);
|
||||||
|
@ -525,11 +534,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onArrowDownKey(event) {
|
onArrowDownKey(event) {
|
||||||
const optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.findFirstFocusedOptionIndex();
|
if (!this.overlayVisible) {
|
||||||
|
this.show();
|
||||||
|
this.editable && this.changeFocusedOptionIndex(event, this.findSelectedOptionIndex());
|
||||||
|
} else {
|
||||||
|
const optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findFirstOptionIndex() : this.findFirstFocusedOptionIndex();
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
!this.overlayVisible && this.show();
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
onArrowUpKey(event, pressedInInputText = false) {
|
onArrowUpKey(event, pressedInInputText = false) {
|
||||||
|
@ -541,7 +554,7 @@ export default {
|
||||||
this.overlayVisible && this.hide();
|
this.overlayVisible && this.hide();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else {
|
} else {
|
||||||
const optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.findLastFocusedOptionIndex();
|
const optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findLastOptionIndex() : this.findLastFocusedOptionIndex();
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
|
||||||
|
@ -589,6 +602,7 @@ export default {
|
||||||
},
|
},
|
||||||
onEnterKey(event) {
|
onEnterKey(event) {
|
||||||
if (!this.overlayVisible) {
|
if (!this.overlayVisible) {
|
||||||
|
this.focusedOptionIndex = -1; // reset
|
||||||
this.onArrowDownKey(event);
|
this.onArrowDownKey(event);
|
||||||
} else {
|
} else {
|
||||||
if (this.focusedOptionIndex !== -1) {
|
if (this.focusedOptionIndex !== -1) {
|
||||||
|
@ -784,6 +798,7 @@ export default {
|
||||||
let optionIndex = -1;
|
let optionIndex = -1;
|
||||||
let matched = false;
|
let matched = false;
|
||||||
|
|
||||||
|
if (ObjectUtils.isNotEmpty(this.searchValue)) {
|
||||||
if (this.focusedOptionIndex !== -1) {
|
if (this.focusedOptionIndex !== -1) {
|
||||||
optionIndex = this.visibleOptions.slice(this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option));
|
optionIndex = this.visibleOptions.slice(this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option));
|
||||||
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option)) : optionIndex + this.focusedOptionIndex;
|
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option)) : optionIndex + this.focusedOptionIndex;
|
||||||
|
@ -802,6 +817,7 @@ export default {
|
||||||
if (optionIndex !== -1) {
|
if (optionIndex !== -1) {
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.searchTimeout) {
|
if (this.searchTimeout) {
|
||||||
clearTimeout(this.searchTimeout);
|
clearTimeout(this.searchTimeout);
|
||||||
|
@ -825,16 +841,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollInView(index = -1) {
|
scrollInView(index = -1) {
|
||||||
|
this.$nextTick(() => {
|
||||||
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
||||||
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
|
||||||
} else if (!this.virtualScrollerDisabled) {
|
} else if (!this.virtualScrollerDisabled) {
|
||||||
setTimeout(() => {
|
|
||||||
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
autoUpdateModel() {
|
autoUpdateModel() {
|
||||||
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
|
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
|
||||||
|
|
|
@ -51,6 +51,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
focusOnHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
filterMessage: {
|
filterMessage: {
|
||||||
type: String,
|
type: String,
|
||||||
default: null
|
default: null
|
||||||
|
|
|
@ -301,6 +301,11 @@ export interface ListboxProps {
|
||||||
* @defaultValue false
|
* @defaultValue false
|
||||||
*/
|
*/
|
||||||
selectOnFocus?: boolean | undefined;
|
selectOnFocus?: boolean | undefined;
|
||||||
|
/**
|
||||||
|
* When enabled, the focus is placed on the hovered option.
|
||||||
|
* @defaultValue true
|
||||||
|
*/
|
||||||
|
focusOnHover?: 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.
|
||||||
* @defaultValue '{0} results are available'
|
* @defaultValue '{0} results are available'
|
||||||
|
|
|
@ -139,7 +139,6 @@ export default {
|
||||||
startRangeIndex: -1,
|
startRangeIndex: -1,
|
||||||
searchTimeout: null,
|
searchTimeout: null,
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
focusOnHover: false,
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
id: this.$attrs.id,
|
id: this.$attrs.id,
|
||||||
|
@ -228,7 +227,7 @@ export default {
|
||||||
},
|
},
|
||||||
onListFocus(event) {
|
onListFocus(event) {
|
||||||
this.focused = true;
|
this.focused = true;
|
||||||
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : this.findSelectedOptionIndex();
|
||||||
this.autoUpdateModel();
|
this.autoUpdateModel();
|
||||||
this.$emit('focus', event);
|
this.$emit('focus', event);
|
||||||
},
|
},
|
||||||
|
@ -306,13 +305,13 @@ export default {
|
||||||
|
|
||||||
this.multiple ? this.onOptionSelectMultiple(event, option) : this.onOptionSelectSingle(event, option);
|
this.multiple ? this.onOptionSelectMultiple(event, option) : this.onOptionSelectSingle(event, option);
|
||||||
this.optionTouched = false;
|
this.optionTouched = false;
|
||||||
index !== -1 && (this.focusedOptionIndex = event?.type === 'click' ? -1 : index);
|
index !== -1 && (this.focusedOptionIndex = index);
|
||||||
},
|
},
|
||||||
onOptionMouseDown(event, index) {
|
onOptionMouseDown(event, index) {
|
||||||
this.changeFocusedOptionIndex(event, index);
|
this.changeFocusedOptionIndex(event, index);
|
||||||
},
|
},
|
||||||
onOptionMouseMove(event, index) {
|
onOptionMouseMove(event, index) {
|
||||||
if (this.focusOnHover) {
|
if (this.focusOnHover && this.focused) {
|
||||||
this.changeFocusedOptionIndex(event, index);
|
this.changeFocusedOptionIndex(event, index);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -520,11 +519,14 @@ export default {
|
||||||
isValidSelectedOption(option) {
|
isValidSelectedOption(option) {
|
||||||
return this.isValidOption(option) && this.isSelected(option);
|
return this.isValidOption(option) && this.isSelected(option);
|
||||||
},
|
},
|
||||||
|
isEquals(value1, value2) {
|
||||||
|
return ObjectUtils.equals(value1, value2, this.equalityKey);
|
||||||
|
},
|
||||||
isSelected(option) {
|
isSelected(option) {
|
||||||
const optionValue = this.getOptionValue(option);
|
const optionValue = this.getOptionValue(option);
|
||||||
|
|
||||||
if (this.multiple) return (this.modelValue || []).some((value) => ObjectUtils.equals(value, optionValue, this.equalityKey));
|
if (this.multiple) return (this.modelValue || []).some((value) => this.isEquals(value, optionValue));
|
||||||
else return ObjectUtils.equals(this.modelValue, optionValue, this.equalityKey);
|
else return this.isEquals(this.modelValue, optionValue);
|
||||||
},
|
},
|
||||||
findFirstOptionIndex() {
|
findFirstOptionIndex() {
|
||||||
return this.visibleOptions.findIndex((option) => this.isValidOption(option));
|
return this.visibleOptions.findIndex((option) => this.isValidOption(option));
|
||||||
|
@ -542,6 +544,22 @@ export default {
|
||||||
|
|
||||||
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
||||||
},
|
},
|
||||||
|
findSelectedOptionIndex() {
|
||||||
|
if (this.hasSelectedOption) {
|
||||||
|
if (this.multiple) {
|
||||||
|
for (let index = this.modelValue.length - 1; index >= 0; index--) {
|
||||||
|
const value = this.modelValue[index];
|
||||||
|
const matchedOptionIndex = this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option) && this.isEquals(value, this.getOptionValue(option)));
|
||||||
|
|
||||||
|
if (matchedOptionIndex > -1) return matchedOptionIndex;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
findFirstSelectedOptionIndex() {
|
findFirstSelectedOptionIndex() {
|
||||||
return this.hasSelectedOption ? this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
return this.hasSelectedOption ? this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
||||||
},
|
},
|
||||||
|
@ -588,6 +606,7 @@ export default {
|
||||||
|
|
||||||
let optionIndex = -1;
|
let optionIndex = -1;
|
||||||
|
|
||||||
|
if (ObjectUtils.isNotEmpty(this.searchValue)) {
|
||||||
if (this.focusedOptionIndex !== -1) {
|
if (this.focusedOptionIndex !== -1) {
|
||||||
optionIndex = this.visibleOptions.slice(this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option));
|
optionIndex = this.visibleOptions.slice(this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option));
|
||||||
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option)) : optionIndex + this.focusedOptionIndex;
|
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option)) : optionIndex + this.focusedOptionIndex;
|
||||||
|
@ -602,6 +621,7 @@ export default {
|
||||||
if (optionIndex !== -1) {
|
if (optionIndex !== -1) {
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.searchTimeout) {
|
if (this.searchTimeout) {
|
||||||
clearTimeout(this.searchTimeout);
|
clearTimeout(this.searchTimeout);
|
||||||
|
@ -626,6 +646,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollInView(index = -1) {
|
scrollInView(index = -1) {
|
||||||
|
this.$nextTick(() => {
|
||||||
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
||||||
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
||||||
|
|
||||||
|
@ -634,6 +655,7 @@ export default {
|
||||||
} else if (!this.virtualScrollerDisabled) {
|
} else if (!this.virtualScrollerDisabled) {
|
||||||
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
autoUpdateModel() {
|
autoUpdateModel() {
|
||||||
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption && !this.multiple && this.focused) {
|
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption && !this.multiple && this.focused) {
|
||||||
|
|
|
@ -131,6 +131,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
focusOnHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
highlightOnSelect: {
|
highlightOnSelect: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
|
|
@ -478,6 +478,11 @@ export interface MultiSelectProps {
|
||||||
* @defaultValue false
|
* @defaultValue false
|
||||||
*/
|
*/
|
||||||
autoFilterFocus?: boolean | undefined;
|
autoFilterFocus?: boolean | undefined;
|
||||||
|
/**
|
||||||
|
* When enabled, the focus is placed on the hovered option.
|
||||||
|
* @defaultValue true
|
||||||
|
*/
|
||||||
|
focusOnHover?: boolean | undefined;
|
||||||
/**
|
/**
|
||||||
* Highlights automatically the first item.
|
* Highlights automatically the first item.
|
||||||
* @defaultValue false
|
* @defaultValue false
|
||||||
|
|
|
@ -223,10 +223,10 @@ export default {
|
||||||
searchTimeout: null,
|
searchTimeout: null,
|
||||||
searchValue: '',
|
searchValue: '',
|
||||||
selectOnFocus: false,
|
selectOnFocus: false,
|
||||||
focusOnHover: false,
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
id: this.$attrs.id,
|
id: this.$attrs.id,
|
||||||
|
clicked: false,
|
||||||
focused: false,
|
focused: false,
|
||||||
focusedOptionIndex: -1,
|
focusedOptionIndex: -1,
|
||||||
filterValue: null,
|
filterValue: null,
|
||||||
|
@ -312,7 +312,7 @@ export default {
|
||||||
show(isFocus) {
|
show(isFocus) {
|
||||||
this.$emit('before-show');
|
this.$emit('before-show');
|
||||||
this.overlayVisible = true;
|
this.overlayVisible = true;
|
||||||
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : this.findSelectedOptionIndex();
|
||||||
|
|
||||||
isFocus && DomHandler.focus(this.$refs.focusInput);
|
isFocus && DomHandler.focus(this.$refs.focusInput);
|
||||||
},
|
},
|
||||||
|
@ -320,6 +320,7 @@ export default {
|
||||||
const _hide = () => {
|
const _hide = () => {
|
||||||
this.$emit('before-hide');
|
this.$emit('before-hide');
|
||||||
this.overlayVisible = false;
|
this.overlayVisible = false;
|
||||||
|
this.clicked = false;
|
||||||
this.focusedOptionIndex = -1;
|
this.focusedOptionIndex = -1;
|
||||||
this.searchValue = '';
|
this.searchValue = '';
|
||||||
|
|
||||||
|
@ -338,11 +339,16 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.focused = true;
|
this.focused = true;
|
||||||
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
|
|
||||||
this.overlayVisible && this.scrollInView(this.focusedOptionIndex);
|
if (this.overlayVisible) {
|
||||||
|
this.focusedOptionIndex = this.focusedOptionIndex !== -1 ? this.focusedOptionIndex : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : this.findSelectedOptionIndex();
|
||||||
|
this.scrollInView(this.focusedOptionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
this.$emit('focus', event);
|
this.$emit('focus', event);
|
||||||
},
|
},
|
||||||
onBlur(event) {
|
onBlur(event) {
|
||||||
|
this.clicked = false;
|
||||||
this.focused = false;
|
this.focused = false;
|
||||||
this.focusedOptionIndex = -1;
|
this.focusedOptionIndex = -1;
|
||||||
this.searchValue = '';
|
this.searchValue = '';
|
||||||
|
@ -419,6 +425,8 @@ export default {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = false;
|
||||||
},
|
},
|
||||||
onContainerClick(event) {
|
onContainerClick(event) {
|
||||||
if (this.disabled || this.loading) {
|
if (this.disabled || this.loading) {
|
||||||
|
@ -428,6 +436,8 @@ export default {
|
||||||
if (!this.overlay || !this.overlay.contains(event.target)) {
|
if (!this.overlay || !this.overlay.contains(event.target)) {
|
||||||
this.overlayVisible ? this.hide(true) : this.show(true);
|
this.overlayVisible ? this.hide(true) : this.show(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.clicked = true;
|
||||||
},
|
},
|
||||||
onFirstHiddenFocus(event) {
|
onFirstHiddenFocus(event) {
|
||||||
const focusableEl = event.relatedTarget === this.$refs.focusInput ? DomHandler.getFirstFocusableElement(this.overlay, ':not([data-p-hidden-focusable="true"])') : this.$refs.focusInput;
|
const focusableEl = event.relatedTarget === this.$refs.focusInput ? DomHandler.getFirstFocusableElement(this.overlay, ':not([data-p-hidden-focusable="true"])') : this.$refs.focusInput;
|
||||||
|
@ -454,7 +464,7 @@ export default {
|
||||||
else value = [...(this.modelValue || []), this.getOptionValue(option)];
|
else value = [...(this.modelValue || []), this.getOptionValue(option)];
|
||||||
|
|
||||||
this.updateModel(event, value);
|
this.updateModel(event, value);
|
||||||
index !== -1 && (this.focusedOptionIndex = event?.type === 'click' ? -1 : index);
|
index !== -1 && (this.focusedOptionIndex = index);
|
||||||
isFocus && DomHandler.focus(this.$refs.focusInput);
|
isFocus && DomHandler.focus(this.$refs.focusInput);
|
||||||
},
|
},
|
||||||
onOptionMouseMove(event, index) {
|
onOptionMouseMove(event, index) {
|
||||||
|
@ -551,15 +561,18 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onArrowDownKey(event) {
|
onArrowDownKey(event) {
|
||||||
const optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.findFirstFocusedOptionIndex();
|
if (!this.overlayVisible) {
|
||||||
|
this.show();
|
||||||
|
} else {
|
||||||
|
const optionIndex = this.focusedOptionIndex !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findFirstOptionIndex() : this.findFirstFocusedOptionIndex();
|
||||||
|
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
this.onOptionSelectRange(event, this.startRangeIndex, optionIndex);
|
this.onOptionSelectRange(event, this.startRangeIndex, optionIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
!this.overlayVisible && this.show();
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
onArrowUpKey(event, pressedInInputText = false) {
|
onArrowUpKey(event, pressedInInputText = false) {
|
||||||
|
@ -571,7 +584,7 @@ export default {
|
||||||
this.overlayVisible && this.hide();
|
this.overlayVisible && this.hide();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else {
|
} else {
|
||||||
const optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.findLastFocusedOptionIndex();
|
const optionIndex = this.focusedOptionIndex !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex) : this.clicked ? this.findLastOptionIndex() : this.findLastFocusedOptionIndex();
|
||||||
|
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey) {
|
||||||
this.onOptionSelectRange(event, optionIndex, this.startRangeIndex);
|
this.onOptionSelectRange(event, optionIndex, this.startRangeIndex);
|
||||||
|
@ -642,6 +655,7 @@ export default {
|
||||||
},
|
},
|
||||||
onEnterKey(event) {
|
onEnterKey(event) {
|
||||||
if (!this.overlayVisible) {
|
if (!this.overlayVisible) {
|
||||||
|
this.focusedOptionIndex = -1; // reset
|
||||||
this.onArrowDownKey(event);
|
this.onArrowDownKey(event);
|
||||||
} else {
|
} else {
|
||||||
if (this.focusedOptionIndex !== -1) {
|
if (this.focusedOptionIndex !== -1) {
|
||||||
|
@ -807,10 +821,13 @@ export default {
|
||||||
isValidSelectedOption(option) {
|
isValidSelectedOption(option) {
|
||||||
return this.isValidOption(option) && this.isSelected(option);
|
return this.isValidOption(option) && this.isSelected(option);
|
||||||
},
|
},
|
||||||
|
isEquals(value1, value2) {
|
||||||
|
return ObjectUtils.equals(value1, value2, this.equalityKey);
|
||||||
|
},
|
||||||
isSelected(option) {
|
isSelected(option) {
|
||||||
const optionValue = this.getOptionValue(option);
|
const optionValue = this.getOptionValue(option);
|
||||||
|
|
||||||
return (this.modelValue || []).some((value) => ObjectUtils.equals(value, optionValue, this.equalityKey));
|
return (this.modelValue || []).some((value) => this.isEquals(value, optionValue));
|
||||||
},
|
},
|
||||||
findFirstOptionIndex() {
|
findFirstOptionIndex() {
|
||||||
return this.visibleOptions.findIndex((option) => this.isValidOption(option));
|
return this.visibleOptions.findIndex((option) => this.isValidOption(option));
|
||||||
|
@ -828,6 +845,18 @@ export default {
|
||||||
|
|
||||||
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
||||||
},
|
},
|
||||||
|
findSelectedOptionIndex() {
|
||||||
|
if (this.hasSelectedOption) {
|
||||||
|
for (let index = this.modelValue.length - 1; index >= 0; index--) {
|
||||||
|
const value = this.modelValue[index];
|
||||||
|
const matchedOptionIndex = this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option) && this.isEquals(value, this.getOptionValue(option)));
|
||||||
|
|
||||||
|
if (matchedOptionIndex > -1) return matchedOptionIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
findFirstSelectedOptionIndex() {
|
findFirstSelectedOptionIndex() {
|
||||||
return this.hasSelectedOption ? this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
return this.hasSelectedOption ? this.visibleOptions.findIndex((option) => this.isValidSelectedOption(option)) : -1;
|
||||||
},
|
},
|
||||||
|
@ -860,12 +889,12 @@ export default {
|
||||||
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
return matchedOptionIndex > -1 ? matchedOptionIndex : index;
|
||||||
},
|
},
|
||||||
findFirstFocusedOptionIndex() {
|
findFirstFocusedOptionIndex() {
|
||||||
const selectedIndex = this.findFirstSelectedOptionIndex();
|
const selectedIndex = this.findSelectedOptionIndex();
|
||||||
|
|
||||||
return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
|
return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
|
||||||
},
|
},
|
||||||
findLastFocusedOptionIndex() {
|
findLastFocusedOptionIndex() {
|
||||||
const selectedIndex = this.findLastSelectedOptionIndex();
|
const selectedIndex = this.findSelectedOptionIndex();
|
||||||
|
|
||||||
return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
|
return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
|
||||||
},
|
},
|
||||||
|
@ -874,6 +903,7 @@ export default {
|
||||||
|
|
||||||
let optionIndex = -1;
|
let optionIndex = -1;
|
||||||
|
|
||||||
|
if (ObjectUtils.isNotEmpty(this.searchValue)) {
|
||||||
if (this.focusedOptionIndex !== -1) {
|
if (this.focusedOptionIndex !== -1) {
|
||||||
optionIndex = this.visibleOptions.slice(this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option));
|
optionIndex = this.visibleOptions.slice(this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option));
|
||||||
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option)) : optionIndex + this.focusedOptionIndex;
|
optionIndex = optionIndex === -1 ? this.visibleOptions.slice(0, this.focusedOptionIndex).findIndex((option) => this.isOptionMatched(option)) : optionIndex + this.focusedOptionIndex;
|
||||||
|
@ -888,6 +918,7 @@ export default {
|
||||||
if (optionIndex !== -1) {
|
if (optionIndex !== -1) {
|
||||||
this.changeFocusedOptionIndex(event, optionIndex);
|
this.changeFocusedOptionIndex(event, optionIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.searchTimeout) {
|
if (this.searchTimeout) {
|
||||||
clearTimeout(this.searchTimeout);
|
clearTimeout(this.searchTimeout);
|
||||||
|
@ -902,9 +933,14 @@ export default {
|
||||||
if (this.focusedOptionIndex !== index) {
|
if (this.focusedOptionIndex !== index) {
|
||||||
this.focusedOptionIndex = index;
|
this.focusedOptionIndex = index;
|
||||||
this.scrollInView();
|
this.scrollInView();
|
||||||
|
|
||||||
|
if (this.selectOnFocus) {
|
||||||
|
this.onOptionSelect(event, this.visibleOptions[index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollInView(index = -1) {
|
scrollInView(index = -1) {
|
||||||
|
this.$nextTick(() => {
|
||||||
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
|
||||||
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
const element = DomHandler.findSingle(this.list, `li[id="${id}"]`);
|
||||||
|
|
||||||
|
@ -913,6 +949,7 @@ export default {
|
||||||
} else if (!this.virtualScrollerDisabled) {
|
} else if (!this.virtualScrollerDisabled) {
|
||||||
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
this.virtualScroller && this.virtualScroller.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
autoUpdateModel() {
|
autoUpdateModel() {
|
||||||
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
|
if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption) {
|
||||||
|
|
|
@ -161,6 +161,9 @@ export default {
|
||||||
scrollToIndex(index, behavior = 'auto') {
|
scrollToIndex(index, behavior = 'auto') {
|
||||||
const both = this.isBoth();
|
const both = this.isBoth();
|
||||||
const horizontal = this.isHorizontal();
|
const horizontal = this.isHorizontal();
|
||||||
|
const valid = both ? index.every((i) => i > -1) : index > -1;
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
const first = this.first;
|
const first = this.first;
|
||||||
const { numToleratedItems } = this.calculateNumItems();
|
const { numToleratedItems } = this.calculateNumItems();
|
||||||
const contentPos = this.getContentPosition();
|
const contentPos = this.getContentPosition();
|
||||||
|
@ -183,11 +186,15 @@ export default {
|
||||||
|
|
||||||
this.isRangeChanged = isRangeChanged;
|
this.isRangeChanged = isRangeChanged;
|
||||||
this.first = newFirst;
|
this.first = newFirst;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
scrollInView(index, to, behavior = 'auto') {
|
scrollInView(index, to, behavior = 'auto') {
|
||||||
if (to) {
|
if (to) {
|
||||||
const both = this.isBoth();
|
const both = this.isBoth();
|
||||||
const horizontal = this.isHorizontal();
|
const horizontal = this.isHorizontal();
|
||||||
|
const valid = both ? index.every((i) => i > -1) : index > -1;
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
const { first, viewport } = this.getRenderedRange();
|
const { first, viewport } = this.getRenderedRange();
|
||||||
const scrollTo = (left = 0, top = 0) => this.scrollTo({ left, top, behavior });
|
const scrollTo = (left = 0, top = 0) => this.scrollTo({ left, top, behavior });
|
||||||
const isToStart = to === 'to-start';
|
const isToStart = to === 'to-start';
|
||||||
|
@ -222,6 +229,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.scrollToIndex(index, behavior);
|
this.scrollToIndex(index, behavior);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue