-
Notifications
You must be signed in to change notification settings - Fork 428
[dev-v5] Add Radio and RadioGroup #3647
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
5d67d21
Initial Radio/RadioGroup work
vnbaaij bba197e
Make it work, add tests.
vnbaaij 430bbc0
Merge dev
vnbaaij f1b0798
Cleanup & Tests
vnbaaij 56a9f04
Unit Tests: 100%
vnbaaij 927d0f9
Docs (wip)
vnbaaij e3ac1c2
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/radio
dvoituron e290ef2
- Update docs
vnbaaij 0220c49
Merge branch 'users/vnbaaij/dev-v5/radio' of https://github.com/micro…
vnbaaij afb11a2
Let FluentRadio inherit from FluentComponentBase
vnbaaij 0eefae9
Merge branch 'dev-v5' into users/vnbaaij/dev-v5/radio
vnbaaij d3410aa
Fix formatting, remove commented code
vnbaaij 8471879
Review comments
vnbaaij File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
17 changes: 17 additions & 0 deletions
17
...ples/Demo/FluentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioDefault.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<FluentStack Orientation="Orientation.Vertical" VerticalGap="10"> | ||
<FluentRadioGroup TValue="string" Label="Default"> | ||
<FluentRadio></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
<FluentRadioGroup TValue="string" Label="Checked" Value="@(string.Empty)"> | ||
<FluentRadio Value="@(string.Empty)"></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
<FluentRadioGroup TValue="string" Label="Disabled"> | ||
<FluentRadio Disabled="true"></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
<FluentRadioGroup TValue="string" Label="Field"> | ||
<FluentRadio Label="Apple" Value="@("Apple")"></FluentRadio> | ||
</FluentRadioGroup> | ||
</FluentStack> |
13 changes: 13 additions & 0 deletions
13
...Demo/FluentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioGroupDefault.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<FluentRadioGroup @bind-Value="@fruit" Label="Favorite fruit" Name="favorite-fruit"> | ||
<FluentRadio Value="@("apple")" Label="Apple"></FluentRadio> | ||
<FluentRadio Value="@("banana")" Label="Banana"></FluentRadio> | ||
<FluentRadio Value="@("orange")" Label="Orange"></FluentRadio> | ||
<FluentRadio Value="@("grape")" Label="Grape"></FluentRadio> | ||
<FluentRadio Value="@("kiwi")" Label="Kiwi"></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
<p>Favorite fruit: @fruit</p> | ||
|
||
@code { | ||
string? fruit = "banana"; | ||
} |
12 changes: 12 additions & 0 deletions
12
...luentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioGroupDisabledGroup.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<FluentRadioGroup @bind-Value="@fruit" Disabled="true" Label="Favorite fruit"> | ||
<FluentRadio Value="@("apple")" Label="Apple"></FluentRadio> | ||
<FluentRadio Value="@("banana")" Label="Banana"></FluentRadio> | ||
<FluentRadio Value="@("orange")" Label="Orange"></FluentRadio> | ||
<FluentRadio Value="@("grape")" Label="Grape"></FluentRadio> | ||
<FluentRadio Value="@("kiwi")" Label="Kiwi"></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
|
||
@code { | ||
private string? fruit; | ||
} |
12 changes: 12 additions & 0 deletions
12
...luentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioGroupDisabledItems.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<FluentRadioGroup @bind-Value="@fruit" Label="Favorite fruit"> | ||
<FluentRadio Value="@("apple")" Label="Apple"></FluentRadio> | ||
<FluentRadio Value="@("banana")" Label="Banana"></FluentRadio> | ||
<FluentRadio Value="@("orange")" Label="Orange" Disabled="true"></FluentRadio> | ||
<FluentRadio Value="@("grape")" Label="Grape"></FluentRadio> | ||
<FluentRadio Value="@("kiwi")" Label="Kiwi" Disabled="true"></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
|
||
@code { | ||
private string fruit = "banana"; | ||
} |
24 changes: 24 additions & 0 deletions
24
...luentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioGroupLabelTemplate.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<FluentRadioGroup Name="numbers" @bind-Value="@numberValue" Label="Numbers"> | ||
<FluentRadio Value="1"> | ||
<LabelTemplate><strong>One</strong></LabelTemplate> | ||
</FluentRadio> | ||
<FluentRadio Value="2"> | ||
<LabelTemplate><em>Two</em></LabelTemplate> | ||
</FluentRadio> | ||
</FluentRadioGroup> | ||
<p> | ||
Selected: @(numberValue is null ? "-" : $"{numberValue} (Type: {numberValue?.GetType()})" ) | ||
</p> | ||
|
||
<FluentRadioGroup Name="strings" @bind-Value="@stringValue" Label="Strings"> | ||
<FluentRadio Value="@("one")"><LabelTemplate><em>One</em></LabelTemplate></FluentRadio> | ||
<FluentRadio Value="@("two")"><LabelTemplate><strong>Two</strong></LabelTemplate></FluentRadio> | ||
</FluentRadioGroup> | ||
<p> | ||
Selected: @(stringValue is null ? "-" : $"{stringValue} (Type: {stringValue?.GetType()})") | ||
</p> | ||
|
||
@code { | ||
int? numberValue; | ||
string? stringValue; | ||
} |
18 changes: 18 additions & 0 deletions
18
...emo/FluentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioGroupRequired.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<form> | ||
<FluentRadioGroup Name="options" Id="radio-group-required" Label="Choose an option" Required="true" @bind-Value="@value" Message="Please select a fruit." > | ||
<FluentRadio Id="option1" Name="options" Value="@("Option 1")" Label="Option 1"></FluentRadio> | ||
<FluentRadio Id="option2" Name="options" Value="@("Option 2")" Label="Option 2"></FluentRadio> | ||
<FluentRadio Id="option3" Name="options" Value="@("Option 3")" Label="Option 3"></FluentRadio> | ||
</FluentRadioGroup> | ||
<br /> | ||
<div> | ||
<FluentButton Type="ButtonType.Submit" Appearance="ButtonAppearance.Primary">Submit</FluentButton> | ||
<FluentButton Id="reset-button" Type="ButtonType.Reset">Reset</FluentButton> | ||
</div> | ||
<span id="success-message" hidden>Form submitted successfully!</span> | ||
</form> | ||
|
||
|
||
@code { | ||
private string? value; | ||
} |
13 changes: 13 additions & 0 deletions
13
...emo/FluentUI.Demo.Client/Documentation/Components/Radio/Examples/RadioGroupVertical.razor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@page "/radiovertical" | ||
<FluentRadioGroup @bind-Value="@fruit" Label="Favorite fruit" Orientation="@Orientation.Vertical"> | ||
<FluentRadio Label="Apple"></FluentRadio> | ||
<FluentRadio Label="Banana"></FluentRadio> | ||
<FluentRadio Label="Orange"></FluentRadio> | ||
<FluentRadio Label="Grape"></FluentRadio> | ||
<FluentRadio Label="Kiwi"></FluentRadio> | ||
</FluentRadioGroup> | ||
|
||
<p>Favorite fruit: @fruit</p> | ||
@code { | ||
private string fruit = "banana"; | ||
} |
85 changes: 85 additions & 0 deletions
85
examples/Demo/FluentUI.Demo.Client/Documentation/Components/Radio/FluentRadio.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
--- | ||
title: RadioGroup and Radio | ||
route: /Radio | ||
--- | ||
|
||
# RadioGroup and Radio | ||
|
||
Radio groups let people select a single item from a short list. Use them in layouts that offer enough space to list up to five options or if it's important to view all options at once. | ||
|
||
If there isn't enough space, try a dropdown instead. If you need to let people select more than one option, use checkboxes. To let them immediately turn a setting on or off, try a switch. | ||
|
||
## Behavior | ||
|
||
Although it is technically possible to show a single Radio button (as can be seen below), it *must* be placed inside a RadioGroup to have any function. | ||
|
||
### Default selection | ||
Present a selected option in radio groups by default. The default selection should be placed first and should be the most logical response. Remaining options should be listed in a logical order. For more information, see the Content section. | ||
|
||
## Layout | ||
Radio groups can be aligned vertically or horizontally (default). When horizontally aligned, the label can appear next to or under the radio input. | ||
|
||
## Accessibility | ||
Include intuitive labels with radio groups. | ||
|
||
When tabbing, focus will fall on the first option if no options are selected. If there is a selection, focus will fall on that option first. | ||
|
||
## Content | ||
Keep labels short and clear | ||
Keep individual radio labels as concise and descriptive as possible. Use fragments instead of full sentences. If long labels can’t be avoided, text will wrap onto the next line. Never truncate radio text with an ellipsis. Use sentence case with no end punctuation. | ||
|
||
Skip the period in radio labels. For the label that introduces the radio group, don’t end with a colon. For more info, go to Periods in the Microsoft Writing Style Guide. | ||
|
||
Use sentence style capitalization—only capitalize the first word. For more info, go to Capitalization in the Microsoft Writing Style Guide. | ||
|
||
## Examples | ||
|
||
### Radio button appearances | ||
|
||
A radio button is either unchecked or checked. Usually, once an item in a group has been checked, the result of the group as a whole cannot be unchecked again. | ||
An item can also be disabled and can show a label to indicate the value. | ||
|
||
{{ RadioDefault }} | ||
|
||
## RadioGroup | ||
|
||
Radios are placed and used inside a radio group. Only one of the items in a group can have a checked state. | ||
You can bind to the `Value` of the group to the get the value of the checked item. | ||
|
||
{{ RadioGroupDefault }} | ||
|
||
## Strongly typed items and using Label template | ||
Radio items allow for strongly binding to types. Because of this, string values need to be defined in the following way: | ||
`Value="@("one")"` | ||
|
||
As an alternative to of using the `Label` parameter (string value only), | ||
it is possible to use the `LabelTemplate` parameter to specify a template for the label. | ||
In case both are specified, the `Label` parameter is used. | ||
|
||
{{ RadioGroupLabelTemplate }} | ||
|
||
## RadioGroup with vertical orientation | ||
When the radio group has a vertical orientation, the items are stacked on top of each other. | ||
|
||
{{ RadioGroupVertical }} | ||
|
||
## Disabled RadioGroup | ||
A radio group can be disabled as a whole. This means that the user cannot select any of the items in the group. | ||
{{ RadioGroupDisabledGroup }} | ||
|
||
## RadioGroup with disabled items | ||
Besides disabling the whole group, it is also possible to disable specific items in a group. | ||
{{ RadioGroupDisabledItems }} | ||
|
||
## RadioGroup required | ||
{{ RadioGroupRequired }} | ||
|
||
## API FluentRadioGroup | ||
{{ API Type=FluentRadioGroup }} | ||
|
||
## API FluentRadio | ||
{{ API Type=FluentRadio }} | ||
|
||
## Migrating to v5 | ||
|
||
{{ INCLUDE File=MigrationFluentRadio }} |
15 changes: 15 additions & 0 deletions
15
...FluentUI.Demo.Client/Documentation/GetStarted/Migration/MigrationFluentRadio.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
title: Migration FluentRadio and FluentRadioGroup | ||
route: /Migration/Radio | ||
hidden: true | ||
--- | ||
|
||
### FluentRadio specific changes | ||
- The `FluentRadio` component now inherits from `FluentInputBase` (instead of `FluentComponentBase` before). This means it supports and uses all parameters from `FluentInputBase`, such as `Disabled`, `Required`, `Value`, `Label`, etc. | ||
- Using the `ChildContent` parameter to specify the contents/label of a Radio item is no longer supported. Use the `Label` or `LabelTemplate` parameters instead | ||
- The `ReadOnly` parameter is not supported. Use the `Disabled` parameter instead. | ||
|
||
|
||
|
||
### Removed properties💥 | ||
- `ChildContent`, use `Label` or `LabelTemplate` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
@namespace Microsoft.FluentUI.AspNetCore.Components | ||
@using Microsoft.FluentUI.AspNetCore.Components.Extensions | ||
@using System.Diagnostics | ||
@inherits FluentComponentBase | ||
@typeparam TValue | ||
@{ | ||
Debug.Assert(Context != null); | ||
} | ||
<FluentField ForId="@Id" | ||
Class="@ClassValue" | ||
Style="@StyleValue" | ||
Label="@Label" | ||
LabelPosition="@Components.LabelPosition.After" | ||
LabelWidth="@LabelWidth" | ||
IncludeInputSlot="false"> | ||
<LabelTemplate>@LabelTemplate</LabelTemplate> | ||
<ChildContent> | ||
<fluent-radio id="@Id" | ||
checked="@(Context.CurrentValue?.Equals(Value) == true ? GetToggledTrueValue() : null)" | ||
disabled="@Disabled" | ||
slot="@FluentSlot.FieldInput" | ||
value="@(Value?.ToString() ?? Label ?? null)" | ||
vnbaaij marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name="@Context.GroupName" | ||
@onchange="@Context.ChangeEventCallback" | ||
vnbaaij marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@attributes="@AdditionalAttributes"> | ||
</fluent-radio> | ||
</ChildContent> | ||
</FluentField> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// ------------------------------------------------------------------------ | ||
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved. | ||
// ------------------------------------------------------------------------ | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
using Microsoft.AspNetCore.Components; | ||
using Microsoft.FluentUI.AspNetCore.Components.Utilities; | ||
|
||
namespace Microsoft.FluentUI.AspNetCore.Components; | ||
|
||
/// <summary> | ||
/// A Fluent Radio button component. | ||
/// </summary> | ||
/// <typeparam name="TValue">The type for the value of the radio button</typeparam> | ||
public partial class FluentRadio<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TValue> : FluentComponentBase | ||
{ | ||
bool _trueValueToggle; | ||
|
||
internal FluentRadioContext? Context { get; private set; } | ||
|
||
/// <summary /> | ||
public FluentRadio() | ||
{ | ||
Id = Identifier.NewId(); | ||
vnbaaij marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// <summary> | ||
/// Gets the optional CSS class. If given, this will be included in the class attribute of the component. | ||
/// </summary> | ||
protected virtual string? ClassValue => DefaultClassBuilder.Build(); | ||
|
||
/// <summary> | ||
/// Gets the optional in-line styles. If given, these will be included in the style attribute of the component. | ||
/// </summary> | ||
protected virtual string? StyleValue => DefaultStyleBuilder | ||
.Build(); | ||
|
||
/// <summary> | ||
/// Gets or sets the name of the element. | ||
/// Allows access by name from the associated form. | ||
/// ⚠️ This value needs to be set manually for SSR scenarios to work correctly. | ||
/// </summary> | ||
[Parameter] | ||
public virtual string? Name { get; set; } | ||
|
||
/// <inheritdoc cref="IFluentField.Disabled" /> | ||
[Parameter] | ||
public virtual bool? Disabled { get; set; } | ||
|
||
/// <inheritdoc cref="IFluentField.Label" /> | ||
[Parameter] | ||
public virtual string? Label { get; set; } | ||
|
||
/// <inheritdoc cref="IFluentField.LabelTemplate" /> | ||
[Parameter] | ||
public virtual RenderFragment? LabelTemplate { get; set; } | ||
|
||
/// <inheritdoc cref="IFluentField.LabelWidth" /> | ||
[Parameter] | ||
public virtual string? LabelWidth { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the value of the element. | ||
/// </summary> | ||
[Parameter] | ||
public TValue? Value { get; set; } | ||
|
||
[CascadingParameter] | ||
private FluentRadioContext? CascadedContext { get; set; } | ||
|
||
/// <inheritdoc /> | ||
protected override void OnParametersSet() | ||
{ | ||
Context = string.IsNullOrEmpty(Name) ? CascadedContext : CascadedContext?.FindContextInAncestors(Name); | ||
|
||
if (Context == null) | ||
{ | ||
throw new InvalidOperationException($"{GetType()} must have an ancestor {typeof(FluentRadioGroup<TValue>)} " + | ||
$"with a matching 'Name' property, if specified."); | ||
} | ||
} | ||
|
||
// This is an unfortunate hack, but is needed for the scenario described by test InputRadioGroupWorksWithMutatingSetter. | ||
// Radio groups are special in that modifying one <input type=radio> instantly and implicitly also modifies the previously | ||
// selected one in the same group. As such, our SetUpdatesAttributeName mechanism isn't sufficient to stay in sync with the | ||
// DOM, because the 'change' event will fire on the new <input type=radio> you just selected, not the previously-selected | ||
// one, and so the previously-selected one doesn't get notified to update its state in the old rendertree. So, if the setter | ||
// reverts the incoming value, the previously-selected one would produce an empty diff (because its .NET value hasn't changed) | ||
// and hence it would be left unselected in the DOM. If you don't understand why this is a problem, try commenting out the | ||
// line that toggles _trueValueToggle and see the E2E test fail. | ||
// | ||
// This hack works around that by causing InputRadio *always* to force its own 'checked' state to be true in the DOM if it's | ||
// true in .NET, whether or not it was true before, by continually changing the value that represents 'true'. This doesn't | ||
// really cause any significant increase in traffic because if we're rendering this InputRadio at all, sending one more small | ||
// attribute value is inconsequential. | ||
// | ||
// Ultimately, a better solution would be to make SetUpdatesAttributeName smarter still so that it knows about the special | ||
// semantics of radio buttons so that, when one <input type="radio"> changes, it treats any previously-selected sibling | ||
// as needing DOM sync as well. That's a more sophisticated change and might not even be useful if the radio buttons | ||
// aren't truly siblings and are in different DOM subtrees (and especially if they were rendered by different components!) | ||
private string GetToggledTrueValue() | ||
{ | ||
_trueValueToggle = !_trueValueToggle; | ||
return _trueValueToggle ? "a" : "b"; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.