Refactor #5681, #5683 - For Listbox, Select

pull/5701/head
tugcekucukoglu 2024-05-03 23:53:04 +03:00
parent 46ddebc0c0
commit 4221682530
7 changed files with 122 additions and 70 deletions

View File

@ -130,15 +130,15 @@ export interface ListboxPassThroughOptions<T = any> {
* Used to pass attributes to the InputText component.
* @see {@link InputTextPassThroughOptions}
*/
filterInput?: InputTextPassThroughOptions<ListboxSharedPassThroughMethodOptions>;
filter?: InputTextPassThroughOptions<ListboxSharedPassThroughMethodOptions>;
/**
* Used to pass attributes to the filter icon's DOM element.
*/
filterIcon?: ListboxPassThroughOptionType;
/**
* Used to pass attributes to the wrapper's DOM element.
* Used to pass attributes to the list container's DOM element.
*/
wrapper?: ListboxPassThroughOptionType;
listContainer?: ListboxPassThroughOptionType;
/**
* Used to pass attributes to the VirtualScroller component.
* @see {@link VirtualScrollerPassThroughOptionType}
@ -149,13 +149,13 @@ export interface ListboxPassThroughOptions<T = any> {
*/
list?: ListboxPassThroughOptionType<T>;
/**
* Used to pass attributes to the item group's DOM element.
* Used to pass attributes to the option group's DOM element.
*/
itemGroup?: ListboxPassThroughOptionType;
optionGroup?: ListboxPassThroughOptionType;
/**
* Used to pass attributes to the item's DOM element.
* Used to pass attributes to the option's DOM element.
*/
item?: ListboxPassThroughOptionType;
option?: ListboxPassThroughOptionType;
/**
* Used to pass attributes to the emptyMessage's DOM element.
*/

View File

@ -19,7 +19,7 @@
<InputText
v-model="filterValue"
type="text"
:class="cx('filterInput')"
:class="cx('filter')"
:placeholder="filterPlaceholder"
role="searchbox"
autocomplete="off"
@ -32,7 +32,7 @@
@input="onFilterChange"
@blur="onFilterBlur"
@keydown="onFilterKeyDown"
:pt="ptm('filterInput')"
:pt="ptm('filter')"
/>
<slot name="filtericon" :class="cx('filterIcon')">
@ -43,7 +43,7 @@
{{ filterResultMessageText }}
</span>
</div>
<div :class="cx('wrapper')" :style="[{ 'max-height': virtualScrollerDisabled ? scrollHeight : '' }, listStyle]" v-bind="ptm('wrapper')">
<div :class="cx('listContainer')" :style="[{ 'max-height': virtualScrollerDisabled ? scrollHeight : '' }, listStyle]" v-bind="ptm('listContainer')">
<VirtualScroller :ref="virtualScrollerRef" v-bind="virtualScrollerOptions" :items="visibleOptions" :style="[{ height: scrollHeight }, listStyle]" :tabindex="-1" :disabled="virtualScrollerDisabled" :pt="ptm('virtualScroller')">
<template v-slot:content="{ styleClass, contentRef, items, getItemOptions, contentStyle, itemSize }">
<ul
@ -64,7 +64,7 @@
v-bind="ptm('list')"
>
<template v-for="(option, i) of items" :key="getOptionRenderKey(option, getOptionIndex(i, getItemOptions))">
<li v-if="isOptionGroup(option)" :id="id + '_' + getOptionIndex(i, getItemOptions)" :style="{ height: itemSize ? itemSize + 'px' : undefined }" :class="cx('itemGroup')" role="option" v-bind="ptm('itemGroup')">
<li v-if="isOptionGroup(option)" :id="id + '_' + getOptionIndex(i, getItemOptions)" :style="{ height: itemSize ? itemSize + 'px' : undefined }" :class="cx('optionGroup')" role="option" v-bind="ptm('optionGroup')">
<slot name="optiongroup" :option="option.optionGroup" :index="getOptionIndex(i, getItemOptions)">{{ getOptionGroupLabel(option.optionGroup) }}</slot>
</li>
<li
@ -72,7 +72,7 @@
:id="id + '_' + getOptionIndex(i, getItemOptions)"
v-ripple
:style="{ height: itemSize ? itemSize + 'px' : undefined }"
:class="cx('item', { option, index: i, getItemOptions })"
:class="cx('option', { option, index: i, getItemOptions })"
role="option"
:aria-label="getOptionLabel(option)"
:aria-selected="isSelected(option)"
@ -84,7 +84,7 @@
@mousemove="onOptionMouseMove($event, getOptionIndex(i, getItemOptions))"
@touchend="onOptionTouchEnd()"
@dblclick="onOptionDblClick($event, option)"
v-bind="getPTOptions(option, getItemOptions, i, 'item')"
v-bind="getPTOptions(option, getItemOptions, i, 'option')"
:data-p-highlight="isSelected(option)"
:data-p-focused="focusedOptionIndex === getOptionIndex(i, getItemOptions)"
:data-p-disabled="isOptionDisabled(option)"

View File

@ -126,12 +126,12 @@ const classes = {
],
header: 'p-listbox-header',
filterContainer: 'p-listbox-filter-container',
filterInput: 'p-listbox-filter',
filter: 'p-listbox-filter',
filterIcon: 'p-listbox-filter-icon',
wrapper: 'p-listbox-list-container',
listContainer: 'p-listbox-list-container',
list: 'p-listbox-list',
itemGroup: 'p-listbox-option-group',
item: ({ instance, option, index, getItemOptions }) => [
optionGroup: 'p-listbox-option-group',
option: ({ instance, option, index, getItemOptions }) => [
'p-listbox-option',
{
'p-listbox-option-selected': instance.isSelected(option),

View File

@ -62,10 +62,30 @@ export default {
type: Object,
default: null
},
labelId: {
type: String,
default: null
},
labelClass: {
type: [String, Object],
default: null
},
labelStyle: {
type: Object,
default: null
},
panelClass: {
type: [String, Object],
default: null
},
overlayStyle: {
type: Object,
default: null
},
overlayClass: {
type: [String, Object],
default: null
},
panelStyle: {
type: Object,
default: null

View File

@ -87,25 +87,25 @@ export interface SelectPassThroughOptions<T = any> {
*/
root?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the input's DOM element.
* Used to pass attributes to the label's DOM element.
*/
input?: SelectPassThroughOptionType<T>;
label?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the clear icon's DOM element.
*/
clearIcon?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the trigger' DOM element.
* Used to pass attributes to the dropdown' DOM element.
*/
trigger?: SelectPassThroughOptionType<T>;
dropdown?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the loading icon's DOM element.
*/
loadingIcon?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the panel's DOM element.
* Used to pass attributes to the overlay's DOM element.
*/
panel?: SelectPassThroughOptionType<T>;
overlay?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the header's DOM element.
*/
@ -115,17 +115,17 @@ export interface SelectPassThroughOptions<T = any> {
*/
filterContainer?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the filter input's DOM element.
* Used to pass attributes to the filter's DOM element.
*/
filterInput?: SelectPassThroughOptionType<T>;
filter?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the filter icon's DOM element.
*/
filterIcon?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the wrapper's DOM element.
* Used to pass attributes to the list container's DOM element.
*/
wrapper?: SelectPassThroughOptionType<T>;
listContainer?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the VirtualScroller component.
* @see {@link VirtualScrollerPassThroughOptionType}
@ -136,29 +136,29 @@ export interface SelectPassThroughOptions<T = any> {
*/
list?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the item group's DOM element.
* Used to pass attributes to the option group's DOM element.
*/
itemGroup?: SelectPassThroughOptionType<T>;
optionGroup?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the item group label's DOM element.
* Used to pass attributes to the option group label's DOM element.
*/
itemGroupLabel?: SelectPassThroughOptionType<T>;
optionGroupLabel?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the item's DOM element.
* Used to pass attributes to the option's DOM element.
*/
item?: SelectPassThroughOptionType<T>;
option?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the item label's DOM element.
* Used to pass attributes to the option label's DOM element.
*/
itemLabel?: SelectPassThroughOptionType<T>;
optionLabel?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the check icon's DOM element.
* Used to pass attributes to the option check icon's DOM element.
*/
checkIcon?: SelectPassThroughOptionType<T>;
optionCheckIcon?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the bank icon's DOM element.
* Used to pass attributes to the option blank icon's DOM element.
*/
blankIcon?: SelectPassThroughOptionType<T>;
optionBlankIcon?: SelectPassThroughOptionType<T>;
/**
* Used to pass attributes to the empty message's DOM element.
*/
@ -352,25 +352,50 @@ export interface SelectProps {
*/
showClear?: boolean | undefined;
/**
* @deprecated since v4.0. Use 'labelId' instead.
* Identifier of the underlying input element.
*/
inputId?: string | undefined;
/**
* @deprecated since v4.0. Use 'labelStyle' instead.
* Inline style of the input field.
*/
inputStyle?: object | undefined;
/**
* @deprecated since v4.0. Use 'labelClass' instead.
* Style class of the input field.
*/
inputClass?: string | object | undefined;
/**
* Identifier of the underlying label element.
*/
labelId?: string | undefined;
/**
* Inline style of the label field.
*/
labelStyle?: object | undefined;
/**
* Style class of the label field.
*/
labelClass?: string | object | undefined;
/**
* @deprecated since v4.0. Use 'overlayStyle' instead.
* Inline style of the overlay panel.
*/
panelStyle?: object | undefined;
/**
* @deprecated since v4.0. Use 'overlayClass' instead.
* Style class of the overlay panel.
*/
panelClass?: string | object | undefined;
/**
* Inline style of the overlay.
*/
overlayStyle?: object | undefined;
/**
* Style class of the overlay.
*/
overlayClass?: string | object | undefined;
/**
* A valid query selector or an HTMLElement to specify where the overlay gets attached.
* @defaultValue body

View File

@ -3,10 +3,10 @@
<input
v-if="editable"
ref="focusInput"
:id="inputId"
:id="labelId || inputId"
type="text"
:class="[cx('input'), inputClass]"
:style="inputStyle"
:class="[cx('label'), inputClass, labelClass]"
:style="[inputStyle, labelStyle]"
:value="editableInputValue"
:placeholder="placeholder"
:tabindex="!disabled ? tabindex : -1"
@ -24,14 +24,14 @@
@blur="onBlur"
@keydown="onKeyDown"
@input="onEditableInput"
v-bind="ptm('input')"
v-bind="ptm('label')"
/>
<span
v-else
ref="focusInput"
:id="inputId"
:class="[cx('input'), inputClass]"
:style="inputStyle"
:id="labelId || inputId"
:class="[cx('label'), inputClass, labelClass]"
:style="[inputStyle, labelStyle]"
:tabindex="!disabled ? tabindex : -1"
role="combobox"
:aria-label="ariaLabel || (label === 'p-emptylabel' ? undefined : label)"
@ -44,14 +44,14 @@
@focus="onFocus"
@blur="onBlur"
@keydown="onKeyDown"
v-bind="ptm('input')"
v-bind="ptm('label')"
>
<slot name="value" :value="modelValue" :placeholder="placeholder">{{ label === 'p-emptylabel' ? '&nbsp;' : label || 'empty' }}</slot>
</span>
<slot v-if="showClear && modelValue != null" name="clearicon" :class="cx('clearIcon')" :onClick="onClearClick" :clearCallback="onClearClick">
<component :is="clearIcon ? 'i' : 'TimesIcon'" ref="clearIcon" :class="[cx('clearIcon'), clearIcon]" @click="onClearClick" v-bind="ptm('clearIcon')" data-pc-section="clearicon" />
</slot>
<div :class="cx('trigger')" v-bind="ptm('trigger')">
<div :class="cx('dropdown')" v-bind="ptm('dropdown')">
<slot v-if="loading" name="loadingicon" :class="cx('loadingIcon')">
<span v-if="loadingIcon" :class="[cx('loadingIcon'), 'pi-spin', loadingIcon]" aria-hidden="true" v-bind="ptm('loadingIcon')" />
<SpinnerIcon v-else :class="cx('loadingIcon')" spin aria-hidden="true" v-bind="ptm('loadingIcon')" />
@ -62,7 +62,7 @@
</div>
<Portal :appendTo="appendTo">
<transition name="p-connected-overlay" @enter="onOverlayEnter" @after-enter="onOverlayAfterEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave" v-bind="ptm('transition')">
<div v-if="overlayVisible" :ref="overlayRef" :class="[cx('panel'), panelClass]" :style="panelStyle" @click="onOverlayClick" @keydown="onOverlayKeyDown" v-bind="ptm('panel')">
<div v-if="overlayVisible" :ref="overlayRef" :class="[cx('overlay'), panelClass, overlayClass]" :style="[panelStyle, overlayStyle]" @click="onOverlayClick" @keydown="onOverlayKeyDown" v-bind="ptm('overlay')">
<span
ref="firstHiddenFocusableElementOnOverlay"
role="presentation"
@ -83,7 +83,7 @@
:value="filterValue"
@vue:mounted="onFilterUpdated"
@vue:updated="onFilterUpdated"
:class="cx('filterInput')"
:class="cx('filter')"
:placeholder="filterPlaceholder"
:invalid="invalid"
:variant="variant"
@ -95,7 +95,7 @@
@keydown="onFilterKeyDown"
@blur="onFilterBlur"
@input="onFilterChange"
:pt="ptm('filterInput')"
:pt="ptm('filter')"
/>
<slot name="filtericon" :class="cx('filterIcon')">
<component :is="filterIcon ? 'span' : 'SearchIcon'" :class="[cx('filterIcon'), filterIcon]" v-bind="ptm('filterIcon')" />
@ -105,21 +105,28 @@
{{ filterResultMessageText }}
</span>
</div>
<div :class="cx('wrapper')" :style="{ 'max-height': virtualScrollerDisabled ? scrollHeight : '' }" v-bind="ptm('wrapper')">
<div :class="cx('listContainer')" :style="{ 'max-height': virtualScrollerDisabled ? scrollHeight : '' }" v-bind="ptm('listContainer')">
<VirtualScroller :ref="virtualScrollerRef" v-bind="virtualScrollerOptions" :items="visibleOptions" :style="{ height: scrollHeight }" :tabindex="-1" :disabled="virtualScrollerDisabled" :pt="ptm('virtualScroller')">
<template v-slot:content="{ styleClass, contentRef, items, getItemOptions, contentStyle, itemSize }">
<ul :ref="(el) => listRef(el, contentRef)" :id="id + '_list'" :class="[cx('list'), styleClass]" :style="contentStyle" role="listbox" v-bind="ptm('list')">
<template v-for="(option, i) of items" :key="getOptionRenderKey(option, getOptionIndex(i, getItemOptions))">
<li v-if="isOptionGroup(option)" :id="id + '_' + getOptionIndex(i, getItemOptions)" :style="{ height: itemSize ? itemSize + 'px' : undefined }" :class="cx('itemGroup')" role="option" v-bind="ptm('itemGroup')">
<li
v-if="isOptionGroup(option)"
:id="id + '_' + getOptionIndex(i, getItemOptions)"
:style="{ height: itemSize ? itemSize + 'px' : undefined }"
:class="cx('optionGroup')"
role="option"
v-bind="ptm('optionGroup')"
>
<slot name="optiongroup" :option="option.optionGroup" :index="getOptionIndex(i, getItemOptions)">
<span :class="cx('itemGroupLabel')" v-bind="ptm('itemGroupLabel')">{{ getOptionGroupLabel(option.optionGroup) }}</span>
<span :class="cx('optionGroupLabel')" v-bind="ptm('optionGroupLabel')">{{ getOptionGroupLabel(option.optionGroup) }}</span>
</slot>
</li>
<li
v-else
:id="id + '_' + getOptionIndex(i, getItemOptions)"
v-ripple
:class="cx('item', { option, focusedOption: getOptionIndex(i, getItemOptions) })"
:class="cx('option', { option, focusedOption: getOptionIndex(i, getItemOptions) })"
:style="{ height: itemSize ? itemSize + 'px' : undefined }"
role="option"
:aria-label="getOptionLabel(option)"
@ -132,14 +139,14 @@
:data-p-highlight="isSelected(option)"
:data-p-focused="focusedOptionIndex === getOptionIndex(i, getItemOptions)"
:data-p-disabled="isOptionDisabled(option)"
v-bind="getPTItemOptions(option, getItemOptions, i, 'item')"
v-bind="getPTItemOptions(option, getItemOptions, i, 'option')"
>
<template v-if="checkmark">
<CheckIcon v-if="isSelected(option)" :class="cx('checkIcon')" v-bind="ptm('checkIcon')" />
<BlankIcon v-else :class="cx('blankIcon')" v-bind="ptm('blankIcon')" />
<CheckIcon v-if="isSelected(option)" :class="cx('optionCheckIcon')" v-bind="ptm('optionCheckIcon')" />
<BlankIcon v-else :class="cx('optionBlankIcon')" v-bind="ptm('optionBlankIcon')" />
</template>
<slot name="option" :option="option" :index="getOptionIndex(i, getItemOptions)">
<span :class="cx('itemLabel')" v-bind="ptm('itemLabel')">{{ getOptionLabel(option) }}</span>
<span :class="cx('optionLabel')" v-bind="ptm('optionLabel')">{{ getOptionLabel(option) }}</span>
</slot>
</li>
</template>

View File

@ -227,7 +227,7 @@ const classes = {
'p-select-open': state.overlayVisible
}
],
input: ({ instance, props }) => [
label: ({ instance, props }) => [
'p-select-label',
{
'p-placeholder': !props.editable && instance.label === props.placeholder,
@ -235,10 +235,10 @@ const classes = {
}
],
clearIcon: 'p-select-clear-icon',
trigger: 'p-select-dropdown',
dropdown: 'p-select-dropdown',
loadingicon: 'p-select-loading-icon',
dropdownIcon: 'p-select-dropdown-icon',
panel: ({ instance }) => [
overlay: ({ instance }) => [
'p-select-overlay p-component',
{
'p-ripple-disabled': instance.$primevue.config.ripple === false
@ -246,13 +246,13 @@ const classes = {
],
header: 'p-select-header',
filterContainer: 'p-select-filter-container',
filterInput: 'p-select-filter',
filter: 'p-select-filter',
filterIcon: 'p-select-filter-icon',
wrapper: 'p-select-list-container',
listContainer: 'p-select-list-container',
list: 'p-select-list',
itemGroup: 'p-select-option-group',
itemGroupLabel: 'p-select-option-group-label',
item: ({ instance, props, state, option, focusedOption }) => [
optionGroup: 'p-select-option-group',
optionGroupLabel: 'p-select-option-group-label',
option: ({ instance, props, state, option, focusedOption }) => [
'p-select-option',
{
'p-select-option-selected': instance.isSelected(option) && props.highlightOnSelect,
@ -260,9 +260,9 @@ const classes = {
'p-disabled': instance.isOptionDisabled(option)
}
],
itemLabel: 'p-select-option-label',
checkIcon: 'p-select-option-check-icon',
blankIcon: 'p-select-option-blank-icon',
optionLabel: 'p-select-option-label',
optionCheckIcon: 'p-select-option-check-icon',
optionBlankIcon: 'p-select-option-blank-icon',
emptyMessage: 'p-select-empty-message'
};