Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,11 @@
Constructs an instance of <see cref="T:Microsoft.FluentUI.AspNetCore.Components.ColumnBase`1" />.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ColumnResizeOptions`1.Grid">
<summary>
Gets a reference to the enclosing <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1" />.
</summary>
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.GridSort`1">
<summary>
Represents a sort order specification used within <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/>.
Expand Down Expand Up @@ -1676,6 +1681,13 @@
manually. Size changes are not persisted.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.ResizeType">
<summary>
To comply with WCAG 2.2, a one-click option should be offered to change column widths. We providesuch an option through the
ColumnOptions UI. This parameter allows you to enable or disable this resize UI.
Defualts to false.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1.ItemKey">
<summary>
Optionally defines a value for @key on each rendered row. Typically this should be used to specify a
Expand Down Expand Up @@ -12468,6 +12480,21 @@
Cell is a row header.
</summary>
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.DataGridResizeType">
<summary>
The type of <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1"/> in a <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/>.
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.DataGridResizeType.Discrete">
<summary>
Resize datagrid columns by discreet steps of 10 pixels
</summary>
</member>
<member name="F:Microsoft.FluentUI.AspNetCore.Components.DataGridResizeType.Exact">
<summary>
Resize datagrid columns by exact pixel values
</summary>
</member>
<member name="T:Microsoft.FluentUI.AspNetCore.Components.DataGridRowType">
<summary>
The type of <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGridRow`1"/> in a <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid`1"/>.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
@inject DataSource Data

<p>To test set ResizeType on the DataGrid to either DataGridResizeType.Discrete or DataGridResizeType.Exact</p>
<p>Remove the parameter completely to get the original behavior</p>

<FluentDataGrid Items="@FilteredItems" ResizableColumns=true Pagination="@pagination" GridTemplateColumns="0.2fr 1fr 0.2fr 0.2fr 0.2fr 0.2fr" RowClass="@rowClass" RowStyle="@rowStyle" Style="height: 405px;overflow:auto;">
<FluentDataGrid Items="@FilteredItems" ResizableColumns=true ResizeType="DataGridResizeType.Exact" Pagination="@pagination" GridTemplateColumns="0.2fr 1fr 0.2fr 0.2fr 0.2fr 0.2fr" RowClass="@rowClass" RowStyle="@rowStyle" Style="height: 405px;overflow:auto;">
<TemplateColumn Tooltip="true" TooltipText="@(c => "Flag of " + c.Name)" Title="Rank" SortBy="@rankSort" Align="Align.Center" InitialSortDirection="SortDirection.Ascending" IsDefaultSortColumn=true>
<img class="flag" src="_content/FluentUI.Demo.Shared/flags/@(context.Code).svg" alt="Flag of @(context.Code)" />
</TemplateColumn>
<PropertyColumn Property="@(c => c.Name)" Sortable="true" Filtered="!string.IsNullOrWhiteSpace(nameFilter)" Tooltip="true" Title="Name of the country">
<ColumnOptions>
<div class="search-box">
<FluentSearch 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..." Style="width: 100%;" Label="Filter" />
</div>
</ColumnOptions>
</PropertyColumn>
<PropertyColumn Property="@(c => c.Medals.Gold)" Sortable="true" Align="Align.Start" Tooltip="true" TooltipText="@(c => "That is " + c.Medals.Gold + " x GOLD!!")" />
<PropertyColumn Property="@(c => c.Medals.Silver)" Sortable="true" Align="Align.Center" Tooltip="true" />
<PropertyColumn Property="@(c => c.Medals.Bronze)" Sortable="true" Align="Align.End" />
<PropertyColumn Property="@(c => c.Medals.Total)" Align="Align.End" Tooltip="true" />
<PropertyColumn Property="@(c => c.Medals.Total)" Filtered="@(minMedals != 0 || maxMedals != 120)" Align="Align.End" Tooltip="true">
<ColumnOptions>
<div style="width: 100%; height: 150px;">
<FluentSlider Label="@($"Min ({minMedals})")" Min="0" Max="150" Step="1" Orientation="Orientation.Horizontal" @bind-Value=minMedals Immediate="true" Style="width: 100%;">
<FluentSliderLabel Position="0">0</FluentSliderLabel>
<FluentSliderLabel Position="50">50</FluentSliderLabel>
<FluentSliderLabel Position="100">100</FluentSliderLabel>
<FluentSliderLabel Position="150">150</FluentSliderLabel>
</FluentSlider>
<br /><br />
<FluentSlider Label="@($"Max ({maxMedals})")" Min="0" Max="150" Step="1" Orientation="Orientation.Horizontal" @bind-Value=maxMedals Immediate="true" Style="width: 100%;">
<FluentSliderLabel Position="0">0</FluentSliderLabel>
<FluentSliderLabel Position="50">50</FluentSliderLabel>
<FluentSliderLabel Position="100">100</FluentSliderLabel>
<FluentSliderLabel Position="150">150</FluentSliderLabel>
</FluentSlider>
</div>
</ColumnOptions>
</PropertyColumn>
</FluentDataGrid>


Expand All @@ -32,6 +52,8 @@
IQueryable<Country>? items;
PaginationState pagination = new PaginationState { ItemsPerPage = 10 };
string nameFilter = string.Empty;
int minMedals;
int maxMedals = 120;

GridSort<Country> rankSort = GridSort<Country>
.ByDescending(x => x.Medals.Gold)
Expand All @@ -41,7 +63,27 @@
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;

IQueryable<Country>? FilteredItems => items?.Where(x => x.Name.Contains(nameFilter, StringComparison.CurrentCultureIgnoreCase));
//IQueryable<Country>? FilteredItems => items?.Where(x => x.Name.Contains(nameFilter, StringComparison.CurrentCultureIgnoreCase));
IQueryable<Country>? FilteredItems
{
get
{
var result = items?.Where(c => c.Medals.Total <= maxMedals);

if (result is not null && !string.IsNullOrEmpty(nameFilter))
{
result = result.Where(c => c.Name.Contains(nameFilter, StringComparison.CurrentCultureIgnoreCase));
}

if (result is not null && minMedals > 0)
{
result = result.Where(c => c.Medals.Total >= minMedals);
}

return result;
}
}

protected override async Task OnInitializedAsync()
{
Expand All @@ -67,12 +109,12 @@
private async Task ToggleItemsAsync()
{
if (_clearItems)
{
items = null;
}
else
{
items = (await Data.GetCountriesAsync()).AsQueryable();
}
{
items = null;
}
else
{
items = (await Data.GetCountriesAsync()).AsQueryable();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
/* Ensure all the flags are the same size, and centered */
/* Ensure all the flags are the same size, and centered */
.flag {
height: 1rem;
margin: auto;
border: 1px solid var(--neutral-layer-3);
}
}
.search-box {
min-width: 250px;
width: 100%;
}

.search-box fluent-search {
width: 100%;
}
2 changes: 2 additions & 0 deletions examples/Demo/Shared/Pages/Lab/IssueTester.razor
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
@page "/issue-tester"

<FluentUI.Demo.Shared.Pages.DataGrid.Examples.DataGridTypical />
104 changes: 72 additions & 32 deletions src/Core/Components/DataGrid/Columns/ColumnBase.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@typeparam TGridItem
@{
InternalGridContext.Grid.AddColumn(this, InitialSortDirection, IsDefaultSortColumn);
Grid.AddColumn(this, InitialSortDirection, IsDefaultSortColumn);
}
@code
{
Expand All @@ -17,62 +17,102 @@
{
string? tooltip = Tooltip ? Title : null;

@if (ColumnOptions is not null && (Align == Align.Start || Align == Align.Center))
@if (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())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.FilterDismiss())" />
}
else
@if (Grid.ResizeType is not null)
{
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ChevronDown())" Color="Color.Neutral" Style="opacity: 0.5;" />

</FluentButton>
}
else
{
@if (ColumnOptions is not null)
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.Filter())" />
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.FilterDismiss())" />
}
else
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.Filter())" />
}

</FluentButton>
}
</FluentButton>
}
}

if (Sortable.HasValue ? Sortable.Value : IsSortableByDefault())
{
<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>
<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")" Style="opacity: 0.5;" />
}
else
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ArrowSortDown())" Slot="@(Align == Align.End ? "start" : "end")" Style="opacity: 0.5;" />
}
}
else
@if (Grid.ResizeType is not null && ColumnOptions is not null)
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ArrowSortDown())" Slot="@(Align == Align.End ? "start" : "end")" />
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.Filter())" Slot="@(Align == Align.End ? "start" : "end")" Style="opacity: 0.5;" />
}
}
}

</FluentButton>
</span>
</FluentButton>
</span>
</FluentKeyCode>
}
else
{
<div class="col-title">
<div class="col-title-text" title="@tooltip">@Title</div>
@if (Grid.ResizeType is not null && ColumnOptions is not null)
{
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.Filter())" Slot="@(Align == Align.End ? "start" : "end")" Style="opacity: 0.5;" />
}
}
</div>
}

@if (ColumnOptions is not null && Align == Align.End)
@if (Align == Align.End)
{
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.FilterDismiss())" />
}
else
@if (Grid.ResizeType is not null)
{
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
<FluentIcon Value="@(new CoreIcons.Regular.Size24.ChevronDown())" Color="Color.Neutral" Style="opacity: 0.5;" />
</FluentButton>
}
else
{
@if (ColumnOptions is not null)
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.Filter())" />
<FluentButton Appearance="Appearance.Stealth" class="col-options-button" @onclick="@(() => Grid.ShowColumnOptionsAsync(this))" aria-label="Filter this column">
@if (Filtered.GetValueOrDefault())
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.FilterDismiss())" />
}
else
{
<FluentIcon Value="@(new CoreIcons.Regular.Size24.Filter())" />
}

</FluentButton>
}
</FluentButton>
}
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions src/Core/Components/DataGrid/Columns/ColumnResizeOptions.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@typeparam TGridItem

<FluentStack Class="resize-options" VerticalAlignment="VerticalAlignment.Center" HorizontalGap="4">
@if (ResizeType == DataGridResizeType.Discrete)
{
<FluentLabel>@Label</FluentLabel>

<FluentSpacer />
<FluentButton OnClick="HandleShrinkAsync">
<FluentIcon Value="@(new CoreIcons.Regular.Size20.Subtract())" />
</FluentButton>
<FluentButton OnClick="HandleGrowAsync">
<FluentIcon Value="@(new CoreIcons.Regular.Size20.Add())" />
</FluentButton>
<FluentButton OnClick="HandleResetAsync">
<FluentIcon Value="@(new CoreIcons.Regular.Size20.ArrowReset())" />
</FluentButton>
}
else
{
<FluentStack Orientation="Orientation.Horizontal" HorizontalAlignment="HorizontalAlignment.End" VerticalAlignment="VerticalAlignment.Bottom">
<div style="display: flex; flex-direction: column; ">
<FluentTextField Id="width"
@bind-Value="@_width"
Style="width: 100%;"
TextFieldType="TextFieldType.Text"
InputMode="InputMode.Numeric"
Immediate="true"
ImmediateDelay="200"
Label="@Label"
AutoComplete="off"
@onkeydown="@HandleColumnWidthKeyDownAsync" />
</div>
<FluentButton Appearance="@Appearance.Accent" Style="height: 30px;" OnClick="@HandleColumnWidthAsync">
<FluentIcon Value="@(new CoreIcons.Regular.Size20.Checkmark())" Color="@Color.Fill" />
</FluentButton>
<FluentButton Style="height: 30px;" OnClick="HandleResetAsync" >
<FluentIcon Value="@(new CoreIcons.Regular.Size20.ArrowReset())" />
</FluentButton>

</FluentStack>
}
</FluentStack>

Loading