diff --git a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridVirtualize.razor b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridVirtualize.razor index e766da3431..086965438c 100644 --- a/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridVirtualize.razor +++ b/examples/Demo/Shared/Pages/DataGrid/Examples/DataGridVirtualize.razor @@ -26,7 +26,6 @@ Simulate data loading - @code { FluentDataGrid? grid; FluentSwitch? _clearToggle; diff --git a/src/Core/Components/DataGrid/Columns/ColumnBase.razor b/src/Core/Components/DataGrid/Columns/ColumnBase.razor index 17b868f5df..c7a7a25768 100644 --- a/src/Core/Components/DataGrid/Columns/ColumnBase.razor +++ b/src/Core/Components/DataGrid/Columns/ColumnBase.razor @@ -21,7 +21,7 @@ @if (AnyColumnActionEnabled) { - +
@Title
@if (Grid.SortByAscending.HasValue && IsActiveSortColumn) @@ -90,13 +90,24 @@ else { string? tooltip = Tooltip ? (HeaderTooltip ?? Title) : null; - string? wdelta = "20px"; + string? wdelta = "10px"; + string? align; if (Grid.ResizeType is not null || ColumnOptions is not null) { wdelta = "56px"; } -
+ + // determine align string based on Align value + align = Align switch + { + Align.Start => "flex-start", + Align.Center => "center", + Align.End => "flex-end", + _ => "flex-start" + }; + +
@if (Align == Align.Start || Align == Align.Center) { @if (Grid.ResizeType is not null) diff --git a/src/Core/Components/DataGrid/Columns/ColumnBase.razor.css b/src/Core/Components/DataGrid/Columns/ColumnBase.razor.css index cbf496e9c2..d8dfd0a8e3 100644 --- a/src/Core/Components/DataGrid/Columns/ColumnBase.razor.css +++ b/src/Core/Components/DataGrid/Columns/ColumnBase.razor.css @@ -1,5 +1,5 @@ .col-title { - padding: 0.4rem 0.8rem; + padding: 6px 16px; user-select: none; } diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor b/src/Core/Components/DataGrid/FluentDataGrid.razor index a6576af49a..071d862b77 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor @@ -193,7 +193,7 @@ @if (ResizableColumns) { - +
} } diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.css b/src/Core/Components/DataGrid/FluentDataGrid.razor.css index 58a06b2938..e0b58bbce7 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor.css +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.css @@ -64,19 +64,15 @@ ::deep .resize-handle { position: absolute; - top: 5px; + top: 6px; right: 0; left: unset; bottom: 0; - height: 32px; + height: 30px; cursor: col-resize; - margin-left: calc(var(--design-unit) * 2px); - width: calc(var(--design-unit) * 1px + 2px); -} - -[dir=rtl] * ::deep .resize-handle { - left: 0; - right: unset; + width: 6px; + border-inline-end: 1px solid var(--neutral-stroke-divider-rest); + ; } .header { diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.js b/src/Core/Components/DataGrid/FluentDataGrid.razor.js index 9c3d7cc8bd..21e7f54641 100644 --- a/src/Core/Components/DataGrid/FluentDataGrid.razor.js +++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.js @@ -160,108 +160,154 @@ export function checkColumnPopupPosition(gridElement, selector) { export function enableColumnResizing(gridElement) { const columns = []; - let min = 75; - let headerBeingResized; - let resizeHandle; - const headers = gridElement.querySelectorAll('.column-header.resizable'); if (headers.length === 0) { return; } - headers.forEach(header => { + const isRTL = getComputedStyle(gridElement).direction === 'rtl'; + const isGrid = gridElement.classList.contains('grid') + + let tableHeight = gridElement.offsetHeight; + // rows have not been loaded yet, so we need to calculate the height + if (tableHeight < 70) { + // by getting the aria rowcount attribute + const rowCount = gridElement.getAttribute('aria-rowcount'); + if (rowCount) { + const rowHeight = gridElement.querySelector('thead tr th').offsetHeight; + // and multiply by the itemsize (== height of the header cells) + tableHeight = rowCount * rowHeight; + } + } + + headers.forEach((header) => { columns.push({ header, - size: `minmax(${minWidth}px,auto)`, + size: `${header.clientWidth}px`, }); - const onPointerMove = (e) => requestAnimationFrame(() => { - if (!headerBeingResized) { - return; - } - gridElement.style.tableLayout = "fixed"; + const div = createDiv(tableHeight, isRTL); + header.appendChild(div); + header.style.position = 'relative'; + setListeners(div, isRTL); + }); - const horizontalScrollOffset = document.documentElement.scrollLeft; - let width; + let initialWidths; + if (gridElement.style.gridTemplateColumns) { + initialWidths = gridElement.style.gridTemplateColumns; + } else { + initialWidths = columns.map(({ size }) => size).join(' '); - if (document.body.dir === '' || document.body.dir === 'ltr') { - width = (horizontalScrollOffset + e.clientX) - headerBeingResized.getClientRects()[0].x; - } - else { - width = headerBeingResized.getClientRects()[0].x + headerBeingResized.clientWidth - (horizontalScrollOffset + e.clientX); - } + if (isGrid) { + gridElement.style.gridTemplateColumns = initialWidths; + } + } - const column = columns.find(({ header }) => header === headerBeingResized); - column.size = Math.max(minWidth, width) + 'px'; + const id = gridElement.id; + grids.push({ + id, + columns, + initialWidths, + }); - columns.forEach((column) => { - if (column.size.startsWith('minmax')) { - column.size = parseInt(column.header.clientWidth, 10) + 'px'; - } - }); + function setListeners(div, isRTL) { + let pageX, curCol, curColWidth; + + div.addEventListener('pointerdown', function (e) { + curCol = e.target.parentElement; + pageX = e.pageX; + + const padding = paddingDiff(curCol); - gridElement.style.gridTemplateColumns = columns - .map(({ size }) => size) - .join(' '); + curColWidth = curCol.offsetWidth - padding; }); - const onPointerUp = (e) => { + div.addEventListener('pointerover', function (e) { + e.target.style.borderInlineEnd = '2px solid var(--neutral-stroke-focus)'; + }); - window.removeEventListener('pointermove', onPointerMove); - window.removeEventListener('pointerup', onPointerUp); - window.removeEventListener('pointercancel', onPointerUp); - window.removeEventListener('pointerleave', onPointerUp); + div.addEventListener('pointerup', removeBorder); + div.addEventListener('pointercancel', removeBorder); + div.addEventListener('pointerleave', removeBorder); - headerBeingResized.classList.remove('header-being-resized'); - headerBeingResized = null; + document.addEventListener('pointermove', (e) => + requestAnimationFrame(() => { + gridElement.style.tableLayout = 'fixed'; - if (e.target.hasPointerCapture(e.pointerId)) { - e.target.releasePointerCapture(e.pointerId); - } - }; + if (curCol) { + const diffX = isRTL ? pageX - e.pageX : e.pageX - pageX; + const column = columns.find(({ header }) => header === curCol); - const initResize = ({ target, pointerId }) => { - headerBeingResized = target.parentNode; - headerBeingResized.classList.add('header-being-resized'); + column.size = parseInt(Math.max(minWidth, curColWidth + diffX), 10) + 'px'; + columns.forEach((col) => { + if (col.size.startsWith('minmax')) { + col.size = parseInt(col.header.clientWidth, 10) + 'px'; + } + }); - window.addEventListener('pointermove', onPointerMove); - window.addEventListener('pointerup', onPointerUp); - window.addEventListener('pointercancel', onPointerUp); - window.addEventListener('pointerleave', onPointerUp); + if (isGrid) { + gridElement.style.gridTemplateColumns = columns + .map(({ size }) => size) + .join(' '); + } + else { + curCol.style.width = column.size; + } + } + }) + ); - if (resizeHandle) { - resizeHandle.setPointerCapture(pointerId); - } - }; + document.addEventListener('pointerup', function () { + curCol = undefined; + curColWidth = undefined; + pageX = undefined; + }); + } - header.querySelector('.resize-handle').addEventListener('pointerdown', initResize); + function createDiv(height, isRTL) { + const div = document.createElement('div'); + div.style.top = '5px'; + div.style.position = 'absolute'; + div.style.cursor = 'col-resize'; + div.style.userSelect = 'none'; + div.style.height = height + 'px'; + div.style.width = '5px'; + + if (isRTL) { + div.style.left = '0px'; + div.style.right = 'unset'; + } else { + div.style.left = 'unset'; + div.style.right = '0px'; + } + return div; + } - }); + function paddingDiff(col) { + if (getStyleVal(col, 'box-sizing') === 'border-box') { + return 0; + } - let initialWidths; - if (gridElement.style.gridTemplateColumns) { - initialWidths = gridElement.style.gridTemplateColumns; + const padLeft = getStyleVal(col, 'padding-left'); + const padRight = getStyleVal(col, 'padding-right'); + return parseInt(padLeft) + parseInt(padRight); } - else { - initialWidths = columns - .map(({ header, size }) => size) - .join(' '); - gridElement.style.gridTemplateColumns = initialWidths; + function getStyleVal(elm, css) { + return window.getComputedStyle(elm, null).getPropertyValue(css); } - let id = gridElement.id; - grids.push({ - id, - columns, - initialWidths - }); + function removeBorder(e) { + e.target.style.borderInlineEnd = ''; + } } -export function resetColumnWidths(gridElement) { + +export function resetColumnWidths(gridElement) { + const isGrid = gridElement.classList.contains('grid'); const grid = grids.find(({ id }) => id === gridElement.id); if (!grid) { return; @@ -270,11 +316,19 @@ export function resetColumnWidths(gridElement) { const columnsWidths = grid.initialWidths.split(' '); grid.columns.forEach((column, index) => { - column.size = columnsWidths[index]; + if (isGrid) { + column.size = columnsWidths[index]; + } else { + column.header.style.width = columnsWidths[index]; + } }); - gridElement.style.gridTemplateColumns = grid.initialWidths; - gridElement.dispatchEvent(new CustomEvent('closecolumnresize', { bubbles: true })); + if (isGrid) { + gridElement.style.gridTemplateColumns = grid.initialWidths; + } + gridElement.dispatchEvent( + new CustomEvent('closecolumnresize', { bubbles: true }) + ); gridElement.focus(); } @@ -308,7 +362,7 @@ export function resizeColumnDiscrete(gridElement, column, change) { } else { if (column.size.startsWith('minmax')) { - column.size = parseInt(column.header.clientWidth, 10) + 'px'; + column.size = parseInt(column.header.clientWidth, 10) + 'px'; } } columns.push(column.size); diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs index 7a51c9a632..57a9ce561d 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs @@ -75,7 +75,7 @@ public partial class FluentDataGridCell : FluentComponentBase .AddStyle("padding-top", "calc(var(--design-unit) * 2.5px)", Column is SelectColumn && (Grid.RowSize == DataGridRowSize.Medium || Owner.RowType == DataGridRowType.Header)) .AddStyle("padding-top", "calc(var(--design-unit) * 1.5px)", Column is SelectColumn && Grid.RowSize == DataGridRowSize.Small && Owner.RowType == DataGridRowType.Default) .AddStyle("width", Column?.Width, !string.IsNullOrEmpty(Column?.Width) && Grid.DisplayMode == DataGridDisplayMode.Table) - .AddStyle("height", $"{Grid.ItemSize:0}px", () => !Grid.EffectiveLoadingValue && Grid.Virtualize && Owner.RowType == DataGridRowType.Default) + .AddStyle("height", $"{Grid.ItemSize:0}px", () => !Grid.EffectiveLoadingValue && Grid.Virtualize) .AddStyle("height", $"{(int)Grid.RowSize}px", () => !Grid.EffectiveLoadingValue && !Grid.Virtualize && !Grid.MultiLine && (Grid.Items is not null || Grid.ItemsProvider is not null)) .AddStyle("height", "100%", Grid.MultiLine) .AddStyle("min-height", "44px", Owner.RowType != DataGridRowType.Default) diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.css b/src/Core/Components/DataGrid/FluentDataGridCell.razor.css index 4bff78e44a..1b175d54d8 100644 --- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.css +++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.css @@ -3,7 +3,7 @@ th, td { } td { - padding: calc((var(--design-unit) + var(--focus-stroke-width) - var(--stroke-width))* 1px) calc(((var(--design-unit)* 3) + var(--focus-stroke-width) - var(--stroke-width))* 1px); + padding: 6px 16px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -13,19 +13,22 @@ td { td.col-justify-center { text-align: center; - padding-inline-start: 0; } td.col-justify-end, td.col-justify-right { text-align: end; - padding-inline-end: calc(var(--design-unit) * 7px); } - td.grid-cell-placeholder:after { - content: '\2026'; /*horizontal ellipsis*/ - opacity: 0.75; - } +th.col-justify-end > div { + justify-content: flex-end; +} + + +td.grid-cell-placeholder:after { + content: '\2026'; /*horizontal ellipsis*/ + opacity: 0.75; +} .empty-content-cell, @@ -45,6 +48,7 @@ td { .column-header { font-weight: 600; + text-align: center; position: relative; padding: calc((var(--design-unit) + var(--focus-stroke-width) - var(--stroke-width)) * 1px) 1px calc((var(--design-unit) + var(--focus-stroke-width) - var(--stroke-width)) * 1px); } @@ -87,11 +91,14 @@ td { margin-inline-start: 2px; } +.col-justify-start ::deep .col-title { + text-align: left; +} + .col-justify-center ::deep .col-title { text-align: center; } .col-justify-end ::deep .col-title { text-align: end; - margin-inline-end: calc(var(--design-unit) * 4px); } diff --git a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Ascending.verified.razor.html b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Ascending.verified.razor.html index 8d006f2a62..bead8fb4ae 100644 --- a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Ascending.verified.razor.html +++ b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Ascending.verified.razor.html @@ -3,9 +3,9 @@ -
+
- +
Item1
-
-
+
+
Item2
diff --git a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Descending.verified.razor.html b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Descending.verified.razor.html index 6138666d8c..cfee491e29 100644 --- a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Descending.verified.razor.html +++ b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnIndex_Descending.verified.razor.html @@ -3,9 +3,9 @@ -
+
- +
Item1
-
-
+
+
Item2
diff --git a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Ascending.verified.razor.html b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Ascending.verified.razor.html index 8d006f2a62..bead8fb4ae 100644 --- a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Ascending.verified.razor.html +++ b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Ascending.verified.razor.html @@ -3,9 +3,9 @@ -
+
- +
Item1
-
-
+
+
Item2
diff --git a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Descending.verified.razor.html b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Descending.verified.razor.html index 6138666d8c..cfee491e29 100644 --- a/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Descending.verified.razor.html +++ b/tests/Core/DataGrid/DataGridSortByTests.DataGridSortByTests_SortByColumnTitle_Descending.verified.razor.html @@ -3,9 +3,9 @@ -
+
- +
Item1
-
-
+
+
Item2
diff --git a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Customized_Rendering.verified.razor.html b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Customized_Rendering.verified.razor.html index 9fded25aaf..b9e14ddad6 100644 --- a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Customized_Rendering.verified.razor.html +++ b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Customized_Rendering.verified.razor.html @@ -6,8 +6,8 @@
-
-
+
+
Name
diff --git a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Rendering.verified.razor.html b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Rendering.verified.razor.html index 08f9277e1f..6b9faeb27b 100644 --- a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Rendering.verified.razor.html +++ b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_MultiSelect_Rendering.verified.razor.html @@ -10,8 +10,8 @@ -
-
+
+
Name
diff --git a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleSelect_Rendering.verified.razor.html b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleSelect_Rendering.verified.razor.html index 0cbedf0437..713f83231e 100644 --- a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleSelect_Rendering.verified.razor.html +++ b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleSelect_Rendering.verified.razor.html @@ -4,8 +4,8 @@ -
-
+
+
Name
diff --git a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleStickySelect_Rendering.verified.razor.html b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleStickySelect_Rendering.verified.razor.html index 0cbedf0437..713f83231e 100644 --- a/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleStickySelect_Rendering.verified.razor.html +++ b/tests/Core/DataGrid/FluentDataGridColumSelectTests.FluentDataGrid_ColumSelect_SingleStickySelect_Rendering.verified.razor.html @@ -4,8 +4,8 @@ -
-
+
+
Name
diff --git a/tests/Core/DataGrid/FluentDataGridTests.FluentDataGrid_Default.verified.razor.html b/tests/Core/DataGrid/FluentDataGridTests.FluentDataGrid_Default.verified.razor.html index 0af36df66c..fd82a98758 100644 --- a/tests/Core/DataGrid/FluentDataGridTests.FluentDataGrid_Default.verified.razor.html +++ b/tests/Core/DataGrid/FluentDataGridTests.FluentDataGrid_Default.verified.razor.html @@ -3,8 +3,8 @@ -
-
+
+
Name