Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Add remove sort capability #1826

Merged
merged 4 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions WHATSNEW.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v4.6.2

### Components
[DataGrid] Add remove sort capability on columns ([#1826](https://github.com/microsoft/fluentui-blazor/pull/1826))

## V4.6.1

### Demo site and documentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1084,20 +1084,20 @@
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.Title">
<summary>
Gets or sets the title text for the column.
Gets or sets the title text for the column.
This is rendered automatically if <see cref="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.HeaderCellItemTemplate" /> is not used.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.Class">
<summary>
Gets or sets the an optional CSS class name.
Gets or sets the an optional CSS class name.
If specified, this is included in the class attribute of header and grid cells
for this column.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.Style">
<summary>
Gets or sets an optional CSS style specification.
Gets or sets an optional CSS style specification.
If specified, this is included in the style attribute of header and grid cells
for this column.
</summary>
Expand All @@ -1119,7 +1119,7 @@
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.HeaderCellItemTemplate">
<summary>
Gets or sets an optional template for this column's header cell.
Gets or sets an optional template for this column's header cell.
If not specified, the default header template includes the <see cref="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.Title" /> along with any applicable sort indicators and options buttons.
</summary>
</member>
Expand Down Expand Up @@ -1471,6 +1471,13 @@
<param name="direction">The direction of sorting. If the value is <see cref="F:Microsoft.FluentUI.AspNetCore.Components.SortDirection.Auto"/>, then it will toggle the direction on each call.</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> representing the completion of the operation.</returns>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.RemoveSortByColumnAsync(Microsoft.FluentUI.AspNetCore.Components.ColumnBase{`0})">
<summary>
Removes the grid's sort on double click if this is specified <paramref name="column"/> currently sorted on.
</summary>
<param name="column">The column to check against the current sorted on column.</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> representing the completion of the operation.</returns>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.ShowColumnOptionsAsync(Microsoft.FluentUI.AspNetCore.Components.ColumnBase{`0})">
<summary>
Displays the <see cref="P:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1.ColumnOptions"/> UI for the specified column, closing any other column
Expand Down
12 changes: 12 additions & 0 deletions examples/Demo/Shared/Pages/DataGrid/DataGridPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@
as this will interfere with the DataGrid scripts that use this attribute as well. Use the <code>RowClass</code> instead.
</p>

<h2 id="a11y">Accessibility</h2>
<p>
You can use the <kbd>Arrow</kbd> keys to navigate through a DataGrid. When a header cell is focused and the column is sortable, you can use the <kbd>Tab</kbd> key to select the sort button.
Pressing the <kbd>Enter</kbd> key will toggle the sorting direction. Pressing <kbd>Ctrl+Enter</kbd> removes the column sorting and restores the default/start situation with regards to sorting.
<em>You cannot not remove the default grid sorting with this key combination.</em>
</p>
<p>
When a header cell is focused and the column allows setting options, you can use the <kbd>Tab</kbd> key to select the options button.
Pressing the <kbd>Enter</kbd> key then will toggle the options popover. Pressing <kbd>Esc</kbd> closes the popover
.
</p>

<h2 id="example">Examples</h2>

<DemoSection Title="Get started" Component="@typeof(DataGridGetStarted)">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<PropertyColumn Property="@(c => c.Name)" Sortable="true" Filtered="!string.IsNullOrWhiteSpace(nameFilter)" Tooltip="true" Title="Name of the country">
<ColumnOptions>
<div class="search-box">
<FluentSearch type="search" Autofocus=true @bind-Value=nameFilter @oninput="HandleCountryFilter" @bind-Value:after="HandleClear" Placeholder="Country name..." />
<FluentSearch Autofocus=true @bind-Value=nameFilter @oninput="HandleCountryFilter" @bind-Value:after="HandleClear" Placeholder="Country name..." />
</div>
</ColumnOptions>
</PropertyColumn>
Expand All @@ -21,8 +21,8 @@

<FluentPaginator State="@pagination" />

<FluentSwitch @bind-Value="@_clearItems"
@bind-Value:after="ToggleItemsAsync"
<FluentSwitch @bind-Value="@_clearItems"
@bind-Value:after="ToggleItemsAsync"
UncheckedMessage="Clear all results"
CheckedMessage="Restore all results">
</FluentSwitch>
Expand All @@ -37,7 +37,7 @@
.ByDescending(x => x.Medals.Gold)
.ThenDescending(x => x.Medals.Silver)
.ThenDescending(x => x.Medals.Bronze);

Func<Country, string?> rowClass = x => x.Name.StartsWith("A") ? "highlighted-row" : null;
Func<Country, string?> rowStyle = x => x.Name.StartsWith("Au") ? "background-color: var(--highlight-bg);" : null;

Expand Down
6 changes: 5 additions & 1 deletion examples/Demo/Shared/wwwroot/docs/WhatsNew.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v4.6.2

### Components
[DataGrid] Add remove sort capability on columns ([#1826](https://github.com/microsoft/fluentui-blazor/pull/1826))

## V4.6.1

### Demo site and documentation
Expand All @@ -8,7 +13,6 @@
- [Demo & docs] CSS files improvements ([#1807](https://github.com/microsoft/fluentui-blazor/pull/1807))
- [Demo & docs] The empty CSS rule in site.css has been removed ([#1809](https://github.com/microsoft/fluentui-blazor/pull/1809))


### Components
- [AppBar] Add Count parameter and facilitate OnClick without navigation ([#1790](https://github.com/microsoft/fluentui-blazor/pull/1790))
- [CounterBadge] Add ShowWhen, Dot, and VerticalPosition ([#1786](https://github.com/microsoft/fluentui-blazor/pull/1786))
Expand Down
34 changes: 19 additions & 15 deletions src/Core/Components/DataGrid/Columns/ColumnBase.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.AspNetCore.Components.Rendering
@using Microsoft.FluentUI.AspNetCore.Components.DataGrid.Infrastructure
@namespace Microsoft.FluentUI.AspNetCore.Components
@typeparam TGridItem
Expand All @@ -20,7 +20,7 @@
@if (ColumnOptions is not null && (Align == Align.Start || Align == Align.Center))
{
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
@if(Filtered.GetValueOrDefault())
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.FilterDismiss())" />
}
Expand All @@ -33,22 +33,26 @@

if (Sortable.HasValue ? Sortable.Value : IsSortableByDefault())
{
<FluentButton Appearance="Appearance.Stealth" class="col-sort-button" @onclick="@(() => Grid.SortByColumnAsync(this))" aria-label="@tooltip" title="@tooltip">
<div class="col-title-text" title="@tooltip">@Title</div>
<FluentKeyCode Only="new [] { KeyCode.Ctrl, KeyCode.Enter}" OnKeyDown="HandleKeyDown" class="keycapture">
<span class="col-sort-container" @oncontextmenu="@(() => Grid.RemoveSortByColumnAsync(this))" @oncontextmenu:preventDefault>
<FluentButton Appearance="Appearance.Stealth" class="col-sort-button" @onclick="@(() => Grid.SortByColumnAsync(this))" aria-label="@tooltip" title="@tooltip">
<div class="col-title-text" title="@tooltip">@Title</div>

@if (Grid.SortByAscending.HasValue && ShowSortIcon)
{
if (Grid.SortByAscending == true)
@if (Grid.SortByAscending.HasValue && ShowSortIcon)
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ArrowSortUp())" Slot="@(Align == Align.End ? "start" : "end")" />
if (Grid.SortByAscending == true)
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ArrowSortUp())" Slot="@(Align == Align.End ? "start" : "end")" />
}
else
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ArrowSortDown())" Slot="@(Align == Align.End ? "start" : "end")" />
}
}
else
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ArrowSortDown())" Slot="@(Align == Align.End ? "start" : "end")" />
}
}

</FluentButton>
</FluentButton>
</span>
</FluentKeyCode>
}
else
{
Expand All @@ -60,7 +64,7 @@
@if (ColumnOptions is not null && Align == Align.End)
{
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
@if(Filtered.GetValueOrDefault())
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.FilterDismiss())" />
}
Expand Down
16 changes: 12 additions & 4 deletions src/Core/Components/DataGrid/Columns/ColumnBase.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ public abstract partial class ColumnBase<TGridItem>
[CascadingParameter] internal InternalGridContext<TGridItem> InternalGridContext { get; set; } = default!;

/// <summary>
/// Gets or sets the title text for the column.
/// Gets or sets the title text for the column.
/// This is rendered automatically if <see cref="HeaderCellItemTemplate" /> is not used.
/// </summary>
[Parameter] public string? Title { get; set; }

/// <summary>
/// Gets or sets the an optional CSS class name.
/// Gets or sets the an optional CSS class name.
/// If specified, this is included in the class attribute of header and grid cells
/// for this column.
/// </summary>
[Parameter] public string? Class { get; set; }

/// <summary>
/// Gets or sets an optional CSS style specification.
/// Gets or sets an optional CSS style specification.
/// If specified, this is included in the style attribute of header and grid cells
/// for this column.
/// </summary>
Expand All @@ -49,7 +49,7 @@ public abstract partial class ColumnBase<TGridItem>
[Parameter] public Func<TGridItem, string?>? TooltipText { get; set; }

/// <summary>
/// Gets or sets an optional template for this column's header cell.
/// Gets or sets an optional template for this column's header cell.
/// If not specified, the default header template includes the <see cref="Title" /> along with any applicable sort indicators and options buttons.
/// </summary>
[Parameter] public RenderFragment<ColumnBase<TGridItem>>? HeaderCellItemTemplate { get; set; }
Expand Down Expand Up @@ -135,6 +135,14 @@ public abstract partial class ColumnBase<TGridItem>
/// <returns>True if the column should be sortable by default, otherwise false.</returns>
protected virtual bool IsSortableByDefault() => false;

protected void HandleKeyDown(FluentKeyCodeEventArgs e)
{
if (e.CtrlKey && e.Key == KeyCode.Enter)
{
Grid.RemoveSortByColumnAsync(this);
}
}

public bool ShowSortIcon;

/// <summary>
Expand Down
27 changes: 22 additions & 5 deletions src/Core/Components/DataGrid/FluentDataGrid.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ internal void AddColumn(ColumnBase<TGridItem> column, SortDirection? initialSort
{
_sortByColumn = column;
_sortByAscending = initialSortDirection.Value != SortDirection.Descending;
_internalGridContext.DefaultSortColumn = (column, initialSortDirection.Value);
}
}
}
Expand Down Expand Up @@ -319,6 +320,23 @@ public Task SortByColumnAsync(ColumnBase<TGridItem> column, SortDirection direct
return RefreshDataAsync();
}

/// <summary>
/// Removes the grid's sort on double click if this is specified <paramref name="column"/> currently sorted on.
/// </summary>
/// <param name="column">The column to check against the current sorted on column.</param>
/// <returns>A <see cref="Task"/> representing the completion of the operation.</returns>
public Task RemoveSortByColumnAsync(ColumnBase<TGridItem> column)
{
if (_sortByColumn == column && !column.IsDefaultSortColumn)
{
_sortByColumn = _internalGridContext.DefaultSortColumn.Column ?? null;
_sortByAscending = _internalGridContext.DefaultSortColumn.Direction != SortDirection.Descending;
}

StateHasChanged(); // We want to see the updated sort order in the header, even before the data query is completed
return RefreshDataCoreAsync();
}

/// <summary>
/// Displays the <see cref="ColumnBase{TGridItem}.ColumnOptions"/> UI for the specified column, closing any other column
/// options UI that was previously displayed.
Expand All @@ -331,6 +349,10 @@ public Task ShowColumnOptionsAsync(ColumnBase<TGridItem> column)
StateHasChanged();
return Task.CompletedTask;
}
public void SetLoadingState(bool loading)
{
Loading = loading;
}

/// <summary>
/// Instructs the grid to re-fetch and render the current data from the supplied data source
Expand All @@ -342,11 +364,6 @@ public async Task RefreshDataAsync()
await RefreshDataCoreAsync();
}

public void SetLoadingState(bool loading)
{
Loading = loading;
}

// Same as RefreshDataAsync, except without forcing a re-render. We use this from OnParametersSetAsync
// because in that case there's going to be a re-render anyway.
private async Task RefreshDataCoreAsync()
Expand Down
1 change: 1 addition & 0 deletions src/Core/Components/DataGrid/FluentDataGrid.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function init(gridElement) {
if (columnOptionsElement) {
if (event.key === "Escape") {
gridElement.dispatchEvent(new CustomEvent('closecolumnoptions', { bubbles: true }));
gridElement.focus();
}
columnOptionsElement.addEventListener(
"keydown",
Expand Down
30 changes: 23 additions & 7 deletions src/Core/Components/DataGrid/FluentDataGridCell.razor.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fluent-data-grid-cell {
fluent-data-grid-cell {
text-overflow: ellipsis;
}

Expand All @@ -10,28 +10,44 @@

.column-header {
display: flex;
width: 100%;
height: 100%;
align-self: center;
padding-inline: 0;
padding-right: 1px;
padding-left: 1px;
}

.column-header.col-justify-end, .column-header.col-justify-right {
width: 100%;
padding: 0;

padding-right: 1px;
padding-left: 1px;
justify-content: end;
}

.column-header.col-justify-center {
width: 100%;
padding: 0;

padding-left: 1px;
padding-right: 1px;
justify-content: center;
}

.column-header > ::deep .col-sort-button {
.column-header > ::deep .keycapture {
display: flex;
flex-grow: 1;
}

.column-header > ::deep .keycapture .col-sort-container {
display: flex;
flex-grow: 1;
}

.column-header > ::deep .keycapture .col-sort-container .col-sort-button {
flex-grow: 1;
padding-inline-end: 5px;
}

.column-header > ::deep .col-sort-button::part(content) {
.column-header > ::deep .keycapture .col-sort-container .col-sort-button::part(content) {
overflow: hidden;
text-overflow: ellipsis;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ internal sealed class InternalGridContext<TGridItem>
private int _rowId = 0;
private int _cellId = 0;

public (ColumnBase<TGridItem>? Column, SortDirection? Direction) DefaultSortColumn { get; set; }
//public SortDirection? DefaultSortDirection { get; set; }

public Dictionary<string, FluentDataGridRow<TGridItem>> Rows { get; set; } = [];

public FluentDataGrid<TGridItem> Grid { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public async Task<IDialogReference> ShowDialogAsync(RenderFragment renderFragmen
return await ShowDialogAsync(typeof(RenderFragmentDialog), renderFragment, dialogParameters);
}

private DialogParameters FixPanelParameters(DialogParameters value)
private static DialogParameters FixPanelParameters(DialogParameters value)
{
value.DialogType = DialogType.Panel;

Expand Down
Loading