From eb8d708a8eda9e0772f9c3208c99926b12d7cb45 Mon Sep 17 00:00:00 2001
From: m-akinc <7282195+m-akinc@users.noreply.github.com>
Date: Thu, 29 Sep 2022 14:26:22 -0500
Subject: [PATCH] Blazor integration for radio button and group (#754)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 🤨 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.
---
...-edc0cd68-5b88-4b6b-87e0-710ca16d49b0.json | 7 ++
.../Demo.Shared/Pages/ComponentsDemo.razor | 9 +++
.../Demo.Shared/Pages/ComponentsDemo.razor.cs | 1 +
.../Components/NimbleRadioButton.razor | 8 ++
.../Components/NimbleRadioButton.razor.cs | 37 +++++++++
.../Components/NimbleRadioGroup.razor | 10 +++
.../Components/NimbleRadioGroup.razor.cs | 38 +++++++++
.../nimble-blazor/NimbleBlazor/Orientation.cs | 14 ++++
.../Unit/Components/NimbleRadioButtonTests.cs | 55 +++++++++++++
.../Unit/Components/NimbleRadioGroupTests.cs | 80 +++++++++++++++++++
10 files changed, 259 insertions(+)
create mode 100644 change/@ni-nimble-blazor-edc0cd68-5b88-4b6b-87e0-710ca16d49b0.json
create mode 100644 packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor
create mode 100644 packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor.cs
create mode 100644 packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor
create mode 100644 packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor.cs
create mode 100644 packages/nimble-blazor/NimbleBlazor/Orientation.cs
create mode 100644 packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioButtonTests.cs
create mode 100644 packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs
diff --git a/change/@ni-nimble-blazor-edc0cd68-5b88-4b6b-87e0-710ca16d49b0.json b/change/@ni-nimble-blazor-edc0cd68-5b88-4b6b-87e0-710ca16d49b0.json
new file mode 100644
index 0000000000..3f48662175
--- /dev/null
+++ b/change/@ni-nimble-blazor-edc0cd68-5b88-4b6b-87e0-710ca16d49b0.json
@@ -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"
+}
diff --git a/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor b/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor
index f800a3c4e2..574d28ed05 100644
--- a/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor
+++ b/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor
@@ -49,6 +49,15 @@
Checkbox label
Checkbox label
+
+
Radio Buttons
+
+ Option 1
+ Option 2
+ Option 3
+
+
Value
+
Dialog:
Open Dialog
diff --git a/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor.cs b/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor.cs
index 995b8a7013..07f3b0a779 100644
--- a/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor.cs
+++ b/packages/nimble-blazor/Examples/Demo.Shared/Pages/ComponentsDemo.razor.cs
@@ -12,6 +12,7 @@ public partial class ComponentsDemo
private string? ActiveTabId { get; set; }
private NimbleDialog
? _dialog;
private string? ClosedReason { get; set; }
+ private string? SelectedRadio { get; set; } = "2";
private string DrawerLocationAsString
{
diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor
new file mode 100644
index 0000000000..8948513863
--- /dev/null
+++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor
@@ -0,0 +1,8 @@
+@namespace NimbleBlazor
+@inherits ComponentBase
+
+ @ChildContent
+
\ No newline at end of file
diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor.cs b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor.cs
new file mode 100644
index 0000000000..fc3e1837dd
--- /dev/null
+++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioButton.razor.cs
@@ -0,0 +1,37 @@
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.AspNetCore.Components;
+
+namespace NimbleBlazor;
+
+public partial class NimbleRadioButton : ComponentBase
+{
+ ///
+ /// Gets or sets the value.
+ ///
+ [Parameter]
+ public string? CurrentValue { get; set; }
+
+ ///
+ /// Gets or sets the disabled state.
+ ///
+ [Parameter]
+ public bool Disabled { get; set; }
+
+ ///
+ /// Gets or sets the name.
+ ///
+ [Parameter]
+ public string? Name { get; set; }
+
+ ///
+ /// Gets or sets the child content to be rendered inside the .
+ ///
+ [Parameter]
+ public RenderFragment? ChildContent { get; set; }
+
+ ///
+ /// Gets or sets any additional attributes to set on the element.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)]
+ public IDictionary? AdditionalAttributes { get; set; }
+}
diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor
new file mode 100644
index 0000000000..7126ca671b
--- /dev/null
+++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor
@@ -0,0 +1,10 @@
+@namespace NimbleBlazor
+@inherits NimbleInputBase
+(this, __value => CurrentValue = __value, CurrentValue))"
+ @attributes="AdditionalAttributes">
+ @ChildContent
+
\ No newline at end of file
diff --git a/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor.cs b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor.cs
new file mode 100644
index 0000000000..2409272603
--- /dev/null
+++ b/packages/nimble-blazor/NimbleBlazor/Components/NimbleRadioGroup.razor.cs
@@ -0,0 +1,38 @@
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.AspNetCore.Components;
+
+namespace NimbleBlazor;
+
+public partial class NimbleRadioGroup : NimbleInputBase
+{
+ ///
+ /// Gets or sets the disabled state.
+ ///
+ [Parameter]
+ public bool? Disabled { get; set; }
+
+ ///
+ /// Gets or sets the name.
+ ///
+ [Parameter]
+ public string? Name { get; set; }
+
+ ///
+ /// Gets or sets the Orientation of the group.
+ ///
+ [Parameter]
+ public Orientation? Orientation { get; set; }
+
+ ///
+ /// Gets or sets the child content to be rendered inside the .
+ ///
+ [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;
+ }
+}
diff --git a/packages/nimble-blazor/NimbleBlazor/Orientation.cs b/packages/nimble-blazor/NimbleBlazor/Orientation.cs
new file mode 100644
index 0000000000..fa251401bb
--- /dev/null
+++ b/packages/nimble-blazor/NimbleBlazor/Orientation.cs
@@ -0,0 +1,14 @@
+namespace NimbleBlazor;
+
+public enum Orientation
+{
+ Horizontal,
+ Vertical
+}
+
+internal static class OrientationExtensions
+{
+ private static readonly Dictionary _orientationValues = AttributeHelpers.GetEnumNamesAsKebabCaseValues();
+
+ public static string? ToAttributeValue(this Orientation? value) => value == null ? null : _orientationValues[value.Value];
+}
\ No newline at end of file
diff --git a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioButtonTests.cs b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioButtonTests.cs
new file mode 100644
index 0000000000..10998f4552
--- /dev/null
+++ b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioButtonTests.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Linq.Expressions;
+using Bunit;
+using Xunit;
+
+namespace NimbleBlazor.Tests.Unit.Components;
+
+///
+/// Tests for
+///
+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();
+
+ 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 RenderNimbleRadioButtonWithPropertySet(Expression> propertyGetter, TProperty propertyValue)
+ {
+ var context = new TestContext();
+ context.JSInterop.Mode = JSRuntimeMode.Loose;
+ return context.RenderComponent(p => p.Add(propertyGetter, propertyValue));
+ }
+}
diff --git a/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs
new file mode 100644
index 0000000000..c3382741da
--- /dev/null
+++ b/packages/nimble-blazor/Tests/NimbleBlazor.Tests/Unit/Components/NimbleRadioGroupTests.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Linq.Expressions;
+using Bunit;
+using Xunit;
+
+namespace NimbleBlazor.Tests.Unit.Components;
+
+///
+/// Tests for
+///
+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();
+
+ 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 RenderNimbleRadioGroupWithPropertySet(Expression> propertyGetter, TProperty propertyValue)
+ {
+ var context = new TestContext();
+ context.JSInterop.Mode = JSRuntimeMode.Loose;
+ return context.RenderComponent(p => p.Add(propertyGetter, propertyValue));
+ }
+
+ private IRenderedComponent RenderNimbleRadioGroupWithButton()
+ {
+ var context = new TestContext();
+ context.JSInterop.Mode = JSRuntimeMode.Loose;
+ return context.RenderComponent(p => p.AddChildContent());
+ }
+
+ private IRenderedComponent RenderNimbleRadioGroup(Orientation orientation)
+ {
+ var context = new TestContext();
+ context.JSInterop.Mode = JSRuntimeMode.Loose;
+ return context.RenderComponent(p => p.Add(x => x.Orientation, orientation));
+ }
+}