Refactor #3924 - For Tree

pull/3938/head
Tuğçe Küçükoğlu 2023-05-07 22:21:37 +03:00
parent 6a4226a4e0
commit e10c1cf988
5 changed files with 158 additions and 19 deletions

View File

@ -77,6 +77,12 @@ const TreeProps = [
type: 'string', type: 'string',
default: 'null', default: 'null',
description: 'Height of the scroll viewport in fixed units or the "flex" keyword for a dynamic size.' description: 'Height of the scroll viewport in fixed units or the "flex" keyword for a dynamic size.'
},
{
name: 'pt',
type: 'any',
default: 'null',
description: 'Uses to pass attributes to DOM elements inside the component.'
} }
]; ];

View File

@ -63,6 +63,7 @@ import { TextareaPassThroughOptions } from '../textarea';
import { TieredMenuPassThroughOptions } from '../tieredmenu'; import { TieredMenuPassThroughOptions } from '../tieredmenu';
import { ToastPassThroughOptions } from '../toast'; import { ToastPassThroughOptions } from '../toast';
import { ToolbarPassThroughOptions } from '../toolbar'; import { ToolbarPassThroughOptions } from '../toolbar';
import { TreePassThroughOptions } from '../tree';
import { VirtualScrollerPassThroughOptions } from '../virtualscroller'; import { VirtualScrollerPassThroughOptions } from '../virtualscroller';
interface PrimeVueConfiguration { interface PrimeVueConfiguration {
@ -148,6 +149,7 @@ interface PrimeVuePTOptions {
tieredmenu?: TieredMenuPassThroughOptions; tieredmenu?: TieredMenuPassThroughOptions;
toast?: ToastPassThroughOptions; toast?: ToastPassThroughOptions;
toolbar?: ToolbarPassThroughOptions; toolbar?: ToolbarPassThroughOptions;
tree?: TreePassThroughOptions;
virtualscroller?: VirtualScrollerPassThroughOptions; virtualscroller?: VirtualScrollerPassThroughOptions;
} }

View File

@ -10,6 +10,16 @@
import { VNode } from 'vue'; import { VNode } from 'vue';
import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers'; import { ClassComponent, GlobalComponentConstructor } from '../ts-helpers';
export declare type TreePassThroughOptionType = TreePassThroughAttributes | ((options: TreePassThroughMethodOptions) => TreePassThroughAttributes) | null | undefined;
/**
* Custom passthrough(pt) option method.
*/
export interface TreePassThroughMethodOptions {
props: TreeProps;
state: TreeState;
}
/** /**
* Custom TreeNode metadata. * Custom TreeNode metadata.
*/ */
@ -90,6 +100,106 @@ export interface TreeSelectionKeys {
[key: string]: any; [key: string]: any;
} }
/**
* Custom passthrough(pt) options.
* @see {@link TreeProps.pt}
*/
export interface TreePassThroughOptions {
/**
* Uses to pass attributes to the root's DOM element.
*/
root?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the loading overlay's DOM element.
*/
loadingOverlay?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the loading icon's DOM element.
*/
loadingIcon?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the filter container's DOM element.
*/
filterContainer?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the input's DOM element.
*/
input?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the search icon's DOM element.
*/
searchIcon?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the wrapper's DOM element.
*/
wrapper?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the container's DOM element.
*/
container?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the node's DOM element.
*/
node?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the content's DOM element.
*/
content?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the toggler's DOM element.
*/
toggler?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the toggler icon's DOM element.
*/
togglerIcon?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the checkbox container's DOM element.
*/
checkboxContainer?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the checkbox's DOM element.
*/
checkbox?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the checkbox icon's DOM element.
*/
checkboxIcon?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the node icon's DOM element.
*/
nodeIcon?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the label's DOM element.
*/
label?: TreePassThroughOptionType;
/**
* Uses to pass attributes to the subgroup's DOM element.
*/
subgroup?: TreePassThroughOptionType;
}
/**
* Custom passthrough attributes for each DOM elements
*/
export interface TreePassThroughAttributes {
[key: string]: any;
}
/**
* Defines current inline state in Tree component.
*/
export interface TreeState {
/**
* Current expanded keys state.
*/
d_expandedKeys: TreeExpandedKeys;
/**
* Current filter value state as a string.
*/
filterValue: string;
}
/** /**
* Defines valid properties in Tree component. * Defines valid properties in Tree component.
*/ */
@ -161,6 +271,11 @@ export interface TreeProps {
* Identifier of the underlying menu element. * Identifier of the underlying menu element.
*/ */
'aria-labelledby'?: string | undefined; 'aria-labelledby'?: string | undefined;
/**
* Uses to pass attributes to DOM elements inside the component.
* @type {TreePassThroughOptions}
*/
pt?: TreePassThroughOptions;
} }
/** /**

View File

@ -1,21 +1,21 @@
<template> <template>
<div :class="containerClass"> <div :class="containerClass" v-bind="ptm('root')">
<template v-if="loading"> <template v-if="loading">
<div class="p-tree-loading-overlay p-component-overlay"> <div class="p-tree-loading-overlay p-component-overlay" v-bind="ptm('loadingOverlay')">
<slot name="loadingicon"> <slot name="loadingicon">
<i v-if="loadingIcon" :class="['p-tree-loading-icon pi-spin', loadingIcon]" /> <i v-if="loadingIcon" :class="['p-tree-loading-icon pi-spin', loadingIcon]" v-bind="ptm('loadingIcon')" />
<SpinnerIcon v-else spin class="p-tree-loading-icon" /> <SpinnerIcon v-else spin class="p-tree-loading-icon" v-bind="ptm('loadingIcon')" />
</slot> </slot>
</div> </div>
</template> </template>
<div v-if="filter" class="p-tree-filter-container"> <div v-if="filter" class="p-tree-filter-container" v-bind="ptm('filterContainer')">
<input v-model="filterValue" type="text" autocomplete="off" class="p-tree-filter p-inputtext p-component" :placeholder="filterPlaceholder" @keydown="onFilterKeydown" /> <input v-model="filterValue" type="text" autocomplete="off" class="p-tree-filter p-inputtext p-component" :placeholder="filterPlaceholder" @keydown="onFilterKeydown" v-bind="ptm('input')" />
<slot name="searchicon"> <slot name="searchicon">
<SearchIcon class="p-tree-filter-icon" /> <SearchIcon class="p-tree-filter-icon" v-bind="ptm('searchIcon')" />
</slot> </slot>
</div> </div>
<div class="p-tree-wrapper" :style="{ maxHeight: scrollHeight }"> <div class="p-tree-wrapper" :style="{ maxHeight: scrollHeight }" v-bind="ptm('wrapper')">
<ul class="p-tree-container" role="tree" :aria-labelledby="ariaLabelledby" :aria-label="ariaLabel"> <ul class="p-tree-container" role="tree" :aria-labelledby="ariaLabelledby" :aria-label="ariaLabel" v-bind="ptm('container')">
<TreeNode <TreeNode
v-for="(node, index) of valueToRender" v-for="(node, index) of valueToRender"
:key="node.key" :key="node.key"
@ -29,6 +29,7 @@
:selectionMode="selectionMode" :selectionMode="selectionMode"
:selectionKeys="selectionKeys" :selectionKeys="selectionKeys"
@checkbox-change="onCheckboxChange" @checkbox-change="onCheckboxChange"
:pt="pt"
></TreeNode> ></TreeNode>
</ul> </ul>
</div> </div>
@ -36,6 +37,7 @@
</template> </template>
<script> <script>
import BaseComponent from 'primevue/basecomponent';
import SearchIcon from 'primevue/icons/search'; import SearchIcon from 'primevue/icons/search';
import SpinnerIcon from 'primevue/icons/spinner'; import SpinnerIcon from 'primevue/icons/spinner';
import { ObjectUtils } from 'primevue/utils'; import { ObjectUtils } from 'primevue/utils';
@ -43,6 +45,7 @@ import TreeNode from './TreeNode.vue';
export default { export default {
name: 'Tree', name: 'Tree',
extends: BaseComponent,
emits: ['node-expand', 'node-collapse', 'update:expandedKeys', 'update:selectionKeys', 'node-select', 'node-unselect'], emits: ['node-expand', 'node-collapse', 'update:expandedKeys', 'update:selectionKeys', 'node-select', 'node-unselect'],
props: { props: {
value: { value: {

View File

@ -12,26 +12,27 @@
:aria-checked="ariaChecked" :aria-checked="ariaChecked"
:tabindex="index === 0 ? 0 : -1" :tabindex="index === 0 ? 0 : -1"
@keydown="onKeyDown" @keydown="onKeyDown"
v-bind="getPTOptions('node')"
> >
<div :class="contentClass" @click="onClick" @touchend="onTouchEnd" :style="node.style"> <div :class="contentClass" @click="onClick" @touchend="onTouchEnd" :style="node.style" v-bind="getPTOptions('content')">
<button v-ripple type="button" class="p-tree-toggler p-link" @click="toggle" tabindex="-1" aria-hidden="true"> <button v-ripple type="button" class="p-tree-toggler p-link" @click="toggle" tabindex="-1" aria-hidden="true" v-bind="getPTOptions('toggler')">
<component v-if="templates['togglericon']" :is="templates['togglericon']" :node="node" :expanded="expanded" class="p-tree-toggler-icon" /> <component v-if="templates['togglericon']" :is="templates['togglericon']" :node="node" :expanded="expanded" class="p-tree-toggler-icon" />
<component v-else-if="expanded" :is="node.expandedIcon ? 'span' : 'ChevronDownIcon'" class="p-tree-toggler-icon" /> <component v-else-if="expanded" :is="node.expandedIcon ? 'span' : 'ChevronDownIcon'" class="p-tree-toggler-icon" v-bind="getPTOptions('togglerIcon')" />
<component v-else :is="node.collapsedIcon ? 'span' : 'ChevronRightIcon'" class="p-tree-toggler-icon" /> <component v-else :is="node.collapsedIcon ? 'span' : 'ChevronRightIcon'" class="p-tree-toggler-icon" v-bind="getPTOptions('togglerIcon')" />
</button> </button>
<div v-if="checkboxMode" class="p-checkbox p-component" aria-hidden="true"> <div v-if="checkboxMode" class="p-checkbox p-component" aria-hidden="true" v-bind="getPTOptions('checkboxContainer')">
<div :class="checkboxClass" role="checkbox"> <div :class="checkboxClass" role="checkbox" v-bind="getPTOptions('checkbox')">
<component v-if="templates['checkboxicon']" :is="templates['checkboxicon']" :checked="checked" :partialChecked="partialChecked" class="p-checkbox-icon" /> <component v-if="templates['checkboxicon']" :is="templates['checkboxicon']" :checked="checked" :partialChecked="partialChecked" class="p-checkbox-icon" />
<component v-else :is="checked ? 'CheckIcon' : partialChecked ? 'MinusIcon' : null" class="p-checkbox-icon" /> <component v-else :is="checked ? 'CheckIcon' : partialChecked ? 'MinusIcon' : null" class="p-checkbox-icon" v-bind="getPTOptions('checkboxIcon')" />
</div> </div>
</div> </div>
<span :class="icon"></span> <span :class="icon" v-bind="getPTOptions('nodeIcon')"></span>
<span class="p-treenode-label"> <span class="p-treenode-label" v-bind="getPTOptions('label')">
<component v-if="templates[node.type] || templates['default']" :is="templates[node.type] || templates['default']" :node="node" /> <component v-if="templates[node.type] || templates['default']" :is="templates[node.type] || templates['default']" :node="node" />
<template v-else>{{ label(node) }}</template> <template v-else>{{ label(node) }}</template>
</span> </span>
</div> </div>
<ul v-if="hasChildren && expanded" class="p-treenode-children" role="group"> <ul v-if="hasChildren && expanded" class="p-treenode-children" role="group" v-bind="ptm('subgroup')">
<TreeNode <TreeNode
v-for="childNode of node.children" v-for="childNode of node.children"
:key="childNode.key" :key="childNode.key"
@ -44,12 +45,14 @@
:selectionMode="selectionMode" :selectionMode="selectionMode"
:selectionKeys="selectionKeys" :selectionKeys="selectionKeys"
@checkbox-change="propagateUp" @checkbox-change="propagateUp"
:pt="pt"
/> />
</ul> </ul>
</li> </li>
</template> </template>
<script> <script>
import BaseComponent from 'primevue/basecomponent';
import CheckIcon from 'primevue/icons/check'; import CheckIcon from 'primevue/icons/check';
import ChevronDownIcon from 'primevue/icons/chevrondown'; import ChevronDownIcon from 'primevue/icons/chevrondown';
import ChevronRightIcon from 'primevue/icons/chevronright'; import ChevronRightIcon from 'primevue/icons/chevronright';
@ -59,6 +62,7 @@ import { DomHandler } from 'primevue/utils';
export default { export default {
name: 'TreeNode', name: 'TreeNode',
extends: BaseComponent,
emits: ['node-toggle', 'node-click', 'checkbox-change'], emits: ['node-toggle', 'node-click', 'checkbox-change'],
props: { props: {
node: { node: {
@ -110,6 +114,15 @@ export default {
onChildNodeToggle(node) { onChildNodeToggle(node) {
this.$emit('node-toggle', node); this.$emit('node-toggle', node);
}, },
getPTOptions(key) {
return this.ptm(key, {
context: {
expanded: this.expanded,
selected: this.selected,
checked: this.checked
}
});
},
onClick(event) { onClick(event) {
if (this.toggleClicked || DomHandler.hasClass(event.target, 'p-tree-toggler') || DomHandler.hasClass(event.target.parentElement, 'p-tree-toggler')) { if (this.toggleClicked || DomHandler.hasClass(event.target, 'p-tree-toggler') || DomHandler.hasClass(event.target.parentElement, 'p-tree-toggler')) {
this.toggleClicked = false; this.toggleClicked = false;