Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
7ab2d22
Add rating component
franklupo Jun 25, 2024
aaca1ed
Merge branch 'dev' into rating
vnbaaij Jun 25, 2024
9ef2f20
Fix IconVariant
franklupo Jun 25, 2024
1cebab9
Add IconColor
franklupo Jun 25, 2024
8715dd1
Merge branch 'rating' of https://github.com/franklupo/fluentui-blazor…
franklupo Jun 25, 2024
3b81877
Fix page name
franklupo Jun 25, 2024
fa89df7
Add support disabled
franklupo Jun 25, 2024
d3e007d
Add support label
franklupo Jun 25, 2024
0796e11
Remove area not overable
franklupo Jun 25, 2024
84de233
Imprve icona name
franklupo Jun 25, 2024
1cd1940
Add icon color
franklupo Jun 25, 2024
a099a81
Add support arrowup/arrowdown
franklupo Jun 25, 2024
868c559
Improve sample
franklupo Jun 25, 2024
ae7f412
Add event HoveredValueChanged
franklupo Jun 25, 2024
c3a0607
Add IconCustomColor
franklupo Jun 25, 2024
b379fd0
Fix aria-readonly
franklupo Jun 25, 2024
792ba8d
Fix LabelTemplate
franklupo Jun 25, 2024
56cee95
Improve code style
franklupo Jun 25, 2024
fd99146
Improve icon name
franklupo Jun 25, 2024
62d8475
Add IconWidth
franklupo Jun 25, 2024
833e18a
Fix label documentation
franklupo Jun 25, 2024
872de54
Fix default value
franklupo Jun 25, 2024
45e19ca
Fix HoveredValueChanged to OnPointerOver
franklupo Jun 25, 2024
3b91b0a
Add AllowReset and rewrite HandleKeyDownAsync
franklupo Jun 26, 2024
5fc5059
Add AllowReset
franklupo Jun 26, 2024
99040df
Rewrite key down event
franklupo Jun 26, 2024
111e0e4
Fix Style and Class
franklupo Jun 26, 2024
88a94e9
Component explanation
franklupo Jun 26, 2024
26a4b0f
Merge branch 'dev' into rating
vnbaaij Jun 26, 2024
6fc81f6
Merge branch 'microsoft:dev' into rating
franklupo Jun 26, 2024
37a800e
Improve code
franklupo Jun 26, 2024
dbb9479
Add Unit test
franklupo Jun 27, 2024
b7fbd45
Fix IconWidth like React Component
franklupo Jun 27, 2024
79d25d2
Merge branch 'dev' into rating
vnbaaij Jun 27, 2024
ce9637f
Merge branch 'dev' into rating
vnbaaij Jun 27, 2024
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 @@ -7553,6 +7553,27 @@
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentRadioGroup`1.TryParseValueFromString(System.String,`0@,System.String@)">
<inheritdoc />
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.MaxValue">
<summary>
Gets or sets the maximum value.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.IconColor">
<summary>
Gets or sets the icon drawing and fill color.
Value comes from the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Color"/> enumeration. Defaults to Accent.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.FullIcon">
<summary>
Selected or hovered icon.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.EmptyIcon">
<summary>
Non-selected item icon.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentSearch.JSRuntime">
<summary />
</member>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

<FluentRating MaxValue="10" Value="5"/>
25 changes: 25 additions & 0 deletions examples/Demo/Shared/Pages/Rating/Examples/RatingExample.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<h4>Example</h4>

<FluentStack Orientation="Orientation.Horizontal">
<FluentCheckbox Label="Read Only" @bind-Value="@_readOnly" />
<FluentNumberField TValue="int" Label="Max Value" @bind-Value="@_maxValue" />
<FluentSelect TOption="Color"
@bind-SelectedOption="@_iconColor"
Style="min-width: 100px;"
Items="@(Enum.GetValues<Color>().Where(i => i != Color.Custom))"
OptionValue="@(i => i.ToAttributeValue())" />
</FluentStack>

<div>
<FluentRating MaxValue="@_maxValue" @bind-Value="@_value" ReadOnly="@_readOnly" IconColor="@_iconColor" />
</div>

<div>Value: @_value</div>

@code
{
bool _readOnly;
int _maxValue = 10;
int _value = 2;
Color _iconColor = Color.Accent;
}
17 changes: 17 additions & 0 deletions examples/Demo/Shared/Pages/Rating/RatingPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@page "/Rating"
@using FluentUI.Demo.Shared.Pages.Rating.Examples

<PageTitle>@App.PageTitle("Rating")</PageTitle>

<h1>Rating</h1>

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

<DemoSection Title="Default" Component="@typeof(RatingDefault)"></DemoSection>

<DemoSection Title="Example" Component="@typeof(RatingExample)"></DemoSection>


<h2 id="documentation">Documentation</h2>

<ApiDocumentation Component="typeof(FluentRating)" />
5 changes: 5 additions & 0 deletions examples/Demo/Shared/Shared/DemoNavProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ public DemoNavProvider()
icon: new Icons.Regular.Size20.RadioButton(),
title: "Radio Group"
),
new NavLink(
href: "/Rating",
icon: new Icons.Regular.Size20.Star(),
title: "Rating"
),
new NavLink(
href: "/Search",
icon: new Icons.Regular.Size20.SearchSquare(),
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Components/Icons/CoreIcons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class Warning : Icon { public Warning() : base("Warning", IconVariant.Fil
public class CheckboxChecked : Icon { public CheckboxChecked() : base("CheckboxChecked", IconVariant.Filled, IconSize.Size20, "<path d=\"M6 3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3H6Zm7.85 4.85-5 5a.5.5 0 0 1-.7 0l-2-2a.5.5 0 0 1 .7-.7l1.65 1.64 4.65-4.64a.5.5 0 0 1 .7.7Z\" />") { } }
public class CheckboxIndeterminate : Icon { public CheckboxIndeterminate() : base("CheckboxIndeterminate", IconVariant.Filled, IconSize.Size20, "<path d=\"M6 3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3H6ZM4.5 6c0-.83.67-1.5 1.5-1.5h8c.83 0 1.5.67 1.5 1.5v8c0 .83-.67 1.5-1.5 1.5H6A1.5 1.5 0 0 1 4.5 14V6ZM7 6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1H7Z\"></path><path d=\"M6 3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3V6a3 3 0 0 0-3-3H6ZM4.5 6c0-.83.67-1.5 1.5-1.5h8c.83 0 1.5.67 1.5 1.5v8c0 .83-.67 1.5-1.5 1.5H6A1.5 1.5 0 0 1 4.5 14V6ZM7 6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1H7Z\"></path>") { } }
public class RadioButton : Icon { public RadioButton() : base("RadioButton", IconVariant.Regular, IconSize.Size20, "<path d=\"M10 15a5 5 0 1 0 0-10 5 5 0 0 0 0 10Zm0-13a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm-7 8a7 7 0 1 1 14 0 7 7 0 0 1-14 0Z\" />") { } };
public class Star : Icon { public Star() : base("Star", IconVariant.Filled, IconSize.Size20, "<path d=\"M9.1 2.9a1 1 0 0 1 1.8 0l1.93 3.91 4.31.63a1 1 0 0 1 .56 1.7l-3.12 3.05.73 4.3a1 1 0 0 1-1.45 1.05L10 15.51l-3.86 2.03a1 1 0 0 1-1.45-1.05l.74-4.3L2.3 9.14a1 1 0 0 1 .56-1.7l4.31-.63L9.1 2.9Z\"></path>") { } };
}
}

Expand Down Expand Up @@ -99,6 +100,7 @@ public class Dismiss : Icon { public Dismiss() : base("Dismiss", IconVariant.Reg
public class DismissCircle : Icon { public DismissCircle() : base("DismissCircle", IconVariant.Regular, IconSize.Size20, "<path d=\"M10 2a8 8 0 1 1 0 16 8 8 0 0 1 0-16Zm0 1a7 7 0 1 0 0 14 7 7 0 0 0 0-14ZM7.8 7.11l.08.06L10 9.3l2.12-2.12a.5.5 0 0 1 .64-.06l.07.06c.17.18.2.44.06.64l-.06.07L10.7 10l2.12 2.12c.17.17.2.44.06.64l-.06.07a.5.5 0 0 1-.64.06l-.07-.06L10 10.7l-2.12 2.12a.5.5 0 0 1-.64.06l-.07-.06a.5.5 0 0 1-.06-.64l.06-.07L9.3 10 7.17 7.88a.5.5 0 0 1-.06-.64l.06-.07a.5.5 0 0 1 .64-.06Z\"/>") { } }
public class CheckboxUnchecked : Icon { public CheckboxUnchecked() : base("CheckboxUnchecked", IconVariant.Regular, IconSize.Size20, "<path d=\"M3 6a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6Zm3-2a2 2 0 0 0-2 2v8c0 1.1.9 2 2 2h8a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6Z\" />") { } }
public class RadioButton : Icon { public RadioButton() : base("RadioButton", IconVariant.Regular, IconSize.Size20, "<path d=\"M10 3a7 7 0 1 0 0 14 7 7 0 0 0 0-14Zm-8 7a8 8 0 1 1 16 0 8 8 0 0 1-16 0Z\" />") { } };
public class Star : Icon { public Star() : base("Star", IconVariant.Regular, IconSize.Size20, "<path d=\"M9.1 2.9a1 1 0 0 1 1.8 0l1.93 3.91 4.31.63a1 1 0 0 1 .56 1.7l-3.12 3.05.73 4.3a1 1 0 0 1-1.45 1.05L10 15.51l-3.86 2.03a1 1 0 0 1-1.45-1.05l.74-4.3L2.3 9.14a1 1 0 0 1 .56-1.7l4.31-.63L9.1 2.9Zm.9.44L8.07 7.25a1 1 0 0 1-.75.55L3 8.43l3.12 3.04a1 1 0 0 1 .3.89l-.75 4.3 3.87-2.03a1 1 0 0 1 .93 0l3.86 2.03-.74-4.3a1 1 0 0 1 .29-.89L17 8.43l-4.32-.63a1 1 0 0 1-.75-.55L10 3.35Z\"></path>") { } };
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/Core/Components/Rating/FluentRating.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@inherits FluentInputBase<int>

<FluentStack Id="@Id"
Orientation="Orientation.Horizontal"
Class="ClassValue"
Style="StyleValue"
role="radiogroup"
@onkeydown="HandleKeyDownAsync"
tabindex="@(Disabled ? -1 : 0)"
aria-readonly="@(ReadOnly.ToString().ToLower())">
@for (int i = 1; i <= MaxValue; i++)
{
var currentValue = i;
@if (ReadOnly)
{
<FluentIcon Value="@GetIcon(currentValue)" Color="IconColor" />
}
else
{
<FluentIcon Value="@GetIcon(currentValue)"
Color="IconColor"
OnClick="@(() => OnClickAsync(currentValue))"
@onpointerover="@(() => OnPointerOver(currentValue))"
@onpointerout="@(() => OnPointerOut())" />
}
}
</FluentStack>
88 changes: 88 additions & 0 deletions src/Core/Components/Rating/FluentRating.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;

namespace Microsoft.FluentUI.AspNetCore.Components;

public partial class FluentRating : FluentInputBase<int>
{
private int? _mouseOverValue;

public FluentRating() => Id = Identifier.NewId();

/// <summary>
/// Gets or sets the maximum value.
/// </summary>
[Parameter] public int MaxValue { get; set; } = 10;


/// <summary>
/// Gets or sets the icon drawing and fill color.
/// Value comes from the <see cref="AspNetCore.Components.Color"/> enumeration. Defaults to Accent.
/// </summary>
[Parameter] public Color? IconColor { get; set; }

/// <summary>
/// Selected or hovered icon.
/// </summary>
[Parameter] public Icon FullIcon { get; set; } = new CoreIcons.Filled.Size20.Star();

/// <summary>
/// Non-selected item icon.
/// </summary>
[Parameter] public Icon EmptyIcon { get; set; } = new CoreIcons.Regular.Size20.Star();

private Icon GetIcon(int index) => index <= (_mouseOverValue ?? Value) ? FullIcon : EmptyIcon;

protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out int result, [NotNullWhen(false)] out string?
validationErrorMessage)
{
if (BindConverter.TryConvertTo(value, CultureInfo.InvariantCulture, out result))
{
validationErrorMessage = null;
return true;
}
else
{
validationErrorMessage = string.Format(CultureInfo.InvariantCulture,
"The {0} field must be a number.",
FieldBound ? FieldIdentifier.FieldName : UnknownBoundField);
return false;
}
}

protected internal async Task HandleKeyDownAsync(KeyboardEventArgs keyboardEventArgs)
{
if (Disabled || ReadOnly) { return; }

var value = Value + keyboardEventArgs.Key switch
{
"ArrowRight" when keyboardEventArgs.ShiftKey => MaxValue - Value,
"ArrowRight" => 1,
"ArrowLeft" when keyboardEventArgs.ShiftKey => -Value,
"ArrowLeft" => -1,
_ => 1,
};

_mouseOverValue = null;
if (value > MaxValue)
{
value = MaxValue;
}
else if (value < 0)
{
value = 0;
}

await SetCurrentValueAsync(value);
}

private void OnPointerOut() => _mouseOverValue = null;
private void OnPointerOver(int value) => _mouseOverValue = value;
private async Task OnClickAsync(int value)
{
if (value == Value) { value = 0; }
await SetCurrentValueAsync(value);
}
}