From 16833178f15c2a7106e567d861b1ebfa19409f39 Mon Sep 17 00:00:00 2001 From: mertsincan Date: Tue, 28 Feb 2023 10:33:00 +0000 Subject: [PATCH 1/2] DataTable CSS and responsive structure improvements (#3684) * DataTable CSS and responsive structure improvements Fixed #3682 and #3683 * Update DataTable.vue --- components/datatable/DataTable.d.ts | 16 +- components/datatable/DataTable.vue | 183 ++++------ components/datatable/TableBody.vue | 20 +- .../virtualscroller/VirtualScroller.d.ts | 25 ++ .../virtualscroller/VirtualScroller.vue | 316 ++++++++++++++---- 5 files changed, 348 insertions(+), 212 deletions(-) diff --git a/components/datatable/DataTable.d.ts b/components/datatable/DataTable.d.ts index f4281f2f3..7590f1206 100755 --- a/components/datatable/DataTable.d.ts +++ b/components/datatable/DataTable.d.ts @@ -39,8 +39,6 @@ export declare type DataTableStateStorageType = 'session' | 'local' | undefined; export declare type DataTableEditModeType = 'cell' | 'row' | undefined; -export declare type DataTableScrollDirectionType = 'vertical' | 'horizontal' | 'both' | undefined; - export declare type DataTableScrollHeightType = 'flex' | string | undefined; export declare type DataTableResponsiveLayoutType = 'stack' | 'scroll' | undefined; @@ -663,10 +661,6 @@ export interface DataTableProps { * @see DataTableExportFunctionOptions */ exportFunction?(options: DataTableExportFunctionOptions): any; - /** - * Whether the cell widths scale according to their content or not. Does not apply to scrollable tables. - */ - autoLayout?: boolean | undefined; /** * When enabled, columns can be resized using drag and drop. */ @@ -752,12 +746,6 @@ export interface DataTableProps { * @see DataTableScrollHeightType */ scrollHeight?: DataTableScrollHeightType; - /** - * Orientation of the scrolling, options are 'vertical', 'horizontal' and 'both'. - * @see DataTableScrollDirectionType - * Default value is 'vertical'. - */ - scrollDirection?: DataTableScrollDirectionType; /** * Whether to use the virtualScroller feature. The properties of VirtualScroller component can be used like an object in it. * Note: Currently only vertical orientation mode is supported. @@ -769,9 +757,9 @@ export interface DataTableProps { */ frozenValue?: any[] | undefined; /** - * Defines the responsive mode, valid options are 'stack' and 'scroll'. + * Defines the responsive mode, valid options are 'stack' and 'scroll'. Default value is 'scroll'. * @see DataTableResponsiveLayoutType - * Default value is 'stack'. + * @deprecated since version 3.24.0 */ responsiveLayout?: DataTableResponsiveLayoutType; /** diff --git a/components/datatable/DataTable.vue b/components/datatable/DataTable.vue index e54de07da..ca3154854 100755 --- a/components/datatable/DataTable.vue +++ b/components/datatable/DataTable.vue @@ -29,9 +29,21 @@
- + @@ -401,10 +414,6 @@ export default { type: Function, default: null }, - autoLayout: { - type: Boolean, - default: false - }, resizableColumns: { type: Boolean, default: false @@ -473,10 +482,6 @@ export default { type: Boolean, default: false }, - scrollDirection: { - type: String, - default: 'vertical' - }, virtualScrollerOptions: { type: Object, default: null @@ -491,7 +496,7 @@ export default { }, responsiveLayout: { type: String, - default: 'stack' + default: 'scroll' }, breakpoint: { type: String, @@ -1462,15 +1467,16 @@ export default { this.createStyleElement(); let innerHTML = ''; + let selector = `.p-datatable[${this.attributeSelector}] > .p-datatable-wrapper ${this.virtualScrollerDisabled ? '' : '> .p-virtualscroller'} > .p-datatable-table`; widths.forEach((width, index) => { let colWidth = index === colIndex ? newColumnWidth : nextColumnWidth && index === colIndex + 1 ? nextColumnWidth : width; - let style = this.scrollable ? `flex: 1 1 ${colWidth}px !important` : `width: ${colWidth}px !important`; + let style = `width: ${colWidth}px !important; max-width: ${colWidth}px !important`; innerHTML += ` - .p-datatable[${this.attributeSelector}] .p-datatable-thead > tr > th:nth-child(${index + 1}), - .p-datatable[${this.attributeSelector}] .p-datatable-tbody > tr > td:nth-child(${index + 1}), - .p-datatable[${this.attributeSelector}] .p-datatable-tfoot > tr > td:nth-child(${index + 1}) { + ${selector} > .p-datatable-thead > tr > th:nth-child(${index + 1}), + ${selector} > .p-datatable-tbody > tr > td:nth-child(${index + 1}), + ${selector} > .p-datatable-tfoot > tr > td:nth-child(${index + 1}) { ${style} } `; @@ -1902,14 +1908,15 @@ export default { this.createStyleElement(); let innerHTML = ''; + let selector = `.p-datatable[${this.attributeSelector}] > .p-datatable-wrapper ${this.virtualScrollerDisabled ? '' : '> .p-virtualscroller'} > .p-datatable-table`; widths.forEach((width, index) => { - let style = this.scrollable ? `flex: 1 1 ${width}px !important` : `width: ${width}px !important`; + let style = `width: ${width}px !important; max-width: ${width}px !important`; innerHTML += ` - .p-datatable[${this.attributeSelector}] .p-datatable-thead > tr > th:nth-child(${index + 1}), - .p-datatable[${this.attributeSelector}] .p-datatable-tbody > tr > td:nth-child(${index + 1}), - .p-datatable[${this.attributeSelector}] .p-datatable-tfoot > tr > td:nth-child(${index + 1}) { + ${selector} > .p-datatable-thead > tr > th:nth-child(${index + 1}), + ${selector} > .p-datatable-tbody > tr > td:nth-child(${index + 1}), + ${selector} > .p-datatable-tfoot > tr > td:nth-child(${index + 1}) { ${style} } `; @@ -2034,31 +2041,34 @@ export default { this.responsiveStyleElement.type = 'text/css'; document.head.appendChild(this.responsiveStyleElement); + let tableSelector = `.p-datatable-wrapper ${this.virtualScrollerDisabled ? '' : '> .p-virtualscroller'} > .p-datatable-table`; + let selector = `.p-datatable[${this.attributeSelector}] > ${tableSelector}`; + let gridLinesSelector = `.p-datatable[${this.attributeSelector}].p-datatable-gridlines > ${tableSelector}`; let innerHTML = ` @media screen and (max-width: ${this.breakpoint}) { - .p-datatable[${this.attributeSelector}] .p-datatable-thead > tr > th, - .p-datatable[${this.attributeSelector}] .p-datatable-tfoot > tr > td { + ${selector} > .p-datatable-thead > tr > th, + ${selector} > .p-datatable-tfoot > tr > td { display: none !important; } - .p-datatable[${this.attributeSelector}] .p-datatable-tbody > tr > td { + ${selector} > .p-datatable-tbody > tr > td { display: flex; width: 100% !important; align-items: center; justify-content: space-between; } - .p-datatable[${this.attributeSelector}] .p-datatable-tbody > tr > td:not(:last-child) { + ${selector} > .p-datatable-tbody > tr > td:not(:last-child) { border: 0 none; } - .p-datatable[${this.attributeSelector}].p-datatable-gridlines .p-datatable-tbody > tr > td:last-child { + ${gridLinesSelector} > .p-datatable-tbody > tr > td:last-child { border-top: 0; border-right: 0; border-left: 0; } - .p-datatable[${this.attributeSelector}] .p-datatable-tbody > tr > td > .p-column-title { + ${selector} > .p-datatable-tbody > tr > td > .p-column-title { display: block; } } @@ -2109,6 +2119,9 @@ export default { }, getVirtualScrollerRef() { return this.$refs.virtualScroller; + }, + hasSpacerStyle(style) { + return ObjectUtils.isNotEmpty(style); } }, computed: { @@ -2117,13 +2130,9 @@ export default { 'p-datatable p-component', { 'p-datatable-hoverable-rows': this.rowHover || this.selectionMode, - 'p-datatable-auto-layout': this.autoLayout, 'p-datatable-resizable': this.resizableColumns, 'p-datatable-resizable-fit': this.resizableColumns && this.columnResizeMode === 'fit', 'p-datatable-scrollable': this.scrollable, - 'p-datatable-scrollable-vertical': this.scrollable && this.scrollDirection === 'vertical', - 'p-datatable-scrollable-horizontal': this.scrollable && this.scrollDirection === 'horizontal', - 'p-datatable-scrollable-both': this.scrollable && this.scrollDirection === 'both', 'p-datatable-flex-scrollable': this.scrollable && this.scrollHeight === 'flex', 'p-datatable-responsive-stack': this.responsiveLayout === 'stack', 'p-datatable-responsive-scroll': this.responsiveLayout === 'scroll', @@ -2134,6 +2143,17 @@ export default { } ]; }, + tableStyleClass() { + return [ + 'p-datatable-table', + { + 'p-datatable-scrollable-table': this.scrollable, + 'p-datatable-resizable-table': this.resizableColumns, + 'p-datatable-resizable-table-fit': this.resizableColumns && this.columnResizeMode === 'fit' + }, + this.tableClass + ]; + }, columns() { let children = this.getChildren(); @@ -2266,10 +2286,13 @@ export default { position: relative; } -.p-datatable table { - border-collapse: collapse; - min-width: 100%; - table-layout: fixed; +.p-datatable > .p-datatable-wrapper { + overflow: auto; +} + +.p-datatable-table { + border-spacing: 0px; + width: 100%; } .p-datatable .p-sortable-column { @@ -2289,59 +2312,27 @@ export default { justify-content: center; } -.p-datatable-responsive-scroll > .p-datatable-wrapper { - overflow-x: auto; -} - -.p-datatable-responsive-scroll > .p-datatable-wrapper > table, -.p-datatable-auto-layout > .p-datatable-wrapper > table { - table-layout: auto; -} - .p-datatable-hoverable-rows .p-selectable-row { cursor: pointer; } /* Scrollable */ -.p-datatable-scrollable .p-datatable-wrapper { +.p-datatable-scrollable > .p-datatable-wrapper { position: relative; - overflow: auto; } -.p-datatable-scrollable .p-datatable-thead, -.p-datatable-scrollable .p-datatable-tbody, -.p-datatable-scrollable .p-datatable-tfoot { - display: block; -} - -.p-datatable-scrollable .p-datatable-thead > tr, -.p-datatable-scrollable .p-datatable-tbody > tr, -.p-datatable-scrollable .p-datatable-tfoot > tr { - display: flex; - flex-wrap: nowrap; - width: 100%; -} - -.p-datatable-scrollable .p-datatable-thead > tr > th, -.p-datatable-scrollable .p-datatable-tbody > tr > td, -.p-datatable-scrollable .p-datatable-tfoot > tr > td { - display: flex; - flex: 1 1 0; - align-items: center; -} - -.p-datatable-scrollable .p-datatable-thead { +.p-datatable-scrollable-table > .p-datatable-thead { position: sticky; top: 0; z-index: 1; } -.p-datatable-scrollable .p-datatable-frozen-tbody { +.p-datatable-scrollable-table > .p-datatable-frozen-tbody { position: sticky; z-index: 1; } -.p-datatable-scrollable .p-datatable-tfoot { +.p-datatable-scrollable-table > .p-datatable-tfoot { position: sticky; bottom: 0; z-index: 1; @@ -2356,72 +2347,38 @@ export default { z-index: 1; } -.p-datatable-scrollable-both .p-datatable-thead > tr > th, -.p-datatable-scrollable-both .p-datatable-tbody > tr > td, -.p-datatable-scrollable-both .p-datatable-tfoot > tr > td, -.p-datatable-scrollable-horizontal .p-datatable-thead > tr > th .p-datatable-scrollable-horizontal .p-datatable-tbody > tr > td, -.p-datatable-scrollable-horizontal .p-datatable-tfoot > tr > td { - flex: 1 0 auto; -} - .p-datatable-flex-scrollable { display: flex; flex-direction: column; height: 100%; } -.p-datatable-flex-scrollable .p-datatable-wrapper { +.p-datatable-flex-scrollable > .p-datatable-wrapper { display: flex; flex-direction: column; flex: 1; height: 100%; } -.p-datatable-scrollable .p-rowgroup-header { +.p-datatable-scrollable-table > .p-datatable-tbody > .p-rowgroup-header { position: sticky; z-index: 1; } -.p-datatable-scrollable.p-datatable-grouped-header .p-datatable-thead, -.p-datatable-scrollable.p-datatable-grouped-footer .p-datatable-tfoot { - display: table; - border-collapse: collapse; - width: 100%; - table-layout: fixed; -} - -.p-datatable-scrollable.p-datatable-grouped-header .p-datatable-thead > tr, -.p-datatable-scrollable.p-datatable-grouped-footer .p-datatable-tfoot > tr { - display: table-row; -} - -.p-datatable-scrollable.p-datatable-grouped-header .p-datatable-thead > tr > th, -.p-datatable-scrollable.p-datatable-grouped-footer .p-datatable-tfoot > tr > td { - display: table-cell; -} - -.p-datatable-scrollable .p-virtualscroller > .p-datatable-table { - display: inline-block; /* For Safari */ -} - /* Resizable */ -.p-datatable-resizable > .p-datatable-wrapper { - overflow-x: auto; -} - -.p-datatable-resizable .p-datatable-thead > tr > th, -.p-datatable-resizable .p-datatable-tfoot > tr > td, -.p-datatable-resizable .p-datatable-tbody > tr > td { +.p-datatable-resizable-table > .p-datatable-thead > tr > th, +.p-datatable-resizable-table > .p-datatable-tfoot > tr > td, +.p-datatable-resizable-table > .p-datatable-tbody > tr > td { overflow: hidden; white-space: nowrap; } -.p-datatable-resizable .p-resizable-column:not(.p-frozen-column) { +.p-datatable-resizable-table > .p-datatable-thead > tr > th.p-resizable-column:not(.p-frozen-column) { background-clip: padding-box; position: relative; } -.p-datatable-resizable-fit .p-resizable-column:last-child .p-column-resizer { +.p-datatable-resizable-table-fit > .p-datatable-thead > tr > th.p-resizable-column:last-child .p-column-resizer { display: none; } @@ -2560,7 +2517,11 @@ export default { } /* VirtualScroller */ -.p-datatable .p-virtualscroller-loading { +.p-datatable-virtualscroller-spacer { + display: flex; +} + +.p-datatable .p-virtualscroller .p-virtualscroller-loading { transform: none !important; min-height: 0; position: sticky; diff --git a/components/datatable/TableBody.vue b/components/datatable/TableBody.vue index 927faff0b..7e52290cd 100755 --- a/components/datatable/TableBody.vue +++ b/components/datatable/TableBody.vue @@ -67,7 +67,9 @@ - + + + @@ -238,13 +240,6 @@ export default { isARowSelected: false }; }, - watch: { - virtualScrollerContentProps(newValue, oldValue) { - if (!this.isVirtualScrollerDisabled && this.getVirtualScrollerProp('vertical') && this.getVirtualScrollerProp('itemSize', oldValue) !== this.getVirtualScrollerProp('itemSize', newValue)) { - this.updateVirtualScrollerPosition(); - } - } - }, mounted() { if (this.frozenRow) { this.updateFrozenRowStickyPosition(); @@ -253,10 +248,6 @@ export default { if (this.scrollable && this.rowGroupMode === 'subheader') { this.updateFrozenRowGroupHeaderStickyPosition(); } - - if (!this.isVirtualScrollerDisabled && this.getVirtualScrollerProp('vertical')) { - this.updateVirtualScrollerPosition(); - } }, updated() { if (this.frozenRow) { @@ -538,11 +529,6 @@ export default { this.rowGroupHeaderStyleObject.top = tableHeaderHeight + 'px'; }, - updateVirtualScrollerPosition() { - const tableHeaderHeight = DomHandler.getOuterHeight(this.$el.previousElementSibling); - - this.$el.style.top = (this.$el.style.top || 0) + tableHeaderHeight + 'px'; - }, getVirtualScrollerProp(option, options) { options = options || this.virtualScrollerContentProps; diff --git a/components/virtualscroller/VirtualScroller.d.ts b/components/virtualscroller/VirtualScroller.d.ts index 1b1cbcfcc..2fa448fd8 100644 --- a/components/virtualscroller/VirtualScroller.d.ts +++ b/components/virtualscroller/VirtualScroller.d.ts @@ -128,6 +128,11 @@ export interface VirtualScrollerProps { * Default value is 0. */ delay?: number | undefined; + /** + * Delay after window's resize finishes. + * @defaultValue 10 + */ + resizeDelay?: number | undefined; /** * Defines if data is loaded and interacted with in lazy manner. */ @@ -163,6 +168,26 @@ export interface VirtualScrollerProps { * Default value is 0. */ tabindex?: number | string | undefined; + /** + * When enabled, positions the content as inline. + * @defaultValue false + */ + inline?: boolean | undefined; + /** + * Used to specify how many items to load in each load method in lazy mode. + * @defaultValue 0 + */ + step?: number | undefined; + /** + * Used to append each loaded item to top without removing any items from the DOM. Using very large data may cause the browser to crash. + * @defaultValue false + */ + appendOnly?: boolean | undefined; + /** + * Whether to dynamically change the height or width of scrollable container. + * @defaultValue false + */ + autoSize?: boolean | undefined; } export interface VirtualScrollerSlots { diff --git a/components/virtualscroller/VirtualScroller.vue b/components/virtualscroller/VirtualScroller.vue index 93efe8ac2..89a3d5e85 100644 --- a/components/virtualscroller/VirtualScroller.vue +++ b/components/virtualscroller/VirtualScroller.vue @@ -42,6 +42,8 @@