Skip to content

Commit

Permalink
Blazor integration for radio button and group (#754)
Browse files Browse the repository at this point in the history
## 🀨 Rationale

Blazor integration for radio button and radio group.

## πŸ‘©β€πŸ’» Implementation

- Copied and modified the Blazor wrapper for the FluentRadio and
FluentRadioGroup
- Added Orientation type for radio group's orientation property
- Created a few tests, following the example of other Blazor wrappers
- Added a radio group to the Blazor example app
- Updated README table from spreadsheet

## πŸ§ͺ Testing

Unit tests and example app

## βœ… Checklist

- [x] I have updated the project documentation to reflect my changes or
determined no changes are needed.
  • Loading branch information
m-akinc authored Sep 29, 2022
1 parent 22b9674 commit eb8d708
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Blazor wrapper for radio button and group",
"packageName": "@ni/nimble-blazor",
"email": "7282195+m-akinc@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@
<NimbleCheckbox>Checkbox label</NimbleCheckbox>
<NimbleCheckbox>Checkbox label</NimbleCheckbox>
</div>
<div class="sub-container">
<div class="container-label">Radio Buttons</div>
<NimbleRadioGroup Name="options" @bind-Value="@SelectedRadio">
<NimbleRadioButton Value="1">Option 1</NimbleRadioButton>
<NimbleRadioButton Value="2">Option 2</NimbleRadioButton>
<NimbleRadioButton Value="3">Option 3</NimbleRadioButton>
</NimbleRadioGroup>
<NimbleTextField @bind-Value="@SelectedRadio">Value</NimbleTextField>
</div>
<div class="sub-container">
<div class="container-label">Dialog:</div>
<NimbleButton Appearance="ButtonAppearance.Outline" @onclick="OpenDialogAsync">Open Dialog</NimbleButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public partial class ComponentsDemo
private string? ActiveTabId { get; set; }
private NimbleDialog<DialogResult>? _dialog;
private string? ClosedReason { get; set; }
private string? SelectedRadio { get; set; } = "2";

private string DrawerLocationAsString
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@namespace NimbleBlazor
@inherits ComponentBase
<nimble-radio-button current-value="@CurrentValue"
disabled="@Disabled"
name="@Name"
@attributes="AdditionalAttributes">
@ChildContent
</nimble-radio-button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
ο»Ώusing System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;

namespace NimbleBlazor;

public partial class NimbleRadioButton : ComponentBase
{
/// <summary>
/// Gets or sets the value.
/// </summary>
[Parameter]
public string? CurrentValue { get; set; }

/// <summary>
/// Gets or sets the disabled state.
/// </summary>
[Parameter]
public bool Disabled { get; set; }

/// <summary>
/// Gets or sets the name.
/// </summary>
[Parameter]
public string? Name { get; set; }

/// <summary>
/// Gets or sets the child content to be rendered inside the <see cref="NimbleRadioButton"/>.
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; }

/// <summary>
/// Gets or sets any additional attributes to set on the element.
/// </summary>
[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object>? AdditionalAttributes { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@namespace NimbleBlazor
@inherits NimbleInputBase<string>
<nimble-radio-group disabled=@Disabled
name="@Name"
orientation="@Orientation.ToAttributeValue()"
value="@Value"
@onchange="@(EventCallback.Factory.CreateBinder<string?>(this, __value => CurrentValue = __value, CurrentValue))"
@attributes="AdditionalAttributes">
@ChildContent
</nimble-radio-group>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
ο»Ώusing System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;

namespace NimbleBlazor;

public partial class NimbleRadioGroup : NimbleInputBase<string>
{
/// <summary>
/// Gets or sets the disabled state.
/// </summary>
[Parameter]
public bool? Disabled { get; set; }

/// <summary>
/// Gets or sets the name.
/// </summary>
[Parameter]
public string? Name { get; set; }

/// <summary>
/// Gets or sets the Orientation of the group.
/// </summary>
[Parameter]
public Orientation? Orientation { get; set; }

/// <summary>
/// Gets or sets the child content to be rendered inside the <see cref="NimbleRadioGroup"/>.
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; }

protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out string result, [NotNullWhen(false)] out string? validationErrorMessage)
{
result = value ?? string.Empty;
validationErrorMessage = null;
return true;
}
}
14 changes: 14 additions & 0 deletions packages/nimble-blazor/NimbleBlazor/Orientation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ο»Ώnamespace NimbleBlazor;

public enum Orientation
{
Horizontal,
Vertical
}

internal static class OrientationExtensions
{
private static readonly Dictionary<Orientation, string> _orientationValues = AttributeHelpers.GetEnumNamesAsKebabCaseValues<Orientation>();

public static string? ToAttributeValue(this Orientation? value) => value == null ? null : _orientationValues[value.Value];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Linq.Expressions;
using Bunit;
using Xunit;

namespace NimbleBlazor.Tests.Unit.Components;

/// <summary>
/// Tests for <see cref="NimbleRadioButton"/>
/// </summary>
public class NimbleRadioButtonTests
{
[Fact]
public void NimbleRadioButton_Rendered_HasRadioButtonMarkup()
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
var expectedMarkup = "nimble-radio-button";

var radioButton = context.RenderComponent<NimbleRadioButton>();

Assert.Contains(expectedMarkup, radioButton.Markup);
}

[Fact]
public void NimbleRadioButtonCurrentValue_AttributeIsSet()
{
var radioButton = RenderNimbleRadioButtonWithPropertySet(x => x.CurrentValue, "foo");

Assert.Contains("current-value", radioButton.Markup);
}

[Fact]
public void NimbleRadioButtonDisabled_AttributeIsSet()
{
var radioButton = RenderNimbleRadioButtonWithPropertySet(x => x.Disabled, true);

Assert.Contains("disabled", radioButton.Markup);
}

[Fact]
public void NimbleRadioButtonName_AttributeIsSet()
{
var radioButton = RenderNimbleRadioButtonWithPropertySet(x => x.Name, "buttons");

Assert.Contains("name", radioButton.Markup);
}

private IRenderedComponent<NimbleRadioButton> RenderNimbleRadioButtonWithPropertySet<TProperty>(Expression<Func<NimbleRadioButton, TProperty>> propertyGetter, TProperty propertyValue)
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
return context.RenderComponent<NimbleRadioButton>(p => p.Add(propertyGetter, propertyValue));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Linq.Expressions;
using Bunit;
using Xunit;

namespace NimbleBlazor.Tests.Unit.Components;

/// <summary>
/// Tests for <see cref="NimbleRadioGroup"/>
/// </summary>
public class NimbleRadioGroupTests
{
[Fact]
public void NimbleRadioGroup_Rendered_HasRadioGroupMarkup()
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
var expectedMarkup = "nimble-radio-group";

var radioGroup = context.RenderComponent<NimbleRadioGroup>();

Assert.Contains(expectedMarkup, radioGroup.Markup);
}

[Theory]
[InlineData(Orientation.Horizontal, "horizontal")]
[InlineData(Orientation.Vertical, "vertical")]
public void RadioGroupOrientation_AttributeIsSet(Orientation value, string expectedAttribute)
{
var radioGroup = RenderNimbleRadioGroup(value);

Assert.Contains(expectedAttribute, radioGroup.Markup);
}

[Fact]
public void RadioGroupWithButton_HasRadioButtonMarkup()
{
var expectedMarkup = "nimble-radio-button";
var select = RenderNimbleRadioGroupWithButton();

Assert.Contains(expectedMarkup, select.Markup);
}

[Fact]
public void NimbleRadioGroupDisabled_AttributeIsSet()
{
var radioGroup = RenderNimbleRadioGroupWithPropertySet(x => x.Disabled, true);

Assert.Contains("disabled", radioGroup.Markup);
}

[Fact]
public void NimbleRadioGroupName_AttributeIsSet()
{
var radioGroup = RenderNimbleRadioGroupWithPropertySet(x => x.Name, "foo");

Assert.Contains("name", radioGroup.Markup);
}

private IRenderedComponent<NimbleRadioGroup> RenderNimbleRadioGroupWithPropertySet<TProperty>(Expression<Func<NimbleRadioGroup, TProperty>> propertyGetter, TProperty propertyValue)
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
return context.RenderComponent<NimbleRadioGroup>(p => p.Add(propertyGetter, propertyValue));
}

private IRenderedComponent<NimbleRadioGroup> RenderNimbleRadioGroupWithButton()
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
return context.RenderComponent<NimbleRadioGroup>(p => p.AddChildContent<NimbleRadioButton>());
}

private IRenderedComponent<NimbleRadioGroup> RenderNimbleRadioGroup(Orientation orientation)
{
var context = new TestContext();
context.JSInterop.Mode = JSRuntimeMode.Loose;
return context.RenderComponent<NimbleRadioGroup>(p => p.Add(x => x.Orientation, orientation));
}
}

0 comments on commit eb8d708

Please sign in to comment.