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

[Rating] New rating component #2258

Merged
merged 35 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -7559,6 +7559,55 @@
<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.IconCustomColor">
<summary>
Gets or sets the icon drawing and fill color to a custom value.
Needs to be formatted as an HTML hex color string (#rrggbb or #rgb) or CSS variable.
⚠️ Only available when Color is set to Color.Custom.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.IconWidth">
<summary>
The icon width.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.IconFilled">
<summary>
The icon to display when the rating value is greater than or equal to the item's value.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.IconOutline">
<summary>
The icon to display when the rating value is less than the item's value.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.AllowReset">
<summary>
Gets or sets a value that whether to allow clear when click again.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.OnPointerOver">
<summary>
Fires when hovered value changes. Value will be null if no rating item is hovered.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.ClassValue">
<summary />
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentRating.StyleValue">
<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 @@

franklupo marked this conversation as resolved.
Show resolved Hide resolved
<FluentRating MaxValue="10" Value="5" Label="Test"/>
38 changes: 38 additions & 0 deletions examples/Demo/Shared/Pages/Rating/Examples/RatingEvent.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<h4>Event</h4>

<FluentStack Orientation="Orientation.Vertical">
<FluentRating MaxValue="10"
OnPointerOver="OnPointerOver"
@bind-Value="@_value" />

<div>Value: @_value</div>
<div>Hovered value: @_overedValue</div>
<div>Hovered text value: @_overedTextValue</div>
</FluentStack>

@code
{
int _value = 2;
int? _overedValue;
string _overedTextValue = default!;

private void OnPointerOver(int? value)
{
_overedValue = value;
_overedTextValue = value.HasValue
? new string[]
{
"Very bad",
"Bad",
"Sufficient -2",
"Sufficient -1",
"Sufficient",
"Good -4",
"Good -3",
"Good -2" ,
"Good -1",
"Good"
}[value.Value - 1]
: string.Empty;
}
}
69 changes: 69 additions & 0 deletions examples/Demo/Shared/Pages/Rating/Examples/RatingExample.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<h4>Example</h4>
franklupo marked this conversation as resolved.
Show resolved Hide resolved

<FluentStack Orientation="Orientation.Vertical">
<FluentCheckbox Label="Read Only" @bind-Value="@_readOnly" />

<FluentCheckbox Label="Allow reset" @bind-Value="@_allowReset" />

<FluentCheckbox Label="Disabled" @bind-Value="@_disabled" />

<FluentNumberField TValue="int" Label="Max Value" @bind-Value="@_maxValue" />

<FluentSelect Label="Color"
@bind-SelectedOption="@_iconColor"
Style="min-width: 100px;"
Items="@(Enum.GetValues<Color>().Where(i => i != Color.Custom))"
OptionValue="@(i => i.ToAttributeValue())" />

<FluentSelect TOption="string"
Label="Icons Full/Empty"
SelectedOptionChanged="SelectedOptionChanged"
Style="min-width: 100px;"
Items="_icons" />

<FluentRating MaxValue="@_maxValue"
@bind-Value="@_value"
IconFilled="@_iconFilled"
IconOutline="@_iconOutline"
ReadOnly="@_readOnly"
IconColor="@_iconColor"
Disabled="@_disabled" ,
AllowReset="@_allowReset" />

<div>Value: @_value</div>
</FluentStack>

@code
{
bool _readOnly;
bool _disabled;
bool _allowReset;
int _maxValue = 10;
int _value = 2;
Color _iconColor = Color.Accent;

Icon _iconFilled = new Icons.Filled.Size20.Star();
Icon _iconOutline = new Icons.Regular.Size20.Star();
List<string> _icons = ["Star", "Heart", "Alert", "PersonCircle"];

private void SelectedOptionChanged(string name) => SetIcon(_icons.IndexOf(name));

private void SetIcon(int index)
{
_iconFilled = new Icon[]
{ new Icons.Filled.Size20.Star(),
new Icons.Filled.Size20.Heart(),
new Icons.Filled.Size20.Alert(),
new Icons.Filled.Size20.PersonCircle(),
}[index];

_iconOutline = new Icon[]
{ new Icons.Regular.Size20.Star(),
new Icons.Regular.Size20.Heart(),
new Icons.Regular.Size20.Alert(),
new Icons.Regular.Size20.PersonCircle(),
}[index];
}

protected override void OnParametersSet() => SetIcon(0);
}
30 changes: 30 additions & 0 deletions examples/Demo/Shared/Pages/Rating/RatingPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@page "/Rating"
@using FluentUI.Demo.Shared.Pages.Rating.Examples

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

<h1>Rating</h1>

<p>
A <code>&lt;FluentRating&gt;</code> component allows users to provide a rating for a particular item.
<code>&lt;FluentRating&gt;</code> allows customers to determine a sense of value of a good or a service.
By default, the rating is selected out of 5 stars, but the number and symbol used can be customized.
</p>

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

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

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


<h2 id="a11y">Accessibility</h2>
<p>
You can use the <kbd>arrow</kbd> keys to increase or decrease the value. Pressing <kbd>Shift+arrow</kbd> changes the value to 0 or the maximum value.
</p>

<DemoSection Title="Event" Component="@typeof(RatingEvent)"></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
4 changes: 3 additions & 1 deletion src/Core/Components/Icons/CoreIcons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public class Info : Icon { public Info() : base("Info", IconVariant.Filled, Icon
public class Warning : Icon { public Warning() : base("Warning", IconVariant.Filled, IconSize.Size20, "<path d=\"M8.68 2.79a1.5 1.5 0 0 1 2.64 0l6.5 12A1.5 1.5 0 0 1 16.5 17h-13a1.5 1.5 0 0 1-1.32-2.21l6.5-12ZM10.5 7.5a.5.5 0 0 0-1 0v4a.5.5 0 0 0 1 0v-4Zm.25 6.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z\"/>") { } }
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.Filled, 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 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
43 changes: 43 additions & 0 deletions src/Core/Components/Rating/FluentRating.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@inherits FluentInputBase<int>

@if (!ReadOnly && !Disabled)
{
<FluentKeyCode Anchor="@Id"
PreventDefaultOnly="new[] { KeyCode.Left, KeyCode.Right, KeyCode.Up, KeyCode.Down, KeyCode.Shift }"
StopPropagation="@true"
OnKeyDown="@HandleKeyDownAsync" />
}

<FluentInputLabel ForId="@Id" Label="@Label" AriaLabel="@AriaLabel" Required="@Required">@LabelTemplate</FluentInputLabel>

<FluentStack Id="@Id"
Orientation="Orientation.Horizontal"
Class="@ClassValue"
Style="@StyleValue"
role="radiogroup"
tabindex="@(Disabled ? -1 : 0)"
aria-readonly="@ReadOnly.ToAttributeValue()"
HorizontalGap="0">
@for (int i = 1; i <= MaxValue; i++)
{
var currentValue = i;
dvoituron marked this conversation as resolved.
Show resolved Hide resolved
@if (ReadOnly || Disabled)
{
<FluentIcon Value="@GetIcon(currentValue)"
Width="@IconWidth"
Color="@(Disabled && IconColor != Color.Custom ? Color.Disabled : IconColor)"
CustomColor="@IconCustomColor" />
}
else
{
<FluentIcon Value="@GetIcon(currentValue)"
Width="@IconWidth"
Color="IconColor"
franklupo marked this conversation as resolved.
Show resolved Hide resolved
CustomColor="@IconCustomColor"
OnClick="@(() => OnClickAsync(currentValue))"
@onpointerover="@(async () => await OnPointerOverAsync(currentValue))"
@onpointerout="@(async () => await OnPointerOutAsync())" />
}
}
</FluentStack>
Loading
Loading