Fixed #6489 - TreeTable: ContextMenu implementation
parent
0bc1689995
commit
aa73025403
|
@ -30,6 +30,14 @@ export default {
|
|||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
contextMenu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
contextMenuSelection: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: 0
|
||||
|
|
|
@ -173,6 +173,21 @@ export interface TreeTableFilterEvent extends TreeTableSortEvent {
|
|||
filteredValue: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom row context menu event.
|
||||
* @see {@link TreeTableEmitsOptions['row-contextmenu']}
|
||||
*/
|
||||
export interface TreeTableRowContextMenuEvent {
|
||||
/**
|
||||
* Browser event.
|
||||
*/
|
||||
originalEvent: Event;
|
||||
/**
|
||||
* Selected row data.
|
||||
*/
|
||||
node: TreeNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom sort metadata.
|
||||
*/
|
||||
|
@ -420,6 +435,15 @@ export interface TreeTableProps {
|
|||
* @defaultValue false
|
||||
*/
|
||||
metaKeySelection?: boolean | undefined;
|
||||
/**
|
||||
* Enables context menu integration.
|
||||
* @defaultValue false
|
||||
*/
|
||||
contextMenu?: boolean | undefined;
|
||||
/**
|
||||
* Selected row instance with the ContextMenu.
|
||||
*/
|
||||
contextMenuSelection?: any | any[] | undefined;
|
||||
/**
|
||||
* Number of rows to display per page.
|
||||
*/
|
||||
|
@ -730,6 +754,11 @@ export interface TreeTableEmitsOptions {
|
|||
* @param {TreeSelectionKeys} value - New selection keys.
|
||||
*/
|
||||
'update:selectionKeys'(event: TreeTableSelectionKeys): void;
|
||||
/**
|
||||
* Emitted when the contextMenuSelection changes.
|
||||
* @param {*} value - New value.
|
||||
*/
|
||||
'update:contextMenuSelection'(value: any[] | any | undefined): void;
|
||||
/**
|
||||
* Emitted when the first changes.
|
||||
* @param {number} value - New value.
|
||||
|
@ -795,6 +824,11 @@ export interface TreeTableEmitsOptions {
|
|||
* @param {Event} event - Browser event.
|
||||
*/
|
||||
'column-resize-end'(event: Event): void;
|
||||
/**
|
||||
* Callback to invoke when a row is selected with a ContextMenu.
|
||||
* @param {TreeTableRowContextMenuEvent} event - Custom row context menu event.
|
||||
*/
|
||||
'row-contextmenu'(event: TreeTableRowContextMenuEvent): void;
|
||||
}
|
||||
|
||||
export declare type TreeTableEmits = EmitFn<TreeTableEmitsOptions>;
|
||||
|
|
|
@ -97,10 +97,13 @@
|
|||
:ariaPosInset="index + 1"
|
||||
:tabindex="setTabindex(node, index)"
|
||||
:loadingMode="loadingMode"
|
||||
:contextMenu="contextMenu"
|
||||
:contextMenuSelection="contextMenuSelection"
|
||||
:templates="$slots"
|
||||
@node-toggle="onNodeToggle"
|
||||
@node-click="onNodeClick"
|
||||
@checkbox-change="onCheckboxChange"
|
||||
@row-rightclick="onRowRightClick($event)"
|
||||
:unstyled="unstyled"
|
||||
:pt="pt"
|
||||
></TTRow>
|
||||
|
@ -198,7 +201,9 @@ export default {
|
|||
'update:multiSortMeta',
|
||||
'sort',
|
||||
'filter',
|
||||
'column-resize-end'
|
||||
'column-resize-end',
|
||||
'update:contextMenuSelection',
|
||||
'row-contextmenu'
|
||||
],
|
||||
provide() {
|
||||
return {
|
||||
|
@ -348,6 +353,15 @@ export default {
|
|||
if (event.check) this.$emit('node-select', event.node);
|
||||
else this.$emit('node-unselect', event.node);
|
||||
},
|
||||
onRowRightClick(event) {
|
||||
if (this.contextMenu) {
|
||||
clearSelection();
|
||||
event.originalEvent.target.focus();
|
||||
}
|
||||
|
||||
this.$emit('update:contextMenuSelection', event.node);
|
||||
this.$emit('row-contextmenu', event);
|
||||
},
|
||||
isSingleSelectionMode() {
|
||||
return this.selectionMode === 'single';
|
||||
},
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
@click="onClick"
|
||||
@keydown="onKeyDown"
|
||||
@touchend="onTouchEnd"
|
||||
@contextmenu="onRowRightClick"
|
||||
v-bind="ptm('row', ptmOptions)"
|
||||
:data-p-selected="selected"
|
||||
:data-p-selected-contextmenu="contextMenuSelection && isSelectedWithContextMenu"
|
||||
>
|
||||
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
|
||||
<TTBodyCell
|
||||
|
@ -51,12 +53,15 @@
|
|||
:expandedKeys="expandedKeys"
|
||||
:selectionMode="selectionMode"
|
||||
:selectionKeys="selectionKeys"
|
||||
:contextMenu="contextMenu"
|
||||
:contextMenuSelection="contextMenuSelection"
|
||||
:indentation="indentation"
|
||||
:ariaPosInset="node.children.indexOf(childNode) + 1"
|
||||
:ariaSetSize="node.children.length"
|
||||
:templates="templates"
|
||||
@node-toggle="$emit('node-toggle', $event)"
|
||||
@node-click="$emit('node-click', $event)"
|
||||
@row-rightclick="$emit('row-rightclick', $event)"
|
||||
@checkbox-change="onCheckboxChange"
|
||||
:unstyled="unstyled"
|
||||
:pt="pt"
|
||||
|
@ -66,7 +71,7 @@
|
|||
|
||||
<script>
|
||||
import { find, findSingle, focus, getAttribute, isClickable } from '@primeuix/utils/dom';
|
||||
import { resolveFieldData } from '@primeuix/utils/object';
|
||||
import { equals, resolveFieldData } from '@primeuix/utils/object';
|
||||
import BaseComponent from '@primevue/core/basecomponent';
|
||||
import { getVNodeProp } from '@primevue/core/utils';
|
||||
import BodyCell from './BodyCell.vue';
|
||||
|
@ -75,7 +80,7 @@ export default {
|
|||
name: 'TreeTableRow',
|
||||
hostName: 'TreeTable',
|
||||
extends: BaseComponent,
|
||||
emits: ['node-click', 'node-toggle', 'checkbox-change', 'nodeClick', 'nodeToggle', 'checkboxChange'],
|
||||
emits: ['node-click', 'node-toggle', 'checkbox-change', 'nodeClick', 'nodeToggle', 'checkboxChange', 'row-rightclick', 'rowRightclick'],
|
||||
props: {
|
||||
node: {
|
||||
type: null,
|
||||
|
@ -132,6 +137,14 @@ export default {
|
|||
templates: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
contextMenu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
contextMenuSelection: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
nodeTouched: false,
|
||||
|
@ -156,6 +169,12 @@ export default {
|
|||
});
|
||||
this.nodeTouched = false;
|
||||
},
|
||||
onRowRightClick(event) {
|
||||
this.$emit('row-rightclick', {
|
||||
originalEvent: event,
|
||||
node: this.node
|
||||
});
|
||||
},
|
||||
onTouchEnd() {
|
||||
this.nodeTouched = true;
|
||||
},
|
||||
|
@ -426,6 +445,13 @@ export default {
|
|||
selected() {
|
||||
return this.selectionMode && this.selectionKeys ? this.selectionKeys[this.nodeKey(this.node)] === true : false;
|
||||
},
|
||||
isSelectedWithContextMenu() {
|
||||
if (this.node && this.contextMenuSelection) {
|
||||
return equals(this.node, this.contextMenuSelection, this.dataKey);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
checked() {
|
||||
return this.selectionKeys ? this.selectionKeys[this.nodeKey(this.node)] && this.selectionKeys[this.nodeKey(this.node)].checked : false;
|
||||
},
|
||||
|
|
|
@ -198,9 +198,9 @@ const theme = ({ dt }) => `
|
|||
|
||||
.p-treetable-tbody > tr:focus-visible,
|
||||
.p-treetable-tbody > tr.p-treetable-contextmenu-row-selected {
|
||||
box-shadow: ${dt('treetable.body.cell.focus.ring.shadow')};
|
||||
outline: ${dt('treetable.body.cell.focus.ring.width')} ${dt('treetable.body.cell.focus.ring.style')} ${dt('treetable.body.cell.focus.ring.color')};
|
||||
outline-offset: ${dt('treetable.body.cell.focus.ring.offset')};
|
||||
box-shadow: ${dt('treetable.row.focus.ring.shadow')};
|
||||
outline: ${dt('treetable.row.focus.ring.width')} ${dt('treetable.row.focus.ring.style')} ${dt('treetable.row.focus.ring.color')};
|
||||
outline-offset: ${dt('treetable.row.focus.ring.offset')};
|
||||
}
|
||||
|
||||
.p-treetable-tfoot > tr > td {
|
||||
|
@ -470,9 +470,10 @@ const classes = {
|
|||
sortIcon: 'p-treetable-sort-icon',
|
||||
pcSortBadge: 'p-treetable-sort-badge',
|
||||
tbody: 'p-treetable-tbody',
|
||||
row: ({ instance }) => [
|
||||
row: ({ props, instance }) => [
|
||||
{
|
||||
'p-treetable-row-selected': instance.selected
|
||||
'p-treetable-row-selected': instance.selected,
|
||||
'p-treetable-contextmenu-row-selected': props.contextMenuSelection && instance.isSelectedWithContextMenu
|
||||
}
|
||||
],
|
||||
bodyCell: ({ instance }) => [
|
||||
|
|
Loading…
Reference in New Issue