Refactor #3922 - For CascadeSelect

pull/3925/head
Tuğçe Küçükoğlu 2023-05-05 11:45:08 +03:00
parent 1f00024df1
commit d180ac7002
5 changed files with 163 additions and 15 deletions

View File

@ -184,6 +184,12 @@ const CascadeSelectProps = [
type: 'string', type: 'string',
default: 'null', default: 'null',
description: 'Identifier of the underlying input element.' description: 'Identifier of the underlying input element.'
},
{
name: 'pt',
type: 'any',
default: 'null',
description: 'Uses to pass attributes to DOM elements inside the component.'
} }
]; ];

View File

@ -10,6 +10,16 @@
import { HTMLAttributes, InputHTMLAttributes, VNode } from 'vue'; import { HTMLAttributes, InputHTMLAttributes, VNode } from 'vue';
import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers'; import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers';
export declare type CascadeSelectPassThroughOptionType = CascadeSelectPassThroughAttributes | ((options: CascadeSelectPassThroughMethodOptions) => CascadeSelectPassThroughAttributes) | null | undefined;
/**
* Custom passthrough(pt) option method.
*/
export interface CascadeSelectPassThroughMethodOptions {
props: CascadeSelectProps;
state: CascadeSelectState;
}
/** /**
* Custom change event * Custom change event
* @see {@link CascadeSelectEmits.change} * @see {@link CascadeSelectEmits.change}
@ -31,6 +41,124 @@ export interface CascadeSelectChangeEvent {
*/ */
export interface CascadeSelectGroupChangeEvent extends CascadeSelectChangeEvent {} export interface CascadeSelectGroupChangeEvent extends CascadeSelectChangeEvent {}
/**
* Custom passthrough(pt) options.
* @see {@link CascadeSelectProps.pt}
*/
export interface CascadeSelectPassThroughOptions {
/**
* Uses to pass attributes to the root's DOM element.
*/
root?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the input's DOM element.
*/
input?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the label's DOM element.
*/
label?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the dropdown button's DOM element.
*/
dropdownButton?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the loading icon's DOM element.
*/
loadingIcon?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the dropdown icon's DOM element.
*/
dropdownIcon?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the panel's DOM element.
*/
panel?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the list's DOM element.
*/
list?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the item's DOM element.
*/
item?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the content's DOM element.
*/
content?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the text's DOM element.
*/
text?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the input sria's DOM element.
*/
inputAria?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the search result message text aria's DOM element.
*/
searchResultAria?: CascadeSelectPassThroughOptionType;
/**
* Uses to pass attributes to the selected message text aria's DOM element.
*/
selectedMessageAria?: CascadeSelectPassThroughOptionType;
}
/**
* Custom passthrough attributes for each DOM elements
*/
export interface CascadeSelectPassThroughAttributes {
[key: string]: any;
}
/**
* Defines focused item info
*/
export interface CascadeSelectFocusedOptionInfo {
/**
* Active item index
*/
index: number;
/**
* Active item level
*/
level: number;
/**
* Parent key info
*/
parentKey: string;
}
/**
* Defines current inline state in CascadeSelect component.
*/
export interface CascadeSelectState {
/**
* Current id state as a string
*/
id: string;
/**
* Current focused state as a boolean.
* @defaultValue false
*/
focused: boolean;
/**
* Current focused item info.
* @type {CascadeSelectFocusedOptionInfo}
*/
focusedOptionInfo: CascadeSelectFocusedOptionInfo;
/**
* Current focused state as a boolean.
* @defaultValue false
*/
activeOptionPath: any[];
/**
* Current overlay visible state as a boolean.
* @defaultValue false
*/
overlayVisible: boolean;
}
/** /**
* Defines valid properties in CascadeSelect component. * Defines valid properties in CascadeSelect component.
*/ */
@ -180,6 +308,11 @@ export interface CascadeSelectProps {
* Establishes a string value that labels the component. * Establishes a string value that labels the component.
*/ */
'aria-label'?: string | undefined; 'aria-label'?: string | undefined;
/**
* Uses to pass attributes to DOM elements inside the component.
* @type {CascadeSelectPassThroughOptions}
*/
pt?: CascadeSelectPassThroughOptions;
} }
/** /**

View File

@ -1,6 +1,6 @@
<template> <template>
<div ref="container" :class="containerClass" @click="onContainerClick($event)"> <div ref="container" :class="containerClass" @click="onContainerClick($event)" v-bind="ptm('root')">
<div class="p-hidden-accessible"> <div class="p-hidden-accessible" v-bind="ptm('inputAria')">
<input <input
ref="focusInput" ref="focusInput"
:id="inputId" :id="inputId"
@ -21,30 +21,30 @@
@focus="onFocus" @focus="onFocus"
@blur="onBlur" @blur="onBlur"
@keydown="onKeyDown" @keydown="onKeyDown"
v-bind="inputProps" v-bind="{ ...inputProps, ...ptm('input') }"
/> />
</div> </div>
<span :class="labelClass"> <span :class="labelClass" v-bind="ptm('label')">
<slot name="value" :value="modelValue" :placeholder="placeholder"> <slot name="value" :value="modelValue" :placeholder="placeholder">
{{ label }} {{ label }}
</slot> </slot>
</span> </span>
<div class="p-cascadeselect-trigger" role="button" tabindex="-1" aria-hidden="true"> <div class="p-cascadeselect-trigger" role="button" tabindex="-1" aria-hidden="true" v-bind="ptm('dropdownButton')">
<slot v-if="loading" name="loadingicon" class="p-cascadeselect-trigger-icon"> <slot v-if="loading" name="loadingicon" class="p-cascadeselect-trigger-icon">
<span v-if="loadingIcon" :class="['p-cascadeselect-trigger-icon pi-spin', loadingIcon]" aria-hidden="true" /> <span v-if="loadingIcon" :class="['p-cascadeselect-trigger-icon pi-spin', loadingIcon]" aria-hidden="true" v-bind="ptm('loadingIcon')" />
<SpinnerIcon v-else class="p-cascadeselect-trigger-icon" spin aria-hidden="true" /> <SpinnerIcon v-else class="p-cascadeselect-trigger-icon" spin aria-hidden="true" v-bind="ptm('loadingIcon')" />
</slot> </slot>
<slot v-else name="dropdownicon" class="p-cascadeselect-trigger-icon"> <slot v-else name="dropdownicon" class="p-cascadeselect-trigger-icon">
<component :is="dropdownIcon ? 'span' : 'ChevronDownIcon'" :class="['p-cascadeselect-trigger-icon', dropdownIcon]" aria-hidden="true" /> <component :is="dropdownIcon ? 'span' : 'ChevronDownIcon'" :class="['p-cascadeselect-trigger-icon', dropdownIcon]" aria-hidden="true" v-bind="ptm('dropdownIcon')" />
</slot> </slot>
</div> </div>
<span role="status" aria-live="polite" class="p-hidden-accessible"> <span role="status" aria-live="polite" class="p-hidden-accessible" v-bind="ptm('searchResultAria')">
{{ searchResultMessageText }} {{ searchResultMessageText }}
</span> </span>
<Portal :appendTo="appendTo"> <Portal :appendTo="appendTo">
<transition name="p-connected-overlay" @enter="onOverlayEnter" @after-enter="onOverlayAfterEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave"> <transition name="p-connected-overlay" @enter="onOverlayEnter" @after-enter="onOverlayAfterEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave">
<div v-if="overlayVisible" :ref="overlayRef" :style="panelStyle" :class="panelStyleClass" @click="onOverlayClick" @keydown="onOverlayKeyDown" v-bind="panelProps"> <div v-if="overlayVisible" :ref="overlayRef" :style="panelStyle" :class="panelStyleClass" @click="onOverlayClick" @keydown="onOverlayKeyDown" v-bind="{ ...panelProps, ...ptm('panel') }">
<div class="p-cascadeselect-items-wrapper"> <div class="p-cascadeselect-items-wrapper" v-bind="ptm('wrapper')">
<CascadeSelectSub <CascadeSelectSub
:id="id + '_tree'" :id="id + '_tree'"
role="tree" role="tree"
@ -62,10 +62,11 @@
:optionGroupLabel="optionGroupLabel" :optionGroupLabel="optionGroupLabel"
:optionGroupChildren="optionGroupChildren" :optionGroupChildren="optionGroupChildren"
@option-change="onOptionChange" @option-change="onOptionChange"
:pt="pt"
/> />
</div> </div>
<span role="status" aria-live="polite" class="p-hidden-accessible"> <span role="status" aria-live="polite" class="p-hidden-accessible" v-bind="ptm('selectedMessageAria')">
{{ selectedMessageText }} {{ selectedMessageText }}
</span> </span>
</div> </div>
@ -75,6 +76,7 @@
</template> </template>
<script> <script>
import BaseComponent from 'primevue/basecomponent';
import AngleRightIcon from 'primevue/icons/angleright'; import AngleRightIcon from 'primevue/icons/angleright';
import ChevronDownIcon from 'primevue/icons/chevrondown'; import ChevronDownIcon from 'primevue/icons/chevrondown';
import SpinnerIcon from 'primevue/icons/spinner'; import SpinnerIcon from 'primevue/icons/spinner';
@ -85,6 +87,7 @@ import CascadeSelectSub from './CascadeSelectSub.vue';
export default { export default {
name: 'CascadeSelect', name: 'CascadeSelect',
extends: BaseComponent,
emits: ['update:modelValue', 'change', 'focus', 'blur', 'click', 'group-change', 'before-show', 'before-hide', 'hide', 'show'], emits: ['update:modelValue', 'change', 'focus', 'blur', 'click', 'group-change', 'before-show', 'before-hide', 'hide', 'show'],
props: { props: {
modelValue: null, modelValue: null,

View File

@ -1,5 +1,5 @@
<template> <template>
<ul class="p-cascadeselect-panel p-cascadeselect-items"> <ul class="p-cascadeselect-panel p-cascadeselect-items" v-bind="ptm('list')">
<template v-for="(processedOption, index) of options" :key="getOptionLabelToRender(processedOption)"> <template v-for="(processedOption, index) of options" :key="getOptionLabelToRender(processedOption)">
<li <li
:id="getOptionId(processedOption)" :id="getOptionId(processedOption)"
@ -11,10 +11,11 @@
:aria-level="level + 1" :aria-level="level + 1"
:aria-setsize="options.length" :aria-setsize="options.length"
:aria-posinset="index + 1" :aria-posinset="index + 1"
v-bind="ptm('item')"
> >
<div v-ripple class="p-cascadeselect-item-content" @click="onOptionClick($event, processedOption)"> <div v-ripple class="p-cascadeselect-item-content" @click="onOptionClick($event, processedOption)" v-bind="ptm('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="p-cascadeselect-item-text">{{ getOptionLabelToRender(processedOption) }}</span> <span v-else class="p-cascadeselect-item-text" v-bind="ptm('text')">{{ getOptionLabelToRender(processedOption) }}</span>
<component <component
v-if="isOptionGroup(processedOption)" v-if="isOptionGroup(processedOption)"
:is="templates['optiongroupicon'] ? templates['optiongroupicon'] : optionGroupIcon ? 'span' : 'AngleRightIcon'" :is="templates['optiongroupicon'] ? templates['optiongroupicon'] : optionGroupIcon ? 'span' : 'AngleRightIcon'"
@ -39,6 +40,7 @@
:optionGroupLabel="optionGroupLabel" :optionGroupLabel="optionGroupLabel"
:optionGroupChildren="optionGroupChildren" :optionGroupChildren="optionGroupChildren"
@option-change="onOptionChange" @option-change="onOptionChange"
:pt="pt"
/> />
</li> </li>
</template> </template>
@ -46,12 +48,14 @@
</template> </template>
<script> <script>
import BaseComponent from 'primevue/basecomponent';
import AngleRightIcon from 'primevue/icons/angleright'; import AngleRightIcon from 'primevue/icons/angleright';
import Ripple from 'primevue/ripple'; import Ripple from 'primevue/ripple';
import { DomHandler, ObjectUtils } from 'primevue/utils'; import { DomHandler, ObjectUtils } from 'primevue/utils';
export default { export default {
name: 'CascadeSelectSub', name: 'CascadeSelectSub',
extends: BaseComponent,
emits: ['option-change'], emits: ['option-change'],
props: { props: {
selectId: String, selectId: String,

View File

@ -10,6 +10,7 @@ import { ButtonPassThroughOptions } from '../button';
import { CalendarPassThroughOptions } from '../calendar'; import { CalendarPassThroughOptions } from '../calendar';
import { CardPassThroughOptions } from '../card'; import { CardPassThroughOptions } from '../card';
import { CarouselPassThroughOptions } from '../carousel'; import { CarouselPassThroughOptions } from '../carousel';
import { CascadeSelectPassThroughOptions } from '../cascadeselect';
import { ChartPassThroughOptions } from '../chart'; import { ChartPassThroughOptions } from '../chart';
import { ChipPassThroughOptions } from '../chip'; import { ChipPassThroughOptions } from '../chip';
import { ConfirmDialogPassThroughOptions } from '../confirmdialog'; import { ConfirmDialogPassThroughOptions } from '../confirmdialog';
@ -79,6 +80,7 @@ interface PrimeVuePTOptions {
calendar?: CalendarPassThroughOptions; calendar?: CalendarPassThroughOptions;
card?: CardPassThroughOptions; card?: CardPassThroughOptions;
carousel?: CarouselPassThroughOptions; carousel?: CarouselPassThroughOptions;
cascadeselect?: CascadeSelectPassThroughOptions;
chart?: ChartPassThroughOptions; chart?: ChartPassThroughOptions;
chip?: ChipPassThroughOptions; chip?: ChipPassThroughOptions;
confirmdialog?: ConfirmDialogPassThroughOptions; confirmdialog?: ConfirmDialogPassThroughOptions;