Refactor #5678 - TreeTable CSS and responsive structure improvements
parent
2c65e1b3fd
commit
5cb78b9b3c
|
@ -210,12 +210,6 @@ const TreeTableProps = [
|
|||
default: 'false',
|
||||
description: 'When specified, enables horizontal and/or vertical scrolling.'
|
||||
},
|
||||
{
|
||||
name: 'scrollDirection',
|
||||
type: 'string',
|
||||
default: 'vertical',
|
||||
description: 'Orientation of the scrolling, options are "vertical", "horizontal" and "both".'
|
||||
},
|
||||
{
|
||||
name: 'scrollHeight',
|
||||
type: 'string',
|
||||
|
|
|
@ -150,22 +150,26 @@ export default {
|
|||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
scrollDirection: {
|
||||
type: String,
|
||||
default: 'vertical'
|
||||
},
|
||||
scrollHeight: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
responsiveLayout: {
|
||||
type: String,
|
||||
default: null
|
||||
default: 'scroll'
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
tableStyle: {
|
||||
type: null,
|
||||
default: null
|
||||
},
|
||||
tableClass: {
|
||||
type: [String, Object],
|
||||
default: null
|
||||
},
|
||||
tableProps: {
|
||||
type: Object,
|
||||
default: null
|
||||
|
|
|
@ -137,7 +137,6 @@ export default {
|
|||
selected: this.$parent.selected,
|
||||
frozen: this.columnProp('frozen'),
|
||||
scrollable: this.$parentInstance.scrollable,
|
||||
scrollDirection: this.$parentInstance.scrollDirection,
|
||||
showGridlines: this.$parentInstance.showGridlines,
|
||||
size: this.$parentInstance?.size
|
||||
}
|
||||
|
|
|
@ -99,7 +99,6 @@ export default {
|
|||
frozen: this.$parentInstance.scrollable && this.columnProp('frozen'),
|
||||
resizable: this.resizableColumns,
|
||||
scrollable: this.$parentInstance.scrollable,
|
||||
scrollDirection: this.$parentInstance.scrollDirection,
|
||||
showGridlines: this.$parentInstance.showGridlines,
|
||||
size: this.$parentInstance?.size
|
||||
}
|
||||
|
|
|
@ -586,20 +586,18 @@ export interface TreeTableProps {
|
|||
* Height of the scroll viewport in fixed pixels or the 'flex' keyword for a dynamic size.
|
||||
*/
|
||||
scrollHeight?: HintedString<'flex'> | undefined;
|
||||
/**
|
||||
* Orientation of the scrolling.
|
||||
* @defaultValue vertical
|
||||
*/
|
||||
scrollDirection?: 'vertical' | 'horizontal' | 'both' | undefined;
|
||||
/**
|
||||
* Defines the responsive mode, currently only option is scroll.
|
||||
* @defaultValue stack
|
||||
*/
|
||||
responsiveLayout?: 'stack' | 'scroll' | undefined;
|
||||
/**
|
||||
* Defines the size of the table.
|
||||
*/
|
||||
size?: 'small' | 'large' | undefined;
|
||||
/**
|
||||
* Inline style of the table element.
|
||||
*/
|
||||
tableStyle?: string | object | undefined;
|
||||
/**
|
||||
* Style class of the table element.
|
||||
*/
|
||||
tableClass?: string | object | undefined;
|
||||
/**
|
||||
* Props to pass to the table element.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div :class="cx('root')" data-scrollselectors=".p-treetable-scrollable-body" role="table" v-bind="ptmi('root')">
|
||||
<div :class="cx('root')" data-scrollselectors=".p-treetable-scrollable-body" v-bind="ptmi('root')">
|
||||
<slot></slot>
|
||||
<div v-if="loading && loadingMode === 'mask'" :class="cx('loading')" v-bind="ptm('loading')">
|
||||
<div :class="cx('mask')" v-bind="ptm('mask')">
|
||||
|
@ -51,9 +51,9 @@
|
|||
<slot name="paginatorrowsperpagedropdownicon" :class="slotProps.class"></slot>
|
||||
</template>
|
||||
</TTPaginator>
|
||||
<div :class="cx('tableContainer')" :style="{ maxHeight: scrollHeight }" v-bind="ptm('tableContainer')">
|
||||
<table ref="table" role="table" v-bind="{ ...tableProps, ...ptm('table') }">
|
||||
<thead :class="cx('thead')" role="rowgroup" v-bind="ptm('thead')">
|
||||
<div :class="cx('tableContainer')" :style="[sx('tableContainer'), { maxHeight: scrollHeight }]" v-bind="ptm('tableContainer')">
|
||||
<table ref="table" role="table" :class="[cx('table'), tableClass]" :style="tableStyle" v-bind="{ ...tableProps, ...ptm('table') }">
|
||||
<thead :class="cx('thead')" :style="sx('thead')" role="rowgroup" v-bind="ptm('thead')">
|
||||
<tr role="row" v-bind="ptm('headerRow')">
|
||||
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
|
||||
<TTHeaderCell
|
||||
|
@ -111,7 +111,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot v-if="hasFooter" :class="cx('tfoot')" role="rowgroup" v-bind="ptm('tfoot')">
|
||||
<tfoot v-if="hasFooter" :class="cx('tfoot')" :style="sx('tfoot')" role="rowgroup" v-bind="ptm('tfoot')">
|
||||
<tr role="row" v-bind="ptm('footerRow')">
|
||||
<template v-for="(col, i) of columns" :key="columnProp(col, 'columnKey') || columnProp(col, 'field') || i">
|
||||
<TTFooterCell v-if="!columnProp(col, 'hidden')" :column="col" :index="i" :unstyled="unstyled" :pt="pt"></TTFooterCell>
|
||||
|
@ -171,7 +171,7 @@
|
|||
import { FilterService } from 'primevue/api';
|
||||
import SpinnerIcon from 'primevue/icons/spinner';
|
||||
import Paginator from 'primevue/paginator';
|
||||
import { DomHandler, HelperSet, ObjectUtils } from 'primevue/utils';
|
||||
import { DomHandler, HelperSet, ObjectUtils, UniqueComponentId } from 'primevue/utils';
|
||||
import BaseTreeTable from './BaseTreeTable.vue';
|
||||
import FooterCell from './FooterCell.vue';
|
||||
import HeaderCell from './HeaderCell.vue';
|
||||
|
@ -240,16 +240,10 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.scrollable && this.scrollDirection !== 'vertical') {
|
||||
this.updateScrollWidth();
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
if (this.scrollable && this.scrollDirection !== 'vertical') {
|
||||
this.updateScrollWidth();
|
||||
}
|
||||
this.$el.setAttribute(this.attributeSelector, '');
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.destroyStyleElement();
|
||||
this.d_columns.clear();
|
||||
},
|
||||
methods: {
|
||||
|
@ -649,21 +643,18 @@ export default {
|
|||
let nextColumnWidth = nextColumn.offsetWidth - delta;
|
||||
|
||||
if (newColumnWidth > 15 && nextColumnWidth > 15) {
|
||||
if (!this.scrollable) {
|
||||
this.resizeColumnElement.style.width = newColumnWidth + 'px';
|
||||
|
||||
if (nextColumn) {
|
||||
nextColumn.style.width = nextColumnWidth + 'px';
|
||||
}
|
||||
} else {
|
||||
this.resizeTableCells(newColumnWidth, nextColumnWidth);
|
||||
}
|
||||
}
|
||||
} else if (this.columnResizeMode === 'expand') {
|
||||
this.$refs.table.style.width = this.$refs.table.offsetWidth + delta + 'px';
|
||||
const tableWidth = this.$refs.table.offsetWidth + delta + 'px';
|
||||
|
||||
if (!this.scrollable) this.resizeColumnElement.style.width = newColumnWidth + 'px';
|
||||
else this.resizeTableCells(newColumnWidth);
|
||||
const updateTableWidth = (el) => {
|
||||
!!el && (el.style.width = el.style.minWidth = tableWidth);
|
||||
};
|
||||
|
||||
// Reasoning: resize table cells before updating the table width so that it can use existing computed cell widths and adjust only the one column.
|
||||
this.resizeTableCells(newColumnWidth);
|
||||
updateTableWidth(this.$refs.table);
|
||||
}
|
||||
|
||||
this.$emit('column-resize-end', {
|
||||
|
@ -681,23 +672,31 @@ export default {
|
|||
},
|
||||
resizeTableCells(newColumnWidth, nextColumnWidth) {
|
||||
let colIndex = DomHandler.index(this.resizeColumnElement);
|
||||
let children = this.$refs.table.children;
|
||||
let widths = [];
|
||||
let headers = DomHandler.find(this.$refs.table, 'thead[data-pc-section="thead"] > tr > th');
|
||||
|
||||
for (let child of children) {
|
||||
for (let row of child.children) {
|
||||
let resizeCell = row.children[colIndex];
|
||||
headers.forEach((header) => widths.push(DomHandler.getOuterWidth(header)));
|
||||
|
||||
resizeCell.style.flex = '0 0 ' + newColumnWidth + 'px';
|
||||
this.destroyStyleElement();
|
||||
this.createStyleElement();
|
||||
|
||||
if (this.columnResizeMode === 'fit') {
|
||||
let nextCell = resizeCell.nextElementSibling;
|
||||
let innerHTML = '';
|
||||
let selector = `[data-pc-name="treetable"][${this.attributeSelector}] > [data-pc-section="tablecontainer"] > table[data-pc-section="table"]`;
|
||||
|
||||
if (nextCell) {
|
||||
nextCell.style.flex = '0 0 ' + nextColumnWidth + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
widths.forEach((width, index) => {
|
||||
let colWidth = index === colIndex ? newColumnWidth : nextColumnWidth && index === colIndex + 1 ? nextColumnWidth : width;
|
||||
let style = `width: ${colWidth}px !important; max-width: ${colWidth}px !important`;
|
||||
|
||||
innerHTML += `
|
||||
${selector} > thead[data-pc-section="thead"] > tr > th:nth-child(${index + 1}),
|
||||
${selector} > tbody[data-pc-section="tbody"] > tr > td:nth-child(${index + 1}),
|
||||
${selector} > tfoot[data-pc-section="tfoot"] > tr > td:nth-child(${index + 1}) {
|
||||
${style}
|
||||
}
|
||||
`;
|
||||
});
|
||||
|
||||
this.styleElement.innerHTML = innerHTML;
|
||||
},
|
||||
bindColumnResizeEvents() {
|
||||
if (!this.documentColumnResizeListener) {
|
||||
|
@ -750,12 +749,21 @@ export default {
|
|||
hasGlobalFilter() {
|
||||
return this.filters && Object.prototype.hasOwnProperty.call(this.filters, 'global');
|
||||
},
|
||||
updateScrollWidth() {
|
||||
this.$refs.table.style.width = this.$refs.table.scrollWidth + 'px';
|
||||
},
|
||||
getItemLabel(node) {
|
||||
return node.data.name;
|
||||
},
|
||||
createStyleElement() {
|
||||
this.styleElement = document.createElement('style');
|
||||
this.styleElement.type = 'text/css';
|
||||
DomHandler.setAttribute(this.styleElement, 'nonce', this.$primevue?.config?.csp?.nonce);
|
||||
document.head.appendChild(this.styleElement);
|
||||
},
|
||||
destroyStyleElement() {
|
||||
if (this.styleElement) {
|
||||
document.head.removeChild(this.styleElement);
|
||||
this.styleElement = null;
|
||||
}
|
||||
},
|
||||
setTabindex(node, index) {
|
||||
if (this.isNodeSelected(node)) {
|
||||
this.hasASelectedNode = true;
|
||||
|
@ -852,6 +860,9 @@ export default {
|
|||
|
||||
return data ? data.length : 0;
|
||||
}
|
||||
},
|
||||
attributeSelector() {
|
||||
return UniqueComponentId();
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
|
|
@ -427,6 +427,7 @@ p-treetable-gridlines .p-treetable-tbody > tr:last-child>td {
|
|||
transition: background-color ${dt('transition.duration')}, color ${dt('transition.duration')}, border-color ${dt('transition.duration')}, box-shadow ${dt('transition.duration')}, outline-color ${dt('transition.duration')};
|
||||
outline-color: transparent;
|
||||
user-select: none;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.p-treetable-row-toggle-button:enabled:hover {
|
||||
|
@ -443,6 +444,11 @@ p-treetable-gridlines .p-treetable-tbody > tr:last-child>td {
|
|||
background: ${dt('treetable.row.action.highlight.hover.background')};
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.p-treetable .p-treetable-row-checkbox {
|
||||
vertical-align: middle;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
`;
|
||||
|
||||
const classes = {
|
||||
|
@ -465,12 +471,20 @@ const classes = {
|
|||
header: 'p-treetable-header',
|
||||
paginator: ({ position }) => 'p-treetable-paginator-' + position,
|
||||
tableContainer: 'p-treetable-table-container',
|
||||
table: ({ props }) => [
|
||||
'p-treetable-table',
|
||||
{
|
||||
'p-treetable-scrollable-table': props.scrollable,
|
||||
'p-treetable-resizable-table': props.resizableColumns,
|
||||
'p-treetable-resizable-table-fit': props.resizableColumns && props.columnResizeMode === 'fit'
|
||||
}
|
||||
],
|
||||
thead: 'p-treetable-thead',
|
||||
headerCell: ({ instance, props }) => [
|
||||
headerCell: ({ instance, props, context }) => [
|
||||
{
|
||||
'p-treetable-sortable-column': instance.columnProp('sortable'),
|
||||
'p-treetable-resizable-column': props.resizableColumns,
|
||||
'p-treetable-column-sorted': instance.isColumnSorted(),
|
||||
'p-treetable-column-sorted': context?.sorted,
|
||||
'p-treetable-frozen-column': instance.columnProp('frozen')
|
||||
}
|
||||
],
|
||||
|
@ -503,8 +517,15 @@ const classes = {
|
|||
columnResizeHelper: 'p-treetable-column-resize-indicator'
|
||||
};
|
||||
|
||||
const inlineStyles = {
|
||||
tableContainer: { overflow: 'auto' },
|
||||
thead: { position: 'sticky' },
|
||||
tfoot: { position: 'sticky' }
|
||||
};
|
||||
|
||||
export default BaseStyle.extend({
|
||||
name: 'treetable',
|
||||
theme,
|
||||
classes
|
||||
classes,
|
||||
inlineStyles
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue